@drivexstudio/animations 1.0.0 → 1.0.2
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/README.md +24 -0
- package/dist/index.cjs +1918 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +1862 -0
- package/dist/index.js.map +1 -0
- package/package.json +4 -3
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1918 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// packages/index.js
|
|
31
|
+
var packages_exports = {};
|
|
32
|
+
__export(packages_exports, {
|
|
33
|
+
AnimatedButton: () => AnimatedButton,
|
|
34
|
+
AnimatedHeadline: () => AnimatedHeadline_default,
|
|
35
|
+
AnimatedLink: () => AnimatedLink_default,
|
|
36
|
+
AnimatedProse: () => AnimatedProse,
|
|
37
|
+
AnimatedProseContext: () => AnimatedProseContext,
|
|
38
|
+
AnimatedSubtext: () => AnimatedSubtext_default,
|
|
39
|
+
AnimatedText: () => AnimatedText,
|
|
40
|
+
DEFAULT_CHARS: () => DEFAULT_CHARS,
|
|
41
|
+
LenisProvider: () => Lenis,
|
|
42
|
+
PageEnterProvider: () => PageEnterProvider,
|
|
43
|
+
PageTransitionProvider: () => PageTransitionProvider,
|
|
44
|
+
Preloader: () => Preloader,
|
|
45
|
+
PreloaderProvider: () => PreloaderProvider,
|
|
46
|
+
ScrambleGroup: () => ScrambleGroup,
|
|
47
|
+
ScrambleText: () => ScrambleText,
|
|
48
|
+
ScrambleTextPlugin: () => import_ScrambleTextPlugin.ScrambleTextPlugin,
|
|
49
|
+
ScrollAnimatedHeadline: () => ScrollAnimatedHeadline,
|
|
50
|
+
ScrollTrigger: () => import_ScrollTrigger.ScrollTrigger,
|
|
51
|
+
SplitText: () => import_SplitText.SplitText,
|
|
52
|
+
cva: () => import_class_variance_authority2.cva,
|
|
53
|
+
cx: () => cx,
|
|
54
|
+
easingDefinitionToFunction: () => easingDefinitionToFunction,
|
|
55
|
+
getCssScrollLocked: () => getCssScrollLocked,
|
|
56
|
+
getLenis: () => getLenis,
|
|
57
|
+
gsap: () => import_gsap.default,
|
|
58
|
+
scrollToTop: () => scrollToTop,
|
|
59
|
+
setCssScrollLocked: () => setCssScrollLocked,
|
|
60
|
+
stagger: () => stagger,
|
|
61
|
+
useAsciiDelay: () => useAsciiDelay,
|
|
62
|
+
useDualLayerScramble: () => useDualLayerScramble,
|
|
63
|
+
useGSAP: () => import_react.useGSAP,
|
|
64
|
+
useIdleGSAP: () => useIdleGSAP,
|
|
65
|
+
useLenis: () => import_react3.useLenis,
|
|
66
|
+
usePageEnter: () => usePageEnter,
|
|
67
|
+
usePageEnterContext: () => usePageEnterContext,
|
|
68
|
+
usePageTransition: () => usePageTransition,
|
|
69
|
+
usePageTransitionContext: () => usePageTransitionContext,
|
|
70
|
+
usePreloader: () => usePreloader,
|
|
71
|
+
useScrambleGroup: () => useScrambleGroup
|
|
72
|
+
});
|
|
73
|
+
module.exports = __toCommonJS(packages_exports);
|
|
74
|
+
|
|
75
|
+
// packages/animations/ScrambleText.jsx
|
|
76
|
+
var import_react9 = __toESM(require("react"), 1);
|
|
77
|
+
|
|
78
|
+
// libs/vendor.js
|
|
79
|
+
var import_gsap = __toESM(require("gsap"), 1);
|
|
80
|
+
var import_react = require("@gsap/react");
|
|
81
|
+
var import_ScrollTrigger = require("gsap/ScrollTrigger");
|
|
82
|
+
var import_Flip = require("gsap/Flip");
|
|
83
|
+
var import_SplitText = require("gsap/SplitText");
|
|
84
|
+
var import_ScrambleTextPlugin = require("gsap/ScrambleTextPlugin");
|
|
85
|
+
var import_InertiaPlugin = require("gsap/InertiaPlugin");
|
|
86
|
+
var import_Draggable = require("gsap/Draggable");
|
|
87
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
88
|
+
var import_class_variance_authority2 = require("class-variance-authority");
|
|
89
|
+
import_gsap.default.registerPlugin(
|
|
90
|
+
import_ScrollTrigger.ScrollTrigger,
|
|
91
|
+
import_ScrambleTextPlugin.ScrambleTextPlugin,
|
|
92
|
+
import_SplitText.SplitText,
|
|
93
|
+
import_Flip.Flip,
|
|
94
|
+
import_Draggable.Draggable,
|
|
95
|
+
import_InertiaPlugin.InertiaPlugin
|
|
96
|
+
);
|
|
97
|
+
var cx = import_class_variance_authority.cx;
|
|
98
|
+
|
|
99
|
+
// packages/animations/ScrambleGroup.jsx
|
|
100
|
+
var import_react8 = __toESM(require("react"), 1);
|
|
101
|
+
|
|
102
|
+
// libs/hooks/useIdleGSAP.js
|
|
103
|
+
var import_react6 = require("react");
|
|
104
|
+
var import_react7 = require("@gsap/react");
|
|
105
|
+
|
|
106
|
+
// libs/hooks/usePageTransition.js
|
|
107
|
+
var import_react5 = require("react");
|
|
108
|
+
|
|
109
|
+
// packages/providers/PageTransitionProvider.jsx
|
|
110
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
111
|
+
|
|
112
|
+
// packages/providers/LenisProvider.jsx
|
|
113
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
114
|
+
var import_react3 = require("lenis/react");
|
|
115
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
116
|
+
var globalLenisInstance = null;
|
|
117
|
+
var isCssScrollLocked = false;
|
|
118
|
+
function getLenis() {
|
|
119
|
+
return globalLenisInstance;
|
|
120
|
+
}
|
|
121
|
+
function setCssScrollLocked(isLocked) {
|
|
122
|
+
if (isLocked !== isCssScrollLocked) {
|
|
123
|
+
isCssScrollLocked = isLocked;
|
|
124
|
+
if (isLocked) {
|
|
125
|
+
document.documentElement.classList.add("scroll-locked");
|
|
126
|
+
} else {
|
|
127
|
+
document.documentElement.classList.remove("scroll-locked");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function getCssScrollLocked() {
|
|
132
|
+
return isCssScrollLocked;
|
|
133
|
+
}
|
|
134
|
+
function scrollToTop(immediate = true) {
|
|
135
|
+
const lenis = globalLenisInstance;
|
|
136
|
+
if (lenis) {
|
|
137
|
+
lenis.scrollTo(0, { immediate });
|
|
138
|
+
} else {
|
|
139
|
+
window.scrollTo(0, 0);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function LenisTracker() {
|
|
143
|
+
const lenis = (0, import_react3.useLenis)();
|
|
144
|
+
(0, import_react2.useEffect)(() => {
|
|
145
|
+
globalLenisInstance = lenis ?? null;
|
|
146
|
+
return () => {
|
|
147
|
+
globalLenisInstance = null;
|
|
148
|
+
};
|
|
149
|
+
}, [lenis]);
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
function customEasing(t) {
|
|
153
|
+
return t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2;
|
|
154
|
+
}
|
|
155
|
+
function Lenis(props) {
|
|
156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
157
|
+
import_react3.ReactLenis,
|
|
158
|
+
{
|
|
159
|
+
root: true,
|
|
160
|
+
options: {
|
|
161
|
+
anchors: {
|
|
162
|
+
duration: 1.2,
|
|
163
|
+
easing: customEasing
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
...props,
|
|
167
|
+
children: [
|
|
168
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(LenisTracker, {}),
|
|
169
|
+
props.children
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// packages/providers/PageTransitionProvider.jsx
|
|
176
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
177
|
+
var PageTransitionContext = (0, import_react4.createContext)(null);
|
|
178
|
+
var scrollTriggerModulePromise = null;
|
|
179
|
+
function getScrollTriggerModule() {
|
|
180
|
+
if (!scrollTriggerModulePromise) {
|
|
181
|
+
scrollTriggerModulePromise = import("gsap/ScrollTrigger");
|
|
182
|
+
}
|
|
183
|
+
return scrollTriggerModulePromise;
|
|
184
|
+
}
|
|
185
|
+
function clearScrollMemory() {
|
|
186
|
+
const modulePromise = getScrollTriggerModule();
|
|
187
|
+
if (modulePromise) {
|
|
188
|
+
modulePromise.then(({ ScrollTrigger: ScrollTrigger2 }) => {
|
|
189
|
+
ScrollTrigger2.clearScrollMemory();
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function refreshScrollTrigger() {
|
|
194
|
+
const modulePromise = getScrollTriggerModule();
|
|
195
|
+
if (modulePromise) {
|
|
196
|
+
modulePromise.then(({ ScrollTrigger: ScrollTrigger2 }) => {
|
|
197
|
+
ScrollTrigger2.refresh(true);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
function PageTransitionProvider({ children }) {
|
|
202
|
+
const [phase, setPhase] = (0, import_react4.useState)("idle");
|
|
203
|
+
const [isPending, startTransitionReact] = (0, import_react4.useTransition)();
|
|
204
|
+
const timerRef = (0, import_react4.useRef)(null);
|
|
205
|
+
const pendingCallbackRef = (0, import_react4.useRef)(null);
|
|
206
|
+
const startTimeRef = (0, import_react4.useRef)(0);
|
|
207
|
+
const clearTimer = (0, import_react4.useCallback)(() => {
|
|
208
|
+
if (timerRef.current) {
|
|
209
|
+
clearTimeout(timerRef.current);
|
|
210
|
+
timerRef.current = null;
|
|
211
|
+
}
|
|
212
|
+
}, []);
|
|
213
|
+
const handlePopState = (0, import_react4.useCallback)(() => {
|
|
214
|
+
clearTimer();
|
|
215
|
+
if (!window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
216
|
+
startTimeRef.current = 0;
|
|
217
|
+
pendingCallbackRef.current = null;
|
|
218
|
+
setPhase("holding");
|
|
219
|
+
clearScrollMemory();
|
|
220
|
+
timerRef.current = window.setTimeout(() => {
|
|
221
|
+
setPhase("exiting");
|
|
222
|
+
timerRef.current = window.setTimeout(() => {
|
|
223
|
+
setPhase("idle");
|
|
224
|
+
refreshScrollTrigger();
|
|
225
|
+
}, 1200);
|
|
226
|
+
}, 100);
|
|
227
|
+
}
|
|
228
|
+
}, [clearTimer]);
|
|
229
|
+
const startTransition = (0, import_react4.useCallback)((callback) => {
|
|
230
|
+
clearTimer();
|
|
231
|
+
pendingCallbackRef.current = callback;
|
|
232
|
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
233
|
+
callback();
|
|
234
|
+
} else {
|
|
235
|
+
setPhase("entering");
|
|
236
|
+
timerRef.current = window.setTimeout(() => {
|
|
237
|
+
startTimeRef.current = Date.now();
|
|
238
|
+
setPhase("holding");
|
|
239
|
+
clearScrollMemory();
|
|
240
|
+
scrollToTop();
|
|
241
|
+
startTransitionReact(() => {
|
|
242
|
+
var _a;
|
|
243
|
+
(_a = pendingCallbackRef.current) == null ? void 0 : _a.call(pendingCallbackRef);
|
|
244
|
+
});
|
|
245
|
+
}, 1300);
|
|
246
|
+
}
|
|
247
|
+
}, [clearTimer, startTransitionReact]);
|
|
248
|
+
(0, import_react4.useEffect)(() => {
|
|
249
|
+
if (phase === "holding" && !isPending && startTimeRef.current > 0) {
|
|
250
|
+
const elapsed = Date.now() - startTimeRef.current;
|
|
251
|
+
const remainingDelay = Math.max(0, 100 - elapsed);
|
|
252
|
+
timerRef.current = window.setTimeout(() => {
|
|
253
|
+
setPhase("exiting");
|
|
254
|
+
startTimeRef.current = 0;
|
|
255
|
+
timerRef.current = window.setTimeout(() => {
|
|
256
|
+
setPhase("idle");
|
|
257
|
+
refreshScrollTrigger();
|
|
258
|
+
}, 1200);
|
|
259
|
+
}, remainingDelay);
|
|
260
|
+
}
|
|
261
|
+
}, [phase, isPending]);
|
|
262
|
+
(0, import_react4.useEffect)(() => {
|
|
263
|
+
const onPopState = () => {
|
|
264
|
+
handlePopState();
|
|
265
|
+
};
|
|
266
|
+
window.addEventListener("popstate", onPopState);
|
|
267
|
+
return () => {
|
|
268
|
+
window.removeEventListener("popstate", onPopState);
|
|
269
|
+
};
|
|
270
|
+
}, [handlePopState]);
|
|
271
|
+
(0, import_react4.useEffect)(() => {
|
|
272
|
+
return () => {
|
|
273
|
+
clearTimer();
|
|
274
|
+
};
|
|
275
|
+
}, [clearTimer]);
|
|
276
|
+
const contextValue = (0, import_react4.useMemo)(() => ({
|
|
277
|
+
phase,
|
|
278
|
+
startTransition,
|
|
279
|
+
isPending
|
|
280
|
+
}), [phase, startTransition, isPending]);
|
|
281
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PageTransitionContext.Provider, { value: contextValue, children });
|
|
282
|
+
}
|
|
283
|
+
var defaultContextValue = {
|
|
284
|
+
phase: "idle",
|
|
285
|
+
startTransition: (t) => t(),
|
|
286
|
+
isPending: false
|
|
287
|
+
};
|
|
288
|
+
function usePageTransitionContext() {
|
|
289
|
+
return (0, import_react4.useContext)(PageTransitionContext) ?? defaultContextValue;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// libs/hooks/usePageTransition.js
|
|
293
|
+
function usePageTransition() {
|
|
294
|
+
const {
|
|
295
|
+
startTransition,
|
|
296
|
+
phase,
|
|
297
|
+
isPending
|
|
298
|
+
} = usePageTransitionContext();
|
|
299
|
+
const isTransitioning = phase !== "idle";
|
|
300
|
+
const transitionState = (0, import_react5.useMemo)(() => ({
|
|
301
|
+
startTransition,
|
|
302
|
+
isTransitioning,
|
|
303
|
+
phase,
|
|
304
|
+
isPending
|
|
305
|
+
}), [isPending, phase, startTransition, isTransitioning]);
|
|
306
|
+
return transitionState;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// libs/hooks/useIdleGSAP.js
|
|
310
|
+
function useIdleGSAP(callback, config) {
|
|
311
|
+
const { phase } = usePageTransition();
|
|
312
|
+
const [isIdle, setIsIdle] = (0, import_react6.useState)(phase === "idle");
|
|
313
|
+
(0, import_react6.useEffect)(() => {
|
|
314
|
+
if (phase === "idle") {
|
|
315
|
+
setIsIdle(true);
|
|
316
|
+
} else if (phase === "holding") {
|
|
317
|
+
setIsIdle(false);
|
|
318
|
+
}
|
|
319
|
+
}, [phase]);
|
|
320
|
+
const wrappedCallback = (0, import_react6.useCallback)((context, contextSafe) => {
|
|
321
|
+
if (isIdle) {
|
|
322
|
+
return callback(context, contextSafe);
|
|
323
|
+
}
|
|
324
|
+
}, [callback, isIdle]);
|
|
325
|
+
const gsapConfig = (0, import_react6.useMemo)(() => {
|
|
326
|
+
const configDependencies = (config == null ? void 0 : config.dependencies) ?? [];
|
|
327
|
+
const combinedDependencies = [...configDependencies, isIdle];
|
|
328
|
+
return {
|
|
329
|
+
...config,
|
|
330
|
+
dependencies: combinedDependencies
|
|
331
|
+
};
|
|
332
|
+
}, [config, isIdle]);
|
|
333
|
+
return (0, import_react7.useGSAP)(wrappedCallback, gsapConfig);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// packages/animations/ScrambleGroup.jsx
|
|
337
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
338
|
+
var ScrambleContext = (0, import_react8.createContext)(null);
|
|
339
|
+
function ScrambleGroup({
|
|
340
|
+
children,
|
|
341
|
+
stagger: stagger2 = 0.1,
|
|
342
|
+
start = "top 80%",
|
|
343
|
+
markers = false,
|
|
344
|
+
manual = false,
|
|
345
|
+
className
|
|
346
|
+
}) {
|
|
347
|
+
const childrenMapRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
|
|
348
|
+
const [hasTriggered, setHasTriggered] = (0, import_react8.useState)(false);
|
|
349
|
+
const isTriggering = (0, import_react8.useRef)(false);
|
|
350
|
+
const scrollTriggerRef = (0, import_react8.useRef)(null);
|
|
351
|
+
const containerRef = (0, import_react8.useRef)(null);
|
|
352
|
+
const register = (0, import_react8.useCallback)((id, callback) => {
|
|
353
|
+
childrenMapRef.current.set(id, callback);
|
|
354
|
+
}, []);
|
|
355
|
+
const unregister = (0, import_react8.useCallback)((id) => {
|
|
356
|
+
childrenMapRef.current.delete(id);
|
|
357
|
+
}, []);
|
|
358
|
+
const triggerAll = (0, import_react8.useCallback)((customStagger) => {
|
|
359
|
+
if (isTriggering.current) return;
|
|
360
|
+
isTriggering.current = true;
|
|
361
|
+
const callbacks = Array.from(childrenMapRef.current.values());
|
|
362
|
+
const staggerValue = customStagger ?? stagger2;
|
|
363
|
+
callbacks.forEach((callbackFn, index) => {
|
|
364
|
+
import_gsap.default.delayedCall(index * staggerValue, () => {
|
|
365
|
+
callbackFn();
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
setHasTriggered(true);
|
|
369
|
+
}, [stagger2]);
|
|
370
|
+
const setupScrollTrigger = (0, import_react8.useCallback)(() => {
|
|
371
|
+
if (manual || !containerRef.current) return;
|
|
372
|
+
isTriggering.current = false;
|
|
373
|
+
const tween = import_gsap.default.to(containerRef.current, {
|
|
374
|
+
scrollTrigger: {
|
|
375
|
+
trigger: containerRef.current,
|
|
376
|
+
start,
|
|
377
|
+
markers,
|
|
378
|
+
toggleActions: "play none none none"
|
|
379
|
+
},
|
|
380
|
+
onStart: () => {
|
|
381
|
+
triggerAll();
|
|
382
|
+
},
|
|
383
|
+
duration: 1e-3
|
|
384
|
+
});
|
|
385
|
+
scrollTriggerRef.current = tween.scrollTrigger ?? null;
|
|
386
|
+
return () => {
|
|
387
|
+
var _a;
|
|
388
|
+
tween.kill();
|
|
389
|
+
(_a = scrollTriggerRef.current) == null ? void 0 : _a.kill();
|
|
390
|
+
};
|
|
391
|
+
}, [manual, start, markers, triggerAll]);
|
|
392
|
+
useIdleGSAP(setupScrollTrigger, {
|
|
393
|
+
dependencies: [manual, start, markers, triggerAll]
|
|
394
|
+
});
|
|
395
|
+
const contextValue = (0, import_react8.useMemo)(() => ({
|
|
396
|
+
register,
|
|
397
|
+
unregister,
|
|
398
|
+
triggerAll,
|
|
399
|
+
hasTriggered
|
|
400
|
+
}), [register, unregister, triggerAll, hasTriggered]);
|
|
401
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ScrambleContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { ref: containerRef, className, children }) });
|
|
402
|
+
}
|
|
403
|
+
function useScrambleGroup() {
|
|
404
|
+
return (0, import_react8.useContext)(ScrambleContext);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// libs/constants/chars.js
|
|
408
|
+
var DEFAULT_CHARS = " .'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$";
|
|
409
|
+
|
|
410
|
+
// packages/animations/ScrambleText.jsx
|
|
411
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
412
|
+
function ScrambleText({
|
|
413
|
+
children,
|
|
414
|
+
className,
|
|
415
|
+
duration = 0.6,
|
|
416
|
+
chars = DEFAULT_CHARS,
|
|
417
|
+
dualLayer = true,
|
|
418
|
+
triggerOnHover = false,
|
|
419
|
+
revealMode = false,
|
|
420
|
+
theme = "dark",
|
|
421
|
+
firstColorClass,
|
|
422
|
+
secondColorClass,
|
|
423
|
+
onComplete,
|
|
424
|
+
onReady,
|
|
425
|
+
multiLine = false
|
|
426
|
+
}) {
|
|
427
|
+
const containerRef = (0, import_react9.useRef)(null);
|
|
428
|
+
const textElementRef = (0, import_react9.useRef)(null);
|
|
429
|
+
const timelineRef = (0, import_react9.useRef)(null);
|
|
430
|
+
const internalTextRef = (0, import_react9.useRef)("");
|
|
431
|
+
const isCompleteRef = (0, import_react9.useRef)(false);
|
|
432
|
+
const instanceIdRef = (0, import_react9.useRef)(`scramble-${Math.random().toString(36).slice(2, 9)}`);
|
|
433
|
+
const themeColors = theme === "brand" ? { firstColorClass: "scramble-white", secondColorClass: "scramble-foreground" } : { firstColorClass: "scramble-brand", secondColorClass: "scramble-foreground" };
|
|
434
|
+
const color1 = firstColorClass ?? themeColors.firstColorClass;
|
|
435
|
+
const color2 = secondColorClass ?? themeColors.secondColorClass;
|
|
436
|
+
const scrambleGroup = useScrambleGroup();
|
|
437
|
+
let childText;
|
|
438
|
+
if (typeof children === "string") {
|
|
439
|
+
childText = children;
|
|
440
|
+
} else if (typeof children === "number") {
|
|
441
|
+
childText = String(children);
|
|
442
|
+
} else {
|
|
443
|
+
childText = "";
|
|
444
|
+
}
|
|
445
|
+
(0, import_react9.useEffect)(() => {
|
|
446
|
+
internalTextRef.current = childText;
|
|
447
|
+
}, [childText]);
|
|
448
|
+
const killTimeline = () => {
|
|
449
|
+
if (timelineRef.current) {
|
|
450
|
+
timelineRef.current.kill();
|
|
451
|
+
timelineRef.current = null;
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
const triggerAnimation = () => {
|
|
455
|
+
if (!textElementRef.current) return null;
|
|
456
|
+
const targetEl = textElementRef.current;
|
|
457
|
+
const textToScramble = internalTextRef.current || childText;
|
|
458
|
+
if (!textToScramble || textToScramble.length === 0) return null;
|
|
459
|
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
460
|
+
targetEl.textContent = textToScramble;
|
|
461
|
+
targetEl.className = targetEl.className.replace(/\bscramble-\w+\b/g, "");
|
|
462
|
+
isCompleteRef.current = true;
|
|
463
|
+
onComplete == null ? void 0 : onComplete();
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
killTimeline();
|
|
467
|
+
timelineRef.current = import_gsap.default.timeline({
|
|
468
|
+
onComplete: () => {
|
|
469
|
+
timelineRef.current = null;
|
|
470
|
+
isCompleteRef.current = true;
|
|
471
|
+
onComplete == null ? void 0 : onComplete();
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
if (dualLayer) {
|
|
475
|
+
const generateScrambledString = (targetString, charset = DEFAULT_CHARS) => {
|
|
476
|
+
let result = "";
|
|
477
|
+
for (let t = 0; t < targetString.length; t++) {
|
|
478
|
+
let char = targetString[t];
|
|
479
|
+
if (char === " " || char === "\n" || char === "\r") {
|
|
480
|
+
result += char;
|
|
481
|
+
} else {
|
|
482
|
+
result += charset[Math.floor(Math.random() * charset.length)];
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return result;
|
|
486
|
+
};
|
|
487
|
+
const scrambledText = generateScrambledString(textToScramble, chars);
|
|
488
|
+
const nonWhitespaceLength = textToScramble.replace(/\s/g, "").length;
|
|
489
|
+
const stepDuration = nonWhitespaceLength > 0 ? duration / nonWhitespaceLength : 0;
|
|
490
|
+
if (revealMode && !isCompleteRef.current) {
|
|
491
|
+
targetEl.textContent = textToScramble.replace(/[^\s\n\r]/g, "\xA0");
|
|
492
|
+
timelineRef.current.to(targetEl, {
|
|
493
|
+
duration,
|
|
494
|
+
scrambleText: {
|
|
495
|
+
text: scrambledText,
|
|
496
|
+
chars,
|
|
497
|
+
speed: 1,
|
|
498
|
+
revealDelay: 0.1,
|
|
499
|
+
oldClass: color1,
|
|
500
|
+
newClass: color1
|
|
501
|
+
},
|
|
502
|
+
ease: "none"
|
|
503
|
+
});
|
|
504
|
+
} else {
|
|
505
|
+
timelineRef.current.to(targetEl, {
|
|
506
|
+
duration,
|
|
507
|
+
scrambleText: {
|
|
508
|
+
text: scrambledText,
|
|
509
|
+
chars,
|
|
510
|
+
speed: 1,
|
|
511
|
+
revealDelay: 0.1,
|
|
512
|
+
oldClass: color2,
|
|
513
|
+
newClass: color1
|
|
514
|
+
},
|
|
515
|
+
ease: "none"
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
timelineRef.current.to(targetEl, {
|
|
519
|
+
duration,
|
|
520
|
+
scrambleText: {
|
|
521
|
+
text: textToScramble,
|
|
522
|
+
chars,
|
|
523
|
+
speed: 1,
|
|
524
|
+
revealDelay: 0.1,
|
|
525
|
+
oldClass: color1,
|
|
526
|
+
newClass: color2
|
|
527
|
+
},
|
|
528
|
+
ease: "none"
|
|
529
|
+
}, stepDuration);
|
|
530
|
+
} else {
|
|
531
|
+
timelineRef.current.to(targetEl, {
|
|
532
|
+
duration,
|
|
533
|
+
scrambleText: {
|
|
534
|
+
text: textToScramble,
|
|
535
|
+
chars,
|
|
536
|
+
speed: 1,
|
|
537
|
+
revealDelay: 0.2
|
|
538
|
+
},
|
|
539
|
+
ease: "none"
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
return timelineRef.current;
|
|
543
|
+
};
|
|
544
|
+
(0, import_react9.useEffect)(() => {
|
|
545
|
+
if (scrambleGroup) {
|
|
546
|
+
scrambleGroup.register(instanceIdRef.current, triggerAnimation);
|
|
547
|
+
return () => {
|
|
548
|
+
scrambleGroup.unregister(instanceIdRef.current);
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
}, [scrambleGroup, triggerAnimation]);
|
|
552
|
+
(0, import_react9.useEffect)(() => {
|
|
553
|
+
onReady == null ? void 0 : onReady(triggerAnimation);
|
|
554
|
+
}, [onReady, triggerAnimation]);
|
|
555
|
+
const handleMouseEnter = () => {
|
|
556
|
+
if (triggerOnHover) {
|
|
557
|
+
triggerAnimation();
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
(0, import_react9.useEffect)(() => {
|
|
561
|
+
return () => {
|
|
562
|
+
killTimeline();
|
|
563
|
+
};
|
|
564
|
+
}, []);
|
|
565
|
+
const initialDisplayText = revealMode ? childText.replace(/[^\s\n\r]/g, "\xA0") : childText;
|
|
566
|
+
const whiteSpaceValue = multiLine ? "normal" : "nowrap";
|
|
567
|
+
const displayValue = multiLine ? "inline" : "inline-block";
|
|
568
|
+
const containerStyle = {
|
|
569
|
+
position: "relative",
|
|
570
|
+
display: displayValue,
|
|
571
|
+
whiteSpace: whiteSpaceValue
|
|
572
|
+
};
|
|
573
|
+
const hiddenSpanStyle = {
|
|
574
|
+
visibility: "hidden",
|
|
575
|
+
whiteSpace: whiteSpaceValue
|
|
576
|
+
};
|
|
577
|
+
const animatedSpanStyle = {
|
|
578
|
+
position: "absolute",
|
|
579
|
+
top: 0,
|
|
580
|
+
left: 0,
|
|
581
|
+
whiteSpace: whiteSpaceValue,
|
|
582
|
+
...multiLine ? { width: "100%" } : {}
|
|
583
|
+
};
|
|
584
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
585
|
+
"span",
|
|
586
|
+
{
|
|
587
|
+
ref: containerRef,
|
|
588
|
+
className,
|
|
589
|
+
style: containerStyle,
|
|
590
|
+
onMouseEnter: triggerOnHover ? handleMouseEnter : void 0,
|
|
591
|
+
children: [
|
|
592
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "sr-only", children: childText }),
|
|
593
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": "true", style: hiddenSpanStyle, children: childText }),
|
|
594
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { ref: textElementRef, "aria-hidden": "true", style: animatedSpanStyle, children: initialDisplayText })
|
|
595
|
+
]
|
|
596
|
+
}
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// packages/animations/AnimatedHeadline.jsx
|
|
601
|
+
var import_react10 = __toESM(require("react"), 1);
|
|
602
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
603
|
+
var typographyClasses = {
|
|
604
|
+
display: "text-display",
|
|
605
|
+
h1: "text-h1",
|
|
606
|
+
h2: "text-h2",
|
|
607
|
+
h3: "text-h3",
|
|
608
|
+
h4: "text-h4",
|
|
609
|
+
h5: "text-h5",
|
|
610
|
+
h6: "text-h6"
|
|
611
|
+
};
|
|
612
|
+
var AnimatedHeadline = (0, import_react10.forwardRef)(({
|
|
613
|
+
children,
|
|
614
|
+
as: Component = "h1",
|
|
615
|
+
displayAs,
|
|
616
|
+
className,
|
|
617
|
+
skip,
|
|
618
|
+
trigger = "manual",
|
|
619
|
+
wrapperClassName
|
|
620
|
+
}, ref) => {
|
|
621
|
+
const containerRef = (0, import_react10.useRef)(null);
|
|
622
|
+
const wrapperRef = (0, import_react10.useRef)(null);
|
|
623
|
+
const hasRevealedRef = (0, import_react10.useRef)(false);
|
|
624
|
+
const [lines, setLines] = (0, import_react10.useState)(null);
|
|
625
|
+
const shouldSkip = skip ?? window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
626
|
+
(0, import_react10.useLayoutEffect)(() => {
|
|
627
|
+
if (!containerRef.current) return;
|
|
628
|
+
const wordNodes = containerRef.current.querySelectorAll("[data-word]");
|
|
629
|
+
if (wordNodes.length === 0) return;
|
|
630
|
+
const computedLines = [];
|
|
631
|
+
let currentLine = [];
|
|
632
|
+
let lastY = -Infinity;
|
|
633
|
+
let lastExplicitLine = -1;
|
|
634
|
+
for (const node of wordNodes) {
|
|
635
|
+
const top = node.getBoundingClientRect().top;
|
|
636
|
+
const explicitLine = Number(node.dataset.explicitLine ?? -1);
|
|
637
|
+
const isNewExplicit = explicitLine !== lastExplicitLine && lastExplicitLine !== -1;
|
|
638
|
+
if (lastY > -Infinity && top - lastY > 2 || isNewExplicit) {
|
|
639
|
+
computedLines.push(currentLine.join(" "));
|
|
640
|
+
currentLine = [];
|
|
641
|
+
}
|
|
642
|
+
currentLine.push(node.textContent || "");
|
|
643
|
+
lastY = top;
|
|
644
|
+
lastExplicitLine = explicitLine;
|
|
645
|
+
}
|
|
646
|
+
if (currentLine.length > 0) {
|
|
647
|
+
computedLines.push(currentLine.join(" "));
|
|
648
|
+
}
|
|
649
|
+
setLines(computedLines);
|
|
650
|
+
}, []);
|
|
651
|
+
(0, import_react.useGSAP)(() => {
|
|
652
|
+
if (shouldSkip || !containerRef.current || !lines) return;
|
|
653
|
+
const container = containerRef.current;
|
|
654
|
+
import_gsap.default.set(container.querySelectorAll("[data-line-inner]"), { opacity: 0 });
|
|
655
|
+
import_gsap.default.set(container.querySelectorAll("[data-brand-rect], [data-fg-rect]"), { scaleX: 0, transformOrigin: "left" });
|
|
656
|
+
}, { dependencies: [shouldSkip, lines] });
|
|
657
|
+
useIdleGSAP(() => {
|
|
658
|
+
if (trigger !== "scroll" || shouldSkip || !lines) return;
|
|
659
|
+
const triggerEl = wrapperRef.current || containerRef.current;
|
|
660
|
+
if (triggerEl) {
|
|
661
|
+
import_ScrollTrigger.ScrollTrigger.create({
|
|
662
|
+
trigger: triggerEl,
|
|
663
|
+
start: "top bottom",
|
|
664
|
+
once: true,
|
|
665
|
+
onEnter: () => reveal()
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
}, { dependencies: [trigger, shouldSkip, lines] });
|
|
669
|
+
const reveal = (0, import_react10.useCallback)((delayOffset = 0) => {
|
|
670
|
+
if (hasRevealedRef.current || shouldSkip || !containerRef.current) return;
|
|
671
|
+
hasRevealedRef.current = true;
|
|
672
|
+
const lineNodes = containerRef.current.querySelectorAll("[data-line]");
|
|
673
|
+
for (let r = 0; r < lineNodes.length; r++) {
|
|
674
|
+
const lineNode = lineNodes[r];
|
|
675
|
+
if (!lineNode) continue;
|
|
676
|
+
const delay = delayOffset + 0.15 * r;
|
|
677
|
+
const lineInner = lineNode.querySelector("[data-line-inner]");
|
|
678
|
+
const brandRect = lineNode.querySelector("[data-brand-rect]");
|
|
679
|
+
const fgRect = lineNode.querySelector("[data-fg-rect]");
|
|
680
|
+
if (!lineInner || !brandRect || !fgRect) continue;
|
|
681
|
+
const rects = [brandRect, fgRect];
|
|
682
|
+
const tl = import_gsap.default.timeline({ delay });
|
|
683
|
+
tl.to(brandRect, { scaleX: 1, duration: 0.45, ease: "power3.inOut" }, 0);
|
|
684
|
+
tl.to(fgRect, { scaleX: 1, duration: 0.45, ease: "power3.inOut" }, 0.1);
|
|
685
|
+
tl.set(lineInner, { opacity: 1 }, 0.5);
|
|
686
|
+
tl.set(rects, { transformOrigin: "right" }, 0.5);
|
|
687
|
+
tl.to(fgRect, { scaleX: 0, duration: 0.45, ease: "power3.inOut" }, 0.5);
|
|
688
|
+
tl.to(brandRect, { scaleX: 0, duration: 0.45, ease: "power3.inOut" }, 0.6);
|
|
689
|
+
}
|
|
690
|
+
}, [shouldSkip]);
|
|
691
|
+
const reset = (0, import_react10.useCallback)(() => {
|
|
692
|
+
hasRevealedRef.current = false;
|
|
693
|
+
if (!containerRef.current) return;
|
|
694
|
+
const container = containerRef.current;
|
|
695
|
+
import_gsap.default.set(container.querySelectorAll("[data-line-inner]"), { opacity: 0 });
|
|
696
|
+
import_gsap.default.set(container.querySelectorAll("[data-brand-rect], [data-fg-rect]"), { scaleX: 0, transformOrigin: "left" });
|
|
697
|
+
}, []);
|
|
698
|
+
(0, import_react10.useImperativeHandle)(ref, () => ({ reveal, reset }), [reveal, reset]);
|
|
699
|
+
const resolvedClassName = cx(typographyClasses[displayAs ?? Component], className);
|
|
700
|
+
if (!lines) {
|
|
701
|
+
const manualLines = children.split("\n");
|
|
702
|
+
const preRenderedContent = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Component, { ref: containerRef, className: resolvedClassName, children: manualLines.map((lineStr, lineIndex) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react10.Fragment, { children: [
|
|
703
|
+
lineIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("br", {}),
|
|
704
|
+
lineStr.split(/\s+/).filter(Boolean).map((word, wordIndex) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react10.Fragment, { children: [
|
|
705
|
+
wordIndex > 0 && " ",
|
|
706
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "data-word": true, "data-explicit-line": lineIndex, children: word })
|
|
707
|
+
] }, wordIndex))
|
|
708
|
+
] }, lineIndex)) });
|
|
709
|
+
return trigger === "scroll" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: wrapperRef, className: wrapperClassName, children: preRenderedContent }) : preRenderedContent;
|
|
710
|
+
}
|
|
711
|
+
const animatedContent = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Component, { ref: containerRef, className: resolvedClassName, children: lines.map((lineStr, lineIndex) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react10.Fragment, { children: [
|
|
712
|
+
lineIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("br", {}),
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { "data-line": true, className: "relative inline-block", children: [
|
|
714
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { "data-line-inner": true, className: "block whitespace-nowrap", children: lineStr }),
|
|
715
|
+
!shouldSkip && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react10.Fragment, { children: [
|
|
716
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { "data-brand-rect": true, className: "absolute -inset-x-[0.1em] -inset-y-[0.1em] bg-brand" }),
|
|
717
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { "data-fg-rect": true, className: "absolute -inset-x-[0.1em] -inset-y-[0.1em] bg-foreground" })
|
|
718
|
+
] })
|
|
719
|
+
] })
|
|
720
|
+
] }, lineIndex)) });
|
|
721
|
+
return trigger === "scroll" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: wrapperRef, className: wrapperClassName, children: animatedContent }) : animatedContent;
|
|
722
|
+
});
|
|
723
|
+
var AnimatedHeadline_default = AnimatedHeadline;
|
|
724
|
+
|
|
725
|
+
// packages/animations/AnimatedButton.jsx
|
|
726
|
+
var import_react12 = __toESM(require("react"), 1);
|
|
727
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
728
|
+
|
|
729
|
+
// libs/hooks/useDualLayerScramble.js
|
|
730
|
+
var import_react11 = require("react");
|
|
731
|
+
var DEFAULT_CHARS2 = " .'`^\",:;Il!i><~+_-?][}{1)(|\\/tfjrxnuvczXYUJCLQ0OZmwqpdbkhao*#MW&8%B@$";
|
|
732
|
+
function useDualLayerScramble(options) {
|
|
733
|
+
const elementRef = (0, import_react11.useRef)(null);
|
|
734
|
+
const timelineRef = (0, import_react11.useRef)(null);
|
|
735
|
+
const originalTextRef = (0, import_react11.useRef)("");
|
|
736
|
+
const originalHTMLRef = (0, import_react11.useRef)("");
|
|
737
|
+
const dimensionsRef = (0, import_react11.useRef)(null);
|
|
738
|
+
const linesDataRef = (0, import_react11.useRef)([]);
|
|
739
|
+
const spansRef = (0, import_react11.useRef)([]);
|
|
740
|
+
const isAnimatingRef = (0, import_react11.useRef)(false);
|
|
741
|
+
const isPreparedRef = (0, import_react11.useRef)(false);
|
|
742
|
+
(0, import_react11.useEffect)(() => {
|
|
743
|
+
if (!elementRef.current) return;
|
|
744
|
+
const el = elementRef.current;
|
|
745
|
+
const innerText = el.innerText ?? "";
|
|
746
|
+
if (innerText.trim().length > 0) {
|
|
747
|
+
originalTextRef.current = innerText;
|
|
748
|
+
originalHTMLRef.current = el.innerHTML;
|
|
749
|
+
dimensionsRef.current = { width: el.offsetWidth, height: el.offsetHeight };
|
|
750
|
+
}
|
|
751
|
+
}, []);
|
|
752
|
+
const killTimeline = (0, import_react11.useCallback)(() => {
|
|
753
|
+
if (timelineRef.current) {
|
|
754
|
+
timelineRef.current.kill();
|
|
755
|
+
timelineRef.current = null;
|
|
756
|
+
isAnimatingRef.current = false;
|
|
757
|
+
}
|
|
758
|
+
}, []);
|
|
759
|
+
const prepareDOM = (0, import_react11.useCallback)(() => {
|
|
760
|
+
var _a, _b;
|
|
761
|
+
if (!elementRef.current || isPreparedRef.current) return;
|
|
762
|
+
const el = elementRef.current;
|
|
763
|
+
if ((originalTextRef.current || el.innerText || "").trim().length === 0) return;
|
|
764
|
+
if (!dimensionsRef.current) {
|
|
765
|
+
dimensionsRef.current = { width: el.offsetWidth, height: el.offsetHeight };
|
|
766
|
+
}
|
|
767
|
+
const splitTextIntoLines = (element) => {
|
|
768
|
+
const text = element.innerText || "";
|
|
769
|
+
if (text.trim().length === 0) return [];
|
|
770
|
+
if (text.includes("\n")) return text.split("\n").filter((line) => line.length > 0);
|
|
771
|
+
const firstChild = element.firstChild;
|
|
772
|
+
if (!firstChild || firstChild.nodeType !== Node.TEXT_NODE) return [text];
|
|
773
|
+
const range = document.createRange();
|
|
774
|
+
const lines2 = [];
|
|
775
|
+
let currentLine = "";
|
|
776
|
+
let lastTop = null;
|
|
777
|
+
const length = firstChild.length;
|
|
778
|
+
for (let i = 0; i < text.length && i < length; i++) {
|
|
779
|
+
range.setStart(firstChild, i);
|
|
780
|
+
range.setEnd(firstChild, i + 1);
|
|
781
|
+
const rect = range.getBoundingClientRect();
|
|
782
|
+
if (lastTop !== null && Math.abs(rect.top - lastTop) > 2) {
|
|
783
|
+
if (currentLine.length > 0) lines2.push(currentLine);
|
|
784
|
+
currentLine = "";
|
|
785
|
+
}
|
|
786
|
+
currentLine += text[i];
|
|
787
|
+
lastTop = rect.top;
|
|
788
|
+
}
|
|
789
|
+
if (currentLine.length > 0) lines2.push(currentLine);
|
|
790
|
+
return lines2.length > 0 ? lines2 : [text];
|
|
791
|
+
};
|
|
792
|
+
const lines = splitTextIntoLines(el);
|
|
793
|
+
const testDiv = document.createElement("div");
|
|
794
|
+
testDiv.style.cssText = `
|
|
795
|
+
position: absolute;
|
|
796
|
+
visibility: hidden;
|
|
797
|
+
pointer-events: none;
|
|
798
|
+
white-space: nowrap;
|
|
799
|
+
`;
|
|
800
|
+
const computedStyle = window.getComputedStyle(el);
|
|
801
|
+
testDiv.style.font = computedStyle.font;
|
|
802
|
+
testDiv.style.fontSize = computedStyle.fontSize;
|
|
803
|
+
testDiv.style.fontFamily = computedStyle.fontFamily;
|
|
804
|
+
testDiv.style.fontWeight = computedStyle.fontWeight;
|
|
805
|
+
testDiv.style.letterSpacing = computedStyle.letterSpacing;
|
|
806
|
+
testDiv.style.textTransform = computedStyle.textTransform;
|
|
807
|
+
document.body.appendChild(testDiv);
|
|
808
|
+
linesDataRef.current = lines.map((line) => {
|
|
809
|
+
testDiv.textContent = line;
|
|
810
|
+
return { text: line, width: testDiv.offsetWidth, height: testDiv.offsetHeight };
|
|
811
|
+
});
|
|
812
|
+
document.body.removeChild(testDiv);
|
|
813
|
+
const maxWidth = Math.max(...linesDataRef.current.map((lineData) => lineData.width));
|
|
814
|
+
const totalHeight = linesDataRef.current.reduce((sum, lineData) => sum + lineData.height, 0);
|
|
815
|
+
const finalWidth = Math.max(((_a = dimensionsRef.current) == null ? void 0 : _a.width) ?? 0, maxWidth);
|
|
816
|
+
const finalHeight = Math.max(((_b = dimensionsRef.current) == null ? void 0 : _b.height) ?? 0, totalHeight);
|
|
817
|
+
isPreparedRef.current = true;
|
|
818
|
+
import_gsap.default.set(el, { width: finalWidth, height: finalHeight, display: "inline-block", overflow: "hidden" });
|
|
819
|
+
el.innerHTML = "";
|
|
820
|
+
spansRef.current = [];
|
|
821
|
+
linesDataRef.current.forEach((lineData) => {
|
|
822
|
+
const span = document.createElement("span");
|
|
823
|
+
span.style.cssText = `
|
|
824
|
+
display: block;
|
|
825
|
+
opacity: 0;
|
|
826
|
+
width: ${lineData.width}px;
|
|
827
|
+
height: ${lineData.height}px;
|
|
828
|
+
overflow: hidden;
|
|
829
|
+
white-space: nowrap;
|
|
830
|
+
`;
|
|
831
|
+
span.innerText = lineData.text;
|
|
832
|
+
el.appendChild(span);
|
|
833
|
+
spansRef.current.push(span);
|
|
834
|
+
});
|
|
835
|
+
import_gsap.default.set(el, { opacity: 1 });
|
|
836
|
+
}, []);
|
|
837
|
+
const playScramble = (0, import_react11.useCallback)((overrides) => {
|
|
838
|
+
var _a;
|
|
839
|
+
if (!elementRef.current) return null;
|
|
840
|
+
if (isAnimatingRef.current) return timelineRef.current;
|
|
841
|
+
prepareDOM();
|
|
842
|
+
const config = { ...options, ...overrides };
|
|
843
|
+
const duration = config.duration ?? 1;
|
|
844
|
+
const speed = config.speed ?? 1;
|
|
845
|
+
const chars = config.chars ?? DEFAULT_CHARS2;
|
|
846
|
+
const firstColorClass = config.firstColorClass ?? "scramble-brand";
|
|
847
|
+
const secondColorClass = config.secondColorClass ?? "scramble-foreground";
|
|
848
|
+
const stagger2 = config.stagger ?? 0.08;
|
|
849
|
+
const linesData = linesDataRef.current;
|
|
850
|
+
const spans = spansRef.current;
|
|
851
|
+
if (linesData.length === 0 || spans.length === 0) return null;
|
|
852
|
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
853
|
+
spans.forEach((span, index) => {
|
|
854
|
+
const lineData = linesData[index];
|
|
855
|
+
if (lineData) {
|
|
856
|
+
span.innerText = lineData.text;
|
|
857
|
+
}
|
|
858
|
+
span.style.opacity = "1";
|
|
859
|
+
span.className = span.className.replace(/\bscramble-\w+\b/g, "");
|
|
860
|
+
});
|
|
861
|
+
(_a = config.onComplete) == null ? void 0 : _a.call(config);
|
|
862
|
+
return null;
|
|
863
|
+
}
|
|
864
|
+
killTimeline();
|
|
865
|
+
isAnimatingRef.current = true;
|
|
866
|
+
timelineRef.current = import_gsap.default.timeline({
|
|
867
|
+
onComplete: () => {
|
|
868
|
+
var _a2;
|
|
869
|
+
isAnimatingRef.current = false;
|
|
870
|
+
timelineRef.current = null;
|
|
871
|
+
(_a2 = config.onComplete) == null ? void 0 : _a2.call(config);
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
spans.forEach((span, index) => {
|
|
875
|
+
var _a2, _b, _c;
|
|
876
|
+
const lineData = linesData[index];
|
|
877
|
+
if (!lineData) return;
|
|
878
|
+
const originalText = lineData.text;
|
|
879
|
+
const delay = index * stagger2;
|
|
880
|
+
const generateScrambled = (text, charSet = DEFAULT_CHARS2) => {
|
|
881
|
+
let scrambled = "";
|
|
882
|
+
for (let i = 0; i < text.length; i++) {
|
|
883
|
+
const char = text[i];
|
|
884
|
+
if (char === " ") {
|
|
885
|
+
scrambled += char;
|
|
886
|
+
} else {
|
|
887
|
+
scrambled += charSet[Math.floor(Math.random() * charSet.length)];
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
return scrambled;
|
|
891
|
+
};
|
|
892
|
+
const initialScrambledText = generateScrambled(originalText, chars);
|
|
893
|
+
const nonSpaceCount = originalText.replace(/\s/g, "").length;
|
|
894
|
+
const spacesOnly = originalText.replace(/[^\s]/g, " ");
|
|
895
|
+
(_a2 = timelineRef.current) == null ? void 0 : _a2.add(() => {
|
|
896
|
+
import_gsap.default.set(span, { opacity: 1 });
|
|
897
|
+
span.innerText = spacesOnly;
|
|
898
|
+
}, delay);
|
|
899
|
+
(_b = timelineRef.current) == null ? void 0 : _b.to(span, {
|
|
900
|
+
duration,
|
|
901
|
+
scrambleText: {
|
|
902
|
+
text: initialScrambledText,
|
|
903
|
+
chars,
|
|
904
|
+
speed,
|
|
905
|
+
revealDelay: 0.1,
|
|
906
|
+
oldClass: firstColorClass,
|
|
907
|
+
newClass: firstColorClass
|
|
908
|
+
},
|
|
909
|
+
ease: "none"
|
|
910
|
+
}, delay);
|
|
911
|
+
(_c = timelineRef.current) == null ? void 0 : _c.to(span, {
|
|
912
|
+
duration,
|
|
913
|
+
scrambleText: {
|
|
914
|
+
text: originalText,
|
|
915
|
+
chars,
|
|
916
|
+
speed,
|
|
917
|
+
revealDelay: 0.1,
|
|
918
|
+
oldClass: firstColorClass,
|
|
919
|
+
newClass: secondColorClass
|
|
920
|
+
},
|
|
921
|
+
ease: "none"
|
|
922
|
+
}, delay + (nonSpaceCount > 0 ? duration / nonSpaceCount : 0));
|
|
923
|
+
});
|
|
924
|
+
return timelineRef.current;
|
|
925
|
+
}, [options, killTimeline, prepareDOM]);
|
|
926
|
+
const resetDOM = (0, import_react11.useCallback)(() => {
|
|
927
|
+
killTimeline();
|
|
928
|
+
if (elementRef.current && isPreparedRef.current) {
|
|
929
|
+
elementRef.current.innerHTML = originalHTMLRef.current || originalTextRef.current;
|
|
930
|
+
import_gsap.default.set(elementRef.current, {
|
|
931
|
+
opacity: 0,
|
|
932
|
+
width: "auto",
|
|
933
|
+
height: "auto",
|
|
934
|
+
overflow: "visible"
|
|
935
|
+
});
|
|
936
|
+
spansRef.current = [];
|
|
937
|
+
linesDataRef.current = [];
|
|
938
|
+
isPreparedRef.current = false;
|
|
939
|
+
}
|
|
940
|
+
}, [killTimeline]);
|
|
941
|
+
(0, import_react11.useEffect)(() => {
|
|
942
|
+
return () => {
|
|
943
|
+
killTimeline();
|
|
944
|
+
spansRef.current = [];
|
|
945
|
+
linesDataRef.current = [];
|
|
946
|
+
isPreparedRef.current = false;
|
|
947
|
+
};
|
|
948
|
+
}, [killTimeline]);
|
|
949
|
+
return {
|
|
950
|
+
ref: elementRef,
|
|
951
|
+
scramble: playScramble,
|
|
952
|
+
kill: resetDOM,
|
|
953
|
+
isAnimating: isAnimatingRef.current
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// packages/animations/AnimatedButton.jsx
|
|
958
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
959
|
+
var buttonVariants = (0, import_class_variance_authority2.cva)(
|
|
960
|
+
[
|
|
961
|
+
"group inline-flex min-w-0 shrink-0 cursor-pointer items-center justify-center whitespace-nowrap",
|
|
962
|
+
"font-medium font-mono uppercase",
|
|
963
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-brand/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
964
|
+
"disabled:pointer-events-none disabled:opacity-50"
|
|
965
|
+
],
|
|
966
|
+
{
|
|
967
|
+
variants: {
|
|
968
|
+
variant: {
|
|
969
|
+
primary: []
|
|
970
|
+
},
|
|
971
|
+
size: {
|
|
972
|
+
xs: "text-body-sm",
|
|
973
|
+
sm: "text-body-sm",
|
|
974
|
+
default: "text-body-sm lg:text-body",
|
|
975
|
+
lg: "text-body lg:text-body-lg"
|
|
976
|
+
}
|
|
977
|
+
},
|
|
978
|
+
defaultVariants: {
|
|
979
|
+
variant: "primary",
|
|
980
|
+
size: "default"
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
);
|
|
984
|
+
var iconVariants = (0, import_class_variance_authority2.cva)(
|
|
985
|
+
[
|
|
986
|
+
"flex items-center justify-center",
|
|
987
|
+
"transition-transform duration-700 [transition-timing-function:var(--ease-power4-in-out)]"
|
|
988
|
+
],
|
|
989
|
+
{
|
|
990
|
+
variants: {
|
|
991
|
+
size: {
|
|
992
|
+
xs: "size-32",
|
|
993
|
+
sm: "size-32 lg:size-40",
|
|
994
|
+
default: "size-40 lg:size-48",
|
|
995
|
+
lg: "size-48 lg:size-56"
|
|
996
|
+
},
|
|
997
|
+
position: {
|
|
998
|
+
left: "origin-left -rotate-45 scale-0",
|
|
999
|
+
right: "absolute right-0 z-10 origin-right rotate-0 scale-100"
|
|
1000
|
+
},
|
|
1001
|
+
theme: {
|
|
1002
|
+
light: "bg-foreground text-background",
|
|
1003
|
+
dark: "bg-foreground text-background",
|
|
1004
|
+
brand: "bg-brand text-black"
|
|
1005
|
+
}
|
|
1006
|
+
},
|
|
1007
|
+
defaultVariants: {
|
|
1008
|
+
size: "default",
|
|
1009
|
+
theme: "light"
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
);
|
|
1013
|
+
var textWrapperVariants = (0, import_class_variance_authority2.cva)(
|
|
1014
|
+
[
|
|
1015
|
+
"flex w-full flex-1 items-center justify-center",
|
|
1016
|
+
"transition-transform duration-700 [transition-timing-function:var(--ease-power4-in-out)]"
|
|
1017
|
+
],
|
|
1018
|
+
{
|
|
1019
|
+
variants: {
|
|
1020
|
+
size: {
|
|
1021
|
+
xs: "h-32 -translate-x-[calc(32px+6px)] px-8",
|
|
1022
|
+
sm: "h-32 -translate-x-[calc(32px+6px)] px-8 lg:h-40 lg:-translate-x-[calc(40px+6px)] lg:px-12",
|
|
1023
|
+
default: "h-40 -translate-x-[calc(40px+6px)] px-12 lg:h-48 lg:-translate-x-[calc(48px+6px)] lg:px-16",
|
|
1024
|
+
lg: "h-48 -translate-x-[calc(48px+6px)] px-16 lg:h-56 lg:-translate-x-[calc(56px+6px)] lg:px-24"
|
|
1025
|
+
},
|
|
1026
|
+
theme: {
|
|
1027
|
+
light: "bg-foreground text-background",
|
|
1028
|
+
dark: "bg-foreground text-background",
|
|
1029
|
+
brand: "bg-brand text-black"
|
|
1030
|
+
}
|
|
1031
|
+
},
|
|
1032
|
+
defaultVariants: {
|
|
1033
|
+
size: "default",
|
|
1034
|
+
theme: "light"
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
);
|
|
1038
|
+
function PlusIcon({ className }) {
|
|
1039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1040
|
+
"svg",
|
|
1041
|
+
{
|
|
1042
|
+
className: cx("size-[0.75em]", className),
|
|
1043
|
+
viewBox: "0 0 12 12",
|
|
1044
|
+
fill: "none",
|
|
1045
|
+
"aria-hidden": "true",
|
|
1046
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1047
|
+
"path",
|
|
1048
|
+
{
|
|
1049
|
+
d: "M6 1v10M1 6h10",
|
|
1050
|
+
stroke: "currentColor",
|
|
1051
|
+
strokeWidth: "1.5",
|
|
1052
|
+
strokeLinecap: "square"
|
|
1053
|
+
}
|
|
1054
|
+
)
|
|
1055
|
+
}
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
function AnimatedButton(props) {
|
|
1059
|
+
const {
|
|
1060
|
+
children,
|
|
1061
|
+
className,
|
|
1062
|
+
asChild,
|
|
1063
|
+
variant,
|
|
1064
|
+
size,
|
|
1065
|
+
theme,
|
|
1066
|
+
type,
|
|
1067
|
+
...rest
|
|
1068
|
+
} = props;
|
|
1069
|
+
const resolvedType = type === void 0 ? asChild ? void 0 : "button" : type;
|
|
1070
|
+
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
1071
|
+
const themeColors = theme === "brand" ? { firstColorClass: "scramble-white", secondColorClass: "scramble-inherit" } : { firstColorClass: "scramble-brand", secondColorClass: "scramble-inherit" };
|
|
1072
|
+
const scrambleConfig = {
|
|
1073
|
+
duration: 0.5,
|
|
1074
|
+
initiallyVisible: true,
|
|
1075
|
+
firstColorClass: themeColors.firstColorClass,
|
|
1076
|
+
secondColorClass: themeColors.secondColorClass
|
|
1077
|
+
};
|
|
1078
|
+
const scrambleResult = useDualLayerScramble(scrambleConfig);
|
|
1079
|
+
const isScramblingRef = (0, import_react12.useRef)(false);
|
|
1080
|
+
const handleMouseEnter = () => {
|
|
1081
|
+
if (!isScramblingRef.current) {
|
|
1082
|
+
isScramblingRef.current = true;
|
|
1083
|
+
scrambleResult.scramble();
|
|
1084
|
+
}
|
|
1085
|
+
};
|
|
1086
|
+
const handleMouseLeave = () => {
|
|
1087
|
+
isScramblingRef.current = false;
|
|
1088
|
+
};
|
|
1089
|
+
const buttonClasses = buttonVariants({ variant, size, className });
|
|
1090
|
+
const renderContent = (content) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "relative flex w-full items-center gap-6", children: [
|
|
1091
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1092
|
+
"span",
|
|
1093
|
+
{
|
|
1094
|
+
className: cx(
|
|
1095
|
+
iconVariants({ size, theme, position: "left" }),
|
|
1096
|
+
"group-hover:rotate-0 group-hover:scale-100"
|
|
1097
|
+
),
|
|
1098
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PlusIcon, {})
|
|
1099
|
+
}
|
|
1100
|
+
),
|
|
1101
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1102
|
+
"span",
|
|
1103
|
+
{
|
|
1104
|
+
className: cx(
|
|
1105
|
+
textWrapperVariants({ size, theme }),
|
|
1106
|
+
"group-hover:translate-x-0"
|
|
1107
|
+
),
|
|
1108
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { ref: scrambleResult.ref, children: content })
|
|
1109
|
+
}
|
|
1110
|
+
),
|
|
1111
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1112
|
+
"span",
|
|
1113
|
+
{
|
|
1114
|
+
className: cx(
|
|
1115
|
+
iconVariants({ size, theme, position: "right" }),
|
|
1116
|
+
"group-hover:-rotate-45 group-hover:scale-0"
|
|
1117
|
+
),
|
|
1118
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PlusIcon, {})
|
|
1119
|
+
}
|
|
1120
|
+
)
|
|
1121
|
+
] });
|
|
1122
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1123
|
+
Comp,
|
|
1124
|
+
{
|
|
1125
|
+
type: resolvedType,
|
|
1126
|
+
className: buttonClasses,
|
|
1127
|
+
onMouseEnter: handleMouseEnter,
|
|
1128
|
+
onMouseLeave: handleMouseLeave,
|
|
1129
|
+
...rest,
|
|
1130
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_slot.Slottable, { asChild, child: children, children: renderContent })
|
|
1131
|
+
}
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// packages/animations/AnimatedLink.jsx
|
|
1136
|
+
var import_react13 = __toESM(require("react"), 1);
|
|
1137
|
+
var import_react_slot2 = require("@radix-ui/react-slot");
|
|
1138
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
1139
|
+
var AnimatedLink = (0, import_react13.forwardRef)(function AnimatedLink2(props, ref) {
|
|
1140
|
+
const {
|
|
1141
|
+
children,
|
|
1142
|
+
className,
|
|
1143
|
+
asChild,
|
|
1144
|
+
indicator,
|
|
1145
|
+
...restProps
|
|
1146
|
+
} = props;
|
|
1147
|
+
const Component = asChild ? import_react_slot2.Slot : "a";
|
|
1148
|
+
const displayClass = indicator ? "inline-flex items-center" : "inline-block";
|
|
1149
|
+
const combinedClassName = cx(
|
|
1150
|
+
"group relative w-fit cursor-pointer",
|
|
1151
|
+
displayClass,
|
|
1152
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-brand/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
1153
|
+
className
|
|
1154
|
+
);
|
|
1155
|
+
const renderChildren = (childContent) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1156
|
+
indicator && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1157
|
+
"span",
|
|
1158
|
+
{
|
|
1159
|
+
className: cx(
|
|
1160
|
+
"absolute left-0 size-8 bg-brand lg:size-12",
|
|
1161
|
+
"-rotate-90 scale-0",
|
|
1162
|
+
"transition-transform duration-500 [transition-timing-function:cubic-bezier(0.34,1.56,0.64,1)]",
|
|
1163
|
+
"group-hover:rotate-0 group-hover:scale-100",
|
|
1164
|
+
"group-focus-visible:rotate-0 group-focus-visible:scale-100"
|
|
1165
|
+
),
|
|
1166
|
+
"aria-hidden": "true"
|
|
1167
|
+
}
|
|
1168
|
+
),
|
|
1169
|
+
indicator ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1170
|
+
"span",
|
|
1171
|
+
{
|
|
1172
|
+
className: cx(
|
|
1173
|
+
"transition-transform duration-500 [transition-timing-function:cubic-bezier(0.33,1,0.68,1)]",
|
|
1174
|
+
"group-hover:translate-x-24",
|
|
1175
|
+
"group-focus-visible:translate-x-24"
|
|
1176
|
+
),
|
|
1177
|
+
children: childContent
|
|
1178
|
+
}
|
|
1179
|
+
) : childContent,
|
|
1180
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1181
|
+
"span",
|
|
1182
|
+
{
|
|
1183
|
+
className: cx(
|
|
1184
|
+
"pointer-events-none absolute inset-x-0 -bottom-1",
|
|
1185
|
+
indicator && [
|
|
1186
|
+
"transition-transform duration-500 [transition-timing-function:cubic-bezier(0.33,1,0.68,1)]",
|
|
1187
|
+
"group-hover:translate-x-24 group-focus-visible:translate-x-24"
|
|
1188
|
+
]
|
|
1189
|
+
),
|
|
1190
|
+
"aria-hidden": "true",
|
|
1191
|
+
children: [
|
|
1192
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1193
|
+
"span",
|
|
1194
|
+
{
|
|
1195
|
+
className: cx(
|
|
1196
|
+
"absolute inset-x-0 top-0 h-px bg-current",
|
|
1197
|
+
"origin-left scale-x-100",
|
|
1198
|
+
"transition-transform duration-700 [transition-timing-function:cubic-bezier(0.625,0.05,0,1)]",
|
|
1199
|
+
"delay-300 group-hover:origin-right group-hover:scale-x-0 group-hover:delay-0",
|
|
1200
|
+
"group-focus-visible:origin-right group-focus-visible:scale-x-0 group-focus-visible:delay-0"
|
|
1201
|
+
)
|
|
1202
|
+
}
|
|
1203
|
+
),
|
|
1204
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1205
|
+
"span",
|
|
1206
|
+
{
|
|
1207
|
+
className: cx(
|
|
1208
|
+
"absolute inset-x-0 top-0 h-px bg-current",
|
|
1209
|
+
"origin-right scale-x-0",
|
|
1210
|
+
"transition-transform duration-700 [transition-timing-function:cubic-bezier(0.625,0.05,0,1)]",
|
|
1211
|
+
"delay-0 group-hover:origin-left group-hover:scale-x-100 group-hover:delay-300",
|
|
1212
|
+
"group-focus-visible:origin-left group-focus-visible:scale-x-100 group-focus-visible:delay-300"
|
|
1213
|
+
)
|
|
1214
|
+
}
|
|
1215
|
+
)
|
|
1216
|
+
]
|
|
1217
|
+
}
|
|
1218
|
+
)
|
|
1219
|
+
] });
|
|
1220
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Component, { ref, className: combinedClassName, ...restProps, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_react_slot2.Slottable, { asChild, child: children, children: renderChildren }) });
|
|
1221
|
+
});
|
|
1222
|
+
var AnimatedLink_default = AnimatedLink;
|
|
1223
|
+
|
|
1224
|
+
// packages/animations/AnimatedProse.jsx
|
|
1225
|
+
var import_react14 = __toESM(require("react"), 1);
|
|
1226
|
+
var import_framer_motion = require("framer-motion");
|
|
1227
|
+
|
|
1228
|
+
// libs/utils/easings.js
|
|
1229
|
+
function cubicBezier(x1, y1, x2, y2) {
|
|
1230
|
+
const cx2 = 3 * x1;
|
|
1231
|
+
const bx = 3 * (x2 - x1) - cx2;
|
|
1232
|
+
const ax = 1 - cx2 - bx;
|
|
1233
|
+
const cy = 3 * y1;
|
|
1234
|
+
const by = 3 * (y2 - y1) - cy;
|
|
1235
|
+
const ay = 1 - cy - by;
|
|
1236
|
+
function sampleCurveX(t) {
|
|
1237
|
+
return ((ax * t + bx) * t + cx2) * t;
|
|
1238
|
+
}
|
|
1239
|
+
function sampleCurveY(t) {
|
|
1240
|
+
return ((ay * t + by) * t + cy) * t;
|
|
1241
|
+
}
|
|
1242
|
+
function sampleCurveDerivativeX(t) {
|
|
1243
|
+
return (3 * ax * t + 2 * bx) * t + cx2;
|
|
1244
|
+
}
|
|
1245
|
+
function solveCurveX(x, epsilon = 1e-6) {
|
|
1246
|
+
let t = x;
|
|
1247
|
+
for (let i = 0; i < 8; i++) {
|
|
1248
|
+
const currentX = sampleCurveX(t) - x;
|
|
1249
|
+
if (Math.abs(currentX) < epsilon) return t;
|
|
1250
|
+
const currentSlope = sampleCurveDerivativeX(t);
|
|
1251
|
+
if (Math.abs(currentSlope) < epsilon) break;
|
|
1252
|
+
t -= currentX / currentSlope;
|
|
1253
|
+
}
|
|
1254
|
+
let lower = 0;
|
|
1255
|
+
let upper = 1;
|
|
1256
|
+
t = x;
|
|
1257
|
+
if (t < lower) return lower;
|
|
1258
|
+
if (t > upper) return upper;
|
|
1259
|
+
while (lower < upper) {
|
|
1260
|
+
const currentX = sampleCurveX(t);
|
|
1261
|
+
if (Math.abs(currentX - x) < epsilon) return t;
|
|
1262
|
+
if (x > currentX) {
|
|
1263
|
+
lower = t;
|
|
1264
|
+
} else {
|
|
1265
|
+
upper = t;
|
|
1266
|
+
}
|
|
1267
|
+
t = (upper - lower) / 2 + lower;
|
|
1268
|
+
}
|
|
1269
|
+
return t;
|
|
1270
|
+
}
|
|
1271
|
+
return function bezierEase(t) {
|
|
1272
|
+
if (t <= 0) return 0;
|
|
1273
|
+
if (t >= 1) return 1;
|
|
1274
|
+
return sampleCurveY(solveCurveX(t));
|
|
1275
|
+
};
|
|
1276
|
+
}
|
|
1277
|
+
var NAMED_EASINGS = {
|
|
1278
|
+
linear: (t) => t,
|
|
1279
|
+
easeIn: cubicBezier(0.42, 0, 1, 1),
|
|
1280
|
+
easeOut: cubicBezier(0, 0, 0.58, 1),
|
|
1281
|
+
easeInOut: cubicBezier(0.42, 0, 0.58, 1),
|
|
1282
|
+
circIn: cubicBezier(0.55, 0, 1, 0.45),
|
|
1283
|
+
circOut: cubicBezier(0, 0.55, 0.45, 1),
|
|
1284
|
+
circInOut: cubicBezier(0.85, 0, 0.15, 1),
|
|
1285
|
+
backIn: cubicBezier(0.36, 0, 0.66, -0.56),
|
|
1286
|
+
backOut: cubicBezier(0.34, 1.56, 0.64, 1),
|
|
1287
|
+
backInOut: cubicBezier(0.68, -0.6, 0.32, 1.6),
|
|
1288
|
+
anticipate: cubicBezier(0.36, 0, 0.66, -0.56)
|
|
1289
|
+
};
|
|
1290
|
+
function easingDefinitionToFunction(definition) {
|
|
1291
|
+
if (typeof definition === "function") {
|
|
1292
|
+
return definition;
|
|
1293
|
+
}
|
|
1294
|
+
if (Array.isArray(definition) && definition.length === 4) {
|
|
1295
|
+
const [x1, y1, x2, y2] = definition;
|
|
1296
|
+
return cubicBezier(x1, y1, x2, y2);
|
|
1297
|
+
}
|
|
1298
|
+
if (typeof definition === "string" && NAMED_EASINGS[definition]) {
|
|
1299
|
+
return NAMED_EASINGS[definition];
|
|
1300
|
+
}
|
|
1301
|
+
return NAMED_EASINGS.linear;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
// packages/animations/AnimatedProse.jsx
|
|
1305
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1306
|
+
function stagger(amount = 0.1, { startDelay = 0, from = 0, ease } = {}) {
|
|
1307
|
+
return (index, totalElements) => {
|
|
1308
|
+
let fromVal = typeof from === "number" ? from : (function(fromStr, total) {
|
|
1309
|
+
if (fromStr === "first") return 0;
|
|
1310
|
+
let lastIndex = total - 1;
|
|
1311
|
+
return fromStr === "last" ? lastIndex : lastIndex / 2;
|
|
1312
|
+
})(from, totalElements);
|
|
1313
|
+
let distance = amount * Math.abs(fromVal - index);
|
|
1314
|
+
if (ease) {
|
|
1315
|
+
let maxStagger = totalElements * amount;
|
|
1316
|
+
distance = easingDefinitionToFunction(ease)(distance / maxStagger) * maxStagger;
|
|
1317
|
+
}
|
|
1318
|
+
return startDelay + distance;
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
var AnimatedProseContext = (0, import_react14.createContext)(false);
|
|
1322
|
+
function AnimatedProse({
|
|
1323
|
+
children,
|
|
1324
|
+
className,
|
|
1325
|
+
staggerDelay = 0.03,
|
|
1326
|
+
duration = 0.5,
|
|
1327
|
+
delay = 0,
|
|
1328
|
+
margin = "0px 0px -10% 0px"
|
|
1329
|
+
}) {
|
|
1330
|
+
const [isInView, setIsInView] = (0, import_react14.useState)(false);
|
|
1331
|
+
const [hasSplitLines, setHasSplitLines] = (0, import_react14.useState)(false);
|
|
1332
|
+
const containerRef = (0, import_react14.useRef)(null);
|
|
1333
|
+
const hasAnimatedRef = (0, import_react14.useRef)(false);
|
|
1334
|
+
(0, import_react14.useEffect)(() => {
|
|
1335
|
+
if (!containerRef.current) return;
|
|
1336
|
+
const checkSplitLines = () => {
|
|
1337
|
+
var _a;
|
|
1338
|
+
const lines = (_a = containerRef.current) == null ? void 0 : _a.querySelectorAll(".split-line");
|
|
1339
|
+
if (lines && lines.length > 0) {
|
|
1340
|
+
setHasSplitLines(true);
|
|
1341
|
+
return true;
|
|
1342
|
+
}
|
|
1343
|
+
return false;
|
|
1344
|
+
};
|
|
1345
|
+
if (checkSplitLines()) return;
|
|
1346
|
+
const intervalId = setInterval(() => {
|
|
1347
|
+
if (checkSplitLines()) {
|
|
1348
|
+
clearInterval(intervalId);
|
|
1349
|
+
}
|
|
1350
|
+
}, 50);
|
|
1351
|
+
const timeoutId = setTimeout(() => {
|
|
1352
|
+
clearInterval(intervalId);
|
|
1353
|
+
setHasSplitLines(true);
|
|
1354
|
+
}, 500);
|
|
1355
|
+
return () => {
|
|
1356
|
+
clearInterval(intervalId);
|
|
1357
|
+
clearTimeout(timeoutId);
|
|
1358
|
+
};
|
|
1359
|
+
}, []);
|
|
1360
|
+
(0, import_react14.useEffect)(() => {
|
|
1361
|
+
if (!isInView || !hasSplitLines || !containerRef.current || hasAnimatedRef.current) return;
|
|
1362
|
+
const lines = containerRef.current.querySelectorAll(".split-line");
|
|
1363
|
+
if (lines.length === 0) return;
|
|
1364
|
+
hasAnimatedRef.current = true;
|
|
1365
|
+
containerRef.current.querySelectorAll(".invisible").forEach(makeVisible);
|
|
1366
|
+
const animation = (0, import_framer_motion.animate)(
|
|
1367
|
+
Array.from(lines),
|
|
1368
|
+
{ y: ["100%", "0%"] },
|
|
1369
|
+
{
|
|
1370
|
+
delay: stagger(staggerDelay, { startDelay: delay }),
|
|
1371
|
+
duration,
|
|
1372
|
+
ease: [0.33, 1, 0.68, 1]
|
|
1373
|
+
}
|
|
1374
|
+
);
|
|
1375
|
+
return () => {
|
|
1376
|
+
animation == null ? void 0 : animation.cancel();
|
|
1377
|
+
};
|
|
1378
|
+
}, [isInView, hasSplitLines, staggerDelay, duration, delay]);
|
|
1379
|
+
const handleViewportEnter = () => setIsInView(true);
|
|
1380
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AnimatedProseContext.Provider, { value: true, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1381
|
+
import_framer_motion.motion.div,
|
|
1382
|
+
{
|
|
1383
|
+
ref: containerRef,
|
|
1384
|
+
onViewportEnter: handleViewportEnter,
|
|
1385
|
+
viewport: { once: true, margin },
|
|
1386
|
+
className: cx(className),
|
|
1387
|
+
children
|
|
1388
|
+
}
|
|
1389
|
+
) });
|
|
1390
|
+
}
|
|
1391
|
+
function makeVisible(el) {
|
|
1392
|
+
el.style.visibility = "visible";
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// packages/animations/AnimatedSubtext.jsx
|
|
1396
|
+
var import_react15 = __toESM(require("react"), 1);
|
|
1397
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1398
|
+
var AnimatedSubtext = (0, import_react15.forwardRef)(({
|
|
1399
|
+
children,
|
|
1400
|
+
className,
|
|
1401
|
+
skip = false,
|
|
1402
|
+
staggerDelay = 0.05,
|
|
1403
|
+
duration = 0.8
|
|
1404
|
+
}, ref) => {
|
|
1405
|
+
const elementRef = (0, import_react15.useRef)(null);
|
|
1406
|
+
const splitTextRef = (0, import_react15.useRef)(null);
|
|
1407
|
+
const [isSplit, setIsSplit] = (0, import_react15.useState)(false);
|
|
1408
|
+
(0, import_react15.useLayoutEffect)(() => {
|
|
1409
|
+
if (elementRef.current && !skip) {
|
|
1410
|
+
setIsSplit(false);
|
|
1411
|
+
splitTextRef.current = new import_SplitText.SplitText(elementRef.current, {
|
|
1412
|
+
type: "lines",
|
|
1413
|
+
autoSplit: true,
|
|
1414
|
+
aria: false,
|
|
1415
|
+
deepSlice: true,
|
|
1416
|
+
reduceWhiteSpace: false,
|
|
1417
|
+
mask: "lines",
|
|
1418
|
+
linesClass: "split-line",
|
|
1419
|
+
onSplit: () => setIsSplit(true)
|
|
1420
|
+
});
|
|
1421
|
+
return () => {
|
|
1422
|
+
var _a;
|
|
1423
|
+
(_a = splitTextRef.current) == null ? void 0 : _a.revert();
|
|
1424
|
+
splitTextRef.current = null;
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
}, [skip]);
|
|
1428
|
+
(0, import_react15.useImperativeHandle)(ref, () => ({
|
|
1429
|
+
reveal: (delay = 0) => {
|
|
1430
|
+
if (!elementRef.current || !splitTextRef.current || skip) return;
|
|
1431
|
+
const lines = splitTextRef.current.lines ?? [];
|
|
1432
|
+
if (lines.length !== 0) {
|
|
1433
|
+
elementRef.current.style.visibility = "visible";
|
|
1434
|
+
import_gsap.default.fromTo(
|
|
1435
|
+
lines,
|
|
1436
|
+
{ y: "100%" },
|
|
1437
|
+
{
|
|
1438
|
+
y: "0%",
|
|
1439
|
+
duration,
|
|
1440
|
+
ease: "power3.out",
|
|
1441
|
+
stagger: staggerDelay,
|
|
1442
|
+
delay
|
|
1443
|
+
}
|
|
1444
|
+
);
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}), [skip, duration, staggerDelay]);
|
|
1448
|
+
const renderWithLineBreaks = (text) => {
|
|
1449
|
+
const lines = text.split("\n");
|
|
1450
|
+
return lines.map((line, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { children: [
|
|
1451
|
+
line,
|
|
1452
|
+
index < lines.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("br", {})
|
|
1453
|
+
] }, index));
|
|
1454
|
+
};
|
|
1455
|
+
return skip ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { className, children: renderWithLineBreaks(children) }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", { ref: elementRef, className: cx("invisible", className), children: renderWithLineBreaks(children) });
|
|
1456
|
+
});
|
|
1457
|
+
var AnimatedSubtext_default = AnimatedSubtext;
|
|
1458
|
+
|
|
1459
|
+
// packages/animations/AnimatedText.jsx
|
|
1460
|
+
var import_react16 = __toESM(require("react"), 1);
|
|
1461
|
+
var import_framer_motion2 = require("framer-motion");
|
|
1462
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1463
|
+
function AnimatedText({
|
|
1464
|
+
children,
|
|
1465
|
+
className,
|
|
1466
|
+
staggerDelay = 0.03,
|
|
1467
|
+
duration = 0.5,
|
|
1468
|
+
delay = 0,
|
|
1469
|
+
margin = "0px 0px -10% 0px",
|
|
1470
|
+
revert = false
|
|
1471
|
+
}) {
|
|
1472
|
+
const [isInView, setIsInView] = (0, import_react16.useState)(false);
|
|
1473
|
+
const [isSplit, setIsSplit] = (0, import_react16.useState)(false);
|
|
1474
|
+
const containerRef = (0, import_react16.useRef)(null);
|
|
1475
|
+
const splitTextRef = (0, import_react16.useRef)(null);
|
|
1476
|
+
const inAnimatedProse = (0, import_react16.useContext)(AnimatedProseContext);
|
|
1477
|
+
(0, import_react16.useLayoutEffect)(() => {
|
|
1478
|
+
if (containerRef.current) {
|
|
1479
|
+
setIsSplit(false);
|
|
1480
|
+
splitTextRef.current = new import_SplitText.SplitText(containerRef.current, {
|
|
1481
|
+
type: "lines",
|
|
1482
|
+
autoSplit: true,
|
|
1483
|
+
aria: false,
|
|
1484
|
+
deepSlice: true,
|
|
1485
|
+
reduceWhiteSpace: false,
|
|
1486
|
+
mask: "lines",
|
|
1487
|
+
linesClass: "split-line",
|
|
1488
|
+
onSplit: () => setIsSplit(true)
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
return () => {
|
|
1492
|
+
splitTextRef.current = null;
|
|
1493
|
+
};
|
|
1494
|
+
}, []);
|
|
1495
|
+
(0, import_react16.useEffect)(() => {
|
|
1496
|
+
if (inAnimatedProse || !isInView || !isSplit || !containerRef.current || !splitTextRef.current) {
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
const lines = splitTextRef.current.lines ?? [];
|
|
1500
|
+
if (lines.length === 0) return;
|
|
1501
|
+
containerRef.current.style.visibility = "visible";
|
|
1502
|
+
const animation = (0, import_framer_motion2.animate)(
|
|
1503
|
+
lines,
|
|
1504
|
+
{ y: ["100%", "0%"] },
|
|
1505
|
+
{
|
|
1506
|
+
delay: stagger(staggerDelay, { startDelay: delay }),
|
|
1507
|
+
duration,
|
|
1508
|
+
ease: [0.33, 1, 0.68, 1]
|
|
1509
|
+
}
|
|
1510
|
+
);
|
|
1511
|
+
const handleRevert = async () => {
|
|
1512
|
+
var _a;
|
|
1513
|
+
try {
|
|
1514
|
+
await animation;
|
|
1515
|
+
if (revert) {
|
|
1516
|
+
(_a = splitTextRef.current) == null ? void 0 : _a.revert();
|
|
1517
|
+
}
|
|
1518
|
+
} catch (err) {
|
|
1519
|
+
}
|
|
1520
|
+
};
|
|
1521
|
+
handleRevert();
|
|
1522
|
+
return () => {
|
|
1523
|
+
animation == null ? void 0 : animation.cancel();
|
|
1524
|
+
};
|
|
1525
|
+
}, [isInView, isSplit, inAnimatedProse, staggerDelay, duration, delay, revert]);
|
|
1526
|
+
const handleViewportEnter = () => setIsInView(true);
|
|
1527
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1528
|
+
import_framer_motion2.motion.span,
|
|
1529
|
+
{
|
|
1530
|
+
ref: containerRef,
|
|
1531
|
+
onViewportEnter: handleViewportEnter,
|
|
1532
|
+
viewport: { once: true, margin },
|
|
1533
|
+
className: cx("invisible", className),
|
|
1534
|
+
children
|
|
1535
|
+
}
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
// packages/animations/ScrollAnimatedHeadline.jsx
|
|
1540
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1541
|
+
function ScrollAnimatedHeadline({
|
|
1542
|
+
headline,
|
|
1543
|
+
displayAs,
|
|
1544
|
+
className,
|
|
1545
|
+
headlineClassName
|
|
1546
|
+
}) {
|
|
1547
|
+
if (!(headline == null ? void 0 : headline.text) || !(headline == null ? void 0 : headline.level)) return null;
|
|
1548
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1549
|
+
AnimatedHeadline_default,
|
|
1550
|
+
{
|
|
1551
|
+
trigger: "scroll",
|
|
1552
|
+
as: headline.level,
|
|
1553
|
+
displayAs,
|
|
1554
|
+
className: cx(headlineClassName),
|
|
1555
|
+
wrapperClassName: className,
|
|
1556
|
+
children: headline.text
|
|
1557
|
+
}
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
// packages/animations/Preloader.jsx
|
|
1562
|
+
var import_react18 = __toESM(require("react"), 1);
|
|
1563
|
+
|
|
1564
|
+
// packages/providers/PreloaderProvider.jsx
|
|
1565
|
+
var import_react17 = __toESM(require("react"), 1);
|
|
1566
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1567
|
+
var PreloaderContext = (0, import_react17.createContext)(null);
|
|
1568
|
+
var defaultContextValue2 = {
|
|
1569
|
+
phase: "hidden",
|
|
1570
|
+
setPhase: () => {
|
|
1571
|
+
},
|
|
1572
|
+
isInitialLoad: false
|
|
1573
|
+
};
|
|
1574
|
+
function PreloaderProvider({ children }) {
|
|
1575
|
+
const [phase, setPhase] = (0, import_react17.useState)("loading");
|
|
1576
|
+
const [isInitialLoad, setIsInitialLoad] = (0, import_react17.useState)(true);
|
|
1577
|
+
(0, import_react17.useEffect)(() => {
|
|
1578
|
+
if (phase === "revealing") {
|
|
1579
|
+
const timer = setTimeout(() => {
|
|
1580
|
+
setPhase("hidden");
|
|
1581
|
+
setIsInitialLoad(false);
|
|
1582
|
+
}, 200);
|
|
1583
|
+
return () => clearTimeout(timer);
|
|
1584
|
+
}
|
|
1585
|
+
}, [phase]);
|
|
1586
|
+
const contextValue = (0, import_react17.useMemo)(() => ({
|
|
1587
|
+
phase,
|
|
1588
|
+
setPhase,
|
|
1589
|
+
isInitialLoad
|
|
1590
|
+
}), [phase, isInitialLoad]);
|
|
1591
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PreloaderContext.Provider, { value: contextValue, children });
|
|
1592
|
+
}
|
|
1593
|
+
function usePreloader() {
|
|
1594
|
+
return (0, import_react17.useContext)(PreloaderContext) ?? defaultContextValue2;
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
// packages/animations/Preloader.jsx
|
|
1598
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1599
|
+
function Preloader() {
|
|
1600
|
+
const { phase, setPhase, isInitialLoad } = usePreloader();
|
|
1601
|
+
const containerRef = (0, import_react18.useRef)(null);
|
|
1602
|
+
const contentRef = (0, import_react18.useRef)(null);
|
|
1603
|
+
const squaresContainerRef = (0, import_react18.useRef)(null);
|
|
1604
|
+
const squaresRefs = (0, import_react18.useRef)([]);
|
|
1605
|
+
const onReadyRef = (0, import_react18.useRef)(null);
|
|
1606
|
+
const timelineRef = (0, import_react18.useRef)(null);
|
|
1607
|
+
const hasStartedRef = (0, import_react18.useRef)(false);
|
|
1608
|
+
const [isReducedMotion, setIsReducedMotion] = (0, import_react18.useState)(false);
|
|
1609
|
+
(0, import_react18.useEffect)(() => {
|
|
1610
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
1611
|
+
setIsReducedMotion(mediaQuery.matches);
|
|
1612
|
+
const handleChange = (e) => setIsReducedMotion(e.matches);
|
|
1613
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
1614
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
1615
|
+
}, []);
|
|
1616
|
+
const handleReady = (readyFn) => {
|
|
1617
|
+
onReadyRef.current = readyFn;
|
|
1618
|
+
};
|
|
1619
|
+
(0, import_react.useGSAP)(() => {
|
|
1620
|
+
if (!isInitialLoad || phase !== "loading" || hasStartedRef.current) return;
|
|
1621
|
+
if (isReducedMotion) {
|
|
1622
|
+
setPhase("complete");
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
const squares = squaresRefs.current.filter(Boolean);
|
|
1626
|
+
if (squares.length === 0) return;
|
|
1627
|
+
hasStartedRef.current = true;
|
|
1628
|
+
let timeoutId;
|
|
1629
|
+
const runAnimation = () => {
|
|
1630
|
+
var _a, _b;
|
|
1631
|
+
if (!onReadyRef.current) {
|
|
1632
|
+
requestAnimationFrame(runAnimation);
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
timelineRef.current = import_gsap.default.timeline();
|
|
1636
|
+
onReadyRef.current();
|
|
1637
|
+
squares.forEach((square, index) => {
|
|
1638
|
+
var _a2;
|
|
1639
|
+
(_a2 = timelineRef.current) == null ? void 0 : _a2.fromTo(
|
|
1640
|
+
square,
|
|
1641
|
+
{
|
|
1642
|
+
x: index === 0 ? -16 : (index - 1) * 18,
|
|
1643
|
+
rotate: 0
|
|
1644
|
+
},
|
|
1645
|
+
{
|
|
1646
|
+
x: index * 18 - 16,
|
|
1647
|
+
rotate: 90,
|
|
1648
|
+
duration: 0.7,
|
|
1649
|
+
ease: "expo.inOut",
|
|
1650
|
+
immediateRender: false
|
|
1651
|
+
},
|
|
1652
|
+
index === 0 ? 0 : ">-25%"
|
|
1653
|
+
);
|
|
1654
|
+
});
|
|
1655
|
+
const timeOffset = 2.2749999999999995;
|
|
1656
|
+
(_a = timelineRef.current) == null ? void 0 : _a.to(
|
|
1657
|
+
contentRef.current,
|
|
1658
|
+
{ opacity: 0, duration: 0.4, ease: "power3.out" },
|
|
1659
|
+
timeOffset + 0.2
|
|
1660
|
+
);
|
|
1661
|
+
const clipState = { value: 0 };
|
|
1662
|
+
const eventState = { value: false };
|
|
1663
|
+
(_b = timelineRef.current) == null ? void 0 : _b.to(
|
|
1664
|
+
clipState,
|
|
1665
|
+
{
|
|
1666
|
+
value: 1,
|
|
1667
|
+
duration: 1.5,
|
|
1668
|
+
ease: "expo.inOut",
|
|
1669
|
+
onUpdate: () => {
|
|
1670
|
+
if (containerRef.current) {
|
|
1671
|
+
const val = clipState.value;
|
|
1672
|
+
containerRef.current.style.clipPath = val <= 0 ? "polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%)" : val >= 1 ? "polygon(0% 100%, 0% 100%, 0% 100%)" : val <= 0.5 ? `polygon(0% 100%, ${2 * val * 100}% 0%, 100% 0%, 100% 100%)` : `polygon(0% 100%, 100% ${(val - 0.5) * 200}%, 100% 100%)`;
|
|
1673
|
+
}
|
|
1674
|
+
if (!eventState.value && clipState.value >= 0.9) {
|
|
1675
|
+
eventState.value = true;
|
|
1676
|
+
setPhase("revealing");
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
},
|
|
1680
|
+
timeOffset
|
|
1681
|
+
);
|
|
1682
|
+
};
|
|
1683
|
+
timeoutId = setTimeout(runAnimation, 100);
|
|
1684
|
+
return () => {
|
|
1685
|
+
var _a;
|
|
1686
|
+
clearTimeout(timeoutId);
|
|
1687
|
+
(_a = timelineRef.current) == null ? void 0 : _a.kill();
|
|
1688
|
+
};
|
|
1689
|
+
}, { dependencies: [isInitialLoad, isReducedMotion, setPhase] });
|
|
1690
|
+
if (!isInitialLoad || phase === "hidden") return null;
|
|
1691
|
+
const pointerEventsClass = phase === "complete" ? "pointer-events-none" : "";
|
|
1692
|
+
const containerClasses = cx("fixed inset-0 z-[10000] flex items-center justify-center bg-background", pointerEventsClass);
|
|
1693
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { ref: containerRef, "data-theme": "brand", className: containerClasses, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { ref: contentRef, className: "flex flex-col items-center gap-4", children: [
|
|
1694
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1695
|
+
"div",
|
|
1696
|
+
{
|
|
1697
|
+
ref: squaresContainerRef,
|
|
1698
|
+
className: "relative overflow-x-clip overflow-y-visible",
|
|
1699
|
+
style: { width: 70, height: 16 },
|
|
1700
|
+
children: [0, 1, 2, 3].map((index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1701
|
+
"div",
|
|
1702
|
+
{
|
|
1703
|
+
ref: (el) => {
|
|
1704
|
+
squaresRefs.current[index] = el;
|
|
1705
|
+
},
|
|
1706
|
+
className: "absolute top-0 left-0 bg-foreground",
|
|
1707
|
+
style: {
|
|
1708
|
+
width: 16,
|
|
1709
|
+
height: 16,
|
|
1710
|
+
transform: "translateX(-16px)",
|
|
1711
|
+
transformOrigin: "bottom right"
|
|
1712
|
+
}
|
|
1713
|
+
},
|
|
1714
|
+
index
|
|
1715
|
+
))
|
|
1716
|
+
}
|
|
1717
|
+
) }),
|
|
1718
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ScrambleText, { revealMode: true, duration: 1, onReady: handleReady, children: "LOADING" }) }) })
|
|
1719
|
+
] }) });
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
// packages/providers/PageEnterProvider.jsx
|
|
1723
|
+
var import_react19 = __toESM(require("react"), 1);
|
|
1724
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1725
|
+
var PageEnterContext = (0, import_react19.createContext)(null);
|
|
1726
|
+
function sortByPriority(a, b) {
|
|
1727
|
+
return a.priority - b.priority;
|
|
1728
|
+
}
|
|
1729
|
+
function PageEnterProvider({ children }) {
|
|
1730
|
+
const { phase: pageTransitionPhase } = usePageTransition();
|
|
1731
|
+
const { phase: preloaderPhase } = usePreloader();
|
|
1732
|
+
const [phase, setPhase] = (0, import_react19.useState)("waiting");
|
|
1733
|
+
const [prefersReducedMotion, setPrefersReducedMotion] = (0, import_react19.useState)(false);
|
|
1734
|
+
const callbacksMapRef = (0, import_react19.useRef)(/* @__PURE__ */ new Map());
|
|
1735
|
+
const isTriggeringRef = (0, import_react19.useRef)(false);
|
|
1736
|
+
(0, import_react19.useEffect)(() => {
|
|
1737
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
1738
|
+
setPrefersReducedMotion(mediaQuery.matches);
|
|
1739
|
+
const handleMediaQueryChange = (e) => setPrefersReducedMotion(e.matches);
|
|
1740
|
+
mediaQuery.addEventListener("change", handleMediaQueryChange);
|
|
1741
|
+
return () => {
|
|
1742
|
+
mediaQuery.removeEventListener("change", handleMediaQueryChange);
|
|
1743
|
+
};
|
|
1744
|
+
}, []);
|
|
1745
|
+
const register = (0, import_react19.useCallback)((id, trigger, priority = 0) => {
|
|
1746
|
+
callbacksMapRef.current.set(id, { id, trigger, priority });
|
|
1747
|
+
}, []);
|
|
1748
|
+
const unregister = (0, import_react19.useCallback)((id) => {
|
|
1749
|
+
callbacksMapRef.current.delete(id);
|
|
1750
|
+
}, []);
|
|
1751
|
+
const triggerEnter = (0, import_react19.useCallback)(() => {
|
|
1752
|
+
if (isTriggeringRef.current) {
|
|
1753
|
+
return;
|
|
1754
|
+
}
|
|
1755
|
+
isTriggeringRef.current = true;
|
|
1756
|
+
setPhase("entering");
|
|
1757
|
+
const callbacks = Array.from(callbacksMapRef.current.values());
|
|
1758
|
+
callbacks.sort(sortByPriority);
|
|
1759
|
+
let lastPriority = null;
|
|
1760
|
+
let staggerIndex = 0;
|
|
1761
|
+
for (const item of callbacks) {
|
|
1762
|
+
if (lastPriority !== null && item.priority > lastPriority) {
|
|
1763
|
+
staggerIndex += 0.08;
|
|
1764
|
+
}
|
|
1765
|
+
lastPriority = item.priority;
|
|
1766
|
+
item.trigger(staggerIndex);
|
|
1767
|
+
}
|
|
1768
|
+
setTimeout(() => {
|
|
1769
|
+
setPhase("complete");
|
|
1770
|
+
}, 1e3 * (staggerIndex + 1));
|
|
1771
|
+
}, []);
|
|
1772
|
+
(0, import_react19.useEffect)(() => {
|
|
1773
|
+
const isPreloaderReady = preloaderPhase === "revealing" || preloaderPhase === "hidden";
|
|
1774
|
+
if ((pageTransitionPhase === "exiting" || pageTransitionPhase === "idle") && phase === "waiting" && isPreloaderReady) {
|
|
1775
|
+
const timerId = setTimeout(() => {
|
|
1776
|
+
triggerEnter();
|
|
1777
|
+
}, 250);
|
|
1778
|
+
return () => clearTimeout(timerId);
|
|
1779
|
+
}
|
|
1780
|
+
}, [pageTransitionPhase, preloaderPhase, phase, triggerEnter]);
|
|
1781
|
+
(0, import_react19.useEffect)(() => {
|
|
1782
|
+
if (pageTransitionPhase === "entering" || pageTransitionPhase === "holding") {
|
|
1783
|
+
setPhase("waiting");
|
|
1784
|
+
isTriggeringRef.current = false;
|
|
1785
|
+
}
|
|
1786
|
+
}, [pageTransitionPhase]);
|
|
1787
|
+
const contextValue = (0, import_react19.useMemo)(() => ({
|
|
1788
|
+
phase,
|
|
1789
|
+
register,
|
|
1790
|
+
unregister,
|
|
1791
|
+
prefersReducedMotion
|
|
1792
|
+
}), [phase, register, unregister, prefersReducedMotion]);
|
|
1793
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(PageEnterContext.Provider, { value: contextValue, children });
|
|
1794
|
+
}
|
|
1795
|
+
var defaultContextValue3 = {
|
|
1796
|
+
phase: "complete",
|
|
1797
|
+
register: () => {
|
|
1798
|
+
},
|
|
1799
|
+
unregister: () => {
|
|
1800
|
+
},
|
|
1801
|
+
prefersReducedMotion: false
|
|
1802
|
+
};
|
|
1803
|
+
function usePageEnterContext() {
|
|
1804
|
+
return (0, import_react19.useContext)(PageEnterContext) ?? defaultContextValue3;
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
// libs/hooks/usePageEnter.js
|
|
1808
|
+
var import_react20 = require("react");
|
|
1809
|
+
function usePageEnter(callback, options = {}) {
|
|
1810
|
+
const { priority = 0, skip = false } = options;
|
|
1811
|
+
const {
|
|
1812
|
+
register,
|
|
1813
|
+
unregister,
|
|
1814
|
+
phase,
|
|
1815
|
+
prefersReducedMotion
|
|
1816
|
+
} = usePageEnterContext();
|
|
1817
|
+
const uuid = (0, import_react20.useMemo)(() => crypto.randomUUID(), []);
|
|
1818
|
+
const idRef = (0, import_react20.useRef)(uuid);
|
|
1819
|
+
(0, import_react20.useEffect)(() => {
|
|
1820
|
+
if (skip) {
|
|
1821
|
+
return;
|
|
1822
|
+
}
|
|
1823
|
+
const currentId = idRef.current;
|
|
1824
|
+
register(currentId, callback, priority);
|
|
1825
|
+
return () => {
|
|
1826
|
+
unregister(currentId);
|
|
1827
|
+
};
|
|
1828
|
+
}, [register, unregister, callback, priority, skip]);
|
|
1829
|
+
const isEntering = phase === "entering";
|
|
1830
|
+
const isComplete = phase === "complete";
|
|
1831
|
+
const returnedState = (0, import_react20.useMemo)(() => ({
|
|
1832
|
+
phase,
|
|
1833
|
+
prefersReducedMotion,
|
|
1834
|
+
isEntering,
|
|
1835
|
+
isComplete
|
|
1836
|
+
}), [phase, prefersReducedMotion, isEntering, isComplete]);
|
|
1837
|
+
return returnedState;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
// libs/hooks/useBreakpoint.js
|
|
1841
|
+
var import_react21 = require("react");
|
|
1842
|
+
var BREAKPOINTS = {
|
|
1843
|
+
sm: 640,
|
|
1844
|
+
md: 768,
|
|
1845
|
+
lg: 1024,
|
|
1846
|
+
xl: 1280,
|
|
1847
|
+
"2xl": 1536
|
|
1848
|
+
};
|
|
1849
|
+
function useBreakpoint(breakpoint = "md") {
|
|
1850
|
+
const minWidth = BREAKPOINTS[breakpoint] ?? BREAKPOINTS.md;
|
|
1851
|
+
const [matches, setMatches] = (0, import_react21.useState)(() => {
|
|
1852
|
+
if (typeof window === "undefined") return false;
|
|
1853
|
+
return window.matchMedia(`(min-width: ${minWidth}px)`).matches;
|
|
1854
|
+
});
|
|
1855
|
+
(0, import_react21.useEffect)(() => {
|
|
1856
|
+
const mediaQuery = window.matchMedia(`(min-width: ${minWidth}px)`);
|
|
1857
|
+
const handleChange = (event) => setMatches(event.matches);
|
|
1858
|
+
setMatches(mediaQuery.matches);
|
|
1859
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
1860
|
+
return () => {
|
|
1861
|
+
mediaQuery.removeEventListener("change", handleChange);
|
|
1862
|
+
};
|
|
1863
|
+
}, [minWidth]);
|
|
1864
|
+
return matches;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
// libs/constants/timing.js
|
|
1868
|
+
var ASCII_REVEAL_DURATION = 1.2;
|
|
1869
|
+
|
|
1870
|
+
// libs/hooks/useAsciiDelay.js
|
|
1871
|
+
var asciiDelayBase = 0.1 * ASCII_REVEAL_DURATION;
|
|
1872
|
+
function useAsciiDelay() {
|
|
1873
|
+
const md = useBreakpoint("md");
|
|
1874
|
+
return md ? asciiDelayBase : 0;
|
|
1875
|
+
}
|
|
1876
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1877
|
+
0 && (module.exports = {
|
|
1878
|
+
AnimatedButton,
|
|
1879
|
+
AnimatedHeadline,
|
|
1880
|
+
AnimatedLink,
|
|
1881
|
+
AnimatedProse,
|
|
1882
|
+
AnimatedProseContext,
|
|
1883
|
+
AnimatedSubtext,
|
|
1884
|
+
AnimatedText,
|
|
1885
|
+
DEFAULT_CHARS,
|
|
1886
|
+
LenisProvider,
|
|
1887
|
+
PageEnterProvider,
|
|
1888
|
+
PageTransitionProvider,
|
|
1889
|
+
Preloader,
|
|
1890
|
+
PreloaderProvider,
|
|
1891
|
+
ScrambleGroup,
|
|
1892
|
+
ScrambleText,
|
|
1893
|
+
ScrambleTextPlugin,
|
|
1894
|
+
ScrollAnimatedHeadline,
|
|
1895
|
+
ScrollTrigger,
|
|
1896
|
+
SplitText,
|
|
1897
|
+
cva,
|
|
1898
|
+
cx,
|
|
1899
|
+
easingDefinitionToFunction,
|
|
1900
|
+
getCssScrollLocked,
|
|
1901
|
+
getLenis,
|
|
1902
|
+
gsap,
|
|
1903
|
+
scrollToTop,
|
|
1904
|
+
setCssScrollLocked,
|
|
1905
|
+
stagger,
|
|
1906
|
+
useAsciiDelay,
|
|
1907
|
+
useDualLayerScramble,
|
|
1908
|
+
useGSAP,
|
|
1909
|
+
useIdleGSAP,
|
|
1910
|
+
useLenis,
|
|
1911
|
+
usePageEnter,
|
|
1912
|
+
usePageEnterContext,
|
|
1913
|
+
usePageTransition,
|
|
1914
|
+
usePageTransitionContext,
|
|
1915
|
+
usePreloader,
|
|
1916
|
+
useScrambleGroup
|
|
1917
|
+
});
|
|
1918
|
+
//# sourceMappingURL=index.cjs.map
|