tensum 0.1.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.
Files changed (134) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +21 -0
  3. package/README.md +340 -0
  4. package/dist/coupled-system.d.ts +50 -0
  5. package/dist/coupled-system.d.ts.map +1 -0
  6. package/dist/coupled-system.js +269 -0
  7. package/dist/coupled-system.js.map +1 -0
  8. package/dist/coupled.d.ts +3 -0
  9. package/dist/coupled.d.ts.map +1 -0
  10. package/dist/coupled.js +2 -0
  11. package/dist/coupled.js.map +1 -0
  12. package/dist/css-linear.d.ts +20 -0
  13. package/dist/css-linear.d.ts.map +1 -0
  14. package/dist/css-linear.js +95 -0
  15. package/dist/css-linear.js.map +1 -0
  16. package/dist/css.d.ts +3 -0
  17. package/dist/css.d.ts.map +1 -0
  18. package/dist/css.js +2 -0
  19. package/dist/css.js.map +1 -0
  20. package/dist/gsap/active-tracks.d.ts +32 -0
  21. package/dist/gsap/active-tracks.d.ts.map +1 -0
  22. package/dist/gsap/active-tracks.js +177 -0
  23. package/dist/gsap/active-tracks.js.map +1 -0
  24. package/dist/gsap/gsap-time.d.ts +10 -0
  25. package/dist/gsap/gsap-time.d.ts.map +1 -0
  26. package/dist/gsap/gsap-time.js +62 -0
  27. package/dist/gsap/gsap-time.js.map +1 -0
  28. package/dist/gsap/plugin-tween-coordinator.d.ts +30 -0
  29. package/dist/gsap/plugin-tween-coordinator.d.ts.map +1 -0
  30. package/dist/gsap/plugin-tween-coordinator.js +72 -0
  31. package/dist/gsap/plugin-tween-coordinator.js.map +1 -0
  32. package/dist/gsap/plugin.d.ts +84 -0
  33. package/dist/gsap/plugin.d.ts.map +1 -0
  34. package/dist/gsap/plugin.js +552 -0
  35. package/dist/gsap/plugin.js.map +1 -0
  36. package/dist/gsap/spring-to.d.ts +93 -0
  37. package/dist/gsap/spring-to.d.ts.map +1 -0
  38. package/dist/gsap/spring-to.js +569 -0
  39. package/dist/gsap/spring-to.js.map +1 -0
  40. package/dist/gsap/spring-track-policy.d.ts +24 -0
  41. package/dist/gsap/spring-track-policy.d.ts.map +1 -0
  42. package/dist/gsap/spring-track-policy.js +76 -0
  43. package/dist/gsap/spring-track-policy.js.map +1 -0
  44. package/dist/gsap/track-lifecycle.d.ts +16 -0
  45. package/dist/gsap/track-lifecycle.d.ts.map +1 -0
  46. package/dist/gsap/track-lifecycle.js +33 -0
  47. package/dist/gsap/track-lifecycle.js.map +1 -0
  48. package/dist/index.d.ts +28 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +16 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/math.d.ts +9 -0
  53. package/dist/math.d.ts.map +1 -0
  54. package/dist/math.js +38 -0
  55. package/dist/math.js.map +1 -0
  56. package/dist/model.d.ts +14 -0
  57. package/dist/model.d.ts.map +1 -0
  58. package/dist/model.js +38 -0
  59. package/dist/model.js.map +1 -0
  60. package/dist/motion-compatibility.d.ts +18 -0
  61. package/dist/motion-compatibility.d.ts.map +1 -0
  62. package/dist/motion-compatibility.js +83 -0
  63. package/dist/motion-compatibility.js.map +1 -0
  64. package/dist/parameters.d.ts +52 -0
  65. package/dist/parameters.d.ts.map +1 -0
  66. package/dist/parameters.js +124 -0
  67. package/dist/parameters.js.map +1 -0
  68. package/dist/settling.d.ts +12 -0
  69. package/dist/settling.d.ts.map +1 -0
  70. package/dist/settling.js +107 -0
  71. package/dist/settling.js.map +1 -0
  72. package/dist/solver.d.ts +17 -0
  73. package/dist/solver.d.ts.map +1 -0
  74. package/dist/solver.js +190 -0
  75. package/dist/solver.js.map +1 -0
  76. package/dist/spring.d.ts +9 -0
  77. package/dist/spring.d.ts.map +1 -0
  78. package/dist/spring.js +91 -0
  79. package/dist/spring.js.map +1 -0
  80. package/dist/support/additive-spring-value.d.ts +39 -0
  81. package/dist/support/additive-spring-value.d.ts.map +1 -0
  82. package/dist/support/additive-spring-value.js +281 -0
  83. package/dist/support/additive-spring-value.js.map +1 -0
  84. package/dist/support/inertia.d.ts +34 -0
  85. package/dist/support/inertia.d.ts.map +1 -0
  86. package/dist/support/inertia.js +293 -0
  87. package/dist/support/inertia.js.map +1 -0
  88. package/dist/support/keyframes.d.ts +34 -0
  89. package/dist/support/keyframes.d.ts.map +1 -0
  90. package/dist/support/keyframes.js +117 -0
  91. package/dist/support/keyframes.js.map +1 -0
  92. package/dist/support/spring-value.d.ts +38 -0
  93. package/dist/support/spring-value.d.ts.map +1 -0
  94. package/dist/support/spring-value.js +289 -0
  95. package/dist/support/spring-value.js.map +1 -0
  96. package/dist/support/velocity.d.ts +14 -0
  97. package/dist/support/velocity.d.ts.map +1 -0
  98. package/dist/support/velocity.js +75 -0
  99. package/dist/support/velocity.js.map +1 -0
  100. package/dist/types.d.ts +61 -0
  101. package/dist/types.d.ts.map +1 -0
  102. package/dist/types.js +2 -0
  103. package/dist/types.js.map +1 -0
  104. package/dist/vector.d.ts +32 -0
  105. package/dist/vector.d.ts.map +1 -0
  106. package/dist/vector.js +121 -0
  107. package/dist/vector.js.map +1 -0
  108. package/package.json +68 -0
  109. package/src/coupled-system.ts +383 -0
  110. package/src/coupled.ts +10 -0
  111. package/src/css-linear.ts +148 -0
  112. package/src/css.ts +6 -0
  113. package/src/gsap/active-tracks.ts +244 -0
  114. package/src/gsap/gsap-time.ts +91 -0
  115. package/src/gsap/plugin-tween-coordinator.ts +112 -0
  116. package/src/gsap/plugin.ts +861 -0
  117. package/src/gsap/spring-to.ts +836 -0
  118. package/src/gsap/spring-track-policy.ts +133 -0
  119. package/src/gsap/track-lifecycle.ts +53 -0
  120. package/src/index.ts +130 -0
  121. package/src/math.ts +46 -0
  122. package/src/model.ts +70 -0
  123. package/src/motion-compatibility.ts +131 -0
  124. package/src/parameters.ts +226 -0
  125. package/src/settling.ts +141 -0
  126. package/src/solver.ts +262 -0
  127. package/src/spring.ts +119 -0
  128. package/src/support/additive-spring-value.ts +343 -0
  129. package/src/support/inertia.ts +367 -0
  130. package/src/support/keyframes.ts +188 -0
  131. package/src/support/spring-value.ts +399 -0
  132. package/src/support/velocity.ts +119 -0
  133. package/src/types.ts +70 -0
  134. package/src/vector.ts +191 -0
@@ -0,0 +1,93 @@
1
+ import type { SpringParameters, SpringSettleInput, SpringSolution, SpringState } from '../types.js';
2
+ import type { UnsettledPolicy } from './spring-track-policy.js';
3
+ export declare const SUPPORTED_PROPERTIES: readonly ["x", "y", "scale", "rotation"];
4
+ export type BuiltInSpringProperty = (typeof SUPPORTED_PROPERTIES)[number];
5
+ export type SpringProperty = string;
6
+ export type SpringTargetValue = number | string;
7
+ export type SpringTargets = Readonly<Partial<Record<SpringProperty, SpringTargetValue>>>;
8
+ export type SpringVelocities = Readonly<Partial<Record<SpringProperty, number>>>;
9
+ type SpringMap<Value> = Readonly<Partial<Record<SpringProperty, Value>>> & Readonly<Partial<Record<BuiltInSpringProperty, Value>>>;
10
+ export type SpringStateMap = SpringMap<SpringState>;
11
+ export type SpringSolutionMap = SpringMap<SpringSolution>;
12
+ export type SpringTweenTarget = Exclude<gsap.TweenTarget, string | null>;
13
+ export type { UnsettledPolicy } from './spring-track-policy.js';
14
+ export interface SpringPropertyAdapter {
15
+ read(target: SpringTweenTarget): number;
16
+ write(target: SpringTweenTarget, value: number): void;
17
+ unit?: string;
18
+ }
19
+ export interface SpringPropertyOptions extends Partial<SpringParameters> {
20
+ velocity?: number;
21
+ settle?: SpringSettleInput;
22
+ }
23
+ export interface SpringTrackConfig {
24
+ spring: SpringParameters & {
25
+ settle?: SpringSettleInput;
26
+ };
27
+ velocity?: number | SpringVelocities;
28
+ properties?: Readonly<Partial<Record<SpringProperty, SpringPropertyOptions>>>;
29
+ adapters?: Readonly<Partial<Record<SpringProperty, SpringPropertyAdapter>>>;
30
+ units?: Readonly<Partial<Record<SpringProperty, string>>>;
31
+ }
32
+ export interface SpringToSnapshot {
33
+ elapsed: number;
34
+ duration: number;
35
+ states: SpringStateMap;
36
+ }
37
+ export interface SpringToVars extends SpringTrackConfig {
38
+ x?: SpringTargetValue;
39
+ y?: SpringTargetValue;
40
+ scale?: SpringTargetValue;
41
+ rotation?: SpringTargetValue;
42
+ targets?: SpringTargets;
43
+ /** Behavior when a track reaches `maxDuration` without settling. */
44
+ unsettled?: UnsettledPolicy;
45
+ /** Runs for each rendered update while this controller owns any track. */
46
+ onUpdate?: (snapshot: SpringToSnapshot) => void;
47
+ /** Runs at each forward logical-completion crossing. */
48
+ onLogicalComplete?: (snapshot: SpringToSnapshot) => void;
49
+ /** Runs at each forward physical-settlement crossing. */
50
+ onSettle?: (snapshot: SpringToSnapshot) => void;
51
+ /** Runs at each forward `maxDuration` crossing for an unsettled track. */
52
+ onUnsettled?: (snapshot: SpringToSnapshot) => void;
53
+ /** Runs after the finite GSAP driver completes. */
54
+ onComplete?: () => void;
55
+ }
56
+ export interface SpringController {
57
+ readonly duration: number;
58
+ readonly springs: SpringSolutionMap;
59
+ readonly tween: gsap.core.Tween;
60
+ getSnapshot(): SpringToSnapshot;
61
+ play(): void;
62
+ pause(): void;
63
+ resume(): void;
64
+ stop(): void;
65
+ seek(time: number): void;
66
+ playbackReverse(): void;
67
+ kill(): void;
68
+ }
69
+ export interface RequestedTarget {
70
+ value: number;
71
+ unit?: string;
72
+ }
73
+ export interface ParsedNumericValue {
74
+ value: number;
75
+ unit?: string;
76
+ }
77
+ export declare function resolveSpringTarget(target: gsap.TweenTarget): SpringTweenTarget;
78
+ export declare function parseNumericValue(input: unknown, property: SpringProperty): ParsedNumericValue;
79
+ export declare function accessFor(target: SpringTweenTarget, property: SpringProperty, requested: RequestedTarget, vars: SpringTrackConfig): {
80
+ from: number;
81
+ unit?: string;
82
+ write: (value: number) => void;
83
+ };
84
+ export declare function velocityFor(velocity: SpringTrackConfig['velocity'], property: SpringProperty): number;
85
+ export declare function optionsFor(vars: SpringTrackConfig, property: SpringProperty): SpringParameters & {
86
+ settle?: SpringSettleInput;
87
+ };
88
+ /**
89
+ * Animates numeric properties with GSAP as a clock only. Position and velocity
90
+ * always come from closed-form spring samples at absolute time.
91
+ */
92
+ export declare function springTo(target: gsap.TweenTarget, vars: SpringToVars): SpringController;
93
+ //# sourceMappingURL=spring-to.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring-to.d.ts","sourceRoot":"","sources":["../../src/gsap/spring-to.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,569 @@
1
+ import { createSpring } from '../spring.js';
2
+ import { gsap } from 'gsap';
3
+ import { activeTrackState, reconcileActiveTrackHandoff, registerActiveTrack, } from './active-tracks.js';
4
+ import { localTimeAt } from './gsap-time.js';
5
+ import { gsapDriverTime, springElapsedTime, springTrackState, springTrackTiming, validateUnsettledPolicy, } from './spring-track-policy.js';
6
+ import { retireActiveTrackRegistrations, syncActiveTrackRegistration, } from './track-lifecycle.js';
7
+ export const SUPPORTED_PROPERTIES = ['x', 'y', 'scale', 'rotation'];
8
+ const NUMERIC_VALUE = /^([+-]?(?:(?:\d+(?:\.\d*)?)|(?:\.\d+))(?:e[+-]?\d+)?)\s*([a-z%]*)$/i;
9
+ const UNSAFE_PROPERTY_NAMES = new Set([
10
+ '__proto__',
11
+ 'constructor',
12
+ 'prototype',
13
+ ]);
14
+ function isRecord(value) {
15
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
16
+ }
17
+ function isElementTarget(target) {
18
+ return (typeof target === 'object' &&
19
+ target !== null &&
20
+ 'nodeType' in target &&
21
+ target.nodeType === 1);
22
+ }
23
+ function validatePropertyName(property) {
24
+ if (property.trim().length === 0 || UNSAFE_PROPERTY_NAMES.has(property)) {
25
+ throw new TypeError(`Invalid spring property: ${property || '(empty)'}`);
26
+ }
27
+ }
28
+ function validateOptionalRecord(value, name) {
29
+ if (value !== undefined && !isRecord(value)) {
30
+ throw new TypeError(`${name} must be an object when provided`);
31
+ }
32
+ }
33
+ function validateSpringToInput(vars) {
34
+ if (!isRecord(vars)) {
35
+ throw new TypeError('springTo requires a configuration object');
36
+ }
37
+ if (!isRecord(vars['spring'])) {
38
+ throw new TypeError('springTo requires a spring parameters object');
39
+ }
40
+ if (vars['spring']['settle'] !== undefined &&
41
+ !isRecord(vars['spring']['settle'])) {
42
+ throw new TypeError('springTo spring.settle must be an object');
43
+ }
44
+ validateOptionalRecord(vars['targets'], 'targets');
45
+ validateOptionalRecord(vars['properties'], 'properties');
46
+ validateOptionalRecord(vars['adapters'], 'adapters');
47
+ validateOptionalRecord(vars['units'], 'units');
48
+ if (vars['velocity'] !== undefined && typeof vars['velocity'] !== 'number') {
49
+ validateOptionalRecord(vars['velocity'], 'velocity');
50
+ }
51
+ if (isRecord(vars['velocity'])) {
52
+ for (const [property, value] of Object.entries(vars['velocity'])) {
53
+ validatePropertyName(property);
54
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
55
+ throw new TypeError(`Velocity for ${property} must be a finite number`);
56
+ }
57
+ }
58
+ }
59
+ if (isRecord(vars['units'])) {
60
+ for (const [property, value] of Object.entries(vars['units'])) {
61
+ validatePropertyName(property);
62
+ if (typeof value !== 'string') {
63
+ throw new TypeError(`Unit for ${property} must be a string`);
64
+ }
65
+ }
66
+ }
67
+ if (isRecord(vars['properties'])) {
68
+ for (const [property, value] of Object.entries(vars['properties'])) {
69
+ validatePropertyName(property);
70
+ if (!isRecord(value)) {
71
+ throw new TypeError(`Properties for ${property} must be an object`);
72
+ }
73
+ if (value['settle'] !== undefined && !isRecord(value['settle'])) {
74
+ throw new TypeError(`settle for ${property} must be an object`);
75
+ }
76
+ for (const parameter of [
77
+ 'mass',
78
+ 'stiffness',
79
+ 'damping',
80
+ 'velocity',
81
+ ]) {
82
+ const parameterValue = value[parameter];
83
+ if (parameterValue !== undefined &&
84
+ (typeof parameterValue !== 'number' ||
85
+ !Number.isFinite(parameterValue))) {
86
+ throw new TypeError(`${parameter} for ${property} must be a finite number`);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ if (isRecord(vars['adapters'])) {
92
+ for (const [property, value] of Object.entries(vars['adapters'])) {
93
+ validatePropertyName(property);
94
+ if (!isRecord(value) ||
95
+ typeof value['read'] !== 'function' ||
96
+ typeof value['write'] !== 'function') {
97
+ throw new TypeError(`Adapter for ${property} must provide read and write functions`);
98
+ }
99
+ if (value['unit'] !== undefined && typeof value['unit'] !== 'string') {
100
+ throw new TypeError(`Adapter unit for ${property} must be a string`);
101
+ }
102
+ }
103
+ }
104
+ for (const callback of [
105
+ 'onUpdate',
106
+ 'onLogicalComplete',
107
+ 'onSettle',
108
+ 'onUnsettled',
109
+ 'onComplete',
110
+ ]) {
111
+ const value = vars[callback];
112
+ if (value !== undefined && typeof value !== 'function') {
113
+ throw new TypeError(`${callback} must be a function when provided`);
114
+ }
115
+ }
116
+ }
117
+ export function resolveSpringTarget(target) {
118
+ const candidates = gsap.utils.toArray(target);
119
+ if (candidates.length !== 1) {
120
+ throw new TypeError(`springTo requires exactly one resolved target; received ${candidates.length}`);
121
+ }
122
+ const resolved = candidates[0];
123
+ if (((typeof resolved !== 'object' || resolved === null) &&
124
+ typeof resolved !== 'function') ||
125
+ Array.isArray(resolved)) {
126
+ throw new TypeError('springTo requires exactly one resolved object target');
127
+ }
128
+ return resolved;
129
+ }
130
+ export function parseNumericValue(input, property) {
131
+ validatePropertyName(property);
132
+ if (typeof input === 'number') {
133
+ if (!Number.isFinite(input)) {
134
+ throw new TypeError(`${property} must be a finite numeric value`);
135
+ }
136
+ return { value: input };
137
+ }
138
+ if (typeof input !== 'string') {
139
+ throw new TypeError(`${property} must be a number or a single-unit numeric string`);
140
+ }
141
+ const match = NUMERIC_VALUE.exec(input.trim());
142
+ if (!match) {
143
+ throw new TypeError(`${property} must be a number or a single-unit numeric string`);
144
+ }
145
+ const value = Number(match[1]);
146
+ if (!Number.isFinite(value)) {
147
+ throw new TypeError(`${property} must contain a finite numeric value`);
148
+ }
149
+ const unit = match[2];
150
+ return unit ? { value, unit } : { value };
151
+ }
152
+ function requestedTargetsFrom(vars) {
153
+ const requested = Object.create(null);
154
+ for (const property of SUPPORTED_PROPERTIES) {
155
+ const value = Object.hasOwn(vars, property) ? vars[property] : undefined;
156
+ if (value !== undefined)
157
+ requested[property] = parseNumericValue(value, property);
158
+ }
159
+ for (const [property, value] of Object.entries(vars.targets ?? {})) {
160
+ requested[property] = parseNumericValue(value, property);
161
+ }
162
+ return requested;
163
+ }
164
+ function defaultUnitFor(property) {
165
+ if (property === 'x' || property === 'y')
166
+ return 'px';
167
+ if (property === 'rotation')
168
+ return 'deg';
169
+ return undefined;
170
+ }
171
+ function resolvedUnit(property, requested, readUnit, vars) {
172
+ const adapterUnit = vars.adapters?.[property]?.unit;
173
+ const hasConfiguredUnit = Object.hasOwn(vars.units ?? {}, property);
174
+ const configuredUnit = hasConfiguredUnit
175
+ ? vars.units?.[property] || undefined
176
+ : undefined;
177
+ const unit = requested.unit ??
178
+ adapterUnit ??
179
+ configuredUnit ??
180
+ (hasConfiguredUnit ? undefined : defaultUnitFor(property)) ??
181
+ readUnit;
182
+ for (const candidate of [
183
+ requested.unit,
184
+ adapterUnit,
185
+ configuredUnit,
186
+ readUnit,
187
+ ]) {
188
+ if (candidate !== undefined && unit !== undefined && candidate !== unit) {
189
+ throw new TypeError(`Unit mismatch for ${property}: expected ${unit}, received ${candidate}`);
190
+ }
191
+ }
192
+ return unit;
193
+ }
194
+ export function accessFor(target, property, requested, vars) {
195
+ const adapter = Object.hasOwn(vars.adapters ?? {}, property)
196
+ ? vars.adapters?.[property]
197
+ : undefined;
198
+ if (adapter !== undefined) {
199
+ if (adapter === null ||
200
+ typeof adapter !== 'object' ||
201
+ typeof adapter.read !== 'function' ||
202
+ typeof adapter.write !== 'function') {
203
+ throw new TypeError(`Adapter for ${property} must provide read and write functions`);
204
+ }
205
+ const from = adapter.read(target);
206
+ if (!Number.isFinite(from)) {
207
+ throw new TypeError(`Adapter for ${property} returned a non-finite value`);
208
+ }
209
+ const unit = resolvedUnit(property, requested, undefined, vars);
210
+ return {
211
+ from,
212
+ ...(unit === undefined ? {} : { unit }),
213
+ write(value) {
214
+ adapter.write(target, value);
215
+ },
216
+ };
217
+ }
218
+ const raw = parseNumericValue(gsap.getProperty(target, property, 'native'), property);
219
+ const unit = resolvedUnit(property, requested, raw.unit, vars);
220
+ const setters = property === 'scale' && isElementTarget(target)
221
+ ? [
222
+ gsap.quickSetter(target, 'scaleX', unit),
223
+ gsap.quickSetter(target, 'scaleY', unit),
224
+ ]
225
+ : [gsap.quickSetter(target, property, unit)];
226
+ return {
227
+ from: raw.value,
228
+ ...(unit === undefined ? {} : { unit }),
229
+ write(value) {
230
+ for (const setter of setters)
231
+ setter(value);
232
+ },
233
+ };
234
+ }
235
+ export function velocityFor(velocity, property) {
236
+ const resolved = typeof velocity === 'number' ? velocity : (velocity?.[property] ?? 0);
237
+ if (!Number.isFinite(resolved)) {
238
+ throw new TypeError(`Velocity for ${property} must be a finite number`);
239
+ }
240
+ return resolved;
241
+ }
242
+ export function optionsFor(vars, property) {
243
+ const propertyOptions = Object.hasOwn(vars.properties ?? {}, property)
244
+ ? vars.properties?.[property]
245
+ : undefined;
246
+ if (propertyOptions !== undefined &&
247
+ (typeof propertyOptions !== 'object' ||
248
+ propertyOptions === null ||
249
+ Array.isArray(propertyOptions))) {
250
+ throw new TypeError(`Properties for ${property} must be an object`);
251
+ }
252
+ const commonSettle = vars.spring.settle;
253
+ const propertySettle = propertyOptions?.settle;
254
+ return {
255
+ mass: propertyOptions?.mass === undefined
256
+ ? vars.spring.mass
257
+ : propertyOptions.mass,
258
+ stiffness: propertyOptions?.stiffness === undefined
259
+ ? vars.spring.stiffness
260
+ : propertyOptions.stiffness,
261
+ damping: propertyOptions?.damping === undefined
262
+ ? vars.spring.damping
263
+ : propertyOptions.damping,
264
+ ...(commonSettle || propertySettle
265
+ ? { settle: { ...commonSettle, ...propertySettle } }
266
+ : {}),
267
+ };
268
+ }
269
+ /**
270
+ * Animates numeric properties with GSAP as a clock only. Position and velocity
271
+ * always come from closed-form spring samples at absolute time.
272
+ */
273
+ export function springTo(target, vars) {
274
+ validateSpringToInput(vars);
275
+ const springTarget = resolveSpringTarget(target);
276
+ const requestedTargets = requestedTargetsFrom(vars);
277
+ if (Object.keys(requestedTargets).length === 0) {
278
+ throw new TypeError('springTo requires at least one numeric target property');
279
+ }
280
+ const unsettledPolicy = validateUnsettledPolicy(vars.unsettled ?? 'stop');
281
+ const clock = { elapsed: 0 };
282
+ let active = {};
283
+ let tween;
284
+ let duration = 0;
285
+ let finiteDuration = 0;
286
+ let driverDuration = 0;
287
+ let hasUnsettled = false;
288
+ let didComplete = false;
289
+ let didLogicalComplete = false;
290
+ let didSettle = false;
291
+ let didNotifyUnsettled = false;
292
+ let killed = false;
293
+ const buildProperties = (targets) => {
294
+ const next = {};
295
+ for (const [property, requested] of Object.entries(targets)) {
296
+ const to = requested.value;
297
+ let inherited = activeTrackState(springTarget, property);
298
+ const resolvedRequest = requested.unit === undefined &&
299
+ !inherited?.terminal &&
300
+ inherited?.unit !== undefined
301
+ ? { ...requested, unit: inherited.unit }
302
+ : requested;
303
+ const access = accessFor(springTarget, property, resolvedRequest, vars);
304
+ inherited = reconcileActiveTrackHandoff(springTarget, property, inherited, access.from, access.unit);
305
+ if (inherited?.unit !== undefined &&
306
+ access.unit !== undefined &&
307
+ inherited.unit !== access.unit) {
308
+ throw new TypeError(`Unit mismatch for ${property}: expected ${inherited.unit}, received ${access.unit}`);
309
+ }
310
+ const from = inherited?.position ?? access.from;
311
+ const velocity = inherited?.velocity ??
312
+ vars.properties?.[property]?.velocity ??
313
+ velocityFor(vars.velocity, property);
314
+ const spring = createSpring({
315
+ from,
316
+ to,
317
+ velocity,
318
+ ...optionsFor(vars, property),
319
+ });
320
+ const settling = spring.getSettlingResult();
321
+ const propertyDuration = settling.duration;
322
+ next[property] = {
323
+ target: to,
324
+ ...(access.unit === undefined ? {} : { unit: access.unit }),
325
+ duration: propertyDuration,
326
+ settling,
327
+ spring,
328
+ lastTime: 0,
329
+ write: access.write,
330
+ };
331
+ }
332
+ const timing = springTrackTiming(Object.values(next), unsettledPolicy);
333
+ return {
334
+ entries: next,
335
+ ...timing,
336
+ };
337
+ };
338
+ const activate = (next) => {
339
+ if (unsettledPolicy === 'error' && next.hasUnsettled) {
340
+ throw new RangeError('springTo cannot start an unsettled spring in error mode');
341
+ }
342
+ active = next.entries;
343
+ finiteDuration = next.finiteDuration;
344
+ driverDuration = next.driverDuration;
345
+ hasUnsettled = next.hasUnsettled;
346
+ duration =
347
+ unsettledPolicy === 'continue' && hasUnsettled
348
+ ? Number.POSITIVE_INFINITY
349
+ : finiteDuration;
350
+ };
351
+ const stateFor = (entry, elapsed) => springTrackState(entry, elapsed, unsettledPolicy);
352
+ const snapshotAt = (elapsed, entries = active) => {
353
+ const states = {};
354
+ for (const [property, entry] of Object.entries(entries)) {
355
+ states[property] = stateFor(entry, elapsed);
356
+ }
357
+ return {
358
+ elapsed: Number.isFinite(duration)
359
+ ? Math.min(elapsed, duration)
360
+ : elapsed,
361
+ duration,
362
+ states: states,
363
+ };
364
+ };
365
+ const timingFor = (entries) => springTrackTiming(Object.values(entries), unsettledPolicy);
366
+ const notifyUnsettled = (snapshot, timing) => {
367
+ if (killed ||
368
+ didNotifyUnsettled ||
369
+ !timing.hasUnsettled ||
370
+ snapshot.elapsed < timing.unsettledAt) {
371
+ return;
372
+ }
373
+ didNotifyUnsettled = true;
374
+ vars.onUnsettled?.(snapshot);
375
+ };
376
+ const notifyTiming = (snapshot, timing) => {
377
+ if (killed)
378
+ return;
379
+ if (snapshot.elapsed < timing.logicalDuration)
380
+ didLogicalComplete = false;
381
+ if (snapshot.elapsed < timing.finiteDuration)
382
+ didSettle = false;
383
+ if (snapshot.elapsed < timing.unsettledAt)
384
+ didNotifyUnsettled = false;
385
+ if (!didLogicalComplete && snapshot.elapsed >= timing.logicalDuration) {
386
+ didLogicalComplete = true;
387
+ vars.onLogicalComplete?.(snapshot);
388
+ if (killed)
389
+ return;
390
+ }
391
+ if (!timing.hasUnsettled &&
392
+ !didSettle &&
393
+ snapshot.elapsed >= timing.finiteDuration) {
394
+ didSettle = true;
395
+ vars.onSettle?.(snapshot);
396
+ }
397
+ };
398
+ const render = (notifyUpdate = true) => {
399
+ const owners = {};
400
+ for (const [property, entry] of Object.entries(active)) {
401
+ const registration = entry.registration;
402
+ if (!registration)
403
+ continue;
404
+ const transition = syncActiveTrackRegistration(registration, clock.elapsed, entry.lastTime);
405
+ entry.lastTime = clock.elapsed;
406
+ if (transition.releasedAtStart) {
407
+ if (!transition.restoredPrevious)
408
+ entry.write(stateFor(entry, 0).position);
409
+ continue;
410
+ }
411
+ if (transition.isOwner)
412
+ owners[property] = entry;
413
+ }
414
+ const snapshot = snapshotAt(clock.elapsed, owners);
415
+ for (const [property, entry] of Object.entries(owners)) {
416
+ const state = snapshot.states[property];
417
+ if (state)
418
+ entry.write(state.position);
419
+ }
420
+ if (Object.keys(owners).length === 0)
421
+ return snapshot;
422
+ const timing = timingFor(owners);
423
+ if (notifyUpdate)
424
+ vars.onUpdate?.(snapshot);
425
+ notifyTiming(snapshot, timing);
426
+ notifyUnsettled(snapshot, timing);
427
+ return snapshot;
428
+ };
429
+ const complete = () => {
430
+ if (killed || didComplete)
431
+ return;
432
+ clock.elapsed = finiteDuration;
433
+ const snapshot = render(false);
434
+ if (killed)
435
+ return;
436
+ retireActiveTrackRegistrations(Object.values(active).map((entry) => entry.registration));
437
+ didComplete = true;
438
+ if (Object.keys(snapshot.states).length === 0)
439
+ return;
440
+ vars.onComplete?.();
441
+ };
442
+ const releaseRegistrations = () => {
443
+ for (const entry of Object.values(active))
444
+ entry.registration?.release();
445
+ };
446
+ const withInterruptCleanup = (runningTween) => {
447
+ const previousInterrupt = runningTween.eventCallback('onInterrupt');
448
+ runningTween.eventCallback('onInterrupt', () => {
449
+ releaseRegistrations();
450
+ previousInterrupt?.();
451
+ });
452
+ return runningTween;
453
+ };
454
+ const startClock = () => {
455
+ clock.elapsed = 0;
456
+ didComplete = false;
457
+ didLogicalComplete = false;
458
+ didSettle = false;
459
+ didNotifyUnsettled = false;
460
+ if (finiteDuration === 0) {
461
+ render();
462
+ return withInterruptCleanup(gsap.to(clock, { elapsed: 0, duration: 0, onComplete: complete }));
463
+ }
464
+ if (unsettledPolicy === 'continue' && hasUnsettled) {
465
+ let runningTween;
466
+ runningTween = gsap.to(clock, {
467
+ elapsed: 1,
468
+ duration: 1,
469
+ repeat: -1,
470
+ ease: 'none',
471
+ onUpdate() {
472
+ clock.elapsed = runningTween.totalTime();
473
+ render();
474
+ },
475
+ });
476
+ return withInterruptCleanup(runningTween);
477
+ }
478
+ return withInterruptCleanup(gsap.to(clock, {
479
+ elapsed: finiteDuration,
480
+ duration: driverDuration,
481
+ ease: 'none',
482
+ onUpdate: render,
483
+ onComplete: complete,
484
+ }));
485
+ };
486
+ activate(buildProperties(requestedTargets));
487
+ for (const [property, entry] of Object.entries(active)) {
488
+ entry.registration = registerActiveTrack(springTarget, property, {
489
+ state: (globalTime) => {
490
+ const elapsed = globalTime === undefined || tween === undefined
491
+ ? clock.elapsed
492
+ : Number.isFinite(duration)
493
+ ? springElapsedTime(localTimeAt(tween, globalTime), finiteDuration, driverDuration)
494
+ : localTimeAt(tween, globalTime);
495
+ const state = stateFor(entry, elapsed);
496
+ return {
497
+ ...state,
498
+ velocity: state.velocity * (tween?.reversed() ? -1 : 1),
499
+ ...(entry.unit === undefined ? {} : { unit: entry.unit }),
500
+ };
501
+ },
502
+ restore: () => {
503
+ entry.write(stateFor(entry, clock.elapsed).position);
504
+ },
505
+ });
506
+ }
507
+ tween = startClock();
508
+ const controller = {
509
+ get duration() {
510
+ return duration;
511
+ },
512
+ get springs() {
513
+ return Object.fromEntries(Object.entries(active).map(([property, entry]) => [
514
+ property,
515
+ entry.spring,
516
+ ]));
517
+ },
518
+ get tween() {
519
+ return tween;
520
+ },
521
+ getSnapshot() {
522
+ return snapshotAt(clock.elapsed);
523
+ },
524
+ play() {
525
+ if (!killed)
526
+ tween.play();
527
+ },
528
+ pause() {
529
+ if (!killed)
530
+ tween.pause();
531
+ },
532
+ resume() {
533
+ if (!killed)
534
+ tween.resume();
535
+ },
536
+ stop() {
537
+ if (!killed)
538
+ tween.pause();
539
+ },
540
+ seek(time) {
541
+ if (killed)
542
+ return;
543
+ if (!Number.isFinite(time) || time < 0) {
544
+ throw new RangeError('seek time must be a finite number greater than or equal to 0');
545
+ }
546
+ const resolvedTime = Number.isFinite(duration)
547
+ ? Math.min(time, duration)
548
+ : time;
549
+ if (Number.isFinite(duration)) {
550
+ tween.time(gsapDriverTime(resolvedTime, finiteDuration, driverDuration), false);
551
+ }
552
+ else
553
+ tween.totalTime(resolvedTime, false);
554
+ },
555
+ playbackReverse() {
556
+ if (!killed)
557
+ tween.reverse();
558
+ },
559
+ kill() {
560
+ if (killed)
561
+ return;
562
+ killed = true;
563
+ releaseRegistrations();
564
+ tween.kill();
565
+ },
566
+ };
567
+ return controller;
568
+ }
569
+ //# sourceMappingURL=spring-to.js.map