@flightdev/transitions 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +86 -0
- package/dist/adapters/react/index.d.ts +210 -0
- package/dist/adapters/react/index.js +261 -0
- package/dist/adapters/react/index.js.map +1 -0
- package/dist/adapters/solid/index.d.ts +5 -0
- package/dist/adapters/solid/index.js +9 -0
- package/dist/adapters/solid/index.js.map +1 -0
- package/dist/adapters/svelte/index.d.ts +5 -0
- package/dist/adapters/svelte/index.js +9 -0
- package/dist/adapters/svelte/index.js.map +1 -0
- package/dist/adapters/vue/index.d.ts +5 -0
- package/dist/adapters/vue/index.js +9 -0
- package/dist/adapters/vue/index.js.map +1 -0
- package/dist/chunk-DZC3OLDU.js +121 -0
- package/dist/chunk-DZC3OLDU.js.map +1 -0
- package/dist/chunk-GEYKSLH6.js +190 -0
- package/dist/chunk-GEYKSLH6.js.map +1 -0
- package/dist/chunk-N7U5LD4Z.js +70 -0
- package/dist/chunk-N7U5LD4Z.js.map +1 -0
- package/dist/chunk-OV3U5STU.js +252 -0
- package/dist/chunk-OV3U5STU.js.map +1 -0
- package/dist/chunk-QSB65CTV.js +438 -0
- package/dist/chunk-QSB65CTV.js.map +1 -0
- package/dist/chunk-SPUGO5I5.js +138 -0
- package/dist/chunk-SPUGO5I5.js.map +1 -0
- package/dist/chunk-W7HSR35B.js +3 -0
- package/dist/chunk-W7HSR35B.js.map +1 -0
- package/dist/chunk-X2A7XWYR.js +442 -0
- package/dist/chunk-X2A7XWYR.js.map +1 -0
- package/dist/chunk-XLVYHPII.js +3 -0
- package/dist/chunk-XLVYHPII.js.map +1 -0
- package/dist/chunk-ZI6E7GNQ.js +136 -0
- package/dist/chunk-ZI6E7GNQ.js.map +1 -0
- package/dist/component/index.d.ts +87 -0
- package/dist/component/index.js +5 -0
- package/dist/component/index.js.map +1 -0
- package/dist/config/index.d.ts +93 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/index.d.ts +107 -0
- package/dist/core/index.js +5 -0
- package/dist/core/index.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/index.d.ts +112 -0
- package/dist/layout/index.js +4 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/page/index.d.ts +87 -0
- package/dist/page/index.js +7 -0
- package/dist/page/index.js.map +1 -0
- package/dist/presets/index.d.ts +192 -0
- package/dist/presets/index.js +3 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/router/index.d.ts +104 -0
- package/dist/router/index.js +7 -0
- package/dist/router/index.js.map +1 -0
- package/dist/transition-manager-QWm4OSFw.d.ts +62 -0
- package/dist/types-BA4L37s4.d.ts +272 -0
- package/dist/view-transition-LSN_PSbm.d.ts +97 -0
- package/package.json +148 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// src/core/animation-engine.ts
|
|
2
|
+
var DEFAULT_DURATION = 200;
|
|
3
|
+
var DEFAULT_EASING = "cubic-bezier(0.4, 0, 0.2, 1)";
|
|
4
|
+
var REDUCED_MOTION_DURATION = 1;
|
|
5
|
+
function animate(element, keyframe, options = {}) {
|
|
6
|
+
const {
|
|
7
|
+
duration = DEFAULT_DURATION,
|
|
8
|
+
easing = DEFAULT_EASING,
|
|
9
|
+
delay = 0,
|
|
10
|
+
fill = "both",
|
|
11
|
+
onStart,
|
|
12
|
+
onComplete,
|
|
13
|
+
onCancel
|
|
14
|
+
} = options;
|
|
15
|
+
const keyframes = [
|
|
16
|
+
convertToKeyframe(keyframe.from),
|
|
17
|
+
convertToKeyframe(keyframe.to)
|
|
18
|
+
];
|
|
19
|
+
const animation = element.animate(keyframes, {
|
|
20
|
+
duration,
|
|
21
|
+
easing,
|
|
22
|
+
delay,
|
|
23
|
+
fill
|
|
24
|
+
});
|
|
25
|
+
if (onStart) {
|
|
26
|
+
animation.ready.then(onStart);
|
|
27
|
+
}
|
|
28
|
+
const finished = animation.finished.then(() => {
|
|
29
|
+
onComplete?.();
|
|
30
|
+
}).catch((error) => {
|
|
31
|
+
if (error.name === "AbortError") {
|
|
32
|
+
onCancel?.();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
animation,
|
|
37
|
+
finished,
|
|
38
|
+
cancel: () => {
|
|
39
|
+
animation.cancel();
|
|
40
|
+
},
|
|
41
|
+
pause: () => {
|
|
42
|
+
animation.pause();
|
|
43
|
+
},
|
|
44
|
+
resume: () => {
|
|
45
|
+
animation.play();
|
|
46
|
+
},
|
|
47
|
+
reverse: () => {
|
|
48
|
+
animation.reverse();
|
|
49
|
+
},
|
|
50
|
+
seek: (progress) => {
|
|
51
|
+
const time = progress * (duration + delay);
|
|
52
|
+
animation.currentTime = time;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function animateOut(element, transition, options) {
|
|
57
|
+
const { leave } = transition;
|
|
58
|
+
return animateWithKeyframes(element, leave.keyframes, {
|
|
59
|
+
...leave.options,
|
|
60
|
+
...options
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function animateIn(element, transition, options) {
|
|
64
|
+
const { enter } = transition;
|
|
65
|
+
return animateWithKeyframes(element, enter.keyframes, {
|
|
66
|
+
...enter.options,
|
|
67
|
+
...options
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function animateWithKeyframes(element, keyframes, options) {
|
|
71
|
+
const { onStart, onComplete, onCancel, ...animOptions } = options;
|
|
72
|
+
const animation = element.animate(keyframes, animOptions);
|
|
73
|
+
if (onStart) {
|
|
74
|
+
animation.ready.then(onStart);
|
|
75
|
+
}
|
|
76
|
+
const finished = animation.finished.then(() => {
|
|
77
|
+
onComplete?.();
|
|
78
|
+
}).catch((error) => {
|
|
79
|
+
if (error.name === "AbortError") {
|
|
80
|
+
onCancel?.();
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
animation,
|
|
85
|
+
finished,
|
|
86
|
+
cancel: () => animation.cancel(),
|
|
87
|
+
pause: () => animation.pause(),
|
|
88
|
+
resume: () => animation.play(),
|
|
89
|
+
reverse: () => animation.reverse(),
|
|
90
|
+
seek: (progress) => {
|
|
91
|
+
const duration = typeof animOptions.duration === "number" ? animOptions.duration : 0;
|
|
92
|
+
animation.currentTime = progress * duration;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function convertToKeyframe(properties) {
|
|
97
|
+
const keyframe = {};
|
|
98
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
99
|
+
if (value !== void 0) {
|
|
100
|
+
const camelKey = kebabToCamel(key);
|
|
101
|
+
keyframe[camelKey] = value;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return keyframe;
|
|
105
|
+
}
|
|
106
|
+
function kebabToCamel(str) {
|
|
107
|
+
return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
108
|
+
}
|
|
109
|
+
function resolveTransition(input, reducedMotion = false) {
|
|
110
|
+
if (input === false) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const base = typeof input === "string" ? getPresetTransition(input) : normalizeCustomTransition(input);
|
|
114
|
+
if (!base) {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
if (reducedMotion) {
|
|
118
|
+
return applyReducedMotion(base);
|
|
119
|
+
}
|
|
120
|
+
return base;
|
|
121
|
+
}
|
|
122
|
+
function getPresetTransition(name) {
|
|
123
|
+
switch (name) {
|
|
124
|
+
case "none":
|
|
125
|
+
return {
|
|
126
|
+
name: "none",
|
|
127
|
+
leave: {
|
|
128
|
+
keyframes: [{ opacity: 1 }, { opacity: 1 }],
|
|
129
|
+
options: { duration: 0, easing: "linear", fill: "both" }
|
|
130
|
+
},
|
|
131
|
+
enter: {
|
|
132
|
+
keyframes: [{ opacity: 1 }, { opacity: 1 }],
|
|
133
|
+
options: { duration: 0, easing: "linear", fill: "both" }
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
case "fade":
|
|
137
|
+
return {
|
|
138
|
+
name: "fade",
|
|
139
|
+
leave: {
|
|
140
|
+
keyframes: [{ opacity: 1 }, { opacity: 0 }],
|
|
141
|
+
options: { duration: 150, easing: "ease-out", fill: "both" }
|
|
142
|
+
},
|
|
143
|
+
enter: {
|
|
144
|
+
keyframes: [{ opacity: 0 }, { opacity: 1 }],
|
|
145
|
+
options: { duration: 150, easing: "ease-in", fill: "both" }
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
default:
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function normalizeCustomTransition(custom) {
|
|
153
|
+
const name = custom.name || "custom";
|
|
154
|
+
const leaveDuration = typeof custom.duration === "number" ? custom.duration : custom.duration?.leave ?? DEFAULT_DURATION;
|
|
155
|
+
const enterDuration = typeof custom.duration === "number" ? custom.duration : custom.duration?.enter ?? DEFAULT_DURATION;
|
|
156
|
+
const leaveEasing = typeof custom.easing === "string" ? custom.easing : custom.easing?.leave ?? DEFAULT_EASING;
|
|
157
|
+
const enterEasing = typeof custom.easing === "string" ? custom.easing : custom.easing?.enter ?? DEFAULT_EASING;
|
|
158
|
+
const leaveDelay = typeof custom.delay === "number" ? custom.delay : custom.delay?.leave ?? 0;
|
|
159
|
+
const enterDelay = typeof custom.delay === "number" ? custom.delay : custom.delay?.enter ?? 0;
|
|
160
|
+
const fill = custom.fill ?? "both";
|
|
161
|
+
return {
|
|
162
|
+
name,
|
|
163
|
+
leave: {
|
|
164
|
+
keyframes: custom.leave ? [convertToKeyframe(custom.leave.from), convertToKeyframe(custom.leave.to)] : [{ opacity: 1 }, { opacity: 0 }],
|
|
165
|
+
options: {
|
|
166
|
+
duration: leaveDuration,
|
|
167
|
+
easing: leaveEasing,
|
|
168
|
+
delay: leaveDelay,
|
|
169
|
+
fill
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
enter: {
|
|
173
|
+
keyframes: custom.enter ? [convertToKeyframe(custom.enter.from), convertToKeyframe(custom.enter.to)] : [{ opacity: 0 }, { opacity: 1 }],
|
|
174
|
+
options: {
|
|
175
|
+
duration: enterDuration,
|
|
176
|
+
easing: enterEasing,
|
|
177
|
+
delay: enterDelay,
|
|
178
|
+
fill
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function applyReducedMotion(transition) {
|
|
184
|
+
return {
|
|
185
|
+
...transition,
|
|
186
|
+
name: `${transition.name}-reduced`,
|
|
187
|
+
leave: {
|
|
188
|
+
...transition.leave,
|
|
189
|
+
options: {
|
|
190
|
+
...transition.leave.options,
|
|
191
|
+
duration: REDUCED_MOTION_DURATION
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
enter: {
|
|
195
|
+
...transition.enter,
|
|
196
|
+
options: {
|
|
197
|
+
...transition.enter.options,
|
|
198
|
+
duration: REDUCED_MOTION_DURATION
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function prefersReducedMotion() {
|
|
204
|
+
if (typeof window === "undefined") return false;
|
|
205
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
206
|
+
}
|
|
207
|
+
function onReducedMotionChange(callback) {
|
|
208
|
+
if (typeof window === "undefined") {
|
|
209
|
+
return () => {
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
213
|
+
const handler = (event) => {
|
|
214
|
+
callback(event.matches);
|
|
215
|
+
};
|
|
216
|
+
mediaQuery.addEventListener("change", handler);
|
|
217
|
+
return () => {
|
|
218
|
+
mediaQuery.removeEventListener("change", handler);
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function cancelAnimations(element) {
|
|
222
|
+
element.getAnimations().forEach((anim) => anim.cancel());
|
|
223
|
+
}
|
|
224
|
+
async function waitForAnimations(element) {
|
|
225
|
+
const animations = element.getAnimations();
|
|
226
|
+
await Promise.all(animations.map((anim) => anim.finished));
|
|
227
|
+
}
|
|
228
|
+
function flip(element, callback, options = {}) {
|
|
229
|
+
const first = element.getBoundingClientRect();
|
|
230
|
+
callback();
|
|
231
|
+
const last = element.getBoundingClientRect();
|
|
232
|
+
const deltaX = first.left - last.left;
|
|
233
|
+
const deltaY = first.top - last.top;
|
|
234
|
+
const deltaW = first.width / last.width;
|
|
235
|
+
const deltaH = first.height / last.height;
|
|
236
|
+
return animate(element, {
|
|
237
|
+
from: {
|
|
238
|
+
transform: `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`
|
|
239
|
+
},
|
|
240
|
+
to: {
|
|
241
|
+
transform: "translate(0, 0) scale(1, 1)"
|
|
242
|
+
}
|
|
243
|
+
}, {
|
|
244
|
+
duration: options.duration ?? 300,
|
|
245
|
+
easing: options.easing ?? "cubic-bezier(0.2, 0, 0.2, 1)",
|
|
246
|
+
...options
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export { DEFAULT_DURATION, DEFAULT_EASING, REDUCED_MOTION_DURATION, animate, animateIn, animateOut, cancelAnimations, flip, onReducedMotionChange, prefersReducedMotion, resolveTransition, waitForAnimations };
|
|
251
|
+
//# sourceMappingURL=chunk-OV3U5STU.js.map
|
|
252
|
+
//# sourceMappingURL=chunk-OV3U5STU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/animation-engine.ts"],"names":[],"mappings":"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","file":"chunk-OV3U5STU.js","sourcesContent":["/**\r\n * @flightdev/transitions - Animation Engine\r\n * \r\n * Low-level animation primitives using the Web Animations API.\r\n * Provides performant, interruptible animations with proper cleanup.\r\n */\r\n\r\nimport type {\r\n TransitionKeyframe,\r\n CustomTransition,\r\n ResolvedTransition,\r\n TransitionPreset,\r\n FillMode,\r\n} from './types';\r\n\r\n// =============================================================================\r\n// CONSTANTS\r\n// =============================================================================\r\n\r\n/** Default animation duration in milliseconds */\r\nexport const DEFAULT_DURATION = 200;\r\n\r\n/** Default easing function */\r\nexport const DEFAULT_EASING = 'cubic-bezier(0.4, 0, 0.2, 1)';\r\n\r\n/** Reduced motion duration (near-instant) */\r\nexport const REDUCED_MOTION_DURATION = 1;\r\n\r\n// =============================================================================\r\n// ANIMATION ENGINE\r\n// =============================================================================\r\n\r\n/**\r\n * Options for creating an animation\r\n */\r\nexport interface AnimationOptions {\r\n /** Animation duration in milliseconds */\r\n duration?: number;\r\n /** CSS easing function */\r\n easing?: string;\r\n /** Delay before animation starts */\r\n delay?: number;\r\n /** Animation fill mode */\r\n fill?: FillMode;\r\n /** Callback when animation starts */\r\n onStart?: () => void;\r\n /** Callback when animation completes */\r\n onComplete?: () => void;\r\n /** Callback when animation is cancelled */\r\n onCancel?: () => void;\r\n}\r\n\r\n/**\r\n * Result from creating an animation\r\n */\r\nexport interface AnimationHandle {\r\n /** The underlying Animation object */\r\n animation: Animation;\r\n /** Promise that resolves when animation finishes */\r\n finished: Promise<void>;\r\n /** Cancel the animation */\r\n cancel(): void;\r\n /** Pause the animation */\r\n pause(): void;\r\n /** Resume a paused animation */\r\n resume(): void;\r\n /** Reverse the animation direction */\r\n reverse(): void;\r\n /** Set the current time (0-1 normalized) */\r\n seek(progress: number): void;\r\n}\r\n\r\n/**\r\n * Animate an element with keyframes\r\n * \r\n * Uses the Web Animations API for smooth, performant animations.\r\n * \r\n * @example\r\n * ```typescript\r\n * const handle = animate(element, {\r\n * from: { opacity: '1', transform: 'scale(1)' },\r\n * to: { opacity: '0', transform: 'scale(0.95)' }\r\n * }, { duration: 200 });\r\n * \r\n * await handle.finished;\r\n * ```\r\n */\r\nexport function animate(\r\n element: Element,\r\n keyframe: TransitionKeyframe,\r\n options: AnimationOptions = {}\r\n): AnimationHandle {\r\n const {\r\n duration = DEFAULT_DURATION,\r\n easing = DEFAULT_EASING,\r\n delay = 0,\r\n fill = 'both',\r\n onStart,\r\n onComplete,\r\n onCancel,\r\n } = options;\r\n\r\n // Convert TransitionKeyframe to Web Animations API format\r\n const keyframes: Keyframe[] = [\r\n convertToKeyframe(keyframe.from),\r\n convertToKeyframe(keyframe.to),\r\n ];\r\n\r\n // Create the animation\r\n const animation = element.animate(keyframes, {\r\n duration,\r\n easing,\r\n delay,\r\n fill,\r\n });\r\n\r\n // Call onStart when animation begins\r\n if (onStart) {\r\n animation.ready.then(onStart);\r\n }\r\n\r\n // Create finished promise with callbacks\r\n const finished = animation.finished.then(() => {\r\n onComplete?.();\r\n }).catch((error) => {\r\n // Animation was cancelled\r\n if (error.name === 'AbortError') {\r\n onCancel?.();\r\n }\r\n });\r\n\r\n return {\r\n animation,\r\n finished,\r\n cancel: () => {\r\n animation.cancel();\r\n },\r\n pause: () => {\r\n animation.pause();\r\n },\r\n resume: () => {\r\n animation.play();\r\n },\r\n reverse: () => {\r\n animation.reverse();\r\n },\r\n seek: (progress: number) => {\r\n const time = progress * (duration + delay);\r\n animation.currentTime = time;\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Animate an element out (leaving)\r\n */\r\nexport function animateOut(\r\n element: Element,\r\n transition: ResolvedTransition,\r\n options?: Omit<AnimationOptions, 'duration' | 'easing'>\r\n): AnimationHandle {\r\n const { leave } = transition;\r\n\r\n return animateWithKeyframes(element, leave.keyframes, {\r\n ...leave.options,\r\n ...options,\r\n });\r\n}\r\n\r\n/**\r\n * Animate an element in (entering)\r\n */\r\nexport function animateIn(\r\n element: Element,\r\n transition: ResolvedTransition,\r\n options?: Omit<AnimationOptions, 'duration' | 'easing'>\r\n): AnimationHandle {\r\n const { enter } = transition;\r\n\r\n return animateWithKeyframes(element, enter.keyframes, {\r\n ...enter.options,\r\n ...options,\r\n });\r\n}\r\n\r\n/**\r\n * Animate with raw keyframes\r\n */\r\nfunction animateWithKeyframes(\r\n element: Element,\r\n keyframes: Keyframe[],\r\n options: KeyframeAnimationOptions & {\r\n onStart?: () => void;\r\n onComplete?: () => void;\r\n onCancel?: () => void;\r\n }\r\n): AnimationHandle {\r\n const { onStart, onComplete, onCancel, ...animOptions } = options;\r\n\r\n const animation = element.animate(keyframes, animOptions);\r\n\r\n if (onStart) {\r\n animation.ready.then(onStart);\r\n }\r\n\r\n const finished = animation.finished.then(() => {\r\n onComplete?.();\r\n }).catch((error) => {\r\n if (error.name === 'AbortError') {\r\n onCancel?.();\r\n }\r\n });\r\n\r\n return {\r\n animation,\r\n finished,\r\n cancel: () => animation.cancel(),\r\n pause: () => animation.pause(),\r\n resume: () => animation.play(),\r\n reverse: () => animation.reverse(),\r\n seek: (progress: number) => {\r\n const duration = typeof animOptions.duration === 'number'\r\n ? animOptions.duration\r\n : 0;\r\n animation.currentTime = progress * duration;\r\n },\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// KEYFRAME CONVERSION\r\n// =============================================================================\r\n\r\n/**\r\n * Convert CSS property object to Web Animations API Keyframe\r\n */\r\nfunction convertToKeyframe(\r\n properties: Partial<Record<string, string>>\r\n): Keyframe {\r\n const keyframe: Keyframe = {};\r\n\r\n for (const [key, value] of Object.entries(properties)) {\r\n if (value !== undefined) {\r\n // Convert kebab-case to camelCase\r\n const camelKey = kebabToCamel(key);\r\n (keyframe as Record<string, string>)[camelKey] = value;\r\n }\r\n }\r\n\r\n return keyframe;\r\n}\r\n\r\n/**\r\n * Convert kebab-case to camelCase\r\n */\r\nfunction kebabToCamel(str: string): string {\r\n return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\r\n}\r\n\r\n// =============================================================================\r\n// TRANSITION RESOLUTION\r\n// =============================================================================\r\n\r\n/**\r\n * Resolve a preset name or custom transition to a normalized format\r\n */\r\nexport function resolveTransition(\r\n input: TransitionPreset | CustomTransition | false,\r\n reducedMotion: boolean = false\r\n): ResolvedTransition | null {\r\n // Disabled\r\n if (input === false) {\r\n return null;\r\n }\r\n\r\n // Get base transition\r\n const base = typeof input === 'string'\r\n ? getPresetTransition(input)\r\n : normalizeCustomTransition(input);\r\n\r\n if (!base) {\r\n return null;\r\n }\r\n\r\n // Apply reduced motion if needed\r\n if (reducedMotion) {\r\n return applyReducedMotion(base);\r\n }\r\n\r\n return base;\r\n}\r\n\r\n/**\r\n * Get a built-in preset transition by name\r\n * Returns null for unknown presets (they'll be loaded from presets module)\r\n */\r\nfunction getPresetTransition(name: TransitionPreset): ResolvedTransition | null {\r\n // This is a minimal built-in set\r\n // Full presets are in the presets module\r\n switch (name) {\r\n case 'none':\r\n return {\r\n name: 'none',\r\n leave: {\r\n keyframes: [{ opacity: 1 }, { opacity: 1 }],\r\n options: { duration: 0, easing: 'linear', fill: 'both' as FillMode },\r\n },\r\n enter: {\r\n keyframes: [{ opacity: 1 }, { opacity: 1 }],\r\n options: { duration: 0, easing: 'linear', fill: 'both' as FillMode },\r\n },\r\n };\r\n\r\n case 'fade':\r\n return {\r\n name: 'fade',\r\n leave: {\r\n keyframes: [{ opacity: 1 }, { opacity: 0 }],\r\n options: { duration: 150, easing: 'ease-out', fill: 'both' as FillMode },\r\n },\r\n enter: {\r\n keyframes: [{ opacity: 0 }, { opacity: 1 }],\r\n options: { duration: 150, easing: 'ease-in', fill: 'both' as FillMode },\r\n },\r\n };\r\n\r\n default:\r\n // Will be loaded from presets module\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Normalize a custom transition to resolved format\r\n */\r\nfunction normalizeCustomTransition(custom: CustomTransition): ResolvedTransition {\r\n const name = custom.name || 'custom';\r\n\r\n // Parse duration\r\n const leaveDuration = typeof custom.duration === 'number'\r\n ? custom.duration\r\n : custom.duration?.leave ?? DEFAULT_DURATION;\r\n const enterDuration = typeof custom.duration === 'number'\r\n ? custom.duration\r\n : custom.duration?.enter ?? DEFAULT_DURATION;\r\n\r\n // Parse easing\r\n const leaveEasing = typeof custom.easing === 'string'\r\n ? custom.easing\r\n : custom.easing?.leave ?? DEFAULT_EASING;\r\n const enterEasing = typeof custom.easing === 'string'\r\n ? custom.easing\r\n : custom.easing?.enter ?? DEFAULT_EASING;\r\n\r\n // Parse delay\r\n const leaveDelay = typeof custom.delay === 'number'\r\n ? custom.delay\r\n : custom.delay?.leave ?? 0;\r\n const enterDelay = typeof custom.delay === 'number'\r\n ? custom.delay\r\n : custom.delay?.enter ?? 0;\r\n\r\n const fill = custom.fill ?? 'both';\r\n\r\n return {\r\n name,\r\n leave: {\r\n keyframes: custom.leave\r\n ? [convertToKeyframe(custom.leave.from), convertToKeyframe(custom.leave.to)]\r\n : [{ opacity: 1 }, { opacity: 0 }],\r\n options: {\r\n duration: leaveDuration,\r\n easing: leaveEasing,\r\n delay: leaveDelay,\r\n fill,\r\n },\r\n },\r\n enter: {\r\n keyframes: custom.enter\r\n ? [convertToKeyframe(custom.enter.from), convertToKeyframe(custom.enter.to)]\r\n : [{ opacity: 0 }, { opacity: 1 }],\r\n options: {\r\n duration: enterDuration,\r\n easing: enterEasing,\r\n delay: enterDelay,\r\n fill,\r\n },\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Apply reduced motion to a transition (near-instant)\r\n */\r\nfunction applyReducedMotion(transition: ResolvedTransition): ResolvedTransition {\r\n return {\r\n ...transition,\r\n name: `${transition.name}-reduced`,\r\n leave: {\r\n ...transition.leave,\r\n options: {\r\n ...transition.leave.options,\r\n duration: REDUCED_MOTION_DURATION,\r\n },\r\n },\r\n enter: {\r\n ...transition.enter,\r\n options: {\r\n ...transition.enter.options,\r\n duration: REDUCED_MOTION_DURATION,\r\n },\r\n },\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// REDUCED MOTION DETECTION\r\n// =============================================================================\r\n\r\n/**\r\n * Check if user prefers reduced motion\r\n */\r\nexport function prefersReducedMotion(): boolean {\r\n if (typeof window === 'undefined') return false;\r\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\r\n}\r\n\r\n/**\r\n * Subscribe to reduced motion preference changes\r\n */\r\nexport function onReducedMotionChange(\r\n callback: (prefersReduced: boolean) => void\r\n): () => void {\r\n if (typeof window === 'undefined') {\r\n return () => { };\r\n }\r\n\r\n const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');\r\n\r\n const handler = (event: MediaQueryListEvent) => {\r\n callback(event.matches);\r\n };\r\n\r\n mediaQuery.addEventListener('change', handler);\r\n\r\n return () => {\r\n mediaQuery.removeEventListener('change', handler);\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// UTILITY FUNCTIONS\r\n// =============================================================================\r\n\r\n/**\r\n * Cancel all running animations on an element\r\n */\r\nexport function cancelAnimations(element: Element): void {\r\n element.getAnimations().forEach((anim) => anim.cancel());\r\n}\r\n\r\n/**\r\n * Wait for all animations on an element to complete\r\n */\r\nexport async function waitForAnimations(element: Element): Promise<void> {\r\n const animations = element.getAnimations();\r\n await Promise.all(animations.map((anim) => anim.finished));\r\n}\r\n\r\n/**\r\n * FLIP animation helper (First, Last, Invert, Play)\r\n * Useful for shared element transitions\r\n */\r\nexport function flip(\r\n element: HTMLElement,\r\n callback: () => void | Promise<void>,\r\n options: AnimationOptions = {}\r\n): AnimationHandle {\r\n // FIRST: Get initial position\r\n const first = element.getBoundingClientRect();\r\n\r\n // Execute the callback (DOM changes)\r\n const result = callback();\r\n\r\n // LAST: Get final position\r\n const last = element.getBoundingClientRect();\r\n\r\n // INVERT: Calculate the difference\r\n const deltaX = first.left - last.left;\r\n const deltaY = first.top - last.top;\r\n const deltaW = first.width / last.width;\r\n const deltaH = first.height / last.height;\r\n\r\n // PLAY: Animate from inverted position to final\r\n return animate(element, {\r\n from: {\r\n transform: `translate(${deltaX}px, ${deltaY}px) scale(${deltaW}, ${deltaH})`,\r\n },\r\n to: {\r\n transform: 'translate(0, 0) scale(1, 1)',\r\n },\r\n }, {\r\n duration: options.duration ?? 300,\r\n easing: options.easing ?? 'cubic-bezier(0.2, 0, 0.2, 1)',\r\n ...options,\r\n });\r\n}\r\n"]}
|