1 /*
2  * Copyright 2025 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.compose.foundation.BorderStroke
20 import androidx.compose.foundation.shape.CornerBasedShape
21 import androidx.compose.material3.tokens.FilledIconButtonTokens
22 import androidx.compose.material3.tokens.FilledTonalIconButtonTokens
23 import androidx.compose.material3.tokens.LargeIconButtonTokens
24 import androidx.compose.material3.tokens.MediumIconButtonTokens
25 import androidx.compose.material3.tokens.OutlinedIconButtonTokens
26 import androidx.compose.material3.tokens.SmallIconButtonTokens
27 import androidx.compose.material3.tokens.StandardIconButtonTokens
28 import androidx.compose.material3.tokens.XLargeIconButtonTokens
29 import androidx.compose.material3.tokens.XSmallIconButtonTokens
30 import androidx.compose.runtime.Composable
31 import androidx.compose.runtime.remember
32 import androidx.compose.ui.graphics.Color
33 import androidx.compose.ui.graphics.Shape
34 import androidx.compose.ui.unit.Dp
35 import androidx.compose.ui.unit.DpSize
36 import androidx.compose.ui.unit.dp
37 import kotlin.jvm.JvmInline
38 
39 /** Contains the default values for all four icon and icon toggle button types. */
40 object IconButtonDefaults {
41     /**
42      * Contains the default values used by [IconButton]. [LocalContentColor] will be applied to the
43      * icon and down the UI tree.
44      *
45      * See [iconButtonVibrantColors] for default values that applies the recommended high contrast
46      * colors.
47      */
48     @Composable
iconButtonColorsnull49     fun iconButtonColors(): IconButtonColors {
50         val contentColor = LocalContentColor.current
51         val colors = MaterialTheme.colorScheme.defaultIconButtonColors(contentColor)
52         return if (colors.contentColor == contentColor) {
53             colors
54         } else {
55             colors.copy(
56                 contentColor = contentColor,
57                 disabledContentColor =
58                     contentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity)
59             )
60         }
61     }
62 
63     /**
64      * Creates a [IconButtonColors] that represents the default colors used in a [IconButton].
65      * [LocalContentColor] will be applied to the icon and down the UI tree unless a custom
66      * [contentColor] is provided.
67      *
68      * See [iconButtonVibrantColors] for default values that applies the recommended high contrast
69      * colors.
70      *
71      * @param containerColor the container color of this icon button when enabled.
72      * @param contentColor the content color of this icon button when enabled. By default, this will
73      *   use the current LocalContentColor value.
74      * @param disabledContainerColor the container color of this icon button when not enabled.
75      * @param disabledContentColor the content color of this icon button when not enabled.
76      */
77     @Composable
iconButtonColorsnull78     fun iconButtonColors(
79         containerColor: Color = Color.Unspecified,
80         contentColor: Color = LocalContentColor.current,
81         disabledContainerColor: Color = Color.Unspecified,
82         disabledContentColor: Color =
83             contentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity)
84     ): IconButtonColors =
85         MaterialTheme.colorScheme
86             .defaultIconButtonColors(LocalContentColor.current)
87             .copy(
88                 containerColor = containerColor,
89                 contentColor = contentColor,
90                 disabledContainerColor = disabledContainerColor,
91                 disabledContentColor = disabledContentColor,
92             )
93 
94     internal fun ColorScheme.defaultIconButtonColors(localContentColor: Color): IconButtonColors {
95         return defaultIconButtonColorsCached
96             ?: run {
97                 IconButtonColors(
98                         containerColor = Color.Transparent,
99                         contentColor = localContentColor,
100                         disabledContainerColor = Color.Transparent,
101                         disabledContentColor =
102                             localContentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity)
103                     )
104                     .also { defaultIconButtonColorsCached = it }
105             }
106     }
107 
108     /**
109      * Creates a [IconButtonColors] that represents the recommended high contrast colors used in an
110      * [IconButton].
111      *
112      * See [iconButtonColors] for default values that applies [LocalContentColor] to the icon and
113      * down the UI tree.
114      */
115     @Composable
iconButtonVibrantColorsnull116     fun iconButtonVibrantColors(): IconButtonColors =
117         MaterialTheme.colorScheme.defaultIconButtonVibrantColors()
118 
119     /**
120      * Creates a [IconButtonColors] that represents the recommended high contrast colors used in an
121      * [IconButton].
122      *
123      * See [iconButtonColors] for default values that applies [LocalContentColor] to the icon and
124      * down the UI tree.
125      *
126      * @param containerColor the container color of this icon button when enabled.
127      * @param contentColor the content color of this icon button when enabled.
128      * @param disabledContainerColor the container color of this icon button when not enabled.
129      * @param disabledContentColor the content color of this icon button when not enabled.
130      */
131     @Composable
132     fun iconButtonVibrantColors(
133         containerColor: Color = Color.Unspecified,
134         contentColor: Color = Color.Unspecified,
135         disabledContainerColor: Color = Color.Unspecified,
136         disabledContentColor: Color =
137             contentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity)
138     ): IconButtonColors =
139         MaterialTheme.colorScheme
140             .defaultIconButtonVibrantColors()
141             .copy(
142                 containerColor = containerColor,
143                 contentColor = contentColor,
144                 disabledContainerColor = disabledContainerColor,
145                 disabledContentColor = disabledContentColor,
146             )
147 
148     internal fun ColorScheme.defaultIconButtonVibrantColors(): IconButtonColors {
149         return defaultIconButtonVibrantColorsCached
150             ?: run {
151                 IconButtonColors(
152                         containerColor = Color.Transparent,
153                         contentColor = fromToken(StandardIconButtonTokens.Color),
154                         disabledContainerColor = Color.Transparent,
155                         disabledContentColor =
156                             fromToken(StandardIconButtonTokens.DisabledColor)
157                                 .copy(alpha = StandardIconButtonTokens.DisabledOpacity)
158                     )
159                     .also { defaultIconButtonVibrantColorsCached = it }
160             }
161     }
162 
163     /**
164      * Creates a [IconToggleButtonColors] that represents the default colors used in a
165      * [IconToggleButton]. [LocalContentColor] will be applied to the icon and down the UI tree.
166      *
167      * See [iconToggleButtonVibrantColors] for default values that applies the recommended high
168      * contrast colors.
169      */
170     @Composable
iconToggleButtonColorsnull171     fun iconToggleButtonColors(): IconToggleButtonColors {
172         val contentColor = LocalContentColor.current
173         val colors = MaterialTheme.colorScheme.defaultIconToggleButtonColors(contentColor)
174         if (colors.contentColor == contentColor) {
175             return colors
176         } else {
177             return colors.copy(
178                 contentColor = contentColor,
179                 disabledContentColor =
180                     contentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity)
181             )
182         }
183     }
184 
185     /**
186      * Creates a [IconToggleButtonColors] that represents the default colors used in a
187      * [IconToggleButton]. [LocalContentColor] will be applied to the icon and down the UI tree
188      * unless a custom [contentColor] is provided.
189      *
190      * See [iconToggleButtonVibrantColors] for default values that applies the recommended high
191      * contrast colors.
192      *
193      * @param containerColor the container color of this icon button when enabled.
194      * @param contentColor the content color of this icon button when enabled.
195      * @param disabledContainerColor the container color of this icon button when not enabled.
196      * @param disabledContentColor the content color of this icon button when not enabled.
197      * @param checkedContainerColor the container color of this icon button when checked.
198      * @param checkedContentColor the content color of this icon button when checked.
199      */
200     @Composable
iconToggleButtonColorsnull201     fun iconToggleButtonColors(
202         containerColor: Color = Color.Unspecified,
203         contentColor: Color = LocalContentColor.current,
204         disabledContainerColor: Color = Color.Unspecified,
205         disabledContentColor: Color =
206             contentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity),
207         checkedContainerColor: Color = Color.Unspecified,
208         checkedContentColor: Color = Color.Unspecified
209     ): IconToggleButtonColors =
210         MaterialTheme.colorScheme
211             .defaultIconToggleButtonColors(LocalContentColor.current)
212             .copy(
213                 containerColor = containerColor,
214                 contentColor = contentColor,
215                 disabledContainerColor = disabledContainerColor,
216                 disabledContentColor = disabledContentColor,
217                 checkedContainerColor = checkedContainerColor,
218                 checkedContentColor = checkedContentColor,
219             )
220 
221     internal fun ColorScheme.defaultIconToggleButtonColors(
222         localContentColor: Color
223     ): IconToggleButtonColors {
224         return defaultIconToggleButtonColorsCached
225             ?: run {
226                 IconToggleButtonColors(
227                         containerColor = Color.Transparent,
228                         contentColor = localContentColor,
229                         disabledContainerColor = Color.Transparent,
230                         disabledContentColor =
231                             localContentColor.copy(
232                                 alpha = StandardIconButtonTokens.DisabledOpacity
233                             ),
234                         checkedContainerColor = Color.Transparent,
235                         checkedContentColor = fromToken(StandardIconButtonTokens.SelectedColor)
236                     )
237                     .also { defaultIconToggleButtonColorsCached = it }
238             }
239     }
240 
241     /**
242      * Creates a [IconToggleButtonColors] that represents the recommended high contrast colors used
243      * in a [IconToggleButton]. See [iconToggleButtonColors] for default values that applies
244      * [LocalContentColor] to the icon and down the UI tree.
245      */
246     @Composable
iconToggleButtonVibrantColorsnull247     fun iconToggleButtonVibrantColors(): IconToggleButtonColors =
248         MaterialTheme.colorScheme.defaultIconToggleButtonVibrantColors()
249 
250     /**
251      * Creates a [IconToggleButtonColors] that represents the recommended high contrast colors used
252      * in a [IconToggleButton].
253      *
254      * See [iconToggleButtonColors] for default values that applies [LocalContentColor] to the icon
255      * and down the UI tree.
256      *
257      * @param containerColor the container color of this icon button when enabled.
258      * @param contentColor the content color of this icon button when enabled.
259      * @param disabledContainerColor the container color of this icon button when not enabled.
260      * @param disabledContentColor the content color of this icon button when not enabled.
261      * @param checkedContainerColor the container color of this icon button when checked.
262      * @param checkedContentColor the content color of this icon button when checked.
263      */
264     @Composable
265     fun iconToggleButtonVibrantColors(
266         containerColor: Color = Color.Unspecified,
267         contentColor: Color = Color.Unspecified,
268         disabledContainerColor: Color = Color.Unspecified,
269         disabledContentColor: Color =
270             contentColor.copy(alpha = StandardIconButtonTokens.DisabledOpacity),
271         checkedContainerColor: Color = Color.Unspecified,
272         checkedContentColor: Color = Color.Unspecified
273     ): IconToggleButtonColors =
274         MaterialTheme.colorScheme
275             .defaultIconToggleButtonVibrantColors()
276             .copy(
277                 containerColor = containerColor,
278                 contentColor = contentColor,
279                 disabledContainerColor = disabledContainerColor,
280                 disabledContentColor = disabledContentColor,
281                 checkedContainerColor = checkedContainerColor,
282                 checkedContentColor = checkedContentColor,
283             )
284 
285     internal fun ColorScheme.defaultIconToggleButtonVibrantColors(): IconToggleButtonColors {
286         return defaultIconToggleButtonVibrantColorsCached
287             ?: run {
288                 IconToggleButtonColors(
289                         containerColor = Color.Transparent,
290                         contentColor = fromToken(StandardIconButtonTokens.UnselectedColor),
291                         disabledContainerColor = Color.Transparent,
292                         disabledContentColor =
293                             fromToken(StandardIconButtonTokens.DisabledColor)
294                                 .copy(alpha = StandardIconButtonTokens.DisabledOpacity),
295                         checkedContainerColor = Color.Transparent,
296                         checkedContentColor = fromToken(StandardIconButtonTokens.SelectedColor)
297                     )
298                     .also { defaultIconToggleButtonVibrantColorsCached = it }
299             }
300     }
301 
302     /**
303      * Creates a [IconButtonColors] that represents the default colors used in a [FilledIconButton].
304      */
305     @Composable
filledIconButtonColorsnull306     fun filledIconButtonColors(): IconButtonColors =
307         MaterialTheme.colorScheme.defaultFilledIconButtonColors
308 
309     /**
310      * Creates a [IconButtonColors] that represents the default colors used in a [FilledIconButton].
311      *
312      * @param containerColor the container color of this icon button when enabled.
313      * @param contentColor the content color of this icon button when enabled.
314      * @param disabledContainerColor the container color of this icon button when not enabled.
315      * @param disabledContentColor the content color of this icon button when not enabled.
316      */
317     @Composable
318     fun filledIconButtonColors(
319         containerColor: Color = Color.Unspecified,
320         contentColor: Color = contentColorFor(containerColor),
321         disabledContainerColor: Color = Color.Unspecified,
322         disabledContentColor: Color = Color.Unspecified
323     ): IconButtonColors =
324         MaterialTheme.colorScheme.defaultFilledIconButtonColors.copy(
325             containerColor = containerColor,
326             contentColor = contentColor,
327             disabledContainerColor = disabledContainerColor,
328             disabledContentColor = disabledContentColor,
329         )
330 
331     internal val ColorScheme.defaultFilledIconButtonColors: IconButtonColors
332         get() {
333             return defaultFilledIconButtonColorsCached
334                 ?: IconButtonColors(
335                         containerColor = fromToken(FilledIconButtonTokens.ContainerColor),
336                         contentColor = fromToken(FilledIconButtonTokens.Color),
337                         disabledContainerColor =
338                             fromToken(FilledIconButtonTokens.DisabledContainerColor)
339                                 .copy(alpha = FilledIconButtonTokens.DisabledContainerOpacity),
340                         disabledContentColor =
341                             fromToken(FilledIconButtonTokens.DisabledColor)
342                                 .copy(alpha = FilledIconButtonTokens.DisabledOpacity)
343                     )
344                     .also { defaultFilledIconButtonColorsCached = it }
345         }
346 
347     /**
348      * Creates a [IconToggleButtonColors] that represents the default colors used in a
349      * [FilledIconToggleButton].
350      */
351     @Composable
filledIconToggleButtonColorsnull352     fun filledIconToggleButtonColors(): IconToggleButtonColors =
353         MaterialTheme.colorScheme.defaultFilledIconToggleButtonColors
354 
355     /**
356      * Creates a [IconToggleButtonColors] that represents the default colors used in a
357      * [FilledIconToggleButton].
358      *
359      * @param containerColor the container color of this icon button when enabled.
360      * @param contentColor the content color of this icon button when enabled.
361      * @param disabledContainerColor the container color of this icon button when not enabled.
362      * @param disabledContentColor the content color of this icon button when not enabled.
363      * @param checkedContainerColor the container color of this icon button when checked.
364      * @param checkedContentColor the content color of this icon button when checked.
365      */
366     @Composable
367     fun filledIconToggleButtonColors(
368         containerColor: Color = Color.Unspecified,
369         // TODO(b/228455081): Using contentColorFor here will return OnSurfaceVariant,
370         //  while the token value is Primary.
371         contentColor: Color = Color.Unspecified,
372         disabledContainerColor: Color = Color.Unspecified,
373         disabledContentColor: Color = Color.Unspecified,
374         checkedContainerColor: Color = Color.Unspecified,
375         checkedContentColor: Color = contentColorFor(checkedContainerColor)
376     ): IconToggleButtonColors =
377         MaterialTheme.colorScheme.defaultFilledIconToggleButtonColors.copy(
378             containerColor = containerColor,
379             contentColor = contentColor,
380             disabledContainerColor = disabledContainerColor,
381             disabledContentColor = disabledContentColor,
382             checkedContainerColor = checkedContainerColor,
383             checkedContentColor = checkedContentColor,
384         )
385 
386     internal val ColorScheme.defaultFilledIconToggleButtonColors: IconToggleButtonColors
387         get() {
388             return defaultFilledIconToggleButtonColorsCached
389                 ?: IconToggleButtonColors(
390                         containerColor = fromToken(FilledIconButtonTokens.UnselectedContainerColor),
391                         // TODO(b/228455081): Using contentColorFor here will return
392                         // OnSurfaceVariant,
393                         //  while the token value is Primary.
394                         contentColor = fromToken(FilledIconButtonTokens.UnselectedColor),
395                         disabledContainerColor =
396                             fromToken(FilledIconButtonTokens.DisabledContainerColor)
397                                 .copy(alpha = FilledIconButtonTokens.DisabledContainerOpacity),
398                         disabledContentColor =
399                             fromToken(FilledIconButtonTokens.DisabledColor)
400                                 .copy(alpha = FilledIconButtonTokens.DisabledOpacity),
401                         checkedContainerColor =
402                             fromToken(FilledIconButtonTokens.SelectedContainerColor),
403                         checkedContentColor = fromToken(FilledIconButtonTokens.SelectedColor)
404                     )
405                     .also { defaultFilledIconToggleButtonColorsCached = it }
406         }
407 
408     /**
409      * Creates a [IconButtonColors] that represents the default colors used in a
410      * [FilledTonalIconButton].
411      */
412     @Composable
filledTonalIconButtonColorsnull413     fun filledTonalIconButtonColors(): IconButtonColors =
414         MaterialTheme.colorScheme.defaultFilledTonalIconButtonColors
415 
416     /**
417      * Creates a [IconButtonColors] that represents the default colors used in a
418      * [FilledTonalIconButton].
419      *
420      * @param containerColor the container color of this icon button when enabled.
421      * @param contentColor the content color of this icon button when enabled.
422      * @param disabledContainerColor the container color of this icon button when not enabled.
423      * @param disabledContentColor the content color of this icon button when not enabled.
424      */
425     @Composable
426     fun filledTonalIconButtonColors(
427         containerColor: Color = Color.Unspecified,
428         contentColor: Color = contentColorFor(containerColor),
429         disabledContainerColor: Color = Color.Unspecified,
430         disabledContentColor: Color = Color.Unspecified
431     ): IconButtonColors =
432         MaterialTheme.colorScheme.defaultFilledTonalIconButtonColors.copy(
433             containerColor = containerColor,
434             contentColor = contentColor,
435             disabledContainerColor = disabledContainerColor,
436             disabledContentColor = disabledContentColor,
437         )
438 
439     internal val ColorScheme.defaultFilledTonalIconButtonColors: IconButtonColors
440         get() {
441             return defaultFilledTonalIconButtonColorsCached
442                 ?: IconButtonColors(
443                         containerColor = fromToken(FilledTonalIconButtonTokens.ContainerColor),
444                         contentColor = fromToken(FilledTonalIconButtonTokens.Color),
445                         disabledContainerColor =
446                             fromToken(FilledTonalIconButtonTokens.DisabledContainerColor)
447                                 .copy(alpha = FilledTonalIconButtonTokens.DisabledContainerOpacity),
448                         disabledContentColor =
449                             fromToken(FilledTonalIconButtonTokens.DisabledColor)
450                                 .copy(alpha = FilledTonalIconButtonTokens.DisabledOpacity)
451                     )
452                     .also { defaultFilledTonalIconButtonColorsCached = it }
453         }
454 
455     /**
456      * Creates a [IconToggleButtonColors] that represents the default colors used in a
457      * [FilledTonalIconToggleButton].
458      */
459     @Composable
filledTonalIconToggleButtonColorsnull460     fun filledTonalIconToggleButtonColors(): IconToggleButtonColors =
461         MaterialTheme.colorScheme.defaultFilledTonalIconToggleButtonColors
462 
463     /**
464      * Creates a [IconToggleButtonColors] that represents the default colors used in a
465      * [FilledTonalIconToggleButton].
466      *
467      * @param containerColor the container color of this icon button when enabled.
468      * @param contentColor the content color of this icon button when enabled.
469      * @param disabledContainerColor the container color of this icon button when not enabled.
470      * @param disabledContentColor the content color of this icon button when not enabled.
471      * @param checkedContainerColor the container color of this icon button when checked.
472      * @param checkedContentColor the content color of this icon button when checked.
473      */
474     @Composable
475     fun filledTonalIconToggleButtonColors(
476         containerColor: Color = Color.Unspecified,
477         contentColor: Color = contentColorFor(containerColor),
478         disabledContainerColor: Color = Color.Unspecified,
479         disabledContentColor: Color = Color.Unspecified,
480         checkedContainerColor: Color = Color.Unspecified,
481         checkedContentColor: Color = contentColorFor(checkedContainerColor)
482     ): IconToggleButtonColors =
483         MaterialTheme.colorScheme.defaultFilledTonalIconToggleButtonColors.copy(
484             containerColor = containerColor,
485             contentColor = contentColor,
486             disabledContainerColor = disabledContainerColor,
487             disabledContentColor = disabledContentColor,
488             checkedContainerColor = checkedContainerColor,
489             checkedContentColor = checkedContentColor,
490         )
491 
492     internal val ColorScheme.defaultFilledTonalIconToggleButtonColors: IconToggleButtonColors
493         get() {
494             return defaultFilledTonalIconToggleButtonColorsCached
495                 ?: IconToggleButtonColors(
496                         containerColor =
497                             fromToken(FilledTonalIconButtonTokens.UnselectedContainerColor),
498                         contentColor = fromToken(FilledTonalIconButtonTokens.UnselectedColor),
499                         disabledContainerColor =
500                             fromToken(FilledTonalIconButtonTokens.DisabledContainerColor)
501                                 .copy(alpha = FilledTonalIconButtonTokens.DisabledContainerOpacity),
502                         disabledContentColor =
503                             fromToken(FilledTonalIconButtonTokens.DisabledColor)
504                                 .copy(alpha = FilledTonalIconButtonTokens.DisabledOpacity),
505                         checkedContainerColor =
506                             fromToken(FilledTonalIconButtonTokens.SelectedContainerColor),
507                         checkedContentColor = fromToken(FilledTonalIconButtonTokens.SelectedColor)
508                     )
509                     .also { defaultFilledTonalIconToggleButtonColorsCached = it }
510         }
511 
512     /**
513      * Creates a [IconButtonColors] that represents the default colors used in a
514      * [OutlinedIconButton]. [LocalContentColor] will be applied to the icon and down the UI tree.
515      *
516      * See [outlinedIconButtonVibrantColors] for default values that applies the recommended high
517      * contrast colors.
518      */
519     @Composable
outlinedIconButtonColorsnull520     fun outlinedIconButtonColors(): IconButtonColors {
521         val contentColor = LocalContentColor.current
522         val colors = MaterialTheme.colorScheme.defaultOutlinedIconButtonColors(contentColor)
523         if (colors.contentColor == contentColor) {
524             return colors
525         } else {
526             return colors.copy(
527                 contentColor = contentColor,
528                 disabledContentColor =
529                     contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
530             )
531         }
532     }
533 
534     /**
535      * Creates a [IconButtonColors] that represents the default colors used in a
536      * [OutlinedIconButton].
537      *
538      * See [outlinedIconButtonVibrantColors] for default values that applies the recommended high
539      * contrast colors.
540      *
541      * @param containerColor the container color of this icon button when enabled.
542      * @param contentColor the content color of this icon button when enabled.
543      * @param disabledContainerColor the container color of this icon button when not enabled.
544      * @param disabledContentColor the content color of this icon button when not enabled.
545      */
546     @Composable
outlinedIconButtonColorsnull547     fun outlinedIconButtonColors(
548         containerColor: Color = Color.Unspecified,
549         contentColor: Color = LocalContentColor.current,
550         disabledContainerColor: Color = Color.Unspecified,
551         disabledContentColor: Color =
552             contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
553     ): IconButtonColors =
554         MaterialTheme.colorScheme
555             .defaultOutlinedIconButtonColors(LocalContentColor.current)
556             .copy(
557                 containerColor = containerColor,
558                 contentColor = contentColor,
559                 disabledContainerColor = disabledContainerColor,
560                 disabledContentColor = disabledContentColor,
561             )
562 
563     internal fun ColorScheme.defaultOutlinedIconButtonColors(
564         localContentColor: Color
565     ): IconButtonColors {
566         return defaultOutlinedIconButtonColorsCached
567             ?: run {
568                 IconButtonColors(
569                         containerColor = Color.Transparent,
570                         contentColor = localContentColor,
571                         disabledContainerColor = Color.Transparent,
572                         disabledContentColor =
573                             localContentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
574                     )
575                     .also { defaultOutlinedIconButtonColorsCached = it }
576             }
577     }
578 
579     /**
580      * Creates a [IconButtonColors] that represents the default colors used in a
581      * [OutlinedIconButton].
582      *
583      * See [outlinedIconButtonColors] for default values that applies [LocalContentColor] to the
584      * icon and down the UI tree.
585      */
586     @Composable
outlinedIconButtonVibrantColorsnull587     fun outlinedIconButtonVibrantColors(): IconButtonColors =
588         MaterialTheme.colorScheme.defaultOutlinedIconButtonVibrantColors()
589 
590     /**
591      * Creates a [IconButtonColors] that represents the default colors used in a
592      * [OutlinedIconButton].
593      *
594      * See [outlinedIconButtonColors] for default values that applies [LocalContentColor] to the
595      * icon and down the UI tree.
596      *
597      * @param containerColor the container color of this icon button when enabled.
598      * @param contentColor the content color of this icon button when enabled.
599      * @param disabledContainerColor the container color of this icon button when not enabled.
600      * @param disabledContentColor the content color of this icon button when not enabled.
601      */
602     @Composable
603     fun outlinedIconButtonVibrantColors(
604         containerColor: Color = Color.Unspecified,
605         contentColor: Color = Color.Unspecified,
606         disabledContainerColor: Color = Color.Unspecified,
607         disabledContentColor: Color =
608             contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
609     ): IconButtonColors =
610         MaterialTheme.colorScheme
611             .defaultOutlinedIconButtonVibrantColors()
612             .copy(
613                 containerColor = containerColor,
614                 contentColor = contentColor,
615                 disabledContainerColor = disabledContainerColor,
616                 disabledContentColor = disabledContentColor,
617             )
618 
619     internal fun ColorScheme.defaultOutlinedIconButtonVibrantColors(): IconButtonColors {
620         return defaultOutlinedIconButtonVibrantColorsCached
621             ?: run {
622                 IconButtonColors(
623                         containerColor = Color.Transparent,
624                         contentColor = fromToken(OutlinedIconButtonTokens.Color),
625                         disabledContainerColor = Color.Transparent,
626                         disabledContentColor =
627                             fromToken(OutlinedIconButtonTokens.DisabledColor)
628                                 .copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
629                     )
630                     .also { defaultOutlinedIconButtonVibrantColorsCached = it }
631             }
632     }
633 
634     /**
635      * Creates a [IconToggleButtonColors] that represents the default colors used in a
636      * [OutlinedIconToggleButton]. [LocalContentColor] will be applied to the icon and down the UI
637      * tree.
638      *
639      * See [outlinedIconButtonVibrantColors] for default values that applies the recommended high
640      * contrast colors.
641      */
642     @Composable
outlinedIconToggleButtonColorsnull643     fun outlinedIconToggleButtonColors(): IconToggleButtonColors {
644         val contentColor = LocalContentColor.current
645         val colors = MaterialTheme.colorScheme.defaultOutlinedIconToggleButtonColors(contentColor)
646         if (colors.contentColor == contentColor) {
647             return colors
648         } else {
649             return colors.copy(
650                 contentColor = contentColor,
651                 disabledContentColor =
652                     contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
653             )
654         }
655     }
656 
657     /**
658      * Creates a [IconToggleButtonColors] that represents the default colors used in a
659      * [OutlinedIconToggleButton]. [LocalContentColor] will be applied to the icon and down the UI
660      * tree.
661      *
662      * See [outlinedIconButtonVibrantColors] for default values that applies the recommended high
663      * contrast colors.
664      *
665      * @param containerColor the container color of this icon button when enabled.
666      * @param contentColor the content color of this icon button when enabled.
667      * @param disabledContainerColor the container color of this icon button when not enabled.
668      * @param disabledContentColor the content color of this icon button when not enabled.
669      * @param checkedContainerColor the container color of this icon button when checked.
670      * @param checkedContentColor the content color of this icon button when checked.
671      */
672     @Composable
outlinedIconToggleButtonColorsnull673     fun outlinedIconToggleButtonColors(
674         containerColor: Color = Color.Unspecified,
675         contentColor: Color = LocalContentColor.current,
676         disabledContainerColor: Color = Color.Unspecified,
677         disabledContentColor: Color =
678             contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity),
679         checkedContainerColor: Color = Color.Unspecified,
680         checkedContentColor: Color = contentColorFor(checkedContainerColor)
681     ): IconToggleButtonColors =
682         MaterialTheme.colorScheme
683             .defaultOutlinedIconToggleButtonColors(LocalContentColor.current)
684             .copy(
685                 containerColor = containerColor,
686                 contentColor = contentColor,
687                 disabledContainerColor = disabledContainerColor,
688                 disabledContentColor = disabledContentColor,
689                 checkedContainerColor = checkedContainerColor,
690                 checkedContentColor = checkedContentColor,
691             )
692 
693     internal fun ColorScheme.defaultOutlinedIconToggleButtonColors(
694         localContentColor: Color
695     ): IconToggleButtonColors {
696         return defaultIconToggleButtonColorsCached
697             ?: run {
698                 IconToggleButtonColors(
699                         containerColor = Color.Transparent,
700                         contentColor = localContentColor,
701                         disabledContainerColor = Color.Transparent,
702                         disabledContentColor =
703                             localContentColor.copy(
704                                 alpha = OutlinedIconButtonTokens.DisabledOpacity
705                             ),
706                         checkedContainerColor =
707                             fromToken(OutlinedIconButtonTokens.SelectedContainerColor),
708                         checkedContentColor =
709                             contentColorFor(
710                                 fromToken(OutlinedIconButtonTokens.SelectedContainerColor)
711                             )
712                     )
713                     .also { defaultOutlinedIconToggleButtonColorsCached = it }
714             }
715     }
716 
717     /**
718      * Creates a [IconToggleButtonColors] that represents the default colors used in a
719      * [OutlinedIconToggleButton].
720      *
721      * See [outlinedIconToggleButtonColors] for default values that applies [LocalContentColor] to
722      * the icon and down the UI tree.
723      */
724     @Composable
outlinedIconToggleButtonVibrantColorsnull725     fun outlinedIconToggleButtonVibrantColors(): IconToggleButtonColors =
726         MaterialTheme.colorScheme.defaultOutlinedIconToggleButtonVibrantColors()
727 
728     /**
729      * Creates a [IconToggleButtonColors] that represents the default colors used in a
730      * [OutlinedIconToggleButton].
731      *
732      * See [outlinedIconToggleButtonColors] for default values that applies [LocalContentColor] to
733      * the icon and down the UI tree.
734      *
735      * @param containerColor the container color of this icon button when enabled.
736      * @param contentColor the content color of this icon button when enabled.
737      * @param disabledContainerColor the container color of this icon button when not enabled.
738      * @param disabledContentColor the content color of this icon button when not enabled.
739      * @param checkedContainerColor the container color of this icon button when checked.
740      * @param checkedContentColor the content color of this icon button when checked.
741      */
742     @Composable
743     fun outlinedIconToggleButtonVibrantColors(
744         containerColor: Color = Color.Unspecified,
745         contentColor: Color = Color.Unspecified,
746         disabledContainerColor: Color = Color.Unspecified,
747         disabledContentColor: Color =
748             contentColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity),
749         checkedContainerColor: Color = Color.Unspecified,
750         checkedContentColor: Color = contentColorFor(checkedContainerColor)
751     ): IconToggleButtonColors =
752         MaterialTheme.colorScheme
753             .defaultOutlinedIconToggleButtonVibrantColors()
754             .copy(
755                 containerColor = containerColor,
756                 contentColor = contentColor,
757                 disabledContainerColor = disabledContainerColor,
758                 disabledContentColor = disabledContentColor,
759                 checkedContainerColor = checkedContainerColor,
760                 checkedContentColor = checkedContentColor,
761             )
762 
763     internal fun ColorScheme.defaultOutlinedIconToggleButtonVibrantColors():
764         IconToggleButtonColors {
765         return defaultOutlinedIconToggleButtonVibrantColorsCached
766             ?: run {
767                 IconToggleButtonColors(
768                         containerColor = Color.Transparent,
769                         contentColor = fromToken(OutlinedIconButtonTokens.UnselectedColor),
770                         disabledContainerColor = Color.Transparent,
771                         disabledContentColor =
772                             fromToken(OutlinedIconButtonTokens.DisabledColor)
773                                 .copy(alpha = OutlinedIconButtonTokens.DisabledOpacity),
774                         checkedContainerColor =
775                             fromToken(OutlinedIconButtonTokens.SelectedContainerColor),
776                         checkedContentColor = fromToken(OutlinedIconButtonTokens.SelectedColor)
777                     )
778                     .also { defaultOutlinedIconToggleButtonColorsCached = it }
779             }
780     }
781 
782     /**
783      * Represents the [BorderStroke] for an [OutlinedIconButton], depending on its [enabled] and
784      * [checked] state. [LocalContentColor] will be used as the border color.
785      *
786      * See [outlinedIconToggleButtonVibrantBorder] for a [BorderStroke] that uses the spec
787      * recommended color as the border color.
788      *
789      * @param enabled whether the icon button is enabled
790      * @param checked whether the icon button is checked
791      */
792     @Composable
outlinedIconToggleButtonBordernull793     fun outlinedIconToggleButtonBorder(enabled: Boolean, checked: Boolean): BorderStroke? {
794         if (checked) {
795             return null
796         }
797         return outlinedIconButtonBorder(enabled)
798     }
799 
800     /**
801      * Represents the [BorderStroke] for an [OutlinedIconButton], depending on its [enabled] and
802      * [checked] state. The spec recommended color will be used as the border color.
803      *
804      * @param enabled whether the icon button is enabled
805      * @param checked whether the icon button is checked
806      */
807     @Composable
outlinedIconToggleButtonVibrantBordernull808     fun outlinedIconToggleButtonVibrantBorder(enabled: Boolean, checked: Boolean): BorderStroke? {
809         if (checked) {
810             return null
811         }
812         return outlinedIconButtonVibrantBorder(enabled)
813     }
814 
815     /**
816      * Represents the [BorderStroke] for an [OutlinedIconButton], depending on its [enabled] state.
817      * [LocalContentColor] will be used as the border color.
818      *
819      * See [outlinedIconToggleButtonVibrantBorder] for a [BorderStroke] that uses the spec
820      * recommended color as the border color.
821      *
822      * @param enabled whether the icon button is enabled
823      */
824     @Composable
outlinedIconButtonBordernull825     fun outlinedIconButtonBorder(enabled: Boolean): BorderStroke {
826         val outlineColor = LocalContentColor.current
827         val color: Color =
828             if (enabled) {
829                 outlineColor
830             } else {
831                 outlineColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
832             }
833         return remember(color) { BorderStroke(SmallIconButtonTokens.OutlinedOutlineWidth, color) }
834     }
835 
836     /**
837      * Represents the [BorderStroke] for an [OutlinedIconButton], depending on its [enabled] state.
838      * The spec recommended color will be used as the border color.
839      *
840      * @param enabled whether the icon button is enabled
841      */
842     @Composable
outlinedIconButtonVibrantBordernull843     fun outlinedIconButtonVibrantBorder(enabled: Boolean): BorderStroke {
844         val outlineColor = OutlinedIconButtonTokens.OutlineColor.value
845         val color: Color =
846             if (enabled) {
847                 outlineColor
848             } else {
849                 outlineColor.copy(alpha = OutlinedIconButtonTokens.DisabledOpacity)
850             }
851         return remember(color) { BorderStroke(SmallIconButtonTokens.OutlinedOutlineWidth, color) }
852     }
853 
854     /** Default ripple shape for a standard icon button. */
855     val standardShape: Shape
856         @Composable get() = SmallIconButtonTokens.ContainerShapeRound.value
857 
858     /** Default shape for a filled icon button. */
859     val filledShape: Shape
860         @Composable get() = SmallIconButtonTokens.ContainerShapeRound.value
861 
862     /** Default shape for an outlined icon button. */
863     val outlinedShape: Shape
864         @Composable get() = SmallIconButtonTokens.ContainerShapeRound.value
865 
866     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
867     @get:ExperimentalMaterial3ExpressiveApi
868     @ExperimentalMaterial3ExpressiveApi
869     /** Default round shape for any extra small icon button. */
870     val extraSmallRoundShape: Shape
871         @Composable get() = XSmallIconButtonTokens.ContainerShapeRound.value
872 
873     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
874     @get:ExperimentalMaterial3ExpressiveApi
875     @ExperimentalMaterial3ExpressiveApi
876     /** Default square shape for any extra small icon button. */
877     val extraSmallSquareShape: Shape
878         @Composable get() = XSmallIconButtonTokens.ContainerShapeSquare.value
879 
880     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
881     @get:ExperimentalMaterial3ExpressiveApi
882     @ExperimentalMaterial3ExpressiveApi
883     /** Default pressed shape for any extra small icon button. */
884     val extraSmallPressedShape: Shape
885         @Composable get() = XSmallIconButtonTokens.PressedContainerShape.value
886 
887     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
888     @get:ExperimentalMaterial3ExpressiveApi
889     @ExperimentalMaterial3ExpressiveApi
890     /** Default selected shape for any extra small icon button. */
891     val extraSmallSelectedRoundShape: Shape
892         @Composable get() = XSmallIconButtonTokens.SelectedContainerShapeRound.value
893 
894     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
895     @get:ExperimentalMaterial3ExpressiveApi
896     @ExperimentalMaterial3ExpressiveApi
897     /** Default selected shape for any extra small, square icon button. */
898     val extraSmallSelectedSquareShape: Shape
899         @Composable get() = XSmallIconButtonTokens.SelectedContainerShapeSquare.value
900 
901     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
902     @get:ExperimentalMaterial3ExpressiveApi
903     @ExperimentalMaterial3ExpressiveApi
904     /** Default shape for any small icon button. */
905     val smallRoundShape: Shape
906         @Composable get() = SmallIconButtonTokens.ContainerShapeRound.value
907 
908     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
909     @get:ExperimentalMaterial3ExpressiveApi
910     @ExperimentalMaterial3ExpressiveApi
911     /** Default square shape for any small icon button. */
912     val smallSquareShape: Shape
913         @Composable get() = SmallIconButtonTokens.ContainerShapeSquare.value
914 
915     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
916     @get:ExperimentalMaterial3ExpressiveApi
917     @ExperimentalMaterial3ExpressiveApi
918     /** Default pressed shape for any small icon button. */
919     val smallPressedShape: Shape
920         @Composable get() = SmallIconButtonTokens.PressedContainerShape.value
921 
922     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
923     @get:ExperimentalMaterial3ExpressiveApi
924     @ExperimentalMaterial3ExpressiveApi
925     /** Default selected shape for any small icon button. */
926     val smallSelectedRoundShape: Shape
927         @Composable get() = SmallIconButtonTokens.SelectedContainerShapeRound.value
928 
929     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
930     @get:ExperimentalMaterial3ExpressiveApi
931     @ExperimentalMaterial3ExpressiveApi
932     /** Default selected shape for any small, square icon button. */
933     val SmallSelectedSquareShape: Shape
934         @Composable get() = SmallIconButtonTokens.SelectedContainerShapeSquare.value
935 
936     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
937     @get:ExperimentalMaterial3ExpressiveApi
938     @ExperimentalMaterial3ExpressiveApi
939     /** Default shape for any medium icon button. */
940     val mediumRoundShape: Shape
941         @Composable get() = MediumIconButtonTokens.ContainerShapeRound.value
942 
943     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
944     @get:ExperimentalMaterial3ExpressiveApi
945     @ExperimentalMaterial3ExpressiveApi
946     /** Default shape for any medium icon button. */
947     val mediumSquareShape: Shape
948         @Composable get() = MediumIconButtonTokens.ContainerShapeSquare.value
949 
950     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
951     @get:ExperimentalMaterial3ExpressiveApi
952     @ExperimentalMaterial3ExpressiveApi
953     /** Default pressed shape for any medium icon button. */
954     val mediumPressedShape: Shape
955         @Composable get() = MediumIconButtonTokens.PressedContainerShape.value
956 
957     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
958     @get:ExperimentalMaterial3ExpressiveApi
959     @ExperimentalMaterial3ExpressiveApi
960     /** Default selected shape for any medium icon button. */
961     val mediumSelectedRoundShape: Shape
962         @Composable get() = MediumIconButtonTokens.SelectedContainerShapeRound.value
963 
964     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
965     @get:ExperimentalMaterial3ExpressiveApi
966     @ExperimentalMaterial3ExpressiveApi
967     /** Default selected shape for any medium, square icon button. */
968     val mediumSelectedSquareShape: Shape
969         @Composable get() = MediumIconButtonTokens.SelectedContainerShapeSquare.value
970 
971     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
972     @get:ExperimentalMaterial3ExpressiveApi
973     @ExperimentalMaterial3ExpressiveApi
974     /** Default shape for any large icon button. */
975     val largeRoundShape: Shape
976         @Composable get() = LargeIconButtonTokens.ContainerShapeRound.value
977 
978     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
979     @get:ExperimentalMaterial3ExpressiveApi
980     @ExperimentalMaterial3ExpressiveApi
981     /** Default shape for any large icon button. */
982     val largeSquareShape: Shape
983         @Composable get() = LargeIconButtonTokens.ContainerShapeSquare.value
984 
985     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
986     @get:ExperimentalMaterial3ExpressiveApi
987     @ExperimentalMaterial3ExpressiveApi
988     /** Default pressed shape for any large icon button. */
989     val largePressedShape: Shape
990         @Composable get() = LargeIconButtonTokens.PressedContainerShape.value
991 
992     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
993     @get:ExperimentalMaterial3ExpressiveApi
994     @ExperimentalMaterial3ExpressiveApi
995     /** Default selected shape for any large icon button. */
996     val largeSelectedRoundShape: Shape
997         @Composable get() = LargeIconButtonTokens.SelectedContainerShapeRound.value
998 
999     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1000     @get:ExperimentalMaterial3ExpressiveApi
1001     @ExperimentalMaterial3ExpressiveApi
1002     /** Default selected shape for any large, square icon button. */
1003     val largeSelectedSquareShape: Shape
1004         @Composable get() = LargeIconButtonTokens.SelectedContainerShapeSquare.value
1005 
1006     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1007     @get:ExperimentalMaterial3ExpressiveApi
1008     @ExperimentalMaterial3ExpressiveApi
1009     /** Default shape for any extra large icon button. */
1010     val extraLargeRoundShape: Shape
1011         @Composable get() = XLargeIconButtonTokens.ContainerShapeRound.value
1012 
1013     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1014     @get:ExperimentalMaterial3ExpressiveApi
1015     @ExperimentalMaterial3ExpressiveApi
1016     /** Default shape for any extra large icon button. */
1017     val extraLargeSquareShape: Shape
1018         @Composable get() = XLargeIconButtonTokens.ContainerShapeSquare.value
1019 
1020     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1021     @get:ExperimentalMaterial3ExpressiveApi
1022     @ExperimentalMaterial3ExpressiveApi
1023     /** Default pressed shape for any extra large icon button. */
1024     val extraLargePressedShape: Shape
1025         @Composable get() = XLargeIconButtonTokens.PressedContainerShape.value
1026 
1027     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1028     @get:ExperimentalMaterial3ExpressiveApi
1029     @ExperimentalMaterial3ExpressiveApi
1030     /** Default selected shape for any extra large icon button. */
1031     val extraLargeSelectedRoundShape: Shape
1032         @Composable get() = XLargeIconButtonTokens.SelectedContainerShapeRound.value
1033 
1034     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1035     @get:ExperimentalMaterial3ExpressiveApi
1036     @ExperimentalMaterial3ExpressiveApi
1037     /** Default selected shape for any extra large, square icon button. */
1038     val extraLargeSelectedSquareShape: Shape
1039         @Composable get() = XLargeIconButtonTokens.SelectedContainerShapeSquare.value
1040 
1041     /**
1042      * Creates a [IconButtonShapes] that correspond to the shapes in the default or pressed states.
1043      * Icon button will morph between these shapes as long as the shapes are all
1044      * [CornerBasedShape]s.
1045      *
1046      * @param shape the unchecked shape for [ButtonShapes]
1047      * @param pressedShape the unchecked shape for [ButtonShapes]
1048      */
1049     @ExperimentalMaterial3ExpressiveApi
1050     @Composable
shapesnull1051     fun shapes(shape: Shape? = null, pressedShape: Shape? = null): IconButtonShapes =
1052         MaterialTheme.shapes.defaultIconButtonShapes.copy(
1053             shape = shape,
1054             pressedShape = pressedShape,
1055         )
1056 
1057     /**
1058      * Creates a [IconButtonShapes] that correspond to a default [IconButton] in the active and
1059      * pressed states. [IconButton] will morph between these shapes as long as the shapes are all
1060      * [CornerBasedShape]s.
1061      */
1062     @ExperimentalMaterial3ExpressiveApi
1063     @Composable
1064     fun shapes(): IconButtonShapes = MaterialTheme.shapes.defaultIconButtonShapes
1065 
1066     @OptIn(ExperimentalMaterial3ExpressiveApi::class)
1067     internal val Shapes.defaultIconButtonShapes: IconButtonShapes
1068         get() {
1069             return defaultIconButtonShapesCached
1070                 ?: IconButtonShapes(
1071                         shape = fromToken(SmallIconButtonTokens.ContainerShapeRound),
1072                         pressedShape = fromToken(SmallIconButtonTokens.PressedContainerShape),
1073                     )
1074                     .also { defaultIconButtonShapesCached = it }
1075         }
1076 
1077     /**
1078      * Creates a [IconToggleButtonShapes] that correspond to the shapes in the default, pressed, and
1079      * checked states. Icon button will morph between these shapes as long as the shapes are all
1080      * [CornerBasedShape]s.
1081      *
1082      * @param shape the active shape for [IconToggleButtonShapes]
1083      * @param pressedShape the pressed shape for [IconToggleButtonShapes]
1084      * @param checkedShape the checked shape for [IconToggleButtonShapes]
1085      */
1086     @ExperimentalMaterial3ExpressiveApi
1087     @Composable
toggleableShapesnull1088     fun toggleableShapes(
1089         shape: Shape? = null,
1090         pressedShape: Shape? = null,
1091         checkedShape: Shape? = null
1092     ): IconToggleButtonShapes =
1093         MaterialTheme.shapes.defaultIconToggleButtonShapes.copy(
1094             shape = shape,
1095             pressedShape = pressedShape,
1096             checkedShape = checkedShape
1097         )
1098 
1099     /**
1100      * Creates a [ButtonShapes] that correspond to a default [IconToggleButton] in the active,
1101      * pressed and selected states. [IconToggleButton] will morph between these shapes as long as
1102      * the shapes are all [CornerBasedShape]s.
1103      */
1104     @ExperimentalMaterial3ExpressiveApi
1105     @Composable
1106     fun toggleableShapes(): IconToggleButtonShapes =
1107         MaterialTheme.shapes.defaultIconToggleButtonShapes
1108 
1109     @OptIn(ExperimentalMaterial3ExpressiveApi::class)
1110     internal val Shapes.defaultIconToggleButtonShapes: IconToggleButtonShapes
1111         get() {
1112             return defaultIconToggleButtonShapesCached
1113                 ?: IconToggleButtonShapes(
1114                         shape = fromToken(SmallIconButtonTokens.ContainerShapeRound),
1115                         pressedShape = fromToken(SmallIconButtonTokens.PressedContainerShape),
1116                         checkedShape = fromToken(SmallIconButtonTokens.SelectedContainerShapeRound)
1117                     )
1118                     .also { defaultIconToggleButtonShapesCached = it }
1119         }
1120 
1121     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1122     @get:ExperimentalMaterial3ExpressiveApi
1123     @ExperimentalMaterial3ExpressiveApi
1124     /** Default container for any extra small icon button. */
1125     val extraSmallIconSize: Dp = XSmallIconButtonTokens.IconSize
1126 
1127     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1128     @get:ExperimentalMaterial3ExpressiveApi
1129     @ExperimentalMaterial3ExpressiveApi
1130     /** Default size for any small icon button. */
1131     val smallIconSize: Dp = SmallIconButtonTokens.IconSize
1132 
1133     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1134     @get:ExperimentalMaterial3ExpressiveApi
1135     @ExperimentalMaterial3ExpressiveApi
1136     /** Default container size for any medium icon button. */
1137     val mediumIconSize: Dp = MediumIconButtonTokens.IconSize
1138 
1139     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1140     @get:ExperimentalMaterial3ExpressiveApi
1141     @ExperimentalMaterial3ExpressiveApi
1142     /** Default size for any large icon button. */
1143     val largeIconSize: Dp = LargeIconButtonTokens.IconSize
1144 
1145     /** Default size for any xlarge icon button. */
1146     @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1147     @get:ExperimentalMaterial3ExpressiveApi
1148     @ExperimentalMaterial3ExpressiveApi
1149     val extraLargeIconSize: Dp = XLargeIconButtonTokens.IconSize
1150 
1151     /**
1152      * Default container size for any extra small icon button.
1153      *
1154      * @param widthOption the width of the container
1155      */
1156     @ExperimentalMaterial3ExpressiveApi
extraSmallContainerSizenull1157     fun extraSmallContainerSize(
1158         widthOption: IconButtonWidthOption = IconButtonWidthOption.Uniform
1159     ): DpSize {
1160         val horizontalSpace =
1161             when (widthOption) {
1162                 IconButtonWidthOption.Narrow ->
1163                     XSmallIconButtonTokens.NarrowLeadingSpace +
1164                         XSmallIconButtonTokens.NarrowTrailingSpace
1165                 IconButtonWidthOption.Uniform ->
1166                     XSmallIconButtonTokens.DefaultLeadingSpace +
1167                         XSmallIconButtonTokens.DefaultLeadingSpace
1168                 IconButtonWidthOption.Wide ->
1169                     XSmallIconButtonTokens.WideLeadingSpace +
1170                         XSmallIconButtonTokens.WideTrailingSpace
1171                 else -> 0.dp
1172             }
1173         return DpSize(
1174             XSmallIconButtonTokens.IconSize + horizontalSpace,
1175             XSmallIconButtonTokens.ContainerHeight
1176         )
1177     }
1178 
1179     /**
1180      * Default container size for any small icon button.
1181      *
1182      * @param widthOption the width of the container
1183      */
1184     @ExperimentalMaterial3ExpressiveApi
smallContainerSizenull1185     fun smallContainerSize(
1186         widthOption: IconButtonWidthOption = IconButtonWidthOption.Uniform
1187     ): DpSize {
1188         val horizontalSpace =
1189             when (widthOption) {
1190                 IconButtonWidthOption.Narrow ->
1191                     SmallIconButtonTokens.NarrowLeadingSpace +
1192                         SmallIconButtonTokens.NarrowTrailingSpace
1193                 IconButtonWidthOption.Uniform ->
1194                     SmallIconButtonTokens.DefaultLeadingSpace +
1195                         SmallIconButtonTokens.DefaultLeadingSpace
1196                 IconButtonWidthOption.Wide ->
1197                     SmallIconButtonTokens.WideLeadingSpace + SmallIconButtonTokens.WideTrailingSpace
1198                 else -> 0.dp
1199             }
1200         return DpSize(
1201             SmallIconButtonTokens.IconSize + horizontalSpace,
1202             SmallIconButtonTokens.ContainerHeight
1203         )
1204     }
1205 
1206     /**
1207      * Default container size for any medium icon button.
1208      *
1209      * @param widthOption the width of the container
1210      */
1211     @ExperimentalMaterial3ExpressiveApi
mediumContainerSizenull1212     fun mediumContainerSize(
1213         widthOption: IconButtonWidthOption = IconButtonWidthOption.Uniform
1214     ): DpSize {
1215         val horizontalSpace =
1216             when (widthOption) {
1217                 IconButtonWidthOption.Narrow ->
1218                     MediumIconButtonTokens.NarrowLeadingSpace +
1219                         MediumIconButtonTokens.NarrowTrailingSpace
1220                 IconButtonWidthOption.Uniform ->
1221                     MediumIconButtonTokens.DefaultLeadingSpace +
1222                         MediumIconButtonTokens.DefaultLeadingSpace
1223                 IconButtonWidthOption.Wide ->
1224                     MediumIconButtonTokens.WideLeadingSpace +
1225                         MediumIconButtonTokens.WideTrailingSpace
1226                 else -> 0.dp
1227             }
1228         return DpSize(
1229             MediumIconButtonTokens.IconSize + horizontalSpace,
1230             MediumIconButtonTokens.ContainerHeight
1231         )
1232     }
1233 
1234     /**
1235      * Default container size for any large icon button.
1236      *
1237      * @param widthOption the width of the container
1238      */
1239     @ExperimentalMaterial3ExpressiveApi
largeContainerSizenull1240     fun largeContainerSize(
1241         widthOption: IconButtonWidthOption = IconButtonWidthOption.Uniform
1242     ): DpSize {
1243         val horizontalSpace =
1244             when (widthOption) {
1245                 IconButtonWidthOption.Narrow ->
1246                     LargeIconButtonTokens.NarrowLeadingSpace +
1247                         LargeIconButtonTokens.NarrowTrailingSpace
1248                 IconButtonWidthOption.Uniform ->
1249                     LargeIconButtonTokens.UniformLeadingSpace +
1250                         LargeIconButtonTokens.UniformLeadingSpace
1251                 IconButtonWidthOption.Wide ->
1252                     LargeIconButtonTokens.WideLeadingSpace + LargeIconButtonTokens.WideTrailingSpace
1253                 else -> 0.dp
1254             }
1255         return DpSize(
1256             LargeIconButtonTokens.IconSize + horizontalSpace,
1257             LargeIconButtonTokens.ContainerHeight
1258         )
1259     }
1260 
1261     /**
1262      * Default container size for any extra large icon button.
1263      *
1264      * @param widthOption the width of the container
1265      */
1266     @ExperimentalMaterial3ExpressiveApi
extraLargeContainerSizenull1267     fun extraLargeContainerSize(
1268         widthOption: IconButtonWidthOption = IconButtonWidthOption.Uniform
1269     ): DpSize {
1270         val horizontalSpace =
1271             when (widthOption) {
1272                 IconButtonWidthOption.Narrow ->
1273                     XLargeIconButtonTokens.NarrowLeadingSpace +
1274                         XLargeIconButtonTokens.NarrowTrailingSpace
1275                 IconButtonWidthOption.Uniform ->
1276                     XLargeIconButtonTokens.DefaultLeadingSpace +
1277                         XLargeIconButtonTokens.DefaultLeadingSpace
1278                 IconButtonWidthOption.Wide ->
1279                     XLargeIconButtonTokens.WideLeadingSpace +
1280                         XLargeIconButtonTokens.WideTrailingSpace
1281                 else -> 0.dp
1282             }
1283         return DpSize(
1284             XLargeIconButtonTokens.IconSize + horizontalSpace,
1285             XLargeIconButtonTokens.ContainerHeight
1286         )
1287     }
1288 
1289     /** Class that describes the different supported widths of the [IconButton]. */
1290     @JvmInline
1291     value class IconButtonWidthOption private constructor(private val value: Int) {
1292         companion object {
1293             // TODO(b/342666275): update this kdoc with spec guidance
1294             /*
1295              * This configuration is recommended for small screens.
1296              */
1297             val Narrow = IconButtonWidthOption(0)
1298 
1299             /*
1300              * This configuration is recommended for medium width screens.
1301              */
1302             val Uniform = IconButtonWidthOption(1)
1303 
1304             /*
1305              * This configuration is recommended for wide screens.
1306              */
1307             val Wide = IconButtonWidthOption(2)
1308         }
1309 
toStringnull1310         override fun toString() =
1311             when (this) {
1312                 Narrow -> "Narrow"
1313                 Uniform -> "Uniform"
1314                 Wide -> "Wide"
1315                 else -> "Unknown"
1316             }
1317     }
1318 }
1319