@kyralabs/m3e-motion 0.0.0-stage → 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/NOTICE ADDED
@@ -0,0 +1,50 @@
1
+ m3exp-web
2
+ Copyright 2026 Kyra Labs
3
+
4
+ This product is licensed under the Apache License, Version 2.0 (see LICENSE).
5
+
6
+ This product includes software from the projects listed below, each licensed
7
+ under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0).
8
+ Portions have been modified and ported to TypeScript by Kyra Labs. Every ported
9
+ file keeps its original copyright and license header and names its source path
10
+ and commit.
11
+
12
+ --------------------------------------------------------------------------------
13
+ AndroidX Compose Material3 (design tokens, component logic, MaterialShapes)
14
+ https://android.googlesource.com/platform/frameworks/support/+/19991f2c0858aadfcb442ce02b2c8e4743c96898/compose/material3/
15
+ Copyright (C) The Android Open Source Project
16
+ Licensed under the Apache License, Version 2.0
17
+
18
+ --------------------------------------------------------------------------------
19
+ AndroidX Compose Animation (animation-core: spring simulation and duration estimate)
20
+ https://android.googlesource.com/platform/frameworks/support/+/19991f2c0858aadfcb442ce02b2c8e4743c96898/compose/animation/animation-core/
21
+ Copyright (C) The Android Open Source Project
22
+ Licensed under the Apache License, Version 2.0
23
+
24
+ --------------------------------------------------------------------------------
25
+ AndroidX Compose UI Graphics (Matrix: the subset MaterialShapes uses)
26
+ https://android.googlesource.com/platform/frameworks/support/+/19991f2c0858aadfcb442ce02b2c8e4743c96898/compose/ui/ui-graphics/
27
+ Copyright (C) The Android Open Source Project
28
+ Licensed under the Apache License, Version 2.0
29
+
30
+ --------------------------------------------------------------------------------
31
+ AndroidX graphics-shapes (androidx.graphics:graphics-shapes 1.0.1, sources jar)
32
+ https://dl.google.com/android/maven2/androidx/graphics/graphics-shapes/1.0.1/graphics-shapes-1.0.1-sources.jar
33
+ Copyright (C) The Android Open Source Project
34
+ Licensed under the Apache License, Version 2.0
35
+
36
+ --------------------------------------------------------------------------------
37
+ Material Web (@material/web 2.5.0: elevation shadow values in @kyralabs/m3e-tokens)
38
+ https://github.com/material-components/material-web
39
+ Copyright 2022 Google LLC
40
+ Licensed under the Apache License, Version 2.0
41
+
42
+ --------------------------------------------------------------------------------
43
+ material-color-utilities (@material/material-color-utilities 0.4.0, bundled in @kyralabs/m3e-tokens)
44
+ https://github.com/material-foundation/material-color-utilities
45
+ Copyright 2021 Google LLC
46
+ Licensed under the Apache License, Version 2.0
47
+
48
+ --------------------------------------------------------------------------------
49
+ Bundled fonts are distributed under their own licenses, included beside each
50
+ font file in packages/m3e-tokens/fonts/.
package/README.md CHANGED
@@ -1,3 +1,22 @@
1
- # Temporary Holding Version
1
+ # @kyralabs/m3e-motion
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Spring math for m3exp-web: TypeScript ports of Compose's `SpringSimulation` and spring duration
4
+ estimate (float32-exact against the JVM), `FloatSpringSpec` helpers, a CSS `linear()` sampler and
5
+ the top app bar scroll state. Mostly used by the other `@kyralabs` packages; no DOM access.
6
+
7
+ ```sh
8
+ npm install @kyralabs/m3e-motion
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```ts
14
+ import { springDurationMillis, springToLinear, springValue } from '@kyralabs/m3e-motion';
15
+
16
+ const spec = { dampingRatio: 0.9, stiffness: 700 };
17
+ springValue(spec, 100, 0, 1); // position after 100 ms, animating 0 → 1
18
+ springDurationMillis(spec, 0, 1); // settle time in ms
19
+ springToLinear(spec); // CSS linear() easing plus its duration
20
+ ```
21
+
22
+ Apache-2.0; see `LICENSE` and `NOTICE`.
@@ -0,0 +1,160 @@
1
+ /** A Material motion-scheme spring (`dampingRatio` ζ, `stiffness` k; mass 1). */
2
+ interface SpringSpec {
3
+ readonly dampingRatio: number;
4
+ readonly stiffness: number;
5
+ }
6
+ /** `Spring.DefaultDisplacementThreshold` (VectorizedAnimationSpec.kt L842). */
7
+ declare const DEFAULT_DISPLACEMENT_THRESHOLD = 0.01;
8
+ /** Value at `playTimeMillis` (whole milliseconds, as in Compose). */
9
+ declare function springValue(spec: SpringSpec, playTimeMillis: number, initialValue: number, targetValue: number, initialVelocity?: number): number;
10
+ /** Velocity (units/s) at `playTimeMillis`. */
11
+ declare function springVelocity(spec: SpringSpec, playTimeMillis: number, initialValue: number, targetValue: number, initialVelocity?: number): number;
12
+ /**
13
+ * Duration until the spring stays within `visibilityThreshold` of the target, as Compose computes
14
+ * it (`FloatSpringSpec.getDurationNanos` / 1e6).
15
+ */
16
+ declare function springDurationMillis(spec: SpringSpec, initialValue: number, targetValue: number, initialVelocity?: number, visibilityThreshold?: number): number;
17
+ /**
18
+ * Damping coefficient c = 2ζ√(k·m), for physics engines parameterized by stiffness/damping/mass
19
+ * (e.g. Motion's `{ type: 'spring', stiffness, damping, mass }`).
20
+ */
21
+ declare function dampingCoefficient(spec: SpringSpec, mass?: number): number;
22
+ /** Inverse of {@link dampingCoefficient}: ζ = c / (2√(k·m)). */
23
+ declare function dampingRatioFromCoefficient(damping: number, stiffness: number, mass?: number): number;
24
+
25
+ interface LinearEasingOptions {
26
+ /** Fraction of the travel considered settled. Default 0.001. */
27
+ visibilityThreshold?: number;
28
+ /** Maximum stops in the `linear()` function (FOUNDATIONS §4: ≤ 40). Default 40. */
29
+ maxStops?: number;
30
+ }
31
+ interface LinearEasing {
32
+ /** e.g. `linear(0, 0.1234 5%, …, 1)` */
33
+ easing: string;
34
+ durationMillis: number;
35
+ /** `[progress 0–1, value]` pairs after rounding. */
36
+ stops: readonly (readonly [number, number])[];
37
+ /** Max |linear(t) − spring(t)| over every millisecond sample. */
38
+ maxError: number;
39
+ }
40
+ declare function springToLinear(spec: SpringSpec, options?: LinearEasingOptions): LinearEasing;
41
+
42
+ interface LoadingIndicatorTiming {
43
+ /** `MorphIntervalMillis`: how often a morph starts. */
44
+ readonly morphIntervalMillis: number;
45
+ /** `GlobalRotationDurationMillis`: one linear turn. */
46
+ readonly rotationDurationMillis: number;
47
+ /** The morph spring (`morphAnimationSpec`). */
48
+ readonly spring: SpringSpec;
49
+ /** The morph spring's `visibilityThreshold`; it decides when the spring finishes. */
50
+ readonly visibilityThreshold: number;
51
+ }
52
+ /** What the indicator draws: a morph at a progress, rotated clockwise about the center. */
53
+ interface IndeterminateFrame {
54
+ morphIndex: number;
55
+ /** The raw spring value: it overshoots past 1, as in Compose (the morph extrapolates). */
56
+ morphProgress: number;
57
+ /** Degrees, clockwise. */
58
+ rotation: number;
59
+ }
60
+ /**
61
+ * The first frame (and the one held under reduced motion): the first morph at 0, rotated by the
62
+ * initial `morphRotationTargetAngle` (a quarter turn).
63
+ */
64
+ declare const initialIndeterminateFrame: Readonly<IndeterminateFrame>;
65
+ /** How long one morph spring runs (Compose's `FloatSpringSpec.getDurationNanos`), in ms. */
66
+ declare const morphSpringDurationMillis: (timing: LoadingIndicatorTiming) => number;
67
+ /**
68
+ * The frame of an indeterminate loading indicator [elapsedMillis] after it started, cycling
69
+ * through [morphCount] morphs.
70
+ */
71
+ declare function indeterminateFrame(elapsedMillis: number, morphCount: number, timing: LoadingIndicatorTiming): IndeterminateFrame;
72
+
73
+ /**
74
+ * Returns the estimated time that the spring will last be at [delta]. Arguments are Kotlin
75
+ * `Float`s (rounded to float32).
76
+ */
77
+ declare function estimateAnimationDurationMillis(stiffness: number, dampingRatio: number, initialVelocity: number, initialDisplacement: number, delta: number): number;
78
+ /** Returns the estimated time that the spring will last be at [delta] (Double overload). */
79
+ declare function estimateAnimationDurationMillisDouble(stiffness: number, dampingRatio: number, initialVelocity: number, initialDisplacement: number, delta: number): number;
80
+
81
+ interface Motion {
82
+ value: number;
83
+ velocity: number;
84
+ }
85
+ /**
86
+ * Spring Simulation simulates spring physics, and allows you to query the motion (i.e. value and
87
+ * velocity) at certain time in the future based on the starting velocity and value.
88
+ *
89
+ * By configuring the stiffness and damping ratio, callers can create a spring with the look and
90
+ * feel suits their use case. Stiffness corresponds to the spring constant. The stiffer the spring
91
+ * is, the harder it is to stretch it, the faster it undergoes dampening.
92
+ *
93
+ * Spring damping ratio describes how oscillations in a system decay after a disturbance. When
94
+ * damping ratio > 1* (i.e. over-damped), the object will quickly return to the rest position
95
+ * without overshooting. If damping ratio equals to 1 (i.e. critically damped), the object will
96
+ * return to equilibrium within the shortest amount of time. When damping ratio is less than 1 (i.e.
97
+ * under-damped), the mass tends to overshoot, and return, and overshoot again. Without any damping
98
+ * (i.e. damping ratio = 0), the mass will oscillate forever.
99
+ */
100
+ declare class SpringSimulation {
101
+ #private;
102
+ constructor(finalPosition: number);
103
+ get finalPosition(): number;
104
+ set finalPosition(value: number);
105
+ /** Stiffness of the spring. */
106
+ get stiffness(): number;
107
+ set stiffness(value: number);
108
+ /** Returns the damping ratio of the spring. */
109
+ get dampingRatio(): number;
110
+ set dampingRatio(value: number);
111
+ getAcceleration(lastDisplacement: number, lastVelocity: number): number;
112
+ /**
113
+ * Internal only call for Spring to calculate the spring position/velocity using an analytical
114
+ * approach.
115
+ */
116
+ updateValues(lastDisplacement: number, lastVelocity: number, timeElapsed: number): Motion;
117
+ }
118
+
119
+ /** How the bar reacts to its scroll container (TopAppBarDefaults.*ScrollBehavior). */
120
+ type AppBarScrollBehavior = 'pinned' | 'enter-always';
121
+ interface AppBarScrollState {
122
+ /** Most negative height offset: minus the bar's full height (adjustHeightOffsetLimit). */
123
+ readonly heightOffsetLimit: number;
124
+ /** Current height offset, between heightOffsetLimit and 0. */
125
+ readonly heightOffset: number;
126
+ /** Content scrolled under the bar (minus the scroll position). */
127
+ readonly contentOffset: number;
128
+ /** Whether the scrolling content is at its start (scroll position 0). */
129
+ readonly atStart: boolean;
130
+ }
131
+ /** A fully expanded bar of `height` px over unscrolled content. */
132
+ declare function appBarScrollState(height: number): AppBarScrollState;
133
+ /** TopAppBarState.heightOffset setter: coerced between heightOffsetLimit and 0. */
134
+ declare function withHeightOffset(state: AppBarScrollState, offset: number): AppBarScrollState;
135
+ /** A new bar height (onSizeChanged → adjustHeightOffsetLimit), keeping the offset in range. */
136
+ declare function withHeight(state: AppBarScrollState, height: number): AppBarScrollState;
137
+ /** 0 = fully expanded, 1 = fully collapsed (TopAppBarState.collapsedFraction). */
138
+ declare function collapsedFraction(state: AppBarScrollState): number;
139
+ /** Share of the visible bar overlapping scrolled content (TopAppBarState.overlappedFraction). */
140
+ declare function overlappedFraction(state: AppBarScrollState): number;
141
+ /**
142
+ * Whether the bar shows its scrolled container color: SingleRowTopAppBar targets the scrolled
143
+ * color once `overlappedFraction > 0.01f` (L2689-2693).
144
+ */
145
+ declare function isScrolledUnder(state: AppBarScrollState): boolean;
146
+ /**
147
+ * Applies a scroll position change. `delta` is the previous minus the new scroll position
148
+ * (positive when the content is pulled down, like Compose's `available.y`).
149
+ * - pinned: only the content offset moves (PinnedScrollBehavior.onPostScroll).
150
+ * - enter-always: the bar also collapses/expands by the same amount
151
+ * (EnterAlwaysScrollBehavior.onPreScroll: `heightOffset += available.y`).
152
+ */
153
+ declare function scrollAppBar(state: AppBarScrollState, behavior: AppBarScrollBehavior, scrollTop: number, delta: number): AppBarScrollState;
154
+ /**
155
+ * Where a partially collapsed bar snaps when scrolling stops (settleAppBar): fully expanded below
156
+ * half, fully collapsed from half, or null when it is already (within 1%) settled.
157
+ */
158
+ declare function settleTarget(state: AppBarScrollState): number | null;
159
+
160
+ export { type AppBarScrollBehavior, type AppBarScrollState, DEFAULT_DISPLACEMENT_THRESHOLD, type IndeterminateFrame, type LinearEasing, type LinearEasingOptions, type LoadingIndicatorTiming, type Motion, SpringSimulation, type SpringSpec, appBarScrollState, collapsedFraction, dampingCoefficient, dampingRatioFromCoefficient, estimateAnimationDurationMillis, estimateAnimationDurationMillisDouble, indeterminateFrame, initialIndeterminateFrame, isScrolledUnder, morphSpringDurationMillis, overlappedFraction, scrollAppBar, settleTarget, springDurationMillis, springToLinear, springValue, springVelocity, withHeight, withHeightOffset };
package/dist/index.js ADDED
@@ -0,0 +1,403 @@
1
+ // src/spring-estimation.ts
2
+ var LONG_MAX = 2 ** 63;
3
+ var LONG_MIN = -9223372036854776e3;
4
+ var MAX_LONG_MILLIS = 9223372036854;
5
+ var toLong = (x) => Number.isNaN(x) ? 0 : x >= LONG_MAX ? LONG_MAX : x <= LONG_MIN ? LONG_MIN : Math.trunc(x);
6
+ function estimateAnimationDurationMillis(stiffness, dampingRatio, initialVelocity, initialDisplacement, delta) {
7
+ const f323 = Math.fround;
8
+ if (f323(dampingRatio) === 0) {
9
+ return MAX_LONG_MILLIS;
10
+ }
11
+ return estimateAnimationDurationMillisDouble(
12
+ f323(stiffness),
13
+ f323(dampingRatio),
14
+ f323(initialVelocity),
15
+ f323(initialDisplacement),
16
+ f323(delta)
17
+ );
18
+ }
19
+ function estimateAnimationDurationMillisDouble(stiffness, dampingRatio, initialVelocity, initialDisplacement, delta) {
20
+ const dampingCoefficient2 = 2 * dampingRatio * Math.sqrt(stiffness);
21
+ const partialRoot = dampingCoefficient2 * dampingCoefficient2 - 4 * stiffness;
22
+ const partialRootReal = partialRoot < 0 ? 0 : Math.sqrt(partialRoot);
23
+ const partialRootImaginary = partialRoot < 0 ? Math.sqrt(Math.abs(partialRoot)) : 0;
24
+ const firstRootReal = (-dampingCoefficient2 + partialRootReal) * 0.5;
25
+ const firstRootImaginary = partialRootImaginary * 0.5;
26
+ const secondRootReal = (-dampingCoefficient2 - partialRootReal) * 0.5;
27
+ return estimateDurationInternal(
28
+ firstRootReal,
29
+ firstRootImaginary,
30
+ secondRootReal,
31
+ dampingRatio,
32
+ initialVelocity,
33
+ initialDisplacement,
34
+ delta
35
+ );
36
+ }
37
+ function estimateUnderDamped(firstRootReal, firstRootImaginary, p0, v0, delta) {
38
+ const r = firstRootReal;
39
+ const c1 = p0;
40
+ const c2 = (v0 - r * c1) / firstRootImaginary;
41
+ const c = Math.sqrt(c1 * c1 + c2 * c2);
42
+ return Math.log(delta / c) / r;
43
+ }
44
+ var isNotFinite = (x) => !Number.isFinite(x);
45
+ var iterateNewtonsMethod = (x, fn, fnPrime) => x - fn(x) / fnPrime(x);
46
+ function estimateCriticallyDamped(firstRootReal, p0, v0, delta) {
47
+ const r = firstRootReal;
48
+ const c1 = p0;
49
+ const c2 = v0 - r * c1;
50
+ const t1 = Math.log(Math.abs(delta / c1)) / r;
51
+ const t2 = (() => {
52
+ const guess = Math.log(Math.abs(delta / c2));
53
+ let t = guess;
54
+ for (let i = 0; i <= 5; i++) {
55
+ t = guess - Math.log(Math.abs(t / r));
56
+ }
57
+ return t;
58
+ })() / r;
59
+ let tCurr = isNotFinite(t1) ? t2 : isNotFinite(t2) ? t1 : Math.max(t1, t2);
60
+ const tInflection = -(r * c1 + c2) / (r * c2);
61
+ const xInflection = c1 * Math.exp(r * tInflection) + c2 * tInflection * Math.exp(r * tInflection);
62
+ let signedDelta;
63
+ if (Number.isNaN(tInflection) || tInflection <= 0) {
64
+ signedDelta = -delta;
65
+ } else if (tInflection > 0 && -xInflection < delta) {
66
+ if (c2 < 0 && c1 > 0) {
67
+ tCurr = 0;
68
+ }
69
+ signedDelta = -delta;
70
+ } else {
71
+ tCurr = -(2 / r) - c1 / c2;
72
+ signedDelta = delta;
73
+ }
74
+ let tDelta = Number.MAX_VALUE;
75
+ let iterations = 0;
76
+ while (tDelta > 1e-3 && iterations < 100) {
77
+ iterations++;
78
+ const tLast = tCurr;
79
+ tCurr = iterateNewtonsMethod(
80
+ tCurr,
81
+ (t) => (c1 + c2 * t) * Math.exp(r * t) + signedDelta,
82
+ (t) => (c2 * (r * t + 1) + c1 * r) * Math.exp(r * t)
83
+ );
84
+ tDelta = Math.abs(tLast - tCurr);
85
+ }
86
+ return tCurr;
87
+ }
88
+ function estimateOverDamped(firstRootReal, secondRootReal, p0, v0, delta) {
89
+ const r1 = firstRootReal;
90
+ const r2 = secondRootReal;
91
+ const c2 = (r1 * p0 - v0) / (r1 - r2);
92
+ const c1 = p0 - c2;
93
+ const t1 = Math.log(Math.abs(delta / c1)) / r1;
94
+ const t2 = Math.log(Math.abs(delta / c2)) / r2;
95
+ let tCurr = isNotFinite(t1) ? t2 : isNotFinite(t2) ? t1 : Math.max(t1, t2);
96
+ const tInflection = Math.log(c1 * r1 / (-c2 * r2)) / (r2 - r1);
97
+ const xInflection = () => c1 * Math.exp(r1 * tInflection) + c2 * Math.exp(r2 * tInflection);
98
+ let signedDelta;
99
+ if (Number.isNaN(tInflection) || tInflection <= 0) {
100
+ signedDelta = -delta;
101
+ } else if (tInflection > 0 && -xInflection() < delta) {
102
+ if (c2 > 0 && c1 < 0) {
103
+ tCurr = 0;
104
+ }
105
+ signedDelta = -delta;
106
+ } else {
107
+ tCurr = Math.log(-(c2 * r2 * r2) / (c1 * r1 * r1)) / (r1 - r2);
108
+ signedDelta = delta;
109
+ }
110
+ if (Math.abs(c1 * r1 * Math.exp(r1 * tCurr) + c2 * r2 * Math.exp(r2 * tCurr)) < 1e-4) {
111
+ return tCurr;
112
+ }
113
+ let tDelta = Number.MAX_VALUE;
114
+ let iterations = 0;
115
+ while (tDelta > 1e-3 && iterations < 100) {
116
+ iterations++;
117
+ const tLast = tCurr;
118
+ tCurr = iterateNewtonsMethod(
119
+ tCurr,
120
+ (t) => c1 * Math.exp(r1 * t) + c2 * Math.exp(r2 * t) + signedDelta,
121
+ (t) => c1 * r1 * Math.exp(r1 * t) + c2 * r2 * Math.exp(r2 * t)
122
+ );
123
+ tDelta = Math.abs(tLast - tCurr);
124
+ }
125
+ return tCurr;
126
+ }
127
+ function estimateDurationInternal(firstRootReal, firstRootImaginary, secondRootReal, dampingRatio, initialVelocity, initialPosition, delta) {
128
+ if (initialPosition === 0 && initialVelocity === 0) {
129
+ return 0;
130
+ }
131
+ const v0 = initialPosition < 0 ? -initialVelocity : initialVelocity;
132
+ const p0 = Math.abs(initialPosition);
133
+ const seconds = dampingRatio > 1 ? estimateOverDamped(firstRootReal, secondRootReal, p0, v0, delta) : dampingRatio < 1 ? estimateUnderDamped(firstRootReal, firstRootImaginary, p0, v0, delta) : estimateCriticallyDamped(firstRootReal, p0, v0, delta);
134
+ return toLong(seconds * 1e3);
135
+ }
136
+
137
+ // src/spring-simulation.ts
138
+ var f32 = Math.fround;
139
+ var STIFFNESS_VERY_LOW = 50;
140
+ var DAMPING_RATIO_NO_BOUNCY = 1;
141
+ var SpringSimulation = class {
142
+ // Natural frequency
143
+ #naturalFreq = Math.sqrt(STIFFNESS_VERY_LOW);
144
+ #dampingRatio = DAMPING_RATIO_NO_BOUNCY;
145
+ #finalPosition;
146
+ constructor(finalPosition) {
147
+ this.#finalPosition = f32(finalPosition);
148
+ }
149
+ get finalPosition() {
150
+ return this.#finalPosition;
151
+ }
152
+ set finalPosition(value) {
153
+ this.#finalPosition = f32(value);
154
+ }
155
+ /** Stiffness of the spring. */
156
+ get stiffness() {
157
+ return f32(this.#naturalFreq * this.#naturalFreq);
158
+ }
159
+ set stiffness(value) {
160
+ if (this.stiffness <= 0) {
161
+ throw new RangeError("Spring stiffness constant must be positive.");
162
+ }
163
+ this.#naturalFreq = Math.sqrt(f32(value));
164
+ }
165
+ /** Returns the damping ratio of the spring. */
166
+ get dampingRatio() {
167
+ return this.#dampingRatio;
168
+ }
169
+ set dampingRatio(value) {
170
+ if (value < 0) {
171
+ throw new RangeError("Damping ratio must be non-negative");
172
+ }
173
+ this.#dampingRatio = f32(value);
174
+ }
175
+ getAcceleration(lastDisplacement, lastVelocity) {
176
+ const adjustedDisplacement = f32(f32(lastDisplacement) - this.#finalPosition);
177
+ const k = this.#naturalFreq * this.#naturalFreq;
178
+ const c = 2 * this.#naturalFreq * this.#dampingRatio;
179
+ return f32(-k * adjustedDisplacement - c * f32(lastVelocity));
180
+ }
181
+ /**
182
+ * Internal only call for Spring to calculate the spring position/velocity using an analytical
183
+ * approach.
184
+ */
185
+ updateValues(lastDisplacement, lastVelocity, timeElapsed) {
186
+ const dampingRatio = this.#dampingRatio;
187
+ const naturalFreq = this.#naturalFreq;
188
+ const velocity0 = f32(lastVelocity);
189
+ const adjustedDisplacement = f32(f32(lastDisplacement) - this.#finalPosition);
190
+ const deltaT = Math.trunc(timeElapsed) / 1e3;
191
+ const dampingRatioSquared = dampingRatio * dampingRatio;
192
+ const r = -dampingRatio * naturalFreq;
193
+ let displacement;
194
+ let currentVelocity;
195
+ if (dampingRatio > 1) {
196
+ const s = naturalFreq * Math.sqrt(dampingRatioSquared - 1);
197
+ const gammaPlus = r + s;
198
+ const gammaMinus = r - s;
199
+ const coeffB = (gammaMinus * adjustedDisplacement - velocity0) / (gammaMinus - gammaPlus);
200
+ const coeffA = adjustedDisplacement - coeffB;
201
+ displacement = coeffA * Math.exp(gammaMinus * deltaT) + coeffB * Math.exp(gammaPlus * deltaT);
202
+ currentVelocity = coeffA * gammaMinus * Math.exp(gammaMinus * deltaT) + coeffB * gammaPlus * Math.exp(gammaPlus * deltaT);
203
+ } else if (dampingRatio === 1) {
204
+ const coeffA = adjustedDisplacement;
205
+ const coeffB = velocity0 + naturalFreq * adjustedDisplacement;
206
+ const nFdT = -naturalFreq * deltaT;
207
+ displacement = (coeffA + coeffB * deltaT) * Math.exp(nFdT);
208
+ currentVelocity = (coeffA + coeffB * deltaT) * Math.exp(nFdT) * -naturalFreq + coeffB * Math.exp(nFdT);
209
+ } else {
210
+ const dampedFreq = naturalFreq * Math.sqrt(1 - dampingRatioSquared);
211
+ const cosCoeff = adjustedDisplacement;
212
+ const sinCoeff = 1 / dampedFreq * (-r * adjustedDisplacement + velocity0);
213
+ const dFdT = dampedFreq * deltaT;
214
+ displacement = Math.exp(r * deltaT) * (cosCoeff * Math.cos(dFdT) + sinCoeff * Math.sin(dFdT));
215
+ currentVelocity = displacement * r + Math.exp(r * deltaT) * (-dampedFreq * cosCoeff * Math.sin(dFdT) + dampedFreq * sinCoeff * Math.cos(dFdT));
216
+ }
217
+ return {
218
+ value: f32(displacement + this.#finalPosition),
219
+ velocity: f32(currentVelocity)
220
+ };
221
+ }
222
+ };
223
+
224
+ // src/spring.ts
225
+ var DEFAULT_DISPLACEMENT_THRESHOLD = 0.01;
226
+ var f322 = Math.fround;
227
+ function simulation(spec, targetValue) {
228
+ const sim = new SpringSimulation(targetValue);
229
+ sim.dampingRatio = spec.dampingRatio;
230
+ sim.stiffness = spec.stiffness;
231
+ return sim;
232
+ }
233
+ function springValue(spec, playTimeMillis, initialValue, targetValue, initialVelocity = 0) {
234
+ return simulation(spec, targetValue).updateValues(initialValue, initialVelocity, playTimeMillis).value;
235
+ }
236
+ function springVelocity(spec, playTimeMillis, initialValue, targetValue, initialVelocity = 0) {
237
+ return simulation(spec, targetValue).updateValues(initialValue, initialVelocity, playTimeMillis).velocity;
238
+ }
239
+ function springDurationMillis(spec, initialValue, targetValue, initialVelocity = 0, visibilityThreshold = DEFAULT_DISPLACEMENT_THRESHOLD) {
240
+ const sim = simulation(spec, targetValue);
241
+ const threshold = f322(visibilityThreshold);
242
+ return estimateAnimationDurationMillis(
243
+ sim.stiffness,
244
+ sim.dampingRatio,
245
+ f322(f322(initialVelocity) / threshold),
246
+ f322(f322(f322(initialValue) - f322(targetValue)) / threshold),
247
+ 1
248
+ );
249
+ }
250
+ function dampingCoefficient(spec, mass = 1) {
251
+ return 2 * spec.dampingRatio * Math.sqrt(spec.stiffness * mass);
252
+ }
253
+ function dampingRatioFromCoefficient(damping, stiffness, mass = 1) {
254
+ return damping / (2 * Math.sqrt(stiffness * mass));
255
+ }
256
+
257
+ // src/linear.ts
258
+ var round = (n, digits) => {
259
+ const r = Number(n.toFixed(digits));
260
+ return Object.is(r, -0) ? 0 : r;
261
+ };
262
+ function at(list, i) {
263
+ const item = list[i];
264
+ if (item === void 0) throw new RangeError(`index ${String(i)} out of range`);
265
+ return item;
266
+ }
267
+ function simplify(points, tolerance) {
268
+ const keep = /* @__PURE__ */ new Set([0, points.length - 1]);
269
+ const stack = [[0, points.length - 1]];
270
+ for (let range = stack.pop(); range; range = stack.pop()) {
271
+ const [a, b] = range;
272
+ const [x0, y0] = at(points, a);
273
+ const [x1, y1] = at(points, b);
274
+ let worst = -1;
275
+ let worstDistance = tolerance;
276
+ for (let i = a + 1; i < b; i++) {
277
+ const [x, y] = at(points, i);
278
+ const expected = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
279
+ const distance = Math.abs(y - expected);
280
+ if (distance > worstDistance) {
281
+ worst = i;
282
+ worstDistance = distance;
283
+ }
284
+ }
285
+ if (worst !== -1) {
286
+ keep.add(worst);
287
+ stack.push([a, worst], [worst, b]);
288
+ }
289
+ }
290
+ return [...keep].sort((x, y) => x - y);
291
+ }
292
+ function interpolate(stops, x) {
293
+ for (let i = 1; i < stops.length; i++) {
294
+ const [x1, y1] = at(stops, i);
295
+ const [x0, y0] = at(stops, i - 1);
296
+ if (x <= x1) return x1 === x0 ? y1 : y0 + (y1 - y0) * (x - x0) / (x1 - x0);
297
+ }
298
+ return at(stops, stops.length - 1)[1];
299
+ }
300
+ function springToLinear(spec, options = {}) {
301
+ const { visibilityThreshold = 1e-3, maxStops = 40 } = options;
302
+ if (maxStops < 2) throw new RangeError("maxStops must be at least 2");
303
+ const durationMillis = Math.max(1, springDurationMillis(spec, 0, 1, 0, visibilityThreshold));
304
+ const sim = new SpringSimulation(1);
305
+ sim.dampingRatio = spec.dampingRatio;
306
+ sim.stiffness = spec.stiffness;
307
+ const samples = [];
308
+ for (let t = 0; t <= durationMillis; t++) {
309
+ samples.push([t / durationMillis, sim.updateValues(0, 0, t).value]);
310
+ }
311
+ samples[samples.length - 1] = [1, 1];
312
+ let lo = 0;
313
+ let hi = 0.5;
314
+ let best = simplify(samples, hi);
315
+ for (let i = 0; i < 40; i++) {
316
+ const mid = (lo + hi) / 2;
317
+ const kept = simplify(samples, mid);
318
+ if (kept.length <= maxStops) {
319
+ best = kept;
320
+ hi = mid;
321
+ } else {
322
+ lo = mid;
323
+ }
324
+ }
325
+ const stops = best.map((i) => {
326
+ const [x, y] = at(samples, i);
327
+ return [round(x, 4), round(y, 4)];
328
+ });
329
+ const maxError = samples.reduce(
330
+ (m, [x, y]) => Math.max(m, Math.abs(interpolate(stops, x) - y)),
331
+ 0
332
+ );
333
+ const body = stops.map(
334
+ ([x, y], i) => i === 0 || i === stops.length - 1 ? String(y) : `${String(y)} ${String(round(x * 100, 2))}%`
335
+ );
336
+ return { easing: `linear(${body.join(", ")})`, durationMillis, stops, maxError };
337
+ }
338
+
339
+ // src/loading-indicator.ts
340
+ var FULL_ROTATION = 360;
341
+ var QUARTER_ROTATION = FULL_ROTATION / 4;
342
+ var initialIndeterminateFrame = {
343
+ morphIndex: 0,
344
+ morphProgress: 0,
345
+ rotation: QUARTER_ROTATION
346
+ };
347
+ var morphSpringDurationMillis = (timing) => springDurationMillis(timing.spring, 0, 1, 0, timing.visibilityThreshold);
348
+ function indeterminateFrame(elapsedMillis, morphCount, timing) {
349
+ const t = Math.max(0, elapsedMillis);
350
+ const springMillis = morphSpringDurationMillis(timing);
351
+ const period = Math.max(timing.morphIntervalMillis, springMillis);
352
+ const completed = Math.floor(t / period);
353
+ const local = t - completed * period;
354
+ const running = local < springMillis;
355
+ const finished = running ? completed : completed + 1;
356
+ const morphIndex = finished % morphCount;
357
+ const targetAngle = QUARTER_ROTATION * (finished + 1) % FULL_ROTATION;
358
+ const morphProgress = running ? springValue(timing.spring, Math.floor(local), 0, 1) : 0;
359
+ const globalRotation = FULL_ROTATION * Math.floor(t % timing.rotationDurationMillis) / timing.rotationDurationMillis;
360
+ return {
361
+ morphIndex,
362
+ morphProgress,
363
+ rotation: morphProgress * QUARTER_ROTATION + targetAngle + globalRotation
364
+ };
365
+ }
366
+
367
+ // src/app-bar-scroll.ts
368
+ function appBarScrollState(height) {
369
+ return { heightOffsetLimit: -height, heightOffset: 0, contentOffset: 0, atStart: true };
370
+ }
371
+ function withHeightOffset(state, offset) {
372
+ return { ...state, heightOffset: Math.min(Math.max(offset, state.heightOffsetLimit), 0) };
373
+ }
374
+ function withHeight(state, height) {
375
+ return withHeightOffset({ ...state, heightOffsetLimit: -height }, state.heightOffset);
376
+ }
377
+ function collapsedFraction(state) {
378
+ return state.heightOffsetLimit !== 0 ? state.heightOffset / state.heightOffsetLimit + 0 : 0;
379
+ }
380
+ function overlappedFraction(state) {
381
+ if (!state.atStart && state.contentOffset === 0) return 1;
382
+ if (state.heightOffsetLimit === 0) return 0;
383
+ const limit = state.heightOffsetLimit;
384
+ const clamped = Math.min(Math.max(limit + Math.abs(state.contentOffset), limit), 0);
385
+ return 1 - clamped / limit;
386
+ }
387
+ function isScrolledUnder(state) {
388
+ return overlappedFraction(state) > 0.01;
389
+ }
390
+ function scrollAppBar(state, behavior, scrollTop, delta) {
391
+ const next = { ...state, contentOffset: -scrollTop, atStart: scrollTop <= 0 };
392
+ return behavior === "enter-always" ? withHeightOffset(next, state.heightOffset + delta) : next;
393
+ }
394
+ function settleTarget(state) {
395
+ const fraction = collapsedFraction(state);
396
+ if (fraction < 0.01 || fraction === 1) return null;
397
+ if (!(state.heightOffset < 0 && state.heightOffset > state.heightOffsetLimit)) return null;
398
+ return fraction < 0.5 ? 0 : state.heightOffsetLimit;
399
+ }
400
+
401
+ export { DEFAULT_DISPLACEMENT_THRESHOLD, SpringSimulation, appBarScrollState, collapsedFraction, dampingCoefficient, dampingRatioFromCoefficient, estimateAnimationDurationMillis, estimateAnimationDurationMillisDouble, indeterminateFrame, initialIndeterminateFrame, isScrolledUnder, morphSpringDurationMillis, overlappedFraction, scrollAppBar, settleTarget, springDurationMillis, springToLinear, springValue, springVelocity, withHeight, withHeightOffset };
402
+ //# sourceMappingURL=index.js.map
403
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/spring-estimation.ts","../src/spring-simulation.ts","../src/spring.ts","../src/linear.ts","../src/loading-indicator.ts","../src/app-bar-scroll.ts"],"names":["f32","dampingCoefficient"],"mappings":"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","file":"index.js","sourcesContent":["/*\n * Copyright 2020 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n// Ported to TypeScript by Kyra Labs from compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringEstimation.kt@19991f2c0858aadfcb442ce02b2c8e4743c96898\n//\n// The Float overload's arguments are rounded to float32 (Math.fround) before widening to Double,\n// as in Kotlin. Durations are Long milliseconds: Kotlin's Double.toLong() (truncation, NaN → 0,\n// saturating) is reproduced by `toLong`.\n\n/** Maximum duration in Milliseconds. This takes into account that the duration will be converted to nanos. */\n// Long.MAX_VALUE / Long.MIN_VALUE as doubles (2^63 is what Kotlin's Long.toDouble() yields).\nconst LONG_MAX = 2 ** 63;\nconst LONG_MIN = -(2 ** 63);\nconst MAX_LONG_MILLIS = 9_223_372_036_854; // Long.MAX_VALUE / 1_000_000 (integer division)\n\nconst toLong = (x: number): number =>\n Number.isNaN(x) ? 0 : x >= LONG_MAX ? LONG_MAX : x <= LONG_MIN ? LONG_MIN : Math.trunc(x);\n\n/**\n * Returns the estimated time that the spring will last be at [delta]. Arguments are Kotlin\n * `Float`s (rounded to float32).\n */\nexport function estimateAnimationDurationMillis(\n stiffness: number,\n dampingRatio: number,\n initialVelocity: number,\n initialDisplacement: number,\n delta: number,\n): number {\n const f32 = Math.fround;\n if (f32(dampingRatio) === 0) {\n // No damping, duration is infinite (max value).\n return MAX_LONG_MILLIS;\n }\n\n return estimateAnimationDurationMillisDouble(\n f32(stiffness),\n f32(dampingRatio),\n f32(initialVelocity),\n f32(initialDisplacement),\n f32(delta),\n );\n}\n\n/** Returns the estimated time that the spring will last be at [delta] (Double overload). */\nexport function estimateAnimationDurationMillisDouble(\n stiffness: number,\n dampingRatio: number,\n initialVelocity: number,\n initialDisplacement: number,\n delta: number,\n): number {\n const dampingCoefficient = 2.0 * dampingRatio * Math.sqrt(stiffness);\n\n // Compute the roots of the polynomial [a]x^2+[b]x+[c]=0 which may be complex.\n // Here a is set to the constant 1.0, and folded into the other computations\n const partialRoot = dampingCoefficient * dampingCoefficient - 4.0 * stiffness;\n const partialRootReal = partialRoot < 0.0 ? 0.0 : Math.sqrt(partialRoot);\n const partialRootImaginary = partialRoot < 0.0 ? Math.sqrt(Math.abs(partialRoot)) : 0.0;\n\n const firstRootReal = (-dampingCoefficient + partialRootReal) * 0.5;\n const firstRootImaginary = partialRootImaginary * 0.5;\n const secondRootReal = (-dampingCoefficient - partialRootReal) * 0.5;\n\n return estimateDurationInternal(\n firstRootReal,\n firstRootImaginary,\n secondRootReal,\n dampingRatio,\n initialVelocity,\n initialDisplacement,\n delta,\n );\n}\n\n/**\n * In the under-damped case we simply calculate the envelope of the function. The general solution\n * is of the form x(t) = c_1*e^(r*t)*cos(...) + c_2*e^(r*t)sin(...) which simplifies to x(t) =\n * c*e^(r*t)*cos(...) where c*e^(r*t) is the envelope of x(t)\n */\nfunction estimateUnderDamped(\n firstRootReal: number,\n firstRootImaginary: number,\n p0: number,\n v0: number,\n delta: number,\n): number {\n const r = firstRootReal;\n const c1 = p0;\n const c2 = (v0 - r * c1) / firstRootImaginary;\n const c = Math.sqrt(c1 * c1 + c2 * c2);\n\n return Math.log(delta / c) / r;\n}\n\nconst isNotFinite = (x: number) => !Number.isFinite(x);\n\nconst iterateNewtonsMethod = (\n x: number,\n fn: (t: number) => number,\n fnPrime: (t: number) => number,\n): number => x - fn(x) / fnPrime(x);\n\n/**\n * In the critically-damped case we apply Newton-Raphson's iterative numerical method of solving the\n * equation x(t) = c_1*e^(r*t) + c_2*t*e^(r*t)\n */\nfunction estimateCriticallyDamped(\n firstRootReal: number,\n p0: number,\n v0: number,\n delta: number,\n): number {\n const r = firstRootReal;\n const c1 = p0;\n const c2 = v0 - r * c1;\n\n // For our initial guess, determine the max t of c_1*e^(r*t) = delta and\n // c_2*t*e^(r*t) = delta\n const t1 = Math.log(Math.abs(delta / c1)) / r;\n const t2 =\n (() => {\n // Application of Lambert's W function to solve te^t\n const guess = Math.log(Math.abs(delta / c2));\n let t = guess;\n for (let i = 0; i <= 5; i++) {\n t = guess - Math.log(Math.abs(t / r));\n }\n return t;\n })() / r;\n let tCurr = isNotFinite(t1) ? t2 : isNotFinite(t2) ? t1 : Math.max(t1, t2);\n\n // Calculate the inflection time. This is important if the inflection is in t > 0\n const tInflection = -(r * c1 + c2) / (r * c2);\n const xInflection = c1 * Math.exp(r * tInflection) + c2 * tInflection * Math.exp(r * tInflection);\n\n // For inflection that does not exist in real time, we always solve for x(t)=delta. Note\n // the system is manipulated such that p0 is always positive.\n let signedDelta: number;\n if (Number.isNaN(tInflection) || tInflection <= 0.0) {\n signedDelta = -delta;\n } else if (tInflection > 0.0 && -xInflection < delta) {\n // In this scenario the first crossing with the threshold is to be found. Note that\n // the inflection does not exceed delta. As such, we search from the left.\n if (c2 < 0 && c1 > 0) {\n tCurr = 0.0;\n }\n signedDelta = -delta;\n } else {\n // In this scenario there are three total crossings of the threshold, once from\n // above, and then once when the inflection exceeds the threshold and then one last\n // one when x(t) finally decays to zero. The point of determining concavity is to\n // find the final crossing.\n //\n // By finding a point between when concavity changes, and when the inflection point is,\n // Newton's method will always converge onto the rightmost point (in this case),\n // the one that we are interested in.\n tCurr = -(2.0 / r) - c1 / c2;\n signedDelta = delta;\n }\n\n let tDelta = Number.MAX_VALUE;\n let iterations = 0;\n while (tDelta > 0.001 && iterations < 100) {\n iterations++;\n const tLast = tCurr;\n tCurr = iterateNewtonsMethod(\n tCurr,\n (t) => (c1 + c2 * t) * Math.exp(r * t) + signedDelta,\n (t) => (c2 * (r * t + 1) + c1 * r) * Math.exp(r * t),\n );\n tDelta = Math.abs(tLast - tCurr);\n }\n\n return tCurr;\n}\n\n/**\n * In the over-damped case we apply Newton-Raphson's iterative numerical method of solving the\n * equation x(t) = c_1*e^(r_1*t) + c_2*e^(r_2*t)\n */\nfunction estimateOverDamped(\n firstRootReal: number,\n secondRootReal: number,\n p0: number,\n v0: number,\n delta: number,\n): number {\n const r1 = firstRootReal;\n const r2 = secondRootReal;\n const c2 = (r1 * p0 - v0) / (r1 - r2);\n const c1 = p0 - c2;\n\n // For our initial guess, determine the max t of c_1*e^(r_1*t) = delta and\n // c_2*e^(r_2*t) = delta\n const t1 = Math.log(Math.abs(delta / c1)) / r1;\n const t2 = Math.log(Math.abs(delta / c2)) / r2;\n\n let tCurr = isNotFinite(t1) ? t2 : isNotFinite(t2) ? t1 : Math.max(t1, t2);\n\n // Calculate the inflection time. This is important if the inflection is in t > 0\n const tInflection = Math.log((c1 * r1) / (-c2 * r2)) / (r2 - r1);\n const xInflection = () => c1 * Math.exp(r1 * tInflection) + c2 * Math.exp(r2 * tInflection);\n\n // For inflection that does not exist in real time, we always solve for x(t)=delta. Note\n // the system is manipulated such that p0 is always positive.\n let signedDelta: number;\n if (Number.isNaN(tInflection) || tInflection <= 0.0) {\n signedDelta = -delta;\n } else if (tInflection > 0.0 && -xInflection() < delta) {\n // In this scenario the first crossing with the threshold is to be found. Note that\n // the inflection does not exceed delta. As such, we search from the left.\n if (c2 > 0.0 && c1 < 0.0) {\n tCurr = 0.0;\n }\n signedDelta = -delta;\n } else {\n // In this scenario there are three total crossings of the threshold, once from\n // above, and then once when the inflection exceeds the threshold and then one last\n // one when x(t) finally decays to zero. The point of determining concavity is to\n // find the final crossing.\n //\n // By finding a point between when concavity changes, and when the inflection point is,\n // Newton's method will always converge onto the rightmost point (in this case),\n // the one that we are interested in.\n tCurr = Math.log(-(c2 * r2 * r2) / (c1 * r1 * r1)) / (r1 - r2);\n signedDelta = delta;\n }\n\n // For a good initial guess, simply return\n if (Math.abs(c1 * r1 * Math.exp(r1 * tCurr) + c2 * r2 * Math.exp(r2 * tCurr)) < 0.0001) {\n return tCurr;\n }\n let tDelta = Number.MAX_VALUE;\n\n // Cap iterations for safety - Experimentally this method takes <= 5 iterations\n let iterations = 0;\n while (tDelta > 0.001 && iterations < 100) {\n iterations++;\n const tLast = tCurr;\n tCurr = iterateNewtonsMethod(\n tCurr,\n (t) => c1 * Math.exp(r1 * t) + c2 * Math.exp(r2 * t) + signedDelta,\n (t) => c1 * r1 * Math.exp(r1 * t) + c2 * r2 * Math.exp(r2 * t),\n );\n tDelta = Math.abs(tLast - tCurr);\n }\n\n return tCurr;\n}\n\n// Applies Newton-Raphson's method to solve for the estimated time the spring mass system will\n// last be at [delta].\nfunction estimateDurationInternal(\n firstRootReal: number,\n firstRootImaginary: number,\n secondRootReal: number,\n dampingRatio: number,\n initialVelocity: number,\n initialPosition: number,\n delta: number,\n): number {\n if (initialPosition === 0.0 && initialVelocity === 0.0) {\n return 0;\n }\n\n const v0 = initialPosition < 0 ? -initialVelocity : initialVelocity;\n const p0 = Math.abs(initialPosition);\n\n const seconds =\n dampingRatio > 1.0\n ? estimateOverDamped(firstRootReal, secondRootReal, p0, v0, delta)\n : dampingRatio < 1.0\n ? estimateUnderDamped(firstRootReal, firstRootImaginary, p0, v0, delta)\n : estimateCriticallyDamped(firstRootReal, p0, v0, delta);\n return toLong(seconds * 1000.0);\n}\n","/*\n * Copyright 2019 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n// Ported to TypeScript by Kyra Labs from compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SpringSimulation.kt@19991f2c0858aadfcb442ce02b2c8e4743c96898\n//\n// Precision follows the Kotlin source: parameters and results are Float (Math.fround), the\n// solution is computed in Double, and time is whole milliseconds.\n\nconst f32 = Math.fround;\n\n/** `Spring.StiffnessVeryLow` / `Spring.DampingRatioNoBouncy` (VectorizedAnimationSpec.kt L813, L839). */\nconst STIFFNESS_VERY_LOW = 50;\nconst DAMPING_RATIO_NO_BOUNCY = 1;\n\nexport interface Motion {\n value: number;\n velocity: number;\n}\n\n/**\n * Spring Simulation simulates spring physics, and allows you to query the motion (i.e. value and\n * velocity) at certain time in the future based on the starting velocity and value.\n *\n * By configuring the stiffness and damping ratio, callers can create a spring with the look and\n * feel suits their use case. Stiffness corresponds to the spring constant. The stiffer the spring\n * is, the harder it is to stretch it, the faster it undergoes dampening.\n *\n * Spring damping ratio describes how oscillations in a system decay after a disturbance. When\n * damping ratio > 1* (i.e. over-damped), the object will quickly return to the rest position\n * without overshooting. If damping ratio equals to 1 (i.e. critically damped), the object will\n * return to equilibrium within the shortest amount of time. When damping ratio is less than 1 (i.e.\n * under-damped), the mass tends to overshoot, and return, and overshoot again. Without any damping\n * (i.e. damping ratio = 0), the mass will oscillate forever.\n */\nexport class SpringSimulation {\n // Natural frequency\n #naturalFreq = Math.sqrt(STIFFNESS_VERY_LOW);\n #dampingRatio = DAMPING_RATIO_NO_BOUNCY;\n #finalPosition: number;\n\n constructor(finalPosition: number) {\n this.#finalPosition = f32(finalPosition);\n }\n\n get finalPosition(): number {\n return this.#finalPosition;\n }\n\n set finalPosition(value: number) {\n this.#finalPosition = f32(value);\n }\n\n /** Stiffness of the spring. */\n get stiffness(): number {\n return f32(this.#naturalFreq * this.#naturalFreq);\n }\n\n set stiffness(value: number) {\n // Upstream checks the *current* stiffness here (always positive), so the new value is not\n // validated; kept as-is for parity.\n if (this.stiffness <= 0) {\n throw new RangeError('Spring stiffness constant must be positive.');\n }\n this.#naturalFreq = Math.sqrt(f32(value));\n }\n\n /** Returns the damping ratio of the spring. */\n get dampingRatio(): number {\n return this.#dampingRatio;\n }\n\n set dampingRatio(value: number) {\n if (value < 0) {\n throw new RangeError('Damping ratio must be non-negative');\n }\n this.#dampingRatio = f32(value);\n }\n\n getAcceleration(lastDisplacement: number, lastVelocity: number): number {\n const adjustedDisplacement = f32(f32(lastDisplacement) - this.#finalPosition);\n\n const k = this.#naturalFreq * this.#naturalFreq;\n const c = 2.0 * this.#naturalFreq * this.#dampingRatio;\n\n return f32(-k * adjustedDisplacement - c * f32(lastVelocity));\n }\n\n /**\n * Internal only call for Spring to calculate the spring position/velocity using an analytical\n * approach.\n */\n updateValues(lastDisplacement: number, lastVelocity: number, timeElapsed: number): Motion {\n const dampingRatio = this.#dampingRatio;\n const naturalFreq = this.#naturalFreq;\n const velocity0 = f32(lastVelocity);\n const adjustedDisplacement = f32(f32(lastDisplacement) - this.#finalPosition);\n const deltaT = Math.trunc(timeElapsed) / 1000.0; // unit: seconds\n const dampingRatioSquared = dampingRatio * dampingRatio;\n const r = -dampingRatio * naturalFreq;\n\n let displacement: number;\n let currentVelocity: number;\n\n if (dampingRatio > 1) {\n // Over damping\n const s = naturalFreq * Math.sqrt(dampingRatioSquared - 1);\n const gammaPlus = r + s;\n const gammaMinus = r - s;\n\n // Overdamped\n const coeffB = (gammaMinus * adjustedDisplacement - velocity0) / (gammaMinus - gammaPlus);\n const coeffA = adjustedDisplacement - coeffB;\n displacement = coeffA * Math.exp(gammaMinus * deltaT) + coeffB * Math.exp(gammaPlus * deltaT);\n currentVelocity =\n coeffA * gammaMinus * Math.exp(gammaMinus * deltaT) +\n coeffB * gammaPlus * Math.exp(gammaPlus * deltaT);\n } else if (dampingRatio === 1.0) {\n // Critically damped\n const coeffA = adjustedDisplacement;\n const coeffB = velocity0 + naturalFreq * adjustedDisplacement;\n const nFdT = -naturalFreq * deltaT;\n displacement = (coeffA + coeffB * deltaT) * Math.exp(nFdT);\n currentVelocity =\n (coeffA + coeffB * deltaT) * Math.exp(nFdT) * -naturalFreq + coeffB * Math.exp(nFdT);\n } else {\n const dampedFreq = naturalFreq * Math.sqrt(1 - dampingRatioSquared);\n // Underdamped\n const cosCoeff = adjustedDisplacement;\n const sinCoeff = (1 / dampedFreq) * (-r * adjustedDisplacement + velocity0);\n const dFdT = dampedFreq * deltaT;\n displacement = Math.exp(r * deltaT) * (cosCoeff * Math.cos(dFdT) + sinCoeff * Math.sin(dFdT));\n currentVelocity =\n displacement * r +\n Math.exp(r * deltaT) *\n (-dampedFreq * cosCoeff * Math.sin(dFdT) + dampedFreq * sinCoeff * Math.cos(dFdT));\n }\n\n return {\n value: f32(displacement + this.#finalPosition),\n velocity: f32(currentVelocity),\n };\n }\n}\n","// Spring helpers with Compose `FloatSpringSpec` semantics (animation-core FloatAnimationSpec.kt\n// L133–187 @19991f2c), built on the ported SpringSimulation / SpringEstimation.\nimport { estimateAnimationDurationMillis } from './spring-estimation.js';\nimport { SpringSimulation } from './spring-simulation.js';\n\n/** A Material motion-scheme spring (`dampingRatio` ζ, `stiffness` k; mass 1). */\nexport interface SpringSpec {\n readonly dampingRatio: number;\n readonly stiffness: number;\n}\n\n/** `Spring.DefaultDisplacementThreshold` (VectorizedAnimationSpec.kt L842). */\nexport const DEFAULT_DISPLACEMENT_THRESHOLD = 0.01;\n\nconst f32 = Math.fround;\n\nfunction simulation(spec: SpringSpec, targetValue: number): SpringSimulation {\n const sim = new SpringSimulation(targetValue);\n sim.dampingRatio = spec.dampingRatio;\n sim.stiffness = spec.stiffness;\n return sim;\n}\n\n/** Value at `playTimeMillis` (whole milliseconds, as in Compose). */\nexport function springValue(\n spec: SpringSpec,\n playTimeMillis: number,\n initialValue: number,\n targetValue: number,\n initialVelocity = 0,\n): number {\n return simulation(spec, targetValue).updateValues(initialValue, initialVelocity, playTimeMillis)\n .value;\n}\n\n/** Velocity (units/s) at `playTimeMillis`. */\nexport function springVelocity(\n spec: SpringSpec,\n playTimeMillis: number,\n initialValue: number,\n targetValue: number,\n initialVelocity = 0,\n): number {\n return simulation(spec, targetValue).updateValues(initialValue, initialVelocity, playTimeMillis)\n .velocity;\n}\n\n/**\n * Duration until the spring stays within `visibilityThreshold` of the target, as Compose computes\n * it (`FloatSpringSpec.getDurationNanos` / 1e6).\n */\nexport function springDurationMillis(\n spec: SpringSpec,\n initialValue: number,\n targetValue: number,\n initialVelocity = 0,\n visibilityThreshold = DEFAULT_DISPLACEMENT_THRESHOLD,\n): number {\n const sim = simulation(spec, targetValue);\n const threshold = f32(visibilityThreshold);\n return estimateAnimationDurationMillis(\n sim.stiffness,\n sim.dampingRatio,\n f32(f32(initialVelocity) / threshold),\n f32(f32(f32(initialValue) - f32(targetValue)) / threshold),\n 1,\n );\n}\n\n/**\n * Damping coefficient c = 2ζ√(k·m), for physics engines parameterized by stiffness/damping/mass\n * (e.g. Motion's `{ type: 'spring', stiffness, damping, mass }`).\n */\nexport function dampingCoefficient(spec: SpringSpec, mass = 1): number {\n return 2 * spec.dampingRatio * Math.sqrt(spec.stiffness * mass);\n}\n\n/** Inverse of {@link dampingCoefficient}: ζ = c / (2√(k·m)). */\nexport function dampingRatioFromCoefficient(damping: number, stiffness: number, mass = 1): number {\n return damping / (2 * Math.sqrt(stiffness * mass));\n}\n","// CSS `linear()` approximation of a spring (FOUNDATIONS §4).\n//\n// - Duration: Compose's own settle estimate (`FloatSpringSpec.getDurationNanos`) for a 0 → 1\n// animation at a visibility threshold of 0.001 (0.1% of the travel; e.g. Compose's 0.1 dp\n// Dp threshold over a 100 dp move).\n// - Samples: the exact spring at every whole millisecond (Compose's time resolution), last stop\n// forced to 1 so the animation lands on its target.\n// - Stops: Ramer–Douglas–Peucker in (progress, value) space with the smallest tolerance that fits\n// `maxStops`.\n//\n// Limits (FOUNDATIONS §4): no velocity carry-over on interruption and a fixed duration; use the JS\n// spring for drags, rapid toggles and other interruptible motion.\nimport { type SpringSpec, springDurationMillis } from './spring.js';\nimport { SpringSimulation } from './spring-simulation.js';\n\nexport interface LinearEasingOptions {\n /** Fraction of the travel considered settled. Default 0.001. */\n visibilityThreshold?: number;\n /** Maximum stops in the `linear()` function (FOUNDATIONS §4: ≤ 40). Default 40. */\n maxStops?: number;\n}\n\nexport interface LinearEasing {\n /** e.g. `linear(0, 0.1234 5%, …, 1)` */\n easing: string;\n durationMillis: number;\n /** `[progress 0–1, value]` pairs after rounding. */\n stops: readonly (readonly [number, number])[];\n /** Max |linear(t) − spring(t)| over every millisecond sample. */\n maxError: number;\n}\n\nconst round = (n: number, digits: number) => {\n const r = Number(n.toFixed(digits));\n return Object.is(r, -0) ? 0 : r;\n};\n\ntype Point = readonly [number, number];\n\nfunction at<T>(list: readonly T[], i: number): T {\n const item = list[i];\n if (item === undefined) throw new RangeError(`index ${String(i)} out of range`);\n return item;\n}\n\n/** Ramer–Douglas–Peucker: indices of points to keep (vertical distance, monotone x). */\nfunction simplify(points: readonly Point[], tolerance: number): number[] {\n const keep = new Set<number>([0, points.length - 1]);\n const stack: [number, number][] = [[0, points.length - 1]];\n for (let range = stack.pop(); range; range = stack.pop()) {\n const [a, b] = range;\n const [x0, y0] = at(points, a);\n const [x1, y1] = at(points, b);\n let worst = -1;\n let worstDistance = tolerance;\n for (let i = a + 1; i < b; i++) {\n const [x, y] = at(points, i);\n const expected = y0 + ((y1 - y0) * (x - x0)) / (x1 - x0);\n const distance = Math.abs(y - expected);\n if (distance > worstDistance) {\n worst = i;\n worstDistance = distance;\n }\n }\n if (worst !== -1) {\n keep.add(worst);\n stack.push([a, worst], [worst, b]);\n }\n }\n return [...keep].sort((x, y) => x - y);\n}\n\nfunction interpolate(stops: readonly Point[], x: number): number {\n for (let i = 1; i < stops.length; i++) {\n const [x1, y1] = at(stops, i);\n const [x0, y0] = at(stops, i - 1);\n if (x <= x1) return x1 === x0 ? y1 : y0 + ((y1 - y0) * (x - x0)) / (x1 - x0);\n }\n return at(stops, stops.length - 1)[1];\n}\n\nexport function springToLinear(spec: SpringSpec, options: LinearEasingOptions = {}): LinearEasing {\n const { visibilityThreshold = 0.001, maxStops = 40 } = options;\n if (maxStops < 2) throw new RangeError('maxStops must be at least 2');\n const durationMillis = Math.max(1, springDurationMillis(spec, 0, 1, 0, visibilityThreshold));\n\n const sim = new SpringSimulation(1);\n sim.dampingRatio = spec.dampingRatio;\n sim.stiffness = spec.stiffness;\n const samples: Point[] = [];\n for (let t = 0; t <= durationMillis; t++) {\n samples.push([t / durationMillis, sim.updateValues(0, 0, t).value]);\n }\n samples[samples.length - 1] = [1, 1];\n\n // Smallest tolerance (bisection) whose simplification fits maxStops.\n let lo = 0;\n let hi = 0.5;\n let best = simplify(samples, hi);\n for (let i = 0; i < 40; i++) {\n const mid = (lo + hi) / 2;\n const kept = simplify(samples, mid);\n if (kept.length <= maxStops) {\n best = kept;\n hi = mid;\n } else {\n lo = mid;\n }\n }\n\n const stops = best.map((i) => {\n const [x, y] = at(samples, i);\n return [round(x, 4), round(y, 4)] as const;\n });\n const maxError = samples.reduce(\n (m, [x, y]) => Math.max(m, Math.abs(interpolate(stops, x) - y)),\n 0,\n );\n const body = stops.map(([x, y], i) =>\n i === 0 || i === stops.length - 1 ? String(y) : `${String(y)} ${String(round(x * 100, 2))}%`,\n );\n return { easing: `linear(${body.join(', ')})`, durationMillis, stops, maxError };\n}\n","/*\n * Copyright 2024 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n// Ported to TypeScript by Kyra Labs from compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/LoadingIndicator.kt@19991f2c0858aadfcb442ce02b2c8e4743c96898\n//\n// The indeterminate LoadingIndicator's LaunchedEffect (L391–451) as a pure function of elapsed\n// time. Compose runs two coroutines:\n// - every MorphIntervalMillis a spring animates the morph progress 0 → 1; when it finishes, the\n// indicator advances to the next morph, snaps the progress to 0 and adds a quarter turn to the\n// morph rotation. The loop then waits for the rest of the interval (or for the spring, if it is\n// slower than the interval);\n// - a linear global rotation turns 360° every GlobalRotationDurationMillis, restarting.\n// The drawn rotation is `progress × 90 + morphRotationTargetAngle + globalRotation` (L473).\n// The interval, rotation duration and spring are tokens (components/loading-indicator-motion.css).\n\nimport { type SpringSpec, springDurationMillis, springValue } from './spring.js';\n\nconst FULL_ROTATION = 360;\nconst QUARTER_ROTATION = FULL_ROTATION / 4;\n\nexport interface LoadingIndicatorTiming {\n /** `MorphIntervalMillis`: how often a morph starts. */\n readonly morphIntervalMillis: number;\n /** `GlobalRotationDurationMillis`: one linear turn. */\n readonly rotationDurationMillis: number;\n /** The morph spring (`morphAnimationSpec`). */\n readonly spring: SpringSpec;\n /** The morph spring's `visibilityThreshold`; it decides when the spring finishes. */\n readonly visibilityThreshold: number;\n}\n\n/** What the indicator draws: a morph at a progress, rotated clockwise about the center. */\nexport interface IndeterminateFrame {\n morphIndex: number;\n /** The raw spring value: it overshoots past 1, as in Compose (the morph extrapolates). */\n morphProgress: number;\n /** Degrees, clockwise. */\n rotation: number;\n}\n\n/**\n * The first frame (and the one held under reduced motion): the first morph at 0, rotated by the\n * initial `morphRotationTargetAngle` (a quarter turn).\n */\nexport const initialIndeterminateFrame: Readonly<IndeterminateFrame> = {\n morphIndex: 0,\n morphProgress: 0,\n rotation: QUARTER_ROTATION,\n};\n\n/** How long one morph spring runs (Compose's `FloatSpringSpec.getDurationNanos`), in ms. */\nexport const morphSpringDurationMillis = (timing: LoadingIndicatorTiming): number =>\n springDurationMillis(timing.spring, 0, 1, 0, timing.visibilityThreshold);\n\n/**\n * The frame of an indeterminate loading indicator [elapsedMillis] after it started, cycling\n * through [morphCount] morphs.\n */\nexport function indeterminateFrame(\n elapsedMillis: number,\n morphCount: number,\n timing: LoadingIndicatorTiming,\n): IndeterminateFrame {\n const t = Math.max(0, elapsedMillis);\n const springMillis = morphSpringDurationMillis(timing);\n // `delay(MorphIntervalMillis)` then `deferred.await()`: the next morph starts after both.\n const period = Math.max(timing.morphIntervalMillis, springMillis);\n const completed = Math.floor(t / period);\n const local = t - completed * period;\n const running = local < springMillis;\n // Each finished spring advances the index and adds a quarter turn (starting at a quarter turn).\n const finished = running ? completed : completed + 1;\n const morphIndex = finished % morphCount;\n const targetAngle = (QUARTER_ROTATION * (finished + 1)) % FULL_ROTATION;\n // Compose samples the spring at whole milliseconds of play time.\n const morphProgress = running ? springValue(timing.spring, Math.floor(local), 0, 1) : 0;\n const globalRotation =\n (FULL_ROTATION * Math.floor(t % timing.rotationDurationMillis)) / timing.rotationDurationMillis;\n return {\n morphIndex,\n morphProgress,\n rotation: morphProgress * QUARTER_ROTATION + targetAngle + globalRotation,\n };\n}\n","/*\n * Copyright 2021 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n// Ported to TypeScript by Kyra Labs from compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/AppBar.kt@19991f2c0858aadfcb442ce02b2c8e4743c96898\n//\n// TopAppBarState (L2050-2130), the pinned and enter-always scroll behaviors (L3267-3303,\n// L3400-3455) and the settle decision of settleAppBar (L3542-3589), adapted to DOM scrolling.\n// Compose receives nested\n// scroll deltas and can consume them; the web observes `scrollTop` after the browser scrolled, so\n// every delta goes to both the bar and the content, and momentum comes from the browser instead\n// of flingAnimationSpec. Offsets are in CSS px; y grows downward, so collapsing is negative.\n\n/** How the bar reacts to its scroll container (TopAppBarDefaults.*ScrollBehavior). */\nexport type AppBarScrollBehavior = 'pinned' | 'enter-always';\n\nexport interface AppBarScrollState {\n /** Most negative height offset: minus the bar's full height (adjustHeightOffsetLimit). */\n readonly heightOffsetLimit: number;\n /** Current height offset, between heightOffsetLimit and 0. */\n readonly heightOffset: number;\n /** Content scrolled under the bar (minus the scroll position). */\n readonly contentOffset: number;\n /** Whether the scrolling content is at its start (scroll position 0). */\n readonly atStart: boolean;\n}\n\n/** A fully expanded bar of `height` px over unscrolled content. */\nexport function appBarScrollState(height: number): AppBarScrollState {\n return { heightOffsetLimit: -height, heightOffset: 0, contentOffset: 0, atStart: true };\n}\n\n/** TopAppBarState.heightOffset setter: coerced between heightOffsetLimit and 0. */\nexport function withHeightOffset(state: AppBarScrollState, offset: number): AppBarScrollState {\n return { ...state, heightOffset: Math.min(Math.max(offset, state.heightOffsetLimit), 0) };\n}\n\n/** A new bar height (onSizeChanged → adjustHeightOffsetLimit), keeping the offset in range. */\nexport function withHeight(state: AppBarScrollState, height: number): AppBarScrollState {\n return withHeightOffset({ ...state, heightOffsetLimit: -height }, state.heightOffset);\n}\n\n/** 0 = fully expanded, 1 = fully collapsed (TopAppBarState.collapsedFraction). */\nexport function collapsedFraction(state: AppBarScrollState): number {\n // `+ 0` turns the -0 of 0 / -height into 0.\n return state.heightOffsetLimit !== 0 ? state.heightOffset / state.heightOffsetLimit + 0 : 0;\n}\n\n/** Share of the visible bar overlapping scrolled content (TopAppBarState.overlappedFraction). */\nexport function overlappedFraction(state: AppBarScrollState): number {\n if (!state.atStart && state.contentOffset === 0) return 1;\n if (state.heightOffsetLimit === 0) return 0;\n const limit = state.heightOffsetLimit;\n const clamped = Math.min(Math.max(limit + Math.abs(state.contentOffset), limit), 0);\n return 1 - clamped / limit;\n}\n\n/**\n * Whether the bar shows its scrolled container color: SingleRowTopAppBar targets the scrolled\n * color once `overlappedFraction > 0.01f` (L2689-2693).\n */\nexport function isScrolledUnder(state: AppBarScrollState): boolean {\n return overlappedFraction(state) > 0.01;\n}\n\n/**\n * Applies a scroll position change. `delta` is the previous minus the new scroll position\n * (positive when the content is pulled down, like Compose's `available.y`).\n * - pinned: only the content offset moves (PinnedScrollBehavior.onPostScroll).\n * - enter-always: the bar also collapses/expands by the same amount\n * (EnterAlwaysScrollBehavior.onPreScroll: `heightOffset += available.y`).\n */\nexport function scrollAppBar(\n state: AppBarScrollState,\n behavior: AppBarScrollBehavior,\n scrollTop: number,\n delta: number,\n): AppBarScrollState {\n const next: AppBarScrollState = { ...state, contentOffset: -scrollTop, atStart: scrollTop <= 0 };\n return behavior === 'enter-always' ? withHeightOffset(next, state.heightOffset + delta) : next;\n}\n\n/**\n * Where a partially collapsed bar snaps when scrolling stops (settleAppBar): fully expanded below\n * half, fully collapsed from half, or null when it is already (within 1%) settled.\n */\nexport function settleTarget(state: AppBarScrollState): number | null {\n const fraction = collapsedFraction(state);\n if (fraction < 0.01 || fraction === 1) return null;\n if (!(state.heightOffset < 0 && state.heightOffset > state.heightOffsetLimit)) return null;\n return fraction < 0.5 ? 0 : state.heightOffsetLimit;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,52 @@
1
1
  {
2
2
  "name": "@kyralabs/m3e-motion",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.1",
4
+ "description": "Spring and easing math for m3exp-web (internal-first).",
5
+ "keywords": [
6
+ "material-design",
7
+ "material-3",
8
+ "material-you",
9
+ "m3-expressive",
10
+ "design-system",
11
+ "spring",
12
+ "animation",
13
+ "motion"
14
+ ],
15
+ "license": "Apache-2.0",
16
+ "author": "Kyra Labs",
17
+ "homepage": "https://github.com/kyra-labs/m3exp-web/tree/main/packages/m3e-motion#readme",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "https://github.com/kyra-labs/m3exp-web",
21
+ "directory": "packages/m3e-motion"
22
+ },
23
+ "bugs": "https://github.com/kyra-labs/m3exp-web/issues",
24
+ "type": "module",
25
+ "main": "./dist/index.js",
26
+ "module": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "sideEffects": false,
29
+ "exports": {
30
+ ".": {
31
+ "@kyralabs/source": "./src/index.ts",
32
+ "types": "./dist/index.d.ts",
33
+ "import": "./dist/index.js",
34
+ "default": "./dist/index.js"
35
+ },
36
+ "./package.json": "./package.json"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "LICENSE",
41
+ "NOTICE",
42
+ "README.md"
43
+ ],
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "provenance": true
47
+ },
48
+ "scripts": {
49
+ "build": "tsup",
50
+ "typecheck": "tsc --noEmit -p tsconfig.json"
51
+ }
6
52
  }