@kyralabs/m3e-motion 0.0.0-stage → 1.0.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/LICENSE +201 -0
- package/NOTICE +50 -0
- package/README.md +21 -2
- package/dist/index.d.ts +160 -0
- package/dist/index.js +403 -0
- package/dist/index.js.map +1 -0
- package/package.json +49 -3
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
|
-
#
|
|
1
|
+
# @kyralabs/m3e-motion
|
|
2
2
|
|
|
3
|
-
|
|
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`.
|
package/dist/index.d.ts
ADDED
|
@@ -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": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.0",
|
|
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
|
}
|