kuinetic 0.1.3 → 0.2.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 (125) hide show
  1. package/README.md +93 -10
  2. package/dist/esm/advanced/index.mjs +4727 -0
  3. package/dist/esm/chunk-AEQGC2KM.mjs +189 -0
  4. package/dist/esm/chunk-MQSNMYRP.mjs +9332 -0
  5. package/dist/esm/chunk-RVTYN6NZ.mjs +3446 -0
  6. package/dist/esm/chunk-U43BX5O2.mjs +2984 -0
  7. package/dist/esm/core/index.mjs +16 -9
  8. package/dist/esm/effects/index.mjs +19 -4
  9. package/dist/esm/index.mjs +17 -10
  10. package/dist/kuinetic.advanced.js +5070 -0
  11. package/dist/kuinetic.advanced.min.js +749 -0
  12. package/dist/kuinetic.all.js +15218 -5595
  13. package/dist/kuinetic.all.min.js +2 -0
  14. package/dist/kuinetic.css +2900 -360
  15. package/dist/kuinetic.js +15217 -5593
  16. package/dist/kuinetic.min.css +1 -0
  17. package/dist/kuinetic.min.js +7 -0
  18. package/dist/types/3d/angles.d.ts +30 -0
  19. package/dist/types/3d/flattening.d.ts +49 -0
  20. package/dist/types/3d/index.d.ts +36 -0
  21. package/dist/types/3d/model-3d.d.ts +115 -0
  22. package/dist/types/3d/register.d.ts +26 -0
  23. package/dist/types/3d/webgl.d.ts +24 -0
  24. package/dist/types/advanced/audio.d.ts +322 -0
  25. package/dist/types/advanced/base.d.ts +233 -0
  26. package/dist/types/advanced/camera-3d.d.ts +236 -0
  27. package/dist/types/advanced/fluid-cursor.d.ts +149 -0
  28. package/dist/types/advanced/gl-utils.d.ts +52 -0
  29. package/dist/types/advanced/glsl.d.ts +60 -0
  30. package/dist/types/advanced/index.d.ts +23 -0
  31. package/dist/types/advanced/particles.d.ts +108 -0
  32. package/dist/types/advanced/scenes.d.ts +207 -0
  33. package/dist/types/advanced/shaders.d.ts +972 -0
  34. package/dist/types/browser/boot.d.ts +72 -0
  35. package/dist/types/core/activation.d.ts +227 -2
  36. package/dist/types/core/animator.d.ts +446 -11
  37. package/dist/types/core/attrs.d.ts +9 -0
  38. package/dist/types/core/breakpoints.d.ts +260 -0
  39. package/dist/types/core/bundles.d.ts +71 -0
  40. package/dist/types/core/callback.d.ts +64 -0
  41. package/dist/types/core/capabilities.d.ts +47 -0
  42. package/dist/types/core/channels.d.ts +120 -2
  43. package/dist/types/core/cloak-selectors.d.ts +47 -0
  44. package/dist/types/core/compile.d.ts +207 -2
  45. package/dist/types/core/control.d.ts +218 -0
  46. package/dist/types/core/declarations.d.ts +128 -0
  47. package/dist/types/core/derived/aggregate.d.ts +43 -0
  48. package/dist/types/core/derived/book.d.ts +30 -0
  49. package/dist/types/core/derived/diagnostics.d.ts +51 -0
  50. package/dist/types/core/derived/group-gate.d.ts +62 -0
  51. package/dist/types/core/derived/install.d.ts +110 -0
  52. package/dist/types/core/derived/late-matches.d.ts +19 -0
  53. package/dist/types/core/derived/types.d.ts +108 -0
  54. package/dist/types/core/easing.d.ts +57 -0
  55. package/dist/types/core/element-config.d.ts +47 -6
  56. package/dist/types/core/element-size.d.ts +23 -0
  57. package/dist/types/core/event-sources.d.ts +39 -0
  58. package/dist/types/core/flip.d.ts +34 -1
  59. package/dist/types/core/gesture.d.ts +12 -0
  60. package/dist/types/core/host-facts.d.ts +155 -0
  61. package/dist/types/core/index.d.ts +7 -3
  62. package/dist/types/core/owned-styles.d.ts +129 -2
  63. package/dist/types/core/params.d.ts +48 -0
  64. package/dist/types/core/parse.d.ts +28 -1
  65. package/dist/types/core/register-into.d.ts +29 -0
  66. package/dist/types/core/registry.d.ts +10 -3
  67. package/dist/types/core/repeat.d.ts +91 -0
  68. package/dist/types/core/sequence.d.ts +126 -0
  69. package/dist/types/core/stagger-config.d.ts +199 -0
  70. package/dist/types/core/stagger-keys.d.ts +63 -0
  71. package/dist/types/core/stagger.d.ts +187 -6
  72. package/dist/types/core/style-plan.d.ts +21 -16
  73. package/dist/types/core/target.d.ts +128 -0
  74. package/dist/types/core/threshold-reachability.d.ts +45 -0
  75. package/dist/types/core/time-scale.d.ts +9 -0
  76. package/dist/types/core/toggle-actions.d.ts +141 -0
  77. package/dist/types/core/travel.d.ts +59 -0
  78. package/dist/types/core/types.d.ts +705 -13
  79. package/dist/types/core/unquoted-selectors.d.ts +53 -0
  80. package/dist/types/effects/carousel/drag.d.ts +80 -0
  81. package/dist/types/effects/carousel/index.d.ts +149 -0
  82. package/dist/types/effects/catalog/background-media.d.ts +152 -0
  83. package/dist/types/effects/catalog/discrete.d.ts +13 -0
  84. package/dist/types/effects/catalog/interaction-proximity.d.ts +24 -0
  85. package/dist/types/effects/catalog/interaction-reveal.d.ts +248 -0
  86. package/dist/types/effects/catalog/interaction-shared.d.ts +42 -0
  87. package/dist/types/effects/catalog/interaction-states.d.ts +68 -0
  88. package/dist/types/effects/catalog/materials.d.ts +67 -0
  89. package/dist/types/effects/catalog/media-shared.d.ts +3 -2
  90. package/dist/types/effects/catalog/numbers-shared.d.ts +8 -5
  91. package/dist/types/effects/catalog/shared.d.ts +2 -2
  92. package/dist/types/effects/catalog/text-shared.d.ts +92 -10
  93. package/dist/types/effects/catalog/transforms.d.ts +13 -0
  94. package/dist/types/effects/catalog/view-transitions.d.ts +13 -0
  95. package/dist/types/effects/forms/primitives.d.ts +15 -4
  96. package/dist/types/effects/gestures/index.d.ts +53 -0
  97. package/dist/types/effects/index.d.ts +5 -0
  98. package/dist/types/effects/layout/presets.d.ts +35 -0
  99. package/dist/types/effects/motion-path/index.d.ts +35 -0
  100. package/dist/types/effects/scroll-mechanics/params.d.ts +23 -0
  101. package/dist/types/effects/scroll-mechanics/presets.d.ts +51 -0
  102. package/dist/types/effects/scroll-mechanics/section-index.d.ts +47 -0
  103. package/dist/types/effects/shared.d.ts +162 -2
  104. package/dist/types/effects/step-index.d.ts +121 -0
  105. package/dist/types/effects/step-marking.d.ts +41 -33
  106. package/dist/types/effects/svg/icon-parts.d.ts +23 -0
  107. package/dist/types/effects/three-d/flip-parts.d.ts +46 -0
  108. package/dist/types/effects/tween/index.d.ts +57 -0
  109. package/dist/types/effects/tween/properties.d.ts +107 -0
  110. package/dist/types/effects/tween/waypoints.d.ts +106 -0
  111. package/dist/types/showcase/compare.d.ts +4 -0
  112. package/dist/types/showcase/device-frame.d.ts +3 -0
  113. package/dist/types/showcase/hotspots.d.ts +3 -0
  114. package/dist/types/showcase/index.d.ts +30 -0
  115. package/dist/types/showcase/lightbox.d.ts +3 -0
  116. package/dist/types/showcase/media-source.d.ts +13 -0
  117. package/dist/types/showcase/modal-shell.d.ts +22 -0
  118. package/dist/types/showcase/scroll-story.d.ts +4 -0
  119. package/dist/types/showcase/shared.d.ts +47 -0
  120. package/dist/types/showcase/slideshow.d.ts +3 -0
  121. package/dist/types/showcase/slow-mo.d.ts +5 -0
  122. package/package.json +14 -7
  123. package/dist/esm/chunk-5DON3UFQ.mjs +0 -4380
  124. package/dist/esm/chunk-JT4PZL3A.mjs +0 -773
  125. package/dist/esm/chunk-QUVFODSQ.mjs +0 -1278
@@ -1,773 +0,0 @@
1
- // src/core/registry.ts
2
- var Registry = class {
3
- primitives = /* @__PURE__ */ new Map();
4
- presets = /* @__PURE__ */ new Map();
5
- /** Sorted-name key → preset that renders that combination as one tested keyframe. */
6
- combos = /* @__PURE__ */ new Map();
7
- registerPrimitive(primitive) {
8
- if (this.primitives.has(primitive.id)) {
9
- throw new Error(`kuinetic: primitive "${primitive.id}" is already registered`);
10
- }
11
- this.primitives.set(primitive.id, namespaceTiming(primitive));
12
- return this;
13
- }
14
- registerPreset(preset) {
15
- if (this.presets.has(preset.name)) {
16
- throw new Error(`kuinetic: effect "${preset.name}" is already registered`);
17
- }
18
- if (!this.primitives.has(preset.primitive)) {
19
- throw new Error(
20
- `kuinetic: effect "${preset.name}" references unknown primitive "${preset.primitive}"`
21
- );
22
- }
23
- this.presets.set(preset.name, preset);
24
- return this;
25
- }
26
- registerPresets(presets) {
27
- for (const preset of presets) this.registerPreset(preset);
28
- return this;
29
- }
30
- registerPrimitives(primitives) {
31
- for (const primitive of primitives) this.registerPrimitive(primitive);
32
- return this;
33
- }
34
- /**
35
- * Declare that a set of effect names has a purpose-built single-keyframe implementation.
36
- * Checked before channel conflict analysis, so `fade-up` + `blur-in` can resolve to the
37
- * tested `fade-blur-up` rather than being rejected for both writing `opacity`.
38
- */
39
- registerCombo(names, presetName) {
40
- this.combos.set(comboKey(names), presetName);
41
- return this;
42
- }
43
- resolve(name) {
44
- const preset = this.presets.get(name);
45
- if (!preset) return void 0;
46
- const primitive = this.primitives.get(preset.primitive);
47
- return { preset, primitive };
48
- }
49
- findCombo(names) {
50
- const comboName = this.combos.get(comboKey(names));
51
- return comboName ? this.resolve(comboName) : void 0;
52
- }
53
- has(name) {
54
- return this.presets.has(name);
55
- }
56
- /** All registered effect names, for docs generation and dev-mode "did you mean" hints. */
57
- names() {
58
- return [...this.presets.keys()].sort((a, b) => a.localeCompare(b));
59
- }
60
- getPrimitive(id) {
61
- return this.primitives.get(id);
62
- }
63
- };
64
- var TIMING_PARAMS = ["duration", "delay", "ease"];
65
- function timingProperty(primitiveId, name) {
66
- return `--kui-${primitiveId}-${name}`;
67
- }
68
- function namespaceTiming(primitive) {
69
- const parameters = { ...primitive.parameters };
70
- for (const name of TIMING_PARAMS) {
71
- const spec = parameters[name];
72
- if (spec) parameters[name] = { ...spec, cssProperty: timingProperty(primitive.id, name) };
73
- }
74
- return { ...primitive, parameters };
75
- }
76
- function comboKey(names) {
77
- return [...names].sort((a, b) => a.localeCompare(b)).join("+");
78
- }
79
- function suggest(name, candidates) {
80
- let best;
81
- let bestScore = Infinity;
82
- for (const candidate of candidates) {
83
- const score = distance(name, candidate);
84
- if (score < bestScore) {
85
- bestScore = score;
86
- best = candidate;
87
- }
88
- }
89
- return bestScore <= Math.max(2, Math.floor(name.length / 3)) ? best : void 0;
90
- }
91
- function distance(a, b) {
92
- const rows = a.length + 1;
93
- const cols = b.length + 1;
94
- let prev = Array.from({ length: cols }, (_, i) => i);
95
- for (let i = 1; i < rows; i++) {
96
- const curr = [i, ...Array(cols - 1).fill(0)];
97
- for (let j = 1; j < cols; j++) {
98
- const cost = a[i - 1] === b[j - 1] ? 0 : 1;
99
- curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);
100
- }
101
- prev = curr;
102
- }
103
- return prev[cols - 1];
104
- }
105
-
106
- // src/core/types.ts
107
- var CHANNEL = {
108
- opacity: "opacity",
109
- translate: "translate",
110
- scale: "scale",
111
- rotate: "rotate",
112
- filter: "filter",
113
- clip: "clip",
114
- background: "background",
115
- color: "color",
116
- stroke: "stroke",
117
- text: "text",
118
- /**
119
- * Skew is the one transform CSS never gave an independent property to — there is no `skew:`
120
- * beside `translate:`/`rotate:`/`scale:`, so it can only be written through the `transform`
121
- * shorthand. That makes it its own channel: anything writing `transform` clobbers the whole
122
- * shorthand, so every primitive that does is on this channel, whatever the transform is for.
123
- * `scroll-skew` is one member; `flip-face` (`effects/three-d`) and `flip-3d`
124
- * (`effects/catalog/core`, the `flip-in-*`/`flip-out-*` family) are the other two — both need
125
- * the `perspective()` transform *function* for an element to have depth on itself, which
126
- * likewise only exists inside `transform`.
127
- */
128
- skew: "skew"
129
- };
130
- function inertInstance(destroy = () => {
131
- }) {
132
- return {
133
- activate() {
134
- },
135
- cancel() {
136
- },
137
- finish() {
138
- },
139
- finished: Promise.resolve(),
140
- destroy
141
- };
142
- }
143
-
144
- // src/core/params.ts
145
- var DANGEROUS = /[;<]|\/\*|url\s*\(|expression\s*\(|@import|image-set\s*\(/i;
146
- var ABSOLUTE_OR_PROTOCOL_RELATIVE = /^(?:[a-z][a-z0-9+.-]*:|[/\\]{2})/i;
147
- var MAX_VALUE_LENGTH = 200;
148
- var NUM = String.raw`-?(?:\d+(?:\.\d+)?|\.\d+)`;
149
- var LENGTH_UNITS = "px|rem|em|vh|vw|vmin|vmax|ch|ex|cm|mm|in|pt|pc|q|%";
150
- var PATTERNS = {
151
- length: new RegExp(`^(?:0|${NUM}(?:${LENGTH_UNITS}))$`, "i"),
152
- time: new RegExp(`^${NUM}(?:ms|s)$`, "i"),
153
- number: new RegExp(`^${NUM}$`),
154
- percentage: new RegExp(`^${NUM}%$`),
155
- angle: new RegExp(`^${NUM}(?:deg|rad|turn|grad)$`, "i")
156
- };
157
- var HEX_COLOR = /^#[0-9a-f]{3,8}$/i;
158
- var COLOR_FUNCTIONS = /^(?:rgba?|hsla?|okl(?:ch|ab)|l(?:ch|ab)|color)\([^()]*\)$/i;
159
- var COLOR_KEYWORD = /^[a-z]+$/i;
160
- var EASING_KEYWORD = /^(?:linear|ease|step-start|step-end|spring|bounce|[a-z]+-(?:in|out|in-out))$/i;
161
- var EASING_FUNCTION = /^(?:cubic-bezier|steps|linear)\([^()]*\)$/i;
162
- var CALC_TYPES = /* @__PURE__ */ new Set(["length", "percentage", "number"]);
163
- var CALC_CHARACTER = /^[\d.\s+\-*/%a-z,]$/i;
164
- var CUSTOM_PROPERTY_NAME = /^--[\w-]+$/;
165
- function validate(raw, spec) {
166
- const value = raw.trim();
167
- const rejection = screen(value, spec);
168
- if (rejection) return rejection;
169
- if (spec.type === "keyword") return checkKeyword(value, spec);
170
- if (spec.type === "text") return { value, ok: true };
171
- if (isAcceptable(value, spec.type)) return checkNumericConstraints(value, spec);
172
- return reject(spec, `not a valid ${spec.type}`);
173
- }
174
- function screen(value, spec) {
175
- if (!value) return reject(spec, "empty value");
176
- if (value.length > MAX_VALUE_LENGTH) {
177
- return reject(spec, `value exceeds ${MAX_VALUE_LENGTH} characters`);
178
- }
179
- if (DANGEROUS.test(value)) return reject(spec, "value contains disallowed CSS syntax");
180
- return null;
181
- }
182
- function isAcceptable(value, type) {
183
- if (type === "color") return isColor(value);
184
- if (type === "easing") return EASING_KEYWORD.test(value) || EASING_FUNCTION.test(value);
185
- const pattern = PATTERNS[type];
186
- if (!pattern) return false;
187
- if (pattern.test(value)) return true;
188
- return CALC_TYPES.has(type) && isSafeCalc(value) && isWellFormedCalc(value);
189
- }
190
- function isColor(value) {
191
- return HEX_COLOR.test(value) || COLOR_FUNCTIONS.test(value) || COLOR_KEYWORD.test(value);
192
- }
193
- function checkKeyword(value, spec) {
194
- if (spec.values?.includes(value)) return { value, ok: true };
195
- return reject(spec, `expected one of ${spec.values?.join(", ") ?? "(none declared)"}`);
196
- }
197
- function isSameOriginPath(value) {
198
- return !ABSOLUTE_OR_PROTOCOL_RELATIVE.test(value);
199
- }
200
- function checkNumericConstraints(value, spec) {
201
- if (spec.type !== "number") return { value, ok: true };
202
- const numeric = Number(value);
203
- if (spec.finite && !Number.isFinite(numeric)) return reject(spec, "expected a finite number");
204
- if (spec.integer && !Number.isInteger(numeric)) return reject(spec, "expected an integer");
205
- if (spec.minimum !== void 0 && numeric < spec.minimum) {
206
- return reject(spec, `expected at least ${spec.minimum}`);
207
- }
208
- if (spec.maximum !== void 0 && numeric > spec.maximum) {
209
- return reject(spec, `expected at most ${spec.maximum}`);
210
- }
211
- return { value, ok: true };
212
- }
213
- function reject(spec, reason) {
214
- return { value: spec.default, ok: false, reason };
215
- }
216
- function isSafeCalc(value) {
217
- if (!value.startsWith("calc(") || !value.endsWith(")")) return false;
218
- const end = value.length - 1;
219
- let index = "calc(".length;
220
- while (index < end) {
221
- index = nextCalcToken(value, index, end);
222
- if (index < 0) return false;
223
- }
224
- return true;
225
- }
226
- function nextCalcToken(value, index, end) {
227
- if (value.startsWith("var(", index)) return consumeVar(value, index, end);
228
- return CALC_CHARACTER.test(value[index]) ? index + 1 : -1;
229
- }
230
- function consumeVar(value, start, end) {
231
- const close = value.indexOf(")", start + "var(".length);
232
- if (close < 0 || close >= end) return -1;
233
- const name = value.slice(start + "var(".length, close);
234
- return CUSTOM_PROPERTY_NAME.test(name) ? close + 1 : -1;
235
- }
236
- function isWellFormedCalc(value) {
237
- const body = value.slice("calc(".length, -1).trim();
238
- return body !== "" && !/[+\-*/]$/.test(body);
239
- }
240
- function resolveParams(authored, schema, warn) {
241
- const out = {};
242
- for (const [key, raw] of Object.entries(authored)) {
243
- const spec = Object.hasOwn(schema, key) ? schema[key] : void 0;
244
- if (!spec) {
245
- warn(`unknown parameter "${key}" (known: ${Object.keys(schema).join(", ") || "none"})`);
246
- continue;
247
- }
248
- if (spec.type === "text") continue;
249
- const result = validate(raw, spec);
250
- if (result.ok) out[spec.cssProperty] = result.value;
251
- else warn(`parameter "${key}": ${result.reason} \u2014 got "${raw}", using default "${spec.default}"`);
252
- }
253
- return out;
254
- }
255
-
256
- // src/core/js-params.ts
257
- var ABSOLUTE_BASIS = {
258
- viewportWidth: 0,
259
- viewportHeight: 0,
260
- percentBasis: 0,
261
- fontSize: 16,
262
- rootFontSize: 16
263
- };
264
- var STATIC_UNITS = {
265
- px: 1,
266
- cm: 96 / 2.54,
267
- mm: 96 / 25.4,
268
- q: 96 / 101.6,
269
- in: 96,
270
- pt: 96 / 72,
271
- pc: 16
272
- };
273
- var BASIS_UNITS = {
274
- vh: (b) => b.viewportHeight / 100,
275
- vw: (b) => b.viewportWidth / 100,
276
- vmin: (b) => Math.min(b.viewportWidth, b.viewportHeight) / 100,
277
- vmax: (b) => Math.max(b.viewportWidth, b.viewportHeight) / 100,
278
- "%": (b) => b.percentBasis / 100,
279
- em: (b) => b.fontSize,
280
- rem: (b) => b.rootFontSize,
281
- ch: (b) => b.fontSize * 0.5,
282
- ex: (b) => b.fontSize * 0.5
283
- };
284
- var NUMBER_WITH_UNIT = /^(-?(?:\d+(?:\.\d+)?|\.\d+))([a-z%]*)$/i;
285
- function readParams(authored, schema, warn) {
286
- const out = {};
287
- for (const [name, spec] of Object.entries(schema)) out[name] = spec.default;
288
- for (const [name, raw] of Object.entries(authored)) {
289
- const spec = Object.hasOwn(schema, name) ? schema[name] : void 0;
290
- if (!spec) {
291
- warn(`unknown parameter "${name}" (known: ${Object.keys(schema).join(", ") || "none"})`);
292
- continue;
293
- }
294
- const result = validate(raw, spec);
295
- out[name] = result.value;
296
- if (!result.ok) {
297
- warn(`parameter "${name}": ${result.reason} \u2014 got "${raw}", using default "${spec.default}"`);
298
- }
299
- }
300
- return out;
301
- }
302
- function toMilliseconds(value, fallback = 0) {
303
- const parts = NUMBER_WITH_UNIT.exec(value.trim());
304
- if (!parts) return fallback;
305
- const amount = Number.parseFloat(parts[1]);
306
- const unit = parts[2].toLowerCase();
307
- if (unit === "ms") return amount;
308
- if (unit === "s") return amount * 1e3;
309
- return fallback;
310
- }
311
- function toPixels(value, basis, fallback = 0) {
312
- const parts = NUMBER_WITH_UNIT.exec(value.trim());
313
- if (!parts) return fallback;
314
- const amount = Number.parseFloat(parts[1]);
315
- const unit = parts[2].toLowerCase();
316
- if (unit === "") return amount === 0 ? 0 : fallback;
317
- const staticFactor = STATIC_UNITS[unit];
318
- if (staticFactor !== void 0) return amount * staticFactor;
319
- const basisFactor = BASIS_UNITS[unit];
320
- return basisFactor ? amount * basisFactor(basis) : fallback;
321
- }
322
- function toNumber(value, fallback = 0) {
323
- const parts = NUMBER_WITH_UNIT.exec(value.trim());
324
- if (!parts) return fallback;
325
- const amount = Number.parseFloat(parts[1]);
326
- const unit = parts[2];
327
- if (unit === "") return amount;
328
- if (unit === "%") return amount / 100;
329
- return fallback;
330
- }
331
- var EASING_SPEC = { type: "easing", default: "", cssProperty: "--kui-ease" };
332
- function timingMs(raw, label, warn) {
333
- if (raw === void 0) return void 0;
334
- const ms = toMilliseconds(raw, Number.NaN);
335
- if (Number.isFinite(ms)) return ms;
336
- warn(`${label} "${raw}" is not a valid time \u2014 ignored`);
337
- return void 0;
338
- }
339
- function timingEasing(raw, warn) {
340
- if (raw === void 0) return void 0;
341
- const result = validate(raw, EASING_SPEC);
342
- if (result.ok) return result.value;
343
- warn(`easing "${raw}": ${result.reason} \u2014 ignored`);
344
- return void 0;
345
- }
346
- function readEffectTiming(spec, warn) {
347
- return {
348
- durationMs: timingMs(spec.duration, "duration", warn),
349
- delayMs: timingMs(spec.delay, "delay", warn),
350
- easing: timingEasing(spec.easing, warn)
351
- };
352
- }
353
- function effectDurationMs(params, fallback) {
354
- return params.timing.durationMs ?? params.ms("duration", fallback);
355
- }
356
- function createParams(values, timing = {}) {
357
- return {
358
- text: (name, fallback = "") => values[name] ?? fallback,
359
- ms: (name, fallback = 0) => toMilliseconds(values[name] ?? "", fallback),
360
- num: (name, fallback = 0) => toNumber(values[name] ?? "", fallback),
361
- is: (name, value = "true") => (values[name] ?? "") === value,
362
- timing
363
- };
364
- }
365
- function readEffectParams(authored, schema, warn, timing = {}) {
366
- return createParams(readParams(authored, schema, warn), timing);
367
- }
368
-
369
- // src/core/scroll-scheduler.ts
370
- function defaultDeps() {
371
- const raf = globalThis.requestAnimationFrame;
372
- if (typeof raf !== "function") {
373
- return {
374
- requestFrame: (callback) => globalThis.setTimeout(callback, 16),
375
- cancelFrame: (handle) => globalThis.clearTimeout(handle)
376
- };
377
- }
378
- return {
379
- requestFrame: (callback) => raf(callback),
380
- cancelFrame: (handle) => globalThis.cancelAnimationFrame(handle)
381
- };
382
- }
383
- function createScrollScheduler(deps = defaultDeps()) {
384
- const entries = /* @__PURE__ */ new Map();
385
- let epoch = 0;
386
- let pending = null;
387
- function schedule(entry) {
388
- if (entry) entry.dirty = true;
389
- else for (const other of entries.values()) other.dirty = true;
390
- if (pending !== null) return;
391
- pending = deps.requestFrame(runFrame);
392
- }
393
- function runFrame() {
394
- pending = null;
395
- for (const entry of entries.values()) {
396
- if (!entry.dirty || entry.subscribers.size === 0) continue;
397
- entry.dirty = false;
398
- const frame = { metrics: entry.root.metrics(), epoch };
399
- for (const subscriber of [...entry.subscribers]) subscriber(frame);
400
- }
401
- }
402
- function attach(root) {
403
- const existing = entries.get(root.key);
404
- if (existing) return existing;
405
- const entry = { root, subscribers: /* @__PURE__ */ new Set(), detach: [], dirty: false };
406
- entry.detach.push(root.onScroll(() => schedule(entry)));
407
- entry.detach.push(
408
- root.onResize(() => {
409
- epoch++;
410
- schedule();
411
- })
412
- );
413
- entries.set(root.key, entry);
414
- return entry;
415
- }
416
- function release(entry) {
417
- if (entry.subscribers.size > 0) return;
418
- for (const detach of entry.detach) detach();
419
- entries.delete(entry.root.key);
420
- }
421
- return {
422
- subscribe(root, onFrame) {
423
- const entry = attach(root);
424
- entry.subscribers.add(onFrame);
425
- schedule(entry);
426
- return () => {
427
- entry.subscribers.delete(onFrame);
428
- release(entry);
429
- };
430
- },
431
- invalidate() {
432
- epoch++;
433
- schedule();
434
- },
435
- rootCount: () => entries.size,
436
- destroy() {
437
- if (pending !== null) deps.cancelFrame(pending);
438
- pending = null;
439
- for (const entry of entries.values()) {
440
- entry.subscribers.clear();
441
- for (const detach of entry.detach) detach();
442
- }
443
- entries.clear();
444
- }
445
- };
446
- }
447
- function windowScrollRoot(win) {
448
- return {
449
- key: "window",
450
- metrics: () => ({
451
- scrollTop: win.scrollY,
452
- scrollLeft: win.scrollX,
453
- viewportWidth: win.innerWidth,
454
- viewportHeight: win.innerHeight,
455
- viewportTop: 0,
456
- viewportLeft: 0
457
- }),
458
- onScroll: (handler) => listen(win, "scroll", handler),
459
- /*
460
- * The document's own height counts as a resize, not just the window's.
461
- *
462
- * `elementScrollRoot` has observed its element's size since it was written, for the reason
463
- * stated three doc comments down: "images loading, fonts swapping, a container changing size,
464
- * or content being inserted". Every one of those applies at least as strongly to the page
465
- * itself, and the page root was the one that only listened for `window.resize` — so on any
466
- * document with lazy-loaded media below the fold, every cached content offset silently drifted
467
- * by however much the page grew after it was measured, with no epoch bump to correct it.
468
- *
469
- * Measured on `demo/scroll.html` (32,000px of lazy screenshots): the horizontal track's stage
470
- * moved ~840px between page load and reaching it, which is a third of that effect's whole
471
- * scroll range. Nothing was wrong with the maths; the number it was doing the maths on was
472
- * taken before forty images existed.
473
- */
474
- onResize: (handler) => observeSize(win.document.documentElement, win, handler)
475
- };
476
- }
477
- function elementScrollRoot(el, win) {
478
- return {
479
- key: `el:${rootId(el)}`,
480
- metrics: () => {
481
- const rect = el.getBoundingClientRect();
482
- return {
483
- scrollTop: el.scrollTop,
484
- scrollLeft: el.scrollLeft,
485
- viewportWidth: el.clientWidth,
486
- viewportHeight: el.clientHeight,
487
- viewportTop: rect.top,
488
- viewportLeft: rect.left
489
- };
490
- },
491
- onScroll: (handler) => listen(el, "scroll", handler),
492
- // Window resize alone misses the cases that actually invalidate a nested scroller: images
493
- // loading, fonts swapping, a container changing size, or content being inserted.
494
- onResize: (handler) => observeSize(el, win, handler)
495
- };
496
- }
497
- function listen(target, type, handler) {
498
- target.addEventListener(type, handler, { passive: true });
499
- return () => target.removeEventListener(type, handler);
500
- }
501
- function observeSize(el, win, handler) {
502
- const stopWindow = listen(win, "resize", handler);
503
- if (typeof ResizeObserver === "undefined") return stopWindow;
504
- const observer = new ResizeObserver(handler);
505
- observer.observe(el);
506
- return () => {
507
- stopWindow();
508
- observer.disconnect();
509
- };
510
- }
511
- var nextRootId = 0;
512
- var rootIds = /* @__PURE__ */ new WeakMap();
513
- function rootId(el) {
514
- const existing = rootIds.get(el);
515
- if (existing) return existing;
516
- const id = String(++nextRootId);
517
- rootIds.set(el, id);
518
- return id;
519
- }
520
- function createRootResolver(options) {
521
- const { win } = options;
522
- const isScrollable = options.isScrollable ?? defaultIsScrollable(win);
523
- const windowRoot = windowScrollRoot(win);
524
- return (el) => {
525
- for (let node = el.parentElement; node; node = node.parentElement) {
526
- if (isScrollable(node)) return elementScrollRoot(node, win);
527
- }
528
- return windowRoot;
529
- };
530
- }
531
- var SCROLLABLE_OVERFLOW = /* @__PURE__ */ new Set(["auto", "scroll", "overlay"]);
532
- function defaultIsScrollable(win) {
533
- return (el) => {
534
- const style = win.getComputedStyle(el);
535
- const vertical = SCROLLABLE_OVERFLOW.has(style.overflowY) && el.scrollHeight > el.clientHeight;
536
- const horizontal = SCROLLABLE_OVERFLOW.has(style.overflowX) && el.scrollWidth > el.clientWidth;
537
- return vertical || horizontal;
538
- };
539
- }
540
- function clamp01(value) {
541
- if (Number.isNaN(value)) return 0;
542
- return Math.min(1, Math.max(0, value));
543
- }
544
- function createMeasureCache(measure) {
545
- let cachedEpoch = -1;
546
- let cached;
547
- return {
548
- read(epoch) {
549
- if (cachedEpoch !== epoch || cached === void 0) {
550
- cached = measure();
551
- cachedEpoch = epoch;
552
- }
553
- return cached;
554
- },
555
- clear() {
556
- cachedEpoch = -1;
557
- cached = void 0;
558
- }
559
- };
560
- }
561
-
562
- // src/core/instances.ts
563
- function animationsOf(el) {
564
- const getAnimations = el.getAnimations;
565
- return typeof getAnimations === "function" ? getAnimations.call(el) : [];
566
- }
567
- function ownedAnimationsOf(el, names) {
568
- return animationsOf(el).filter((animation) => {
569
- const name = animation.animationName;
570
- return typeof name === "string" && names.has(name);
571
- });
572
- }
573
- function flushComputedAnimationName(el) {
574
- return getComputedStyle(el).animationName;
575
- }
576
- function restartCssAnimation(el, ledger) {
577
- const name = el.style.getPropertyValue("animation-name");
578
- ledger.set("animation-name", "none");
579
- flushComputedAnimationName(el);
580
- ledger.set("animation-name", name);
581
- }
582
- function createCssInstance(el, ledger, animationNames, scrubbed = false) {
583
- const ownedNames = new Set(animationNames);
584
- let settle;
585
- let finished = new Promise((resolve) => {
586
- settle = resolve;
587
- });
588
- let activatedBefore = false;
589
- function watch(animations) {
590
- if (animations.length === 0) {
591
- settle?.();
592
- return;
593
- }
594
- void Promise.all(animations.map((a) => a.finished.catch(() => void 0))).then(() => settle?.());
595
- }
596
- return {
597
- activate() {
598
- finished = new Promise((resolve) => {
599
- settle = resolve;
600
- });
601
- if (scrubbed) {
602
- settle?.();
603
- return;
604
- }
605
- let animations = ownedAnimationsOf(el, ownedNames);
606
- if (!activatedBefore) {
607
- restartCssAnimation(el, ledger);
608
- ledger.set("animation-play-state", "running");
609
- animations = ownedAnimationsOf(el, ownedNames);
610
- } else {
611
- const stale = animations.filter((a) => a.playState === "finished");
612
- if (stale.length > 0) {
613
- for (const animation of stale) animation.reverse();
614
- } else {
615
- ledger.set("animation-play-state", "running");
616
- }
617
- }
618
- activatedBefore = true;
619
- watch(animations);
620
- },
621
- cancel() {
622
- for (const animation of ownedAnimationsOf(el, ownedNames)) animation.cancel();
623
- settle?.();
624
- },
625
- finish() {
626
- for (const animation of ownedAnimationsOf(el, ownedNames)) animation.finish();
627
- settle?.();
628
- },
629
- get finished() {
630
- return finished;
631
- },
632
- destroy() {
633
- settle?.();
634
- }
635
- };
636
- }
637
- function continuousSetup(cleanup) {
638
- return { cleanup, continuous: true };
639
- }
640
- function cleanupOf(result) {
641
- if (result === void 0) return void 0;
642
- return typeof result === "function" ? result : result.cleanup;
643
- }
644
- function deferredInstance(setup) {
645
- let running;
646
- let settle;
647
- let finished = Promise.resolve();
648
- const teardown = () => {
649
- cleanupOf(running)?.();
650
- running = void 0;
651
- settle?.();
652
- };
653
- return createJsInstance({
654
- activate() {
655
- running = setup();
656
- if (typeof running === "function" || "continuous" in running) return;
657
- const work = running.finished;
658
- finished = new Promise((resolve) => {
659
- settle = resolve;
660
- });
661
- void work.then(() => settle?.());
662
- },
663
- cancel: teardown,
664
- finish() {
665
- if (typeof running === "object" && "finish" in running) running.finish?.();
666
- settle?.();
667
- },
668
- destroy: teardown,
669
- finished: () => finished,
670
- // Only an explicit marker counts. A bare `Cleanup` deliberately does not — see
671
- // `ContinuousSetup` above for why the two cannot be told apart by shape.
672
- continuous: () => typeof running === "object" && "continuous" in running
673
- });
674
- }
675
- function deferPrepare(setup) {
676
- return (...args) => deferredInstance(() => setup(...args));
677
- }
678
- function createJsInstance(hooks) {
679
- let active = false;
680
- return {
681
- activate() {
682
- if (active) return;
683
- hooks.activate();
684
- active = true;
685
- },
686
- cancel() {
687
- hooks.cancel?.();
688
- active = false;
689
- },
690
- finish() {
691
- hooks.finish?.();
692
- },
693
- get finished() {
694
- return hooks.finished?.() ?? Promise.resolve();
695
- },
696
- get continuous() {
697
- return hooks.continuous?.() ?? false;
698
- },
699
- destroy() {
700
- active = false;
701
- hooks.destroy();
702
- }
703
- };
704
- }
705
-
706
- // src/core/owned-styles.ts
707
- function createStyleLedger(el) {
708
- const style = el.style;
709
- const previous = /* @__PURE__ */ new Map();
710
- const authoredStyleAttribute = el.hasAttribute("style");
711
- function remember(property) {
712
- if (previous.has(property)) return;
713
- const existing = style.getPropertyValue(property);
714
- previous.set(property, existing === "" ? void 0 : existing);
715
- }
716
- return {
717
- set(property, value) {
718
- remember(property);
719
- style.setProperty(property, value);
720
- },
721
- claim: remember,
722
- restore() {
723
- for (const [property, value] of previous) {
724
- if (value === void 0) style.removeProperty(property);
725
- else style.setProperty(property, value);
726
- }
727
- previous.clear();
728
- if (!authoredStyleAttribute && style.length === 0 && !el.getAttribute("style"))
729
- el.removeAttribute("style");
730
- },
731
- owned: () => [...previous.keys()]
732
- };
733
- }
734
- function createAttributeLedger(el) {
735
- const previous = /* @__PURE__ */ new Map();
736
- return {
737
- set(name, value) {
738
- if (!previous.has(name)) previous.set(name, el.getAttribute(name));
739
- el.setAttribute(name, value);
740
- },
741
- restore() {
742
- for (const [name, value] of previous) {
743
- if (value === null) el.removeAttribute(name);
744
- else el.setAttribute(name, value);
745
- }
746
- previous.clear();
747
- }
748
- };
749
- }
750
-
751
- export {
752
- isSameOriginPath,
753
- resolveParams,
754
- Registry,
755
- timingProperty,
756
- suggest,
757
- ABSOLUTE_BASIS,
758
- toPixels,
759
- readEffectTiming,
760
- effectDurationMs,
761
- readEffectParams,
762
- createScrollScheduler,
763
- createRootResolver,
764
- clamp01,
765
- createMeasureCache,
766
- createCssInstance,
767
- continuousSetup,
768
- deferPrepare,
769
- createStyleLedger,
770
- createAttributeLedger,
771
- CHANNEL,
772
- inertInstance
773
- };