@kyralabs/m3e-motion 1.3.0 → 1.4.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
@@ -75,6 +75,142 @@ declare const fabMenuItemVisible: (index: number, itemCount: number, stagger: nu
75
75
  */
76
76
  declare function menuNavigationTarget(key: string, count: number, current: number): number | null;
77
77
 
78
+ type ToolbarOrientation = 'horizontal' | 'vertical';
79
+ /**
80
+ * The item index `key` moves focus to from `current` (−1: none focused) among `count` items, or
81
+ * null when the key does not navigate. At either end the index stays put (no wrapping).
82
+ */
83
+ declare function toolbarNavigationTarget(key: string, count: number, current: number, orientation?: ToolbarOrientation, rtl?: boolean): number | null;
84
+
85
+ /** Where a floating toolbar leaves the screen (FloatingToolbarExitDirection), logical. */
86
+ type FloatingToolbarExitDirection = 'bottom' | 'top' | 'start' | 'end';
87
+ interface FloatingToolbarScrollState {
88
+ /** Most negative offset: minus the distance that takes the toolbar off its container. */
89
+ readonly offsetLimit: number;
90
+ /** Current offset, between offsetLimit and 0. */
91
+ readonly offset: number;
92
+ /** Total content scrolled under the toolbar (sum of the deltas). */
93
+ readonly contentOffset: number;
94
+ }
95
+ /** rememberFloatingToolbarState() defaults: no limit known yet, fully shown. */
96
+ declare function floatingToolbarScrollState(offsetLimit?: number, offset?: number, contentOffset?: number): FloatingToolbarScrollState;
97
+ /** FloatingToolbarState.offset setter: coerced between offsetLimit and 0. */
98
+ declare function withToolbarOffset(state: FloatingToolbarScrollState, offset: number): FloatingToolbarScrollState;
99
+ /**
100
+ * The offset limit from the toolbar's layout (onGloballyPositioned): `distance` is how far the
101
+ * toolbar must travel along its exit direction to leave its container, i.e. its size plus its gap
102
+ * to that edge, measured without the current offset. The offset stays in range.
103
+ */
104
+ declare function withToolbarOffsetLimit(state: FloatingToolbarScrollState, distance: number): FloatingToolbarScrollState;
105
+ /** exitAlways onPostScroll: the content offset and the toolbar offset both move by `delta`. */
106
+ declare function scrollFloatingToolbar(state: FloatingToolbarScrollState, delta: number): FloatingToolbarScrollState;
107
+ /** 0 = fully shown, 1 = fully hidden (FloatingToolbarState.collapsedFraction()). */
108
+ declare function toolbarCollapsedFraction(state: FloatingToolbarScrollState): number;
109
+ /**
110
+ * Where a partly hidden toolbar snaps when scrolling stops (settleFloatingToolbar): shown below
111
+ * half, hidden from half, or null when it is already (within 1%) settled. The decision is the
112
+ * same as the top app bar's settleAppBar, so it reuses that port.
113
+ */
114
+ declare function toolbarSettleTarget(state: FloatingToolbarScrollState): number | null;
115
+ /**
116
+ * floatingToolbarVerticalNestedScroll: collapses the toolbar after scrolling down by the collapse
117
+ * threshold and expands it after scrolling up by the expand threshold (both
118
+ * FloatingToolbarDefaults.ScrollDistanceThreshold by default).
119
+ */
120
+ interface ToolbarExpansionScroll {
121
+ readonly contentOffset: number;
122
+ /** The content offset that triggers the next change. */
123
+ readonly threshold: number;
124
+ }
125
+ /** A tracker for a toolbar that is `expanded` (updateThreshold). */
126
+ declare function toolbarExpansionScroll(expanded: boolean, collapseThreshold: number, expandThreshold: number, contentOffset?: number): ToolbarExpansionScroll;
127
+ /**
128
+ * onPostScroll: moves the content offset by `delta`; returns the new tracker and `'collapse'` /
129
+ * `'expand'` when a threshold was crossed (Compose calls onCollapse / onExpand then).
130
+ */
131
+ declare function scrollToolbarExpansion(state: ToolbarExpansionScroll, delta: number, collapseThreshold: number, expandThreshold: number): {
132
+ state: ToolbarExpansionScroll;
133
+ change: 'collapse' | 'expand' | null;
134
+ };
135
+
136
+ type Easing = (fraction: number) => number;
137
+ /** `cubic-bezier(a, b, c, d)` as an easing function. */
138
+ declare const cubicBezier: (a: number, b: number, c: number, d: number) => Easing;
139
+ /** Parses a resolved CSS `cubic-bezier(a, b, c, d)` (e.g. a motion easing token); null otherwise. */
140
+ declare function parseCubicBezier(css: string): Easing | null;
141
+
142
+ interface LinearIndeterminateTiming {
143
+ /** `LinearAnimationDuration`: one cycle. */
144
+ readonly durationMillis: number;
145
+ /** `[delay, duration]` of each keyframe pair. */
146
+ readonly firstHead: readonly [number, number];
147
+ readonly firstTail: readonly [number, number];
148
+ readonly secondHead: readonly [number, number];
149
+ readonly secondTail: readonly [number, number];
150
+ /** `LinearIndeterminateProgressEasing`. */
151
+ readonly easing: Easing;
152
+ }
153
+ /**
154
+ * The indeterminate linear indicator's fractions at `elapsedMillis`, in the order the wavy indicator
155
+ * draws them (`getProgressFractions`): first tail, first head, second tail, second head (0–1 each).
156
+ */
157
+ declare function linearIndeterminateFractions(elapsedMillis: number, timing: LinearIndeterminateTiming): [number, number, number, number];
158
+ interface CircularIndeterminateTiming {
159
+ /** `CircularAnimationProgressDuration`: one cycle. */
160
+ readonly durationMillis: number;
161
+ /** `CircularGlobalRotationDegreesTarget`: linear rotation per cycle (degrees). */
162
+ readonly rotation: number;
163
+ /** `CircularAdditionalRotationDegreesTarget`: the steps' total per cycle (degrees). */
164
+ readonly additionalRotation: number;
165
+ /** `CircularAnimationAdditionalRotationDelay`: a step starts every this. */
166
+ readonly additionalDelayMillis: number;
167
+ /** `CircularAnimationAdditionalRotationDuration`: and moves for this. */
168
+ readonly additionalDurationMillis: number;
169
+ /** `CircularIndeterminateMinProgress` / `MaxProgress`: the sweep range (0–1). */
170
+ readonly minProgress: number;
171
+ readonly maxProgress: number;
172
+ /** `CircularProgressEasing`: the shrinking half of the sweep. */
173
+ readonly easing: Easing;
174
+ }
175
+ interface CircularIndeterminateFrame {
176
+ /** Global + additional rotation, degrees clockwise. */
177
+ rotation: number;
178
+ /** Sweep, 0–1 of a full turn. */
179
+ sweep: number;
180
+ }
181
+ /** The indeterminate circular indicator at `elapsedMillis`. */
182
+ declare function circularIndeterminateFrame(elapsedMillis: number, timing: CircularIndeterminateTiming): CircularIndeterminateFrame;
183
+ /**
184
+ * The wave offset tween's duration: `((wavelength / waveSpeed) * 1000 * vertexCount)` rounded and
185
+ * floored at `minMillis`; `Infinity` (the offset holds at 0) when either is not positive.
186
+ */
187
+ declare function waveTravelMillis(wavelength: number, waveSpeed: number, minMillis: number, vertexCount?: number): number;
188
+ /** The wave offset (0–1) after `elapsedMillis` of a tween of `travelMillis`. */
189
+ declare const waveOffset: (elapsedMillis: number, travelMillis: number) => number;
190
+ /** `WavyProgressIndicatorDefaults.indicatorAmplitude`: no wave near the start and the end. */
191
+ declare const indicatorAmplitude: (progress: number, minProgress: number, maxProgress: number) => number;
192
+ interface AmplitudeTween {
193
+ readonly durationMillis: number;
194
+ readonly easing: Easing;
195
+ }
196
+ /**
197
+ * The amplitude Animatable of the wavy modifiers: starts at its first target without animating;
198
+ * a new target tweens with `increase` or `decrease` (by direction), but only once the running
199
+ * tween has finished (`amplitudeAnimationJob == null || isCompleted`); a target set meanwhile is
200
+ * ignored, as in Compose, until the next `update` after it finishes.
201
+ */
202
+ declare class AmplitudeAnimation {
203
+ #private;
204
+ constructor(initial: number);
205
+ get value(): number;
206
+ get target(): number;
207
+ get isRunning(): boolean;
208
+ /** Advances to `now` (ms). */
209
+ sample(now: number): number;
210
+ /** Requests `target` at `now`; returns true when a tween started. */
211
+ update(target: number, now: number, increase: AmplitudeTween, decrease: AmplitudeTween): boolean;
212
+ }
213
+
78
214
  interface LoadingIndicatorTiming {
79
215
  /** `MorphIntervalMillis`: how often a morph starts. */
80
216
  readonly morphIntervalMillis: number;
@@ -210,7 +346,7 @@ declare function menuTransformOrigin(anchor: MenuRect, menu: MenuRect): {
210
346
  declare function menuPosition(input: MenuPositionInput): MenuPositionResult;
211
347
 
212
348
  /** How the bar reacts to its scroll container (TopAppBarDefaults.*ScrollBehavior). */
213
- type AppBarScrollBehavior = 'pinned' | 'enter-always';
349
+ type AppBarScrollBehavior = 'pinned' | 'enter-always' | 'exit-until-collapsed';
214
350
  interface AppBarScrollState {
215
351
  /** Most negative height offset: minus the bar's full height (adjustHeightOffsetLimit). */
216
352
  readonly heightOffsetLimit: number;
@@ -242,6 +378,13 @@ declare function isScrolledUnder(state: AppBarScrollState): boolean;
242
378
  * - pinned: only the content offset moves (PinnedScrollBehavior.onPostScroll).
243
379
  * - enter-always: the bar also collapses/expands by the same amount
244
380
  * (EnterAlwaysScrollBehavior.onPreScroll: `heightOffset += available.y`).
381
+ * - exit-until-collapsed: scrolling down collapses the bar by the same amount
382
+ * (ExitUntilCollapsedScrollBehavior.onPreScroll); scrolling up expands it only by what the
383
+ * content cannot take (onPostScroll: `heightOffset += available.y` once the content is at its
384
+ * start). On the web the content scrolls by the whole delta, so the part of an upward scroll
385
+ * that lies within the collapsed distance of the top (scroll position below -heightOffset) is
386
+ * the part Compose hands to the bar: the bar is fully expanded when the content reaches its
387
+ * start, and a bar that collapsed together with the content stays attached to it.
245
388
  */
246
389
  declare function scrollAppBar(state: AppBarScrollState, behavior: AppBarScrollBehavior, scrollTop: number, delta: number): AppBarScrollState;
247
390
  /**
@@ -249,6 +392,177 @@ declare function scrollAppBar(state: AppBarScrollState, behavior: AppBarScrollBe
249
392
  * half, fully collapsed from half, or null when it is already (within 1%) settled.
250
393
  */
251
394
  declare function settleTarget(state: AppBarScrollState): number | null;
395
+ /** TopTitleAlphaEasing (AppBar.kt L3604): CubicBezierEasing(.8f, 0f, .8f, .15f). */
396
+ declare const TOP_TITLE_ALPHA_EASING: readonly [0.8, 0, 0.8, 0.15];
397
+ /** FastOutLinearInEasing (Easing.kt L66): CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f). */
398
+ declare const FAST_OUT_LINEAR_IN_EASING: readonly [0.4, 0, 1, 1];
399
+ /** What a two-rows bar (medium / large flexible, TwoRowsTopAppBar) draws at a collapsed fraction. */
400
+ interface TwoRowsFrame {
401
+ /** Alpha of the collapsed (top row) title and subtitle: TopTitleAlphaEasing(fraction). */
402
+ readonly collapsedTitleAlpha: number;
403
+ /** Alpha of the expanded (bottom row) title and subtitle: 1 - fraction. */
404
+ readonly expandedTitleAlpha: number;
405
+ /** Container → scrolled container color mix (TopAppBarColors.containerColor): FastOutLinearIn. */
406
+ readonly containerColorFraction: number;
407
+ /** Below 0.5 the collapsed title is hidden from accessibility, from 0.5 the expanded one. */
408
+ readonly collapsedTitleHidden: boolean;
409
+ }
410
+ /** TwoRowsTopAppBar (L2818-2836): the color, both title alphas and semantics follow the fraction. */
411
+ declare function twoRowsFrame(fraction: number): TwoRowsFrame;
412
+
413
+ /** SearchBarState.currentValue is Expanded above this (L1535, "tolerance for spring anim"). */
414
+ declare const SEARCH_BAR_EXPANDED_THRESHOLD = 0.02;
415
+ /** ExpandedDockedSearchBarWithGap shows its results once progress passes this (L3667). */
416
+ declare const SEARCH_DROPDOWN_VISIBLE_PROGRESS = 0.1;
417
+ /** A Compose `tween(durationMillis, delayMillis, easing)`. */
418
+ interface TweenSpec {
419
+ readonly duration: number;
420
+ readonly delay: number;
421
+ readonly easing: Easing;
422
+ }
423
+ /**
424
+ * A float with Compose `Animatable.animateTo(tween)` semantics: each target starts a tween from the
425
+ * current value (velocity is not carried), held for `delay`, then eased over `duration`. A null
426
+ * spec is Compose's `snap()`: the value jumps.
427
+ */
428
+ declare class TweenAnimatable {
429
+ #private;
430
+ constructor(value: number);
431
+ get value(): number;
432
+ get target(): number;
433
+ get isRunning(): boolean;
434
+ snapTo(value: number): void;
435
+ animateTo(target: number, spec: TweenSpec | null, now: number): void;
436
+ sample(now: number): number;
437
+ }
438
+ /** The four animation specs of a SearchBarState (null springs / tweens jump, as `snap()`). */
439
+ interface SearchBarSpecs {
440
+ readonly expand: SpringSpec | null;
441
+ readonly collapse: SpringSpec | null;
442
+ readonly contentFadeIn: TweenSpec | null;
443
+ readonly contentFadeOut: TweenSpec | null;
444
+ }
445
+ /** One sampled frame of a {@link SearchBarAnimation}. */
446
+ interface SearchBarSample {
447
+ /** `animatable.value`: may overshoot 1 (expressive spatial springs). */
448
+ readonly value: number;
449
+ /** `progress`: the value clamped to [0, 1]. */
450
+ readonly progress: number;
451
+ /** `contentProgress` (the contained / with-gap results' alpha). */
452
+ readonly contentProgress: number;
453
+ /** The with-gap drop-down's slide offset in px (0 at rest, minus half its height hidden). */
454
+ readonly slide: number;
455
+ /** Whether the with-gap drop-down is shown (AnimatedVisibility is entering, visible or exiting). */
456
+ readonly dropdownShown: boolean;
457
+ }
458
+ /**
459
+ * SearchBarState's animation: `animateToExpanded` / `animateToCollapsed` run the progress spring
460
+ * and the content tween together; a new target starts from the current value and velocity
461
+ * (Animatable). Optionally (ExpandedDockedSearchBarWithGap) it also runs the drop-down's
462
+ * slide-in / slide-out on the same springs, from progress 0.1.
463
+ */
464
+ declare class SearchBarAnimation {
465
+ #private;
466
+ constructor(expanded?: boolean);
467
+ /** SearchBarState.targetValue. */
468
+ get isTargetExpanded(): boolean;
469
+ /** SearchBarState.currentValue: expanded until the value drops to the 0.02 tolerance. */
470
+ get isExpanded(): boolean;
471
+ get isRunning(): boolean;
472
+ /** animateToExpanded() at `now` (ms). */
473
+ expand(specs: SearchBarSpecs, now: number): void;
474
+ /** animateToCollapsed() at `now` (ms). */
475
+ collapse(specs: SearchBarSpecs, now: number): void;
476
+ /** Jumps to collapsed (0) or expanded (1), stopping every animation. */
477
+ snapTo(expanded: boolean): void;
478
+ /**
479
+ * Advances to `now`. `dropdownHeight` (px, the drop-down's full height) enables the with-gap
480
+ * slide: AnimatedVisibility(visible = progress > 0.1 && target == Expanded) slides in from minus
481
+ * half the height on the expand spring and out to it on the collapse spring.
482
+ */
483
+ sample(now: number, dropdownHeight?: number): SearchBarSample;
484
+ }
485
+ /** The expanded views Compose offers for a SearchBarState. */
486
+ type SearchViewVariant = 'full-screen' | 'full-screen-contained' | 'docked' | 'docked-with-gap';
487
+ interface SearchRect {
488
+ readonly x: number;
489
+ readonly y: number;
490
+ readonly width: number;
491
+ readonly height: number;
492
+ }
493
+ /** The SearchBar.kt measurements the layouts read (px; search-defaults.css). */
494
+ interface SearchViewMetrics {
495
+ /** SearchBarVerticalPadding (8dp). */
496
+ readonly verticalPadding: number;
497
+ /** AppBarWithSearchVerticalPadding (4dp): the contained view's top padding. */
498
+ readonly containedTopPadding: number;
499
+ /** FullScreenExpandedHorizontalPadding (8dp). */
500
+ readonly containedHorizontalPadding: number;
501
+ /** SearchBarCornerRadius = InputFieldHeight / 2 (28dp). */
502
+ readonly cornerRadius: number;
503
+ /** DockedExpandedTableMinHeight (240dp). */
504
+ readonly dockedMinHeight: number;
505
+ /** DockedExpandedTableMaxHeightScreenRatio (2/3). */
506
+ readonly dockedMaxHeightRatio: number;
507
+ /** DockedExpandedWithGapTableMaxHeightScreenRatio (1/2). */
508
+ readonly withGapMaxHeightRatio: number;
509
+ /** dockedDropdownGapSize (2dp). */
510
+ readonly dropdownGap: number;
511
+ }
512
+ interface SearchViewInput {
513
+ readonly variant: SearchViewVariant;
514
+ /** The collapsed search bar (`collapsedBounds`), viewport px. */
515
+ readonly collapsed: SearchRect;
516
+ /** The window (viewport) size. */
517
+ readonly window: {
518
+ readonly width: number;
519
+ readonly height: number;
520
+ };
521
+ /** The unconsumed top window inset (safe area). */
522
+ readonly insetTop: number;
523
+ readonly sample: Pick<SearchBarSample, 'value' | 'progress'>;
524
+ readonly metrics: SearchViewMetrics;
525
+ }
526
+ /** Where everything of an expanded view goes in one frame (viewport px). */
527
+ interface SearchViewFrame {
528
+ /**
529
+ * The surface: full-screen, the growing container (with `radius`); contained, the window,
530
+ * faded in by `alpha`; docked, the panel holding field and results (height between `minHeight`
531
+ * and `maxHeight`); with gap, the scrim (drawn at `alpha` × the scrim opacity).
532
+ */
533
+ readonly surface: SearchRect & {
534
+ readonly radius: number;
535
+ readonly alpha: number;
536
+ readonly minHeight: number;
537
+ readonly maxHeight: number;
538
+ };
539
+ /** The input field (collapsed height). */
540
+ readonly field: {
541
+ readonly x: number;
542
+ readonly y: number;
543
+ readonly width: number;
544
+ };
545
+ /** The results: top-left, width and the height they may take. */
546
+ readonly results: {
547
+ readonly x: number;
548
+ readonly y: number;
549
+ readonly width: number;
550
+ readonly maxHeight: number;
551
+ };
552
+ }
553
+ /**
554
+ * The layout of an expanded view at one animation frame: FullScreenSearchBarLayout (`isContained`
555
+ * false / true), DockedSearchBarLayoutImpl (docked) and the with-gap popup. Predictive back is not
556
+ * ported (the web has no back gesture progress).
557
+ */
558
+ declare function searchViewFrame(input: SearchViewInput): SearchViewFrame;
559
+ /**
560
+ * The combobox's next active option for a key (React Aria / APG list autocomplete): ArrowDown
561
+ * from the input goes to the first option and then down, stopping at the last; ArrowUp from the
562
+ * input goes to the last option and then up, and from the first option back to the input (-1).
563
+ * Returns null for keys it does not handle or an empty list. `enabled` filters disabled options.
564
+ */
565
+ declare function searchNavigationTarget(key: string, enabled: readonly boolean[], active: number): number | null;
252
566
 
253
567
  interface ButtonGroupItemSize {
254
568
  /** Resting width (Compose: the item's max intrinsic width). */
@@ -277,4 +591,4 @@ declare function buttonGroupVisibleCount(widths: readonly number[], spacing: num
277
591
  */
278
592
  declare function buttonGroupWidths(items: readonly ButtonGroupItemSize[], pressed: readonly number[], expandedRatio: number, visibleCount?: number): number[];
279
593
 
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 };
594
+ export { AmplitudeAnimation, type AmplitudeTween, type AppBarScrollBehavior, type AppBarScrollState, type ButtonGroupItemSize, type CircularIndeterminateFrame, type CircularIndeterminateTiming, DEFAULT_DISPLACEMENT_THRESHOLD, type Easing, FAST_OUT_LINEAR_IN_EASING, type FloatingToolbarExitDirection, type FloatingToolbarScrollState, type IndeterminateFrame, type LinearEasing, type LinearEasingOptions, type LinearIndeterminateTiming, type LoadingIndicatorTiming, type MenuAnchorPosition, type MenuPositionInput, type MenuPositionResult, type MenuRect, type Motion, SEARCH_BAR_EXPANDED_THRESHOLD, SEARCH_DROPDOWN_VISIBLE_PROGRESS, SearchBarAnimation, type SearchBarSample, type SearchBarSpecs, type SearchRect, type SearchViewFrame, type SearchViewInput, type SearchViewMetrics, type SearchViewVariant, SpringAnimatable, SpringSimulation, type SpringSpec, TOP_TITLE_ALPHA_EASING, type ToolbarExpansionScroll, type ToolbarOrientation, TweenAnimatable, type TweenSpec, type TwoRowsFrame, animatedInt, appBarScrollState, buttonGroupVisibleCount, buttonGroupWidths, circularIndeterminateFrame, collapsedFraction, cubicBezier, dampingCoefficient, dampingRatioFromCoefficient, estimateAnimationDurationMillis, estimateAnimationDurationMillisDouble, fabMenuItemVisible, floatingToolbarScrollState, indeterminateFrame, indicatorAmplitude, initialIndeterminateFrame, isScrolledUnder, linearIndeterminateFractions, menuNavigationTarget, menuPosition, menuTransformOrigin, morphSpringDurationMillis, overlappedFraction, parseCubicBezier, scrollAppBar, scrollFloatingToolbar, scrollToolbarExpansion, searchNavigationTarget, searchViewFrame, settleTarget, springDurationMillis, springToLinear, springValue, springVelocity, toolbarCollapsedFraction, toolbarExpansionScroll, toolbarNavigationTarget, toolbarSettleTarget, twoRowsFrame, waveOffset, waveTravelMillis, withHeight, withHeightOffset, withToolbarOffset, withToolbarOffsetLimit };