@mks2508/mks-ui 0.2.1 → 0.3.1
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/react-ui/hooks/Animation/UseAutoHeight.js +7 -7
- package/dist/react-ui/hooks/DOM/UseIsInView.js +3 -3
- package/dist/react-ui/hooks/Formatting/UseListFormat.d.ts +49 -0
- package/dist/react-ui/hooks/Formatting/UseListFormat.d.ts.map +1 -0
- package/dist/react-ui/hooks/Formatting/UseListFormat.js +105 -0
- package/dist/react-ui/hooks/State/UseControlledState.js +4 -4
- package/dist/react-ui/hooks/State/UseDataState.js +5 -5
- package/dist/react-ui/hooks/index.d.ts +2 -0
- package/dist/react-ui/hooks/index.d.ts.map +1 -1
- package/dist/react-ui/hooks/index.js +1 -0
- package/dist/react-ui/index.js +22 -2
- package/dist/react-ui/lib/get-strict-context.js +3 -3
- package/dist/react-ui/primitives/CountingNumber/index.js +3 -3
- package/dist/react-ui/primitives/Highlight/index.js +26 -26
- package/dist/react-ui/primitives/Slot/index.js +3 -3
- package/dist/react-ui/primitives/index.d.ts +1 -0
- package/dist/react-ui/primitives/index.d.ts.map +1 -1
- package/dist/react-ui/primitives/index.js +18 -0
- package/dist/react-ui/primitives/waapi/Morph/Morph.types.d.ts +76 -0
- package/dist/react-ui/primitives/waapi/Morph/Morph.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/MorphContext.d.ts +11 -0
- package/dist/react-ui/primitives/waapi/Morph/MorphContext.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/MorphContext.js +19 -0
- package/dist/react-ui/primitives/waapi/Morph/index.d.ts +23 -0
- package/dist/react-ui/primitives/waapi/Morph/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/index.js +45 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/index.d.ts +12 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.d.ts +38 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.js +78 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.d.ts +23 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.js +140 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.d.ts +28 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.js +77 -0
- package/dist/react-ui/primitives/waapi/Morph/useMorph.d.ts +27 -0
- package/dist/react-ui/primitives/waapi/Morph/useMorph.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Morph/useMorph.js +86 -0
- package/dist/react-ui/primitives/waapi/Reorder/Reorder.types.d.ts +168 -0
- package/dist/react-ui/primitives/waapi/Reorder/Reorder.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/index.d.ts +25 -0
- package/dist/react-ui/primitives/waapi/Reorder/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/index.js +186 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorder.d.ts +26 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorder.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorder.js +48 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorderPresence.d.ts +33 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorderPresence.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/useReorderPresence.js +137 -0
- package/dist/react-ui/primitives/waapi/Reorder/utils/separatorCoordination.d.ts +47 -0
- package/dist/react-ui/primitives/waapi/Reorder/utils/separatorCoordination.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/Reorder/utils/separatorCoordination.js +72 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.styles.d.ts +10 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.styles.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.types.d.ts +74 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/index.d.ts +33 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingNumber/index.js +354 -0
- package/dist/react-ui/primitives/waapi/SlidingText/SlidingText.styles.d.ts +25 -0
- package/dist/react-ui/primitives/waapi/SlidingText/SlidingText.styles.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingText/SlidingText.types.d.ts +57 -0
- package/dist/react-ui/primitives/waapi/SlidingText/SlidingText.types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingText/index.d.ts +26 -0
- package/dist/react-ui/primitives/waapi/SlidingText/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/SlidingText/index.js +105 -0
- package/dist/react-ui/primitives/waapi/core/animationConstants.d.ts +156 -0
- package/dist/react-ui/primitives/waapi/core/animationConstants.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/animationConstants.js +180 -0
- package/dist/react-ui/primitives/waapi/core/index.d.ts +16 -0
- package/dist/react-ui/primitives/waapi/core/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/index.js +5 -0
- package/dist/react-ui/primitives/waapi/core/types.d.ts +143 -0
- package/dist/react-ui/primitives/waapi/core/types.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/useAnimationOrchestrator.d.ts +32 -0
- package/dist/react-ui/primitives/waapi/core/useAnimationOrchestrator.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/useAnimationOrchestrator.js +322 -0
- package/dist/react-ui/primitives/waapi/core/useElementRegistry.d.ts +21 -0
- package/dist/react-ui/primitives/waapi/core/useElementRegistry.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/useElementRegistry.js +65 -0
- package/dist/react-ui/primitives/waapi/core/useFLIPAnimation.d.ts +20 -0
- package/dist/react-ui/primitives/waapi/core/useFLIPAnimation.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/useFLIPAnimation.js +99 -0
- package/dist/react-ui/primitives/waapi/core/usePositionCapture.d.ts +24 -0
- package/dist/react-ui/primitives/waapi/core/usePositionCapture.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/core/usePositionCapture.js +75 -0
- package/dist/react-ui/primitives/waapi/index.d.ts +33 -0
- package/dist/react-ui/primitives/waapi/index.d.ts.map +1 -0
- package/dist/react-ui/primitives/waapi/index.js +18 -0
- package/dist/react-ui/ui/Accordion/index.js +3 -3
- package/dist/react-ui/ui/Button/index.js +8 -8
- package/dist/react-ui/ui/Combobox/index.js +2 -2
- package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts +35 -0
- package/dist/react-ui/ui/DataCard/DataCard.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/DataCard/DataCard.styles.js +114 -0
- package/dist/react-ui/ui/DataCard/DataCard.types.d.ts +135 -0
- package/dist/react-ui/ui/DataCard/DataCard.types.d.ts.map +1 -0
- package/dist/react-ui/ui/DataCard/index.d.ts +129 -0
- package/dist/react-ui/ui/DataCard/index.d.ts.map +1 -0
- package/dist/react-ui/ui/DataCard/index.js +276 -0
- package/dist/react-ui/ui/Menu/index.js +2 -2
- package/dist/react-ui/ui/Switch/index.js +3 -3
- package/dist/react-ui/ui/Tabs/index.js +3 -3
- package/dist/react-ui/ui/TextFlow/TextFlow.styles.d.ts +16 -0
- package/dist/react-ui/ui/TextFlow/TextFlow.styles.d.ts.map +1 -0
- package/dist/react-ui/ui/TextFlow/TextFlow.types.d.ts +101 -0
- package/dist/react-ui/ui/TextFlow/TextFlow.types.d.ts.map +1 -0
- package/dist/react-ui/ui/TextFlow/index.d.ts +26 -0
- package/dist/react-ui/ui/TextFlow/index.d.ts.map +1 -0
- package/dist/react-ui/ui/TextFlow/index.js +187 -0
- package/dist/react-ui/ui/index.d.ts +2 -1
- package/dist/react-ui/ui/index.d.ts.map +1 -1
- package/dist/react-ui/ui/index.js +3 -1
- package/package.json +6 -2
- package/src/react-ui/hooks/Formatting/UseListFormat.ts +134 -0
- package/src/react-ui/hooks/index.ts +3 -0
- package/src/react-ui/primitives/index.ts +3 -0
- package/src/react-ui/primitives/waapi/Morph/Morph.types.ts +106 -0
- package/src/react-ui/primitives/waapi/Morph/MorphContext.tsx +21 -0
- package/src/react-ui/primitives/waapi/Morph/index.tsx +56 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/index.ts +12 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/useCSSGridMorph.ts +88 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/useFLIPClipPath.ts +175 -0
- package/src/react-ui/primitives/waapi/Morph/techniques/useViewTransitions.ts +86 -0
- package/src/react-ui/primitives/waapi/Morph/useMorph.ts +100 -0
- package/src/react-ui/primitives/waapi/Reorder/Reorder.types.ts +177 -0
- package/src/react-ui/primitives/waapi/Reorder/index.tsx +260 -0
- package/src/react-ui/primitives/waapi/Reorder/useReorder.ts +46 -0
- package/src/react-ui/primitives/waapi/Reorder/useReorderPresence.ts +208 -0
- package/src/react-ui/primitives/waapi/Reorder/utils/separatorCoordination.ts +104 -0
- package/src/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.styles.ts +14 -0
- package/src/react-ui/primitives/waapi/SlidingNumber/SlidingNumber.types.ts +84 -0
- package/src/react-ui/primitives/waapi/SlidingNumber/index.tsx +474 -0
- package/src/react-ui/primitives/waapi/SlidingText/SlidingText.styles.ts +32 -0
- package/src/react-ui/primitives/waapi/SlidingText/SlidingText.types.ts +69 -0
- package/src/react-ui/primitives/waapi/SlidingText/index.tsx +140 -0
- package/src/react-ui/primitives/waapi/core/animationConstants.ts +215 -0
- package/src/react-ui/primitives/waapi/core/index.ts +53 -0
- package/src/react-ui/primitives/waapi/core/types.ts +200 -0
- package/src/react-ui/primitives/waapi/core/useAnimationOrchestrator.ts +429 -0
- package/src/react-ui/primitives/waapi/core/useElementRegistry.ts +80 -0
- package/src/react-ui/primitives/waapi/core/useFLIPAnimation.ts +137 -0
- package/src/react-ui/primitives/waapi/core/usePositionCapture.ts +105 -0
- package/src/react-ui/primitives/waapi/index.ts +116 -0
- package/src/react-ui/styles/animations.css +369 -0
- package/src/react-ui/ui/DataCard/DataCard.styles.ts +150 -0
- package/src/react-ui/ui/DataCard/DataCard.types.ts +146 -0
- package/src/react-ui/ui/DataCard/index.tsx +406 -0
- package/src/react-ui/ui/TextFlow/TextFlow.styles.ts +36 -0
- package/src/react-ui/ui/TextFlow/TextFlow.types.ts +118 -0
- package/src/react-ui/ui/TextFlow/index.tsx +276 -0
- package/src/react-ui/ui/index.ts +4 -1
- /package/dist/react-ui/components/MorphingPopover/{morphing-popover.module-CgbYV_HS.css → morphing-popover.module-BycNI8nU.css} +0 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { EASINGS, EFFECTS, TIMING, TRANSFORMS } from "./animationConstants.js";
|
|
2
|
+
import { useElementRegistry } from "./useElementRegistry.js";
|
|
3
|
+
import { usePositionCapture } from "./usePositionCapture.js";
|
|
4
|
+
import { useFLIPAnimation } from "./useFLIPAnimation.js";
|
|
5
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
6
|
+
|
|
7
|
+
//#region src/react-ui/primitives/waapi/core/useAnimationOrchestrator.ts
|
|
8
|
+
/**
|
|
9
|
+
* Main animation orchestrator hook.
|
|
10
|
+
* Composes useElementRegistry, usePositionCapture, and useFLIPAnimation
|
|
11
|
+
* into a full FLIP exit/enter pipeline.
|
|
12
|
+
*
|
|
13
|
+
* Handles the full exit animation sequence:
|
|
14
|
+
* 1. Capture positions of remaining elements (FIRST)
|
|
15
|
+
* 2. Apply position:absolute to exiting element
|
|
16
|
+
* 3. Force synchronous reflow
|
|
17
|
+
* 4. Capture AFTER positions (LAST)
|
|
18
|
+
* 5. Calculate INVERT deltas and PLAY FLIP animations
|
|
19
|
+
* 6. Run exit animation (per-token stagger or whole-element)
|
|
20
|
+
* 7. Wait for all animations to complete
|
|
21
|
+
* 8. Cleanup and notify completion
|
|
22
|
+
*
|
|
23
|
+
* @param config - Optional orchestrator configuration
|
|
24
|
+
* @returns Full orchestrator API
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* const orchestrator = useAnimationOrchestrator({
|
|
29
|
+
* onExitComplete: (id) => removeFromList(id)
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* <div ref={el => orchestrator.registerElement('item-1', el)} />
|
|
33
|
+
*
|
|
34
|
+
* await orchestrator.startExit('item-1');
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
function useAnimationOrchestrator(config) {
|
|
38
|
+
const configRef = useRef(config);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
configRef.current = config;
|
|
41
|
+
}, [config]);
|
|
42
|
+
const stateRef = useRef({
|
|
43
|
+
animatingIds: /* @__PURE__ */ new Set(),
|
|
44
|
+
positions: /* @__PURE__ */ new Map(),
|
|
45
|
+
activeAnimations: /* @__PURE__ */ new Map()
|
|
46
|
+
});
|
|
47
|
+
const registry = useElementRegistry();
|
|
48
|
+
const positions = usePositionCapture(registry.getAll, { minDeltaPx: config?.minDeltaPx ?? TIMING.MIN_DELTA_PX });
|
|
49
|
+
const flip = useFLIPAnimation();
|
|
50
|
+
const exitDuration = config?.exitDuration ?? TIMING.EXIT_DURATION;
|
|
51
|
+
const flipDuration = config?.flipDuration ?? TIMING.FLIP_DURATION;
|
|
52
|
+
const exitEasing = config?.exitEasing ?? EASINGS.EASE_IN_CUBIC;
|
|
53
|
+
const cancelAnimation = useCallback((id) => {
|
|
54
|
+
const animations = stateRef.current.activeAnimations.get(id);
|
|
55
|
+
if (animations) {
|
|
56
|
+
animations.forEach((anim) => anim.cancel());
|
|
57
|
+
stateRef.current.activeAnimations.delete(id);
|
|
58
|
+
}
|
|
59
|
+
stateRef.current.animatingIds.delete(id);
|
|
60
|
+
flip.cancel(id);
|
|
61
|
+
}, [flip]);
|
|
62
|
+
const cancelAllAnimations = useCallback(() => {
|
|
63
|
+
stateRef.current.activeAnimations.forEach((animations) => {
|
|
64
|
+
animations.forEach((anim) => anim.cancel());
|
|
65
|
+
});
|
|
66
|
+
stateRef.current.activeAnimations.clear();
|
|
67
|
+
stateRef.current.animatingIds.clear();
|
|
68
|
+
flip.cancelAll();
|
|
69
|
+
}, [flip]);
|
|
70
|
+
const flipBehavior = config?.flipBehavior ?? "all";
|
|
71
|
+
const exitPositionStrategy = config?.exitPositionStrategy ?? "absolute-fixed";
|
|
72
|
+
/**
|
|
73
|
+
* Full FLIP exit implementation.
|
|
74
|
+
* Based on research from Paul Lewis (aerotwist.com), react-flip-move,
|
|
75
|
+
* and Framer Motion popLayout mode.
|
|
76
|
+
*/
|
|
77
|
+
const startExit = useCallback(async (id, options) => {
|
|
78
|
+
const el = registry.get(id);
|
|
79
|
+
if (!el || stateRef.current.animatingIds.has(id)) return;
|
|
80
|
+
stateRef.current.animatingIds.add(id);
|
|
81
|
+
const duration = options?.duration ?? exitDuration;
|
|
82
|
+
const easing = options?.easing ?? exitEasing;
|
|
83
|
+
const allElements = registry.getAll();
|
|
84
|
+
const beforePositions = /* @__PURE__ */ new Map();
|
|
85
|
+
const exitingRect = el.getBoundingClientRect();
|
|
86
|
+
beforePositions.set(id, exitingRect);
|
|
87
|
+
allElements.forEach((element, elemId) => {
|
|
88
|
+
if (elemId !== id) {
|
|
89
|
+
const rect = element.getBoundingClientRect();
|
|
90
|
+
if (rect.width > 0 && rect.height > 0) beforePositions.set(elemId, rect);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
const parent = el.parentElement;
|
|
94
|
+
el.dataset.reorderState = "exiting";
|
|
95
|
+
if (exitPositionStrategy === "absolute-fixed") el.dataset.exitPosition = "absolute";
|
|
96
|
+
const parentRectBefore = parent?.getBoundingClientRect() || {
|
|
97
|
+
left: 0,
|
|
98
|
+
top: 0
|
|
99
|
+
};
|
|
100
|
+
const absoluteLeft = exitingRect.left - parentRectBefore.left;
|
|
101
|
+
const absoluteTop = exitingRect.top - parentRectBefore.top;
|
|
102
|
+
if (exitPositionStrategy === "absolute-fixed") {
|
|
103
|
+
el.style.position = "absolute";
|
|
104
|
+
el.style.left = `${absoluteLeft}px`;
|
|
105
|
+
el.style.top = `${absoluteTop}px`;
|
|
106
|
+
el.style.width = `${exitingRect.width}px`;
|
|
107
|
+
el.style.height = `${exitingRect.height}px`;
|
|
108
|
+
el.style.margin = "0";
|
|
109
|
+
}
|
|
110
|
+
const parentRectAfter = parent?.getBoundingClientRect() || {
|
|
111
|
+
left: 0,
|
|
112
|
+
top: 0
|
|
113
|
+
};
|
|
114
|
+
const parentDeltaX = parentRectAfter.left - parentRectBefore.left;
|
|
115
|
+
const parentDeltaY = parentRectAfter.top - parentRectBefore.top;
|
|
116
|
+
if (Math.abs(parentDeltaX) > .5 || Math.abs(parentDeltaY) > .5) el.style.transform = `translate(${-parentDeltaX}px, ${-parentDeltaY}px)`;
|
|
117
|
+
const afterPositions = /* @__PURE__ */ new Map();
|
|
118
|
+
allElements.forEach((element, elemId) => {
|
|
119
|
+
if (elemId !== id) {
|
|
120
|
+
const rect = element.getBoundingClientRect();
|
|
121
|
+
if (rect.width > 0 && rect.height > 0) afterPositions.set(elemId, rect);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
const flipAnimations = [];
|
|
125
|
+
if (flipBehavior !== "none") {
|
|
126
|
+
let siblingsToAnimate = [];
|
|
127
|
+
if (flipBehavior === "all") siblingsToAnimate = [...afterPositions.keys()];
|
|
128
|
+
else if (flipBehavior === "siblings-after") {
|
|
129
|
+
const elementsWithIds = Array.from(allElements.entries());
|
|
130
|
+
elementsWithIds.sort((a, b) => {
|
|
131
|
+
const posA = a[1];
|
|
132
|
+
const posB = b[1];
|
|
133
|
+
return posA.compareDocumentPosition(posB) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
|
|
134
|
+
});
|
|
135
|
+
const sortedKeys = elementsWithIds.map(([k]) => k);
|
|
136
|
+
const exitingIndex = sortedKeys.indexOf(id);
|
|
137
|
+
if (exitingIndex !== -1) siblingsToAnimate = sortedKeys.slice(exitingIndex + 1).filter((k) => afterPositions.has(k));
|
|
138
|
+
}
|
|
139
|
+
siblingsToAnimate.forEach((siblingId) => {
|
|
140
|
+
const before = beforePositions.get(siblingId);
|
|
141
|
+
const after = afterPositions.get(siblingId);
|
|
142
|
+
if (!before || !after) return;
|
|
143
|
+
const deltaX = before.left - after.left;
|
|
144
|
+
const deltaY = before.top - after.top;
|
|
145
|
+
if (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1) {
|
|
146
|
+
const siblingEl = allElements.get(siblingId);
|
|
147
|
+
if (siblingEl) {
|
|
148
|
+
siblingEl.dataset.reorderState = "flipping";
|
|
149
|
+
siblingEl.style.transform = `translate(${deltaX}px, ${deltaY}px)`;
|
|
150
|
+
const anim = siblingEl.animate([{ transform: `translate(${deltaX}px, ${deltaY}px)` }, { transform: "none" }], {
|
|
151
|
+
duration: flipDuration,
|
|
152
|
+
easing: EASINGS.MATERIAL_DECELERATE,
|
|
153
|
+
fill: "forwards"
|
|
154
|
+
});
|
|
155
|
+
flipAnimations.push(anim);
|
|
156
|
+
anim.finished.then(() => {
|
|
157
|
+
siblingEl.style.transform = "";
|
|
158
|
+
siblingEl.dataset.reorderState = "idle";
|
|
159
|
+
}).catch(() => {
|
|
160
|
+
siblingEl.style.transform = "";
|
|
161
|
+
siblingEl.dataset.reorderState = "idle";
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
const exitAnimations = [];
|
|
168
|
+
const tokens = el.querySelectorAll(".waapi-sliding-text-token");
|
|
169
|
+
if (tokens.length > 0) tokens.forEach((token, index) => {
|
|
170
|
+
const delay = index * TIMING.EXIT_STAGGER;
|
|
171
|
+
const anim = token.animate([{
|
|
172
|
+
opacity: 1,
|
|
173
|
+
transform: "translateY(0) scale(1)",
|
|
174
|
+
filter: "blur(0px)"
|
|
175
|
+
}, {
|
|
176
|
+
opacity: 0,
|
|
177
|
+
transform: `translateY(${TRANSFORMS.OFFSET_Y_EXIT}px) scale(${TRANSFORMS.SCALE_EXIT})`,
|
|
178
|
+
filter: `blur(${EFFECTS.BLUR_EXIT}px)`
|
|
179
|
+
}], {
|
|
180
|
+
duration,
|
|
181
|
+
easing,
|
|
182
|
+
delay,
|
|
183
|
+
fill: "forwards"
|
|
184
|
+
});
|
|
185
|
+
exitAnimations.push(anim);
|
|
186
|
+
});
|
|
187
|
+
else {
|
|
188
|
+
const anim = el.animate([{
|
|
189
|
+
opacity: 1,
|
|
190
|
+
transform: "scale(1)"
|
|
191
|
+
}, {
|
|
192
|
+
opacity: 0,
|
|
193
|
+
transform: `scale(${TRANSFORMS.SCALE_EXIT})`
|
|
194
|
+
}], {
|
|
195
|
+
duration,
|
|
196
|
+
easing,
|
|
197
|
+
fill: "forwards"
|
|
198
|
+
});
|
|
199
|
+
exitAnimations.push(anim);
|
|
200
|
+
}
|
|
201
|
+
stateRef.current.activeAnimations.set(id, [...exitAnimations, ...flipAnimations]);
|
|
202
|
+
try {
|
|
203
|
+
await Promise.all([...exitAnimations.map((a) => a.finished), ...flipAnimations.map((a) => a.finished)]);
|
|
204
|
+
} catch {
|
|
205
|
+
stateRef.current.animatingIds.delete(id);
|
|
206
|
+
stateRef.current.activeAnimations.delete(id);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
stateRef.current.animatingIds.delete(id);
|
|
210
|
+
stateRef.current.activeAnimations.delete(id);
|
|
211
|
+
el.dataset.reorderState = "completed";
|
|
212
|
+
if (exitPositionStrategy === "absolute-fixed") {
|
|
213
|
+
el.style.removeProperty("position");
|
|
214
|
+
el.style.removeProperty("left");
|
|
215
|
+
el.style.removeProperty("top");
|
|
216
|
+
el.style.removeProperty("width");
|
|
217
|
+
el.style.removeProperty("height");
|
|
218
|
+
el.style.removeProperty("margin");
|
|
219
|
+
}
|
|
220
|
+
delete el.dataset.exitPosition;
|
|
221
|
+
registry.unregister(id);
|
|
222
|
+
options?.onComplete?.();
|
|
223
|
+
configRef.current?.onExitComplete?.(id);
|
|
224
|
+
}, [
|
|
225
|
+
registry,
|
|
226
|
+
exitDuration,
|
|
227
|
+
exitEasing,
|
|
228
|
+
flipDuration,
|
|
229
|
+
flipBehavior,
|
|
230
|
+
exitPositionStrategy
|
|
231
|
+
]);
|
|
232
|
+
/**
|
|
233
|
+
* Start enter animation for an element.
|
|
234
|
+
*
|
|
235
|
+
* Architecture: CSS + WAAPI
|
|
236
|
+
* - Assumes element already has data-reorder-state="entering" (set by Reorder.tsx)
|
|
237
|
+
* - CSS [data-reorder-state="entering"] { opacity: 0; transform: translateY(-8px) scale(0.95); }
|
|
238
|
+
* - WAAPI animates FROM that state TO visible
|
|
239
|
+
* - Sets data-reorder-state="idle" on completion
|
|
240
|
+
*/
|
|
241
|
+
const startEnter = useCallback(async (id, options) => {
|
|
242
|
+
const el = registry.get(id);
|
|
243
|
+
if (!el) return;
|
|
244
|
+
if (!el.dataset.reorderState) el.dataset.reorderState = "entering";
|
|
245
|
+
const enterDuration = configRef.current?.enterDuration ?? TIMING.ENTER_DURATION;
|
|
246
|
+
const enterEasing = configRef.current?.enterEasing ?? EASINGS.MATERIAL_DECELERATE;
|
|
247
|
+
const duration = options?.duration ?? enterDuration;
|
|
248
|
+
const easing = options?.easing ?? enterEasing;
|
|
249
|
+
const stagger = options?.stagger ?? TIMING.ENTER_STAGGER;
|
|
250
|
+
const tokens = el.querySelectorAll(".waapi-sliding-text-token");
|
|
251
|
+
const animations = [];
|
|
252
|
+
const fromKeyframe = {
|
|
253
|
+
opacity: 0,
|
|
254
|
+
transform: "translateY(-8px) scale(0.95)"
|
|
255
|
+
};
|
|
256
|
+
const toKeyframe = {
|
|
257
|
+
opacity: 1,
|
|
258
|
+
transform: "none"
|
|
259
|
+
};
|
|
260
|
+
if (tokens.length > 0) tokens.forEach((token, index) => {
|
|
261
|
+
const delay = index * stagger;
|
|
262
|
+
token.dataset.reorderIndex = String(index);
|
|
263
|
+
const anim = token.animate([{
|
|
264
|
+
...fromKeyframe,
|
|
265
|
+
filter: `blur(${EFFECTS.BLUR_ENTER}px)`
|
|
266
|
+
}, {
|
|
267
|
+
...toKeyframe,
|
|
268
|
+
filter: "blur(0px)"
|
|
269
|
+
}], {
|
|
270
|
+
duration,
|
|
271
|
+
easing,
|
|
272
|
+
delay,
|
|
273
|
+
fill: "forwards"
|
|
274
|
+
});
|
|
275
|
+
animations.push(anim);
|
|
276
|
+
});
|
|
277
|
+
else {
|
|
278
|
+
const anim = el.animate([fromKeyframe, toKeyframe], {
|
|
279
|
+
duration,
|
|
280
|
+
easing,
|
|
281
|
+
fill: "forwards"
|
|
282
|
+
});
|
|
283
|
+
animations.push(anim);
|
|
284
|
+
}
|
|
285
|
+
try {
|
|
286
|
+
await Promise.all(animations.map((a) => a.finished));
|
|
287
|
+
} catch {
|
|
288
|
+
el.dataset.reorderState = "idle";
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
el.dataset.reorderState = "idle";
|
|
292
|
+
options?.onComplete?.();
|
|
293
|
+
configRef.current?.onEnterComplete?.(id);
|
|
294
|
+
}, [registry]);
|
|
295
|
+
const isAnimating = useCallback((id) => {
|
|
296
|
+
if (id) return stateRef.current.animatingIds.has(id);
|
|
297
|
+
return stateRef.current.animatingIds.size > 0;
|
|
298
|
+
}, []);
|
|
299
|
+
const capturePositions = useCallback((excludeIds) => {
|
|
300
|
+
return positions.capture(excludeIds);
|
|
301
|
+
}, [positions]);
|
|
302
|
+
useEffect(() => {
|
|
303
|
+
return () => {
|
|
304
|
+
cancelAllAnimations();
|
|
305
|
+
};
|
|
306
|
+
}, [cancelAllAnimations]);
|
|
307
|
+
return {
|
|
308
|
+
registry,
|
|
309
|
+
positions,
|
|
310
|
+
flip,
|
|
311
|
+
registerElement: registry.register,
|
|
312
|
+
startExit,
|
|
313
|
+
startEnter,
|
|
314
|
+
isAnimating,
|
|
315
|
+
cancelAnimation,
|
|
316
|
+
cancelAllAnimations,
|
|
317
|
+
capturePositions
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
//#endregion
|
|
322
|
+
export { useAnimationOrchestrator };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { IElementRegistryAPI, IElementRegistryCallbacks } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Hook for tracking DOM elements by ID.
|
|
4
|
+
* Extracted from the WAAPI animation system's element registration logic.
|
|
5
|
+
*
|
|
6
|
+
* @param callbacks - Optional lifecycle callbacks for register/unregister events
|
|
7
|
+
* @returns Registry API for managing elements by ID
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* const registry = useElementRegistry({
|
|
12
|
+
* onRegister: (id) => console.log(`Registered: ${id}`),
|
|
13
|
+
* onUnregister: (id) => console.log(`Unregistered: ${id}`)
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* // In render:
|
|
17
|
+
* <div ref={el => registry.register('item-1', el)} />
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function useElementRegistry(callbacks?: IElementRegistryCallbacks): IElementRegistryAPI;
|
|
21
|
+
//# sourceMappingURL=useElementRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useElementRegistry.d.ts","sourceRoot":"","sources":["../../../../../src/react-ui/primitives/waapi/core/useElementRegistry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAC;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,CAAC,EAAE,yBAAyB,GACpC,mBAAmB,CAwDrB"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/react-ui/primitives/waapi/core/useElementRegistry.ts
|
|
4
|
+
/**
|
|
5
|
+
* Hook for tracking DOM elements by ID.
|
|
6
|
+
* Extracted from the WAAPI animation system's element registration logic.
|
|
7
|
+
*
|
|
8
|
+
* @param callbacks - Optional lifecycle callbacks for register/unregister events
|
|
9
|
+
* @returns Registry API for managing elements by ID
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* const registry = useElementRegistry({
|
|
14
|
+
* onRegister: (id) => console.log(`Registered: ${id}`),
|
|
15
|
+
* onUnregister: (id) => console.log(`Unregistered: ${id}`)
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* // In render:
|
|
19
|
+
* <div ref={el => registry.register('item-1', el)} />
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
function useElementRegistry(callbacks) {
|
|
23
|
+
const elementsRef = useRef(/* @__PURE__ */ new Map());
|
|
24
|
+
const callbacksRef = useRef(callbacks);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
callbacksRef.current = callbacks;
|
|
27
|
+
}, [callbacks]);
|
|
28
|
+
return {
|
|
29
|
+
register: useCallback((id, el) => {
|
|
30
|
+
if (el) {
|
|
31
|
+
elementsRef.current.set(id, el);
|
|
32
|
+
callbacksRef.current?.onRegister?.(id, el);
|
|
33
|
+
} else if (elementsRef.current.has(id)) {
|
|
34
|
+
elementsRef.current.delete(id);
|
|
35
|
+
callbacksRef.current?.onUnregister?.(id);
|
|
36
|
+
}
|
|
37
|
+
}, []),
|
|
38
|
+
unregister: useCallback((id) => {
|
|
39
|
+
if (elementsRef.current.has(id)) {
|
|
40
|
+
elementsRef.current.delete(id);
|
|
41
|
+
callbacksRef.current?.onUnregister?.(id);
|
|
42
|
+
}
|
|
43
|
+
}, []),
|
|
44
|
+
get: useCallback((id) => {
|
|
45
|
+
return elementsRef.current.get(id);
|
|
46
|
+
}, []),
|
|
47
|
+
getAll: useCallback(() => {
|
|
48
|
+
return new Map(elementsRef.current);
|
|
49
|
+
}, []),
|
|
50
|
+
has: useCallback((id) => {
|
|
51
|
+
return elementsRef.current.has(id);
|
|
52
|
+
}, []),
|
|
53
|
+
clear: useCallback(() => {
|
|
54
|
+
const ids = Array.from(elementsRef.current.keys());
|
|
55
|
+
elementsRef.current.clear();
|
|
56
|
+
ids.forEach((id) => callbacksRef.current?.onUnregister?.(id));
|
|
57
|
+
}, []),
|
|
58
|
+
get size() {
|
|
59
|
+
return elementsRef.current.size;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
//#endregion
|
|
65
|
+
export { useElementRegistry };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IFLIPAnimationAPI } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Hook for executing FLIP (First-Last-Invert-Play) animations.
|
|
4
|
+
* Uses spring easing for natural motion with slight overshoot.
|
|
5
|
+
*
|
|
6
|
+
* @returns FLIP animation API with animate, cancel, and status methods
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const flip = useFLIPAnimation();
|
|
11
|
+
*
|
|
12
|
+
* // After calculating deltas:
|
|
13
|
+
* await flip.animateAll(elements, deltas, {
|
|
14
|
+
* duration: 300,
|
|
15
|
+
* onComplete: (id) => console.log(`${id} completed`)
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare function useFLIPAnimation(): IFLIPAnimationAPI;
|
|
20
|
+
//# sourceMappingURL=useFLIPAnimation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFLIPAnimation.d.ts","sourceRoot":"","sources":["../../../../../src/react-ui/primitives/waapi/core/useFLIPAnimation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAqC,MAAM,SAAS,CAAC;AAKpF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,IAAI,iBAAiB,CAgHpD"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { EASINGS, TIMING } from "./animationConstants.js";
|
|
2
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/react-ui/primitives/waapi/core/useFLIPAnimation.ts
|
|
5
|
+
const DEFAULT_DURATION = TIMING.FLIP_DURATION;
|
|
6
|
+
const DEFAULT_EASING = EASINGS.SPRING_GENTLE;
|
|
7
|
+
/**
|
|
8
|
+
* Hook for executing FLIP (First-Last-Invert-Play) animations.
|
|
9
|
+
* Uses spring easing for natural motion with slight overshoot.
|
|
10
|
+
*
|
|
11
|
+
* @returns FLIP animation API with animate, cancel, and status methods
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* const flip = useFLIPAnimation();
|
|
16
|
+
*
|
|
17
|
+
* // After calculating deltas:
|
|
18
|
+
* await flip.animateAll(elements, deltas, {
|
|
19
|
+
* duration: 300,
|
|
20
|
+
* onComplete: (id) => console.log(`${id} completed`)
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
function useFLIPAnimation() {
|
|
25
|
+
const activeAnimationsRef = useRef(/* @__PURE__ */ new Map());
|
|
26
|
+
const animatingIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
27
|
+
const animate = useCallback((element, delta, options) => {
|
|
28
|
+
const duration = options?.duration ?? DEFAULT_DURATION;
|
|
29
|
+
const easing = options?.easing ?? DEFAULT_EASING;
|
|
30
|
+
if (activeAnimationsRef.current.has(delta.id)) activeAnimationsRef.current.get(delta.id)?.cancel();
|
|
31
|
+
animatingIdsRef.current.add(delta.id);
|
|
32
|
+
options?.onStart?.(delta.id);
|
|
33
|
+
const animation = element.animate([{ transform: `translate3d(${delta.deltaX}px, ${delta.deltaY}px, 0)` }, { transform: "translate3d(0, 0, 0)" }], {
|
|
34
|
+
duration,
|
|
35
|
+
easing
|
|
36
|
+
});
|
|
37
|
+
activeAnimationsRef.current.set(delta.id, animation);
|
|
38
|
+
animation.onfinish = () => {
|
|
39
|
+
animatingIdsRef.current.delete(delta.id);
|
|
40
|
+
activeAnimationsRef.current.delete(delta.id);
|
|
41
|
+
options?.onComplete?.(delta.id);
|
|
42
|
+
};
|
|
43
|
+
animation.oncancel = () => {
|
|
44
|
+
animatingIdsRef.current.delete(delta.id);
|
|
45
|
+
activeAnimationsRef.current.delete(delta.id);
|
|
46
|
+
};
|
|
47
|
+
return animation;
|
|
48
|
+
}, []);
|
|
49
|
+
const animateAll = useCallback(async (elements, deltas, options) => {
|
|
50
|
+
const animations = [];
|
|
51
|
+
deltas.forEach((delta, id) => {
|
|
52
|
+
if (!delta.isSignificant) return;
|
|
53
|
+
const element = elements.get(id);
|
|
54
|
+
if (!element) return;
|
|
55
|
+
const anim = animate(element, delta, options);
|
|
56
|
+
animations.push(anim);
|
|
57
|
+
});
|
|
58
|
+
if (animations.length === 0) return;
|
|
59
|
+
await Promise.all(animations.map((anim) => anim.finished.catch(() => {})));
|
|
60
|
+
}, [animate]);
|
|
61
|
+
const cancel = useCallback((id) => {
|
|
62
|
+
const animation = activeAnimationsRef.current.get(id);
|
|
63
|
+
if (animation) {
|
|
64
|
+
animation.cancel();
|
|
65
|
+
activeAnimationsRef.current.delete(id);
|
|
66
|
+
animatingIdsRef.current.delete(id);
|
|
67
|
+
}
|
|
68
|
+
}, []);
|
|
69
|
+
const cancelAll = useCallback(() => {
|
|
70
|
+
activeAnimationsRef.current.forEach((animation) => animation.cancel());
|
|
71
|
+
activeAnimationsRef.current.clear();
|
|
72
|
+
animatingIdsRef.current.clear();
|
|
73
|
+
}, []);
|
|
74
|
+
const isAnimating = useCallback((id) => {
|
|
75
|
+
if (id) return animatingIdsRef.current.has(id);
|
|
76
|
+
return animatingIdsRef.current.size > 0;
|
|
77
|
+
}, []);
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
return () => {
|
|
80
|
+
cancelAll();
|
|
81
|
+
};
|
|
82
|
+
}, [cancelAll]);
|
|
83
|
+
const api = useRef({
|
|
84
|
+
animate,
|
|
85
|
+
animateAll,
|
|
86
|
+
cancel,
|
|
87
|
+
cancelAll,
|
|
88
|
+
isAnimating
|
|
89
|
+
});
|
|
90
|
+
api.current.animate = animate;
|
|
91
|
+
api.current.animateAll = animateAll;
|
|
92
|
+
api.current.cancel = cancel;
|
|
93
|
+
api.current.cancelAll = cancelAll;
|
|
94
|
+
api.current.isAnimating = isAnimating;
|
|
95
|
+
return api.current;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
//#endregion
|
|
99
|
+
export { useFLIPAnimation };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { IPositionCaptureAPI, IPositionCaptureOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Hook for capturing element positions and calculating FLIP deltas.
|
|
4
|
+
* Extracted from the WAAPI animation system's position capture logic.
|
|
5
|
+
*
|
|
6
|
+
* @param getElements - Function that returns the current element map
|
|
7
|
+
* @param options - Optional configuration (e.g. minimum delta threshold)
|
|
8
|
+
* @returns Position capture API with capture, delta calculation, and cache
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const registry = useElementRegistry();
|
|
13
|
+
* const positions = usePositionCapture(registry.getAll);
|
|
14
|
+
*
|
|
15
|
+
* // Before layout change:
|
|
16
|
+
* const before = positions.capture();
|
|
17
|
+
*
|
|
18
|
+
* // After layout change:
|
|
19
|
+
* const after = positions.capture();
|
|
20
|
+
* const deltas = positions.calculateDeltas(before, after);
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export declare function usePositionCapture(getElements: () => Map<string, HTMLElement>, options?: IPositionCaptureOptions): IPositionCaptureAPI;
|
|
24
|
+
//# sourceMappingURL=usePositionCapture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePositionCapture.d.ts","sourceRoot":"","sources":["../../../../../src/react-ui/primitives/waapi/core/usePositionCapture.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAc,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAIxF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,EAC3C,OAAO,CAAC,EAAE,uBAAuB,GAChC,mBAAmB,CA0ErB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { TIMING } from "./animationConstants.js";
|
|
2
|
+
import { useCallback, useRef } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/react-ui/primitives/waapi/core/usePositionCapture.ts
|
|
5
|
+
const DEFAULT_MIN_DELTA_PX = TIMING.MIN_DELTA_PX;
|
|
6
|
+
/**
|
|
7
|
+
* Hook for capturing element positions and calculating FLIP deltas.
|
|
8
|
+
* Extracted from the WAAPI animation system's position capture logic.
|
|
9
|
+
*
|
|
10
|
+
* @param getElements - Function that returns the current element map
|
|
11
|
+
* @param options - Optional configuration (e.g. minimum delta threshold)
|
|
12
|
+
* @returns Position capture API with capture, delta calculation, and cache
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* const registry = useElementRegistry();
|
|
17
|
+
* const positions = usePositionCapture(registry.getAll);
|
|
18
|
+
*
|
|
19
|
+
* // Before layout change:
|
|
20
|
+
* const before = positions.capture();
|
|
21
|
+
*
|
|
22
|
+
* // After layout change:
|
|
23
|
+
* const after = positions.capture();
|
|
24
|
+
* const deltas = positions.calculateDeltas(before, after);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
function usePositionCapture(getElements, options) {
|
|
28
|
+
const lastCaptureRef = useRef(/* @__PURE__ */ new Map());
|
|
29
|
+
const minDeltaPx = options?.minDeltaPx ?? DEFAULT_MIN_DELTA_PX;
|
|
30
|
+
return {
|
|
31
|
+
capture: useCallback((excludeIds) => {
|
|
32
|
+
const positions = /* @__PURE__ */ new Map();
|
|
33
|
+
getElements().forEach((el, id) => {
|
|
34
|
+
if (excludeIds?.has(id)) return;
|
|
35
|
+
const rect = el.getBoundingClientRect();
|
|
36
|
+
if (rect.width > 0 && rect.height > 0) positions.set(id, rect);
|
|
37
|
+
});
|
|
38
|
+
lastCaptureRef.current = positions;
|
|
39
|
+
return positions;
|
|
40
|
+
}, [getElements]),
|
|
41
|
+
getPosition: useCallback((id) => {
|
|
42
|
+
return lastCaptureRef.current.get(id);
|
|
43
|
+
}, []),
|
|
44
|
+
calculateDeltas: useCallback((before, after) => {
|
|
45
|
+
const deltas = /* @__PURE__ */ new Map();
|
|
46
|
+
after.forEach((newRect, id) => {
|
|
47
|
+
const prevRect = before.get(id);
|
|
48
|
+
if (!prevRect) return;
|
|
49
|
+
const deltaX = prevRect.left - newRect.left;
|
|
50
|
+
const deltaY = prevRect.top - newRect.top;
|
|
51
|
+
const deltaWidth = prevRect.width - newRect.width;
|
|
52
|
+
const deltaHeight = prevRect.height - newRect.height;
|
|
53
|
+
const isSignificant = Math.abs(deltaX) >= minDeltaPx || Math.abs(deltaY) >= minDeltaPx || Math.abs(deltaWidth) >= minDeltaPx || Math.abs(deltaHeight) >= minDeltaPx;
|
|
54
|
+
deltas.set(id, {
|
|
55
|
+
id,
|
|
56
|
+
deltaX,
|
|
57
|
+
deltaY,
|
|
58
|
+
deltaWidth,
|
|
59
|
+
deltaHeight,
|
|
60
|
+
isSignificant
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
return deltas;
|
|
64
|
+
}, [minDeltaPx]),
|
|
65
|
+
getLastCapture: useCallback(() => {
|
|
66
|
+
return new Map(lastCaptureRef.current);
|
|
67
|
+
}, []),
|
|
68
|
+
clear: useCallback(() => {
|
|
69
|
+
lastCaptureRef.current.clear();
|
|
70
|
+
}, [])
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
export { usePositionCapture };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WAAPI Animation Primitives
|
|
3
|
+
*
|
|
4
|
+
* Lightweight, performant React animation components built on the Web Animations API (WAAPI).
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* import { SlidingNumber, SlidingText, Reorder, Morph } from '@mks2508/mks-ui/react/primitives/waapi';
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export { TIMING, TRANSFORMS, EFFECTS, EASINGS, RESPONSIVE_CONFIGS, ANIMATION_CONFIGS, ANIMATION_DEFAULTS, PRESETS, getResponsiveDuration, getResponsiveStagger, } from './core';
|
|
12
|
+
export { useElementRegistry } from './core';
|
|
13
|
+
export { usePositionCapture } from './core';
|
|
14
|
+
export { useFLIPAnimation } from './core';
|
|
15
|
+
export { useAnimationOrchestrator } from './core';
|
|
16
|
+
export type { IFLIPDelta, IAnimationTiming, IPositionRect, IElementRegistryAPI, IElementRegistryCallbacks, IPositionCaptureAPI, IPositionCaptureOptions, IFLIPAnimationAPI, IFLIPAnimationOptions, IExitOptions, IEnterOptions, IAnimationOrchestratorConfig, IAnimationOrchestratorAPI, IOrchestratorState, IAnimationEvent, FLIPBehavior, ExitPositionStrategy, AnimationPhase, } from './core';
|
|
17
|
+
export { SlidingNumber } from './SlidingNumber';
|
|
18
|
+
export type { ISlidingNumberProps, IFormatOptions, } from './SlidingNumber/SlidingNumber.types';
|
|
19
|
+
export { SlidingText } from './SlidingText';
|
|
20
|
+
export type { ISlidingTextProps } from './SlidingText/SlidingText.types';
|
|
21
|
+
export { Reorder } from './Reorder';
|
|
22
|
+
export type { IReorderProps, ReorderLayout, DurationConfig, StaggerConfig, IUseReorderReturn, IUseReorderConfig, IReorderItemState, IReorderContextValue, IUseReorderPresenceConfig, IUseReorderPresenceReturn, } from './Reorder/Reorder.types';
|
|
23
|
+
export { useReorder } from './Reorder/useReorder';
|
|
24
|
+
export { useReorderPresence } from './Reorder/useReorderPresence';
|
|
25
|
+
export { calculateSeparatorCoordination, shouldShowSeparator } from './Reorder/utils/separatorCoordination';
|
|
26
|
+
export { Morph } from './Morph';
|
|
27
|
+
export type { IMorphProps, IMorphContextValue, IUseMorphConfig, IUseMorphReturn, MorphTechnique, IFLIPClipPathOptions, IFLIPClipPathAPI, ICSSGridMorphOptions, ICSSGridMorphAPI, IViewTransitionsOptions, IViewTransitionsAPI, } from './Morph/Morph.types';
|
|
28
|
+
export { useMorph } from './Morph/useMorph';
|
|
29
|
+
export { useMorphContext } from './Morph/MorphContext';
|
|
30
|
+
export { useFLIPClipPath } from './Morph/techniques/useFLIPClipPath';
|
|
31
|
+
export { useCSSGridMorph } from './Morph/techniques/useCSSGridMorph';
|
|
32
|
+
export { useViewTransitions } from './Morph/techniques/useViewTransitions';
|
|
33
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/react-ui/primitives/waapi/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAOH,OAAO,EACL,MAAM,EACN,UAAU,EACV,OAAO,EACP,OAAO,EACP,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,OAAO,EACP,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,QAAQ,CAAC;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,QAAQ,CAAC;AAGlD,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,yBAAyB,EACzB,mBAAmB,EACnB,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,4BAA4B,EAC5B,yBAAyB,EACzB,kBAAkB,EAClB,eAAe,EACf,YAAY,EACZ,oBAAoB,EACpB,cAAc,GACf,MAAM,QAAQ,CAAC;AAKhB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,YAAY,EACV,mBAAmB,EACnB,cAAc,GACf,MAAM,qCAAqC,CAAC;AAK7C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAKzE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,YAAY,EACV,aAAa,EACb,aAAa,EACb,cAAc,EACd,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,8BAA8B,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAK5G,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC"}
|