@xanui/core 1.2.70 → 1.3.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 (46) hide show
  1. package/Iframe/index.cjs +1 -2
  2. package/Iframe/index.cjs.map +1 -1
  3. package/Iframe/index.d.ts +2 -1
  4. package/Iframe/index.js +1 -2
  5. package/Iframe/index.js.map +1 -1
  6. package/Transition/index.cjs +50 -100
  7. package/Transition/index.cjs.map +1 -1
  8. package/Transition/index.d.ts +13 -21
  9. package/Transition/index.js +51 -101
  10. package/Transition/index.js.map +1 -1
  11. package/Transition/variants.cjs +92 -171
  12. package/Transition/variants.cjs.map +1 -1
  13. package/Transition/variants.d.ts +65 -83
  14. package/Transition/variants.js +93 -170
  15. package/Transition/variants.js.map +1 -1
  16. package/animate/easing.cjs +59 -0
  17. package/animate/easing.cjs.map +1 -0
  18. package/animate/easing.d.ts +13 -0
  19. package/animate/easing.js +57 -0
  20. package/animate/easing.js.map +1 -0
  21. package/animate/index.cjs +104 -0
  22. package/animate/index.cjs.map +1 -0
  23. package/animate/index.d.ts +19 -0
  24. package/animate/index.js +99 -0
  25. package/animate/index.js.map +1 -0
  26. package/hooks/useTransition.cjs +98 -0
  27. package/hooks/useTransition.cjs.map +1 -0
  28. package/hooks/useTransition.d.ts +23 -0
  29. package/hooks/useTransition.js +96 -0
  30. package/hooks/useTransition.js.map +1 -0
  31. package/hooks/useTransitionGroup.cjs +95 -0
  32. package/hooks/useTransitionGroup.cjs.map +1 -0
  33. package/hooks/useTransitionGroup.d.ts +32 -0
  34. package/hooks/useTransitionGroup.js +93 -0
  35. package/hooks/useTransitionGroup.js.map +1 -0
  36. package/index.cjs +16 -11
  37. package/index.cjs.map +1 -1
  38. package/index.d.ts +5 -2
  39. package/index.js +4 -1
  40. package/index.js.map +1 -1
  41. package/package.json +1 -1
  42. package/hooks/useAnimation.cjs +0 -44
  43. package/hooks/useAnimation.cjs.map +0 -1
  44. package/hooks/useAnimation.d.ts +0 -20
  45. package/hooks/useAnimation.js +0 -39
  46. package/hooks/useAnimation.js.map +0 -1
@@ -0,0 +1,99 @@
1
+ "use client";
2
+ import Easing from './easing.js';
3
+
4
+ const animate = ({ from, to, duration = 400, delay = 0, easing = Easing.default, onUpdate, onDone, breakpoints, repeat = 0, repeatBack = false, }) => {
5
+ let rafId;
6
+ let cycle = 0;
7
+ let forward = true;
8
+ // Track triggered breakpoints
9
+ const triggered = {};
10
+ const resolve = (val) => typeof val === "function" ? val() : val;
11
+ const getEased = (key, t) => {
12
+ if (typeof easing === "function")
13
+ return easing(t);
14
+ if (easing[key])
15
+ return easing[key](t);
16
+ return t;
17
+ };
18
+ const startAnimation = () => {
19
+ const fromVal = resolve(from);
20
+ const toVal = resolve(to);
21
+ const keys = Object.keys(fromVal);
22
+ if (breakpoints) {
23
+ for (const key of keys)
24
+ triggered[key] = new Set();
25
+ }
26
+ const start = performance.now();
27
+ const frame = (now) => {
28
+ const progress = duration === 0 ? 1 : Math.min((now - start) / duration, 1);
29
+ const current = {};
30
+ for (const key of keys) {
31
+ const f = forward ? fromVal[key] : toVal[key];
32
+ const t = forward ? toVal[key] : fromVal[key];
33
+ const eased = getEased(key, progress);
34
+ const val = f + (t - f) * eased;
35
+ current[key] = val;
36
+ // breakpoints
37
+ const bps = breakpoints === null || breakpoints === void 0 ? void 0 : breakpoints[key];
38
+ if (bps) {
39
+ for (let i = 0; i < bps.length; i++) {
40
+ const triggeredSet = triggered[key];
41
+ if (!triggeredSet.has(i) &&
42
+ ((f < t && val >= bps[i].value) ||
43
+ (f > t && val <= bps[i].value))) {
44
+ triggeredSet.add(i);
45
+ bps[i].callback();
46
+ }
47
+ }
48
+ }
49
+ }
50
+ onUpdate(current, progress);
51
+ if (progress < 1) {
52
+ rafId = requestAnimationFrame(frame);
53
+ }
54
+ else {
55
+ const finalState = forward ? toVal : fromVal;
56
+ onUpdate(finalState, 1);
57
+ // fire remaining breakpoints
58
+ if (breakpoints) {
59
+ for (const key of keys) {
60
+ const bps = breakpoints[key];
61
+ if (!bps)
62
+ continue;
63
+ const triggeredSet = triggered[key];
64
+ for (let i = 0; i < bps.length; i++) {
65
+ if (!triggeredSet.has(i)) {
66
+ triggeredSet.add(i);
67
+ bps[i].callback();
68
+ }
69
+ }
70
+ }
71
+ }
72
+ cycle++;
73
+ if (cycle <= repeat) {
74
+ if (repeatBack)
75
+ forward = !forward;
76
+ startAnimation(); // 🔁 re-run with fresh from/to if functions
77
+ }
78
+ else {
79
+ onDone === null || onDone === void 0 ? void 0 : onDone();
80
+ }
81
+ }
82
+ };
83
+ rafId = requestAnimationFrame(frame);
84
+ };
85
+ if (delay > 0) {
86
+ const timeout = setTimeout(startAnimation, delay);
87
+ return () => {
88
+ clearTimeout(timeout);
89
+ cancelAnimationFrame(rafId);
90
+ };
91
+ }
92
+ else {
93
+ startAnimation();
94
+ return () => cancelAnimationFrame(rafId);
95
+ }
96
+ };
97
+
98
+ export { Easing, animate as default };
99
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/animate/index.ts"],"sourcesContent":["\"use client\"\nimport Easing from \"./easing\";\n\nexport { Easing };\n\nexport type AnimateOptions<T extends Record<string, number>> = {\n from: T | (() => T);\n to: T | (() => T);\n duration?: number;\n delay?: number;\n easing?: ((t: number) => number) | Partial<Record<keyof T, (t: number) => number>>;\n onUpdate: (value: T, progress: number) => void;\n onDone?: () => void;\n breakpoints?: Partial<Record<keyof T, Array<{ value: number; callback: () => void }>>>;\n repeat?: number;\n repeatBack?: boolean;\n};\n\nconst animate = <T extends Record<string, number>>({\n from,\n to,\n duration = 400,\n delay = 0,\n easing = Easing.default,\n onUpdate,\n onDone,\n breakpoints,\n repeat = 0,\n repeatBack = false,\n}: AnimateOptions<T>) => {\n let rafId: number;\n let cycle = 0;\n let forward = true;\n\n // Track triggered breakpoints\n const triggered: Partial<Record<keyof T, Set<number>>> = {};\n\n const resolve = (val: T | (() => T)): T =>\n typeof val === \"function\" ? (val as () => T)() : val;\n\n const getEased = (key: keyof T, t: number) => {\n if (typeof easing === \"function\") return easing(t);\n if (easing[key]) return easing[key]!(t);\n return t;\n };\n\n const startAnimation = () => {\n const fromVal = resolve(from);\n const toVal = resolve(to);\n\n const keys = Object.keys(fromVal) as (keyof T)[];\n\n if (breakpoints) {\n for (const key of keys) triggered[key] = new Set();\n }\n\n const start = performance.now();\n\n const frame = (now: number) => {\n const progress =\n duration === 0 ? 1 : Math.min((now - start) / duration, 1);\n\n const current: any = {} as T;\n\n for (const key of keys) {\n const f = forward ? fromVal[key] : toVal[key];\n const t = forward ? toVal[key] : fromVal[key];\n\n const eased = getEased(key, progress);\n const val = f + (t - f) * eased;\n current[key] = val;\n\n // breakpoints\n const bps = breakpoints?.[key];\n if (bps) {\n for (let i = 0; i < bps.length; i++) {\n const triggeredSet = triggered[key]!;\n if (\n !triggeredSet.has(i) &&\n ((f < t && val >= bps[i].value) ||\n (f > t && val <= bps[i].value))\n ) {\n triggeredSet.add(i);\n bps[i].callback();\n }\n }\n }\n }\n\n onUpdate(current, progress);\n\n if (progress < 1) {\n rafId = requestAnimationFrame(frame);\n } else {\n const finalState = forward ? toVal : fromVal;\n onUpdate(finalState, 1);\n\n // fire remaining breakpoints\n if (breakpoints) {\n for (const key of keys) {\n const bps = breakpoints[key];\n if (!bps) continue;\n\n const triggeredSet = triggered[key]!;\n for (let i = 0; i < bps.length; i++) {\n if (!triggeredSet.has(i)) {\n triggeredSet.add(i);\n bps[i].callback();\n }\n }\n }\n }\n\n cycle++;\n\n if (cycle <= repeat) {\n if (repeatBack) forward = !forward;\n startAnimation(); // 🔁 re-run with fresh from/to if functions\n } else {\n onDone?.();\n }\n }\n };\n\n rafId = requestAnimationFrame(frame);\n };\n\n if (delay > 0) {\n const timeout = setTimeout(startAnimation, delay);\n return () => {\n clearTimeout(timeout);\n cancelAnimationFrame(rafId);\n };\n } else {\n startAnimation();\n return () => cancelAnimationFrame(rafId);\n }\n};\n\nexport default animate;"],"names":[],"mappings":";;;AAkBA;AAYG;;;;;;AAUA;;AACqC;;AACjB;AACjB;AACH;;AAGG;AACA;;;;AAK2B;;AAG3B;AAEA;;;AAMG;AACG;AACA;;;AAIA;;;;AAKG;AACG;AACA;AAEG;AACG;AAEH;AACA;;;;;AAMZ;AAEA;AACG;;;;AAGA;;;AAIG;AACG;AACA;;AAEA;AACA;;AAEM;AACA;;;;;AAMZ;AAEA;AACG;;;;;AAGA;;;AAGT;AAEA;AACH;AAEA;;AAEG;;;AAGA;;;AAEA;AACA;;AAEN;;"}
@@ -0,0 +1,98 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var tslib = require('tslib');
5
+ var React = require('react');
6
+ var index = require('../animate/index.cjs');
7
+
8
+ const useTransition = (props) => {
9
+ const { initialStatus = "exited", onEnter, onEntered, onExit, onExited } = props, options = tslib.__rest(props, ["initialStatus", "onEnter", "onEntered", "onExit", "onExited"]);
10
+ const resolve = (val) => typeof val === "function" ? val() : val;
11
+ const [open, setOpen] = React.useState(initialStatus === "entered");
12
+ const [status, setStatus] = React.useState(initialStatus);
13
+ const stateRef = React.useRef(null);
14
+ const readyRef = React.useRef(false);
15
+ const animating = React.useRef(null);
16
+ React.useLayoutEffect(() => {
17
+ const from = resolve(options.from);
18
+ const to = resolve(options.to);
19
+ stateRef.current = initialStatus === "entered" ? to : from;
20
+ readyRef.current = true;
21
+ }, []);
22
+ const run = React.useCallback((nextOpen, withAnimation = true) => {
23
+ var _a, _b, _c, _d;
24
+ if (!readyRef.current || !stateRef.current)
25
+ return;
26
+ (_a = animating.current) === null || _a === void 0 ? void 0 : _a.call(animating);
27
+ const resolvedFrom = resolve(options.from);
28
+ const resolvedTo = resolve(options.to);
29
+ const from = stateRef.current;
30
+ const to = nextOpen ? resolvedTo : resolvedFrom;
31
+ if (nextOpen) {
32
+ setStatus("entering");
33
+ onEnter === null || onEnter === void 0 ? void 0 : onEnter();
34
+ }
35
+ else {
36
+ setStatus("exiting");
37
+ onExit === null || onExit === void 0 ? void 0 : onExit();
38
+ }
39
+ if (!withAnimation) {
40
+ stateRef.current = to;
41
+ (_b = options.onUpdate) === null || _b === void 0 ? void 0 : _b.call(options, to, 1);
42
+ if (nextOpen) {
43
+ setStatus("entered");
44
+ onEntered === null || onEntered === void 0 ? void 0 : onEntered();
45
+ }
46
+ else {
47
+ setStatus("exited");
48
+ onExited === null || onExited === void 0 ? void 0 : onExited();
49
+ }
50
+ (_c = options.onDone) === null || _c === void 0 ? void 0 : _c.call(options);
51
+ return;
52
+ }
53
+ animating.current = index.default(Object.assign(Object.assign({}, options), { from,
54
+ to, duration: (_d = options.duration) !== null && _d !== void 0 ? _d : 400, onUpdate: (value, progress) => {
55
+ var _a;
56
+ stateRef.current = value;
57
+ (_a = options.onUpdate) === null || _a === void 0 ? void 0 : _a.call(options, value, progress);
58
+ }, onDone: () => {
59
+ var _a;
60
+ if (nextOpen) {
61
+ setStatus("entered");
62
+ onEntered === null || onEntered === void 0 ? void 0 : onEntered();
63
+ }
64
+ else {
65
+ setStatus("exited");
66
+ onExited === null || onExited === void 0 ? void 0 : onExited();
67
+ }
68
+ (_a = options.onDone) === null || _a === void 0 ? void 0 : _a.call(options);
69
+ } }));
70
+ }, [options, onEnter, onEntered, onExit, onExited]);
71
+ const enter = React.useCallback((withAnimation = true) => {
72
+ setOpen(true);
73
+ run(true, withAnimation);
74
+ }, [run]);
75
+ const exit = React.useCallback((withAnimation = true) => {
76
+ setOpen(false);
77
+ run(false, withAnimation);
78
+ }, [run]);
79
+ const toggle = React.useCallback((withAnimation = true) => {
80
+ setOpen((prev) => {
81
+ const next = !prev;
82
+ run(next, withAnimation);
83
+ return next;
84
+ });
85
+ }, [run]);
86
+ return {
87
+ isEntered: open,
88
+ status,
89
+ state: stateRef,
90
+ enter,
91
+ exit,
92
+ toggle,
93
+ isReady: readyRef.current
94
+ };
95
+ };
96
+
97
+ module.exports = useTransition;
98
+ //# sourceMappingURL=useTransition.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTransition.cjs","sources":["../../src/hooks/useTransition.ts"],"sourcesContent":["\"use client\"\nimport { useRef, useState, useCallback, useLayoutEffect } from \"react\"\nimport animate, { AnimateOptions } from \"../animate\"\n\nexport type UseTransitionStatus =\n | \"entering\"\n | \"entered\"\n | \"exiting\"\n | \"exited\"\n\nexport type UseTransitionProps<T extends Record<string, number>> = AnimateOptions<T> & {\n initialStatus?: \"entered\" | \"exited\"\n onEnter?: () => void\n onEntered?: () => void\n onExit?: () => void\n onExited?: () => void\n}\n\nconst useTransition = <T extends Record<string, number>>(props: UseTransitionProps<T>) => {\n const {\n initialStatus = \"exited\",\n onEnter,\n onEntered,\n onExit,\n onExited,\n ...options\n } = props\n\n const resolve = (val: T | (() => T)): T =>\n typeof val === \"function\" ? (val as () => T)() : val\n\n const [open, setOpen] = useState(initialStatus === \"entered\")\n const [status, setStatus] = useState<UseTransitionStatus>(initialStatus)\n\n const stateRef = useRef<T | null>(null)\n const readyRef = useRef(false)\n\n const animating = useRef<null | (() => void)>(null)\n\n useLayoutEffect(() => {\n const from = resolve(options.from)\n const to = resolve(options.to)\n stateRef.current = initialStatus === \"entered\" ? to : from\n readyRef.current = true\n }, [])\n\n const run = useCallback(\n (nextOpen: boolean, withAnimation = true) => {\n if (!readyRef.current || !stateRef.current) return\n\n animating.current?.()\n\n const resolvedFrom = resolve(options.from)\n const resolvedTo = resolve(options.to)\n const from = stateRef.current\n const to = nextOpen ? resolvedTo : resolvedFrom\n\n if (nextOpen) {\n setStatus(\"entering\")\n onEnter?.()\n } else {\n setStatus(\"exiting\")\n onExit?.()\n }\n\n if (!withAnimation) {\n stateRef.current = to\n options.onUpdate?.(to, 1)\n\n if (nextOpen) {\n setStatus(\"entered\")\n onEntered?.()\n } else {\n setStatus(\"exited\")\n onExited?.()\n }\n\n options.onDone?.()\n return\n }\n\n animating.current = animate({\n ...options,\n from,\n to,\n duration: options.duration ?? 400,\n onUpdate: (value: T, progress: number) => {\n stateRef.current = value\n options.onUpdate?.(value, progress)\n },\n onDone: () => {\n if (nextOpen) {\n setStatus(\"entered\")\n onEntered?.()\n } else {\n setStatus(\"exited\")\n onExited?.()\n }\n options.onDone?.()\n },\n })\n },\n [options, onEnter, onEntered, onExit, onExited]\n )\n\n const enter = useCallback((withAnimation = true) => {\n setOpen(true)\n run(true, withAnimation)\n }, [run])\n\n const exit = useCallback((withAnimation = true) => {\n setOpen(false)\n run(false, withAnimation)\n }, [run])\n\n const toggle = useCallback((withAnimation = true) => {\n setOpen((prev) => {\n const next = !prev\n run(next, withAnimation)\n return next\n })\n }, [run])\n\n return {\n isEntered: open,\n status,\n state: stateRef,\n enter,\n exit,\n toggle,\n isReady: readyRef.current\n }\n}\n\nexport default useTransition"],"names":[],"mappings":";;;;;;;AAkBA;;;AAaG;;AAGA;AACA;AAEA;;;;AAKG;AACA;;;;;;AAOG;;;AAIA;;;;AAKG;;;;AAGA;;;AAIA;;;;AAKG;;;;AAGA;;AAGH;;;AAIH;AAGG;;AAGG;;AAEH;;;;AAIM;;;;AAGA;;AAEH;AACH;AAEN;;;AAMA;AACH;;;AAIG;AACH;;AAGG;AACG;AACA;AACA;AACH;AACH;;AAGG;;AAEA;;;;;;AAMN;;"}
@@ -0,0 +1,23 @@
1
+ import * as React from 'react';
2
+ import { AnimateOptions } from '../animate/index.js';
3
+
4
+ type UseTransitionStatus = "entering" | "entered" | "exiting" | "exited";
5
+ type UseTransitionProps<T extends Record<string, number>> = AnimateOptions<T> & {
6
+ initialStatus?: "entered" | "exited";
7
+ onEnter?: () => void;
8
+ onEntered?: () => void;
9
+ onExit?: () => void;
10
+ onExited?: () => void;
11
+ };
12
+ declare const useTransition: <T extends Record<string, number>>(props: UseTransitionProps<T>) => {
13
+ isEntered: boolean;
14
+ status: UseTransitionStatus;
15
+ state: React.RefObject<T | null>;
16
+ enter: (withAnimation?: boolean) => void;
17
+ exit: (withAnimation?: boolean) => void;
18
+ toggle: (withAnimation?: boolean) => void;
19
+ isReady: boolean;
20
+ };
21
+
22
+ export { useTransition as default };
23
+ export type { UseTransitionProps, UseTransitionStatus };
@@ -0,0 +1,96 @@
1
+ "use client";
2
+ import { __rest } from 'tslib';
3
+ import { useState, useRef, useLayoutEffect, useCallback } from 'react';
4
+ import animate from '../animate/index.js';
5
+
6
+ const useTransition = (props) => {
7
+ const { initialStatus = "exited", onEnter, onEntered, onExit, onExited } = props, options = __rest(props, ["initialStatus", "onEnter", "onEntered", "onExit", "onExited"]);
8
+ const resolve = (val) => typeof val === "function" ? val() : val;
9
+ const [open, setOpen] = useState(initialStatus === "entered");
10
+ const [status, setStatus] = useState(initialStatus);
11
+ const stateRef = useRef(null);
12
+ const readyRef = useRef(false);
13
+ const animating = useRef(null);
14
+ useLayoutEffect(() => {
15
+ const from = resolve(options.from);
16
+ const to = resolve(options.to);
17
+ stateRef.current = initialStatus === "entered" ? to : from;
18
+ readyRef.current = true;
19
+ }, []);
20
+ const run = useCallback((nextOpen, withAnimation = true) => {
21
+ var _a, _b, _c, _d;
22
+ if (!readyRef.current || !stateRef.current)
23
+ return;
24
+ (_a = animating.current) === null || _a === void 0 ? void 0 : _a.call(animating);
25
+ const resolvedFrom = resolve(options.from);
26
+ const resolvedTo = resolve(options.to);
27
+ const from = stateRef.current;
28
+ const to = nextOpen ? resolvedTo : resolvedFrom;
29
+ if (nextOpen) {
30
+ setStatus("entering");
31
+ onEnter === null || onEnter === void 0 ? void 0 : onEnter();
32
+ }
33
+ else {
34
+ setStatus("exiting");
35
+ onExit === null || onExit === void 0 ? void 0 : onExit();
36
+ }
37
+ if (!withAnimation) {
38
+ stateRef.current = to;
39
+ (_b = options.onUpdate) === null || _b === void 0 ? void 0 : _b.call(options, to, 1);
40
+ if (nextOpen) {
41
+ setStatus("entered");
42
+ onEntered === null || onEntered === void 0 ? void 0 : onEntered();
43
+ }
44
+ else {
45
+ setStatus("exited");
46
+ onExited === null || onExited === void 0 ? void 0 : onExited();
47
+ }
48
+ (_c = options.onDone) === null || _c === void 0 ? void 0 : _c.call(options);
49
+ return;
50
+ }
51
+ animating.current = animate(Object.assign(Object.assign({}, options), { from,
52
+ to, duration: (_d = options.duration) !== null && _d !== void 0 ? _d : 400, onUpdate: (value, progress) => {
53
+ var _a;
54
+ stateRef.current = value;
55
+ (_a = options.onUpdate) === null || _a === void 0 ? void 0 : _a.call(options, value, progress);
56
+ }, onDone: () => {
57
+ var _a;
58
+ if (nextOpen) {
59
+ setStatus("entered");
60
+ onEntered === null || onEntered === void 0 ? void 0 : onEntered();
61
+ }
62
+ else {
63
+ setStatus("exited");
64
+ onExited === null || onExited === void 0 ? void 0 : onExited();
65
+ }
66
+ (_a = options.onDone) === null || _a === void 0 ? void 0 : _a.call(options);
67
+ } }));
68
+ }, [options, onEnter, onEntered, onExit, onExited]);
69
+ const enter = useCallback((withAnimation = true) => {
70
+ setOpen(true);
71
+ run(true, withAnimation);
72
+ }, [run]);
73
+ const exit = useCallback((withAnimation = true) => {
74
+ setOpen(false);
75
+ run(false, withAnimation);
76
+ }, [run]);
77
+ const toggle = useCallback((withAnimation = true) => {
78
+ setOpen((prev) => {
79
+ const next = !prev;
80
+ run(next, withAnimation);
81
+ return next;
82
+ });
83
+ }, [run]);
84
+ return {
85
+ isEntered: open,
86
+ status,
87
+ state: stateRef,
88
+ enter,
89
+ exit,
90
+ toggle,
91
+ isReady: readyRef.current
92
+ };
93
+ };
94
+
95
+ export { useTransition as default };
96
+ //# sourceMappingURL=useTransition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTransition.js","sources":["../../src/hooks/useTransition.ts"],"sourcesContent":["\"use client\"\nimport { useRef, useState, useCallback, useLayoutEffect } from \"react\"\nimport animate, { AnimateOptions } from \"../animate\"\n\nexport type UseTransitionStatus =\n | \"entering\"\n | \"entered\"\n | \"exiting\"\n | \"exited\"\n\nexport type UseTransitionProps<T extends Record<string, number>> = AnimateOptions<T> & {\n initialStatus?: \"entered\" | \"exited\"\n onEnter?: () => void\n onEntered?: () => void\n onExit?: () => void\n onExited?: () => void\n}\n\nconst useTransition = <T extends Record<string, number>>(props: UseTransitionProps<T>) => {\n const {\n initialStatus = \"exited\",\n onEnter,\n onEntered,\n onExit,\n onExited,\n ...options\n } = props\n\n const resolve = (val: T | (() => T)): T =>\n typeof val === \"function\" ? (val as () => T)() : val\n\n const [open, setOpen] = useState(initialStatus === \"entered\")\n const [status, setStatus] = useState<UseTransitionStatus>(initialStatus)\n\n const stateRef = useRef<T | null>(null)\n const readyRef = useRef(false)\n\n const animating = useRef<null | (() => void)>(null)\n\n useLayoutEffect(() => {\n const from = resolve(options.from)\n const to = resolve(options.to)\n stateRef.current = initialStatus === \"entered\" ? to : from\n readyRef.current = true\n }, [])\n\n const run = useCallback(\n (nextOpen: boolean, withAnimation = true) => {\n if (!readyRef.current || !stateRef.current) return\n\n animating.current?.()\n\n const resolvedFrom = resolve(options.from)\n const resolvedTo = resolve(options.to)\n const from = stateRef.current\n const to = nextOpen ? resolvedTo : resolvedFrom\n\n if (nextOpen) {\n setStatus(\"entering\")\n onEnter?.()\n } else {\n setStatus(\"exiting\")\n onExit?.()\n }\n\n if (!withAnimation) {\n stateRef.current = to\n options.onUpdate?.(to, 1)\n\n if (nextOpen) {\n setStatus(\"entered\")\n onEntered?.()\n } else {\n setStatus(\"exited\")\n onExited?.()\n }\n\n options.onDone?.()\n return\n }\n\n animating.current = animate({\n ...options,\n from,\n to,\n duration: options.duration ?? 400,\n onUpdate: (value: T, progress: number) => {\n stateRef.current = value\n options.onUpdate?.(value, progress)\n },\n onDone: () => {\n if (nextOpen) {\n setStatus(\"entered\")\n onEntered?.()\n } else {\n setStatus(\"exited\")\n onExited?.()\n }\n options.onDone?.()\n },\n })\n },\n [options, onEnter, onEntered, onExit, onExited]\n )\n\n const enter = useCallback((withAnimation = true) => {\n setOpen(true)\n run(true, withAnimation)\n }, [run])\n\n const exit = useCallback((withAnimation = true) => {\n setOpen(false)\n run(false, withAnimation)\n }, [run])\n\n const toggle = useCallback((withAnimation = true) => {\n setOpen((prev) => {\n const next = !prev\n run(next, withAnimation)\n return next\n })\n }, [run])\n\n return {\n isEntered: open,\n status,\n state: stateRef,\n enter,\n exit,\n toggle,\n isReady: readyRef.current\n }\n}\n\nexport default useTransition"],"names":[],"mappings":";;;;;AAkBA;;;AAaG;;AAGA;AACA;AAEA;;;;AAKG;AACA;;;;;;AAOG;;;AAIA;;;;AAKG;;;;AAGA;;;AAIA;;;;AAKG;;;;AAGA;;AAGH;;;AAIH;AAGG;;AAGG;;AAEH;;;;AAIM;;;;AAGA;;AAEH;AACH;AAEN;;;AAMA;AACH;;;AAIG;AACH;;AAGG;AACG;AACA;AACA;AACH;AACH;;AAGG;;AAEA;;;;;;AAMN;;"}
@@ -0,0 +1,95 @@
1
+ "use client";
2
+ 'use strict';
3
+
4
+ var React = require('react');
5
+ var index = require('../animate/index.cjs');
6
+
7
+ /**
8
+ * useTransitionGroup - staggered animations for multiple items
9
+ */
10
+ function useTransitionGroup(options) {
11
+ // status of each item
12
+ const [statuses, setStatuses] = React.useState(() => Object.fromEntries(options.items.map((item) => [
13
+ item.key,
14
+ options.mountOnEnter ? "exited" : "entered",
15
+ ])));
16
+ // refs to cancel per-item animations
17
+ const animatingRefs = React.useRef({});
18
+ // track mounted items (for mount/unmount)
19
+ const [mounted, setMounted] = React.useState(() => Object.fromEntries(options.items.map((item) => [
20
+ item.key,
21
+ !options.mountOnEnter,
22
+ ])));
23
+ // animate a single item
24
+ const animateItem = React.useCallback((item, entering, delay = 0) => {
25
+ var _a, _b;
26
+ // cancel previous
27
+ (_b = (_a = animatingRefs.current)[item.key]) === null || _b === void 0 ? void 0 : _b.call(_a);
28
+ if (entering)
29
+ setStatuses((s) => (Object.assign(Object.assign({}, s), { [item.key]: "entering" })));
30
+ else
31
+ setStatuses((s) => (Object.assign(Object.assign({}, s), { [item.key]: "exiting" })));
32
+ if (entering && options.mountOnEnter) {
33
+ setMounted((m) => (Object.assign(Object.assign({}, m), { [item.key]: true })));
34
+ }
35
+ // start animation after delay
36
+ const timeout = setTimeout(() => {
37
+ var _a, _b, _c;
38
+ if (entering)
39
+ (_a = options.onEnter) === null || _a === void 0 ? void 0 : _a.call(options, item.key);
40
+ else
41
+ (_b = options.onExit) === null || _b === void 0 ? void 0 : _b.call(options, item.key);
42
+ animatingRefs.current[item.key] = index.default({
43
+ from: entering ? item.from : item.to,
44
+ to: entering ? item.to : item.from,
45
+ duration: (_c = options.duration) !== null && _c !== void 0 ? _c : 400,
46
+ onUpdate: (value, progress) => { var _a; return (_a = options.onUpdate) === null || _a === void 0 ? void 0 : _a.call(options, value, item.key, progress); },
47
+ onDone: () => {
48
+ var _a, _b;
49
+ if (entering) {
50
+ setStatuses((s) => (Object.assign(Object.assign({}, s), { [item.key]: "entered" })));
51
+ (_a = options.onEntered) === null || _a === void 0 ? void 0 : _a.call(options, item.key);
52
+ }
53
+ else {
54
+ setStatuses((s) => (Object.assign(Object.assign({}, s), { [item.key]: "exited" })));
55
+ (_b = options.onExited) === null || _b === void 0 ? void 0 : _b.call(options, item.key);
56
+ if (options.unmountOnExit) {
57
+ setMounted((m) => (Object.assign(Object.assign({}, m), { [item.key]: false })));
58
+ }
59
+ }
60
+ },
61
+ });
62
+ }, delay);
63
+ return () => clearTimeout(timeout);
64
+ }, [options]);
65
+ // run staggered animation on array of items
66
+ const run = React.useCallback((entering) => {
67
+ options.items.forEach((item, index) => {
68
+ var _a;
69
+ const delay = ((_a = options.stagger) !== null && _a !== void 0 ? _a : 100) * index;
70
+ const status = statuses[item.key];
71
+ // skip if already animating in same direction
72
+ if (entering && (status === "entering" || status === "entered"))
73
+ return;
74
+ if (!entering && (status === "exiting" || status === "exited"))
75
+ return;
76
+ animateItem(item, entering, delay);
77
+ });
78
+ }, [options.items, options.stagger, animateItem, statuses]);
79
+ const enter = React.useCallback(() => run(true), [run]);
80
+ const exit = React.useCallback(() => run(false), [run]);
81
+ const toggle = React.useCallback(() => {
82
+ const anyEntered = Object.values(statuses).some((s) => s === "entering" || s === "entered");
83
+ run(!anyEntered);
84
+ }, [run, statuses]);
85
+ return {
86
+ statuses,
87
+ mounted,
88
+ enter,
89
+ exit,
90
+ toggle,
91
+ };
92
+ }
93
+
94
+ module.exports = useTransitionGroup;
95
+ //# sourceMappingURL=useTransitionGroup.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTransitionGroup.cjs","sources":["../../src/hooks/useTransitionGroup.ts"],"sourcesContent":["\"use client\"\nimport { useRef, useState, useCallback } from \"react\"\nimport animate from \"../animate\"\nimport { UseTransitionStatus } from \"./useTransition\"\n\nexport type UseTransitionGroupItem<T extends Record<string, number>> = {\n key: string | number\n from: T\n to: T\n}\n\nexport type UseTransitionGroupProps<T extends Record<string, number>> = {\n items: UseTransitionGroupItem<T>[]\n duration?: number\n stagger?: number // delay between items in ms\n mountOnEnter?: boolean\n unmountOnExit?: boolean\n onUpdate?: (value: T, key: string | number, progress: number) => void\n onEnter?: (key: string | number) => void\n onEntered?: (key: string | number) => void\n onExit?: (key: string | number) => void\n onExited?: (key: string | number) => void\n}\n\n/**\n * useTransitionGroup - staggered animations for multiple items\n */\nfunction useTransitionGroup<T extends Record<string, number>>(\n options: UseTransitionGroupProps<T>\n) {\n // status of each item\n const [statuses, setStatuses] = useState<\n Record<string | number, UseTransitionStatus>\n >(\n () =>\n Object.fromEntries(\n options.items.map((item) => [\n item.key,\n options.mountOnEnter ? \"exited\" : \"entered\",\n ])\n )\n )\n\n // refs to cancel per-item animations\n const animatingRefs = useRef<Record<string | number, (() => void) | null>>({})\n\n // track mounted items (for mount/unmount)\n const [mounted, setMounted] = useState<Record<string | number, boolean>>(\n () =>\n Object.fromEntries(\n options.items.map((item) => [\n item.key,\n !options.mountOnEnter,\n ])\n )\n )\n\n // animate a single item\n const animateItem = useCallback(\n (item: UseTransitionGroupItem<T>, entering: boolean, delay = 0) => {\n // cancel previous\n animatingRefs.current[item.key]?.()\n\n if (entering) setStatuses((s: any) => ({ ...s, [item.key]: \"entering\" }))\n else setStatuses((s: any) => ({ ...s, [item.key]: \"exiting\" }))\n\n if (entering && options.mountOnEnter) {\n setMounted((m) => ({ ...m, [item.key]: true }))\n }\n\n // start animation after delay\n const timeout = setTimeout(() => {\n if (entering) options.onEnter?.(item.key)\n else options.onExit?.(item.key)\n\n animatingRefs.current[item.key] = animate({\n from: entering ? item.from : item.to,\n to: entering ? item.to : item.from,\n duration: options.duration ?? 400,\n onUpdate: (value, progress) =>\n options.onUpdate?.(value, item.key, progress),\n onDone: () => {\n if (entering) {\n setStatuses((s: any) => ({ ...s, [item.key]: \"entered\" }))\n options.onEntered?.(item.key)\n } else {\n setStatuses((s: any) => ({ ...s, [item.key]: \"exited\" }))\n options.onExited?.(item.key)\n if (options.unmountOnExit) {\n setMounted((m) => ({ ...m, [item.key]: false }))\n }\n }\n },\n })\n }, delay)\n\n return () => clearTimeout(timeout)\n },\n [options]\n )\n\n // run staggered animation on array of items\n const run = useCallback(\n (entering: boolean) => {\n options.items.forEach((item, index) => {\n const delay = (options.stagger ?? 100) * index\n const status = statuses[item.key]\n\n // skip if already animating in same direction\n if (entering && (status === \"entering\" || status === \"entered\")) return\n if (!entering && (status === \"exiting\" || status === \"exited\")) return\n\n animateItem(item, entering, delay)\n })\n },\n [options.items, options.stagger, animateItem, statuses]\n )\n\n const enter = useCallback(() => run(true), [run])\n const exit = useCallback(() => run(false), [run])\n const toggle = useCallback(() => {\n const anyEntered = Object.values(statuses).some(\n (s) => s === \"entering\" || s === \"entered\"\n )\n run(!anyEntered)\n }, [run, statuses])\n\n return {\n statuses,\n mounted,\n enter,\n exit,\n toggle,\n }\n}\n\nexport default useTransitionGroup"],"names":[],"mappings":";;;;;;AAwBA;;AAEG;AACH;;;AAUe;;;;AAOZ;;;AAOY;;;;AAOZ;;;;AAKM;AAAc;;AACT;AAEL;AACG;;;AAIH;;AACG;;;;;AAIG;AACA;AACA;;;;;AAKM;;;;AAGA;;AAEA;AACG;;;;AAIX;;AAGJ;AACH;;AAKH;;;AAGS;;;;;;;AAOA;AACH;AACH;AAIH;AACA;AACA;;AAIG;AACH;;;;;;;;AASH;;"}
@@ -0,0 +1,32 @@
1
+ import { UseTransitionStatus } from './useTransition.js';
2
+
3
+ type UseTransitionGroupItem<T extends Record<string, number>> = {
4
+ key: string | number;
5
+ from: T;
6
+ to: T;
7
+ };
8
+ type UseTransitionGroupProps<T extends Record<string, number>> = {
9
+ items: UseTransitionGroupItem<T>[];
10
+ duration?: number;
11
+ stagger?: number;
12
+ mountOnEnter?: boolean;
13
+ unmountOnExit?: boolean;
14
+ onUpdate?: (value: T, key: string | number, progress: number) => void;
15
+ onEnter?: (key: string | number) => void;
16
+ onEntered?: (key: string | number) => void;
17
+ onExit?: (key: string | number) => void;
18
+ onExited?: (key: string | number) => void;
19
+ };
20
+ /**
21
+ * useTransitionGroup - staggered animations for multiple items
22
+ */
23
+ declare function useTransitionGroup<T extends Record<string, number>>(options: UseTransitionGroupProps<T>): {
24
+ statuses: Record<string | number, UseTransitionStatus>;
25
+ mounted: Record<string | number, boolean>;
26
+ enter: () => void;
27
+ exit: () => void;
28
+ toggle: () => void;
29
+ };
30
+
31
+ export { useTransitionGroup as default };
32
+ export type { UseTransitionGroupItem, UseTransitionGroupProps };
@@ -0,0 +1,93 @@
1
+ "use client";
2
+ import { useState, useRef, useCallback } from 'react';
3
+ import animate from '../animate/index.js';
4
+
5
+ /**
6
+ * useTransitionGroup - staggered animations for multiple items
7
+ */
8
+ function useTransitionGroup(options) {
9
+ // status of each item
10
+ const [statuses, setStatuses] = useState(() => Object.fromEntries(options.items.map((item) => [
11
+ item.key,
12
+ options.mountOnEnter ? "exited" : "entered",
13
+ ])));
14
+ // refs to cancel per-item animations
15
+ const animatingRefs = useRef({});
16
+ // track mounted items (for mount/unmount)
17
+ const [mounted, setMounted] = useState(() => Object.fromEntries(options.items.map((item) => [
18
+ item.key,
19
+ !options.mountOnEnter,
20
+ ])));
21
+ // animate a single item
22
+ const animateItem = useCallback((item, entering, delay = 0) => {
23
+ var _a, _b;
24
+ // cancel previous
25
+ (_b = (_a = animatingRefs.current)[item.key]) === null || _b === void 0 ? void 0 : _b.call(_a);
26
+ if (entering)
27
+ setStatuses((s) => (Object.assign(Object.assign({}, s), { [item.key]: "entering" })));
28
+ else
29
+ setStatuses((s) => (Object.assign(Object.assign({}, s), { [item.key]: "exiting" })));
30
+ if (entering && options.mountOnEnter) {
31
+ setMounted((m) => (Object.assign(Object.assign({}, m), { [item.key]: true })));
32
+ }
33
+ // start animation after delay
34
+ const timeout = setTimeout(() => {
35
+ var _a, _b, _c;
36
+ if (entering)
37
+ (_a = options.onEnter) === null || _a === void 0 ? void 0 : _a.call(options, item.key);
38
+ else
39
+ (_b = options.onExit) === null || _b === void 0 ? void 0 : _b.call(options, item.key);
40
+ animatingRefs.current[item.key] = animate({
41
+ from: entering ? item.from : item.to,
42
+ to: entering ? item.to : item.from,
43
+ duration: (_c = options.duration) !== null && _c !== void 0 ? _c : 400,
44
+ onUpdate: (value, progress) => { var _a; return (_a = options.onUpdate) === null || _a === void 0 ? void 0 : _a.call(options, value, item.key, progress); },
45
+ onDone: () => {
46
+ var _a, _b;
47
+ if (entering) {
48
+ setStatuses((s) => (Object.assign(Object.assign({}, s), { [item.key]: "entered" })));
49
+ (_a = options.onEntered) === null || _a === void 0 ? void 0 : _a.call(options, item.key);
50
+ }
51
+ else {
52
+ setStatuses((s) => (Object.assign(Object.assign({}, s), { [item.key]: "exited" })));
53
+ (_b = options.onExited) === null || _b === void 0 ? void 0 : _b.call(options, item.key);
54
+ if (options.unmountOnExit) {
55
+ setMounted((m) => (Object.assign(Object.assign({}, m), { [item.key]: false })));
56
+ }
57
+ }
58
+ },
59
+ });
60
+ }, delay);
61
+ return () => clearTimeout(timeout);
62
+ }, [options]);
63
+ // run staggered animation on array of items
64
+ const run = useCallback((entering) => {
65
+ options.items.forEach((item, index) => {
66
+ var _a;
67
+ const delay = ((_a = options.stagger) !== null && _a !== void 0 ? _a : 100) * index;
68
+ const status = statuses[item.key];
69
+ // skip if already animating in same direction
70
+ if (entering && (status === "entering" || status === "entered"))
71
+ return;
72
+ if (!entering && (status === "exiting" || status === "exited"))
73
+ return;
74
+ animateItem(item, entering, delay);
75
+ });
76
+ }, [options.items, options.stagger, animateItem, statuses]);
77
+ const enter = useCallback(() => run(true), [run]);
78
+ const exit = useCallback(() => run(false), [run]);
79
+ const toggle = useCallback(() => {
80
+ const anyEntered = Object.values(statuses).some((s) => s === "entering" || s === "entered");
81
+ run(!anyEntered);
82
+ }, [run, statuses]);
83
+ return {
84
+ statuses,
85
+ mounted,
86
+ enter,
87
+ exit,
88
+ toggle,
89
+ };
90
+ }
91
+
92
+ export { useTransitionGroup as default };
93
+ //# sourceMappingURL=useTransitionGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTransitionGroup.js","sources":["../../src/hooks/useTransitionGroup.ts"],"sourcesContent":["\"use client\"\nimport { useRef, useState, useCallback } from \"react\"\nimport animate from \"../animate\"\nimport { UseTransitionStatus } from \"./useTransition\"\n\nexport type UseTransitionGroupItem<T extends Record<string, number>> = {\n key: string | number\n from: T\n to: T\n}\n\nexport type UseTransitionGroupProps<T extends Record<string, number>> = {\n items: UseTransitionGroupItem<T>[]\n duration?: number\n stagger?: number // delay between items in ms\n mountOnEnter?: boolean\n unmountOnExit?: boolean\n onUpdate?: (value: T, key: string | number, progress: number) => void\n onEnter?: (key: string | number) => void\n onEntered?: (key: string | number) => void\n onExit?: (key: string | number) => void\n onExited?: (key: string | number) => void\n}\n\n/**\n * useTransitionGroup - staggered animations for multiple items\n */\nfunction useTransitionGroup<T extends Record<string, number>>(\n options: UseTransitionGroupProps<T>\n) {\n // status of each item\n const [statuses, setStatuses] = useState<\n Record<string | number, UseTransitionStatus>\n >(\n () =>\n Object.fromEntries(\n options.items.map((item) => [\n item.key,\n options.mountOnEnter ? \"exited\" : \"entered\",\n ])\n )\n )\n\n // refs to cancel per-item animations\n const animatingRefs = useRef<Record<string | number, (() => void) | null>>({})\n\n // track mounted items (for mount/unmount)\n const [mounted, setMounted] = useState<Record<string | number, boolean>>(\n () =>\n Object.fromEntries(\n options.items.map((item) => [\n item.key,\n !options.mountOnEnter,\n ])\n )\n )\n\n // animate a single item\n const animateItem = useCallback(\n (item: UseTransitionGroupItem<T>, entering: boolean, delay = 0) => {\n // cancel previous\n animatingRefs.current[item.key]?.()\n\n if (entering) setStatuses((s: any) => ({ ...s, [item.key]: \"entering\" }))\n else setStatuses((s: any) => ({ ...s, [item.key]: \"exiting\" }))\n\n if (entering && options.mountOnEnter) {\n setMounted((m) => ({ ...m, [item.key]: true }))\n }\n\n // start animation after delay\n const timeout = setTimeout(() => {\n if (entering) options.onEnter?.(item.key)\n else options.onExit?.(item.key)\n\n animatingRefs.current[item.key] = animate({\n from: entering ? item.from : item.to,\n to: entering ? item.to : item.from,\n duration: options.duration ?? 400,\n onUpdate: (value, progress) =>\n options.onUpdate?.(value, item.key, progress),\n onDone: () => {\n if (entering) {\n setStatuses((s: any) => ({ ...s, [item.key]: \"entered\" }))\n options.onEntered?.(item.key)\n } else {\n setStatuses((s: any) => ({ ...s, [item.key]: \"exited\" }))\n options.onExited?.(item.key)\n if (options.unmountOnExit) {\n setMounted((m) => ({ ...m, [item.key]: false }))\n }\n }\n },\n })\n }, delay)\n\n return () => clearTimeout(timeout)\n },\n [options]\n )\n\n // run staggered animation on array of items\n const run = useCallback(\n (entering: boolean) => {\n options.items.forEach((item, index) => {\n const delay = (options.stagger ?? 100) * index\n const status = statuses[item.key]\n\n // skip if already animating in same direction\n if (entering && (status === \"entering\" || status === \"entered\")) return\n if (!entering && (status === \"exiting\" || status === \"exited\")) return\n\n animateItem(item, entering, delay)\n })\n },\n [options.items, options.stagger, animateItem, statuses]\n )\n\n const enter = useCallback(() => run(true), [run])\n const exit = useCallback(() => run(false), [run])\n const toggle = useCallback(() => {\n const anyEntered = Object.values(statuses).some(\n (s) => s === \"entering\" || s === \"entered\"\n )\n run(!anyEntered)\n }, [run, statuses])\n\n return {\n statuses,\n mounted,\n enter,\n exit,\n toggle,\n }\n}\n\nexport default useTransitionGroup"],"names":[],"mappings":";;;;AAwBA;;AAEG;AACH;;;AAUe;;;;AAOZ;;;AAOY;;;;AAOZ;;;;AAKM;AAAc;;AACT;AAEL;AACG;;;AAIH;;AACG;;;;;AAIG;AACA;AACA;;;;;AAKM;;;;AAGA;;AAEA;AACG;;;;AAIX;;AAGJ;AACH;;AAKH;;;AAGS;;;;;;;AAOA;AACH;AACH;AAIH;AACA;AACA;;AAIG;AACH;;;;;;;;AASH;;"}