@lab206/animate 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 (53) hide show
  1. package/LICENSE +114 -0
  2. package/README.md +6 -0
  3. package/dist/animate.d.ts +28 -0
  4. package/dist/animate.d.ts.map +1 -0
  5. package/dist/animate.js +184 -0
  6. package/dist/animate.js.map +1 -0
  7. package/dist/driver.d.ts +24 -0
  8. package/dist/driver.d.ts.map +1 -0
  9. package/dist/driver.js +87 -0
  10. package/dist/driver.js.map +1 -0
  11. package/dist/easings.d.ts +6 -0
  12. package/dist/easings.d.ts.map +1 -0
  13. package/dist/easings.js +36 -0
  14. package/dist/easings.js.map +1 -0
  15. package/dist/gsap-bridge.d.ts +65 -0
  16. package/dist/gsap-bridge.d.ts.map +1 -0
  17. package/dist/gsap-bridge.js +98 -0
  18. package/dist/gsap-bridge.js.map +1 -0
  19. package/dist/gsap.d.ts +8 -0
  20. package/dist/gsap.d.ts.map +1 -0
  21. package/dist/gsap.js +21 -0
  22. package/dist/gsap.js.map +1 -0
  23. package/dist/index.d.ts +22 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +20 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/playback.d.ts +10 -0
  28. package/dist/playback.d.ts.map +1 -0
  29. package/dist/playback.js +58 -0
  30. package/dist/playback.js.map +1 -0
  31. package/dist/reduced-motion.d.ts +11 -0
  32. package/dist/reduced-motion.d.ts.map +1 -0
  33. package/dist/reduced-motion.js +25 -0
  34. package/dist/reduced-motion.js.map +1 -0
  35. package/dist/registry.d.ts +8 -0
  36. package/dist/registry.d.ts.map +1 -0
  37. package/dist/registry.js +19 -0
  38. package/dist/registry.js.map +1 -0
  39. package/dist/types.d.ts +69 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +2 -0
  42. package/dist/types.js.map +1 -0
  43. package/package.json +73 -0
  44. package/src/animate.ts +256 -0
  45. package/src/driver.ts +100 -0
  46. package/src/easings.ts +41 -0
  47. package/src/gsap-bridge.ts +183 -0
  48. package/src/gsap.ts +30 -0
  49. package/src/index.ts +45 -0
  50. package/src/playback.ts +67 -0
  51. package/src/reduced-motion.ts +23 -0
  52. package/src/registry.ts +31 -0
  53. package/src/types.ts +88 -0
@@ -0,0 +1,98 @@
1
+ import { createPlayback } from "./playback.js";
2
+ import { clearActive, getActive, setActive } from "./registry.js";
3
+ import { prefersReducedMotion } from "./reduced-motion.js";
4
+ /**
5
+ * Bind a GSAP instance (or mock) to Powers signals.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import gsap from "gsap";
10
+ * import { createGsapBridge } from "@lab206/animate/gsap";
11
+ *
12
+ * const { gsapAnimate } = createGsapBridge(gsap);
13
+ * gsapAnimate(x, 100, { duration: 400, ease: "power3.out" });
14
+ * ```
15
+ */
16
+ export function createGsapBridge(gsap) {
17
+ function run(target, from, to, options) {
18
+ getActive(target)?.cancel();
19
+ const respect = options.respectReducedMotion !== false && prefersReducedMotion();
20
+ let tween = null;
21
+ let finishedCleanup = false;
22
+ const finishClean = () => {
23
+ if (finishedCleanup)
24
+ return;
25
+ finishedCleanup = true;
26
+ clearActive(target, playback);
27
+ };
28
+ const apply = (value) => {
29
+ target.set(value);
30
+ options.onUpdate?.(value);
31
+ };
32
+ const playback = createPlayback({
33
+ onCancel: () => {
34
+ tween?.kill();
35
+ tween = null;
36
+ finishClean();
37
+ options.onCancel?.();
38
+ },
39
+ onComplete: () => {
40
+ apply(to);
41
+ tween = null;
42
+ finishClean();
43
+ options.onComplete?.();
44
+ },
45
+ });
46
+ setActive(target, playback);
47
+ if (respect || from === to) {
48
+ apply(to);
49
+ playback.complete();
50
+ return playback;
51
+ }
52
+ const proxy = { v: from };
53
+ apply(from);
54
+ const durationSec = Math.max(0, (options.duration ?? 300) / 1000);
55
+ const delaySec = Math.max(0, (options.delay ?? 0) / 1000);
56
+ // Strip reserved keys so callers cannot clobber signal wiring
57
+ const extra = { ...(options.vars ?? {}) };
58
+ delete extra.v;
59
+ delete extra.onUpdate;
60
+ delete extra.onComplete;
61
+ delete extra.onInterrupt;
62
+ delete extra.duration;
63
+ delete extra.delay;
64
+ delete extra.ease;
65
+ const toVars = {
66
+ ...extra,
67
+ v: to,
68
+ duration: durationSec,
69
+ delay: delaySec,
70
+ ease: options.ease ?? "power2.out",
71
+ onUpdate: () => {
72
+ apply(proxy.v);
73
+ },
74
+ onComplete: () => {
75
+ if (playback.playState !== "running")
76
+ return;
77
+ playback.complete();
78
+ },
79
+ };
80
+ if (typeof gsap.fromTo === "function") {
81
+ tween = gsap.fromTo(proxy, { v: from }, toVars);
82
+ }
83
+ else {
84
+ tween = gsap.to(proxy, toVars);
85
+ }
86
+ return playback;
87
+ }
88
+ return {
89
+ gsapAnimate(target, to, options = {}) {
90
+ const from = options.from !== undefined ? options.from : target.peek();
91
+ return run(target, from, to, options);
92
+ },
93
+ gsapFromTo(target, from, to, options = {}) {
94
+ return run(target, from, to, { ...options, from });
95
+ },
96
+ };
97
+ }
98
+ //# sourceMappingURL=gsap-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gsap-bridge.js","sourceRoot":"","sources":["../src/gsap-bridge.ts"],"names":[],"mappings":"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"}
package/dist/gsap.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export { createGsapBridge, type GsapLike, type GsapAnimateOptions, type GsapBridge, } from "./gsap-bridge.js";
2
+ /** Animate a number signal with GSAP (duration in ms, same as `animate()`). */
3
+ export declare const gsapAnimate: (target: import("@lab206/core").Signal<number>, to: number, options?: import("./gsap-bridge.js").GsapAnimateOptions) => import("./types.js").AnimationPlayback;
4
+ /** GSAP `fromTo` for a number signal. */
5
+ export declare const gsapFromTo: (target: import("@lab206/core").Signal<number>, from: number, to: number, options?: import("./gsap-bridge.js").GsapAnimateOptions) => import("./types.js").AnimationPlayback;
6
+ /** Re-export native cancel so one import path covers both engines. */
7
+ export { cancel } from "./registry.js";
8
+ //# sourceMappingURL=gsap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gsap.d.ts","sourceRoot":"","sources":["../src/gsap.ts"],"names":[],"mappings":"AAYA,OAAO,EACL,gBAAgB,EAChB,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,UAAU,GAChB,MAAM,kBAAkB,CAAC;AAK1B,+EAA+E;AAC/E,eAAO,MAAM,WAAW,gKAAqB,CAAC;AAE9C,yCAAyC;AACzC,eAAO,MAAM,UAAU,8KAAoB,CAAC;AAE5C,sEAAsE;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC"}
package/dist/gsap.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Optional GSAP adapter for Powers.
3
+ *
4
+ * Install peer: `pnpm add gsap`
5
+ * Import: `import { gsapAnimate } from "@lab206/animate/gsap"`
6
+ *
7
+ * Default motion remains `@lab206/animate` (no GSAP required).
8
+ * Use this for timelines, custom eases, ScrollTrigger (via `vars`), etc.
9
+ */
10
+ import gsap from "gsap";
11
+ import { createGsapBridge } from "./gsap-bridge.js";
12
+ export { createGsapBridge, } from "./gsap-bridge.js";
13
+ // Cast: we only use to/fromTo + tween.kill
14
+ const bridge = createGsapBridge(gsap);
15
+ /** Animate a number signal with GSAP (duration in ms, same as `animate()`). */
16
+ export const gsapAnimate = bridge.gsapAnimate;
17
+ /** GSAP `fromTo` for a number signal. */
18
+ export const gsapFromTo = bridge.gsapFromTo;
19
+ /** Re-export native cancel so one import path covers both engines. */
20
+ export { cancel } from "./registry.js";
21
+ //# sourceMappingURL=gsap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gsap.js","sourceRoot":"","sources":["../src/gsap.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAiB,MAAM,kBAAkB,CAAC;AAEnE,OAAO,EACL,gBAAgB,GAIjB,MAAM,kBAAkB,CAAC;AAE1B,2CAA2C;AAC3C,MAAM,MAAM,GAAG,gBAAgB,CAAC,IAA2B,CAAC,CAAC;AAE7D,+EAA+E;AAC/E,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;AAE9C,yCAAyC;AACzC,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAE5C,sEAAsE;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @lab206/animate
3
+ *
4
+ * Signal-native motion. Learn it in one line:
5
+ * animate(mySignal, 100, { duration: 300 })
6
+ *
7
+ * Optional spring feel:
8
+ * animate(mySignal, 100, spring())
9
+ *
10
+ * Optional GSAP (peer dependency):
11
+ * import { gsapAnimate } from "@lab206/animate/gsap"
12
+ * — or createGsapBridge(gsap) from this package without importing gsap here
13
+ */
14
+ export { animate, spring } from "./animate.js";
15
+ export { cancel } from "./registry.js";
16
+ export { prefersReducedMotion, setReducedMotionOverride, } from "./reduced-motion.js";
17
+ export { installDriver, createTestClock, driver, } from "./driver.js";
18
+ export { resolveEase, easeNames } from "./easings.js";
19
+ export { createGsapBridge } from "./gsap-bridge.js";
20
+ export type { GsapLike, GsapAnimateOptions, GsapBridge, } from "./gsap-bridge.js";
21
+ export type { AnimateOptions, AnimationPlayback, Animatable, Ease, EaseName, EasingFn, FrameDriver, PlayState, SpringOptions, TweenOptions, } from "./types.js";
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EACL,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,eAAe,EACf,MAAM,GACP,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EACV,QAAQ,EACR,kBAAkB,EAClB,UAAU,GACX,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,SAAS,EACT,aAAa,EACb,YAAY,GACb,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @lab206/animate
3
+ *
4
+ * Signal-native motion. Learn it in one line:
5
+ * animate(mySignal, 100, { duration: 300 })
6
+ *
7
+ * Optional spring feel:
8
+ * animate(mySignal, 100, spring())
9
+ *
10
+ * Optional GSAP (peer dependency):
11
+ * import { gsapAnimate } from "@lab206/animate/gsap"
12
+ * — or createGsapBridge(gsap) from this package without importing gsap here
13
+ */
14
+ export { animate, spring } from "./animate.js";
15
+ export { cancel } from "./registry.js";
16
+ export { prefersReducedMotion, setReducedMotionOverride, } from "./reduced-motion.js";
17
+ export { installDriver, createTestClock, driver, } from "./driver.js";
18
+ export { resolveEase, easeNames } from "./easings.js";
19
+ export { createGsapBridge } from "./gsap-bridge.js";
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EACL,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,eAAe,EACf,MAAM,GACP,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { AnimationPlayback } from "./types.js";
2
+ export interface PlaybackController extends AnimationPlayback {
3
+ /** @internal */
4
+ _resolveFinished(): void;
5
+ }
6
+ export declare function createPlayback(handlers: {
7
+ onCancel: () => void;
8
+ onComplete: () => void;
9
+ }): PlaybackController;
10
+ //# sourceMappingURL=playback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playback.d.ts","sourceRoot":"","sources":["../src/playback.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAa,MAAM,YAAY,CAAC;AAE/D,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,gBAAgB;IAChB,gBAAgB,IAAI,IAAI,CAAC;CAC1B;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE;IACvC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,EAAE,MAAM,IAAI,CAAC;CACxB,GAAG,kBAAkB,CA+CrB"}
@@ -0,0 +1,58 @@
1
+ export function createPlayback(handlers) {
2
+ let playState = "running";
3
+ let resolveFinished;
4
+ let rejectFinished;
5
+ let settled = false;
6
+ const finished = new Promise((resolve, reject) => {
7
+ resolveFinished = () => {
8
+ if (settled)
9
+ return;
10
+ settled = true;
11
+ resolve();
12
+ };
13
+ rejectFinished = (reason) => {
14
+ if (settled)
15
+ return;
16
+ settled = true;
17
+ reject(reason ?? abortError());
18
+ };
19
+ });
20
+ // Prevent unhandled rejection when nobody awaits cancel.
21
+ finished.catch(() => { });
22
+ const playback = {
23
+ get playState() {
24
+ return playState;
25
+ },
26
+ finished,
27
+ cancel() {
28
+ if (playState !== "running")
29
+ return;
30
+ playState = "cancelled";
31
+ handlers.onCancel();
32
+ rejectFinished();
33
+ },
34
+ complete() {
35
+ if (playState !== "running")
36
+ return;
37
+ playState = "finished";
38
+ handlers.onComplete();
39
+ resolveFinished();
40
+ },
41
+ _resolveFinished() {
42
+ if (playState === "cancelled")
43
+ return;
44
+ playState = "finished";
45
+ resolveFinished();
46
+ },
47
+ };
48
+ return playback;
49
+ }
50
+ function abortError() {
51
+ if (typeof DOMException !== "undefined") {
52
+ return new DOMException("Animation cancelled", "AbortError");
53
+ }
54
+ const err = new Error("Animation cancelled");
55
+ err.name = "AbortError";
56
+ return err;
57
+ }
58
+ //# sourceMappingURL=playback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"playback.js","sourceRoot":"","sources":["../src/playback.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,cAAc,CAAC,QAG9B;IACC,IAAI,SAAS,GAAc,SAAS,CAAC;IACrC,IAAI,eAA4B,CAAC;IACjC,IAAI,cAA2C,CAAC;IAChD,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrD,eAAe,GAAG,GAAG,EAAE;YACrB,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,cAAc,GAAG,CAAC,MAAgB,EAAE,EAAE;YACpC,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,MAAM,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC,CAAC;QACjC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,yDAAyD;IACzD,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEzB,MAAM,QAAQ,GAAuB;QACnC,IAAI,SAAS;YACX,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,QAAQ;QACR,MAAM;YACJ,IAAI,SAAS,KAAK,SAAS;gBAAE,OAAO;YACpC,SAAS,GAAG,WAAW,CAAC;YACxB,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACpB,cAAc,EAAE,CAAC;QACnB,CAAC;QACD,QAAQ;YACN,IAAI,SAAS,KAAK,SAAS;gBAAE,OAAO;YACpC,SAAS,GAAG,UAAU,CAAC;YACvB,QAAQ,CAAC,UAAU,EAAE,CAAC;YACtB,eAAe,EAAE,CAAC;QACpB,CAAC;QACD,gBAAgB;YACd,IAAI,SAAS,KAAK,WAAW;gBAAE,OAAO;YACtC,SAAS,GAAG,UAAU,CAAC;YACvB,eAAe,EAAE,CAAC;QACpB,CAAC;KACF,CAAC;IAEF,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,OAAO,YAAY,KAAK,WAAW,EAAE,CAAC;QACxC,OAAO,IAAI,YAAY,CAAC,qBAAqB,EAAE,YAAY,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAC7C,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC;IACxB,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Detect `prefers-reduced-motion: reduce`.
3
+ * Safe on server (returns false unless overridden).
4
+ */
5
+ export declare function prefersReducedMotion(): boolean;
6
+ /**
7
+ * Force reduced-motion on/off (tests, user settings).
8
+ * Pass `null` to clear the override.
9
+ */
10
+ export declare function setReducedMotionOverride(value: boolean | null): void;
11
+ //# sourceMappingURL=reduced-motion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reduced-motion.d.ts","sourceRoot":"","sources":["../src/reduced-motion.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAQ9C;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,GAAG,IAAI,CAEpE"}
@@ -0,0 +1,25 @@
1
+ let override = null;
2
+ /**
3
+ * Detect `prefers-reduced-motion: reduce`.
4
+ * Safe on server (returns false unless overridden).
5
+ */
6
+ export function prefersReducedMotion() {
7
+ if (override !== null)
8
+ return override;
9
+ if (typeof matchMedia !== "function")
10
+ return false;
11
+ try {
12
+ return matchMedia("(prefers-reduced-motion: reduce)").matches;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ }
18
+ /**
19
+ * Force reduced-motion on/off (tests, user settings).
20
+ * Pass `null` to clear the override.
21
+ */
22
+ export function setReducedMotionOverride(value) {
23
+ override = value;
24
+ }
25
+ //# sourceMappingURL=reduced-motion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reduced-motion.js","sourceRoot":"","sources":["../src/reduced-motion.ts"],"names":[],"mappings":"AAAA,IAAI,QAAQ,GAAmB,IAAI,CAAC;AAEpC;;;GAGG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,QAAQ,CAAC;IACvC,IAAI,OAAO,UAAU,KAAK,UAAU;QAAE,OAAO,KAAK,CAAC;IACnD,IAAI,CAAC;QACH,OAAO,UAAU,CAAC,kCAAkC,CAAC,CAAC,OAAO,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAqB;IAC5D,QAAQ,GAAG,KAAK,CAAC;AACnB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Animatable } from "./types.js";
2
+ import type { AnimationPlayback } from "./types.js";
3
+ export declare function getActive(target: Animatable): AnimationPlayback | undefined;
4
+ export declare function setActive(target: Animatable, playback: AnimationPlayback): void;
5
+ export declare function clearActive(target: Animatable, playback: AnimationPlayback): void;
6
+ /** Cancel the in-flight animation on a signal, if any. */
7
+ export declare function cancel(target: Animatable): void;
8
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAKpD,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,iBAAiB,GAAG,SAAS,CAE3E;AAED,wBAAgB,SAAS,CACvB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,iBAAiB,GAC1B,IAAI,CAEN;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,iBAAiB,GAC1B,IAAI,CAIN;AAED,0DAA0D;AAC1D,wBAAgB,MAAM,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAG/C"}
@@ -0,0 +1,19 @@
1
+ /** One active animation per signal — new animate() interrupts the previous. */
2
+ const active = new WeakMap();
3
+ export function getActive(target) {
4
+ return active.get(target);
5
+ }
6
+ export function setActive(target, playback) {
7
+ active.set(target, playback);
8
+ }
9
+ export function clearActive(target, playback) {
10
+ if (active.get(target) === playback) {
11
+ active.delete(target);
12
+ }
13
+ }
14
+ /** Cancel the in-flight animation on a signal, if any. */
15
+ export function cancel(target) {
16
+ const current = active.get(target);
17
+ current?.cancel();
18
+ }
19
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAGA,+EAA+E;AAC/E,MAAM,MAAM,GAAG,IAAI,OAAO,EAAiC,CAAC;AAE5D,MAAM,UAAU,SAAS,CAAC,MAAkB;IAC1C,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,MAAkB,EAClB,QAA2B;IAE3B,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,MAAkB,EAClB,QAA2B;IAE3B,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED,0DAA0D;AAC1D,MAAM,UAAU,MAAM,CAAC,MAAkB;IACvC,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnC,OAAO,EAAE,MAAM,EAAE,CAAC;AACpB,CAAC"}
@@ -0,0 +1,69 @@
1
+ import type { Signal } from "@lab206/core";
2
+ /** Easing function: progress 0..1 → eased 0..1. */
3
+ export type EasingFn = (t: number) => number;
4
+ /** Named easings shipped with the library. */
5
+ export type EaseName = "linear" | "easeIn" | "easeOut" | "easeInOut" | "easeInCubic" | "easeOutCubic" | "easeInOutCubic" | "easeInBack" | "easeOutBack" | "easeInOutBack";
6
+ export type Ease = EaseName | EasingFn;
7
+ /** Playback state of a single animation. */
8
+ export type PlayState = "running" | "finished" | "cancelled";
9
+ /**
10
+ * Handle returned by `animate()`.
11
+ * - `finished` resolves on natural completion (not on cancel)
12
+ * - `cancel()` stops mid-flight and leaves the current value
13
+ * - `complete()` jumps to the end value and finishes
14
+ */
15
+ export interface AnimationPlayback {
16
+ readonly playState: PlayState;
17
+ readonly finished: Promise<void>;
18
+ cancel(): void;
19
+ complete(): void;
20
+ }
21
+ /** Duration-based tween options. */
22
+ export interface TweenOptions {
23
+ type?: "tween";
24
+ /** Duration in milliseconds. Default: 300. */
25
+ duration?: number;
26
+ /** Delay before starting, in ms. Default: 0. */
27
+ delay?: number;
28
+ /** Easing curve. Default: "easeOut". */
29
+ ease?: Ease;
30
+ /** Override the starting value (defaults to `target.peek()`). */
31
+ from?: number;
32
+ /**
33
+ * Honor `prefers-reduced-motion` (jump to end).
34
+ * Default: true.
35
+ */
36
+ respectReducedMotion?: boolean;
37
+ onUpdate?: (value: number) => void;
38
+ onComplete?: () => void;
39
+ onCancel?: () => void;
40
+ }
41
+ /** Spring physics options. */
42
+ export interface SpringOptions {
43
+ type: "spring";
44
+ stiffness?: number;
45
+ damping?: number;
46
+ mass?: number;
47
+ /** Initial velocity (units per second). */
48
+ velocity?: number;
49
+ /** Settle threshold for position. */
50
+ restDelta?: number;
51
+ /** Settle threshold for velocity. */
52
+ restSpeed?: number;
53
+ delay?: number;
54
+ from?: number;
55
+ respectReducedMotion?: boolean;
56
+ onUpdate?: (value: number) => void;
57
+ onComplete?: () => void;
58
+ onCancel?: () => void;
59
+ }
60
+ export type AnimateOptions = TweenOptions | SpringOptions;
61
+ /** Anything we can animate — a writable number signal. */
62
+ export type Animatable = Signal<number>;
63
+ /** @internal Driver for time + frames (swappable in tests). */
64
+ export interface FrameDriver {
65
+ now(): number;
66
+ raf(cb: (time: number) => void): number;
67
+ caf(id: number): void;
68
+ }
69
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,mDAAmD;AACnD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAE7C,8CAA8C;AAC9C,MAAM,MAAM,QAAQ,GAChB,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,WAAW,GACX,aAAa,GACb,cAAc,GACd,gBAAgB,GAChB,YAAY,GACZ,aAAa,GACb,eAAe,CAAC;AAEpB,MAAM,MAAM,IAAI,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEvC,4CAA4C;AAC5C,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;AAE7D;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,IAAI,IAAI,CAAC;IACf,QAAQ,IAAI,IAAI,CAAC;CAClB;AAED,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,8BAA8B;AAC9B,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,aAAa,CAAC;AAE1D,0DAA0D;AAC1D,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;AAExC,+DAA+D;AAC/D,MAAM,WAAW,WAAW;IAC1B,GAAG,IAAI,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAAC;IACxC,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "@lab206/animate",
3
+ "version": "0.1.0",
4
+ "description": "Signal-native animation for Powers — tweens, springs, interruptible, a11y-aware.",
5
+ "type": "module",
6
+ "license": "BUSL-1.1",
7
+ "sideEffects": false,
8
+ "exports": {
9
+ ".": {
10
+ "types": "./src/index.ts",
11
+ "development": "./src/index.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "./gsap": {
16
+ "types": "./src/gsap.ts",
17
+ "development": "./src/gsap.ts",
18
+ "import": "./dist/gsap.js",
19
+ "default": "./dist/gsap.js"
20
+ }
21
+ },
22
+ "main": "./dist/index.js",
23
+ "types": "./dist/index.d.ts",
24
+ "files": [
25
+ "dist",
26
+ "README.md",
27
+ "src/**/*.ts",
28
+ "src/**/*.tsx",
29
+ "src/**/*.css",
30
+ "!src/**/*.test.ts",
31
+ "!src/**/*.test.tsx"
32
+ ],
33
+ "dependencies": {
34
+ "@lab206/core": "0.1.0"
35
+ },
36
+ "peerDependencies": {
37
+ "gsap": "^3.12.0"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "gsap": {
41
+ "optional": true
42
+ }
43
+ },
44
+ "devDependencies": {
45
+ "esbuild": "^0.25.1",
46
+ "gsap": "^3.12.7",
47
+ "tsx": "^4.19.3",
48
+ "typescript": "^5.8.2"
49
+ },
50
+ "author": "Scott Powers",
51
+ "private": false,
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "homepage": "https://lab206.com",
56
+ "bugs": {
57
+ "url": "https://github.com/spowers2/powers/issues"
58
+ },
59
+ "engines": {
60
+ "node": ">=20"
61
+ },
62
+ "repository": {
63
+ "type": "git",
64
+ "url": "git+https://github.com/spowers2/powers.git",
65
+ "directory": "packages/animate"
66
+ },
67
+ "scripts": {
68
+ "build": "tsc -p tsconfig.json",
69
+ "typecheck": "tsc -p tsconfig.json --noEmit",
70
+ "test": "node --import tsx --test src/*.test.ts",
71
+ "size": "node --import tsx scripts/size.ts"
72
+ }
73
+ }