1 /*
<lambda>null2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.compose.material3
18 
19 import androidx.annotation.FloatRange
20 import androidx.compose.animation.animateColorAsState
21 import androidx.compose.foundation.border
22 import androidx.compose.foundation.interaction.Interaction
23 import androidx.compose.foundation.interaction.InteractionSource
24 import androidx.compose.foundation.interaction.MutableInteractionSource
25 import androidx.compose.foundation.interaction.collectIsFocusedAsState
26 import androidx.compose.foundation.layout.Box
27 import androidx.compose.foundation.layout.PaddingValues
28 import androidx.compose.foundation.text.BasicTextField
29 import androidx.compose.foundation.text.input.OutputTransformation
30 import androidx.compose.foundation.text.input.TextFieldBuffer
31 import androidx.compose.foundation.text.input.TextFieldDecorator
32 import androidx.compose.foundation.text.input.TextFieldLineLimits
33 import androidx.compose.foundation.text.input.TextFieldLineLimits.MultiLine
34 import androidx.compose.foundation.text.input.TextFieldLineLimits.SingleLine
35 import androidx.compose.foundation.text.input.TextFieldState
36 import androidx.compose.foundation.text.selection.LocalTextSelectionColors
37 import androidx.compose.foundation.text.selection.TextSelectionColors
38 import androidx.compose.material3.internal.CommonDecorationBox
39 import androidx.compose.material3.internal.SupportingTopPadding
40 import androidx.compose.material3.internal.TextFieldPadding
41 import androidx.compose.material3.internal.TextFieldType
42 import androidx.compose.material3.internal.animateBorderStrokeAsState
43 import androidx.compose.material3.internal.textFieldBackground
44 import androidx.compose.material3.tokens.FilledTextFieldTokens
45 import androidx.compose.material3.tokens.MotionSchemeKeyTokens
46 import androidx.compose.material3.tokens.OutlinedTextFieldTokens
47 import androidx.compose.runtime.Composable
48 import androidx.compose.runtime.Immutable
49 import androidx.compose.runtime.Stable
50 import androidx.compose.runtime.remember
51 import androidx.compose.ui.Alignment
52 import androidx.compose.ui.Modifier
53 import androidx.compose.ui.graphics.Color
54 import androidx.compose.ui.graphics.Shape
55 import androidx.compose.ui.graphics.takeOrElse
56 import androidx.compose.ui.text.AnnotatedString
57 import androidx.compose.ui.text.input.VisualTransformation
58 import androidx.compose.ui.unit.Dp
59 import androidx.compose.ui.unit.dp
60 
61 /**
62  * Contains the default values used by [TextField]. For defaults used in [OutlinedTextField], see
63  * [OutlinedTextFieldDefaults].
64  */
65 @Immutable
66 object TextFieldDefaults {
67     /** Default shape for a [TextField]. */
68     val shape: Shape
69         @Composable get() = FilledTextFieldTokens.ContainerShape.value
70 
71     /**
72      * The default min height applied to a [TextField]. Note that you can override it by applying
73      * Modifier.heightIn directly on a text field.
74      */
75     val MinHeight = 56.dp
76 
77     /**
78      * The default min width applied to a [TextField]. Note that you can override it by applying
79      * Modifier.widthIn directly on a text field.
80      */
81     val MinWidth = 280.dp
82 
83     /** The default thickness of the indicator line in [TextField] in unfocused state. */
84     val UnfocusedIndicatorThickness = 1.dp
85 
86     /** The default thickness of the indicator line in [TextField] in focused state. */
87     val FocusedIndicatorThickness = 2.dp
88 
89     /**
90      * A decorator used to create custom text fields based on
91      * [Material Design filled text field](https://m3.material.io/components/text-fields/overview).
92      *
93      * If your text field requires customising elements that aren't exposed by [TextField], such as
94      * the indicator line thickness, consider using this decorator to achieve the desired design.
95      *
96      * For example, if you wish to customise the bottom indicator line, you can pass a custom
97      * [Container] to this decorator's [container].
98      *
99      * This decorator is meant to be used in conjunction with the overload of [BasicTextField] that
100      * accepts a [TextFieldDecorator] parameter. For other overloads of [BasicTextField] that use a
101      * `decorationBox`, see [DecorationBox].
102      *
103      * An example of building a custom text field using [decorator]:
104      *
105      * @sample androidx.compose.material3.samples.CustomTextFieldUsingDecorator
106      * @param state [TextFieldState] object that holds the internal editing state of the text field.
107      * @param enabled the enabled state of the text field. When `false`, this decorator will appear
108      *   visually disabled. This must be the same value that is passed to [BasicTextField].
109      * @param lineLimits whether the text field is [SingleLine] or [MultiLine]. This must be the
110      *   same value that is passed to [BasicTextField].
111      * @param outputTransformation [OutputTransformation] that transforms how the contents of the
112      *   text field are presented. This must be the same value that is passed to [BasicTextField].
113      * @param interactionSource the read-only [InteractionSource] representing the stream of
114      *   [Interaction]s for this text field. You must first create and pass in your own `remember`ed
115      *   [MutableInteractionSource] instance to the [BasicTextField] for it to dispatch events. And
116      *   then pass the same instance to this decorator to observe [Interaction]s and customize the
117      *   appearance/behavior of the text field in different states.
118      * @param labelPosition the position of the label. See [TextFieldLabelPosition].
119      * @param label the optional label to be displayed with this text field. The default text style
120      *   uses [Typography.bodySmall] when minimized and [Typography.bodyLarge] when expanded.
121      * @param placeholder the optional placeholder to be displayed when the input text is empty. The
122      *   default text style uses [Typography.bodyLarge].
123      * @param leadingIcon the optional leading icon to be displayed at the beginning of the text
124      *   field container.
125      * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
126      *   container.
127      * @param prefix the optional prefix to be displayed before the input text in the text field.
128      * @param suffix the optional suffix to be displayed after the input text in the text field.
129      * @param supportingText the optional supporting text to be displayed below the text field.
130      * @param isError indicates if the text field's current value is in an error state. When `true`,
131      *   this decorator will display its contents in an error color.
132      * @param colors [TextFieldColors] that will be used to resolve the colors used for this text
133      *   field decorator in different states. See [TextFieldDefaults.colors].
134      * @param contentPadding the padding between the input field and the surrounding elements of the
135      *   decorator. Note that the padding values may not be respected if they are incompatible with
136      *   the text field's size constraints or layout. See
137      *   [TextFieldDefaults.contentPaddingWithLabel] and
138      *   [TextFieldDefaults.contentPaddingWithoutLabel].
139      * @param container the container to be drawn behind the text field. By default, this uses
140      *   [Container]. Default colors for the container come from the [colors].
141      */
142     @Composable
143     fun decorator(
144         state: TextFieldState,
145         enabled: Boolean,
146         lineLimits: TextFieldLineLimits,
147         outputTransformation: OutputTransformation?,
148         interactionSource: InteractionSource,
149         labelPosition: TextFieldLabelPosition = TextFieldLabelPosition.Attached(),
150         label: @Composable (TextFieldLabelScope.() -> Unit)? = null,
151         placeholder: @Composable (() -> Unit)? = null,
152         leadingIcon: @Composable (() -> Unit)? = null,
153         trailingIcon: @Composable (() -> Unit)? = null,
154         prefix: @Composable (() -> Unit)? = null,
155         suffix: @Composable (() -> Unit)? = null,
156         supportingText: @Composable (() -> Unit)? = null,
157         isError: Boolean = false,
158         colors: TextFieldColors = colors(),
159         contentPadding: PaddingValues =
160             if (label == null || labelPosition is TextFieldLabelPosition.Above) {
161                 contentPaddingWithoutLabel()
162             } else {
163                 contentPaddingWithLabel()
164             },
165         container: @Composable () -> Unit = {
166             Container(
167                 enabled = enabled,
168                 isError = isError,
169                 interactionSource = interactionSource,
170                 colors = colors,
171                 shape = shape,
172                 focusedIndicatorLineThickness = FocusedIndicatorThickness,
173                 unfocusedIndicatorLineThickness = UnfocusedIndicatorThickness,
174             )
175         }
176     ): TextFieldDecorator = TextFieldDecorator { innerTextField ->
177         val visualText =
178             if (outputTransformation == null) state.text
179             else {
180                 // TODO: use constructor to create TextFieldBuffer from TextFieldState when
181                 // available
182                 lateinit var buffer: TextFieldBuffer
183                 state.edit { buffer = this }
184                 // after edit completes, mutations on buffer are ineffective
185                 with(outputTransformation) { buffer.transformOutput() }
186                 buffer.asCharSequence()
187             }
188 
189         CommonDecorationBox(
190             type = TextFieldType.Filled,
191             visualText = visualText,
192             innerTextField = innerTextField,
193             placeholder = placeholder,
194             labelPosition = labelPosition,
195             label = label,
196             leadingIcon = leadingIcon,
197             trailingIcon = trailingIcon,
198             prefix = prefix,
199             suffix = suffix,
200             supportingText = supportingText,
201             singleLine = lineLimits == SingleLine,
202             enabled = enabled,
203             isError = isError,
204             interactionSource = interactionSource,
205             colors = colors,
206             contentPadding = contentPadding,
207             container = container,
208         )
209     }
210 
211     /**
212      * Composable that draws a default container for a [TextField] with an indicator line at the
213      * bottom. You can apply it to a [BasicTextField] using [decorator] or [DecorationBox] to create
214      * a custom text field based on the styling of a Material filled text field. The [TextField]
215      * component applies it automatically.
216      *
217      * @param enabled whether the text field is enabled
218      * @param isError whether the text field's current value is in error
219      * @param interactionSource the [InteractionSource] of the text field. Used to determine if the
220      *   text field is in focus or not
221      * @param modifier the [Modifier] of this container
222      * @param colors [TextFieldColors] used to resolve colors of the text field
223      * @param shape the shape of this container
224      * @param focusedIndicatorLineThickness thickness of the indicator line when the text field is
225      *   focused
226      * @param unfocusedIndicatorLineThickness thickness of the indicator line when the text field is
227      *   not focused
228      */
229     @Composable
230     fun Container(
231         enabled: Boolean,
232         isError: Boolean,
233         interactionSource: InteractionSource,
234         modifier: Modifier = Modifier,
235         colors: TextFieldColors = colors(),
236         shape: Shape = TextFieldDefaults.shape,
237         focusedIndicatorLineThickness: Dp = FocusedIndicatorThickness,
238         unfocusedIndicatorLineThickness: Dp = UnfocusedIndicatorThickness,
239     ) {
240         val focused = interactionSource.collectIsFocusedAsState().value
241         // TODO Load the motionScheme tokens from the component tokens file
242         val containerColor =
243             animateColorAsState(
244                 targetValue = colors.containerColor(enabled, isError, focused),
245                 animationSpec = MotionSchemeKeyTokens.FastEffects.value(),
246             )
247         Box(
248             modifier
249                 .textFieldBackground(containerColor::value, shape)
250                 .indicatorLine(
251                     enabled = enabled,
252                     isError = isError,
253                     interactionSource = interactionSource,
254                     colors = colors,
255                     textFieldShape = shape,
256                     focusedIndicatorLineThickness = focusedIndicatorLineThickness,
257                     unfocusedIndicatorLineThickness = unfocusedIndicatorLineThickness,
258                 )
259         )
260     }
261 
262     /**
263      * A modifier to draw a default bottom indicator line for [TextField]. You can apply it to a
264      * [BasicTextField] to create a custom text field based on the styling of a Material filled text
265      * field.
266      *
267      * Consider using [Container], which automatically applies this modifier as well as other text
268      * field container styling.
269      *
270      * @param enabled whether the text field is enabled
271      * @param isError whether the text field's current value is in error
272      * @param interactionSource the [InteractionSource] of the text field. Used to determine if the
273      *   text field is in focus or not
274      * @param colors [TextFieldColors] used to resolve colors of the text field. If `null`, defaults
275      *   to [TextFieldDefaults.colors].
276      * @param textFieldShape the shape of the text field container. Used for clipping the indicator.
277      *   If `null`, defaults to [TextFieldDefaults.shape].
278      * @param focusedIndicatorLineThickness thickness of the indicator line when the text field is
279      *   focused
280      * @param unfocusedIndicatorLineThickness thickness of the indicator line when the text field is
281      *   not focused
282      */
283     fun Modifier.indicatorLine(
284         enabled: Boolean,
285         isError: Boolean,
286         interactionSource: InteractionSource,
287         colors: TextFieldColors? = null,
288         textFieldShape: Shape? = null,
289         focusedIndicatorLineThickness: Dp = FocusedIndicatorThickness,
290         unfocusedIndicatorLineThickness: Dp = UnfocusedIndicatorThickness
291     ) =
292         this then
293             IndicatorLineElement(
294                 enabled = enabled,
295                 isError = isError,
296                 interactionSource = interactionSource,
297                 colors = colors,
298                 textFieldShape = textFieldShape,
299                 focusedIndicatorLineThickness = focusedIndicatorLineThickness,
300                 unfocusedIndicatorLineThickness = unfocusedIndicatorLineThickness,
301             )
302 
303     /**
304      * A decoration box used to create custom text fields based on
305      * [Material Design filled text field](https://m3.material.io/components/text-fields/overview).
306      *
307      * If your text field requires customising elements that aren't exposed by [TextField], consider
308      * using this decoration box to achieve the desired design.
309      *
310      * For example, if you wish to customise the bottom indicator line, you can pass a custom
311      * [Container] to this decoration box's [container].
312      *
313      * This decoration box is meant to be used in conjunction with overloads of [BasicTextField]
314      * that accept a `decorationBox` parameter. For other overloads of [BasicTextField] that use a
315      * [TextFieldDecorator], see [decorator].
316      *
317      * An example of building a custom text field using [DecorationBox]:
318      *
319      * @sample androidx.compose.material3.samples.CustomTextFieldBasedOnDecorationBox
320      * @param value the input [String] shown by the text field
321      * @param innerTextField input text field that this decoration box wraps. Pass the
322      *   framework-controlled composable parameter `innerTextField` from the `decorationBox` lambda
323      *   of the [BasicTextField]
324      * @param enabled the enabled state of the text field. When `false`, this decoration box will
325      *   appear visually disabled. This must be the same value that is passed to [BasicTextField].
326      * @param singleLine indicates if this is a single line or multi line text field. This must be
327      *   the same value that is passed to [BasicTextField].
328      * @param visualTransformation transforms the visual representation of the input [value]. This
329      *   must be the same value that is passed to [BasicTextField].
330      * @param interactionSource the read-only [InteractionSource] representing the stream of
331      *   [Interaction]s for this text field. You must first create and pass in your own `remember`ed
332      *   [MutableInteractionSource] instance to the [BasicTextField] for it to dispatch events. And
333      *   then pass the same instance to this decoration box to observe [Interaction]s and customize
334      *   the appearance / behavior of this text field in different states.
335      * @param isError indicates if the text field's current value is in an error state. When `true`,
336      *   this decoration box will display its contents in an error color.
337      * @param label the optional label to be displayed with this text field. The default text style
338      *   uses [Typography.bodySmall] when minimized and [Typography.bodyLarge] when expanded.
339      * @param placeholder the optional placeholder to be displayed when the text field is in focus
340      *   and the input text is empty. The default text style for internal [Text] is
341      *   [Typography.bodyLarge].
342      * @param leadingIcon the optional leading icon to be displayed at the beginning of the text
343      *   field container
344      * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
345      *   container
346      * @param prefix the optional prefix to be displayed before the input text in the text field
347      * @param suffix the optional suffix to be displayed after the input text in the text field
348      * @param supportingText the optional supporting text to be displayed below the text field
349      * @param shape defines the shape of this decoration box's container
350      * @param colors [TextFieldColors] that will be used to resolve the colors used for this text
351      *   field decoration box in different states. See [TextFieldDefaults.colors].
352      * @param contentPadding the padding between the input field and the surrounding elements of the
353      *   decoration box. Note that the padding values may not be respected if they are incompatible
354      *   with the text field's size constraints or layout. See
355      *   [TextFieldDefaults.contentPaddingWithLabel] and
356      *   [TextFieldDefaults.contentPaddingWithoutLabel].
357      * @param container the container to be drawn behind the text field. By default, this uses
358      *   [Container]. Default colors for the container come from the [colors].
359      */
360     @Composable
361     fun DecorationBox(
362         value: String,
363         innerTextField: @Composable () -> Unit,
364         enabled: Boolean,
365         singleLine: Boolean,
366         visualTransformation: VisualTransformation,
367         interactionSource: InteractionSource,
368         isError: Boolean = false,
369         label: @Composable (() -> Unit)? = null,
370         placeholder: @Composable (() -> Unit)? = null,
371         leadingIcon: @Composable (() -> Unit)? = null,
372         trailingIcon: @Composable (() -> Unit)? = null,
373         prefix: @Composable (() -> Unit)? = null,
374         suffix: @Composable (() -> Unit)? = null,
375         supportingText: @Composable (() -> Unit)? = null,
376         shape: Shape = TextFieldDefaults.shape,
377         colors: TextFieldColors = colors(),
378         contentPadding: PaddingValues =
379             if (label == null) {
380                 contentPaddingWithoutLabel()
381             } else {
382                 contentPaddingWithLabel()
383             },
384         container: @Composable () -> Unit = {
385             Container(
386                 enabled = enabled,
387                 isError = isError,
388                 interactionSource = interactionSource,
389                 modifier = Modifier,
390                 colors = colors,
391                 shape = shape,
392                 focusedIndicatorLineThickness = FocusedIndicatorThickness,
393                 unfocusedIndicatorLineThickness = UnfocusedIndicatorThickness,
394             )
395         }
396     ) {
397         val visualText =
398             remember(value, visualTransformation) {
399                     visualTransformation.filter(AnnotatedString(value))
400                 }
401                 .text
402                 .text
403 
404         CommonDecorationBox(
405             type = TextFieldType.Filled,
406             visualText = visualText,
407             innerTextField = innerTextField,
408             placeholder = placeholder,
409             labelPosition = TextFieldLabelPosition.Attached(),
410             label = label?.let { { it.invoke() } },
411             leadingIcon = leadingIcon,
412             trailingIcon = trailingIcon,
413             prefix = prefix,
414             suffix = suffix,
415             supportingText = supportingText,
416             singleLine = singleLine,
417             enabled = enabled,
418             isError = isError,
419             interactionSource = interactionSource,
420             colors = colors,
421             contentPadding = contentPadding,
422             container = container,
423         )
424     }
425 
426     /**
427      * Default content padding of the input field within the [TextField] when there is an inside
428      * label. Note that the top padding represents the padding above the label in the focused state.
429      * The input field is placed directly beneath the label.
430      *
431      * Horizontal padding represents the distance between the input field and the leading/trailing
432      * icons (if present) or the horizontal edges of the container if there are no icons.
433      */
434     fun contentPaddingWithLabel(
435         start: Dp = TextFieldPadding,
436         end: Dp = TextFieldPadding,
437         top: Dp = TextFieldWithLabelVerticalPadding,
438         bottom: Dp = TextFieldWithLabelVerticalPadding
439     ): PaddingValues = PaddingValues(start, top, end, bottom)
440 
441     /**
442      * Default content padding of the input field within the [TextField] when the label is null or
443      * positioned [TextFieldLabelPosition.Above].
444      *
445      * Horizontal padding represents the distance between the input field and the leading/trailing
446      * icons (if present) or the horizontal edges of the container if there are no icons.
447      */
448     fun contentPaddingWithoutLabel(
449         start: Dp = TextFieldPadding,
450         top: Dp = TextFieldPadding,
451         end: Dp = TextFieldPadding,
452         bottom: Dp = TextFieldPadding
453     ): PaddingValues = PaddingValues(start, top, end, bottom)
454 
455     /**
456      * Default padding applied to supporting text for both [TextField] and [OutlinedTextField]. See
457      * [PaddingValues] for more details.
458      */
459     // TODO(246775477): consider making this public
460     internal fun supportingTextPadding(
461         start: Dp = TextFieldPadding,
462         top: Dp = SupportingTopPadding,
463         end: Dp = TextFieldPadding,
464         bottom: Dp = 0.dp,
465     ): PaddingValues = PaddingValues(start, top, end, bottom)
466 
467     /**
468      * Creates a [TextFieldColors] that represents the default input text, container, and content
469      * colors (including label, placeholder, icons, etc.) used in a [TextField].
470      */
471     @Composable
472     fun colors() =
473         MaterialTheme.colorScheme.defaultTextFieldColors(LocalTextSelectionColors.current)
474 
475     /**
476      * Creates a [TextFieldColors] that represents the default input text, container, and content
477      * colors (including label, placeholder, icons, etc.) used in a [TextField].
478      *
479      * @param focusedTextColor the color used for the input text of this text field when focused
480      * @param unfocusedTextColor the color used for the input text of this text field when not
481      *   focused
482      * @param disabledTextColor the color used for the input text of this text field when disabled
483      * @param errorTextColor the color used for the input text of this text field when in error
484      *   state
485      * @param focusedContainerColor the container color for this text field when focused
486      * @param unfocusedContainerColor the container color for this text field when not focused
487      * @param disabledContainerColor the container color for this text field when disabled
488      * @param errorContainerColor the container color for this text field when in error state
489      * @param cursorColor the cursor color for this text field
490      * @param errorCursorColor the cursor color for this text field when in error state
491      * @param selectionColors the colors used when the input text of this text field is selected
492      * @param focusedIndicatorColor the indicator color for this text field when focused
493      * @param unfocusedIndicatorColor the indicator color for this text field when not focused
494      * @param disabledIndicatorColor the indicator color for this text field when disabled
495      * @param errorIndicatorColor the indicator color for this text field when in error state
496      * @param focusedLeadingIconColor the leading icon color for this text field when focused
497      * @param unfocusedLeadingIconColor the leading icon color for this text field when not focused
498      * @param disabledLeadingIconColor the leading icon color for this text field when disabled
499      * @param errorLeadingIconColor the leading icon color for this text field when in error state
500      * @param focusedTrailingIconColor the trailing icon color for this text field when focused
501      * @param unfocusedTrailingIconColor the trailing icon color for this text field when not
502      *   focused
503      * @param disabledTrailingIconColor the trailing icon color for this text field when disabled
504      * @param errorTrailingIconColor the trailing icon color for this text field when in error state
505      * @param focusedLabelColor the label color for this text field when focused
506      * @param unfocusedLabelColor the label color for this text field when not focused
507      * @param disabledLabelColor the label color for this text field when disabled
508      * @param errorLabelColor the label color for this text field when in error state
509      * @param focusedPlaceholderColor the placeholder color for this text field when focused
510      * @param unfocusedPlaceholderColor the placeholder color for this text field when not focused
511      * @param disabledPlaceholderColor the placeholder color for this text field when disabled
512      * @param errorPlaceholderColor the placeholder color for this text field when in error state
513      * @param focusedSupportingTextColor the supporting text color for this text field when focused
514      * @param unfocusedSupportingTextColor the supporting text color for this text field when not
515      *   focused
516      * @param disabledSupportingTextColor the supporting text color for this text field when
517      *   disabled
518      * @param errorSupportingTextColor the supporting text color for this text field when in error
519      *   state
520      * @param focusedPrefixColor the prefix color for this text field when focused
521      * @param unfocusedPrefixColor the prefix color for this text field when not focused
522      * @param disabledPrefixColor the prefix color for this text field when disabled
523      * @param errorPrefixColor the prefix color for this text field when in error state
524      * @param focusedSuffixColor the suffix color for this text field when focused
525      * @param unfocusedSuffixColor the suffix color for this text field when not focused
526      * @param disabledSuffixColor the suffix color for this text field when disabled
527      * @param errorSuffixColor the suffix color for this text field when in error state
528      */
529     @Composable
530     fun colors(
531         focusedTextColor: Color = Color.Unspecified,
532         unfocusedTextColor: Color = Color.Unspecified,
533         disabledTextColor: Color = Color.Unspecified,
534         errorTextColor: Color = Color.Unspecified,
535         focusedContainerColor: Color = Color.Unspecified,
536         unfocusedContainerColor: Color = Color.Unspecified,
537         disabledContainerColor: Color = Color.Unspecified,
538         errorContainerColor: Color = Color.Unspecified,
539         cursorColor: Color = Color.Unspecified,
540         errorCursorColor: Color = Color.Unspecified,
541         selectionColors: TextSelectionColors? = null,
542         focusedIndicatorColor: Color = Color.Unspecified,
543         unfocusedIndicatorColor: Color = Color.Unspecified,
544         disabledIndicatorColor: Color = Color.Unspecified,
545         errorIndicatorColor: Color = Color.Unspecified,
546         focusedLeadingIconColor: Color = Color.Unspecified,
547         unfocusedLeadingIconColor: Color = Color.Unspecified,
548         disabledLeadingIconColor: Color = Color.Unspecified,
549         errorLeadingIconColor: Color = Color.Unspecified,
550         focusedTrailingIconColor: Color = Color.Unspecified,
551         unfocusedTrailingIconColor: Color = Color.Unspecified,
552         disabledTrailingIconColor: Color = Color.Unspecified,
553         errorTrailingIconColor: Color = Color.Unspecified,
554         focusedLabelColor: Color = Color.Unspecified,
555         unfocusedLabelColor: Color = Color.Unspecified,
556         disabledLabelColor: Color = Color.Unspecified,
557         errorLabelColor: Color = Color.Unspecified,
558         focusedPlaceholderColor: Color = Color.Unspecified,
559         unfocusedPlaceholderColor: Color = Color.Unspecified,
560         disabledPlaceholderColor: Color = Color.Unspecified,
561         errorPlaceholderColor: Color = Color.Unspecified,
562         focusedSupportingTextColor: Color = Color.Unspecified,
563         unfocusedSupportingTextColor: Color = Color.Unspecified,
564         disabledSupportingTextColor: Color = Color.Unspecified,
565         errorSupportingTextColor: Color = Color.Unspecified,
566         focusedPrefixColor: Color = Color.Unspecified,
567         unfocusedPrefixColor: Color = Color.Unspecified,
568         disabledPrefixColor: Color = Color.Unspecified,
569         errorPrefixColor: Color = Color.Unspecified,
570         focusedSuffixColor: Color = Color.Unspecified,
571         unfocusedSuffixColor: Color = Color.Unspecified,
572         disabledSuffixColor: Color = Color.Unspecified,
573         errorSuffixColor: Color = Color.Unspecified,
574     ): TextFieldColors =
575         MaterialTheme.colorScheme
576             .defaultTextFieldColors(LocalTextSelectionColors.current)
577             .copy(
578                 focusedTextColor = focusedTextColor,
579                 unfocusedTextColor = unfocusedTextColor,
580                 disabledTextColor = disabledTextColor,
581                 errorTextColor = errorTextColor,
582                 focusedContainerColor = focusedContainerColor,
583                 unfocusedContainerColor = unfocusedContainerColor,
584                 disabledContainerColor = disabledContainerColor,
585                 errorContainerColor = errorContainerColor,
586                 cursorColor = cursorColor,
587                 errorCursorColor = errorCursorColor,
588                 textSelectionColors = selectionColors,
589                 focusedIndicatorColor = focusedIndicatorColor,
590                 unfocusedIndicatorColor = unfocusedIndicatorColor,
591                 disabledIndicatorColor = disabledIndicatorColor,
592                 errorIndicatorColor = errorIndicatorColor,
593                 focusedLeadingIconColor = focusedLeadingIconColor,
594                 unfocusedLeadingIconColor = unfocusedLeadingIconColor,
595                 disabledLeadingIconColor = disabledLeadingIconColor,
596                 errorLeadingIconColor = errorLeadingIconColor,
597                 focusedTrailingIconColor = focusedTrailingIconColor,
598                 unfocusedTrailingIconColor = unfocusedTrailingIconColor,
599                 disabledTrailingIconColor = disabledTrailingIconColor,
600                 errorTrailingIconColor = errorTrailingIconColor,
601                 focusedLabelColor = focusedLabelColor,
602                 unfocusedLabelColor = unfocusedLabelColor,
603                 disabledLabelColor = disabledLabelColor,
604                 errorLabelColor = errorLabelColor,
605                 focusedPlaceholderColor = focusedPlaceholderColor,
606                 unfocusedPlaceholderColor = unfocusedPlaceholderColor,
607                 disabledPlaceholderColor = disabledPlaceholderColor,
608                 errorPlaceholderColor = errorPlaceholderColor,
609                 focusedSupportingTextColor = focusedSupportingTextColor,
610                 unfocusedSupportingTextColor = unfocusedSupportingTextColor,
611                 disabledSupportingTextColor = disabledSupportingTextColor,
612                 errorSupportingTextColor = errorSupportingTextColor,
613                 focusedPrefixColor = focusedPrefixColor,
614                 unfocusedPrefixColor = unfocusedPrefixColor,
615                 disabledPrefixColor = disabledPrefixColor,
616                 errorPrefixColor = errorPrefixColor,
617                 focusedSuffixColor = focusedSuffixColor,
618                 unfocusedSuffixColor = unfocusedSuffixColor,
619                 disabledSuffixColor = disabledSuffixColor,
620                 errorSuffixColor = errorSuffixColor,
621             )
622 
623     internal fun ColorScheme.defaultTextFieldColors(
624         localTextSelectionColors: TextSelectionColors
625     ): TextFieldColors {
626         return defaultTextFieldColorsCached?.let { cachedColors ->
627             if (cachedColors.textSelectionColors == localTextSelectionColors) {
628                 cachedColors
629             } else {
630                 cachedColors.copy(textSelectionColors = localTextSelectionColors).also {
631                     defaultTextFieldColorsCached = it
632                 }
633             }
634         }
635             ?: TextFieldColors(
636                     focusedTextColor = fromToken(FilledTextFieldTokens.FocusInputColor),
637                     unfocusedTextColor = fromToken(FilledTextFieldTokens.InputColor),
638                     disabledTextColor =
639                         fromToken(FilledTextFieldTokens.DisabledInputColor)
640                             .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
641                     errorTextColor = fromToken(FilledTextFieldTokens.ErrorInputColor),
642                     focusedContainerColor = fromToken(FilledTextFieldTokens.ContainerColor),
643                     unfocusedContainerColor = fromToken(FilledTextFieldTokens.ContainerColor),
644                     disabledContainerColor = fromToken(FilledTextFieldTokens.ContainerColor),
645                     errorContainerColor = fromToken(FilledTextFieldTokens.ContainerColor),
646                     cursorColor = fromToken(FilledTextFieldTokens.CaretColor),
647                     errorCursorColor = fromToken(FilledTextFieldTokens.ErrorFocusCaretColor),
648                     textSelectionColors = localTextSelectionColors,
649                     focusedIndicatorColor =
650                         fromToken(FilledTextFieldTokens.FocusActiveIndicatorColor),
651                     unfocusedIndicatorColor = fromToken(FilledTextFieldTokens.ActiveIndicatorColor),
652                     disabledIndicatorColor =
653                         fromToken(FilledTextFieldTokens.DisabledActiveIndicatorColor)
654                             .copy(alpha = FilledTextFieldTokens.DisabledActiveIndicatorOpacity),
655                     errorIndicatorColor =
656                         fromToken(FilledTextFieldTokens.ErrorActiveIndicatorColor),
657                     focusedLeadingIconColor =
658                         fromToken(FilledTextFieldTokens.FocusLeadingIconColor),
659                     unfocusedLeadingIconColor = fromToken(FilledTextFieldTokens.LeadingIconColor),
660                     disabledLeadingIconColor =
661                         fromToken(FilledTextFieldTokens.DisabledLeadingIconColor)
662                             .copy(alpha = FilledTextFieldTokens.DisabledLeadingIconOpacity),
663                     errorLeadingIconColor = fromToken(FilledTextFieldTokens.ErrorLeadingIconColor),
664                     focusedTrailingIconColor =
665                         fromToken(FilledTextFieldTokens.FocusTrailingIconColor),
666                     unfocusedTrailingIconColor = fromToken(FilledTextFieldTokens.TrailingIconColor),
667                     disabledTrailingIconColor =
668                         fromToken(FilledTextFieldTokens.DisabledTrailingIconColor)
669                             .copy(alpha = FilledTextFieldTokens.DisabledTrailingIconOpacity),
670                     errorTrailingIconColor =
671                         fromToken(FilledTextFieldTokens.ErrorTrailingIconColor),
672                     focusedLabelColor = fromToken(FilledTextFieldTokens.FocusLabelColor),
673                     unfocusedLabelColor = fromToken(FilledTextFieldTokens.LabelColor),
674                     disabledLabelColor =
675                         fromToken(FilledTextFieldTokens.DisabledLabelColor)
676                             .copy(alpha = FilledTextFieldTokens.DisabledLabelOpacity),
677                     errorLabelColor = fromToken(FilledTextFieldTokens.ErrorLabelColor),
678                     focusedPlaceholderColor =
679                         fromToken(FilledTextFieldTokens.InputPlaceholderColor),
680                     unfocusedPlaceholderColor =
681                         fromToken(FilledTextFieldTokens.InputPlaceholderColor),
682                     disabledPlaceholderColor =
683                         fromToken(FilledTextFieldTokens.DisabledInputColor)
684                             .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
685                     errorPlaceholderColor = fromToken(FilledTextFieldTokens.InputPlaceholderColor),
686                     focusedSupportingTextColor =
687                         fromToken(FilledTextFieldTokens.FocusSupportingColor),
688                     unfocusedSupportingTextColor = fromToken(FilledTextFieldTokens.SupportingColor),
689                     disabledSupportingTextColor =
690                         fromToken(FilledTextFieldTokens.DisabledSupportingColor)
691                             .copy(alpha = FilledTextFieldTokens.DisabledSupportingOpacity),
692                     errorSupportingTextColor =
693                         fromToken(FilledTextFieldTokens.ErrorSupportingColor),
694                     focusedPrefixColor = fromToken(FilledTextFieldTokens.InputPrefixColor),
695                     unfocusedPrefixColor = fromToken(FilledTextFieldTokens.InputPrefixColor),
696                     disabledPrefixColor =
697                         fromToken(FilledTextFieldTokens.InputPrefixColor)
698                             .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
699                     errorPrefixColor = fromToken(FilledTextFieldTokens.InputPrefixColor),
700                     focusedSuffixColor = fromToken(FilledTextFieldTokens.InputSuffixColor),
701                     unfocusedSuffixColor = fromToken(FilledTextFieldTokens.InputSuffixColor),
702                     disabledSuffixColor =
703                         fromToken(FilledTextFieldTokens.InputSuffixColor)
704                             .copy(alpha = FilledTextFieldTokens.DisabledInputOpacity),
705                     errorSuffixColor = fromToken(FilledTextFieldTokens.InputSuffixColor),
706                 )
707                 .also { defaultTextFieldColorsCached = it }
708     }
709 
710     @Deprecated(
711         level = DeprecationLevel.HIDDEN,
712         message = "Maintained for binary compatibility. Use overload with `textFieldShape`.",
713     )
714     @ExperimentalMaterial3Api
715     fun Modifier.indicatorLine(
716         enabled: Boolean,
717         isError: Boolean,
718         interactionSource: InteractionSource,
719         colors: TextFieldColors,
720         focusedIndicatorLineThickness: Dp = FocusedIndicatorThickness,
721         unfocusedIndicatorLineThickness: Dp = UnfocusedIndicatorThickness
722     ) =
723         indicatorLine(
724             enabled = enabled,
725             isError = isError,
726             interactionSource = interactionSource,
727             colors = colors,
728             textFieldShape = null,
729             focusedIndicatorLineThickness = focusedIndicatorLineThickness,
730             unfocusedIndicatorLineThickness = unfocusedIndicatorLineThickness,
731         )
732 
733     @Deprecated(
734         message = "Renamed to TextFieldDefaults.Container",
735         replaceWith =
736             ReplaceWith(
737                 "Container(\n" +
738                     "    enabled = enabled,\n" +
739                     "    isError = isError,\n" +
740                     "    interactionSource = interactionSource,\n" +
741                     "    colors = colors,\n" +
742                     "    shape = shape,\n" +
743                     ")"
744             ),
745         level = DeprecationLevel.WARNING
746     )
747     @ExperimentalMaterial3Api
748     @Composable
749     fun ContainerBox(
750         enabled: Boolean,
751         isError: Boolean,
752         interactionSource: InteractionSource,
753         colors: TextFieldColors,
754         shape: Shape = TextFieldDefaults.shape,
755     ) =
756         Container(
757             enabled = enabled,
758             isError = isError,
759             interactionSource = interactionSource,
760             modifier = Modifier,
761             colors = colors,
762             shape = shape,
763             focusedIndicatorLineThickness = FocusedIndicatorThickness,
764             unfocusedIndicatorLineThickness = UnfocusedIndicatorThickness,
765         )
766 
767     @Deprecated(
768         message = "Renamed to `OutlinedTextFieldDefaults.shape`",
769         replaceWith =
770             ReplaceWith(
771                 "OutlinedTextFieldDefaults.shape",
772                 "androidx.compose.material.OutlinedTextFieldDefaults"
773             ),
774         level = DeprecationLevel.WARNING
775     )
776     val outlinedShape: Shape
777         @Composable get() = OutlinedTextFieldDefaults.shape
778 
779     @Deprecated(
780         message = "Renamed to `TextFieldDefaults.shape`",
781         replaceWith = ReplaceWith("TextFieldDefaults.shape"),
782         level = DeprecationLevel.WARNING
783     )
784     val filledShape: Shape
785         @Composable get() = shape
786 
787     @Deprecated(
788         message =
789             "Split into `TextFieldDefaults.UnfocusedIndicatorThickness` and " +
790                 "`OutlinedTextFieldDefaults.UnfocusedBorderThickness`. Please update as appropriate.",
791         replaceWith = ReplaceWith("TextFieldDefaults.UnfocusedIndicatorThickness"),
792         level = DeprecationLevel.WARNING,
793     )
794     val UnfocusedBorderThickness = UnfocusedIndicatorThickness
795 
796     @Deprecated(
797         message =
798             "Split into `TextFieldDefaults.FocusedIndicatorThickness` and " +
799                 "`OutlinedTextFieldDefaults.FocusedBorderThickness`. Please update as appropriate.",
800         replaceWith = ReplaceWith("TextFieldDefaults.FocusedIndicatorThickness"),
801         level = DeprecationLevel.WARNING,
802     )
803     val FocusedBorderThickness = FocusedIndicatorThickness
804 
805     @Deprecated(
806         message = "Renamed to `TextFieldDefaults.contentPaddingWithLabel`",
807         replaceWith =
808             ReplaceWith(
809                 "TextFieldDefaults.contentPaddingWithLabel(\n" +
810                     "        start = start,\n" +
811                     "        top = top,\n" +
812                     "        end = end,\n" +
813                     "        bottom = bottom,\n" +
814                     "    )"
815             ),
816         level = DeprecationLevel.WARNING
817     )
818     fun textFieldWithLabelPadding(
819         start: Dp = TextFieldPadding,
820         end: Dp = TextFieldPadding,
821         top: Dp = TextFieldWithLabelVerticalPadding,
822         bottom: Dp = TextFieldWithLabelVerticalPadding
823     ): PaddingValues =
824         contentPaddingWithLabel(
825             start = start,
826             top = top,
827             end = end,
828             bottom = bottom,
829         )
830 
831     @Deprecated(
832         message = "Renamed to `TextFieldDefaults.contentPaddingWithoutLabel`",
833         replaceWith =
834             ReplaceWith(
835                 "TextFieldDefaults.contentPaddingWithoutLabel(\n" +
836                     "        start = start,\n" +
837                     "        top = top,\n" +
838                     "        end = end,\n" +
839                     "        bottom = bottom,\n" +
840                     "    )"
841             ),
842         level = DeprecationLevel.WARNING
843     )
844     fun textFieldWithoutLabelPadding(
845         start: Dp = TextFieldPadding,
846         top: Dp = TextFieldPadding,
847         end: Dp = TextFieldPadding,
848         bottom: Dp = TextFieldPadding
849     ): PaddingValues =
850         contentPaddingWithoutLabel(
851             start = start,
852             top = top,
853             end = end,
854             bottom = bottom,
855         )
856 
857     @Deprecated(
858         message = "Renamed to `OutlinedTextFieldDefaults.contentPadding`",
859         replaceWith =
860             ReplaceWith(
861                 "OutlinedTextFieldDefaults.contentPadding(\n" +
862                     "        start = start,\n" +
863                     "        top = top,\n" +
864                     "        end = end,\n" +
865                     "        bottom = bottom,\n" +
866                     "    )",
867                 "androidx.compose.material.OutlinedTextFieldDefaults"
868             ),
869         level = DeprecationLevel.WARNING
870     )
871     fun outlinedTextFieldPadding(
872         start: Dp = TextFieldPadding,
873         top: Dp = TextFieldPadding,
874         end: Dp = TextFieldPadding,
875         bottom: Dp = TextFieldPadding
876     ): PaddingValues =
877         OutlinedTextFieldDefaults.contentPadding(
878             start = start,
879             top = top,
880             end = end,
881             bottom = bottom,
882         )
883 }
884 
885 /**
886  * Contains the default values used by [OutlinedTextField]. For defaults used in [TextField], see
887  * [TextFieldDefaults].
888  */
889 @Immutable
890 object OutlinedTextFieldDefaults {
891     /** Default shape for an [OutlinedTextField]. */
892     val shape: Shape
893         @Composable get() = OutlinedTextFieldTokens.ContainerShape.value
894 
895     /**
896      * The default min height applied to an [OutlinedTextField]. Note that you can override it by
897      * applying Modifier.heightIn directly on a text field.
898      */
899     val MinHeight = 56.dp
900 
901     /**
902      * The default min width applied to an [OutlinedTextField]. Note that you can override it by
903      * applying Modifier.widthIn directly on a text field.
904      */
905     val MinWidth = 280.dp
906 
907     /** The default thickness of the border in [OutlinedTextField] in unfocused state. */
908     val UnfocusedBorderThickness = 1.dp
909 
910     /** The default thickness of the border in [OutlinedTextField] in focused state. */
911     val FocusedBorderThickness = 2.dp
912 
913     /**
914      * A decorator used to create custom text fields based on
915      * [Material Design outlined text field](https://m3.material.io/components/text-fields/overview).
916      *
917      * If your text field requires customising elements that aren't exposed by [OutlinedTextField],
918      * such as the border thickness, consider using this decorator to achieve the desired design.
919      *
920      * For example, if you wish to customize the thickness of the border, you can pass a custom
921      * [Container] to this decoration box's [container].
922      *
923      * This decorator is meant to be used in conjunction with the overload of [BasicTextField] that
924      * accepts a [TextFieldDecorator] parameter. For other overloads of [BasicTextField] that use a
925      * `decorationBox`, see [DecorationBox].
926      *
927      * An example of building a custom text field using [decorator]:
928      *
929      * @sample androidx.compose.material3.samples.CustomOutlinedTextFieldUsingDecorator
930      * @param state [TextFieldState] object that holds the internal editing state of the text field.
931      * @param enabled the enabled state of the text field. When `false`, this decorator will appear
932      *   visually disabled. This must be the same value that is passed to [BasicTextField].
933      * @param lineLimits whether the text field is [SingleLine] or [MultiLine]. This must be the
934      *   same value that is passed to [BasicTextField].
935      * @param outputTransformation [OutputTransformation] that transforms how the contents of the
936      *   text field are presented. This must be the same value that is passed to [BasicTextField].
937      * @param interactionSource the read-only [InteractionSource] representing the stream of
938      *   [Interaction]s for this text field. You must first create and pass in your own `remember`ed
939      *   [MutableInteractionSource] instance to the [BasicTextField] for it to dispatch events. And
940      *   then pass the same instance to this decorator to observe [Interaction]s and customize the
941      *   appearance/behavior of the text field in different states.
942      * @param labelPosition the position of the label. See [TextFieldLabelPosition].
943      * @param label the optional label to be displayed with this text field. The default text style
944      *   uses [Typography.bodySmall] when minimized and [Typography.bodyLarge] when expanded.
945      * @param placeholder the optional placeholder to be displayed when the input text is empty. The
946      *   default text style uses [Typography.bodyLarge].
947      * @param leadingIcon the optional leading icon to be displayed at the beginning of the text
948      *   field container.
949      * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
950      *   container.
951      * @param prefix the optional prefix to be displayed before the input text in the text field.
952      * @param suffix the optional suffix to be displayed after the input text in the text field.
953      * @param supportingText the optional supporting text to be displayed below the text field.
954      * @param isError indicates if the text field's current value is in an error state. When `true`,
955      *   this decorator will display its contents in an error color.
956      * @param colors [TextFieldColors] that will be used to resolve the colors used for this text
957      *   field decorator in different states. See [OutlinedTextFieldDefaults.colors].
958      * @param contentPadding the padding between the input field and the surrounding elements of the
959      *   decorator. Note that the padding values may not be respected if they are incompatible with
960      *   the text field's size constraints or layout. See
961      *   [OutlinedTextFieldDefaults.contentPadding].
962      * @param container the container to be drawn behind the text field. By default, this is
963      *   transparent and only includes a border. The cutout in the border to fit the [label] will be
964      *   automatically added by the framework. Default colors for the container come from the
965      *   [colors].
966      */
967     @Composable
decoratornull968     fun decorator(
969         state: TextFieldState,
970         enabled: Boolean,
971         lineLimits: TextFieldLineLimits,
972         outputTransformation: OutputTransformation?,
973         interactionSource: InteractionSource,
974         labelPosition: TextFieldLabelPosition = TextFieldLabelPosition.Attached(),
975         label: @Composable (TextFieldLabelScope.() -> Unit)? = null,
976         placeholder: @Composable (() -> Unit)? = null,
977         leadingIcon: @Composable (() -> Unit)? = null,
978         trailingIcon: @Composable (() -> Unit)? = null,
979         prefix: @Composable (() -> Unit)? = null,
980         suffix: @Composable (() -> Unit)? = null,
981         supportingText: @Composable (() -> Unit)? = null,
982         isError: Boolean = false,
983         colors: TextFieldColors = colors(),
984         contentPadding: PaddingValues = contentPadding(),
985         container: @Composable () -> Unit = {
986             Container(
987                 enabled = enabled,
988                 isError = isError,
989                 interactionSource = interactionSource,
990                 colors = colors,
991                 shape = shape,
992                 focusedBorderThickness = FocusedBorderThickness,
993                 unfocusedBorderThickness = UnfocusedBorderThickness,
994             )
995         }
996     ): TextFieldDecorator = TextFieldDecorator { innerTextField ->
997         val visualText =
998             if (outputTransformation == null) state.text
999             else {
1000                 // TODO: use constructor to create TextFieldBuffer from TextFieldState when
1001                 // available
1002                 lateinit var buffer: TextFieldBuffer
<lambda>null1003                 state.edit { buffer = this }
1004                 // after edit completes, mutations on buffer are ineffective
<lambda>null1005                 with(outputTransformation) { buffer.transformOutput() }
1006                 buffer.asCharSequence()
1007             }
1008 
1009         CommonDecorationBox(
1010             type = TextFieldType.Outlined,
1011             visualText = visualText,
1012             innerTextField = innerTextField,
1013             placeholder = placeholder,
1014             labelPosition = labelPosition,
1015             label = label,
1016             leadingIcon = leadingIcon,
1017             trailingIcon = trailingIcon,
1018             prefix = prefix,
1019             suffix = suffix,
1020             supportingText = supportingText,
1021             singleLine = lineLimits == SingleLine,
1022             enabled = enabled,
1023             isError = isError,
1024             interactionSource = interactionSource,
1025             colors = colors,
1026             contentPadding = contentPadding,
1027             container = container,
1028         )
1029     }
1030 
1031     /**
1032      * Composable that draws a default container for an [OutlinedTextField] with a border stroke.
1033      * You can apply it to a [BasicTextField] using [decorator] or [DecorationBox] to create a
1034      * custom text field based on the styling of a Material outlined text field. The
1035      * [OutlinedTextField] component applies it automatically.
1036      *
1037      * @param enabled whether the text field is enabled
1038      * @param isError whether the text field's current value is in error
1039      * @param interactionSource the [InteractionSource] of the text field. Used to determine if the
1040      *   text field is in focus or not
1041      * @param modifier the [Modifier] of this container
1042      * @param colors [TextFieldColors] used to resolve colors of the text field
1043      * @param shape the shape of this container
1044      * @param focusedBorderThickness thickness of the border when the text field is focused
1045      * @param unfocusedBorderThickness thickness of the border when the text field is not focused
1046      */
1047     @Composable
Containernull1048     fun Container(
1049         enabled: Boolean,
1050         isError: Boolean,
1051         interactionSource: InteractionSource,
1052         modifier: Modifier = Modifier,
1053         colors: TextFieldColors = colors(),
1054         shape: Shape = OutlinedTextFieldDefaults.shape,
1055         focusedBorderThickness: Dp = FocusedBorderThickness,
1056         unfocusedBorderThickness: Dp = UnfocusedBorderThickness,
1057     ) {
1058         val focused = interactionSource.collectIsFocusedAsState().value
1059         val borderStroke =
1060             animateBorderStrokeAsState(
1061                 enabled,
1062                 isError,
1063                 focused,
1064                 colors,
1065                 focusedBorderThickness,
1066                 unfocusedBorderThickness,
1067             )
1068         // TODO Load the motionScheme tokens from the component tokens file
1069         val containerColor =
1070             animateColorAsState(
1071                 targetValue = colors.containerColor(enabled, isError, focused),
1072                 animationSpec = MotionSchemeKeyTokens.FastEffects.value(),
1073             )
1074         Box(
1075             modifier
1076                 .border(borderStroke.value, shape)
1077                 .textFieldBackground(containerColor::value, shape)
1078         )
1079     }
1080 
1081     /**
1082      * A decoration box used to create custom text fields based on
1083      * [Material Design outlined text field](https://m3.material.io/components/text-fields/overview).
1084      *
1085      * If your text field requires customising elements that aren't exposed by [OutlinedTextField],
1086      * consider using this decoration box to achieve the desired design.
1087      *
1088      * For example, if you wish to customize the thickness of the border, you can pass a custom
1089      * [Container] to this decoration box's [container].
1090      *
1091      * This decoration box is meant to be used in conjunction with overloads of [BasicTextField]
1092      * that accept a `decorationBox` parameter. For other overloads of [BasicTextField] that use a
1093      * [TextFieldDecorator], see [decorator].
1094      *
1095      * An example of building a custom text field using [DecorationBox]:
1096      *
1097      * @sample androidx.compose.material3.samples.CustomOutlinedTextFieldBasedOnDecorationBox
1098      * @param value the input [String] shown by the text field
1099      * @param innerTextField input text field that this decoration box wraps. Pass the
1100      *   framework-controlled composable parameter `innerTextField` from the `decorationBox` lambda
1101      *   of the [BasicTextField]
1102      * @param enabled the enabled state of the text field. When `false`, this decoration box will
1103      *   appear visually disabled. This must be the same value that is passed to [BasicTextField].
1104      * @param singleLine indicates if this is a single line or multi line text field. This must be
1105      *   the same value that is passed to [BasicTextField].
1106      * @param visualTransformation transforms the visual representation of the input [value]. This
1107      *   must be the same value that is passed to [BasicTextField].
1108      * @param interactionSource the read-only [InteractionSource] representing the stream of
1109      *   [Interaction]s for this text field. You must first create and pass in your own `remember`ed
1110      *   [MutableInteractionSource] instance to the [BasicTextField] for it to dispatch events. And
1111      *   then pass the same instance to this decoration box to observe [Interaction]s and customize
1112      *   the appearance / behavior of this text field in different states.
1113      * @param isError indicates if the text field's current value is in an error state. When `true`,
1114      *   this decoration box will display its contents in an error color.
1115      * @param label the optional label to be displayed with this text field. The default text style
1116      *   uses [Typography.bodySmall] when minimized and [Typography.bodyLarge] when expanded.
1117      * @param placeholder the optional placeholder to be displayed when the text field is in focus
1118      *   and the input text is empty. The default text style for internal [Text] is
1119      *   [Typography.bodyLarge].
1120      * @param leadingIcon the optional leading icon to be displayed at the beginning of the text
1121      *   field container
1122      * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
1123      *   container
1124      * @param prefix the optional prefix to be displayed before the input text in the text field
1125      * @param suffix the optional suffix to be displayed after the input text in the text field
1126      * @param supportingText the optional supporting text to be displayed below the text field
1127      * @param colors [TextFieldColors] that will be used to resolve the colors used for this text
1128      *   field in different states. See [OutlinedTextFieldDefaults.colors].
1129      * @param contentPadding the padding between the input field and the surrounding elements of the
1130      *   decoration box. Note that the padding values may not be respected if they are incompatible
1131      *   with the text field's size constraints or layout. See
1132      *   [OutlinedTextFieldDefaults.contentPadding].
1133      * @param container the container to be drawn behind the text field. By default, this is
1134      *   transparent and only includes a border. The cutout in the border to fit the [label] will be
1135      *   automatically added by the framework. Default colors for the container come from the
1136      *   [colors].
1137      */
1138     @Composable
DecorationBoxnull1139     fun DecorationBox(
1140         value: String,
1141         innerTextField: @Composable () -> Unit,
1142         enabled: Boolean,
1143         singleLine: Boolean,
1144         visualTransformation: VisualTransformation,
1145         interactionSource: InteractionSource,
1146         isError: Boolean = false,
1147         label: @Composable (() -> Unit)? = null,
1148         placeholder: @Composable (() -> Unit)? = null,
1149         leadingIcon: @Composable (() -> Unit)? = null,
1150         trailingIcon: @Composable (() -> Unit)? = null,
1151         prefix: @Composable (() -> Unit)? = null,
1152         suffix: @Composable (() -> Unit)? = null,
1153         supportingText: @Composable (() -> Unit)? = null,
1154         colors: TextFieldColors = colors(),
1155         contentPadding: PaddingValues = contentPadding(),
1156         container: @Composable () -> Unit = {
1157             Container(
1158                 enabled = enabled,
1159                 isError = isError,
1160                 interactionSource = interactionSource,
1161                 modifier = Modifier,
1162                 colors = colors,
1163                 shape = shape,
1164                 focusedBorderThickness = FocusedBorderThickness,
1165                 unfocusedBorderThickness = UnfocusedBorderThickness,
1166             )
1167         }
1168     ) {
1169         val visualText =
<lambda>null1170             remember(value, visualTransformation) {
1171                     visualTransformation.filter(AnnotatedString(value))
1172                 }
1173                 .text
1174                 .text
1175 
1176         CommonDecorationBox(
1177             type = TextFieldType.Outlined,
1178             visualText = visualText,
1179             innerTextField = innerTextField,
1180             placeholder = placeholder,
1181             labelPosition = TextFieldLabelPosition.Attached(),
<lambda>null1182             label = label?.let { { it.invoke() } },
1183             leadingIcon = leadingIcon,
1184             trailingIcon = trailingIcon,
1185             prefix = prefix,
1186             suffix = suffix,
1187             supportingText = supportingText,
1188             singleLine = singleLine,
1189             enabled = enabled,
1190             isError = isError,
1191             interactionSource = interactionSource,
1192             colors = colors,
1193             contentPadding = contentPadding,
1194             container = container,
1195         )
1196     }
1197 
1198     /**
1199      * Default content padding of the input field within the [OutlinedTextField].
1200      *
1201      * Horizontal padding represents the distance between the input field and the leading/trailing
1202      * icons (if present) or the horizontal edges of the container if there are no icons.
1203      */
contentPaddingnull1204     fun contentPadding(
1205         start: Dp = TextFieldPadding,
1206         top: Dp = TextFieldPadding,
1207         end: Dp = TextFieldPadding,
1208         bottom: Dp = TextFieldPadding
1209     ): PaddingValues = PaddingValues(start, top, end, bottom)
1210 
1211     /**
1212      * Creates a [TextFieldColors] that represents the default input text, container, and content
1213      * colors (including label, placeholder, icons, etc.) used in an [OutlinedTextField].
1214      */
1215     @Composable fun colors() = MaterialTheme.colorScheme.defaultOutlinedTextFieldColors
1216 
1217     /**
1218      * Creates a [TextFieldColors] that represents the default input text, container, and content
1219      * colors (including label, placeholder, icons, etc.) used in an [OutlinedTextField].
1220      *
1221      * @param focusedTextColor the color used for the input text of this text field when focused
1222      * @param unfocusedTextColor the color used for the input text of this text field when not
1223      *   focused
1224      * @param disabledTextColor the color used for the input text of this text field when disabled
1225      * @param errorTextColor the color used for the input text of this text field when in error
1226      *   state
1227      * @param focusedContainerColor the container color for this text field when focused
1228      * @param unfocusedContainerColor the container color for this text field when not focused
1229      * @param disabledContainerColor the container color for this text field when disabled
1230      * @param errorContainerColor the container color for this text field when in error state
1231      * @param cursorColor the cursor color for this text field
1232      * @param errorCursorColor the cursor color for this text field when in error state
1233      * @param selectionColors the colors used when the input text of this text field is selected
1234      * @param focusedBorderColor the border color for this text field when focused
1235      * @param unfocusedBorderColor the border color for this text field when not focused
1236      * @param disabledBorderColor the border color for this text field when disabled
1237      * @param errorBorderColor the border color for this text field when in error state
1238      * @param focusedLeadingIconColor the leading icon color for this text field when focused
1239      * @param unfocusedLeadingIconColor the leading icon color for this text field when not focused
1240      * @param disabledLeadingIconColor the leading icon color for this text field when disabled
1241      * @param errorLeadingIconColor the leading icon color for this text field when in error state
1242      * @param focusedTrailingIconColor the trailing icon color for this text field when focused
1243      * @param unfocusedTrailingIconColor the trailing icon color for this text field when not
1244      *   focused
1245      * @param disabledTrailingIconColor the trailing icon color for this text field when disabled
1246      * @param errorTrailingIconColor the trailing icon color for this text field when in error state
1247      * @param focusedLabelColor the label color for this text field when focused
1248      * @param unfocusedLabelColor the label color for this text field when not focused
1249      * @param disabledLabelColor the label color for this text field when disabled
1250      * @param errorLabelColor the label color for this text field when in error state
1251      * @param focusedPlaceholderColor the placeholder color for this text field when focused
1252      * @param unfocusedPlaceholderColor the placeholder color for this text field when not focused
1253      * @param disabledPlaceholderColor the placeholder color for this text field when disabled
1254      * @param errorPlaceholderColor the placeholder color for this text field when in error state
1255      * @param focusedSupportingTextColor the supporting text color for this text field when focused
1256      * @param unfocusedSupportingTextColor the supporting text color for this text field when not
1257      *   focused
1258      * @param disabledSupportingTextColor the supporting text color for this text field when
1259      *   disabled
1260      * @param errorSupportingTextColor the supporting text color for this text field when in error
1261      *   state
1262      * @param focusedPrefixColor the prefix color for this text field when focused
1263      * @param unfocusedPrefixColor the prefix color for this text field when not focused
1264      * @param disabledPrefixColor the prefix color for this text field when disabled
1265      * @param errorPrefixColor the prefix color for this text field when in error state
1266      * @param focusedSuffixColor the suffix color for this text field when focused
1267      * @param unfocusedSuffixColor the suffix color for this text field when not focused
1268      * @param disabledSuffixColor the suffix color for this text field when disabled
1269      * @param errorSuffixColor the suffix color for this text field when in error state
1270      */
1271     @Composable
1272     fun colors(
1273         focusedTextColor: Color = Color.Unspecified,
1274         unfocusedTextColor: Color = Color.Unspecified,
1275         disabledTextColor: Color = Color.Unspecified,
1276         errorTextColor: Color = Color.Unspecified,
1277         focusedContainerColor: Color = Color.Unspecified,
1278         unfocusedContainerColor: Color = Color.Unspecified,
1279         disabledContainerColor: Color = Color.Unspecified,
1280         errorContainerColor: Color = Color.Unspecified,
1281         cursorColor: Color = Color.Unspecified,
1282         errorCursorColor: Color = Color.Unspecified,
1283         selectionColors: TextSelectionColors? = null,
1284         focusedBorderColor: Color = Color.Unspecified,
1285         unfocusedBorderColor: Color = Color.Unspecified,
1286         disabledBorderColor: Color = Color.Unspecified,
1287         errorBorderColor: Color = Color.Unspecified,
1288         focusedLeadingIconColor: Color = Color.Unspecified,
1289         unfocusedLeadingIconColor: Color = Color.Unspecified,
1290         disabledLeadingIconColor: Color = Color.Unspecified,
1291         errorLeadingIconColor: Color = Color.Unspecified,
1292         focusedTrailingIconColor: Color = Color.Unspecified,
1293         unfocusedTrailingIconColor: Color = Color.Unspecified,
1294         disabledTrailingIconColor: Color = Color.Unspecified,
1295         errorTrailingIconColor: Color = Color.Unspecified,
1296         focusedLabelColor: Color = Color.Unspecified,
1297         unfocusedLabelColor: Color = Color.Unspecified,
1298         disabledLabelColor: Color = Color.Unspecified,
1299         errorLabelColor: Color = Color.Unspecified,
1300         focusedPlaceholderColor: Color = Color.Unspecified,
1301         unfocusedPlaceholderColor: Color = Color.Unspecified,
1302         disabledPlaceholderColor: Color = Color.Unspecified,
1303         errorPlaceholderColor: Color = Color.Unspecified,
1304         focusedSupportingTextColor: Color = Color.Unspecified,
1305         unfocusedSupportingTextColor: Color = Color.Unspecified,
1306         disabledSupportingTextColor: Color = Color.Unspecified,
1307         errorSupportingTextColor: Color = Color.Unspecified,
1308         focusedPrefixColor: Color = Color.Unspecified,
1309         unfocusedPrefixColor: Color = Color.Unspecified,
1310         disabledPrefixColor: Color = Color.Unspecified,
1311         errorPrefixColor: Color = Color.Unspecified,
1312         focusedSuffixColor: Color = Color.Unspecified,
1313         unfocusedSuffixColor: Color = Color.Unspecified,
1314         disabledSuffixColor: Color = Color.Unspecified,
1315         errorSuffixColor: Color = Color.Unspecified,
1316     ): TextFieldColors =
1317         MaterialTheme.colorScheme.defaultOutlinedTextFieldColors.copy(
1318             focusedTextColor = focusedTextColor,
1319             unfocusedTextColor = unfocusedTextColor,
1320             disabledTextColor = disabledTextColor,
1321             errorTextColor = errorTextColor,
1322             focusedContainerColor = focusedContainerColor,
1323             unfocusedContainerColor = unfocusedContainerColor,
1324             disabledContainerColor = disabledContainerColor,
1325             errorContainerColor = errorContainerColor,
1326             cursorColor = cursorColor,
1327             errorCursorColor = errorCursorColor,
1328             textSelectionColors = selectionColors,
1329             focusedIndicatorColor = focusedBorderColor,
1330             unfocusedIndicatorColor = unfocusedBorderColor,
1331             disabledIndicatorColor = disabledBorderColor,
1332             errorIndicatorColor = errorBorderColor,
1333             focusedLeadingIconColor = focusedLeadingIconColor,
1334             unfocusedLeadingIconColor = unfocusedLeadingIconColor,
1335             disabledLeadingIconColor = disabledLeadingIconColor,
1336             errorLeadingIconColor = errorLeadingIconColor,
1337             focusedTrailingIconColor = focusedTrailingIconColor,
1338             unfocusedTrailingIconColor = unfocusedTrailingIconColor,
1339             disabledTrailingIconColor = disabledTrailingIconColor,
1340             errorTrailingIconColor = errorTrailingIconColor,
1341             focusedLabelColor = focusedLabelColor,
1342             unfocusedLabelColor = unfocusedLabelColor,
1343             disabledLabelColor = disabledLabelColor,
1344             errorLabelColor = errorLabelColor,
1345             focusedPlaceholderColor = focusedPlaceholderColor,
1346             unfocusedPlaceholderColor = unfocusedPlaceholderColor,
1347             disabledPlaceholderColor = disabledPlaceholderColor,
1348             errorPlaceholderColor = errorPlaceholderColor,
1349             focusedSupportingTextColor = focusedSupportingTextColor,
1350             unfocusedSupportingTextColor = unfocusedSupportingTextColor,
1351             disabledSupportingTextColor = disabledSupportingTextColor,
1352             errorSupportingTextColor = errorSupportingTextColor,
1353             focusedPrefixColor = focusedPrefixColor,
1354             unfocusedPrefixColor = unfocusedPrefixColor,
1355             disabledPrefixColor = disabledPrefixColor,
1356             errorPrefixColor = errorPrefixColor,
1357             focusedSuffixColor = focusedSuffixColor,
1358             unfocusedSuffixColor = unfocusedSuffixColor,
1359             disabledSuffixColor = disabledSuffixColor,
1360             errorSuffixColor = errorSuffixColor,
1361         )
1362 
1363     internal val ColorScheme.defaultOutlinedTextFieldColors: TextFieldColors
1364         @Composable
1365         get() {
1366             return defaultOutlinedTextFieldColorsCached?.let { cachedColors ->
1367                 val localTextSelectionColors = LocalTextSelectionColors.current
1368                 if (cachedColors.textSelectionColors == localTextSelectionColors) {
1369                     cachedColors
1370                 } else {
1371                     cachedColors.copy(textSelectionColors = localTextSelectionColors).also {
1372                         defaultOutlinedTextFieldColorsCached = it
1373                     }
1374                 }
1375             }
1376                 ?: TextFieldColors(
1377                         focusedTextColor = fromToken(OutlinedTextFieldTokens.FocusInputColor),
1378                         unfocusedTextColor = fromToken(OutlinedTextFieldTokens.InputColor),
1379                         disabledTextColor =
1380                             fromToken(OutlinedTextFieldTokens.DisabledInputColor)
1381                                 .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
1382                         errorTextColor = fromToken(OutlinedTextFieldTokens.ErrorInputColor),
1383                         focusedContainerColor = Color.Transparent,
1384                         unfocusedContainerColor = Color.Transparent,
1385                         disabledContainerColor = Color.Transparent,
1386                         errorContainerColor = Color.Transparent,
1387                         cursorColor = fromToken(OutlinedTextFieldTokens.CaretColor),
1388                         errorCursorColor = fromToken(OutlinedTextFieldTokens.ErrorFocusCaretColor),
1389                         textSelectionColors = LocalTextSelectionColors.current,
1390                         focusedIndicatorColor =
1391                             fromToken(OutlinedTextFieldTokens.FocusOutlineColor),
1392                         unfocusedIndicatorColor = fromToken(OutlinedTextFieldTokens.OutlineColor),
1393                         disabledIndicatorColor =
1394                             fromToken(OutlinedTextFieldTokens.DisabledOutlineColor)
1395                                 .copy(alpha = OutlinedTextFieldTokens.DisabledOutlineOpacity),
1396                         errorIndicatorColor = fromToken(OutlinedTextFieldTokens.ErrorOutlineColor),
1397                         focusedLeadingIconColor =
1398                             fromToken(OutlinedTextFieldTokens.FocusLeadingIconColor),
1399                         unfocusedLeadingIconColor =
1400                             fromToken(OutlinedTextFieldTokens.LeadingIconColor),
1401                         disabledLeadingIconColor =
1402                             fromToken(OutlinedTextFieldTokens.DisabledLeadingIconColor)
1403                                 .copy(alpha = OutlinedTextFieldTokens.DisabledLeadingIconOpacity),
1404                         errorLeadingIconColor =
1405                             fromToken(OutlinedTextFieldTokens.ErrorLeadingIconColor),
1406                         focusedTrailingIconColor =
1407                             fromToken(OutlinedTextFieldTokens.FocusTrailingIconColor),
1408                         unfocusedTrailingIconColor =
1409                             fromToken(OutlinedTextFieldTokens.TrailingIconColor),
1410                         disabledTrailingIconColor =
1411                             fromToken(OutlinedTextFieldTokens.DisabledTrailingIconColor)
1412                                 .copy(alpha = OutlinedTextFieldTokens.DisabledTrailingIconOpacity),
1413                         errorTrailingIconColor =
1414                             fromToken(OutlinedTextFieldTokens.ErrorTrailingIconColor),
1415                         focusedLabelColor = fromToken(OutlinedTextFieldTokens.FocusLabelColor),
1416                         unfocusedLabelColor = fromToken(OutlinedTextFieldTokens.LabelColor),
1417                         disabledLabelColor =
1418                             fromToken(OutlinedTextFieldTokens.DisabledLabelColor)
1419                                 .copy(alpha = OutlinedTextFieldTokens.DisabledLabelOpacity),
1420                         errorLabelColor = fromToken(OutlinedTextFieldTokens.ErrorLabelColor),
1421                         focusedPlaceholderColor =
1422                             fromToken(OutlinedTextFieldTokens.InputPlaceholderColor),
1423                         unfocusedPlaceholderColor =
1424                             fromToken(OutlinedTextFieldTokens.InputPlaceholderColor),
1425                         disabledPlaceholderColor =
1426                             fromToken(OutlinedTextFieldTokens.DisabledInputColor)
1427                                 .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
1428                         errorPlaceholderColor =
1429                             fromToken(OutlinedTextFieldTokens.InputPlaceholderColor),
1430                         focusedSupportingTextColor =
1431                             fromToken(OutlinedTextFieldTokens.FocusSupportingColor),
1432                         unfocusedSupportingTextColor =
1433                             fromToken(OutlinedTextFieldTokens.SupportingColor),
1434                         disabledSupportingTextColor =
1435                             fromToken(OutlinedTextFieldTokens.DisabledSupportingColor)
1436                                 .copy(alpha = OutlinedTextFieldTokens.DisabledSupportingOpacity),
1437                         errorSupportingTextColor =
1438                             fromToken(OutlinedTextFieldTokens.ErrorSupportingColor),
1439                         focusedPrefixColor = fromToken(OutlinedTextFieldTokens.InputPrefixColor),
1440                         unfocusedPrefixColor = fromToken(OutlinedTextFieldTokens.InputPrefixColor),
1441                         disabledPrefixColor =
1442                             fromToken(OutlinedTextFieldTokens.InputPrefixColor)
1443                                 .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
1444                         errorPrefixColor = fromToken(OutlinedTextFieldTokens.InputPrefixColor),
1445                         focusedSuffixColor = fromToken(OutlinedTextFieldTokens.InputSuffixColor),
1446                         unfocusedSuffixColor = fromToken(OutlinedTextFieldTokens.InputSuffixColor),
1447                         disabledSuffixColor =
1448                             fromToken(OutlinedTextFieldTokens.InputSuffixColor)
1449                                 .copy(alpha = OutlinedTextFieldTokens.DisabledInputOpacity),
1450                         errorSuffixColor = fromToken(OutlinedTextFieldTokens.InputSuffixColor)
1451                     )
1452                     .also { defaultOutlinedTextFieldColorsCached = it }
1453         }
1454 
1455     @Deprecated(
1456         message = "Renamed to OutlinedTextFieldDefaults.Container",
1457         replaceWith =
1458             ReplaceWith(
1459                 "Container(\n" +
1460                     "    enabled = enabled,\n" +
1461                     "    isError = isError,\n" +
1462                     "    interactionSource = interactionSource,\n" +
1463                     "    colors = colors,\n" +
1464                     "    shape = shape,\n" +
1465                     "    focusedBorderThickness = focusedBorderThickness,\n" +
1466                     "    unfocusedBorderThickness = unfocusedBorderThickness,\n" +
1467                     ")"
1468             ),
1469         level = DeprecationLevel.WARNING
1470     )
1471     @ExperimentalMaterial3Api
1472     @Composable
ContainerBoxnull1473     fun ContainerBox(
1474         enabled: Boolean,
1475         isError: Boolean,
1476         interactionSource: InteractionSource,
1477         colors: TextFieldColors = colors(),
1478         shape: Shape = OutlinedTextFieldDefaults.shape,
1479         focusedBorderThickness: Dp = FocusedBorderThickness,
1480         unfocusedBorderThickness: Dp = UnfocusedBorderThickness,
1481     ) =
1482         Container(
1483             enabled = enabled,
1484             isError = isError,
1485             interactionSource = interactionSource,
1486             modifier = Modifier,
1487             colors = colors,
1488             shape = shape,
1489             focusedBorderThickness = focusedBorderThickness,
1490             unfocusedBorderThickness = unfocusedBorderThickness,
1491         )
1492 }
1493 
1494 /**
1495  * Represents the colors of the input text, container, and content (including label, placeholder,
1496  * leading and trailing icons) used in a text field in different states.
1497  *
1498  * @param focusedTextColor the color used for the input text of this text field when focused
1499  * @param unfocusedTextColor the color used for the input text of this text field when not focused
1500  * @param disabledTextColor the color used for the input text of this text field when disabled
1501  * @param errorTextColor the color used for the input text of this text field when in error state
1502  * @param focusedContainerColor the container color for this text field when focused
1503  * @param unfocusedContainerColor the container color for this text field when not focused
1504  * @param disabledContainerColor the container color for this text field when disabled
1505  * @param errorContainerColor the container color for this text field when in error state
1506  * @param cursorColor the cursor color for this text field
1507  * @param errorCursorColor the cursor color for this text field when in error state
1508  * @param textSelectionColors the colors used when the input text of this text field is selected
1509  * @param focusedIndicatorColor the indicator color for this text field when focused
1510  * @param unfocusedIndicatorColor the indicator color for this text field when not focused
1511  * @param disabledIndicatorColor the indicator color for this text field when disabled
1512  * @param errorIndicatorColor the indicator color for this text field when in error state
1513  * @param focusedLeadingIconColor the leading icon color for this text field when focused
1514  * @param unfocusedLeadingIconColor the leading icon color for this text field when not focused
1515  * @param disabledLeadingIconColor the leading icon color for this text field when disabled
1516  * @param errorLeadingIconColor the leading icon color for this text field when in error state
1517  * @param focusedTrailingIconColor the trailing icon color for this text field when focused
1518  * @param unfocusedTrailingIconColor the trailing icon color for this text field when not focused
1519  * @param disabledTrailingIconColor the trailing icon color for this text field when disabled
1520  * @param errorTrailingIconColor the trailing icon color for this text field when in error state
1521  * @param focusedLabelColor the label color for this text field when focused
1522  * @param unfocusedLabelColor the label color for this text field when not focused
1523  * @param disabledLabelColor the label color for this text field when disabled
1524  * @param errorLabelColor the label color for this text field when in error state
1525  * @param focusedPlaceholderColor the placeholder color for this text field when focused
1526  * @param unfocusedPlaceholderColor the placeholder color for this text field when not focused
1527  * @param disabledPlaceholderColor the placeholder color for this text field when disabled
1528  * @param errorPlaceholderColor the placeholder color for this text field when in error state
1529  * @param focusedSupportingTextColor the supporting text color for this text field when focused
1530  * @param unfocusedSupportingTextColor the supporting text color for this text field when not
1531  *   focused
1532  * @param disabledSupportingTextColor the supporting text color for this text field when disabled
1533  * @param errorSupportingTextColor the supporting text color for this text field when in error state
1534  * @param focusedPrefixColor the prefix color for this text field when focused
1535  * @param unfocusedPrefixColor the prefix color for this text field when not focused
1536  * @param disabledPrefixColor the prefix color for this text field when disabled
1537  * @param errorPrefixColor the prefix color for this text field when in error state
1538  * @param focusedSuffixColor the suffix color for this text field when focused
1539  * @param unfocusedSuffixColor the suffix color for this text field when not focused
1540  * @param disabledSuffixColor the suffix color for this text field when disabled
1541  * @param errorSuffixColor the suffix color for this text field when in error state
1542  * @constructor create an instance with arbitrary colors. See [TextFieldDefaults.colors] for the
1543  *   default colors used in [TextField]. See [OutlinedTextFieldDefaults.colors] for the default
1544  *   colors used in [OutlinedTextField].
1545  */
1546 @Immutable
1547 class TextFieldColors
1548 constructor(
1549     val focusedTextColor: Color,
1550     val unfocusedTextColor: Color,
1551     val disabledTextColor: Color,
1552     val errorTextColor: Color,
1553     val focusedContainerColor: Color,
1554     val unfocusedContainerColor: Color,
1555     val disabledContainerColor: Color,
1556     val errorContainerColor: Color,
1557     val cursorColor: Color,
1558     val errorCursorColor: Color,
1559     val textSelectionColors: TextSelectionColors,
1560     val focusedIndicatorColor: Color,
1561     val unfocusedIndicatorColor: Color,
1562     val disabledIndicatorColor: Color,
1563     val errorIndicatorColor: Color,
1564     val focusedLeadingIconColor: Color,
1565     val unfocusedLeadingIconColor: Color,
1566     val disabledLeadingIconColor: Color,
1567     val errorLeadingIconColor: Color,
1568     val focusedTrailingIconColor: Color,
1569     val unfocusedTrailingIconColor: Color,
1570     val disabledTrailingIconColor: Color,
1571     val errorTrailingIconColor: Color,
1572     val focusedLabelColor: Color,
1573     val unfocusedLabelColor: Color,
1574     val disabledLabelColor: Color,
1575     val errorLabelColor: Color,
1576     val focusedPlaceholderColor: Color,
1577     val unfocusedPlaceholderColor: Color,
1578     val disabledPlaceholderColor: Color,
1579     val errorPlaceholderColor: Color,
1580     val focusedSupportingTextColor: Color,
1581     val unfocusedSupportingTextColor: Color,
1582     val disabledSupportingTextColor: Color,
1583     val errorSupportingTextColor: Color,
1584     val focusedPrefixColor: Color,
1585     val unfocusedPrefixColor: Color,
1586     val disabledPrefixColor: Color,
1587     val errorPrefixColor: Color,
1588     val focusedSuffixColor: Color,
1589     val unfocusedSuffixColor: Color,
1590     val disabledSuffixColor: Color,
1591     val errorSuffixColor: Color,
1592 ) {
1593 
1594     /**
1595      * Returns a copy of this ChipColors, optionally overriding some of the values. This uses the
1596      * Color.Unspecified to mean “use the value from the source”
1597      */
1598     fun copy(
1599         focusedTextColor: Color = this.focusedTextColor,
1600         unfocusedTextColor: Color = this.unfocusedTextColor,
1601         disabledTextColor: Color = this.disabledTextColor,
1602         errorTextColor: Color = this.errorTextColor,
1603         focusedContainerColor: Color = this.focusedContainerColor,
1604         unfocusedContainerColor: Color = this.unfocusedContainerColor,
1605         disabledContainerColor: Color = this.disabledContainerColor,
1606         errorContainerColor: Color = this.errorContainerColor,
1607         cursorColor: Color = this.cursorColor,
1608         errorCursorColor: Color = this.errorCursorColor,
1609         textSelectionColors: TextSelectionColors? = this.textSelectionColors,
1610         focusedIndicatorColor: Color = this.focusedIndicatorColor,
1611         unfocusedIndicatorColor: Color = this.unfocusedIndicatorColor,
1612         disabledIndicatorColor: Color = this.disabledIndicatorColor,
1613         errorIndicatorColor: Color = this.errorIndicatorColor,
1614         focusedLeadingIconColor: Color = this.focusedLeadingIconColor,
1615         unfocusedLeadingIconColor: Color = this.unfocusedLeadingIconColor,
1616         disabledLeadingIconColor: Color = this.disabledLeadingIconColor,
1617         errorLeadingIconColor: Color = this.errorLeadingIconColor,
1618         focusedTrailingIconColor: Color = this.focusedTrailingIconColor,
1619         unfocusedTrailingIconColor: Color = this.unfocusedTrailingIconColor,
1620         disabledTrailingIconColor: Color = this.disabledTrailingIconColor,
1621         errorTrailingIconColor: Color = this.errorTrailingIconColor,
1622         focusedLabelColor: Color = this.focusedLabelColor,
1623         unfocusedLabelColor: Color = this.unfocusedLabelColor,
1624         disabledLabelColor: Color = this.disabledLabelColor,
1625         errorLabelColor: Color = this.errorLabelColor,
1626         focusedPlaceholderColor: Color = this.focusedPlaceholderColor,
1627         unfocusedPlaceholderColor: Color = this.unfocusedPlaceholderColor,
1628         disabledPlaceholderColor: Color = this.disabledPlaceholderColor,
1629         errorPlaceholderColor: Color = this.errorPlaceholderColor,
1630         focusedSupportingTextColor: Color = this.focusedSupportingTextColor,
1631         unfocusedSupportingTextColor: Color = this.unfocusedSupportingTextColor,
1632         disabledSupportingTextColor: Color = this.disabledSupportingTextColor,
1633         errorSupportingTextColor: Color = this.errorSupportingTextColor,
1634         focusedPrefixColor: Color = this.focusedPrefixColor,
1635         unfocusedPrefixColor: Color = this.unfocusedPrefixColor,
1636         disabledPrefixColor: Color = this.disabledPrefixColor,
1637         errorPrefixColor: Color = this.errorPrefixColor,
1638         focusedSuffixColor: Color = this.focusedSuffixColor,
1639         unfocusedSuffixColor: Color = this.unfocusedSuffixColor,
1640         disabledSuffixColor: Color = this.disabledSuffixColor,
1641         errorSuffixColor: Color = this.errorSuffixColor,
1642     ) =
1643         TextFieldColors(
1644             focusedTextColor.takeOrElse { this.focusedTextColor },
1645             unfocusedTextColor.takeOrElse { this.unfocusedTextColor },
1646             disabledTextColor.takeOrElse { this.disabledTextColor },
1647             errorTextColor.takeOrElse { this.errorTextColor },
1648             focusedContainerColor.takeOrElse { this.focusedContainerColor },
1649             unfocusedContainerColor.takeOrElse { this.unfocusedContainerColor },
1650             disabledContainerColor.takeOrElse { this.disabledContainerColor },
1651             errorContainerColor.takeOrElse { this.errorContainerColor },
1652             cursorColor.takeOrElse { this.cursorColor },
1653             errorCursorColor.takeOrElse { this.errorCursorColor },
1654             textSelectionColors.takeOrElse { this.textSelectionColors },
1655             focusedIndicatorColor.takeOrElse { this.focusedIndicatorColor },
1656             unfocusedIndicatorColor.takeOrElse { this.unfocusedIndicatorColor },
1657             disabledIndicatorColor.takeOrElse { this.disabledIndicatorColor },
1658             errorIndicatorColor.takeOrElse { this.errorIndicatorColor },
1659             focusedLeadingIconColor.takeOrElse { this.focusedLeadingIconColor },
1660             unfocusedLeadingIconColor.takeOrElse { this.unfocusedLeadingIconColor },
1661             disabledLeadingIconColor.takeOrElse { this.disabledLeadingIconColor },
1662             errorLeadingIconColor.takeOrElse { this.errorLeadingIconColor },
1663             focusedTrailingIconColor.takeOrElse { this.focusedTrailingIconColor },
1664             unfocusedTrailingIconColor.takeOrElse { this.unfocusedTrailingIconColor },
1665             disabledTrailingIconColor.takeOrElse { this.disabledTrailingIconColor },
1666             errorTrailingIconColor.takeOrElse { this.errorTrailingIconColor },
1667             focusedLabelColor.takeOrElse { this.focusedLabelColor },
1668             unfocusedLabelColor.takeOrElse { this.unfocusedLabelColor },
1669             disabledLabelColor.takeOrElse { this.disabledLabelColor },
1670             errorLabelColor.takeOrElse { this.errorLabelColor },
1671             focusedPlaceholderColor.takeOrElse { this.focusedPlaceholderColor },
1672             unfocusedPlaceholderColor.takeOrElse { this.unfocusedPlaceholderColor },
1673             disabledPlaceholderColor.takeOrElse { this.disabledPlaceholderColor },
1674             errorPlaceholderColor.takeOrElse { this.errorPlaceholderColor },
1675             focusedSupportingTextColor.takeOrElse { this.focusedSupportingTextColor },
1676             unfocusedSupportingTextColor.takeOrElse { this.unfocusedSupportingTextColor },
1677             disabledSupportingTextColor.takeOrElse { this.disabledSupportingTextColor },
1678             errorSupportingTextColor.takeOrElse { this.errorSupportingTextColor },
1679             focusedPrefixColor.takeOrElse { this.focusedPrefixColor },
1680             unfocusedPrefixColor.takeOrElse { this.unfocusedPrefixColor },
1681             disabledPrefixColor.takeOrElse { this.disabledPrefixColor },
1682             errorPrefixColor.takeOrElse { this.errorPrefixColor },
1683             focusedSuffixColor.takeOrElse { this.focusedSuffixColor },
1684             unfocusedSuffixColor.takeOrElse { this.unfocusedSuffixColor },
1685             disabledSuffixColor.takeOrElse { this.disabledSuffixColor },
1686             errorSuffixColor.takeOrElse { this.errorSuffixColor },
1687         )
1688 
1689     internal fun TextSelectionColors?.takeOrElse(
1690         block: () -> TextSelectionColors
1691     ): TextSelectionColors = this ?: block()
1692 
1693     /**
1694      * Represents the color used for the leading icon of this text field.
1695      *
1696      * @param enabled whether the text field is enabled
1697      * @param isError whether the text field's current value is in error
1698      * @param focused whether the text field is in focus
1699      */
1700     @Stable
1701     internal fun leadingIconColor(
1702         enabled: Boolean,
1703         isError: Boolean,
1704         focused: Boolean,
1705     ): Color =
1706         when {
1707             !enabled -> disabledLeadingIconColor
1708             isError -> errorLeadingIconColor
1709             focused -> focusedLeadingIconColor
1710             else -> unfocusedLeadingIconColor
1711         }
1712 
1713     /**
1714      * Represents the color used for the trailing icon of this text field.
1715      *
1716      * @param enabled whether the text field is enabled
1717      * @param isError whether the text field's current value is in error
1718      * @param focused whether the text field is in focus
1719      */
1720     @Stable
1721     internal fun trailingIconColor(
1722         enabled: Boolean,
1723         isError: Boolean,
1724         focused: Boolean,
1725     ): Color =
1726         when {
1727             !enabled -> disabledTrailingIconColor
1728             isError -> errorTrailingIconColor
1729             focused -> focusedTrailingIconColor
1730             else -> unfocusedTrailingIconColor
1731         }
1732 
1733     /**
1734      * Represents the color used for the border indicator of this text field.
1735      *
1736      * @param enabled whether the text field is enabled
1737      * @param isError whether the text field's current value is in error
1738      * @param focused whether the text field is in focus
1739      */
1740     @Stable
1741     internal fun indicatorColor(
1742         enabled: Boolean,
1743         isError: Boolean,
1744         focused: Boolean,
1745     ): Color =
1746         when {
1747             !enabled -> disabledIndicatorColor
1748             isError -> errorIndicatorColor
1749             focused -> focusedIndicatorColor
1750             else -> unfocusedIndicatorColor
1751         }
1752 
1753     /**
1754      * Represents the container color for this text field.
1755      *
1756      * @param enabled whether the text field is enabled
1757      * @param isError whether the text field's current value is in error
1758      * @param focused whether the text field is in focus
1759      */
1760     @Stable
1761     internal fun containerColor(
1762         enabled: Boolean,
1763         isError: Boolean,
1764         focused: Boolean,
1765     ): Color =
1766         when {
1767             !enabled -> disabledContainerColor
1768             isError -> errorContainerColor
1769             focused -> focusedContainerColor
1770             else -> unfocusedContainerColor
1771         }
1772 
1773     /**
1774      * Represents the color used for the placeholder of this text field.
1775      *
1776      * @param enabled whether the text field is enabled
1777      * @param isError whether the text field's current value is in error
1778      * @param focused whether the text field is in focus
1779      */
1780     @Stable
1781     internal fun placeholderColor(
1782         enabled: Boolean,
1783         isError: Boolean,
1784         focused: Boolean,
1785     ): Color =
1786         when {
1787             !enabled -> disabledPlaceholderColor
1788             isError -> errorPlaceholderColor
1789             focused -> focusedPlaceholderColor
1790             else -> unfocusedPlaceholderColor
1791         }
1792 
1793     /**
1794      * Represents the color used for the label of this text field.
1795      *
1796      * @param enabled whether the text field is enabled
1797      * @param isError whether the text field's current value is in error
1798      * @param focused whether the text field is in focus
1799      */
1800     @Stable
1801     internal fun labelColor(
1802         enabled: Boolean,
1803         isError: Boolean,
1804         focused: Boolean,
1805     ): Color =
1806         when {
1807             !enabled -> disabledLabelColor
1808             isError -> errorLabelColor
1809             focused -> focusedLabelColor
1810             else -> unfocusedLabelColor
1811         }
1812 
1813     /**
1814      * Represents the color used for the input field of this text field.
1815      *
1816      * @param enabled whether the text field is enabled
1817      * @param isError whether the text field's current value is in error
1818      * @param focused whether the text field is in focus
1819      */
1820     @Stable
1821     internal fun textColor(
1822         enabled: Boolean,
1823         isError: Boolean,
1824         focused: Boolean,
1825     ): Color =
1826         when {
1827             !enabled -> disabledTextColor
1828             isError -> errorTextColor
1829             focused -> focusedTextColor
1830             else -> unfocusedTextColor
1831         }
1832 
1833     /**
1834      * Represents the colors used for the supporting text of this text field.
1835      *
1836      * @param enabled whether the text field is enabled
1837      * @param isError whether the text field's current value is in error
1838      * @param focused whether the text field is in focus
1839      */
1840     @Stable
1841     internal fun supportingTextColor(
1842         enabled: Boolean,
1843         isError: Boolean,
1844         focused: Boolean,
1845     ): Color =
1846         when {
1847             !enabled -> disabledSupportingTextColor
1848             isError -> errorSupportingTextColor
1849             focused -> focusedSupportingTextColor
1850             else -> unfocusedSupportingTextColor
1851         }
1852 
1853     /**
1854      * Represents the color used for the prefix of this text field.
1855      *
1856      * @param enabled whether the text field is enabled
1857      * @param isError whether the text field's current value is in error
1858      * @param focused whether the text field is in focus
1859      */
1860     @Stable
1861     internal fun prefixColor(
1862         enabled: Boolean,
1863         isError: Boolean,
1864         focused: Boolean,
1865     ): Color =
1866         when {
1867             !enabled -> disabledPrefixColor
1868             isError -> errorPrefixColor
1869             focused -> focusedPrefixColor
1870             else -> unfocusedPrefixColor
1871         }
1872 
1873     /**
1874      * Represents the color used for the suffix of this text field.
1875      *
1876      * @param enabled whether the text field is enabled
1877      * @param isError whether the text field's current value is in error
1878      * @param focused whether the text field is in focus
1879      */
1880     @Stable
1881     internal fun suffixColor(
1882         enabled: Boolean,
1883         isError: Boolean,
1884         focused: Boolean,
1885     ): Color =
1886         when {
1887             !enabled -> disabledSuffixColor
1888             isError -> errorSuffixColor
1889             focused -> focusedSuffixColor
1890             else -> unfocusedSuffixColor
1891         }
1892 
1893     /**
1894      * Represents the color used for the cursor of this text field.
1895      *
1896      * @param isError whether the text field's current value is in error
1897      */
1898     @Stable
1899     internal fun cursorColor(isError: Boolean): Color =
1900         if (isError) errorCursorColor else cursorColor
1901 
1902     override fun equals(other: Any?): Boolean {
1903         if (this === other) return true
1904         if (other == null || other !is TextFieldColors) return false
1905 
1906         if (focusedTextColor != other.focusedTextColor) return false
1907         if (unfocusedTextColor != other.unfocusedTextColor) return false
1908         if (disabledTextColor != other.disabledTextColor) return false
1909         if (errorTextColor != other.errorTextColor) return false
1910         if (focusedContainerColor != other.focusedContainerColor) return false
1911         if (unfocusedContainerColor != other.unfocusedContainerColor) return false
1912         if (disabledContainerColor != other.disabledContainerColor) return false
1913         if (errorContainerColor != other.errorContainerColor) return false
1914         if (cursorColor != other.cursorColor) return false
1915         if (errorCursorColor != other.errorCursorColor) return false
1916         if (textSelectionColors != other.textSelectionColors) return false
1917         if (focusedIndicatorColor != other.focusedIndicatorColor) return false
1918         if (unfocusedIndicatorColor != other.unfocusedIndicatorColor) return false
1919         if (disabledIndicatorColor != other.disabledIndicatorColor) return false
1920         if (errorIndicatorColor != other.errorIndicatorColor) return false
1921         if (focusedLeadingIconColor != other.focusedLeadingIconColor) return false
1922         if (unfocusedLeadingIconColor != other.unfocusedLeadingIconColor) return false
1923         if (disabledLeadingIconColor != other.disabledLeadingIconColor) return false
1924         if (errorLeadingIconColor != other.errorLeadingIconColor) return false
1925         if (focusedTrailingIconColor != other.focusedTrailingIconColor) return false
1926         if (unfocusedTrailingIconColor != other.unfocusedTrailingIconColor) return false
1927         if (disabledTrailingIconColor != other.disabledTrailingIconColor) return false
1928         if (errorTrailingIconColor != other.errorTrailingIconColor) return false
1929         if (focusedLabelColor != other.focusedLabelColor) return false
1930         if (unfocusedLabelColor != other.unfocusedLabelColor) return false
1931         if (disabledLabelColor != other.disabledLabelColor) return false
1932         if (errorLabelColor != other.errorLabelColor) return false
1933         if (focusedPlaceholderColor != other.focusedPlaceholderColor) return false
1934         if (unfocusedPlaceholderColor != other.unfocusedPlaceholderColor) return false
1935         if (disabledPlaceholderColor != other.disabledPlaceholderColor) return false
1936         if (errorPlaceholderColor != other.errorPlaceholderColor) return false
1937         if (focusedSupportingTextColor != other.focusedSupportingTextColor) return false
1938         if (unfocusedSupportingTextColor != other.unfocusedSupportingTextColor) return false
1939         if (disabledSupportingTextColor != other.disabledSupportingTextColor) return false
1940         if (errorSupportingTextColor != other.errorSupportingTextColor) return false
1941         if (focusedPrefixColor != other.focusedPrefixColor) return false
1942         if (unfocusedPrefixColor != other.unfocusedPrefixColor) return false
1943         if (disabledPrefixColor != other.disabledPrefixColor) return false
1944         if (errorPrefixColor != other.errorPrefixColor) return false
1945         if (focusedSuffixColor != other.focusedSuffixColor) return false
1946         if (unfocusedSuffixColor != other.unfocusedSuffixColor) return false
1947         if (disabledSuffixColor != other.disabledSuffixColor) return false
1948         if (errorSuffixColor != other.errorSuffixColor) return false
1949 
1950         return true
1951     }
1952 
1953     override fun hashCode(): Int {
1954         var result = focusedTextColor.hashCode()
1955         result = 31 * result + unfocusedTextColor.hashCode()
1956         result = 31 * result + disabledTextColor.hashCode()
1957         result = 31 * result + errorTextColor.hashCode()
1958         result = 31 * result + focusedContainerColor.hashCode()
1959         result = 31 * result + unfocusedContainerColor.hashCode()
1960         result = 31 * result + disabledContainerColor.hashCode()
1961         result = 31 * result + errorContainerColor.hashCode()
1962         result = 31 * result + cursorColor.hashCode()
1963         result = 31 * result + errorCursorColor.hashCode()
1964         result = 31 * result + textSelectionColors.hashCode()
1965         result = 31 * result + focusedIndicatorColor.hashCode()
1966         result = 31 * result + unfocusedIndicatorColor.hashCode()
1967         result = 31 * result + disabledIndicatorColor.hashCode()
1968         result = 31 * result + errorIndicatorColor.hashCode()
1969         result = 31 * result + focusedLeadingIconColor.hashCode()
1970         result = 31 * result + unfocusedLeadingIconColor.hashCode()
1971         result = 31 * result + disabledLeadingIconColor.hashCode()
1972         result = 31 * result + errorLeadingIconColor.hashCode()
1973         result = 31 * result + focusedTrailingIconColor.hashCode()
1974         result = 31 * result + unfocusedTrailingIconColor.hashCode()
1975         result = 31 * result + disabledTrailingIconColor.hashCode()
1976         result = 31 * result + errorTrailingIconColor.hashCode()
1977         result = 31 * result + focusedLabelColor.hashCode()
1978         result = 31 * result + unfocusedLabelColor.hashCode()
1979         result = 31 * result + disabledLabelColor.hashCode()
1980         result = 31 * result + errorLabelColor.hashCode()
1981         result = 31 * result + focusedPlaceholderColor.hashCode()
1982         result = 31 * result + unfocusedPlaceholderColor.hashCode()
1983         result = 31 * result + disabledPlaceholderColor.hashCode()
1984         result = 31 * result + errorPlaceholderColor.hashCode()
1985         result = 31 * result + focusedSupportingTextColor.hashCode()
1986         result = 31 * result + unfocusedSupportingTextColor.hashCode()
1987         result = 31 * result + disabledSupportingTextColor.hashCode()
1988         result = 31 * result + errorSupportingTextColor.hashCode()
1989         result = 31 * result + focusedPrefixColor.hashCode()
1990         result = 31 * result + unfocusedPrefixColor.hashCode()
1991         result = 31 * result + disabledPrefixColor.hashCode()
1992         result = 31 * result + errorPrefixColor.hashCode()
1993         result = 31 * result + focusedSuffixColor.hashCode()
1994         result = 31 * result + unfocusedSuffixColor.hashCode()
1995         result = 31 * result + disabledSuffixColor.hashCode()
1996         result = 31 * result + errorSuffixColor.hashCode()
1997         return result
1998     }
1999 }
2000 
2001 /** The position of the label with respect to the text field. */
2002 abstract class TextFieldLabelPosition private constructor() {
2003     /**
2004      * The default label position according to the Material specification.
2005      *
2006      * For [TextField], the label is positioned inside the text field container. For
2007      * [OutlinedTextField], the label is positioned inside the text field container when expanded
2008      * and cuts into the border when minimized.
2009      *
2010      * @param alwaysMinimize Whether to always keep the label of the text field minimized. If
2011      *   `false`, the label will expand to occupy the input area when the text field is unfocused
2012      *   and empty. If `true`, this allows displaying the placeholder, prefix, and suffix alongside
2013      *   the label when the text field is unfocused and empty.
2014      * @param minimizedAlignment The horizontal alignment of the label when it is minimized.
2015      * @param expandedAlignment The horizontal alignment of the label when it is expanded.
2016      */
2017     class Attached(
2018         @get:Suppress("GetterSetterNames") val alwaysMinimize: Boolean = false,
2019         val minimizedAlignment: Alignment.Horizontal = Alignment.Start,
2020         val expandedAlignment: Alignment.Horizontal = Alignment.Start,
2021     ) : TextFieldLabelPosition() {
equalsnull2022         override fun equals(other: Any?): Boolean {
2023             if (this === other) return true
2024             if (other !is Attached) return false
2025 
2026             if (alwaysMinimize != other.alwaysMinimize) return false
2027             if (minimizedAlignment != other.minimizedAlignment) return false
2028             if (expandedAlignment != other.expandedAlignment) return false
2029 
2030             return true
2031         }
2032 
hashCodenull2033         override fun hashCode(): Int {
2034             var result = alwaysMinimize.hashCode()
2035             result = 31 * result + minimizedAlignment.hashCode()
2036             result = 31 * result + expandedAlignment.hashCode()
2037             return result
2038         }
2039 
toStringnull2040         override fun toString(): String {
2041             return "Attached(" +
2042                 "alwaysMinimize=$alwaysMinimize, " +
2043                 "minimizedAlignment=$minimizedAlignment, " +
2044                 "expandedAlignment=$expandedAlignment" +
2045                 ")"
2046         }
2047     }
2048 
2049     /**
2050      * The label is positioned above and outside the text field container. This results in the label
2051      * always being minimized.
2052      *
2053      * @param alignment The horizontal alignment of the label.
2054      */
2055     class Above(val alignment: Alignment.Horizontal = Alignment.Start) : TextFieldLabelPosition() {
equalsnull2056         override fun equals(other: Any?): Boolean {
2057             if (this === other) return true
2058             if (other !is Above) return false
2059 
2060             return alignment == other.alignment
2061         }
2062 
hashCodenull2063         override fun hashCode(): Int {
2064             return alignment.hashCode()
2065         }
2066 
toStringnull2067         override fun toString(): String = "Above(alignment=$alignment)"
2068     }
2069 }
2070 
2071 /** Scope for the label of a [TextField] or [OutlinedTextField]. */
2072 @Stable
2073 interface TextFieldLabelScope {
2074     /**
2075      * The animation progress of a label between its expanded and minimized sizes, where 0
2076      * represents an expanded label and 1 represents a minimized label.
2077      *
2078      * Label animation is handled by the framework when using a component that reads from
2079      * [LocalTextStyle], such as the default [Text]. This [labelMinimizedProgress] value can be used
2080      * to coordinate other animations in conjunction with the default animation.
2081      */
2082     @get:FloatRange(from = 0.0, to = 1.0) val labelMinimizedProgress: Float
2083 }
2084