@kyralabs/m3e-motion 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -57,9 +57,10 @@ declare class SpringAnimatable {
57
57
  snapTo(value: number): void;
58
58
  /**
59
59
  * Animates to `target` from the value and velocity at `now` (ms); a null spec (e.g. a spatial
60
- * spring under reduced motion) jumps there.
60
+ * spring under reduced motion) jumps there. `velocity` (units per second) overrides the current
61
+ * velocity, e.g. after the value was driven by something else (a drag, a tween).
61
62
  */
62
- animateTo(target: number, spec: SpringSpec | null, now: number): void;
63
+ animateTo(target: number, spec: SpringSpec | null, now: number, velocity?: number): void;
63
64
  /** Advances to `now` (ms) and returns the value; the animation ends once its duration is up. */
64
65
  sample(now: number): number;
65
66
  }
@@ -75,6 +76,142 @@ declare const fabMenuItemVisible: (index: number, itemCount: number, stagger: nu
75
76
  */
76
77
  declare function menuNavigationTarget(key: string, count: number, current: number): number | null;
77
78
 
79
+ type ToolbarOrientation = 'horizontal' | 'vertical';
80
+ /**
81
+ * The item index `key` moves focus to from `current` (−1: none focused) among `count` items, or
82
+ * null when the key does not navigate. At either end the index stays put (no wrapping).
83
+ */
84
+ declare function toolbarNavigationTarget(key: string, count: number, current: number, orientation?: ToolbarOrientation, rtl?: boolean): number | null;
85
+
86
+ /** Where a floating toolbar leaves the screen (FloatingToolbarExitDirection), logical. */
87
+ type FloatingToolbarExitDirection = 'bottom' | 'top' | 'start' | 'end';
88
+ interface FloatingToolbarScrollState {
89
+ /** Most negative offset: minus the distance that takes the toolbar off its container. */
90
+ readonly offsetLimit: number;
91
+ /** Current offset, between offsetLimit and 0. */
92
+ readonly offset: number;
93
+ /** Total content scrolled under the toolbar (sum of the deltas). */
94
+ readonly contentOffset: number;
95
+ }
96
+ /** rememberFloatingToolbarState() defaults: no limit known yet, fully shown. */
97
+ declare function floatingToolbarScrollState(offsetLimit?: number, offset?: number, contentOffset?: number): FloatingToolbarScrollState;
98
+ /** FloatingToolbarState.offset setter: coerced between offsetLimit and 0. */
99
+ declare function withToolbarOffset(state: FloatingToolbarScrollState, offset: number): FloatingToolbarScrollState;
100
+ /**
101
+ * The offset limit from the toolbar's layout (onGloballyPositioned): `distance` is how far the
102
+ * toolbar must travel along its exit direction to leave its container, i.e. its size plus its gap
103
+ * to that edge, measured without the current offset. The offset stays in range.
104
+ */
105
+ declare function withToolbarOffsetLimit(state: FloatingToolbarScrollState, distance: number): FloatingToolbarScrollState;
106
+ /** exitAlways onPostScroll: the content offset and the toolbar offset both move by `delta`. */
107
+ declare function scrollFloatingToolbar(state: FloatingToolbarScrollState, delta: number): FloatingToolbarScrollState;
108
+ /** 0 = fully shown, 1 = fully hidden (FloatingToolbarState.collapsedFraction()). */
109
+ declare function toolbarCollapsedFraction(state: FloatingToolbarScrollState): number;
110
+ /**
111
+ * Where a partly hidden toolbar snaps when scrolling stops (settleFloatingToolbar): shown below
112
+ * half, hidden from half, or null when it is already (within 1%) settled. The decision is the
113
+ * same as the top app bar's settleAppBar, so it reuses that port.
114
+ */
115
+ declare function toolbarSettleTarget(state: FloatingToolbarScrollState): number | null;
116
+ /**
117
+ * floatingToolbarVerticalNestedScroll: collapses the toolbar after scrolling down by the collapse
118
+ * threshold and expands it after scrolling up by the expand threshold (both
119
+ * FloatingToolbarDefaults.ScrollDistanceThreshold by default).
120
+ */
121
+ interface ToolbarExpansionScroll {
122
+ readonly contentOffset: number;
123
+ /** The content offset that triggers the next change. */
124
+ readonly threshold: number;
125
+ }
126
+ /** A tracker for a toolbar that is `expanded` (updateThreshold). */
127
+ declare function toolbarExpansionScroll(expanded: boolean, collapseThreshold: number, expandThreshold: number, contentOffset?: number): ToolbarExpansionScroll;
128
+ /**
129
+ * onPostScroll: moves the content offset by `delta`; returns the new tracker and `'collapse'` /
130
+ * `'expand'` when a threshold was crossed (Compose calls onCollapse / onExpand then).
131
+ */
132
+ declare function scrollToolbarExpansion(state: ToolbarExpansionScroll, delta: number, collapseThreshold: number, expandThreshold: number): {
133
+ state: ToolbarExpansionScroll;
134
+ change: 'collapse' | 'expand' | null;
135
+ };
136
+
137
+ type Easing = (fraction: number) => number;
138
+ /** `cubic-bezier(a, b, c, d)` as an easing function. */
139
+ declare const cubicBezier: (a: number, b: number, c: number, d: number) => Easing;
140
+ /** Parses a resolved CSS `cubic-bezier(a, b, c, d)` (e.g. a motion easing token); null otherwise. */
141
+ declare function parseCubicBezier(css: string): Easing | null;
142
+
143
+ interface LinearIndeterminateTiming {
144
+ /** `LinearAnimationDuration`: one cycle. */
145
+ readonly durationMillis: number;
146
+ /** `[delay, duration]` of each keyframe pair. */
147
+ readonly firstHead: readonly [number, number];
148
+ readonly firstTail: readonly [number, number];
149
+ readonly secondHead: readonly [number, number];
150
+ readonly secondTail: readonly [number, number];
151
+ /** `LinearIndeterminateProgressEasing`. */
152
+ readonly easing: Easing;
153
+ }
154
+ /**
155
+ * The indeterminate linear indicator's fractions at `elapsedMillis`, in the order the wavy indicator
156
+ * draws them (`getProgressFractions`): first tail, first head, second tail, second head (0–1 each).
157
+ */
158
+ declare function linearIndeterminateFractions(elapsedMillis: number, timing: LinearIndeterminateTiming): [number, number, number, number];
159
+ interface CircularIndeterminateTiming {
160
+ /** `CircularAnimationProgressDuration`: one cycle. */
161
+ readonly durationMillis: number;
162
+ /** `CircularGlobalRotationDegreesTarget`: linear rotation per cycle (degrees). */
163
+ readonly rotation: number;
164
+ /** `CircularAdditionalRotationDegreesTarget`: the steps' total per cycle (degrees). */
165
+ readonly additionalRotation: number;
166
+ /** `CircularAnimationAdditionalRotationDelay`: a step starts every this. */
167
+ readonly additionalDelayMillis: number;
168
+ /** `CircularAnimationAdditionalRotationDuration`: and moves for this. */
169
+ readonly additionalDurationMillis: number;
170
+ /** `CircularIndeterminateMinProgress` / `MaxProgress`: the sweep range (0–1). */
171
+ readonly minProgress: number;
172
+ readonly maxProgress: number;
173
+ /** `CircularProgressEasing`: the shrinking half of the sweep. */
174
+ readonly easing: Easing;
175
+ }
176
+ interface CircularIndeterminateFrame {
177
+ /** Global + additional rotation, degrees clockwise. */
178
+ rotation: number;
179
+ /** Sweep, 0–1 of a full turn. */
180
+ sweep: number;
181
+ }
182
+ /** The indeterminate circular indicator at `elapsedMillis`. */
183
+ declare function circularIndeterminateFrame(elapsedMillis: number, timing: CircularIndeterminateTiming): CircularIndeterminateFrame;
184
+ /**
185
+ * The wave offset tween's duration: `((wavelength / waveSpeed) * 1000 * vertexCount)` rounded and
186
+ * floored at `minMillis`; `Infinity` (the offset holds at 0) when either is not positive.
187
+ */
188
+ declare function waveTravelMillis(wavelength: number, waveSpeed: number, minMillis: number, vertexCount?: number): number;
189
+ /** The wave offset (0–1) after `elapsedMillis` of a tween of `travelMillis`. */
190
+ declare const waveOffset: (elapsedMillis: number, travelMillis: number) => number;
191
+ /** `WavyProgressIndicatorDefaults.indicatorAmplitude`: no wave near the start and the end. */
192
+ declare const indicatorAmplitude: (progress: number, minProgress: number, maxProgress: number) => number;
193
+ interface AmplitudeTween {
194
+ readonly durationMillis: number;
195
+ readonly easing: Easing;
196
+ }
197
+ /**
198
+ * The amplitude Animatable of the wavy modifiers: starts at its first target without animating;
199
+ * a new target tweens with `increase` or `decrease` (by direction), but only once the running
200
+ * tween has finished (`amplitudeAnimationJob == null || isCompleted`); a target set meanwhile is
201
+ * ignored, as in Compose, until the next `update` after it finishes.
202
+ */
203
+ declare class AmplitudeAnimation {
204
+ #private;
205
+ constructor(initial: number);
206
+ get value(): number;
207
+ get target(): number;
208
+ get isRunning(): boolean;
209
+ /** Advances to `now` (ms). */
210
+ sample(now: number): number;
211
+ /** Requests `target` at `now`; returns true when a tween started. */
212
+ update(target: number, now: number, increase: AmplitudeTween, decrease: AmplitudeTween): boolean;
213
+ }
214
+
78
215
  interface LoadingIndicatorTiming {
79
216
  /** `MorphIntervalMillis`: how often a morph starts. */
80
217
  readonly morphIntervalMillis: number;
@@ -210,7 +347,7 @@ declare function menuTransformOrigin(anchor: MenuRect, menu: MenuRect): {
210
347
  declare function menuPosition(input: MenuPositionInput): MenuPositionResult;
211
348
 
212
349
  /** How the bar reacts to its scroll container (TopAppBarDefaults.*ScrollBehavior). */
213
- type AppBarScrollBehavior = 'pinned' | 'enter-always';
350
+ type AppBarScrollBehavior = 'pinned' | 'enter-always' | 'exit-until-collapsed';
214
351
  interface AppBarScrollState {
215
352
  /** Most negative height offset: minus the bar's full height (adjustHeightOffsetLimit). */
216
353
  readonly heightOffsetLimit: number;
@@ -242,6 +379,13 @@ declare function isScrolledUnder(state: AppBarScrollState): boolean;
242
379
  * - pinned: only the content offset moves (PinnedScrollBehavior.onPostScroll).
243
380
  * - enter-always: the bar also collapses/expands by the same amount
244
381
  * (EnterAlwaysScrollBehavior.onPreScroll: `heightOffset += available.y`).
382
+ * - exit-until-collapsed: scrolling down collapses the bar by the same amount
383
+ * (ExitUntilCollapsedScrollBehavior.onPreScroll); scrolling up expands it only by what the
384
+ * content cannot take (onPostScroll: `heightOffset += available.y` once the content is at its
385
+ * start). On the web the content scrolls by the whole delta, so the part of an upward scroll
386
+ * that lies within the collapsed distance of the top (scroll position below -heightOffset) is
387
+ * the part Compose hands to the bar: the bar is fully expanded when the content reaches its
388
+ * start, and a bar that collapsed together with the content stays attached to it.
245
389
  */
246
390
  declare function scrollAppBar(state: AppBarScrollState, behavior: AppBarScrollBehavior, scrollTop: number, delta: number): AppBarScrollState;
247
391
  /**
@@ -249,6 +393,177 @@ declare function scrollAppBar(state: AppBarScrollState, behavior: AppBarScrollBe
249
393
  * half, fully collapsed from half, or null when it is already (within 1%) settled.
250
394
  */
251
395
  declare function settleTarget(state: AppBarScrollState): number | null;
396
+ /** TopTitleAlphaEasing (AppBar.kt L3604): CubicBezierEasing(.8f, 0f, .8f, .15f). */
397
+ declare const TOP_TITLE_ALPHA_EASING: readonly [0.8, 0, 0.8, 0.15];
398
+ /** FastOutLinearInEasing (Easing.kt L66): CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f). */
399
+ declare const FAST_OUT_LINEAR_IN_EASING: readonly [0.4, 0, 1, 1];
400
+ /** What a two-rows bar (medium / large flexible, TwoRowsTopAppBar) draws at a collapsed fraction. */
401
+ interface TwoRowsFrame {
402
+ /** Alpha of the collapsed (top row) title and subtitle: TopTitleAlphaEasing(fraction). */
403
+ readonly collapsedTitleAlpha: number;
404
+ /** Alpha of the expanded (bottom row) title and subtitle: 1 - fraction. */
405
+ readonly expandedTitleAlpha: number;
406
+ /** Container → scrolled container color mix (TopAppBarColors.containerColor): FastOutLinearIn. */
407
+ readonly containerColorFraction: number;
408
+ /** Below 0.5 the collapsed title is hidden from accessibility, from 0.5 the expanded one. */
409
+ readonly collapsedTitleHidden: boolean;
410
+ }
411
+ /** TwoRowsTopAppBar (L2818-2836): the color, both title alphas and semantics follow the fraction. */
412
+ declare function twoRowsFrame(fraction: number): TwoRowsFrame;
413
+
414
+ /** SearchBarState.currentValue is Expanded above this (L1535, "tolerance for spring anim"). */
415
+ declare const SEARCH_BAR_EXPANDED_THRESHOLD = 0.02;
416
+ /** ExpandedDockedSearchBarWithGap shows its results once progress passes this (L3667). */
417
+ declare const SEARCH_DROPDOWN_VISIBLE_PROGRESS = 0.1;
418
+ /** A Compose `tween(durationMillis, delayMillis, easing)`. */
419
+ interface TweenSpec {
420
+ readonly duration: number;
421
+ readonly delay: number;
422
+ readonly easing: Easing;
423
+ }
424
+ /**
425
+ * A float with Compose `Animatable.animateTo(tween)` semantics: each target starts a tween from the
426
+ * current value (velocity is not carried), held for `delay`, then eased over `duration`. A null
427
+ * spec is Compose's `snap()`: the value jumps.
428
+ */
429
+ declare class TweenAnimatable {
430
+ #private;
431
+ constructor(value: number);
432
+ get value(): number;
433
+ get target(): number;
434
+ get isRunning(): boolean;
435
+ snapTo(value: number): void;
436
+ animateTo(target: number, spec: TweenSpec | null, now: number): void;
437
+ sample(now: number): number;
438
+ }
439
+ /** The four animation specs of a SearchBarState (null springs / tweens jump, as `snap()`). */
440
+ interface SearchBarSpecs {
441
+ readonly expand: SpringSpec | null;
442
+ readonly collapse: SpringSpec | null;
443
+ readonly contentFadeIn: TweenSpec | null;
444
+ readonly contentFadeOut: TweenSpec | null;
445
+ }
446
+ /** One sampled frame of a {@link SearchBarAnimation}. */
447
+ interface SearchBarSample {
448
+ /** `animatable.value`: may overshoot 1 (expressive spatial springs). */
449
+ readonly value: number;
450
+ /** `progress`: the value clamped to [0, 1]. */
451
+ readonly progress: number;
452
+ /** `contentProgress` (the contained / with-gap results' alpha). */
453
+ readonly contentProgress: number;
454
+ /** The with-gap drop-down's slide offset in px (0 at rest, minus half its height hidden). */
455
+ readonly slide: number;
456
+ /** Whether the with-gap drop-down is shown (AnimatedVisibility is entering, visible or exiting). */
457
+ readonly dropdownShown: boolean;
458
+ }
459
+ /**
460
+ * SearchBarState's animation: `animateToExpanded` / `animateToCollapsed` run the progress spring
461
+ * and the content tween together; a new target starts from the current value and velocity
462
+ * (Animatable). Optionally (ExpandedDockedSearchBarWithGap) it also runs the drop-down's
463
+ * slide-in / slide-out on the same springs, from progress 0.1.
464
+ */
465
+ declare class SearchBarAnimation {
466
+ #private;
467
+ constructor(expanded?: boolean);
468
+ /** SearchBarState.targetValue. */
469
+ get isTargetExpanded(): boolean;
470
+ /** SearchBarState.currentValue: expanded until the value drops to the 0.02 tolerance. */
471
+ get isExpanded(): boolean;
472
+ get isRunning(): boolean;
473
+ /** animateToExpanded() at `now` (ms). */
474
+ expand(specs: SearchBarSpecs, now: number): void;
475
+ /** animateToCollapsed() at `now` (ms). */
476
+ collapse(specs: SearchBarSpecs, now: number): void;
477
+ /** Jumps to collapsed (0) or expanded (1), stopping every animation. */
478
+ snapTo(expanded: boolean): void;
479
+ /**
480
+ * Advances to `now`. `dropdownHeight` (px, the drop-down's full height) enables the with-gap
481
+ * slide: AnimatedVisibility(visible = progress > 0.1 && target == Expanded) slides in from minus
482
+ * half the height on the expand spring and out to it on the collapse spring.
483
+ */
484
+ sample(now: number, dropdownHeight?: number): SearchBarSample;
485
+ }
486
+ /** The expanded views Compose offers for a SearchBarState. */
487
+ type SearchViewVariant = 'full-screen' | 'full-screen-contained' | 'docked' | 'docked-with-gap';
488
+ interface SearchRect {
489
+ readonly x: number;
490
+ readonly y: number;
491
+ readonly width: number;
492
+ readonly height: number;
493
+ }
494
+ /** The SearchBar.kt measurements the layouts read (px; search-defaults.css). */
495
+ interface SearchViewMetrics {
496
+ /** SearchBarVerticalPadding (8dp). */
497
+ readonly verticalPadding: number;
498
+ /** AppBarWithSearchVerticalPadding (4dp): the contained view's top padding. */
499
+ readonly containedTopPadding: number;
500
+ /** FullScreenExpandedHorizontalPadding (8dp). */
501
+ readonly containedHorizontalPadding: number;
502
+ /** SearchBarCornerRadius = InputFieldHeight / 2 (28dp). */
503
+ readonly cornerRadius: number;
504
+ /** DockedExpandedTableMinHeight (240dp). */
505
+ readonly dockedMinHeight: number;
506
+ /** DockedExpandedTableMaxHeightScreenRatio (2/3). */
507
+ readonly dockedMaxHeightRatio: number;
508
+ /** DockedExpandedWithGapTableMaxHeightScreenRatio (1/2). */
509
+ readonly withGapMaxHeightRatio: number;
510
+ /** dockedDropdownGapSize (2dp). */
511
+ readonly dropdownGap: number;
512
+ }
513
+ interface SearchViewInput {
514
+ readonly variant: SearchViewVariant;
515
+ /** The collapsed search bar (`collapsedBounds`), viewport px. */
516
+ readonly collapsed: SearchRect;
517
+ /** The window (viewport) size. */
518
+ readonly window: {
519
+ readonly width: number;
520
+ readonly height: number;
521
+ };
522
+ /** The unconsumed top window inset (safe area). */
523
+ readonly insetTop: number;
524
+ readonly sample: Pick<SearchBarSample, 'value' | 'progress'>;
525
+ readonly metrics: SearchViewMetrics;
526
+ }
527
+ /** Where everything of an expanded view goes in one frame (viewport px). */
528
+ interface SearchViewFrame {
529
+ /**
530
+ * The surface: full-screen, the growing container (with `radius`); contained, the window,
531
+ * faded in by `alpha`; docked, the panel holding field and results (height between `minHeight`
532
+ * and `maxHeight`); with gap, the scrim (drawn at `alpha` × the scrim opacity).
533
+ */
534
+ readonly surface: SearchRect & {
535
+ readonly radius: number;
536
+ readonly alpha: number;
537
+ readonly minHeight: number;
538
+ readonly maxHeight: number;
539
+ };
540
+ /** The input field (collapsed height). */
541
+ readonly field: {
542
+ readonly x: number;
543
+ readonly y: number;
544
+ readonly width: number;
545
+ };
546
+ /** The results: top-left, width and the height they may take. */
547
+ readonly results: {
548
+ readonly x: number;
549
+ readonly y: number;
550
+ readonly width: number;
551
+ readonly maxHeight: number;
552
+ };
553
+ }
554
+ /**
555
+ * The layout of an expanded view at one animation frame: FullScreenSearchBarLayout (`isContained`
556
+ * false / true), DockedSearchBarLayoutImpl (docked) and the with-gap popup. Predictive back is not
557
+ * ported (the web has no back gesture progress).
558
+ */
559
+ declare function searchViewFrame(input: SearchViewInput): SearchViewFrame;
560
+ /**
561
+ * The combobox's next active option for a key (React Aria / APG list autocomplete): ArrowDown
562
+ * from the input goes to the first option and then down, stopping at the last; ArrowUp from the
563
+ * input goes to the last option and then up, and from the first option back to the input (-1).
564
+ * Returns null for keys it does not handle or an empty list. `enabled` filters disabled options.
565
+ */
566
+ declare function searchNavigationTarget(key: string, enabled: readonly boolean[], active: number): number | null;
252
567
 
253
568
  interface ButtonGroupItemSize {
254
569
  /** Resting width (Compose: the item's max intrinsic width). */
@@ -277,4 +592,640 @@ declare function buttonGroupVisibleCount(widths: readonly number[], spacing: num
277
592
  */
278
593
  declare function buttonGroupWidths(items: readonly ButtonGroupItemSize[], pressed: readonly number[], expandedRatio: number, visibleCount?: number): number[];
279
594
 
280
- export { type AppBarScrollBehavior, type AppBarScrollState, type ButtonGroupItemSize, DEFAULT_DISPLACEMENT_THRESHOLD, type IndeterminateFrame, type LinearEasing, type LinearEasingOptions, type LoadingIndicatorTiming, type MenuAnchorPosition, type MenuPositionInput, type MenuPositionResult, type MenuRect, type Motion, SpringAnimatable, SpringSimulation, type SpringSpec, animatedInt, appBarScrollState, buttonGroupVisibleCount, buttonGroupWidths, collapsedFraction, dampingCoefficient, dampingRatioFromCoefficient, estimateAnimationDurationMillis, estimateAnimationDurationMillisDouble, fabMenuItemVisible, indeterminateFrame, initialIndeterminateFrame, isScrolledUnder, menuNavigationTarget, menuPosition, menuTransformOrigin, morphSpringDurationMillis, overlappedFraction, scrollAppBar, settleTarget, springDurationMillis, springToLinear, springValue, springVelocity, withHeight, withHeightOffset };
595
+ /** Width size classes, smallest first (DpWidthSizeClasses). */
596
+ type WindowWidthSizeClass = 'compact' | 'medium' | 'expanded' | 'large' | 'extra-large';
597
+ /** Height size classes, smallest first (DpHeightSizeClasses). */
598
+ type WindowHeightSizeClass = 'compact' | 'medium' | 'expanded';
599
+ /** Lower bound (min-width, dp = CSS px) of each width size class (WindowSizeClass L146-155). */
600
+ declare const WINDOW_WIDTH_BREAKPOINTS: Readonly<Record<WindowWidthSizeClass, number>>;
601
+ /** Lower bound (min-height, dp = CSS px) of each height size class (WindowSizeClass L158-161). */
602
+ declare const WINDOW_HEIGHT_BREAKPOINTS: Readonly<Record<WindowHeightSizeClass, number>>;
603
+ /** A window's (or container's) size class: androidx `WindowSizeClass` plus its bucket names. */
604
+ interface WindowSizeClass {
605
+ readonly widthClass: WindowWidthSizeClass;
606
+ readonly heightClass: WindowHeightSizeClass;
607
+ /** Lower bound of the width class in CSS px (`minWidthDp`). */
608
+ readonly minWidth: number;
609
+ /** Lower bound of the height class in CSS px (`minHeightDp`). */
610
+ readonly minHeight: number;
611
+ }
612
+ interface WindowSizeClassOptions {
613
+ /**
614
+ * Classify widths into the large and extra-large classes (currentWindowAdaptiveInfoV2; default
615
+ * `true`). `false` keeps the V1 set, where every width from 840 is `expanded`.
616
+ */
617
+ largeAndExtraLargeWidth?: boolean | undefined;
618
+ }
619
+ /**
620
+ * The width size class of a window `widthPx` CSS px wide. Negative or NaN widths (androidx
621
+ * rejects them) classify as compact.
622
+ */
623
+ declare function windowWidthSizeClass(widthPx: number, options?: WindowSizeClassOptions): WindowWidthSizeClass;
624
+ /** The height size class of a window `heightPx` CSS px tall. */
625
+ declare function windowHeightSizeClass(heightPx: number): WindowHeightSizeClass;
626
+ /** The size class of a `width` × `height` CSS px window or container. */
627
+ declare function windowSizeClass(size: {
628
+ readonly width: number;
629
+ readonly height: number;
630
+ }, options?: WindowSizeClassOptions): WindowSizeClass;
631
+ /** Whether two size classes are the same bucket (WindowSizeClass.equals). */
632
+ declare function sameWindowSizeClass(a: WindowSizeClass, b: WindowSizeClass): boolean;
633
+ /**
634
+ * `minWidth >= breakpoint` (isWidthAtLeastBreakpoint, L98-100). `breakpoint` is a class name or a
635
+ * px lower bound. Like androidx, check from the largest breakpoint down.
636
+ */
637
+ declare function isWidthAtLeastBreakpoint(sizeClass: WindowSizeClass, breakpoint: WindowWidthSizeClass | number): boolean;
638
+ /** `minHeight >= breakpoint` (isHeightAtLeastBreakpoint, L107-109). */
639
+ declare function isHeightAtLeastBreakpoint(sizeClass: WindowSizeClass, breakpoint: WindowHeightSizeClass | number): boolean;
640
+ /** Both of the above (isAtLeastBreakpoint, L117-120). */
641
+ declare function isAtLeastBreakpoint(sizeClass: WindowSizeClass, widthBreakpoint: WindowWidthSizeClass | number, heightBreakpoint: WindowHeightSizeClass | number): boolean;
642
+ /** Posture input for the directive and the navigation suite (Compose `Posture.isTabletop`). */
643
+ interface WindowPostureOptions {
644
+ /** A half-folded device with a horizontal hinge. Default `false`. */
645
+ isTabletop?: boolean | undefined;
646
+ }
647
+ /** Material's recommended pane layout for a size class (PaneScaffoldDirective, without hinges). */
648
+ interface PaneScaffoldDirective {
649
+ /** Panes side by side at most: 1 at compact/medium, 2 at expanded, 3 from large. */
650
+ readonly maxHorizontalPartitions: number;
651
+ /** Spacer between side-by-side panes, CSS px. */
652
+ readonly horizontalPartitionSpacerSize: number;
653
+ /** Panes stacked at most: 2 on a tabletop posture or a single-pane expanded-height window. */
654
+ readonly maxVerticalPartitions: number;
655
+ readonly verticalPartitionSpacerSize: number;
656
+ /** Default preferred pane width, CSS px (the fixed pane of a fixed-and-flexible layout). */
657
+ readonly defaultPanePreferredWidth: number;
658
+ readonly defaultPanePreferredHeight: number;
659
+ }
660
+ /** calculatePaneScaffoldDirective (PaneScaffoldDirective.kt L48-106), without hinge bounds. */
661
+ declare function paneScaffoldDirective(sizeClass: WindowSizeClass, options?: WindowPostureOptions): PaneScaffoldDirective;
662
+ /**
663
+ * NavigationSuiteType (NavigationSuiteScaffold.kt L1068-1155) without the types of deprecated
664
+ * components (`NavigationBar`, `NavigationRail`: the legacy bar / rail, D4): which navigation
665
+ * component a navigation suite shows. `none` shows none.
666
+ */
667
+ type NavigationSuiteType = 'short-navigation-bar-compact' | 'short-navigation-bar-medium' | 'wide-navigation-rail-collapsed' | 'wide-navigation-rail-expanded' | 'navigation-drawer' | 'none';
668
+ /** The suite types, in NavigationSuiteType's order. */
669
+ declare const NAVIGATION_SUITE_TYPES: readonly NavigationSuiteType[];
670
+ /** Whether a type puts the navigation at the bottom (`NavigationSuiteType.isNavigationBar`). */
671
+ declare function isNavigationBarType(type: NavigationSuiteType): boolean;
672
+ interface NavigationSuiteTypeOptions extends WindowPostureOptions {
673
+ /**
674
+ * From this width class (or px lower bound, compared with the class's lower bound like
675
+ * `isWidthAtLeastBreakpoint`) on, windows that would get the collapsed rail get `expandedType`
676
+ * instead. Compose's default never expands (`undefined` / `null`); the navigation suite scaffold
677
+ * passes {@link NAVIGATION_SUITE_EXPANDED_FROM}. The bar rules (compact width, then tabletop or
678
+ * compact height) still come first, as in Compose's custom configuration sample.
679
+ */
680
+ expandedFrom?: WindowWidthSizeClass | number | null | undefined;
681
+ /** What the expanded suite shows: the expanded wide navigation rail (default) or a drawer. */
682
+ expandedType?: 'wide-navigation-rail-expanded' | 'navigation-drawer' | undefined;
683
+ }
684
+ /**
685
+ * The navigation suite scaffold's default `expandedFrom`: the expanded wide navigation rail at
686
+ * large and extra-large widths (m3.material.io guidance, owner decision 2026-10-17, COMPONENT_SPEC
687
+ * §16). Not a Compose default: Compose's navigationSuiteType never returns the expanded rail.
688
+ */
689
+ declare const NAVIGATION_SUITE_EXPANDED_FROM: WindowWidthSizeClass;
690
+ /**
691
+ * NavigationSuiteScaffoldDefaults.navigationSuiteType (L1167-1180): a short navigation bar at
692
+ * compact width (compact arrangement), a short navigation bar with the medium (horizontal item)
693
+ * arrangement on a tabletop posture or at compact height, otherwise a collapsed wide navigation
694
+ * rail. With `expandedFrom`, the collapsed rail becomes `expandedType` (default: the expanded wide
695
+ * navigation rail) from that width on.
696
+ */
697
+ declare function navigationSuiteType(sizeClass: WindowSizeClass, options?: NavigationSuiteTypeOptions): NavigationSuiteType;
698
+
699
+ interface NavigationSuiteSample {
700
+ /** The layout's animationProgress: 0 hidden … 1 shown. */
701
+ readonly progress: number;
702
+ /** Either spring is still moving (the caller keeps its frame loop going). */
703
+ readonly running: boolean;
704
+ }
705
+ /**
706
+ * NavigationSuiteScaffoldState plus its layout's progress, driven by the caller's clock (ms).
707
+ * `spec` is the scaffold's AnimationSpec (`--m3e-comp-navigation-suite-scaffold-visibility-*`), or
708
+ * null to jump (the spatial spring under reduced motion).
709
+ */
710
+ declare class NavigationSuiteScaffoldAnimation {
711
+ #private;
712
+ /** `hidden`: rememberNavigationSuiteScaffoldState(initialValue = Hidden); rendered at rest. */
713
+ constructor(hidden?: boolean);
714
+ /** NavigationSuiteScaffoldState.targetValue == Hidden. */
715
+ get targetHidden(): boolean;
716
+ /** NavigationSuiteScaffoldState.currentValue == Hidden (anything but exactly Visible). */
717
+ get currentHidden(): boolean;
718
+ /** NavigationSuiteScaffoldState.isAnimating (the state's spring, not the layout's). */
719
+ get isAnimating(): boolean;
720
+ /** NavigationSuiteScaffoldState.hide(). */
721
+ hide(spec: SpringSpec | null, now: number): void;
722
+ /** NavigationSuiteScaffoldState.show(). */
723
+ show(spec: SpringSpec | null, now: number): void;
724
+ /** NavigationSuiteScaffoldState.toggle(): towards the opposite of the target. */
725
+ toggle(spec: SpringSpec | null, now: number): void;
726
+ /** NavigationSuiteScaffoldState.snapTo(): the state jumps; the layout animates from `now`. */
727
+ snapTo(hidden: boolean, spec: SpringSpec | null, now: number): void;
728
+ /** Advances both springs to `now`; the layout retargets when currentValue changes. */
729
+ sample(now: number): NavigationSuiteSample;
730
+ }
731
+ /**
732
+ * How far the navigation is pushed out of the layout (px) for `size` (its height with a bar, its
733
+ * width otherwise) at `progress`: `size − (size × progress).toInt()`. The content gets the rest of
734
+ * the layout; the navigation sits at `layoutHeight − (height × progress).toInt()` (bar types) or
735
+ * `−(width × (1 − progress)).toInt()` (L417-479).
736
+ */
737
+ declare function navigationSuiteOffset(size: number, progress: number): number;
738
+
739
+ /** ModalWideNavigationRail: the window rail expands once positionProgress reaches this (L600). */
740
+ declare const MODAL_RAIL_EXPANDED_PROGRESS = 0.3;
741
+ /** The springs of a wide navigation rail (null jumps: reduced motion snaps spatial springs). */
742
+ interface WideNavigationRailSpecs {
743
+ /** WideNavigationRailLayout `animationSpec` (L324): non-modal width, item spacing / min height. */
744
+ readonly width: SpringSpec | null;
745
+ /** `modalAnimationSpec` (L325): the modal window rail's width. */
746
+ readonly modalWidth: SpringSpec | null;
747
+ /** AnimatedNavigationItem `iconPositionProgress` (NavigationItem.kt L488-493). */
748
+ readonly iconPosition: SpringSpec | null;
749
+ /** ModalWideNavigationRail `positionProgress` (L593-598). */
750
+ readonly position: SpringSpec | null;
751
+ /** The modal scrim alpha (L826-831). */
752
+ readonly scrim: SpringSpec | null;
753
+ /** hideOnCollapse: ModalWideNavigationRailState (L732-736). */
754
+ readonly slide: SpringSpec | null;
755
+ }
756
+ /** One frame of a {@link WideNavigationRailAnimation}. */
757
+ interface WideNavigationRailSample {
758
+ /** The items' iconPositionProgress (0 top icon … 1 start icon); expressive springs overshoot. */
759
+ readonly item: number;
760
+ /** The rail's minWidth / widthFullRange progress (0 collapsed … 1 expanded). */
761
+ readonly width: number;
762
+ /** itemVerticalSpacedBy / itemMinHeight progress (0 collapsed … 1 expanded). */
763
+ readonly layout: number;
764
+ /** Modal: the window (scrim + rail in the top layer) is shown. */
765
+ readonly open: boolean;
766
+ /**
767
+ * The `expanded` WideNavigationRailLayout measures with: the target (non-modal); in the modal
768
+ * window `hideOnCollapse || modalExpanded`; false for the collapsed rail of a modal one.
769
+ */
770
+ readonly railExpanded: boolean;
771
+ /** Modal: the scrim alpha, 0…1. */
772
+ readonly scrim: number;
773
+ /** hideOnCollapse: 0 off screen (offset −width) … 1 in place. */
774
+ readonly slide: number;
775
+ /** Any value is still moving. */
776
+ readonly running: boolean;
777
+ }
778
+ interface WideNavigationRailAnimationOptions {
779
+ readonly expanded: boolean;
780
+ /** ModalWideNavigationRail. */
781
+ readonly modal?: boolean;
782
+ /** ModalWideNavigationRail(hideOnCollapse = true): slides in expanded instead of expanding. */
783
+ readonly hideOnCollapse?: boolean;
784
+ /**
785
+ * Visibility threshold of the width spring in progress units: animateDpAsState uses
786
+ * Spring.DefaultDisplacementThreshold (0.01dp) over the width range (default: 0.01 / 264dp).
787
+ */
788
+ readonly widthThreshold?: number;
789
+ /** Likewise for spacing / min height (default: 0.01 / 16dp, the min-height range). */
790
+ readonly layoutThreshold?: number;
791
+ }
792
+ /**
793
+ * WideNavigationRailState plus the animations it drives. `setExpanded` retargets every value from
794
+ * its current value and velocity (Compose `animate*AsState` / `Animatable.animateTo`).
795
+ */
796
+ declare class WideNavigationRailAnimation {
797
+ #private;
798
+ readonly modal: boolean;
799
+ readonly hideOnCollapse: boolean;
800
+ constructor(options: WideNavigationRailAnimationOptions);
801
+ /** WideNavigationRailState.targetValue. */
802
+ get expanded(): boolean;
803
+ get isRunning(): boolean;
804
+ /** expand() / collapse() at `now` (ms). */
805
+ setExpanded(expanded: boolean, specs: WideNavigationRailSpecs, now: number): void;
806
+ /** WideNavigationRailState.snapTo. */
807
+ snapTo(expanded: boolean): void;
808
+ sample(now: number): WideNavigationRailSample;
809
+ }
810
+ /** The dp values WideNavigationRailLayout and AnimatedNavigationItem measure with. */
811
+ interface WideNavigationRailMetrics {
812
+ /** NavigationRailCollapsedTokens.ContainerWidth (96dp). */
813
+ readonly collapsedWidth: number;
814
+ /** NavigationRailExpandedTokens.ContainerWidthMinimum (220dp). */
815
+ readonly expandedMinWidth: number;
816
+ /** NavigationRailExpandedTokens.ContainerWidthMaximum (360dp). */
817
+ readonly expandedMaxWidth: number;
818
+ /** WNRItemHorizontalPadding (20dp). */
819
+ readonly itemHorizontalPadding: number;
820
+ /** NavigationRailBaselineItemTokens.IconSize (24dp). */
821
+ readonly iconSize: number;
822
+ /** NavigationRailHorizontalItemTokens.IconLabelSpace (8dp). */
823
+ readonly iconLabelSpace: number;
824
+ /** Indicator horizontal padding per side, collapsed: (ActiveIndicatorWidth − IconSize) / 2. */
825
+ readonly collapsedIndicatorPadding: number;
826
+ /** Expanded: NavigationRailHorizontalItemTokens.FullWidthLeadingSpace. */
827
+ readonly expandedIndicatorPadding: number;
828
+ }
829
+ /**
830
+ * An item's measured width (placeAnimatedLabelAndIcon, NavigationItem.kt L1119-1133). `content` is
831
+ * the item's start-icon pill width (icon + gap + label + both expanded paddings), or null for an
832
+ * icon-only item (TopIconOrIconOnlyMeasurePolicy: the 56dp circle plus the padding on both sides).
833
+ * `maxWidth` is the rail's item constraint (expanded: rail maximum − item padding).
834
+ */
835
+ declare function wideNavigationRailItemWidth(content: number | null, progress: number, m: WideNavigationRailMetrics, maxWidth: number): number;
836
+ interface WideNavigationRailWidthInput {
837
+ /** `expanded` passed to WideNavigationRailLayout (the state's target, or modalExpanded). */
838
+ readonly expanded: boolean;
839
+ /** minWidth / widthFullRange progress. */
840
+ readonly widthProgress: number;
841
+ /** The items' iconPositionProgress. */
842
+ readonly itemProgress: number;
843
+ /** Each item's start-icon pill width (null: icon only). */
844
+ readonly items: readonly (number | null)[];
845
+ /** The header's width (0 without one). */
846
+ readonly header: number;
847
+ /** The width of the previous frame (`currentWidth`). */
848
+ readonly previousWidth: number;
849
+ /** `actualMaxExpandedWidth > 0`: the rail was wider than its expanded minimum. */
850
+ readonly wide: boolean;
851
+ /** The available width (the rail's maximum when unconstrained). */
852
+ readonly maxWidth?: number;
853
+ readonly metrics: WideNavigationRailMetrics;
854
+ }
855
+ /**
856
+ * WideNavigationRailLayout's measured width (L373-476): expanding, `widthFullRange` up to the
857
+ * widest item (+ padding) or header when that is wider than the expanded minimum, else
858
+ * `minWidth`; collapsing from such a rail, `widthFullRange` kept between `minWidth` and the previous
859
+ * width. Returns the width and whether the rail is now `wide`.
860
+ */
861
+ declare function wideNavigationRailWidth(input: WideNavigationRailWidthInput): {
862
+ width: number;
863
+ wide: boolean;
864
+ };
865
+
866
+ /** NavigationDrawer.kt `DrawerPositionalThreshold` (L1339): a fraction of the sheet width. */
867
+ declare const DRAWER_POSITIONAL_THRESHOLD = 0.5;
868
+ /** NavigationDrawer.kt `DrawerVelocityThreshold` (L1340-1341), in dp (= CSS px) per second. */
869
+ declare const DRAWER_VELOCITY_THRESHOLD = 400;
870
+ /** NavigationDrawer.kt `AnchoredDraggableDefaultAnimationSpec` (L1354): the settle tween. */
871
+ declare const DRAWER_SETTLE_MILLIS = 256;
872
+ /** The springs and settle tween of a drawer (null jumps: reduced motion). */
873
+ interface DrawerSpecs {
874
+ readonly open: SpringSpec | null;
875
+ readonly close: SpringSpec | null;
876
+ /** AnchoredDraggableDefaultAnimationSpec; null (0ms) jumps. */
877
+ readonly settle: {
878
+ readonly duration: number;
879
+ readonly easing: Easing;
880
+ } | null;
881
+ }
882
+ /** FloatExponentialDecaySpec.getTargetValue (L132-141). */
883
+ declare function exponentialDecayTarget(value: number, velocity: number): number;
884
+ /**
885
+ * DraggableAnchors.computeTarget (AnchoredDraggable.kt L1485-1514) for the drawer's two anchors:
886
+ * whether a release at `offset` (px, −width…0) with `velocity` (px/s, positive towards open)
887
+ * settles open. `velocityThreshold` is px/s.
888
+ */
889
+ declare function drawerSettlesOpen(offset: number, velocity: number, width: number, velocityThreshold?: number): boolean;
890
+ /** One frame of a {@link DrawerAnimation}. */
891
+ interface DrawerSample {
892
+ /** Sheet offset in px: −width (closed) … 0 (open); above 0 while an open spring overshoots. */
893
+ readonly offset: number;
894
+ /** calculateFraction(closed, open, offset): 0 closed … 1 open (the scrim alpha). */
895
+ readonly fraction: number;
896
+ /** Something is moving (an animation or a drag). */
897
+ readonly running: boolean;
898
+ /** The sheet is visible (fraction > 0): Compose only places it then. */
899
+ readonly visible: boolean;
900
+ }
901
+ /** DrawerState: the offset, its animations, drags and the settle after a release. */
902
+ declare class DrawerAnimation {
903
+ #private;
904
+ /** @param open initial value (at rest); @param width the sheet width in px. */
905
+ constructor(open: boolean, width: number);
906
+ /** DrawerState.targetValue === Open. */
907
+ get isOpen(): boolean;
908
+ /** DrawerState.currentValue === Open: the last anchor it settled on. */
909
+ get isSettledOpen(): boolean;
910
+ get isDragging(): boolean;
911
+ get width(): number;
912
+ /** Units: px per second, positive towards open (AnchoredDraggableState.lastVelocity). */
913
+ get velocity(): number;
914
+ /** New anchors (the sheet was measured): at rest the offset follows its anchor. */
915
+ setWidth(width: number): void;
916
+ /** Jumps (DrawerState.snapTo). */
917
+ snapTo(open: boolean): void;
918
+ /** DrawerState.open() / close() at `now` (ms): springs from the current offset and velocity. */
919
+ animateTo(open: boolean, specs: DrawerSpecs, now: number): void;
920
+ /** Grabs the sheet (pointer down past the slop): stops any animation where it is. */
921
+ startDrag(now: number): void;
922
+ /** Moves the offset by `delta` px (positive towards open), coerced between the anchors. */
923
+ dragBy(delta: number): void;
924
+ /**
925
+ * Ends a drag with the pointer `velocity` (px/s, positive towards open): picks the target
926
+ * (computeTarget) and settles on it (animateToWithDecay). Returns whether it settles open.
927
+ * `velocityThreshold`: DrawerVelocityThreshold in px/s.
928
+ */
929
+ release(velocity: number, specs: DrawerSpecs, now: number, velocityThreshold?: number, confirm?: (open: boolean) => boolean): boolean;
930
+ /** Advances to `now` (ms). */
931
+ sample(now: number): DrawerSample;
932
+ }
933
+
934
+ /** TabRow.kt L461 / L608: `maxOf(contentWidth, 24.dp)` ("Enforce minimum touch target of 24.dp"). */
935
+ declare const TAB_INDICATOR_MIN_WIDTH = 24;
936
+ type TabRowVariant = 'primary' | 'secondary';
937
+ /** What the caller measures per tab: its laid-out width and its content's width. */
938
+ interface TabMeasure {
939
+ readonly width: number;
940
+ readonly contentWidth: number;
941
+ }
942
+ /** Compose `TabPosition`. */
943
+ interface TabPosition {
944
+ readonly left: number;
945
+ readonly width: number;
946
+ readonly contentWidth: number;
947
+ }
948
+ /** The tabs' positions from `start` (a scrollable row's edge padding; 0 for a fixed row). */
949
+ declare function tabPositions(tabs: readonly TabMeasure[], start?: number, minIndicatorWidth?: number): TabPosition[];
950
+ /** The indicator's target: offset (the tab's left) and width (per variant). */
951
+ declare function tabIndicatorTarget(position: TabPosition, variant: TabRowVariant): {
952
+ offset: number;
953
+ width: number;
954
+ };
955
+ /** One frame of the indicator. */
956
+ interface TabIndicatorSample {
957
+ /** The animated offset (a tab's left edge). */
958
+ readonly offset: number;
959
+ readonly width: number;
960
+ readonly running: boolean;
961
+ }
962
+ /** TabIndicatorOffsetNode: the offset and width Animatables. */
963
+ declare class TabIndicatorAnimation {
964
+ #private;
965
+ /** Starts at rest on the first layout's target (Compose: initialOffset / initialWidth). */
966
+ constructor(offset: number, width: number);
967
+ get offset(): SpringAnimatable;
968
+ get width(): SpringAnimatable;
969
+ get running(): boolean;
970
+ /**
971
+ * Retargets each Animatable whose target changed, from its value and velocity at `now`; a null
972
+ * spec (reduced motion) jumps.
973
+ */
974
+ animateTo(offset: number, width: number, spec: SpringSpec | null, now: number): void;
975
+ snapTo(offset: number, width: number): void;
976
+ sample(now: number): TabIndicatorSample;
977
+ }
978
+ /**
979
+ * The indicator's shift from where the selected tab draws it at rest (centred in the tab), in the
980
+ * row's logical direction: the centre is offset + tab width / 2 in both cases, so the shift is the
981
+ * animated offset less the tab's left.
982
+ */
983
+ declare const tabIndicatorShift: (sample: {
984
+ offset: number;
985
+ }, selected: TabPosition) => number;
986
+ /**
987
+ * ScrollableTabData.calculateTabOffset: the scroll position centring `tab` (its left includes the
988
+ * edge padding) in a row `scrollWidth` wide (edge padding × 2 + the tabs) seen through
989
+ * `visibleWidth`, clamped to the scroll range.
990
+ */
991
+ declare function scrollableTabOffset(tab: Pick<TabPosition, 'left' | 'width'>, scrollWidth: number, visibleWidth: number): number;
992
+ /** animateScrollTo: a Float animation from the current scroll position, from rest. */
993
+ declare class TabScrollAnimation {
994
+ readonly value: SpringAnimatable;
995
+ constructor(position: number);
996
+ /** Starts a new scroll from `from` (the scroll state's value), velocity 0. */
997
+ animateTo(from: number, target: number, spec: SpringSpec | null, now: number): void;
998
+ }
999
+
1000
+ /** ThreePaneScaffoldRole. */
1001
+ type ThreePaneScaffoldRole = 'primary' | 'secondary' | 'tertiary';
1002
+ /** Roles in priority order (forEachPaneByPriority's tail, ThreePaneScaffoldValue.kt L187-189). */
1003
+ declare const THREE_PANE_SCAFFOLD_ROLES: readonly ThreePaneScaffoldRole[];
1004
+ /** AdaptStrategy.Hide, or AdaptStrategy.Reflow(reflowUnder). */
1005
+ type AdaptStrategy = 'hide' | {
1006
+ readonly reflowUnder: ThreePaneScaffoldRole;
1007
+ };
1008
+ type ThreePaneScaffoldAdaptStrategies = Readonly<Record<ThreePaneScaffoldRole, AdaptStrategy>>;
1009
+ /** ListDetailPaneScaffoldDefaults.adaptStrategies() (L208-217): every pane hides. */
1010
+ declare const LIST_DETAIL_ADAPT_STRATEGIES: ThreePaneScaffoldAdaptStrategies;
1011
+ /**
1012
+ * SupportingPaneScaffoldDefaults.adaptStrategies() (L190-200): the supporting pane reflows under
1013
+ * the main pane; the others hide.
1014
+ */
1015
+ declare const SUPPORTING_PANE_ADAPT_STRATEGIES: ThreePaneScaffoldAdaptStrategies;
1016
+ /** ListDetailPaneScaffoldRole (ListDetailPaneScaffold.kt L238-259). */
1017
+ declare const ListDetailPaneScaffoldRole: Readonly<{
1018
+ readonly List: "secondary";
1019
+ readonly Detail: "primary";
1020
+ readonly Extra: "tertiary";
1021
+ }>;
1022
+ /** SupportingPaneScaffoldRole (SupportingPaneScaffold.kt L221-243). */
1023
+ declare const SupportingPaneScaffoldRole: Readonly<{
1024
+ readonly Main: "primary";
1025
+ readonly Supporting: "secondary";
1026
+ readonly Extra: "tertiary";
1027
+ }>;
1028
+ /** Start-to-end order: list (secondary), detail (primary), extra (ListDetailPaneScaffold L224-229). */
1029
+ declare const LIST_DETAIL_PANE_ORDER: readonly ThreePaneScaffoldRole[];
1030
+ /** Start-to-end order: main, supporting, extra (SupportingPaneScaffold L207-212). */
1031
+ declare const SUPPORTING_PANE_ORDER: readonly ThreePaneScaffoldRole[];
1032
+ /** PaneAdaptedValue (Levitated is not ported). */
1033
+ type PaneAdaptedValue = 'expanded' | 'reflowed' | 'hidden';
1034
+ /** ThreePaneScaffoldValue. */
1035
+ interface ThreePaneScaffoldValue {
1036
+ readonly primary: PaneAdaptedValue;
1037
+ readonly secondary: PaneAdaptedValue;
1038
+ readonly tertiary: PaneAdaptedValue;
1039
+ /** The destination the value was calculated for (internal in Compose; not part of equality). */
1040
+ readonly currentDestination: ThreePaneScaffoldRole | null;
1041
+ }
1042
+ /** ThreePaneScaffoldValue.equals (L260-267): the three adapted values. */
1043
+ declare function sameThreePaneScaffoldValue(a: ThreePaneScaffoldValue, b: ThreePaneScaffoldValue): boolean;
1044
+ /** ThreePaneScaffoldDestinationItem. */
1045
+ interface ThreePaneScaffoldDestinationItem<T = unknown> {
1046
+ readonly pane: ThreePaneScaffoldRole;
1047
+ readonly contentKey?: T | undefined;
1048
+ }
1049
+ /**
1050
+ * calculateThreePaneScaffoldValue (ThreePaneScaffoldValue.kt L86-179): the last destination
1051
+ * first, then the earlier ones (newest first), then primary, secondary, tertiary each take a free
1052
+ * horizontal partition; with a single partition and `maxVerticalPartitions` ≥ 2, the first pane
1053
+ * whose strategy is Reflow goes under its (expanded) anchor instead.
1054
+ */
1055
+ declare function calculateThreePaneScaffoldValue(maxHorizontalPartitions: number, adaptStrategies: ThreePaneScaffoldAdaptStrategies, destinationHistory: readonly ThreePaneScaffoldDestinationItem[], maxVerticalPartitions?: number): ThreePaneScaffoldValue;
1056
+ /** The roles a value expands, in `order` (start to end). */
1057
+ declare function expandedPanes(value: ThreePaneScaffoldValue, order: readonly ThreePaneScaffoldRole[]): ThreePaneScaffoldRole[];
1058
+ /**
1059
+ * How many panes may sit side by side: `recommended` (the default, owner decision 2026-10-18) =
1060
+ * m3.material.io Breakpoints (1 / 1 / 2 / 2 / 3: two panes at large, three at extra-large), never
1061
+ * more than Compose allows; `compose` = calculatePaneScaffoldDirective (1 / 1 / 2 / 3 / 3 by width
1062
+ * class: three panes from large).
1063
+ */
1064
+ type PaneRule = 'compose' | 'recommended';
1065
+ /** m3.material.io Foundations › Layout › Breakpoints, "recommended" pane counts (FOUNDATIONS §9). */
1066
+ declare const RECOMMENDED_MAX_PANES: Readonly<Record<WindowWidthSizeClass, number>>;
1067
+ interface ThreePaneScaffoldDirectiveOptions {
1068
+ /** Default `recommended`; `compose` keeps calculatePaneScaffoldDirective's counts. */
1069
+ paneRule?: PaneRule | undefined;
1070
+ isTabletop?: boolean | undefined;
1071
+ }
1072
+ /**
1073
+ * paneScaffoldDirective (calculatePaneScaffoldDirective) with the `paneRule` cap applied: capped by
1074
+ * RECOMMENDED_MAX_PANES unless `paneRule` is `compose`.
1075
+ */
1076
+ declare function threePaneScaffoldDirective(sizeClass: WindowSizeClass, options?: ThreePaneScaffoldDirectiveOptions): PaneScaffoldDirective;
1077
+ /** BackNavigationBehavior (BackNavigationBehavior.kt L40-75). */
1078
+ type BackNavigationBehavior = 'pop-latest' | 'pop-until-scaffold-value-change' | 'pop-until-current-destination-change' | 'pop-until-content-change';
1079
+ interface ThreePaneScaffoldNavigatorOptions<T> {
1080
+ scaffoldDirective: PaneScaffoldDirective;
1081
+ adaptStrategies: ThreePaneScaffoldAdaptStrategies;
1082
+ /** Default `true` (rememberListDetailPaneScaffoldNavigator). */
1083
+ isDestinationHistoryAware?: boolean | undefined;
1084
+ /** Default: the list pane (list-detail) or main pane (supporting pane); see the defaults below. */
1085
+ initialDestinationHistory: readonly ThreePaneScaffoldDestinationItem<T>[];
1086
+ }
1087
+ /** DefaultListDetailPaneHistory (ThreePaneScaffoldNavigator.kt L536-537): the list. */
1088
+ declare const LIST_DETAIL_INITIAL_HISTORY: readonly ThreePaneScaffoldDestinationItem<never>[];
1089
+ /** DefaultSupportingPaneHistory (L540-541): the main pane. */
1090
+ declare const SUPPORTING_PANE_INITIAL_HISTORY: readonly ThreePaneScaffoldDestinationItem<never>[];
1091
+ /**
1092
+ * DefaultThreePaneScaffoldNavigator (ThreePaneScaffoldNavigator.kt L359-490) without Compose's
1093
+ * transition state: navigateTo / navigateBack change the history and the value at once; the
1094
+ * caller animates (and Compose's directive change snaps, L349-354: so does setting
1095
+ * `scaffoldDirective` here). Content keys compare with Object.is (Kotlin `equals` for data
1096
+ * classes: use primitives or shared objects).
1097
+ */
1098
+ declare class ThreePaneScaffoldNavigator<T = unknown> {
1099
+ #private;
1100
+ constructor(options: ThreePaneScaffoldNavigatorOptions<T>);
1101
+ get scaffoldDirective(): PaneScaffoldDirective;
1102
+ set scaffoldDirective(directive: PaneScaffoldDirective);
1103
+ get adaptStrategies(): ThreePaneScaffoldAdaptStrategies;
1104
+ set adaptStrategies(strategies: ThreePaneScaffoldAdaptStrategies);
1105
+ get isDestinationHistoryAware(): boolean;
1106
+ set isDestinationHistoryAware(aware: boolean);
1107
+ /** The destination history, oldest first. */
1108
+ get destinationHistory(): readonly ThreePaneScaffoldDestinationItem<T>[];
1109
+ get currentDestination(): ThreePaneScaffoldDestinationItem<T> | null;
1110
+ get scaffoldValue(): ThreePaneScaffoldValue;
1111
+ /** Calls `listener` after every change of the history or the value; returns the unsubscriber. */
1112
+ subscribe(listener: () => void): () => void;
1113
+ peekPreviousScaffoldValue(behavior?: BackNavigationBehavior): ThreePaneScaffoldValue;
1114
+ navigateTo(pane: ThreePaneScaffoldRole, contentKey?: T): void;
1115
+ canNavigateBack(behavior?: BackNavigationBehavior): boolean;
1116
+ /** Returns true when there was a destination to go back to (else the history is cleared). */
1117
+ navigateBack(behavior?: BackNavigationBehavior): boolean;
1118
+ }
1119
+ /** A pane's bounds in the scaffold, CSS px, physical (x from the left edge). */
1120
+ interface PaneRect {
1121
+ readonly x: number;
1122
+ readonly y: number;
1123
+ readonly width: number;
1124
+ readonly height: number;
1125
+ }
1126
+ /** PaneExpansionState as the layout reads it (all CSS px). */
1127
+ interface PaneExpansionLayout {
1128
+ /** currentDraggingOffset: the handle's centre while dragging or settling. */
1129
+ readonly draggingOffset?: number | undefined;
1130
+ /** firstPaneWidth: a resting split (set from an anchor or a released drag). */
1131
+ readonly firstPaneWidth?: number | undefined;
1132
+ }
1133
+ interface ThreePaneScaffoldLayoutInput {
1134
+ readonly width: number;
1135
+ readonly height: number;
1136
+ readonly directive: PaneScaffoldDirective;
1137
+ readonly value: ThreePaneScaffoldValue;
1138
+ /** Start to end, already mirrored for RTL (physical left to right). */
1139
+ readonly order: readonly ThreePaneScaffoldRole[];
1140
+ readonly adaptStrategies: ThreePaneScaffoldAdaptStrategies;
1141
+ /** Panes that exist (a scaffold without an extra pane has no tertiary pane). Default: all. */
1142
+ readonly present?: readonly ThreePaneScaffoldRole[] | undefined;
1143
+ /** PaneScaffoldScope.preferredWidth per pane (px); default the directive's. */
1144
+ readonly preferredWidths?: Partial<Record<ThreePaneScaffoldRole, number>> | undefined;
1145
+ /** PaneScaffoldScope.preferredHeight per pane (px); default the directive's. */
1146
+ readonly preferredHeights?: Partial<Record<ThreePaneScaffoldRole, number>> | undefined;
1147
+ readonly expansion?: PaneExpansionLayout | undefined;
1148
+ }
1149
+ interface ThreePaneScaffoldLayout {
1150
+ /** Bounds of the expanded and reflowed panes (a collapsed pane of a split has width 0). */
1151
+ readonly panes: Partial<Record<ThreePaneScaffoldRole, PaneRect>>;
1152
+ /** The drag handle's centre x when exactly two panes are expanded, else null. */
1153
+ readonly handleOffset: number | null;
1154
+ }
1155
+ /** ThreePaneContentMeasurePolicy.measure (ThreePaneScaffold.kt L256-594), no hinges. */
1156
+ declare function threePaneScaffoldLayout(input: ThreePaneScaffoldLayoutInput): ThreePaneScaffoldLayout;
1157
+ /** PaneMotion (PaneMotion.kt L556-632; EnterAsModal / ExitAsModal belong to Levitate). */
1158
+ type PaneMotion = 'none' | 'animate-bounds' | 'enter-from-left' | 'enter-from-right' | 'enter-from-left-delayed' | 'enter-from-right-delayed' | 'exit-to-left' | 'exit-to-right' | 'enter-with-expand' | 'exit-with-shrink';
1159
+ /** calculatePaneMotion (PaneMotion.kt L636-750) for the panes in `order` (physical, LTR). */
1160
+ declare function calculatePaneMotion(previous: ThreePaneScaffoldValue, current: ThreePaneScaffoldValue, order: readonly ThreePaneScaffoldRole[]): Record<ThreePaneScaffoldRole, PaneMotion>;
1161
+ /** Where each pane animates from and to for a motion (the default enter / exit transitions). */
1162
+ interface PaneTransition {
1163
+ readonly motion: PaneMotion;
1164
+ readonly from: PaneRect;
1165
+ readonly to: PaneRect;
1166
+ /** EnterFrom*Delayed: DelayedSpringSpec's delayedRatio (PaneMotionDefaults L167-173). */
1167
+ readonly delayed: boolean;
1168
+ }
1169
+ /** PaneMotionDefaults.DelayedAnimationSpec's delayedRatio (PaneMotion.kt L171). */
1170
+ declare const PANE_MOTION_DELAYED_RATIO = 0.1;
1171
+ /**
1172
+ * calculateDefaultEnterTransition / calculateDefaultExitTransition (PaneMotion.kt L425-476) with
1173
+ * the slide offsets (L276-414): `origin` holds the bounds before the change (the panes shown
1174
+ * then), `target` the bounds after it, both from threePaneScaffoldLayout. Entering panes slide (or
1175
+ * expand) from outside to `target`; exiting panes slide (or shrink) from `origin` out; panes shown
1176
+ * before and after animate their bounds.
1177
+ */
1178
+ declare function paneTransitions(motions: Readonly<Record<ThreePaneScaffoldRole, PaneMotion>>, order: readonly ThreePaneScaffoldRole[], origin: Partial<Record<ThreePaneScaffoldRole, PaneRect>>, target: Partial<Record<ThreePaneScaffoldRole, PaneRect>>, scaffoldWidth: number): Partial<Record<ThreePaneScaffoldRole, PaneTransition>>;
1179
+ /** PaneExpansionAnchor: Proportion, Offset.fromStart or Offset.fromEnd (px). */
1180
+ type PaneExpansionAnchor = {
1181
+ readonly proportion: number;
1182
+ } | {
1183
+ readonly offsetFromStart: number;
1184
+ } | {
1185
+ readonly offsetFromEnd: number;
1186
+ };
1187
+ /**
1188
+ * The samples' anchors (ThreePaneScaffoldSample.kt L1102-1109): 0 %, 240dp from the start, 50 %,
1189
+ * 240dp from the end, 100 %. Compose's own default is no anchors.
1190
+ */
1191
+ declare const PANE_EXPANSION_SAMPLE_ANCHORS: readonly PaneExpansionAnchor[];
1192
+ /** PaneExpansionState.AnchoringVelocityThreshold (px/s, L648). */
1193
+ declare const PANE_EXPANSION_ANCHORING_VELOCITY_THRESHOLD = 200;
1194
+ /** PaneExpansionAnchor.positionIn (L700-712, L754-755, L835-856): the handle's centre x. */
1195
+ declare function paneExpansionAnchorPosition(anchor: PaneExpansionAnchor, width: number, rtl?: boolean): number;
1196
+ /**
1197
+ * The anchor a release settles to (getPositionOfTheClosestAnchor, L610-646): the closest one, or
1198
+ * with |velocity| ≥ 200 px/s the closest in the direction of the fling (the closest overall when
1199
+ * none lies that way). Returns the index into `anchors`, or -1 without anchors. Compose first runs
1200
+ * the fling's decay and settles from where it stops; this picks from the release position.
1201
+ */
1202
+ declare function closestPaneExpansionAnchor(anchors: readonly PaneExpansionAnchor[], width: number, position: number, velocity: number, rtl?: boolean): number;
1203
+ /**
1204
+ * PaneExpansionState.nextAnchor (L345-366): the first anchor (by position) right of `position`,
1205
+ * wrapping to the leftmost. The drag handle's click action moves there. -1 without anchors.
1206
+ */
1207
+ declare function nextPaneExpansionAnchor(anchors: readonly PaneExpansionAnchor[], width: number, position: number, rtl?: boolean): number;
1208
+ /** PaneMotionDefaults' IntRect / IntOffset visibility threshold (PaneMotion.kt L148): 1px. */
1209
+ declare const PANE_MOTION_VISIBILITY_THRESHOLD = 1;
1210
+ interface ThreePaneScaffoldSample {
1211
+ /** The animated bounds of every pane in the transition (entering, shown, exiting). */
1212
+ readonly panes: Partial<Record<ThreePaneScaffoldRole, PaneRect>>;
1213
+ readonly running: boolean;
1214
+ }
1215
+ /**
1216
+ * The pane transitions of one scaffold change, driven by the caller's clock (ms): each pane's
1217
+ * bounds run on PaneMotionDefaults.AnimationSpec (spring 0.8 / 380 at a 1px threshold, each
1218
+ * component on its own, as Compose's IntRect / IntOffset springs), EnterFrom*Delayed after 10 % of
1219
+ * that spring's duration (DelayedSpringSpec, PaneMotion.kt L822-908). A new `start` mid-flight
1220
+ * continues every pane still in the transition from its current bounds and velocity. `spec` null
1221
+ * (reduced motion) jumps to the end.
1222
+ */
1223
+ declare class ThreePaneScaffoldAnimation {
1224
+ #private;
1225
+ start(transitions: Partial<Record<ThreePaneScaffoldRole, PaneTransition>>, spec: SpringSpec | null, now: number): void;
1226
+ /** Jumps every pane to its target. */
1227
+ finish(): void;
1228
+ sample(now: number): ThreePaneScaffoldSample;
1229
+ }
1230
+
1231
+ export { type AdaptStrategy, AmplitudeAnimation, type AmplitudeTween, type AppBarScrollBehavior, type AppBarScrollState, type BackNavigationBehavior, type ButtonGroupItemSize, type CircularIndeterminateFrame, type CircularIndeterminateTiming, DEFAULT_DISPLACEMENT_THRESHOLD, DRAWER_POSITIONAL_THRESHOLD, DRAWER_SETTLE_MILLIS, DRAWER_VELOCITY_THRESHOLD, DrawerAnimation, type DrawerSample, type DrawerSpecs, type Easing, FAST_OUT_LINEAR_IN_EASING, type FloatingToolbarExitDirection, type FloatingToolbarScrollState, type IndeterminateFrame, LIST_DETAIL_ADAPT_STRATEGIES, LIST_DETAIL_INITIAL_HISTORY, LIST_DETAIL_PANE_ORDER, type LinearEasing, type LinearEasingOptions, type LinearIndeterminateTiming, ListDetailPaneScaffoldRole, type LoadingIndicatorTiming, MODAL_RAIL_EXPANDED_PROGRESS, type MenuAnchorPosition, type MenuPositionInput, type MenuPositionResult, type MenuRect, type Motion, NAVIGATION_SUITE_EXPANDED_FROM, NAVIGATION_SUITE_TYPES, type NavigationSuiteSample, NavigationSuiteScaffoldAnimation, type NavigationSuiteType, type NavigationSuiteTypeOptions, PANE_EXPANSION_ANCHORING_VELOCITY_THRESHOLD, PANE_EXPANSION_SAMPLE_ANCHORS, PANE_MOTION_DELAYED_RATIO, PANE_MOTION_VISIBILITY_THRESHOLD, type PaneAdaptedValue, type PaneExpansionAnchor, type PaneExpansionLayout, type PaneMotion, type PaneRect, type PaneRule, type PaneScaffoldDirective, type PaneTransition, RECOMMENDED_MAX_PANES, SEARCH_BAR_EXPANDED_THRESHOLD, SEARCH_DROPDOWN_VISIBLE_PROGRESS, SUPPORTING_PANE_ADAPT_STRATEGIES, SUPPORTING_PANE_INITIAL_HISTORY, SUPPORTING_PANE_ORDER, SearchBarAnimation, type SearchBarSample, type SearchBarSpecs, type SearchRect, type SearchViewFrame, type SearchViewInput, type SearchViewMetrics, type SearchViewVariant, SpringAnimatable, SpringSimulation, type SpringSpec, SupportingPaneScaffoldRole, TAB_INDICATOR_MIN_WIDTH, THREE_PANE_SCAFFOLD_ROLES, TOP_TITLE_ALPHA_EASING, TabIndicatorAnimation, type TabIndicatorSample, type TabMeasure, type TabPosition, type TabRowVariant, TabScrollAnimation, type ThreePaneScaffoldAdaptStrategies, ThreePaneScaffoldAnimation, type ThreePaneScaffoldDestinationItem, type ThreePaneScaffoldDirectiveOptions, type ThreePaneScaffoldLayout, type ThreePaneScaffoldLayoutInput, ThreePaneScaffoldNavigator, type ThreePaneScaffoldNavigatorOptions, type ThreePaneScaffoldRole, type ThreePaneScaffoldSample, type ThreePaneScaffoldValue, type ToolbarExpansionScroll, type ToolbarOrientation, TweenAnimatable, type TweenSpec, type TwoRowsFrame, WINDOW_HEIGHT_BREAKPOINTS, WINDOW_WIDTH_BREAKPOINTS, WideNavigationRailAnimation, type WideNavigationRailAnimationOptions, type WideNavigationRailMetrics, type WideNavigationRailSample, type WideNavigationRailSpecs, type WideNavigationRailWidthInput, type WindowHeightSizeClass, type WindowPostureOptions, type WindowSizeClass, type WindowSizeClassOptions, type WindowWidthSizeClass, animatedInt, appBarScrollState, buttonGroupVisibleCount, buttonGroupWidths, calculatePaneMotion, calculateThreePaneScaffoldValue, circularIndeterminateFrame, closestPaneExpansionAnchor, collapsedFraction, cubicBezier, dampingCoefficient, dampingRatioFromCoefficient, drawerSettlesOpen, estimateAnimationDurationMillis, estimateAnimationDurationMillisDouble, expandedPanes, exponentialDecayTarget, fabMenuItemVisible, floatingToolbarScrollState, indeterminateFrame, indicatorAmplitude, initialIndeterminateFrame, isAtLeastBreakpoint, isHeightAtLeastBreakpoint, isNavigationBarType, isScrolledUnder, isWidthAtLeastBreakpoint, linearIndeterminateFractions, menuNavigationTarget, menuPosition, menuTransformOrigin, morphSpringDurationMillis, navigationSuiteOffset, navigationSuiteType, nextPaneExpansionAnchor, overlappedFraction, paneExpansionAnchorPosition, paneScaffoldDirective, paneTransitions, parseCubicBezier, sameThreePaneScaffoldValue, sameWindowSizeClass, scrollAppBar, scrollFloatingToolbar, scrollToolbarExpansion, scrollableTabOffset, searchNavigationTarget, searchViewFrame, settleTarget, springDurationMillis, springToLinear, springValue, springVelocity, tabIndicatorShift, tabIndicatorTarget, tabPositions, threePaneScaffoldDirective, threePaneScaffoldLayout, toolbarCollapsedFraction, toolbarExpansionScroll, toolbarNavigationTarget, toolbarSettleTarget, twoRowsFrame, waveOffset, waveTravelMillis, wideNavigationRailItemWidth, wideNavigationRailWidth, windowHeightSizeClass, windowSizeClass, windowWidthSizeClass, withHeight, withHeightOffset, withToolbarOffset, withToolbarOffsetLimit };