1 /*
<lambda>null2  * Copyright 2023 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 @file:Suppress("DEPRECATION") // Suppress for imports of WindowWidthSizeClass
18 
19 package androidx.compose.material3.adaptive.navigationsuite
20 
21 import androidx.compose.animation.core.Animatable
22 import androidx.compose.animation.core.SpringSpec
23 import androidx.compose.animation.core.VectorConverter
24 import androidx.compose.animation.core.animateFloatAsState
25 import androidx.compose.animation.core.spring
26 import androidx.compose.foundation.interaction.Interaction
27 import androidx.compose.foundation.interaction.MutableInteractionSource
28 import androidx.compose.foundation.layout.Arrangement
29 import androidx.compose.foundation.layout.Box
30 import androidx.compose.foundation.layout.Spacer
31 import androidx.compose.foundation.layout.WindowInsets
32 import androidx.compose.foundation.layout.WindowInsetsSides
33 import androidx.compose.foundation.layout.consumeWindowInsets
34 import androidx.compose.foundation.layout.heightIn
35 import androidx.compose.foundation.layout.only
36 import androidx.compose.foundation.layout.padding
37 import androidx.compose.material3.BadgedBox
38 import androidx.compose.material3.DrawerDefaults
39 import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
40 import androidx.compose.material3.Icon
41 import androidx.compose.material3.LocalContentColor
42 import androidx.compose.material3.MaterialTheme
43 import androidx.compose.material3.NavigationBar
44 import androidx.compose.material3.NavigationBarDefaults
45 import androidx.compose.material3.NavigationBarItem
46 import androidx.compose.material3.NavigationBarItemColors
47 import androidx.compose.material3.NavigationBarItemDefaults
48 import androidx.compose.material3.NavigationDrawerItem
49 import androidx.compose.material3.NavigationDrawerItemColors
50 import androidx.compose.material3.NavigationDrawerItemDefaults
51 import androidx.compose.material3.NavigationItemColors
52 import androidx.compose.material3.NavigationItemIconPosition
53 import androidx.compose.material3.NavigationRail
54 import androidx.compose.material3.NavigationRailDefaults
55 import androidx.compose.material3.NavigationRailItem
56 import androidx.compose.material3.NavigationRailItemColors
57 import androidx.compose.material3.NavigationRailItemDefaults
58 import androidx.compose.material3.PermanentDrawerSheet
59 import androidx.compose.material3.ShortNavigationBar
60 import androidx.compose.material3.ShortNavigationBarDefaults
61 import androidx.compose.material3.ShortNavigationBarItem
62 import androidx.compose.material3.ShortNavigationBarItemDefaults
63 import androidx.compose.material3.Surface
64 import androidx.compose.material3.Text
65 import androidx.compose.material3.WideNavigationRail
66 import androidx.compose.material3.WideNavigationRailColors
67 import androidx.compose.material3.WideNavigationRailDefaults
68 import androidx.compose.material3.WideNavigationRailItem
69 import androidx.compose.material3.WideNavigationRailItemDefaults
70 import androidx.compose.material3.WideNavigationRailValue
71 import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveComponentOverrideApi
72 import androidx.compose.material3.adaptive.WindowAdaptiveInfo
73 import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
74 import androidx.compose.material3.contentColorFor
75 import androidx.compose.material3.rememberWideNavigationRailState
76 import androidx.compose.runtime.Composable
77 import androidx.compose.runtime.ProvidableCompositionLocal
78 import androidx.compose.runtime.Stable
79 import androidx.compose.runtime.State
80 import androidx.compose.runtime.collection.MutableVector
81 import androidx.compose.runtime.collection.mutableVectorOf
82 import androidx.compose.runtime.compositionLocalOf
83 import androidx.compose.runtime.derivedStateOf
84 import androidx.compose.runtime.getValue
85 import androidx.compose.runtime.movableContentOf
86 import androidx.compose.runtime.remember
87 import androidx.compose.runtime.rememberUpdatedState
88 import androidx.compose.runtime.saveable.Saver
89 import androidx.compose.runtime.saveable.rememberSaveable
90 import androidx.compose.ui.Alignment
91 import androidx.compose.ui.Modifier
92 import androidx.compose.ui.graphics.Color
93 import androidx.compose.ui.layout.Layout
94 import androidx.compose.ui.layout.layoutId
95 import androidx.compose.ui.unit.dp
96 import androidx.compose.ui.util.fastFirst
97 import androidx.window.core.layout.WindowHeightSizeClass
98 import androidx.window.core.layout.WindowWidthSizeClass
99 
100 /** Possible values of [NavigationSuiteScaffoldState]. */
101 enum class NavigationSuiteScaffoldValue {
102     /** The state of the navigation component of the scaffold when it's visible. */
103     Visible,
104 
105     /** The state of the navigation component of the scaffold when it's hidden. */
106     Hidden
107 }
108 
109 /**
110  * A state object that can be hoisted to observe the navigation suite scaffold state. It allows for
111  * setting its navigation component to be hidden or displayed.
112  *
113  * @see rememberNavigationSuiteScaffoldState to construct the default implementation.
114  */
115 @Stable
116 interface NavigationSuiteScaffoldState {
117     /** Whether the state is currently animating. */
118     val isAnimating: Boolean
119 
120     /** Whether the navigation component is going to be shown or hidden. */
121     val targetValue: NavigationSuiteScaffoldValue
122 
123     /** Whether the navigation component is currently shown or hidden. */
124     val currentValue: NavigationSuiteScaffoldValue
125 
126     /** Hide the navigation component with animation and suspend until it fully expands. */
hidenull127     suspend fun hide()
128 
129     /** Show the navigation component with animation and suspend until it fully expands. */
130     suspend fun show()
131 
132     /**
133      * Hide the navigation component with animation if it's shown, or collapse it otherwise, and
134      * suspend until it fully expands.
135      */
136     suspend fun toggle()
137 
138     /**
139      * Set the state without any animation and suspend until it's set.
140      *
141      * @param targetValue the value to set to
142      */
143     suspend fun snapTo(targetValue: NavigationSuiteScaffoldValue)
144 }
145 
146 /** Create and [remember] a [NavigationSuiteScaffoldState] */
147 @Composable
148 fun rememberNavigationSuiteScaffoldState(
149     initialValue: NavigationSuiteScaffoldValue = NavigationSuiteScaffoldValue.Visible
150 ): NavigationSuiteScaffoldState {
151     return rememberSaveable(saver = NavigationSuiteScaffoldStateImpl.Saver()) {
152         NavigationSuiteScaffoldStateImpl(initialValue = initialValue)
153     }
154 }
155 
156 /**
157  * The Navigation Suite Scaffold wraps the provided content and places the adequate provided
158  * navigation component on the screen according to the current [NavigationSuiteType].
159  *
160  * The navigation component can be animated to be hidden or shown via a
161  * [NavigationSuiteScaffoldState].
162  *
163  * The scaffold also supports an optional primary action composable, such as a floating action
164  * button, which will be displayed according to the current [NavigationSuiteType].
165  *
166  * A simple usage example looks like this:
167  *
168  * @sample androidx.compose.material3.adaptive.navigationsuite.samples.NavigationSuiteScaffoldSample
169  *
170  * An usage with custom layout choices looks like this:
171  *
172  * @sample androidx.compose.material3.adaptive.navigationsuite.samples.NavigationSuiteScaffoldCustomConfigSample
173  * @param navigationItems the navigation items to be displayed, typically [NavigationSuiteItem]s
174  * @param modifier the [Modifier] to be applied to the navigation suite scaffold
175  * @param navigationSuiteType the current [NavigationSuiteType]. Defaults to
176  *   [NavigationSuiteScaffoldDefaults.navigationSuiteType]
177  * @param navigationSuiteColors [NavigationSuiteColors] that will be used to determine the container
178  *   (background) color of the navigation component and the preferred color for content inside the
179  *   navigation component
180  * @param containerColor the color used for the background of the navigation suite scaffold,
181  *   including the passed [content] composable. Use [Color.Transparent] to have no color
182  * @param contentColor the preferred color to be used for typography and iconography within the
183  *   passed in [content] lambda inside the navigation suite scaffold.
184  * @param state the [NavigationSuiteScaffoldState] of this navigation suite scaffold
185  * @param navigationItemVerticalArrangement the vertical arrangement of the items inside vertical
186  *   navigation components (such as the types [NavigationSuiteType.WideNavigationRailCollapsed] and
187  *   [NavigationSuiteType.WideNavigationRailExpanded]). It's recommended to use [Arrangement.Top],
188  *   [Arrangement.Center], or [Arrangement.Bottom]. Defaults to [Arrangement.Top]
189  * @param primaryActionContent The optional primary action content of the navigation suite scaffold,
190  *   if any. Typically a [androidx.compose.material3.FloatingActionButton]. It'll be displayed
191  *   inside vertical navigation components as part of their header , and above horizontal navigation
192  *   components.
193  * @param primaryActionContentHorizontalAlignment The horizontal alignment of the primary action
194  *   content, if present, when it's displayed along with a horizontal navigation component.
195  * @param content the content of your screen
196  */
197 @Composable
NavigationSuiteScaffoldnull198 fun NavigationSuiteScaffold(
199     navigationItems: @Composable () -> Unit,
200     modifier: Modifier = Modifier,
201     navigationSuiteType: NavigationSuiteType =
202         NavigationSuiteScaffoldDefaults.navigationSuiteType(WindowAdaptiveInfoDefault),
203     navigationSuiteColors: NavigationSuiteColors = NavigationSuiteDefaults.colors(),
204     containerColor: Color = NavigationSuiteScaffoldDefaults.containerColor,
205     contentColor: Color = NavigationSuiteScaffoldDefaults.contentColor,
206     state: NavigationSuiteScaffoldState = rememberNavigationSuiteScaffoldState(),
207     navigationItemVerticalArrangement: Arrangement.Vertical =
208         NavigationSuiteDefaults.verticalArrangement,
209     primaryActionContent: @Composable (() -> Unit) = {},
210     primaryActionContentHorizontalAlignment: Alignment.Horizontal =
211         NavigationSuiteScaffoldDefaults.primaryActionContentAlignment,
212     content: @Composable () -> Unit,
213 ) {
<lambda>null214     Surface(modifier = modifier, color = containerColor, contentColor = contentColor) {
215         NavigationSuiteScaffoldLayout(
216             navigationSuite = {
217                 NavigationSuite(
218                     navigationSuiteType = navigationSuiteType,
219                     colors = navigationSuiteColors,
220                     primaryActionContent = primaryActionContent,
221                     verticalArrangement = navigationItemVerticalArrangement,
222                     content = navigationItems
223                 )
224             },
225             navigationSuiteType = navigationSuiteType,
226             state = state,
227             primaryActionContent = primaryActionContent,
228             primaryActionContentHorizontalAlignment = primaryActionContentHorizontalAlignment,
229             content = {
230                 Box(
231                     Modifier.navigationSuiteScaffoldConsumeWindowInsets(navigationSuiteType, state)
232                 ) {
233                     content()
234                 }
235             }
236         )
237     }
238 }
239 
240 /**
241  * The Navigation Suite Scaffold wraps the provided content and places the adequate provided
242  * navigation component on the screen according to the current [NavigationSuiteType].
243  *
244  * Note: It is recommended to use the [NavigationSuiteScaffold] function with the navigationItems
245  * param that accepts [NavigationSuiteItem]s instead of this one.
246  *
247  * The navigation component can be animated to be hidden or shown via a
248  * [NavigationSuiteScaffoldState].
249  *
250  * @param navigationSuiteItems the navigation items to be displayed
251  * @param modifier the [Modifier] to be applied to the navigation suite scaffold
252  * @param layoutType the current [NavigationSuiteType]. Defaults to
253  *   [NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo]
254  * @param navigationSuiteColors [NavigationSuiteColors] that will be used to determine the container
255  *   (background) color of the navigation component and the preferred color for content inside the
256  *   navigation component
257  * @param containerColor the color used for the background of the navigation suite scaffold,
258  *   including the passed [content] composable. Use [Color.Transparent] to have no color
259  * @param contentColor the preferred color to be used for typography and iconography within the
260  *   passed in [content] lambda inside the navigation suite scaffold.
261  * @param state the [NavigationSuiteScaffoldState] of this navigation suite scaffold
262  * @param content the content of your screen
263  */
264 @OptIn(ExperimentalMaterial3AdaptiveComponentOverrideApi::class)
265 @Composable
NavigationSuiteScaffoldnull266 fun NavigationSuiteScaffold(
267     navigationSuiteItems: NavigationSuiteScope.() -> Unit,
268     modifier: Modifier = Modifier,
269     layoutType: NavigationSuiteType =
270         NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(WindowAdaptiveInfoDefault),
271     navigationSuiteColors: NavigationSuiteColors = NavigationSuiteDefaults.colors(),
272     containerColor: Color = NavigationSuiteScaffoldDefaults.containerColor,
273     contentColor: Color = NavigationSuiteScaffoldDefaults.contentColor,
274     state: NavigationSuiteScaffoldState = rememberNavigationSuiteScaffoldState(),
275     content: @Composable () -> Unit = {},
276 ) {
<lambda>null277     with(LocalNavigationSuiteScaffoldOverride.current) {
278         NavigationSuiteScaffoldOverrideScope(
279                 navigationSuiteItems = navigationSuiteItems,
280                 modifier = modifier,
281                 layoutType = layoutType,
282                 navigationSuiteColors = navigationSuiteColors,
283                 containerColor = containerColor,
284                 contentColor = contentColor,
285                 state = state,
286                 content = content
287             )
288             .NavigationSuiteScaffold()
289     }
290 }
291 
292 /**
293  * This override provides the default behavior of the [NavigationSuiteScaffold] component.
294  *
295  * [NavigationSuiteScaffoldOverride] used when no override is specified.
296  */
297 @ExperimentalMaterial3AdaptiveComponentOverrideApi
298 object DefaultNavigationSuiteScaffoldOverride : NavigationSuiteScaffoldOverride {
299     @Composable
NavigationSuiteScaffoldnull300     override fun NavigationSuiteScaffoldOverrideScope.NavigationSuiteScaffold() {
301         Surface(modifier = modifier, color = containerColor, contentColor = contentColor) {
302             NavigationSuiteScaffoldLayout(
303                 navigationSuite = {
304                     NavigationSuite(
305                         layoutType = layoutType,
306                         colors = navigationSuiteColors,
307                         content = navigationSuiteItems
308                     )
309                 },
310                 state = state,
311                 layoutType = layoutType,
312                 content = {
313                     Box(
314                         Modifier.consumeWindowInsets(
315                             if (
316                                 state.currentValue == NavigationSuiteScaffoldValue.Hidden &&
317                                     !state.isAnimating
318                             ) {
319                                 NoWindowInsets
320                             } else {
321                                 when (layoutType) {
322                                     NavigationSuiteType.NavigationBar ->
323                                         NavigationBarDefaults.windowInsets.only(
324                                             WindowInsetsSides.Bottom
325                                         )
326                                     NavigationSuiteType.NavigationRail ->
327                                         NavigationRailDefaults.windowInsets.only(
328                                             WindowInsetsSides.Start
329                                         )
330                                     NavigationSuiteType.NavigationDrawer ->
331                                         DrawerDefaults.windowInsets.only(WindowInsetsSides.Start)
332                                     else -> NoWindowInsets
333                                 }
334                             }
335                         )
336                     ) {
337                         content()
338                     }
339                 }
340             )
341         }
342     }
343 }
344 
345 /**
346  * The Navigation Suite Scaffold wraps the provided content and places the adequate provided
347  * navigation component on the screen according to the current [NavigationSuiteType].
348  *
349  * @param navigationSuiteItems the navigation items to be displayed
350  * @param modifier the [Modifier] to be applied to the navigation suite scaffold
351  * @param layoutType the current [NavigationSuiteType]. Defaults to
352  *   [NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo]
353  * @param navigationSuiteColors [NavigationSuiteColors] that will be used to determine the container
354  *   (background) color of the navigation component and the preferred color for content inside the
355  *   navigation component
356  * @param containerColor the color used for the background of the navigation suite scaffold,
357  *   including the passed [content] composable. Use [Color.Transparent] to have no color
358  * @param contentColor the preferred color to be used for typography and iconography within the
359  *   passed in [content] lambda inside the navigation suite scaffold.
360  * @param content the content of your screen
361  */
362 @Deprecated(
363     message = "Deprecated in favor of NavigationSuiteScaffold with state parameter",
364     level = DeprecationLevel.HIDDEN
365 )
366 @Composable
NavigationSuiteScaffoldnull367 fun NavigationSuiteScaffold(
368     navigationSuiteItems: NavigationSuiteScope.() -> Unit,
369     modifier: Modifier = Modifier,
370     layoutType: NavigationSuiteType =
371         NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(WindowAdaptiveInfoDefault),
372     navigationSuiteColors: NavigationSuiteColors = NavigationSuiteDefaults.colors(),
373     containerColor: Color = NavigationSuiteScaffoldDefaults.containerColor,
374     contentColor: Color = NavigationSuiteScaffoldDefaults.contentColor,
375     content: @Composable () -> Unit = {},
376 ) =
377     NavigationSuiteScaffold(
378         navigationSuiteItems = navigationSuiteItems,
379         modifier = modifier,
380         state = rememberNavigationSuiteScaffoldState(),
381         layoutType = layoutType,
382         navigationSuiteColors = navigationSuiteColors,
383         containerColor = containerColor,
384         contentColor = contentColor,
385         content = content
386     )
387 
388 /**
389  * Layout for a [NavigationSuiteScaffold]'s content. This function wraps the [content] and places
390  * the [navigationSuite], and the [primaryActionContent], if any, according to the current
391  * [NavigationSuiteType].
392  *
393  * The usage of this function is recommended when you need some customization that is not viable via
394  * the use of [NavigationSuiteScaffold]. An usage example of using a custom modal wide rail can be
395  * found at androidx.compose.material3.demos.NavigationSuiteScaffoldCustomConfigDemo.
396  *
397  * @param navigationSuite the navigation component to be displayed, typically [NavigationSuite]
398  * @param navigationSuiteType the current [NavigationSuiteType]. Usually
399  *   [NavigationSuiteScaffoldDefaults.navigationSuiteType]
400  * @param state the [NavigationSuiteScaffoldState] of this navigation suite scaffold layout
401  * @param primaryActionContent The optional primary action content of the navigation suite scaffold,
402  *   if any. Typically a [androidx.compose.material3.FloatingActionButton]. It'll be displayed
403  *   inside vertical navigation components as part of their header, and above horizontal navigation
404  *   components.
405  * @param primaryActionContentHorizontalAlignment The horizontal alignment of the primary action
406  *   content, if present, when it's displayed along with a horizontal navigation component.
407  * @param content the content of your screen
408  */
409 @Composable
NavigationSuiteScaffoldLayoutnull410 fun NavigationSuiteScaffoldLayout(
411     navigationSuite: @Composable () -> Unit,
412     navigationSuiteType: NavigationSuiteType,
413     state: NavigationSuiteScaffoldState = rememberNavigationSuiteScaffoldState(),
414     primaryActionContent: @Composable (() -> Unit) = {},
415     primaryActionContentHorizontalAlignment: Alignment.Horizontal =
416         NavigationSuiteScaffoldDefaults.primaryActionContentAlignment,
417     content: @Composable () -> Unit
418 ) {
419     val animationProgress by
420         animateFloatAsState(
421             targetValue = if (state.currentValue == NavigationSuiteScaffoldValue.Hidden) 0f else 1f,
422             animationSpec = AnimationSpec
423         )
424 
<lambda>null425     Layout({
426         // Wrap the navigation suite and content composables each in a Box to not propagate the
427         // parent's (Surface) min constraints to its children (see b/312664933).
428         Box(Modifier.layoutId(NavigationSuiteLayoutIdTag)) { navigationSuite() }
429         Box(Modifier.layoutId(PrimaryActionContentLayoutIdTag)) { primaryActionContent() }
430         Box(Modifier.layoutId(ContentLayoutIdTag)) { content() }
431     }) { measurables, constraints ->
432         val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
433         // Find the navigation suite composable through it's layoutId tag
434         val navigationPlaceable =
435             measurables
<lambda>null436                 .fastFirst { it.layoutId == NavigationSuiteLayoutIdTag }
437                 .measure(looseConstraints)
438         val primaryActionContentPlaceable =
439             measurables
<lambda>null440                 .fastFirst { it.layoutId == PrimaryActionContentLayoutIdTag }
441                 .measure(looseConstraints)
442         val isNavigationBar = navigationSuiteType.isNavigationBar
443         val layoutHeight = constraints.maxHeight
444         val layoutWidth = constraints.maxWidth
445         // Find the content composable through it's layoutId tag.
446         val contentPlaceable =
447             measurables
<lambda>null448                 .fastFirst { it.layoutId == ContentLayoutIdTag }
449                 .measure(
450                     if (isNavigationBar) {
451                         constraints.copy(
452                             minHeight =
453                                 layoutHeight -
454                                     (navigationPlaceable.height * animationProgress).toInt(),
455                             maxHeight =
456                                 layoutHeight -
457                                     (navigationPlaceable.height * animationProgress).toInt()
458                         )
459                     } else {
460                         constraints.copy(
461                             minWidth =
462                                 layoutWidth -
463                                     (navigationPlaceable.width * animationProgress).toInt(),
464                             maxWidth =
465                                 layoutWidth -
466                                     (navigationPlaceable.width * animationProgress).toInt()
467                         )
468                     }
469                 )
470 
<lambda>null471         layout(layoutWidth, layoutHeight) {
472             if (isNavigationBar) {
473                 // Place content above the navigation component.
474                 contentPlaceable.placeRelative(0, 0)
475                 // Place the navigation component at the bottom of the screen.
476                 navigationPlaceable.placeRelative(
477                     0,
478                     layoutHeight - (navigationPlaceable.height * animationProgress).toInt()
479                 )
480                 // Place the primary action content above the navigation component.
481                 val positionX =
482                     if (primaryActionContentHorizontalAlignment == Alignment.Start) {
483                         PrimaryActionContentPadding.roundToPx()
484                     } else if (
485                         primaryActionContentHorizontalAlignment == Alignment.CenterHorizontally
486                     ) {
487                         (layoutWidth - primaryActionContentPlaceable.width) / 2
488                     } else {
489                         layoutWidth -
490                             primaryActionContentPlaceable.width -
491                             PrimaryActionContentPadding.roundToPx()
492                     }
493                 primaryActionContentPlaceable.placeRelative(
494                     positionX,
495                     layoutHeight -
496                         primaryActionContentPlaceable.height -
497                         PrimaryActionContentPadding.roundToPx() -
498                         (navigationPlaceable.height * animationProgress).toInt()
499                 )
500             } else {
501                 // Place the navigation component at the start of the screen.
502                 navigationPlaceable.placeRelative(
503                     (0 - (navigationPlaceable.width * (1f - animationProgress))).toInt(),
504                     0
505                 )
506                 // Place content to the side of the navigation component.
507                 contentPlaceable.placeRelative(
508                     (navigationPlaceable.width * animationProgress).toInt(),
509                     0
510                 )
511             }
512         }
513     }
514 }
515 
516 /**
517  * Layout for a [NavigationSuiteScaffold]'s content. This function wraps the [content] and places
518  * the [navigationSuite] component according to the given [layoutType].
519  *
520  * Note: It is recommended to use the [NavigationSuiteScaffoldLayout] function with the
521  * navigationSuiteType param instead of this one.
522  *
523  * The usage of this function is recommended when you need some customization that is not viable via
524  * the use of [NavigationSuiteScaffold].
525  *
526  * @param navigationSuite the navigation component to be displayed, typically [NavigationSuite]
527  * @param layoutType the current [NavigationSuiteType]. Defaults to
528  *   [NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo]
529  * @param state the [NavigationSuiteScaffoldState] of this navigation suite scaffold layout
530  * @param content the content of your screen
531  */
532 @Composable
NavigationSuiteScaffoldLayoutnull533 fun NavigationSuiteScaffoldLayout(
534     navigationSuite: @Composable () -> Unit,
535     layoutType: NavigationSuiteType =
536         NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(WindowAdaptiveInfoDefault),
537     state: NavigationSuiteScaffoldState = rememberNavigationSuiteScaffoldState(),
538     content: @Composable () -> Unit = {}
539 ) {
540     NavigationSuiteScaffoldLayout(
541         navigationSuite = navigationSuite,
542         navigationSuiteType = layoutType,
543         state = state,
544         content = content
545     )
546 }
547 
548 /**
549  * Layout for a [NavigationSuiteScaffold]'s content. This function wraps the [content] and places
550  * the [navigationSuite] component according to the given [layoutType].
551  *
552  * The usage of this function is recommended when you need some customization that is not viable via
553  * the use of [NavigationSuiteScaffold]. Example usage:
554  *
555  * @param navigationSuite the navigation component to be displayed, typically [NavigationSuite]
556  * @param layoutType the current [NavigationSuiteType]. Defaults to
557  *   [NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo]
558  * @param content the content of your screen
559  */
560 @Deprecated(
561     message = "Deprecated in favor of NavigationSuiteScaffoldLayout with state parameter",
562     level = DeprecationLevel.HIDDEN
563 )
564 @Composable
NavigationSuiteScaffoldLayoutnull565 fun NavigationSuiteScaffoldLayout(
566     navigationSuite: @Composable () -> Unit,
567     layoutType: NavigationSuiteType =
568         NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(WindowAdaptiveInfoDefault),
569     content: @Composable () -> Unit = {}
570 ) =
571     NavigationSuiteScaffoldLayout(
572         navigationSuite = navigationSuite,
573         navigationSuiteType = layoutType,
574         state = rememberNavigationSuiteScaffoldState(),
575         content = content
576     )
577 
578 /**
579  * The default Material navigation component according to the current [NavigationSuiteType] to be
580  * used with the [NavigationSuiteScaffold].
581  *
582  * For specifics about each navigation component, see [ShortNavigationBar], [WideNavigationRail],
583  * [NavigationRail], and [PermanentDrawerSheet].
584  *
585  * @param navigationSuiteType the [NavigationSuiteType] of the associated [NavigationSuiteScaffold].
586  *   Usually [NavigationSuiteScaffoldDefaults.navigationSuiteType]
587  * @param modifier the [Modifier] to be applied to the navigation component
588  * @param colors [NavigationSuiteColors] that will be used to determine the container (background)
589  *   color of the navigation component and the preferred color for content inside the navigation
590  *   component
591  * @param verticalArrangement the vertical arrangement of the items inside vertical navigation
592  *   components, such as the wide navigation rail. It's recommended to use [Arrangement.Top],
593  *   [Arrangement.Center], or [Arrangement.Bottom].
594  * @param primaryActionContent The optional primary action content of the navigation suite scaffold,
595  *   if any. Typically a [androidx.compose.material3.FloatingActionButton]. It'll be displayed
596  *   inside vertical navigation components as their header, and above horizontal navigation
597  *   components.
598  * @param content the content inside the current navigation component, typically
599  *   [NavigationSuiteItem]s
600  */
601 @OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3ExpressiveApi::class)
602 @Composable
NavigationSuitenull603 fun NavigationSuite(
604     navigationSuiteType: NavigationSuiteType,
605     modifier: Modifier = Modifier,
606     colors: NavigationSuiteColors = NavigationSuiteDefaults.colors(),
607     verticalArrangement: Arrangement.Vertical = NavigationSuiteDefaults.verticalArrangement,
608     primaryActionContent: @Composable (() -> Unit) = {},
609     content: @Composable () -> Unit
610 ) {
<lambda>null611     val movableContent = remember(content) { movableContentOf(content) }
612     when (navigationSuiteType) {
613         NavigationSuiteType.ShortNavigationBarCompact -> {
614             ShortNavigationBar(
615                 modifier = modifier,
616                 containerColor = colors.shortNavigationBarContainerColor,
617                 contentColor = colors.shortNavigationBarContentColor,
618                 content = movableContent
619             )
620         }
621         NavigationSuiteType.ShortNavigationBarMedium -> {
622             ShortNavigationBar(
623                 modifier = modifier,
624                 containerColor = colors.shortNavigationBarContainerColor,
625                 contentColor = colors.shortNavigationBarContentColor,
626                 content = movableContent
627             )
628         }
629         NavigationSuiteType.WideNavigationRailCollapsed -> {
630             WideNavigationRail(
631                 modifier = modifier,
632                 header = primaryActionContent,
633                 arrangement = verticalArrangement,
634                 colors = colors.wideNavigationRailColors,
635                 content = movableContent
636             )
637         }
638         NavigationSuiteType.WideNavigationRailExpanded -> {
639             WideNavigationRail(
640                 modifier = modifier,
641                 header = primaryActionContent,
642                 state =
643                     rememberWideNavigationRailState(
644                         initialValue = WideNavigationRailValue.Expanded
645                     ),
646                 arrangement = verticalArrangement,
647                 colors = colors.wideNavigationRailColors,
648                 content = movableContent
649             )
650         }
651         // Note: This function does not support providing a NavigationBar for the
652         // NavigationSuiteType.NavigationBar type instead provides a ShortNavigationBar with a
653         // taller height so that it is visually the same.
654         // It's advised to to use NavigationSuiteType.ShortNavigationBarVerticalItems instead.
655         NavigationSuiteType.NavigationBar -> {
656             ShortNavigationBar(
657                 modifier = modifier.heightIn(min = TallNavigationBarHeight),
658                 containerColor = colors.navigationBarContainerColor,
659                 contentColor = colors.navigationBarContentColor
<lambda>null660             ) {
661                 movableContent()
662             }
663         }
664         // It's advised to to use NavigationSuiteType.WideNavigationRail instead of
665         // NavigationSuiteType.NavigationRail.
666         NavigationSuiteType.NavigationRail -> {
667             NavigationRail(
668                 modifier = modifier,
<lambda>null669                 header = { primaryActionContent() },
670                 containerColor = colors.navigationRailContainerColor,
671                 contentColor = colors.navigationRailContentColor
<lambda>null672             ) {
673                 if (
674                     verticalArrangement == Arrangement.Center ||
675                         verticalArrangement == Arrangement.Bottom
676                 ) {
677                     Spacer(Modifier.weight(1f))
678                 }
679                 movableContent()
680                 if (verticalArrangement == Arrangement.Center) {
681                     Spacer(Modifier.weight(1f))
682                 }
683             }
684         }
685         // It's advised to to use NavigationSuiteType.WideNavigationRail instead of
686         // NavigationSuiteType.NavigationDrawer.
687         NavigationSuiteType.NavigationDrawer -> {
688             PermanentDrawerSheet(
689                 modifier = modifier,
690                 drawerContainerColor = colors.navigationDrawerContainerColor,
691                 drawerContentColor = colors.navigationDrawerContentColor
<lambda>null692             ) {
693                 primaryActionContent()
694                 if (
695                     verticalArrangement == Arrangement.Center ||
696                         verticalArrangement == Arrangement.Bottom
697                 ) {
698                     Spacer(Modifier.weight(1f))
699                 }
700                 movableContent()
701                 if (verticalArrangement == Arrangement.Center) {
702                     Spacer(Modifier.weight(1f))
703                 }
704             }
705         }
706     }
707 }
708 
709 /**
710  * The default Material navigation component according to the current [NavigationSuiteType] to be
711  * used with the [NavigationSuiteScaffold].
712  *
713  * Note: It is recommended to use the [NavigationSuite] function with the navigationSuiteType param
714  * and that accepts [NavigationSuiteItem]s instead of this one.
715  *
716  * For specifics about each navigation component, see [NavigationBar], [NavigationRail], and
717  * [PermanentDrawerSheet].
718  *
719  * @param modifier the [Modifier] to be applied to the navigation component
720  * @param layoutType the current [NavigationSuiteType] of the [NavigationSuiteScaffold]. Defaults to
721  *   [NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo]
722  * @param colors [NavigationSuiteColors] that will be used to determine the container (background)
723  *   color of the navigation component and the preferred color for content inside the navigation
724  *   component
725  * @param content the content inside the current navigation component, typically
726  *   [NavigationSuiteScope.item]s
727  */
728 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
729 @Composable
NavigationSuitenull730 fun NavigationSuite(
731     modifier: Modifier = Modifier,
732     layoutType: NavigationSuiteType =
733         NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(WindowAdaptiveInfoDefault),
734     colors: NavigationSuiteColors = NavigationSuiteDefaults.colors(),
735     content: NavigationSuiteScope.() -> Unit
736 ) {
737     val scope by rememberStateOfItems(content)
738     // Define defaultItemColors here since we can't set NavigationSuiteDefaults.itemColors() as a
739     // default for the colors param of the NavigationSuiteScope.item non-composable function.
740     val defaultItemColors = NavigationSuiteDefaults.itemColors()
741 
742     when (layoutType) {
743         NavigationSuiteType.NavigationBar -> {
744             NavigationBar(
745                 modifier = modifier,
746                 containerColor = colors.navigationBarContainerColor,
747                 contentColor = colors.navigationBarContentColor
748             ) {
749                 scope.itemList.forEach {
750                     NavigationBarItem(
751                         modifier = it.modifier,
752                         selected = it.selected,
753                         onClick = it.onClick,
754                         icon = { NavigationItemIcon(icon = it.icon, badge = it.badge) },
755                         enabled = it.enabled,
756                         label = it.label,
757                         alwaysShowLabel = it.alwaysShowLabel,
758                         colors =
759                             it.colors?.navigationBarItemColors
760                                 ?: defaultItemColors.navigationBarItemColors,
761                         interactionSource = it.interactionSource
762                     )
763                 }
764             }
765         }
766         NavigationSuiteType.NavigationRail -> {
767             NavigationRail(
768                 modifier = modifier,
769                 containerColor = colors.navigationRailContainerColor,
770                 contentColor = colors.navigationRailContentColor
771             ) {
772                 scope.itemList.forEach {
773                     NavigationRailItem(
774                         modifier = it.modifier,
775                         selected = it.selected,
776                         onClick = it.onClick,
777                         icon = { NavigationItemIcon(icon = it.icon, badge = it.badge) },
778                         enabled = it.enabled,
779                         label = it.label,
780                         alwaysShowLabel = it.alwaysShowLabel,
781                         colors =
782                             it.colors?.navigationRailItemColors
783                                 ?: defaultItemColors.navigationRailItemColors,
784                         interactionSource = it.interactionSource
785                     )
786                 }
787             }
788         }
789         NavigationSuiteType.NavigationDrawer -> {
790             PermanentDrawerSheet(
791                 modifier = modifier,
792                 drawerContainerColor = colors.navigationDrawerContainerColor,
793                 drawerContentColor = colors.navigationDrawerContentColor
794             ) {
795                 scope.itemList.forEach {
796                     NavigationDrawerItem(
797                         modifier = it.modifier,
798                         selected = it.selected,
799                         onClick = it.onClick,
800                         icon = it.icon,
801                         badge = it.badge,
802                         label = { it.label?.invoke() ?: Text("") },
803                         colors =
804                             it.colors?.navigationDrawerItemColors
805                                 ?: defaultItemColors.navigationDrawerItemColors,
806                         interactionSource = it.interactionSource
807                     )
808                 }
809             }
810         }
811         NavigationSuiteType.None -> {
812             /* Do nothing. */
813         }
814         else -> {
815             NavigationSuite(
816                 navigationSuiteType = layoutType,
817                 modifier = modifier,
818                 colors = colors,
819             ) {
820                 scope.itemList.forEach {
821                     NavigationSuiteItem(
822                         isNavigationSuite = true,
823                         navigationSuiteType = layoutType,
824                         modifier = it.modifier,
825                         selected = it.selected,
826                         onClick = it.onClick,
827                         icon = it.icon,
828                         badge = it.badge,
829                         enabled = it.enabled,
830                         label = it.label,
831                         navigationSuiteItemColors =
832                             it.colors ?: NavigationSuiteDefaults.itemColors(),
833                         navigationItemColors = null,
834                         interactionSource = it.interactionSource
835                     )
836                 }
837             }
838         }
839     }
840 }
841 
842 /**
843  * The default Material navigation item component according to the current [NavigationSuiteType] to
844  * be used with the [NavigationSuite] that accepts this function.
845  *
846  * For specifics about each navigation component, see [ShortNavigationBarItem],
847  * [WideNavigationRailItem], [NavigationRailItem], and [NavigationDrawerItem].
848  *
849  * @param selected whether this item is selected
850  * @param onClick called when this item is clicked
851  * @param icon icon for this item, typically an [Icon]
852  * @param label the text label for this item
853  * @param modifier the [Modifier] to be applied to this item
854  * @param navigationSuiteType the current [NavigationSuiteType] of the associated [NavigationSuite].
855  *   Defaults to [NavigationSuiteScaffoldDefaults.navigationSuiteType]
856  * @param enabled controls the enabled state of this item. When `false`, this component will not
857  *   respond to user input, and it will appear visually disabled and disabled to accessibility
858  *   services. Note: as of now, for [NavigationDrawerItem], this is always `true`.
859  * @param badge optional badge to show on this item
860  * @param colors [NavigationItemColors] that will be used to resolve the colors used for this item
861  *   in different states. If null, a default Material colors for each specific item will be used.
862  * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
863  *   emitting [Interaction]s for this item. You can use this to change the item's appearance or
864  *   preview the item in different states. Note that if `null` is provided, interactions will still
865  *   happen internally.
866  */
867 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
868 @Composable
NavigationSuiteItemnull869 fun NavigationSuiteItem(
870     selected: Boolean,
871     onClick: () -> Unit,
872     icon: @Composable () -> Unit,
873     label: @Composable (() -> Unit)?,
874     modifier: Modifier = Modifier,
875     navigationSuiteType: NavigationSuiteType =
876         NavigationSuiteScaffoldDefaults.navigationSuiteType(WindowAdaptiveInfoDefault),
877     enabled: Boolean = true,
878     badge: @Composable (() -> Unit)? = null,
879     colors: NavigationItemColors? = null,
880     interactionSource: MutableInteractionSource? = null,
881 ) {
882     NavigationSuiteItem(
883         isNavigationSuite = false,
884         navigationSuiteType = navigationSuiteType,
885         selected = selected,
886         onClick = onClick,
887         icon = icon,
888         label = label,
889         modifier = modifier,
890         enabled = enabled,
891         badge = badge,
892         navigationItemColors = colors,
893         navigationSuiteItemColors = null,
894         interactionSource = interactionSource,
895     )
896 }
897 
898 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
899 @Composable
NavigationSuiteItemnull900 private fun NavigationSuiteItem(
901     isNavigationSuite: Boolean,
902     navigationSuiteType: NavigationSuiteType,
903     selected: Boolean,
904     onClick: () -> Unit,
905     icon: @Composable () -> Unit,
906     label: @Composable (() -> Unit)?,
907     modifier: Modifier,
908     enabled: Boolean,
909     badge: @Composable (() -> Unit)?,
910     navigationItemColors: NavigationItemColors?,
911     navigationSuiteItemColors: NavigationSuiteItemColors?,
912     interactionSource: MutableInteractionSource?
913 ) {
914     when (navigationSuiteType) {
915         NavigationSuiteType.ShortNavigationBarCompact,
916         NavigationSuiteType.ShortNavigationBarMedium -> {
917             val iconPosition =
918                 if (navigationSuiteType == NavigationSuiteType.ShortNavigationBarCompact) {
919                     NavigationItemIconPosition.Top
920                 } else {
921                     NavigationItemIconPosition.Start
922                 }
923             ShortNavigationBarItem(
924                 selected = selected,
925                 onClick = onClick,
926                 icon = { NavigationItemIcon(icon = icon, badge = badge) },
927                 label = label,
928                 modifier = modifier,
929                 enabled = enabled,
930                 iconPosition = iconPosition,
931                 colors = navigationItemColors ?: ShortNavigationBarItemDefaults.colors(),
932                 interactionSource = interactionSource
933             )
934         }
935         NavigationSuiteType.WideNavigationRailCollapsed,
936         NavigationSuiteType.WideNavigationRailExpanded -> {
937             WideNavigationRailItem(
938                 railExpanded =
939                     navigationSuiteType == NavigationSuiteType.WideNavigationRailExpanded,
940                 selected = selected,
941                 onClick = onClick,
942                 icon = { NavigationItemIcon(icon = icon, badge = badge) },
943                 label = label,
944                 modifier = modifier,
945                 enabled = enabled,
946                 colors = navigationItemColors ?: WideNavigationRailItemDefaults.colors(),
947                 interactionSource = interactionSource
948             )
949         }
950         // Note: This function does not support providing a NavigationBarItem for the
951         // NavigationSuiteType.NavigationBar type due to the NavigationBarItem being limited to
952         // RowScope. Instead we provide ShortNavigationBarItem with a top padding so that it is
953         // visually the same.
954         // It's advised to to use NavigationSuiteType.ShortNavigationBarVerticalItems instead.
955         NavigationSuiteType.NavigationBar -> {
956             val defaultColors =
957                 navigationSuiteItemColors?.navigationBarItemColors
958                     ?: NavigationBarItemDefaults.colors()
959             val actualColors =
960                 if ((!isNavigationSuite && navigationItemColors == null) || isNavigationSuite) {
961                     ShortNavigationBarItemDefaults.colors(
962                         selectedIconColor = defaultColors.selectedIconColor,
963                         selectedTextColor = defaultColors.selectedTextColor,
964                         selectedIndicatorColor = defaultColors.selectedIndicatorColor,
965                         unselectedIconColor = defaultColors.unselectedIconColor,
966                         unselectedTextColor = defaultColors.unselectedTextColor,
967                         disabledIconColor = defaultColors.disabledIconColor,
968                         disabledTextColor = defaultColors.disabledTextColor,
969                     )
970                 } else {
971                     navigationItemColors!!
972                 }
973 
974             ShortNavigationBarItem(
975                 selected = selected,
976                 onClick = onClick,
977                 icon = { NavigationItemIcon(icon = icon, badge = badge) },
978                 label = label,
979                 modifier = modifier.padding(top = 8.dp),
980                 enabled = enabled,
981                 colors = actualColors,
982                 interactionSource = interactionSource
983             )
984         }
985         // It's advised to to use NavigationSuiteType.WideNavigationRail instead of
986         // NavigationSuiteType.NavigationRail.
987         NavigationSuiteType.NavigationRail -> {
988             val actualColors =
989                 if (isNavigationSuite) {
990                     navigationSuiteItemColors?.navigationRailItemColors
991                         ?: NavigationRailItemDefaults.colors()
992                 } else {
993                     if (navigationItemColors != null) {
994                         NavigationRailItemDefaults.colors(
995                             selectedIconColor = navigationItemColors.selectedIconColor,
996                             selectedTextColor = navigationItemColors.selectedTextColor,
997                             indicatorColor = navigationItemColors.selectedIndicatorColor,
998                             unselectedIconColor = navigationItemColors.unselectedIconColor,
999                             unselectedTextColor = navigationItemColors.unselectedTextColor,
1000                             disabledIconColor = navigationItemColors.disabledIconColor,
1001                             disabledTextColor = navigationItemColors.disabledTextColor,
1002                         )
1003                     } else {
1004                         NavigationSuiteDefaults.itemColors().navigationRailItemColors
1005                     }
1006                 }
1007             NavigationRailItem(
1008                 selected = selected,
1009                 onClick = onClick,
1010                 icon = { NavigationItemIcon(icon = icon, badge = badge) },
1011                 label = label,
1012                 modifier = modifier,
1013                 enabled = enabled,
1014                 colors = actualColors,
1015                 interactionSource = interactionSource
1016             )
1017         }
1018         // It's advised to to use NavigationSuiteType.WideNavigationRail instead of
1019         // NavigationSuiteType.NavigationDrawer.
1020         NavigationSuiteType.NavigationDrawer -> {
1021             val actualColors =
1022                 if (isNavigationSuite) {
1023                     navigationSuiteItemColors?.navigationDrawerItemColors
1024                         ?: NavigationDrawerItemDefaults.colors()
1025                 } else {
1026                     if (navigationItemColors != null) {
1027                         NavigationDrawerItemDefaults.colors(
1028                             selectedIconColor = navigationItemColors.selectedIconColor,
1029                             selectedTextColor = navigationItemColors.selectedTextColor,
1030                             unselectedIconColor = navigationItemColors.unselectedIconColor,
1031                             unselectedTextColor = navigationItemColors.unselectedTextColor,
1032                             selectedContainerColor = navigationItemColors.selectedIndicatorColor
1033                         )
1034                     } else {
1035                         NavigationSuiteDefaults.itemColors().navigationDrawerItemColors
1036                     }
1037                 }
1038 
1039             NavigationDrawerItem(
1040                 modifier = modifier,
1041                 selected = selected,
1042                 onClick = onClick,
1043                 icon = icon,
1044                 badge = badge,
1045                 label = { label?.invoke() ?: Text("") },
1046                 colors = actualColors,
1047                 interactionSource = interactionSource
1048             )
1049         }
1050     }
1051 }
1052 
1053 /** The scope associated with the [NavigationSuiteScope]. */
1054 sealed interface NavigationSuiteScope {
1055 
1056     /**
1057      * This function sets the parameters of the default Material navigation item to be used with the
1058      * Navigation Suite Scaffold. The item is called in [NavigationSuite], according to the current
1059      * [NavigationSuiteType].
1060      *
1061      * For specifics about each item component, see [NavigationBarItem], [NavigationRailItem], and
1062      * [NavigationDrawerItem].
1063      *
1064      * @param selected whether this item is selected
1065      * @param onClick called when this item is clicked
1066      * @param icon icon for this item, typically an [Icon]
1067      * @param modifier the [Modifier] to be applied to this item
1068      * @param enabled controls the enabled state of this item. When `false`, this component will not
1069      *   respond to user input, and it will appear visually disabled and disabled to accessibility
1070      *   services. Note: as of now, for [NavigationDrawerItem], this is always `true`.
1071      * @param label the text label for this item
1072      * @param alwaysShowLabel whether to always show the label for this item. If `false`, the label
1073      *   will only be shown when this item is selected. Note: for [NavigationDrawerItem] this is
1074      *   always `true`
1075      * @param badge optional badge to show on this item
1076      * @param colors [NavigationSuiteItemColors] that will be used to resolve the colors used for
1077      *   this item in different states. If null, [NavigationSuiteDefaults.itemColors] will be used.
1078      * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
1079      *   emitting [Interaction]s for this item. You can use this to change the item's appearance or
1080      *   preview the item in different states. Note that if `null` is provided, interactions will
1081      *   still happen internally.
1082      */
itemnull1083     fun item(
1084         selected: Boolean,
1085         onClick: () -> Unit,
1086         icon: @Composable () -> Unit,
1087         modifier: Modifier = Modifier,
1088         enabled: Boolean = true,
1089         label: @Composable (() -> Unit)? = null,
1090         alwaysShowLabel: Boolean = true,
1091         badge: (@Composable () -> Unit)? = null,
1092         colors: NavigationSuiteItemColors? = null,
1093         interactionSource: MutableInteractionSource? = null
1094     )
1095 }
1096 
1097 /**
1098  * Class that describes the different navigation suite types of the [NavigationSuiteScaffold].
1099  *
1100  * The [NavigationSuiteType] informs the [NavigationSuite] of what navigation component to expect.
1101  */
1102 @JvmInline
1103 value class NavigationSuiteType private constructor(private val description: String) {
1104     override fun toString(): String {
1105         return description
1106     }
1107 
1108     companion object {
1109         /**
1110          * A navigation suite type that instructs the [NavigationSuite] to expect a
1111          * [ShortNavigationBar] with vertical [ShortNavigationBarItem]s that will be displayed at
1112          * the bottom of the screen.
1113          *
1114          * @see [ShortNavigationBar]
1115          */
1116         val ShortNavigationBarCompact =
1117             NavigationSuiteType(description = "ShortNavigationBarCompact")
1118 
1119         /**
1120          * A navigation suite type that instructs the [NavigationSuite] to expect a
1121          * [ShortNavigationBar] with horizontal [ShortNavigationBarItem]s that will be displayed at
1122          * the bottom of the screen.
1123          *
1124          * @see [ShortNavigationBar]
1125          */
1126         val ShortNavigationBarMedium = NavigationSuiteType(description = "ShortNavigationBarMedium")
1127 
1128         /**
1129          * A navigation suite type that instructs the [NavigationSuite] to expect a collapsed
1130          * [WideNavigationRail] that will be displayed at the start of the screen.
1131          *
1132          * @see [WideNavigationRail]
1133          */
1134         val WideNavigationRailCollapsed =
1135             NavigationSuiteType(description = "WideNavigationRailCollapsed")
1136 
1137         /**
1138          * A navigation suite type that instructs the [NavigationSuite] to expect an expanded
1139          * [WideNavigationRail] that will be displayed at the start of the screen.
1140          *
1141          * @see [WideNavigationRail]
1142          */
1143         val WideNavigationRailExpanded =
1144             NavigationSuiteType(description = "WideNavigationRailExpanded")
1145 
1146         /**
1147          * A navigation suite type that instructs the [NavigationSuite] to expect a [NavigationBar]
1148          * that will be displayed at the bottom of the screen.
1149          *
1150          * Note: It's recommended to use [ShortNavigationBarCompact] instead of this layout type.
1151          *
1152          * @see [NavigationBar]
1153          */
1154         val NavigationBar = NavigationSuiteType(description = "NavigationBar")
1155 
1156         /**
1157          * A navigation suite type that instructs the [NavigationSuite] to expect a [NavigationRail]
1158          * that will be displayed at the start of the screen.
1159          *
1160          * Note: It's recommended to use [WideNavigationRailCollapsed] instead of this layout type.
1161          *
1162          * @see [NavigationRail]
1163          */
1164         val NavigationRail = NavigationSuiteType(description = "NavigationRail")
1165 
1166         /**
1167          * A navigation suite type that instructs the [NavigationSuite] to expect a
1168          * [PermanentDrawerSheet] that will be displayed at the start of the screen.
1169          *
1170          * Note: It's recommended to use [WideNavigationRailExpanded] instead of this layout type.
1171          *
1172          * @see [PermanentDrawerSheet]
1173          */
1174         val NavigationDrawer = NavigationSuiteType(description = "NavigationDrawer")
1175 
1176         /**
1177          * A navigation suite type that instructs the [NavigationSuite] to not display any
1178          * navigation components on the screen.
1179          *
1180          * Note: It's recommended to use [NavigationSuiteScaffoldState] instead of this layout type
1181          * and set the visibility of the navigation component to hidden.
1182          */
1183         val None = NavigationSuiteType(description = "None")
1184     }
1185 }
1186 
1187 /** Contains the default values used by the [NavigationSuiteScaffold]. */
1188 object NavigationSuiteScaffoldDefaults {
1189     /**
1190      * Returns the recommended [NavigationSuiteType] according to the provided [WindowAdaptiveInfo],
1191      * following the Material specifications. Usually used with the [NavigationSuiteScaffold] and
1192      * related APIs.
1193      *
1194      * @param adaptiveInfo the provided [WindowAdaptiveInfo]
1195      * @see NavigationSuiteScaffold
1196      */
1197     @Suppress("DEPRECATION") // WindowWidthSizeClass deprecated
navigationSuiteTypenull1198     fun navigationSuiteType(adaptiveInfo: WindowAdaptiveInfo): NavigationSuiteType {
1199         return with(adaptiveInfo) {
1200             if (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT) {
1201                 NavigationSuiteType.ShortNavigationBarCompact
1202             } else if (
1203                 windowPosture.isTabletop ||
1204                     windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT &&
1205                         (windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.MEDIUM ||
1206                             windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED)
1207             ) {
1208                 NavigationSuiteType.ShortNavigationBarMedium
1209             } else {
1210                 NavigationSuiteType.WideNavigationRailCollapsed
1211             }
1212         }
1213     }
1214 
1215     /**
1216      * Returns the standard [NavigationSuiteType] according to the provided [WindowAdaptiveInfo].
1217      * Usually used with the [NavigationSuiteScaffold] and related APIs.
1218      *
1219      * Note: It's recommended to use [navigationSuiteType] instead of this function, as that one
1220      * offers extended and preferred types.
1221      *
1222      * @param adaptiveInfo the provided [WindowAdaptiveInfo]
1223      * @see NavigationSuiteScaffold
1224      * @see navigationSuiteType
1225      */
1226     @Suppress("DEPRECATION") // WindowWidthSizeClass deprecated
calculateFromAdaptiveInfonull1227     fun calculateFromAdaptiveInfo(adaptiveInfo: WindowAdaptiveInfo): NavigationSuiteType {
1228         return with(adaptiveInfo) {
1229             if (
1230                 windowPosture.isTabletop ||
1231                     windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT ||
1232                     windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT
1233             ) {
1234                 NavigationSuiteType.NavigationBar
1235             } else {
1236                 NavigationSuiteType.NavigationRail
1237             }
1238         }
1239     }
1240 
1241     /** Default container color for a navigation suite scaffold. */
1242     val containerColor: Color
1243         @Composable get() = MaterialTheme.colorScheme.background
1244 
1245     /** Default content color for a navigation suite scaffold. */
1246     val contentColor: Color
1247         @Composable get() = MaterialTheme.colorScheme.onBackground
1248 
1249     /** Default primary action content alignment for a navigation suite scaffold. */
1250     val primaryActionContentAlignment = Alignment.End
1251 }
1252 
1253 /** Contains the default values used by the [NavigationSuite]. */
1254 object NavigationSuiteDefaults {
1255     /** Default items vertical arrangement for a navigation suite. */
1256     val verticalArrangement = Arrangement.Top
1257 
1258     /**
1259      * Creates a [NavigationSuiteColors] with the provided colors for the container color, according
1260      * to the Material specification.
1261      *
1262      * Use [Color.Transparent] for the navigation*ContainerColor to have no color. The
1263      * navigation*ContentColor will default to either the matching content color for
1264      * navigation*ContainerColor, or to the current [LocalContentColor] if navigation*ContainerColor
1265      * is not a color from the theme.
1266      *
1267      * @param shortNavigationBarContainerColor the container color for the [ShortNavigationBar]
1268      * @param shortNavigationBarContentColor the content color for the [ShortNavigationBar]
1269      * @param wideNavigationRailColors the [WideNavigationRailColors] for the [WideNavigationRail]
1270      * @param navigationBarContainerColor the default container color for the [NavigationBar]
1271      * @param navigationBarContentColor the default content color for the [NavigationBar]
1272      * @param navigationRailContainerColor the default container color for the [NavigationRail]
1273      * @param navigationRailContentColor the default content color for the [NavigationRail]
1274      * @param navigationDrawerContainerColor the default container color for the
1275      *   [PermanentDrawerSheet]
1276      * @param navigationDrawerContentColor the default content color for the [PermanentDrawerSheet]
1277      */
1278     @OptIn(ExperimentalMaterial3ExpressiveApi::class)
1279     @Composable
colorsnull1280     fun colors(
1281         shortNavigationBarContentColor: Color = ShortNavigationBarDefaults.contentColor,
1282         shortNavigationBarContainerColor: Color = ShortNavigationBarDefaults.containerColor,
1283         wideNavigationRailColors: WideNavigationRailColors = WideNavigationRailDefaults.colors(),
1284         navigationBarContainerColor: Color = NavigationBarDefaults.containerColor,
1285         navigationBarContentColor: Color = contentColorFor(navigationBarContainerColor),
1286         navigationRailContainerColor: Color = NavigationRailDefaults.ContainerColor,
1287         navigationRailContentColor: Color = contentColorFor(navigationRailContainerColor),
1288         navigationDrawerContainerColor: Color =
1289             @Suppress("DEPRECATION") DrawerDefaults.containerColor,
1290         navigationDrawerContentColor: Color = contentColorFor(navigationDrawerContainerColor),
1291     ): NavigationSuiteColors =
1292         NavigationSuiteColors(
1293             navigationDrawerContentColor = navigationDrawerContentColor,
1294             shortNavigationBarContentColor = shortNavigationBarContentColor,
1295             shortNavigationBarContainerColor = shortNavigationBarContainerColor,
1296             wideNavigationRailColors = wideNavigationRailColors,
1297             navigationBarContainerColor = navigationBarContainerColor,
1298             navigationBarContentColor = navigationBarContentColor,
1299             navigationRailContainerColor = navigationRailContainerColor,
1300             navigationRailContentColor = navigationRailContentColor,
1301             navigationDrawerContainerColor = navigationDrawerContainerColor
1302         )
1303 
1304     /**
1305      * Creates a [NavigationSuiteColors] with the provided colors for the container color, according
1306      * to the Material specification.
1307      *
1308      * Use [Color.Transparent] for the navigation*ContainerColor to have no color. The
1309      * navigation*ContentColor will default to either the matching content color for
1310      * navigation*ContainerColor, or to the current [LocalContentColor] if navigation*ContainerColor
1311      * is not a color from the theme.
1312      *
1313      * @param navigationBarContainerColor the default container color for the [NavigationBar]
1314      * @param navigationBarContentColor the default content color for the [NavigationBar]
1315      * @param navigationRailContainerColor the default container color for the [NavigationRail]
1316      * @param navigationRailContentColor the default content color for the [NavigationRail]
1317      * @param navigationDrawerContainerColor the default container color for the
1318      *   [PermanentDrawerSheet]
1319      * @param navigationDrawerContentColor the default content color for the [PermanentDrawerSheet]
1320      */
1321     @OptIn(ExperimentalMaterial3ExpressiveApi::class)
1322     @Deprecated(
1323         message =
1324             "Deprecated in favor of colors with shortNavigationBar*Color and " +
1325                 "wideNavigationRailColors parameters",
1326         level = DeprecationLevel.HIDDEN
1327     )
1328     @Composable
1329     fun colors(
1330         navigationBarContainerColor: Color = NavigationBarDefaults.containerColor,
1331         navigationBarContentColor: Color = contentColorFor(navigationBarContainerColor),
1332         navigationRailContainerColor: Color = NavigationRailDefaults.ContainerColor,
1333         navigationRailContentColor: Color = contentColorFor(navigationRailContainerColor),
1334         navigationDrawerContainerColor: Color =
1335             @Suppress("DEPRECATION") DrawerDefaults.containerColor,
1336         navigationDrawerContentColor: Color = contentColorFor(navigationDrawerContainerColor),
1337     ): NavigationSuiteColors =
1338         NavigationSuiteColors(
1339             shortNavigationBarContainerColor = ShortNavigationBarDefaults.containerColor,
1340             shortNavigationBarContentColor = ShortNavigationBarDefaults.contentColor,
1341             wideNavigationRailColors = WideNavigationRailDefaults.colors(),
1342             navigationBarContainerColor = navigationBarContainerColor,
1343             navigationBarContentColor = navigationBarContentColor,
1344             navigationRailContainerColor = navigationRailContainerColor,
1345             navigationRailContentColor = navigationRailContentColor,
1346             navigationDrawerContainerColor = navigationDrawerContainerColor,
1347             navigationDrawerContentColor = navigationDrawerContentColor
1348         )
1349 
1350     /**
1351      * Creates a [NavigationSuiteItemColors] with the provided colors for a
1352      * [NavigationSuiteScope.item].
1353      *
1354      * For specifics about each navigation item colors see [NavigationBarItemColors],
1355      * [NavigationRailItemColors], and [NavigationDrawerItemColors].
1356      *
1357      * @param navigationBarItemColors the [NavigationBarItemColors] associated with the
1358      *   [NavigationBarItem] of the [NavigationSuiteScope.item]
1359      * @param navigationRailItemColors the [NavigationRailItemColors] associated with the
1360      *   [NavigationRailItem] of the [NavigationSuiteScope.item]
1361      * @param navigationDrawerItemColors the [NavigationDrawerItemColors] associated with the
1362      *   [NavigationDrawerItem] of the [NavigationSuiteScope.item]
1363      */
1364     @Composable
1365     fun itemColors(
1366         navigationBarItemColors: NavigationBarItemColors = NavigationBarItemDefaults.colors(),
1367         navigationRailItemColors: NavigationRailItemColors = NavigationRailItemDefaults.colors(),
1368         navigationDrawerItemColors: NavigationDrawerItemColors =
1369             NavigationDrawerItemDefaults.colors()
1370     ): NavigationSuiteItemColors =
1371         NavigationSuiteItemColors(
1372             navigationBarItemColors = navigationBarItemColors,
1373             navigationRailItemColors = navigationRailItemColors,
1374             navigationDrawerItemColors = navigationDrawerItemColors
1375         )
1376 }
1377 
1378 /**
1379  * Represents the colors of a [NavigationSuite].
1380  *
1381  * For specifics about each navigation component colors see [NavigationBarDefaults],
1382  * [NavigationRailDefaults], and [DrawerDefaults].
1383  *
1384  * @param shortNavigationBarContainerColor the container color for the [ShortNavigationBar] of the
1385  *   [NavigationSuite]
1386  * @param shortNavigationBarContentColor the content color for the [ShortNavigationBar] of the
1387  *   [NavigationSuite]
1388  * @param wideNavigationRailColors the [WideNavigationRailColors] for the [WideNavigationRail] of
1389  *   the [NavigationSuite]
1390  * @param navigationBarContainerColor the container color for the [NavigationBar] of the
1391  *   [NavigationSuite]
1392  * @param navigationBarContentColor the content color for the [NavigationBar] of the
1393  *   [NavigationSuite]
1394  * @param navigationRailContainerColor the container color for the [NavigationRail] of the
1395  *   [NavigationSuite]
1396  * @param navigationRailContentColor the content color for the [NavigationRail] of the
1397  *   [NavigationSuite]
1398  * @param navigationDrawerContainerColor the container color for the [PermanentDrawerSheet] of the
1399  *   [NavigationSuite]
1400  * @param navigationDrawerContentColor the content color for the [PermanentDrawerSheet] of the
1401  *   [NavigationSuite]
1402  */
1403 class NavigationSuiteColors
1404 internal constructor(
1405     val shortNavigationBarContainerColor: Color,
1406     val shortNavigationBarContentColor: Color,
1407     val wideNavigationRailColors: WideNavigationRailColors,
1408     val navigationBarContainerColor: Color,
1409     val navigationBarContentColor: Color,
1410     val navigationRailContainerColor: Color,
1411     val navigationRailContentColor: Color,
1412     val navigationDrawerContainerColor: Color,
1413     val navigationDrawerContentColor: Color
1414 )
1415 
1416 /**
1417  * Represents the colors of a [NavigationSuiteScope.item].
1418  *
1419  * For specifics about each navigation item colors see [NavigationBarItemColors],
1420  * [NavigationRailItemColors], and [NavigationDrawerItemColors].
1421  *
1422  * @param navigationBarItemColors the [NavigationBarItemColors] associated with the
1423  *   [NavigationBarItem] of the [NavigationSuiteScope.item]
1424  * @param navigationRailItemColors the [NavigationRailItemColors] associated with the
1425  *   [NavigationRailItem] of the [NavigationSuiteScope.item]
1426  * @param navigationDrawerItemColors the [NavigationDrawerItemColors] associated with the
1427  *   [NavigationDrawerItem] of the [NavigationSuiteScope.item]
1428  */
1429 class NavigationSuiteItemColors(
1430     val navigationBarItemColors: NavigationBarItemColors,
1431     val navigationRailItemColors: NavigationRailItemColors,
1432     val navigationDrawerItemColors: NavigationDrawerItemColors,
1433 )
1434 
1435 internal val WindowAdaptiveInfoDefault
1436     @Composable get() = currentWindowAdaptiveInfo()
1437 
1438 internal val NavigationSuiteScaffoldValue.isVisible
1439     get() = this == NavigationSuiteScaffoldValue.Visible
1440 
1441 internal class NavigationSuiteScaffoldStateImpl(var initialValue: NavigationSuiteScaffoldValue) :
1442     NavigationSuiteScaffoldState {
1443     private val internalValue: Float = if (initialValue.isVisible) Visible else Hidden
1444     private val internalState = Animatable(internalValue, Float.VectorConverter)
1445     private val _currentVal = derivedStateOf {
1446         if (internalState.value == Visible) {
1447             NavigationSuiteScaffoldValue.Visible
1448         } else {
1449             NavigationSuiteScaffoldValue.Hidden
1450         }
1451     }
1452 
1453     override val isAnimating: Boolean
1454         get() = internalState.isRunning
1455 
1456     override val targetValue: NavigationSuiteScaffoldValue
1457         get() =
1458             if (internalState.targetValue == Visible) {
1459                 NavigationSuiteScaffoldValue.Visible
1460             } else {
1461                 NavigationSuiteScaffoldValue.Hidden
1462             }
1463 
1464     override val currentValue: NavigationSuiteScaffoldValue
1465         get() = _currentVal.value
1466 
1467     override suspend fun hide() {
1468         internalState.animateTo(targetValue = Hidden, animationSpec = AnimationSpec)
1469     }
1470 
1471     override suspend fun show() {
1472         internalState.animateTo(targetValue = Visible, animationSpec = AnimationSpec)
1473     }
1474 
1475     override suspend fun toggle() {
1476         internalState.animateTo(
1477             targetValue = if (targetValue.isVisible) Hidden else Visible,
1478             animationSpec = AnimationSpec
1479         )
1480     }
1481 
1482     override suspend fun snapTo(targetValue: NavigationSuiteScaffoldValue) {
1483         val target = if (targetValue.isVisible) Visible else Hidden
1484         internalState.snapTo(target)
1485     }
1486 
1487     companion object {
1488         private const val Hidden = 0f
1489         private const val Visible = 1f
1490 
1491         /** The default [Saver] implementation for [NavigationSuiteScaffoldState]. */
1492         fun Saver() =
1493             Saver<NavigationSuiteScaffoldState, NavigationSuiteScaffoldValue>(
1494                 save = { it.targetValue },
1495                 restore = { NavigationSuiteScaffoldStateImpl(it) }
1496             )
1497     }
1498 }
1499 
1500 @Composable
1501 @OptIn(ExperimentalMaterial3ExpressiveApi::class)
Modifiernull1502 private fun Modifier.navigationSuiteScaffoldConsumeWindowInsets(
1503     navigationSuiteType: NavigationSuiteType,
1504     state: NavigationSuiteScaffoldState
1505 ): Modifier =
1506     consumeWindowInsets(
1507         if (state.currentValue == NavigationSuiteScaffoldValue.Hidden && !state.isAnimating) {
1508             NoWindowInsets
1509         } else {
1510             when (navigationSuiteType) {
1511                 NavigationSuiteType.ShortNavigationBarCompact,
1512                 NavigationSuiteType.ShortNavigationBarMedium ->
1513                     ShortNavigationBarDefaults.windowInsets.only(WindowInsetsSides.Bottom)
1514                 NavigationSuiteType.WideNavigationRailCollapsed,
1515                 NavigationSuiteType.WideNavigationRailExpanded, ->
1516                     WideNavigationRailDefaults.windowInsets.only(WindowInsetsSides.Start)
1517                 NavigationSuiteType.NavigationBar ->
1518                     NavigationBarDefaults.windowInsets.only(WindowInsetsSides.Bottom)
1519                 NavigationSuiteType.NavigationRail ->
1520                     NavigationRailDefaults.windowInsets.only(WindowInsetsSides.Start)
1521                 NavigationSuiteType.NavigationDrawer ->
1522                     DrawerDefaults.windowInsets.only(WindowInsetsSides.Start)
1523                 else -> NoWindowInsets
1524             }
1525         }
1526     )
1527 
1528 private val NavigationSuiteType.isNavigationBar
1529     get() =
1530         this == NavigationSuiteType.ShortNavigationBarCompact ||
1531             this == NavigationSuiteType.ShortNavigationBarMedium ||
1532             this == NavigationSuiteType.NavigationBar
1533 
1534 private interface NavigationSuiteItemProvider {
1535     val itemsCount: Int
1536     val itemList: MutableVector<NavigationSuiteItem>
1537 }
1538 
1539 private class NavigationSuiteItem(
1540     val selected: Boolean,
1541     val onClick: () -> Unit,
1542     val icon: @Composable () -> Unit,
1543     val modifier: Modifier,
1544     val enabled: Boolean,
1545     val label: @Composable (() -> Unit)?,
1546     val alwaysShowLabel: Boolean,
1547     val badge: (@Composable () -> Unit)?,
1548     val colors: NavigationSuiteItemColors?,
1549     val interactionSource: MutableInteractionSource?
1550 )
1551 
1552 private class NavigationSuiteScopeImpl : NavigationSuiteScope, NavigationSuiteItemProvider {
1553 
1554     override fun item(
1555         selected: Boolean,
1556         onClick: () -> Unit,
1557         icon: @Composable () -> Unit,
1558         modifier: Modifier,
1559         enabled: Boolean,
1560         label: @Composable (() -> Unit)?,
1561         alwaysShowLabel: Boolean,
1562         badge: (@Composable () -> Unit)?,
1563         colors: NavigationSuiteItemColors?,
1564         interactionSource: MutableInteractionSource?
1565     ) {
1566         itemList.add(
1567             NavigationSuiteItem(
1568                 selected = selected,
1569                 onClick = onClick,
1570                 icon = icon,
1571                 modifier = modifier,
1572                 enabled = enabled,
1573                 label = label,
1574                 alwaysShowLabel = alwaysShowLabel,
1575                 badge = badge,
1576                 colors = colors,
1577                 interactionSource = interactionSource
1578             )
1579         )
1580     }
1581 
1582     override val itemList: MutableVector<NavigationSuiteItem> = mutableVectorOf()
1583 
1584     override val itemsCount: Int
1585         get() = itemList.size
1586 }
1587 
1588 @Composable
rememberStateOfItemsnull1589 private fun rememberStateOfItems(
1590     content: NavigationSuiteScope.() -> Unit
1591 ): State<NavigationSuiteItemProvider> {
1592     val latestContent = rememberUpdatedState(content)
1593     return remember { derivedStateOf { NavigationSuiteScopeImpl().apply(latestContent.value) } }
1594 }
1595 
1596 @Composable
NavigationItemIconnull1597 private fun NavigationItemIcon(
1598     icon: @Composable () -> Unit,
1599     badge: (@Composable () -> Unit)? = null,
1600 ) {
1601     if (badge != null) {
1602         BadgedBox(badge = { badge.invoke() }) { icon() }
1603     } else {
1604         icon()
1605     }
1606 }
1607 
1608 private const val SpringDefaultSpatialDamping = 0.9f
1609 private const val SpringDefaultSpatialStiffness = 700.0f
1610 private const val NavigationSuiteLayoutIdTag = "navigationSuite"
1611 private const val PrimaryActionContentLayoutIdTag = "primaryActionContent"
1612 private const val ContentLayoutIdTag = "content"
1613 
1614 private val TallNavigationBarHeight = 80.dp
1615 private val PrimaryActionContentPadding = 16.dp
1616 private val NoWindowInsets = WindowInsets(0, 0, 0, 0)
1617 private val AnimationSpec: SpringSpec<Float> =
1618     spring(dampingRatio = SpringDefaultSpatialDamping, stiffness = SpringDefaultSpatialStiffness)
1619 
1620 /**
1621  * Interface that allows libraries to override the behavior of the [NavigationSuiteScaffold]
1622  * component.
1623  *
1624  * To override this component, implement the member function of this interface, then provide the
1625  * implementation to [LocalNavigationSuiteScaffoldOverride] in the Compose hierarchy.
1626  */
1627 @ExperimentalMaterial3AdaptiveComponentOverrideApi
1628 interface NavigationSuiteScaffoldOverride {
1629     /** Behavior function that is called by the [NavigationSuiteScaffold] component. */
NavigationSuiteScaffoldnull1630     @Composable fun NavigationSuiteScaffoldOverrideScope.NavigationSuiteScaffold()
1631 }
1632 
1633 /**
1634  * Parameters available to [NavigationSuiteScaffold].
1635  *
1636  * @param navigationSuiteItems the navigation items to be displayed
1637  * @param modifier the [Modifier] to be applied to the navigation suite scaffold
1638  * @param layoutType the current [NavigationSuiteType]. Defaults to
1639  *   [NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo]
1640  * @param navigationSuiteColors [NavigationSuiteColors] that will be used to determine the container
1641  *   (background) color of the navigation component and the preferred color for content inside the
1642  *   navigation component
1643  * @param containerColor the color used for the background of the navigation suite scaffold,
1644  *   including the passed [content] composable. Use [Color.Transparent] to have no color
1645  * @param contentColor the preferred color to be used for typography and iconography within the
1646  *   passed in [content] lambda inside the navigation suite scaffold.
1647  * @param state the [NavigationSuiteScaffoldState] of this navigation suite scaffold
1648  * @param content the content of your screen
1649  */
1650 @ExperimentalMaterial3AdaptiveComponentOverrideApi
1651 class NavigationSuiteScaffoldOverrideScope
1652 internal constructor(
1653     val navigationSuiteItems: NavigationSuiteScope.() -> Unit,
1654     val modifier: Modifier = Modifier,
1655     val layoutType: NavigationSuiteType,
1656     val navigationSuiteColors: NavigationSuiteColors,
1657     val containerColor: Color,
1658     val contentColor: Color,
1659     val state: NavigationSuiteScaffoldState,
1660     val content: @Composable () -> Unit = {},
1661 )
1662 
1663 /** CompositionLocal containing the currently-selected [NavigationSuiteScaffoldOverride]. */
1664 @Suppress("OPT_IN_MARKER_ON_WRONG_TARGET")
1665 @get:ExperimentalMaterial3AdaptiveComponentOverrideApi
1666 @ExperimentalMaterial3AdaptiveComponentOverrideApi
1667 val LocalNavigationSuiteScaffoldOverride:
1668     ProvidableCompositionLocal<NavigationSuiteScaffoldOverride> =
<lambda>null1669     compositionLocalOf {
1670         DefaultNavigationSuiteScaffoldOverride
1671     }
1672