@voila.dev/motion 6.0.123 → 6.0.124
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animate/dom.d.ts.map +1 -1
- package/dist/animate/dom.js +7 -1
- package/dist/animate/dom.js.map +2 -2
- package/dist/animate/style.d.ts.map +1 -1
- package/dist/animate/style.js +3 -1
- package/dist/animate/style.js.map +2 -2
- package/dist/sequence/sequence.d.ts.map +1 -1
- package/dist/sequence/sequence.js +33 -9
- package/dist/sequence/sequence.js.map +3 -3
- package/package.json +1 -1
- package/src/animate/dom.ts +13 -1
- package/src/animate/style.ts +4 -1
- package/src/sequence/sequence.ts +33 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/animate/dom.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAUhF,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,MAAM,oBAAoB,CAAC;AAuB5B;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAC7B,MAAM,EAAE,iBAAiB,CAAC,aAAa,CAAC,KACpC,WAAW,CAAC,aAAa,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"dom.d.ts","sourceRoot":"","sources":["../../src/animate/dom.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAUhF,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,MAAM,oBAAoB,CAAC;AAuB5B;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,CAC7B,MAAM,EAAE,iBAAiB,CAAC,aAAa,CAAC,KACpC,WAAW,CAAC,aAAa,CAAC,CAAC;AA+GhC,qFAAqF;AACrF,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,gBAAgB,EACzB,QAAQ,CAAC,EAAE,eAAe,GACxB,iBAAiB,CAanB"}
|
package/dist/animate/dom.js
CHANGED
|
@@ -28,6 +28,12 @@ const SVG_ATTRIBUTES = {
|
|
|
28
28
|
attrWidth: "width",
|
|
29
29
|
attrHeight: "height"
|
|
30
30
|
};
|
|
31
|
+
const COMPOSITES = {
|
|
32
|
+
translate: "add",
|
|
33
|
+
scale: "add",
|
|
34
|
+
rotate: "add",
|
|
35
|
+
transform: "accumulate"
|
|
36
|
+
};
|
|
31
37
|
const running = /* @__PURE__ */ new WeakMap();
|
|
32
38
|
function channelOf(element, key) {
|
|
33
39
|
const style = element.style;
|
|
@@ -86,7 +92,7 @@ function animateChannel(element, key, value, options, delay, scripted) {
|
|
|
86
92
|
element,
|
|
87
93
|
property: transform?.property ?? key,
|
|
88
94
|
format: (frame) => transform ? transform.alone(withUnit(key, frame)) : withUnit(key, frame),
|
|
89
|
-
composite: transform
|
|
95
|
+
composite: COMPOSITES[transform?.property ?? ""] ?? "replace",
|
|
90
96
|
commit: channel.write
|
|
91
97
|
}) : scripted({ ...config, apply: channel.write });
|
|
92
98
|
animations.set(key, animation);
|
package/dist/animate/dom.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/animate/dom.ts"],
|
|
4
|
-
"sourcesContent": ["import { shouldReduceMotion } from \"#/accessibility/reduced-motion.ts\";\nimport { finishedControls, groupControls } from \"#/animate/controls.ts\";\nimport type { JsAnimation, JsAnimationConfig } from \"#/animate/js-animation.ts\";\nimport {\n\tbeginTransform,\n\tcommitTransform,\n\tcommittedTransform,\n\tcssName,\n\tisMovement,\n\tTRANSFORMS,\n\twithUnit,\n} from \"#/animate/style.ts\";\nimport type {\n\tAnimationControls,\n\tAnimationOptions,\n\tDOMKeyframes,\n\tKeyframeValue,\n} from \"#/animate/types.ts\";\nimport { waapiAnimation } from \"#/animate/waapi.ts\";\n\n/** Attributes an SVG element animates in JavaScript: `d` morphs, the rest are geometry. */\nconst SVG_ATTRIBUTES: Readonly<Record<string, string>> = {\n\td: \"d\",\n\tpoints: \"points\",\n\tviewBox: \"viewBox\",\n\tcx: \"cx\",\n\tcy: \"cy\",\n\tr: \"r\",\n\trx: \"rx\",\n\try: \"ry\",\n\tx1: \"x1\",\n\ty1: \"y1\",\n\tx2: \"x2\",\n\ty2: \"y2\",\n\tattrX: \"x\",\n\tattrY: \"y\",\n\tattrWidth: \"width\",\n\tattrHeight: \"height\",\n};\n\n/**\n * Plays what the browser can't (SVG attributes, CSS variables) on the frame\n * loop. Injected, so an entry that only needs the browser's half never loads\n * the interpolators.\n */\nexport type ScriptedChannel = (\n\tconfig: JsAnimationConfig<KeyframeValue>,\n) => JsAnimation<KeyframeValue>;\n\nconst running = new WeakMap<Element, Map<string, JsAnimation<KeyframeValue>>>();\n\ninterface Channel {\n\tread(): KeyframeValue;\n\twrite(value: KeyframeValue): void;\n\treadonly native: boolean;\n}\n\nfunction channelOf(element: Element, key: string): Channel {\n\tconst style = (element as HTMLElement).style;\n\tconst attribute =\n\t\telement instanceof SVGElement ? SVG_ATTRIBUTES[key] : undefined;\n\tif (TRANSFORMS[key]) {\n\t\treturn {\n\t\t\tread: () => committedTransform(element, key),\n\t\t\twrite: (value) => commitTransform(element, key, value),\n\t\t\tnative: true,\n\t\t};\n\t}\n\tif (attribute) {\n\t\treturn {\n\t\t\tread: () => element.getAttribute(attribute) ?? \"\",\n\t\t\twrite: (value) => element.setAttribute(attribute, String(value)),\n\t\t\tnative: false,\n\t\t};\n\t}\n\tconst name = cssName(key);\n\treturn {\n\t\tread: () => getComputedStyle(element).getPropertyValue(name).trim(),\n\t\twrite: (value) => style.setProperty(name, withUnit(key, value)),\n\t\t// An unregistered custom property only animates discretely in the browser.\n\t\tnative: !key.startsWith(\"--\"),\n\t};\n}\n\nfunction asTarget(read: KeyframeValue, target: KeyframeValue): KeyframeValue {\n\treturn typeof target === \"number\" && typeof read === \"string\"\n\t\t? Number.parseFloat(read) || 0\n\t\t: read;\n}\n\nfunction animateChannel(\n\telement: Element,\n\tkey: string,\n\tvalue: KeyframeValue | readonly KeyframeValue[],\n\toptions: AnimationOptions,\n\tdelay: number,\n\tscripted: ScriptedChannel | undefined,\n): AnimationControls {\n\tconst channel = channelOf(element, key);\n\tconst list: readonly KeyframeValue[] = Array.isArray(value) ? value : [value];\n\tconst target = list.at(-1) as KeyframeValue;\n\tconst animations = running.get(element) ?? new Map();\n\trunning.set(element, animations);\n\tconst previous = animations.get(key);\n\tconst now = previous?.current();\n\tprevious?.stop();\n\tconst from = now?.value ?? asTarget(channel.read(), target);\n\tconst keyframes = list.length > 1 ? list : [from, target];\n\tif (\n\t\t(shouldReduceMotion(options.reducedMotion) && isMovement(key)) ||\n\t\t(!channel.native && !scripted)\n\t) {\n\t\tchannel.write(target);\n\t\treturn finishedControls();\n\t}\n\tconst reduced = shouldReduceMotion(options.reducedMotion)\n\t\t? { ...options, type: \"tween\" as const, bounce: 0 }\n\t\t: options;\n\tconst config = {\n\t\tkeyframes,\n\t\toptions: reduced,\n\t\tdelay,\n\t\tvelocity: list.length > 1 ? 0 : (now?.velocity ?? 0),\n\t};\n\tconst transform = TRANSFORMS[key];\n\tif (transform) beginTransform(element, key);\n\tconst animation = channel.native\n\t\t? waapiAnimation({\n\t\t\t\t...config,\n\t\t\t\telement,\n\t\t\t\tproperty: transform?.property ?? key,\n\t\t\t\tformat: (frame) =>\n\t\t\t\t\ttransform\n\t\t\t\t\t\t? transform.alone(withUnit(key, frame))\n\t\t\t\t\t\t: withUnit(key, frame),\n\t\t\t\tcomposite: transform
|
|
5
|
-
"mappings": "AAAA,SAAS,0BAA0B;AACnC,SAAS,kBAAkB,qBAAqB;AAEhD;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AAOP,SAAS,sBAAsB;AAG/B,MAAM,iBAAmD;AAAA,EACxD,GAAG;AAAA,EACH,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,GAAG;AAAA,EACH,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,WAAW;AAAA,EACX,YAAY;AACb;
|
|
4
|
+
"sourcesContent": ["import { shouldReduceMotion } from \"#/accessibility/reduced-motion.ts\";\nimport { finishedControls, groupControls } from \"#/animate/controls.ts\";\nimport type { JsAnimation, JsAnimationConfig } from \"#/animate/js-animation.ts\";\nimport {\n\tbeginTransform,\n\tcommitTransform,\n\tcommittedTransform,\n\tcssName,\n\tisMovement,\n\tTRANSFORMS,\n\twithUnit,\n} from \"#/animate/style.ts\";\nimport type {\n\tAnimationControls,\n\tAnimationOptions,\n\tDOMKeyframes,\n\tKeyframeValue,\n} from \"#/animate/types.ts\";\nimport { waapiAnimation } from \"#/animate/waapi.ts\";\n\n/** Attributes an SVG element animates in JavaScript: `d` morphs, the rest are geometry. */\nconst SVG_ATTRIBUTES: Readonly<Record<string, string>> = {\n\td: \"d\",\n\tpoints: \"points\",\n\tviewBox: \"viewBox\",\n\tcx: \"cx\",\n\tcy: \"cy\",\n\tr: \"r\",\n\trx: \"rx\",\n\try: \"ry\",\n\tx1: \"x1\",\n\ty1: \"y1\",\n\tx2: \"x2\",\n\ty2: \"y2\",\n\tattrX: \"x\",\n\tattrY: \"y\",\n\tattrWidth: \"width\",\n\tattrHeight: \"height\",\n};\n\n/**\n * Plays what the browser can't (SVG attributes, CSS variables) on the frame\n * loop. Injected, so an entry that only needs the browser's half never loads\n * the interpolators.\n */\nexport type ScriptedChannel = (\n\tconfig: JsAnimationConfig<KeyframeValue>,\n) => JsAnimation<KeyframeValue>;\n\n/**\n * The independent transforms add up. The listed ones (`transform`)\n * accumulate: function by function, so their order never depends on which\n * started first.\n */\nconst COMPOSITES: Readonly<Record<string, CompositeOperation>> = {\n\ttranslate: \"add\",\n\tscale: \"add\",\n\trotate: \"add\",\n\ttransform: \"accumulate\",\n};\n\nconst running = new WeakMap<Element, Map<string, JsAnimation<KeyframeValue>>>();\n\ninterface Channel {\n\tread(): KeyframeValue;\n\twrite(value: KeyframeValue): void;\n\treadonly native: boolean;\n}\n\nfunction channelOf(element: Element, key: string): Channel {\n\tconst style = (element as HTMLElement).style;\n\tconst attribute =\n\t\telement instanceof SVGElement ? SVG_ATTRIBUTES[key] : undefined;\n\tif (TRANSFORMS[key]) {\n\t\treturn {\n\t\t\tread: () => committedTransform(element, key),\n\t\t\twrite: (value) => commitTransform(element, key, value),\n\t\t\tnative: true,\n\t\t};\n\t}\n\tif (attribute) {\n\t\treturn {\n\t\t\tread: () => element.getAttribute(attribute) ?? \"\",\n\t\t\twrite: (value) => element.setAttribute(attribute, String(value)),\n\t\t\tnative: false,\n\t\t};\n\t}\n\tconst name = cssName(key);\n\treturn {\n\t\tread: () => getComputedStyle(element).getPropertyValue(name).trim(),\n\t\twrite: (value) => style.setProperty(name, withUnit(key, value)),\n\t\t// An unregistered custom property only animates discretely in the browser.\n\t\tnative: !key.startsWith(\"--\"),\n\t};\n}\n\nfunction asTarget(read: KeyframeValue, target: KeyframeValue): KeyframeValue {\n\treturn typeof target === \"number\" && typeof read === \"string\"\n\t\t? Number.parseFloat(read) || 0\n\t\t: read;\n}\n\nfunction animateChannel(\n\telement: Element,\n\tkey: string,\n\tvalue: KeyframeValue | readonly KeyframeValue[],\n\toptions: AnimationOptions,\n\tdelay: number,\n\tscripted: ScriptedChannel | undefined,\n): AnimationControls {\n\tconst channel = channelOf(element, key);\n\tconst list: readonly KeyframeValue[] = Array.isArray(value) ? value : [value];\n\tconst target = list.at(-1) as KeyframeValue;\n\tconst animations = running.get(element) ?? new Map();\n\trunning.set(element, animations);\n\tconst previous = animations.get(key);\n\tconst now = previous?.current();\n\tprevious?.stop();\n\tconst from = now?.value ?? asTarget(channel.read(), target);\n\tconst keyframes = list.length > 1 ? list : [from, target];\n\tif (\n\t\t(shouldReduceMotion(options.reducedMotion) && isMovement(key)) ||\n\t\t(!channel.native && !scripted)\n\t) {\n\t\tchannel.write(target);\n\t\treturn finishedControls();\n\t}\n\tconst reduced = shouldReduceMotion(options.reducedMotion)\n\t\t? { ...options, type: \"tween\" as const, bounce: 0 }\n\t\t: options;\n\tconst config = {\n\t\tkeyframes,\n\t\toptions: reduced,\n\t\tdelay,\n\t\tvelocity: list.length > 1 ? 0 : (now?.velocity ?? 0),\n\t};\n\tconst transform = TRANSFORMS[key];\n\tif (transform) beginTransform(element, key);\n\tconst animation = channel.native\n\t\t? waapiAnimation({\n\t\t\t\t...config,\n\t\t\t\telement,\n\t\t\t\tproperty: transform?.property ?? key,\n\t\t\t\tformat: (frame) =>\n\t\t\t\t\ttransform\n\t\t\t\t\t\t? transform.alone(withUnit(key, frame))\n\t\t\t\t\t\t: withUnit(key, frame),\n\t\t\t\tcomposite: COMPOSITES[transform?.property ?? \"\"] ?? \"replace\",\n\t\t\t\tcommit: channel.write,\n\t\t\t})\n\t\t: (scripted as ScriptedChannel)({ ...config, apply: channel.write });\n\tanimations.set(key, animation);\n\tanimation.finished.then(() => {\n\t\tif (animations.get(key) === animation) animations.delete(key);\n\t});\n\treturn animation;\n}\n\n/** Every key of every element, each its own animation, under one set of controls. */\nexport function animateElements(\n\telements: readonly Element[],\n\tkeyframes: DOMKeyframes,\n\toptions: AnimationOptions,\n\tscripted?: ScriptedChannel,\n): AnimationControls {\n\tconst { delay } = options;\n\treturn groupControls(\n\t\telements.flatMap((element, index) => {\n\t\t\tconst start =\n\t\t\t\ttypeof delay === \"function\"\n\t\t\t\t\t? delay(index, elements.length)\n\t\t\t\t\t: (delay ?? 0);\n\t\t\treturn Object.entries(keyframes).map(([key, value]) =>\n\t\t\t\tanimateChannel(element, key, value, options, start, scripted),\n\t\t\t);\n\t\t}),\n\t);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../src/animate/style.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,KAAK,iBAAiB,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AAExE,UAAU,gBAAgB;IACzB,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1C;AASD;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"style.d.ts","sourceRoot":"","sources":["../../src/animate/style.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAExD,KAAK,iBAAiB,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;AAExE,UAAU,gBAAgB;IACzB,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1C;AASD;;;;GAIG;AACH,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAqCjE,CAAC;AAiBF,2DAA2D;AAC3D,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAMlE;AAkBD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAKxE;AASD,4FAA4F;AAC5F,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,QAgB/C;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,QAG3D;AAED,wBAAgB,eAAe,CAC9B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,aAAa,QAKpB;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI3C;AAED,mGAAmG;AACnG,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE/C"}
|
package/dist/animate/style.js
CHANGED
|
@@ -29,7 +29,9 @@ const TRANSFORMS = {
|
|
|
29
29
|
property: "transform",
|
|
30
30
|
unit: "deg",
|
|
31
31
|
identity: 0,
|
|
32
|
-
|
|
32
|
+
// The whole list, the others at identity: accumulated onto the
|
|
33
|
+
// inline list, every function keeps its place whatever starts when.
|
|
34
|
+
alone: (v) => LISTED.map((one) => `${one}(${one === key ? v : "0deg"})`).join(" ")
|
|
33
35
|
}
|
|
34
36
|
])
|
|
35
37
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/animate/style.ts"],
|
|
4
|
-
"sourcesContent": ["import type { KeyframeValue } from \"#/animate/types.ts\";\n\ntype TransformProperty = \"translate\" | \"scale\" | \"rotate\" | \"transform\";\n\ninterface TransformChannel {\n\treadonly property: TransformProperty;\n\treadonly unit: string;\n\treadonly identity: number;\n\t/** The channel alone as a value of its property, the other axes at identity. */\n\treadonly alone: (value: string) => string;\n}\n\n/**\n * The transforms with no CSS property of their own (`rotate` takes one axis,\n * and skew has none): they go through `transform`, in this order, after\n * `translate`, `rotate` and `scale`.\n */\nconst LISTED = [\"rotateX\", \"rotateY\", \"skew\", \"skewX\", \"skewY\"];\n\n/**\n * The independent transforms. Each animates its CSS property alone with\n * `composite: \"add\"`, so `x` and `y` run as two compositor animations that\n * sum, and one can be interrupted without touching the other.\n */\nexport const TRANSFORMS: Readonly<Record<string, TransformChannel>> = {\n\tx: { property: \"translate\", unit: \"px\", identity: 0, alone: (v) => `${v}` },\n\ty: {\n\t\tproperty: \"translate\",\n\t\tunit: \"px\",\n\t\tidentity: 0,\n\t\talone: (v) => `0px ${v}`,\n\t},\n\tz: {\n\t\tproperty: \"translate\",\n\t\tunit: \"px\",\n\t\tidentity: 0,\n\t\talone: (v) => `0px 0px ${v}`,\n\t},\n\tscale: { property: \"scale\", unit: \"\", identity: 1, alone: (v) => `${v}` },\n\tscaleX: { property: \"scale\", unit: \"\", identity: 1, alone: (v) => `${v} 1` },\n\tscaleY: { property: \"scale\", unit: \"\", identity: 1, alone: (v) => `1 ${v}` },\n\trotate: {\n\t\tproperty: \"rotate\",\n\t\tunit: \"deg\",\n\t\tidentity: 0,\n\t\talone: (v) => `${v}`,\n\t},\n\t...Object.fromEntries(\n\t\tLISTED.map((key) => [\n\t\t\tkey,\n\t\t\t{\n\t\t\t\tproperty: \"transform\",\n\t\t\t\tunit: \"deg\",\n\t\t\t\tidentity: 0,\n\t\t\t\talone: (v: string) => `${
|
|
5
|
-
"mappings": "AAiBA,MAAM,SAAS,CAAC,WAAW,WAAW,QAAQ,SAAS,OAAO;AAOvD,MAAM,aAAyD;AAAA,EACrE,GAAG,EAAE,UAAU,aAAa,MAAM,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG;AAAA,EAC1E,GAAG;AAAA,IACF,UAAU;AAAA,IACV,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO,CAAC,MAAM,OAAO,CAAC;AAAA,EACvB;AAAA,EACA,GAAG;AAAA,IACF,UAAU;AAAA,IACV,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO,CAAC,MAAM,WAAW,CAAC;AAAA,EAC3B;AAAA,EACA,OAAO,EAAE,UAAU,SAAS,MAAM,IAAI,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,GAAG;AAAA,EACxE,QAAQ,EAAE,UAAU,SAAS,MAAM,IAAI,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,KAAK;AAAA,EAC3E,QAAQ,EAAE,UAAU,SAAS,MAAM,IAAI,UAAU,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,GAAG;AAAA,EAC3E,QAAQ;AAAA,IACP,UAAU;AAAA,IACV,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO,CAAC,MAAM,GAAG,CAAC;AAAA,EACnB;AAAA,EACA,GAAG,OAAO;AAAA,IACT,OAAO,IAAI,CAAC,QAAQ;AAAA,MACnB;AAAA,MACA;AAAA,QACC,UAAU;AAAA,QACV,MAAM;AAAA,QACN,UAAU;AAAA,
|
|
4
|
+
"sourcesContent": ["import type { KeyframeValue } from \"#/animate/types.ts\";\n\ntype TransformProperty = \"translate\" | \"scale\" | \"rotate\" | \"transform\";\n\ninterface TransformChannel {\n\treadonly property: TransformProperty;\n\treadonly unit: string;\n\treadonly identity: number;\n\t/** The channel alone as a value of its property, the other axes at identity. */\n\treadonly alone: (value: string) => string;\n}\n\n/**\n * The transforms with no CSS property of their own (`rotate` takes one axis,\n * and skew has none): they go through `transform`, in this order, after\n * `translate`, `rotate` and `scale`.\n */\nconst LISTED = [\"rotateX\", \"rotateY\", \"skew\", \"skewX\", \"skewY\"];\n\n/**\n * The independent transforms. Each animates its CSS property alone with\n * `composite: \"add\"`, so `x` and `y` run as two compositor animations that\n * sum, and one can be interrupted without touching the other.\n */\nexport const TRANSFORMS: Readonly<Record<string, TransformChannel>> = {\n\tx: { property: \"translate\", unit: \"px\", identity: 0, alone: (v) => `${v}` },\n\ty: {\n\t\tproperty: \"translate\",\n\t\tunit: \"px\",\n\t\tidentity: 0,\n\t\talone: (v) => `0px ${v}`,\n\t},\n\tz: {\n\t\tproperty: \"translate\",\n\t\tunit: \"px\",\n\t\tidentity: 0,\n\t\talone: (v) => `0px 0px ${v}`,\n\t},\n\tscale: { property: \"scale\", unit: \"\", identity: 1, alone: (v) => `${v}` },\n\tscaleX: { property: \"scale\", unit: \"\", identity: 1, alone: (v) => `${v} 1` },\n\tscaleY: { property: \"scale\", unit: \"\", identity: 1, alone: (v) => `1 ${v}` },\n\trotate: {\n\t\tproperty: \"rotate\",\n\t\tunit: \"deg\",\n\t\tidentity: 0,\n\t\talone: (v) => `${v}`,\n\t},\n\t...Object.fromEntries(\n\t\tLISTED.map((key) => [\n\t\t\tkey,\n\t\t\t{\n\t\t\t\tproperty: \"transform\",\n\t\t\t\tunit: \"deg\",\n\t\t\t\tidentity: 0,\n\t\t\t\t// The whole list, the others at identity: accumulated onto the\n\t\t\t\t// inline list, every function keeps its place whatever starts when.\n\t\t\t\talone: (v: string) =>\n\t\t\t\t\tLISTED.map((one) => `${one}(${one === key ? v : \"0deg\"})`).join(\" \"),\n\t\t\t},\n\t\t]),\n\t),\n};\n\nconst UNITLESS = new Set([\n\t\"opacity\",\n\t\"zIndex\",\n\t\"fontWeight\",\n\t\"lineHeight\",\n\t\"flexGrow\",\n\t\"flexShrink\",\n\t\"order\",\n\t\"fillOpacity\",\n\t\"strokeOpacity\",\n\t\"strokeMiterlimit\",\n\t\"aspectRatio\",\n\t\"pathLength\",\n]);\n\n/** A keyframe as CSS: numbers take the property's unit. */\nexport function withUnit(key: string, value: KeyframeValue): string {\n\tif (typeof value === \"string\") return value;\n\tconst unit =\n\t\tTRANSFORMS[key]?.unit ??\n\t\t(UNITLESS.has(key) || key.startsWith(\"--\") ? \"\" : \"px\");\n\treturn `${value}${unit}`;\n}\n\n/** Committed transform values per element, the ones no animation is driving. */\nconst committed = new WeakMap<Element, Map<string, KeyframeValue>>();\nconst animating = new WeakMap<Element, Set<string>>();\n\nfunction entries<T>(\n\tmap: WeakMap<Element, T>,\n\telement: Element,\n\tfresh: () => T,\n) {\n\tconst existing = map.get(element);\n\tif (existing) return existing;\n\tconst created = fresh();\n\tmap.set(element, created);\n\treturn created;\n}\n\nexport function committedTransform(element: Element, key: string): number {\n\tconst value = committed.get(element)?.get(key);\n\treturn typeof value === \"number\"\n\t\t? value\n\t\t: Number.parseFloat(value ?? \"\") || (TRANSFORMS[key]?.identity ?? 0);\n}\n\nfunction channel(element: Element, key: string): string {\n\tconst channelDef = TRANSFORMS[key] as TransformChannel;\n\tif (animating.get(element)?.has(key))\n\t\treturn `${channelDef.identity}${channelDef.unit}`;\n\treturn withUnit(key, committed.get(element)?.get(key) ?? channelDef.identity);\n}\n\n/** Writes the committed transforms inline, with every animating channel at its identity. */\nexport function writeTransforms(element: Element) {\n\tconst style = (element as HTMLElement).style;\n\tconst at = (key: string) => channel(element, key);\n\tstyle.translate = `${at(\"x\")} ${at(\"y\")} ${at(\"z\")}`;\n\tconst uniform = Number.parseFloat(at(\"scale\"));\n\tstyle.scale = `${uniform * Number.parseFloat(at(\"scaleX\"))} ${uniform * Number.parseFloat(at(\"scaleY\"))}`;\n\tstyle.rotate = at(\"rotate\");\n\t// `transform` stays the page's on an element that never animates these.\n\tif (\n\t\tLISTED.some(\n\t\t\t(key) =>\n\t\t\t\tcommitted.get(element)?.has(key) || animating.get(element)?.has(key),\n\t\t)\n\t) {\n\t\tstyle.transform = LISTED.map((key) => `${key}(${at(key)})`).join(\" \");\n\t}\n}\n\nexport function beginTransform(element: Element, key: string) {\n\tentries(animating, element, () => new Set()).add(key);\n\twriteTransforms(element);\n}\n\nexport function commitTransform(\n\telement: Element,\n\tkey: string,\n\tvalue: KeyframeValue,\n) {\n\tentries(committed, element, () => new Map()).set(key, value);\n\tanimating.get(element)?.delete(key);\n\twriteTransforms(element);\n}\n\nexport function cssName(key: string): string {\n\treturn key.startsWith(\"--\")\n\t\t? key\n\t\t: key.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);\n}\n\n/** Moves things on screen, as opposed to fading or tinting them: what reduced motion turns off. */\nexport function isMovement(key: string): boolean {\n\treturn !/opacity|color|fill|stroke$|filter/i.test(key);\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../src/sequence/sequence.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,SAAS,EACT,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM,CAAC;AAE7E,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACvD,QAAQ,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,MAAM,MAAM,OAAO,GAChB,SAAS,CAAC,aAAa,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC,GAEvD,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC,GAC5D,MAAM,GACN;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,UAAU,GAAG,CACxB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,gBAAgB,KACrB,iBAAiB,CAAC;AAEvB,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,SAAS,MAAM,EAAE,CAAC;AA6CpE;;;;;GAKG;AACH,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,OAAO,EAAE,gBAAgB,EACzB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,GAC5B,iBAAiB,
|
|
1
|
+
{"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../../src/sequence/sequence.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,SAAS,EACT,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM,CAAC;AAE7E,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACvD,QAAQ,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC;CACzB;AAED,MAAM,MAAM,OAAO,GAChB,SAAS,CAAC,aAAa,EAAE,YAAY,EAAE,cAAc,CAAC,CAAC,GAEvD,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC,GAC5D,MAAM,GACN;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,UAAU,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,UAAU,GAAG,CACxB,MAAM,EAAE,OAAO,EACf,SAAS,EAAE,OAAO,EAClB,OAAO,EAAE,gBAAgB,KACrB,iBAAiB,CAAC;AAEvB,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,OAAO,KAAK,SAAS,MAAM,EAAE,CAAC;AA6CpE;;;;;GAKG;AACH,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,SAAS,OAAO,EAAE,EAC5B,OAAO,EAAE,gBAAgB,EACzB,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,GAC5B,iBAAiB,CA4GnB"}
|
|
@@ -24,24 +24,34 @@ function plannedDuration(keyframes, options) {
|
|
|
24
24
|
);
|
|
25
25
|
}
|
|
26
26
|
function animateSequence(segments, options, animateOne, resolveTargets) {
|
|
27
|
-
|
|
27
|
+
let rate = 1;
|
|
28
|
+
let base = 0;
|
|
29
|
+
let since = now();
|
|
30
|
+
function elapsed() {
|
|
31
|
+
return base + (now() - since) / 1e3 * rate;
|
|
32
|
+
}
|
|
28
33
|
const labels = /* @__PURE__ */ new Map();
|
|
29
34
|
const busy = /* @__PURE__ */ new Map();
|
|
30
35
|
const children = [];
|
|
36
|
+
const late = [];
|
|
31
37
|
const waits = [];
|
|
32
38
|
let end = 0;
|
|
33
39
|
let cursor = 0;
|
|
34
40
|
let previousStart = 0;
|
|
35
41
|
for (const segment of segments) {
|
|
36
|
-
let optionsAt2 = function(
|
|
37
|
-
const offset = start -
|
|
42
|
+
let optionsAt2 = function(elapsed2) {
|
|
43
|
+
const offset = start - elapsed2;
|
|
38
44
|
return {
|
|
39
45
|
...options,
|
|
40
46
|
...own,
|
|
41
47
|
delay: typeof delay === "function" ? (index, total) => Math.max(0, offset + delay(index, total)) : Math.max(0, offset + (delay ?? 0))
|
|
42
48
|
};
|
|
49
|
+
}, launch2 = function() {
|
|
50
|
+
const controls = animateOne(target, keyframes, optionsAt2(elapsed()));
|
|
51
|
+
controls.speed = rate;
|
|
52
|
+
return controls;
|
|
43
53
|
};
|
|
44
|
-
var optionsAt = optionsAt2;
|
|
54
|
+
var optionsAt = optionsAt2, launch = launch2;
|
|
45
55
|
if (typeof segment === "string" || "name" in segment) {
|
|
46
56
|
const label = typeof segment === "string" ? { name: segment } : segment;
|
|
47
57
|
labels.set(label.name, startOf(label.at, cursor, previousStart, labels));
|
|
@@ -56,17 +66,21 @@ function animateSequence(segments, options, animateOne, resolveTargets) {
|
|
|
56
66
|
);
|
|
57
67
|
const start = Math.max(placed, ...before.map((earlier) => earlier.end));
|
|
58
68
|
const { delay } = own;
|
|
59
|
-
const launch = () => animateOne(target, keyframes, optionsAt2((now() - begun) / 1e3));
|
|
60
69
|
let finished2;
|
|
61
70
|
let ends;
|
|
62
71
|
if (before.length === 0) {
|
|
63
|
-
const controls =
|
|
72
|
+
const controls = launch2();
|
|
64
73
|
children.push(controls);
|
|
65
74
|
finished2 = controls.finished;
|
|
66
75
|
ends = Math.max(start, controls.duration);
|
|
67
76
|
} else {
|
|
68
77
|
finished2 = Promise.all(before.map((earlier) => earlier.finished)).then(
|
|
69
|
-
() =>
|
|
78
|
+
() => {
|
|
79
|
+
if (rate < 0) return;
|
|
80
|
+
const controls = launch2();
|
|
81
|
+
late.push(controls);
|
|
82
|
+
return controls.finished;
|
|
83
|
+
}
|
|
70
84
|
);
|
|
71
85
|
waits.push(finished2);
|
|
72
86
|
ends = start + plannedDuration(keyframes, { ...options, ...own });
|
|
@@ -84,8 +98,18 @@ function animateSequence(segments, options, animateOne, resolveTargets) {
|
|
|
84
98
|
const finished = Promise.all([group.finished, ...waits]).then(
|
|
85
99
|
() => void 0
|
|
86
100
|
);
|
|
87
|
-
Object.
|
|
88
|
-
|
|
101
|
+
Object.defineProperties(group, {
|
|
102
|
+
// The segments still waiting count too: they end after the ones launched.
|
|
103
|
+
duration: { value: Math.max(end, group.duration) },
|
|
104
|
+
speed: {
|
|
105
|
+
get: () => rate,
|
|
106
|
+
set(next) {
|
|
107
|
+
base = elapsed();
|
|
108
|
+
since = now();
|
|
109
|
+
rate = next;
|
|
110
|
+
for (const child of [...children, ...late]) child.speed = next;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
89
113
|
});
|
|
90
114
|
return Object.assign(group, thenable(finished));
|
|
91
115
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/sequence/sequence.ts"],
|
|
4
|
-
"sourcesContent": ["import { groupControls, thenable } from \"#/animate/controls.ts\";\nimport { planGenerator, totalDuration } from \"#/animate/plan.ts\";\nimport type {\n\tAnimationControls,\n\tAnimationOptions,\n\tDOMKeyframes,\n\tElementTarget,\n\tKeyframes,\n} from \"#/animate/types.ts\";\nimport { now } from \"#/frame/frame.ts\";\nimport type { MotionValue } from \"#/value/motion-value.ts\";\n\n/**\n * When a segment starts: seconds from the start of the sequence, `\"+0.1\"` or\n * `\"-0.2\"` from the end of the segment before, `\"<\"` with the segment before,\n * or the name of a label.\n */\nexport type SequenceAt = number | `+${number}` | `-${number}` | \"<\" | string;\n\nexport interface SegmentOptions extends AnimationOptions {\n\treadonly at?: SequenceAt;\n}\n\nexport type Segment =\n\t| readonly [ElementTarget, DOMKeyframes, SegmentOptions?]\n\t// biome-ignore lint/suspicious/noExplicitAny: a sequence mixes values of any type.\n\t| readonly [MotionValue<any>, Keyframes<any>, SegmentOptions?]\n\t| string\n\t| { readonly name: string; readonly at?: SequenceAt };\n\nexport type AnimateOne = (\n\ttarget: unknown,\n\tkeyframes: unknown,\n\toptions: AnimationOptions,\n) => AnimationControls;\n\nexport type ResolveTargets = (target: unknown) => readonly object[];\n\nfunction startOf(\n\tat: SequenceAt | undefined,\n\tcursor: number,\n\tpreviousStart: number,\n\tlabels: ReadonlyMap<string, number>,\n): number {\n\tif (at === undefined) return cursor;\n\tif (typeof at === \"number\") return at;\n\tif (at === \"<\") return previousStart;\n\tif (/^[+-]/.test(at)) return Math.max(0, cursor + Number(at));\n\treturn labels.get(at) ?? cursor;\n}\n\n/**\n * How long a segment that waits for an earlier one will run once launched.\n * Its first keyframe is only read then, but a tween's length doesn't depend\n * on it, and neither does a default spring's (its rest thresholds scale with\n * the distance).\n */\nfunction plannedDuration(keyframes: unknown, options: AnimationOptions) {\n\tconst channels =\n\t\ttypeof keyframes === \"object\" &&\n\t\tkeyframes !== null &&\n\t\t!Array.isArray(keyframes)\n\t\t\t? Object.values(keyframes)\n\t\t\t: [keyframes];\n\tconst { delay } = options;\n\treturn (\n\t\t(typeof delay === \"number\" ? delay : 0) +\n\t\tMath.max(\n\t\t\t0,\n\t\t\t...channels.map((channel) => {\n\t\t\t\tconst frames = Array.isArray(channel) ? channel : [0, channel];\n\t\t\t\tconst { generator } = planGenerator(\n\t\t\t\t\tframes.map((_frame, index) => index),\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\treturn totalDuration(generator.duration, options);\n\t\t\t}),\n\t\t)\n\t);\n}\n\n/**\n * Launches every segment at once, each delayed to its place on the\n * timeline, so the whole sequence shares one clock and can be scrubbed. A\n * segment that animates a property an earlier segment already animates\n * waits for that one to finish, then starts from where it left off.\n */\nexport function animateSequence(\n\tsegments: readonly Segment[],\n\toptions: AnimationOptions,\n\tanimateOne: AnimateOne,\n\tresolveTargets: ResolveTargets,\n): AnimationControls {\n\
|
|
5
|
-
"mappings": "AAAA,SAAS,eAAe,gBAAgB;AACxC,SAAS,eAAe,qBAAqB;AAQ7C,SAAS,WAAW;AA6BpB,SAAS,QACR,IACA,QACA,eACA,QACS;AACT,MAAI,OAAO,OAAW,QAAO;AAC7B,MAAI,OAAO,OAAO,SAAU,QAAO;AACnC,MAAI,OAAO,IAAK,QAAO;AACvB,MAAI,QAAQ,KAAK,EAAE,EAAG,QAAO,KAAK,IAAI,GAAG,SAAS,OAAO,EAAE,CAAC;AAC5D,SAAO,OAAO,IAAI,EAAE,KAAK;AAC1B;AAQA,SAAS,gBAAgB,WAAoB,SAA2B;AACvE,QAAM,WACL,OAAO,cAAc,YACrB,cAAc,QACd,CAAC,MAAM,QAAQ,SAAS,IACrB,OAAO,OAAO,SAAS,IACvB,CAAC,SAAS;AACd,QAAM,EAAE,MAAM,IAAI;AAClB,UACE,OAAO,UAAU,WAAW,QAAQ,KACrC,KAAK;AAAA,IACJ;AAAA,IACA,GAAG,SAAS,IAAI,CAAC,YAAY;AAC5B,YAAM,SAAS,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC,GAAG,OAAO;AAC7D,YAAM,EAAE,UAAU,IAAI;AAAA,QACrB,OAAO,IAAI,CAAC,QAAQ,UAAU,KAAK;AAAA,QACnC;AAAA,MACD;AACA,aAAO,cAAc,UAAU,UAAU,OAAO;AAAA,IACjD,CAAC;AAAA,EACF;AAEF;AAQO,SAAS,gBACf,UACA,SACA,YACA,gBACoB;
|
|
6
|
-
"names": ["optionsAt", "finished"]
|
|
4
|
+
"sourcesContent": ["import { groupControls, thenable } from \"#/animate/controls.ts\";\nimport { planGenerator, totalDuration } from \"#/animate/plan.ts\";\nimport type {\n\tAnimationControls,\n\tAnimationOptions,\n\tDOMKeyframes,\n\tElementTarget,\n\tKeyframes,\n} from \"#/animate/types.ts\";\nimport { now } from \"#/frame/frame.ts\";\nimport type { MotionValue } from \"#/value/motion-value.ts\";\n\n/**\n * When a segment starts: seconds from the start of the sequence, `\"+0.1\"` or\n * `\"-0.2\"` from the end of the segment before, `\"<\"` with the segment before,\n * or the name of a label.\n */\nexport type SequenceAt = number | `+${number}` | `-${number}` | \"<\" | string;\n\nexport interface SegmentOptions extends AnimationOptions {\n\treadonly at?: SequenceAt;\n}\n\nexport type Segment =\n\t| readonly [ElementTarget, DOMKeyframes, SegmentOptions?]\n\t// biome-ignore lint/suspicious/noExplicitAny: a sequence mixes values of any type.\n\t| readonly [MotionValue<any>, Keyframes<any>, SegmentOptions?]\n\t| string\n\t| { readonly name: string; readonly at?: SequenceAt };\n\nexport type AnimateOne = (\n\ttarget: unknown,\n\tkeyframes: unknown,\n\toptions: AnimationOptions,\n) => AnimationControls;\n\nexport type ResolveTargets = (target: unknown) => readonly object[];\n\nfunction startOf(\n\tat: SequenceAt | undefined,\n\tcursor: number,\n\tpreviousStart: number,\n\tlabels: ReadonlyMap<string, number>,\n): number {\n\tif (at === undefined) return cursor;\n\tif (typeof at === \"number\") return at;\n\tif (at === \"<\") return previousStart;\n\tif (/^[+-]/.test(at)) return Math.max(0, cursor + Number(at));\n\treturn labels.get(at) ?? cursor;\n}\n\n/**\n * How long a segment that waits for an earlier one will run once launched.\n * Its first keyframe is only read then, but a tween's length doesn't depend\n * on it, and neither does a default spring's (its rest thresholds scale with\n * the distance).\n */\nfunction plannedDuration(keyframes: unknown, options: AnimationOptions) {\n\tconst channels =\n\t\ttypeof keyframes === \"object\" &&\n\t\tkeyframes !== null &&\n\t\t!Array.isArray(keyframes)\n\t\t\t? Object.values(keyframes)\n\t\t\t: [keyframes];\n\tconst { delay } = options;\n\treturn (\n\t\t(typeof delay === \"number\" ? delay : 0) +\n\t\tMath.max(\n\t\t\t0,\n\t\t\t...channels.map((channel) => {\n\t\t\t\tconst frames = Array.isArray(channel) ? channel : [0, channel];\n\t\t\t\tconst { generator } = planGenerator(\n\t\t\t\t\tframes.map((_frame, index) => index),\n\t\t\t\t\toptions,\n\t\t\t\t);\n\t\t\t\treturn totalDuration(generator.duration, options);\n\t\t\t}),\n\t\t)\n\t);\n}\n\n/**\n * Launches every segment at once, each delayed to its place on the\n * timeline, so the whole sequence shares one clock and can be scrubbed. A\n * segment that animates a property an earlier segment already animates\n * waits for that one to finish, then starts from where it left off.\n */\nexport function animateSequence(\n\tsegments: readonly Segment[],\n\toptions: AnimationOptions,\n\tanimateOne: AnimateOne,\n\tresolveTargets: ResolveTargets,\n): AnimationControls {\n\t/** The sequence's own clock: it runs at the speed the sequence is set to. */\n\tlet rate = 1;\n\tlet base = 0;\n\tlet since = now();\n\tfunction elapsed(): number {\n\t\treturn base + ((now() - since) / 1000) * rate;\n\t}\n\tconst labels = new Map<string, number>();\n\tconst busy = new Map<\n\t\tobject,\n\t\tMap<string, { readonly finished: Promise<void>; readonly end: number }>\n\t>();\n\tconst children: AnimationControls[] = [];\n\t/** The segments that waited, once launched: they take later speed changes too. */\n\tconst late: AnimationControls[] = [];\n\tconst waits: Promise<void>[] = [];\n\tlet end = 0;\n\tlet cursor = 0;\n\tlet previousStart = 0;\n\tfor (const segment of segments) {\n\t\tif (typeof segment === \"string\" || \"name\" in segment) {\n\t\t\tconst label = typeof segment === \"string\" ? { name: segment } : segment;\n\t\t\tlabels.set(label.name, startOf(label.at, cursor, previousStart, labels));\n\t\t\tcontinue;\n\t\t}\n\t\tconst [target, keyframes, own = {}] = segment as readonly [\n\t\t\tunknown,\n\t\t\tunknown,\n\t\t\tSegmentOptions?,\n\t\t];\n\t\tconst placed = startOf(own.at, cursor, previousStart, labels);\n\t\tconst keys =\n\t\t\ttypeof keyframes === \"object\" &&\n\t\t\tkeyframes !== null &&\n\t\t\t!Array.isArray(keyframes)\n\t\t\t\t? Object.keys(keyframes)\n\t\t\t\t: [\"value\"];\n\t\tconst targets = resolveTargets(target);\n\t\tconst before = targets.flatMap((one) =>\n\t\t\tkeys.flatMap((key) => busy.get(one)?.get(key) ?? []),\n\t\t);\n\t\tconst start = Math.max(placed, ...before.map((earlier) => earlier.end));\n\t\tconst { delay } = own;\n\t\t/** Launched late, a segment only waits for what is left of its delay. */\n\t\tfunction optionsAt(elapsed: number): AnimationOptions {\n\t\t\tconst offset = start - elapsed;\n\t\t\treturn {\n\t\t\t\t...options,\n\t\t\t\t...own,\n\t\t\t\tdelay:\n\t\t\t\t\ttypeof delay === \"function\"\n\t\t\t\t\t\t? (index, total) => Math.max(0, offset + delay(index, total))\n\t\t\t\t\t\t: Math.max(0, offset + (delay ?? 0)),\n\t\t\t};\n\t\t}\n\t\tfunction launch(): AnimationControls {\n\t\t\tconst controls = animateOne(target, keyframes, optionsAt(elapsed()));\n\t\t\tcontrols.speed = rate;\n\t\t\treturn controls;\n\t\t}\n\t\tlet finished: Promise<void>;\n\t\tlet ends: number;\n\t\tif (before.length === 0) {\n\t\t\tconst controls = launch();\n\t\t\tchildren.push(controls);\n\t\t\tfinished = controls.finished;\n\t\t\tends = Math.max(start, controls.duration);\n\t\t} else {\n\t\t\t// Played backwards, the sequence went back past it: it never starts.\n\t\t\tfinished = Promise.all(before.map((earlier) => earlier.finished)).then(\n\t\t\t\t() => {\n\t\t\t\t\tif (rate < 0) return;\n\t\t\t\t\tconst controls = launch();\n\t\t\t\t\tlate.push(controls);\n\t\t\t\t\treturn controls.finished;\n\t\t\t\t},\n\t\t\t);\n\t\t\twaits.push(finished);\n\t\t\tends = start + plannedDuration(keyframes, { ...options, ...own });\n\t\t}\n\t\tcursor = ends;\n\t\tend = Math.max(end, ends);\n\t\tfor (const one of targets) {\n\t\t\tconst byKey = busy.get(one) ?? new Map();\n\t\t\tbusy.set(one, byKey);\n\t\t\tfor (const key of keys) byKey.set(key, { finished, end: ends });\n\t\t}\n\t\tpreviousStart = start;\n\t}\n\tconst group = groupControls(children);\n\tconst finished = Promise.all([group.finished, ...waits]).then(\n\t\t() => undefined,\n\t);\n\tObject.defineProperties(group, {\n\t\t// The segments still waiting count too: they end after the ones launched.\n\t\tduration: { value: Math.max(end, group.duration) },\n\t\tspeed: {\n\t\t\tget: () => rate,\n\t\t\tset(next: number) {\n\t\t\t\tbase = elapsed();\n\t\t\t\tsince = now();\n\t\t\t\trate = next;\n\t\t\t\tfor (const child of [...children, ...late]) child.speed = next;\n\t\t\t},\n\t\t},\n\t});\n\treturn Object.assign(group, thenable(finished));\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["optionsAt", "elapsed", "launch", "finished"]
|
|
7
7
|
}
|
package/package.json
CHANGED
package/src/animate/dom.ts
CHANGED
|
@@ -47,6 +47,18 @@ export type ScriptedChannel = (
|
|
|
47
47
|
config: JsAnimationConfig<KeyframeValue>,
|
|
48
48
|
) => JsAnimation<KeyframeValue>;
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* The independent transforms add up. The listed ones (`transform`)
|
|
52
|
+
* accumulate: function by function, so their order never depends on which
|
|
53
|
+
* started first.
|
|
54
|
+
*/
|
|
55
|
+
const COMPOSITES: Readonly<Record<string, CompositeOperation>> = {
|
|
56
|
+
translate: "add",
|
|
57
|
+
scale: "add",
|
|
58
|
+
rotate: "add",
|
|
59
|
+
transform: "accumulate",
|
|
60
|
+
};
|
|
61
|
+
|
|
50
62
|
const running = new WeakMap<Element, Map<string, JsAnimation<KeyframeValue>>>();
|
|
51
63
|
|
|
52
64
|
interface Channel {
|
|
@@ -133,7 +145,7 @@ function animateChannel(
|
|
|
133
145
|
transform
|
|
134
146
|
? transform.alone(withUnit(key, frame))
|
|
135
147
|
: withUnit(key, frame),
|
|
136
|
-
composite: transform
|
|
148
|
+
composite: COMPOSITES[transform?.property ?? ""] ?? "replace",
|
|
137
149
|
commit: channel.write,
|
|
138
150
|
})
|
|
139
151
|
: (scripted as ScriptedChannel)({ ...config, apply: channel.write });
|
package/src/animate/style.ts
CHANGED
|
@@ -52,7 +52,10 @@ export const TRANSFORMS: Readonly<Record<string, TransformChannel>> = {
|
|
|
52
52
|
property: "transform",
|
|
53
53
|
unit: "deg",
|
|
54
54
|
identity: 0,
|
|
55
|
-
|
|
55
|
+
// The whole list, the others at identity: accumulated onto the
|
|
56
|
+
// inline list, every function keeps its place whatever starts when.
|
|
57
|
+
alone: (v: string) =>
|
|
58
|
+
LISTED.map((one) => `${one}(${one === key ? v : "0deg"})`).join(" "),
|
|
56
59
|
},
|
|
57
60
|
]),
|
|
58
61
|
),
|
package/src/sequence/sequence.ts
CHANGED
|
@@ -91,13 +91,21 @@ export function animateSequence(
|
|
|
91
91
|
animateOne: AnimateOne,
|
|
92
92
|
resolveTargets: ResolveTargets,
|
|
93
93
|
): AnimationControls {
|
|
94
|
-
|
|
94
|
+
/** The sequence's own clock: it runs at the speed the sequence is set to. */
|
|
95
|
+
let rate = 1;
|
|
96
|
+
let base = 0;
|
|
97
|
+
let since = now();
|
|
98
|
+
function elapsed(): number {
|
|
99
|
+
return base + ((now() - since) / 1000) * rate;
|
|
100
|
+
}
|
|
95
101
|
const labels = new Map<string, number>();
|
|
96
102
|
const busy = new Map<
|
|
97
103
|
object,
|
|
98
104
|
Map<string, { readonly finished: Promise<void>; readonly end: number }>
|
|
99
105
|
>();
|
|
100
106
|
const children: AnimationControls[] = [];
|
|
107
|
+
/** The segments that waited, once launched: they take later speed changes too. */
|
|
108
|
+
const late: AnimationControls[] = [];
|
|
101
109
|
const waits: Promise<void>[] = [];
|
|
102
110
|
let end = 0;
|
|
103
111
|
let cursor = 0;
|
|
@@ -138,8 +146,11 @@ export function animateSequence(
|
|
|
138
146
|
: Math.max(0, offset + (delay ?? 0)),
|
|
139
147
|
};
|
|
140
148
|
}
|
|
141
|
-
|
|
142
|
-
animateOne(target, keyframes, optionsAt((
|
|
149
|
+
function launch(): AnimationControls {
|
|
150
|
+
const controls = animateOne(target, keyframes, optionsAt(elapsed()));
|
|
151
|
+
controls.speed = rate;
|
|
152
|
+
return controls;
|
|
153
|
+
}
|
|
143
154
|
let finished: Promise<void>;
|
|
144
155
|
let ends: number;
|
|
145
156
|
if (before.length === 0) {
|
|
@@ -148,8 +159,14 @@ export function animateSequence(
|
|
|
148
159
|
finished = controls.finished;
|
|
149
160
|
ends = Math.max(start, controls.duration);
|
|
150
161
|
} else {
|
|
162
|
+
// Played backwards, the sequence went back past it: it never starts.
|
|
151
163
|
finished = Promise.all(before.map((earlier) => earlier.finished)).then(
|
|
152
|
-
() =>
|
|
164
|
+
() => {
|
|
165
|
+
if (rate < 0) return;
|
|
166
|
+
const controls = launch();
|
|
167
|
+
late.push(controls);
|
|
168
|
+
return controls.finished;
|
|
169
|
+
},
|
|
153
170
|
);
|
|
154
171
|
waits.push(finished);
|
|
155
172
|
ends = start + plannedDuration(keyframes, { ...options, ...own });
|
|
@@ -167,9 +184,18 @@ export function animateSequence(
|
|
|
167
184
|
const finished = Promise.all([group.finished, ...waits]).then(
|
|
168
185
|
() => undefined,
|
|
169
186
|
);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
value: Math.max(end, group.duration),
|
|
187
|
+
Object.defineProperties(group, {
|
|
188
|
+
// The segments still waiting count too: they end after the ones launched.
|
|
189
|
+
duration: { value: Math.max(end, group.duration) },
|
|
190
|
+
speed: {
|
|
191
|
+
get: () => rate,
|
|
192
|
+
set(next: number) {
|
|
193
|
+
base = elapsed();
|
|
194
|
+
since = now();
|
|
195
|
+
rate = next;
|
|
196
|
+
for (const child of [...children, ...late]) child.speed = next;
|
|
197
|
+
},
|
|
198
|
+
},
|
|
173
199
|
});
|
|
174
200
|
return Object.assign(group, thenable(finished));
|
|
175
201
|
}
|