@hua-labs/motion-core 2.3.0 → 2.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,559 +1,9 @@
1
1
  "use client";
2
- import { createContext, useState, useRef, useCallback, useEffect, useMemo, createElement, useContext } from 'react';
2
+ import { getPagePreset, getMotionPreset, mergeWithPreset, motionStateManager, MOTION_PRESETS, useMotionProfile, getEasing, calculateSpring } from './chunk-47QAGQLN.mjs';
3
+ export { MOTION_PRESETS, MotionEngine, MotionProfileProvider, PAGE_MOTIONS, TransitionEffects, applyEasing, calculateSpring, easeIn, easeInOut, easeInOutQuad, easeInQuad, easeOut, easeOutQuad, easingPresets, getAvailableEasings, getEasing, getMotionPreset, getPagePreset, getPresetEasing, hua, isEasingFunction, isValidEasing, linear, mergeProfileOverrides, mergeWithPreset, motionEngine, neutral, resolveProfile, safeApplyEasing, transitionEffects, useMotionProfile } from './chunk-47QAGQLN.mjs';
4
+ import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
3
5
  import { jsx } from 'react/jsx-runtime';
4
6
 
5
- // src/core/MotionEngine.ts
6
- var MotionEngine = class {
7
- constructor() {
8
- this.motions = /* @__PURE__ */ new Map();
9
- this.isRunning = false;
10
- this.animationFrameId = null;
11
- }
12
- /**
13
- * 모션 시작
14
- */
15
- motion(element, motionFrames, options) {
16
- return new Promise((resolve) => {
17
- const motionId = this.generateMotionId();
18
- this.enableGPUAcceleration(element);
19
- this.createLayer(element);
20
- const motion = {
21
- id: motionId,
22
- element,
23
- isRunning: true,
24
- isPaused: false,
25
- currentProgress: 0,
26
- startTime: Date.now() + (options.delay || 0),
27
- pauseTime: 0,
28
- options: {
29
- ...options,
30
- onComplete: () => {
31
- options.onComplete?.();
32
- this.motions.delete(motionId);
33
- }
34
- }
35
- };
36
- this.motions.set(motionId, motion);
37
- if (!this.isRunning) {
38
- this.startAnimationLoop();
39
- }
40
- options.onStart?.();
41
- resolve(motionId);
42
- });
43
- }
44
- /**
45
- * 모션 중지
46
- */
47
- stop(motionId) {
48
- const motion = this.motions.get(motionId);
49
- if (motion) {
50
- motion.isRunning = false;
51
- motion.options.onCancel?.();
52
- this.motions.delete(motionId);
53
- }
54
- }
55
- /**
56
- * 모션 일시정지
57
- */
58
- pause(motionId) {
59
- const motion = this.motions.get(motionId);
60
- if (motion && motion.isRunning && !motion.isPaused) {
61
- motion.isPaused = true;
62
- motion.pauseTime = Date.now();
63
- }
64
- }
65
- /**
66
- * 모션 재개
67
- */
68
- resume(motionId) {
69
- const motion = this.motions.get(motionId);
70
- if (motion && motion.isPaused) {
71
- motion.isPaused = false;
72
- if (motion.pauseTime > 0) {
73
- motion.startTime += Date.now() - motion.pauseTime;
74
- }
75
- }
76
- }
77
- /**
78
- * 모든 모션 중지
79
- */
80
- stopAll() {
81
- this.motions.forEach((motion) => {
82
- motion.isRunning = false;
83
- motion.options.onCancel?.();
84
- });
85
- this.motions.clear();
86
- this.stopAnimationLoop();
87
- }
88
- /**
89
- * 모션 상태 확인
90
- */
91
- getMotion(motionId) {
92
- return this.motions.get(motionId);
93
- }
94
- /**
95
- * 실행 중인 모션 수
96
- */
97
- getActiveMotionCount() {
98
- return this.motions.size;
99
- }
100
- /**
101
- * 애니메이션 루프 시작
102
- */
103
- startAnimationLoop() {
104
- if (this.isRunning) return;
105
- this.isRunning = true;
106
- this.animate();
107
- }
108
- /**
109
- * 애니메이션 루프 중지
110
- */
111
- stopAnimationLoop() {
112
- if (this.animationFrameId) {
113
- cancelAnimationFrame(this.animationFrameId);
114
- this.animationFrameId = null;
115
- }
116
- this.isRunning = false;
117
- }
118
- /**
119
- * 메인 애니메이션 루프
120
- */
121
- animate() {
122
- if (!this.isRunning || this.motions.size === 0) {
123
- this.stopAnimationLoop();
124
- return;
125
- }
126
- const currentTime = Date.now();
127
- const completedMotions = [];
128
- this.motions.forEach((motion) => {
129
- if (!motion.isRunning || motion.isPaused) return;
130
- const elapsed = currentTime - motion.startTime;
131
- if (elapsed < 0) return;
132
- const progress = Math.min(elapsed / motion.options.duration, 1);
133
- const easedProgress = motion.options.easing(progress);
134
- motion.currentProgress = easedProgress;
135
- this.applyMotionFrame(motion.element, easedProgress);
136
- motion.options.onUpdate?.(easedProgress);
137
- if (progress >= 1) {
138
- completedMotions.push(motion.id);
139
- motion.isRunning = false;
140
- motion.options.onComplete?.();
141
- }
142
- });
143
- completedMotions.forEach((id) => this.motions.delete(id));
144
- this.animationFrameId = requestAnimationFrame(() => this.animate());
145
- }
146
- /**
147
- * 모션 프레임 적용
148
- */
149
- applyMotionFrame(element, progress) {
150
- const transforms = [];
151
- if (element.style.transform) {
152
- transforms.push(element.style.transform);
153
- }
154
- element.style.transform = transforms.join(" ");
155
- }
156
- /**
157
- * GPU 가속 활성화
158
- */
159
- enableGPUAcceleration(element) {
160
- element.style.willChange = "transform, opacity";
161
- element.style.transform = "translateZ(0)";
162
- }
163
- /**
164
- * 레이어 분리
165
- */
166
- createLayer(element) {
167
- element.style.transform = "translateZ(0)";
168
- element.style.backfaceVisibility = "hidden";
169
- }
170
- /**
171
- * 고유 모션 ID 생성
172
- */
173
- generateMotionId() {
174
- return `motion_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
175
- }
176
- /**
177
- * 정리
178
- */
179
- destroy() {
180
- this.stopAll();
181
- this.stopAnimationLoop();
182
- }
183
- };
184
- var motionEngine = new MotionEngine();
185
-
186
- // src/core/TransitionEffects.ts
187
- var TransitionEffects = class _TransitionEffects {
188
- constructor() {
189
- this.activeTransitions = /* @__PURE__ */ new Map();
190
- }
191
- static getInstance() {
192
- if (!_TransitionEffects.instance) {
193
- _TransitionEffects.instance = new _TransitionEffects();
194
- }
195
- return _TransitionEffects.instance;
196
- }
197
- /**
198
- * 공통 전환 실행 헬퍼
199
- */
200
- async executeTransition(element, options, config) {
201
- const transitionId = this.generateTransitionId();
202
- config.setup();
203
- this.enableGPUAcceleration(element);
204
- let resolveTransition;
205
- const completed = new Promise((resolve) => {
206
- resolveTransition = resolve;
207
- });
208
- const motionId = await motionEngine.motion(
209
- element,
210
- [
211
- { progress: 0, properties: config.keyframes[0] },
212
- { progress: 1, properties: config.keyframes[1] }
213
- ],
214
- {
215
- duration: options.duration,
216
- easing: options.easing || this.getDefaultEasing(),
217
- delay: options.delay,
218
- onStart: options.onTransitionStart,
219
- onUpdate: config.onUpdate,
220
- onComplete: () => {
221
- config.onCleanup();
222
- options.onTransitionComplete?.();
223
- this.activeTransitions.delete(transitionId);
224
- resolveTransition();
225
- }
226
- }
227
- );
228
- this.activeTransitions.set(transitionId, motionId);
229
- return completed;
230
- }
231
- /**
232
- * 페이드 인/아웃 전환
233
- */
234
- async fade(element, options) {
235
- const initialOpacity = parseFloat(getComputedStyle(element).opacity) || 1;
236
- const targetOpacity = options.direction === "reverse" ? 0 : 1;
237
- return this.executeTransition(element, options, {
238
- setup: () => {
239
- if (options.direction === "reverse") {
240
- element.style.opacity = initialOpacity.toString();
241
- } else {
242
- element.style.opacity = "0";
243
- }
244
- },
245
- keyframes: [
246
- { opacity: options.direction === "reverse" ? initialOpacity : 0 },
247
- { opacity: targetOpacity }
248
- ],
249
- onUpdate: (progress) => {
250
- const currentOpacity = options.direction === "reverse" ? initialOpacity * (1 - progress) : targetOpacity * progress;
251
- element.style.opacity = currentOpacity.toString();
252
- },
253
- onCleanup: () => {
254
- }
255
- });
256
- }
257
- /**
258
- * 슬라이드 전환
259
- */
260
- async slide(element, options) {
261
- const distance = options.distance || 100;
262
- const initialTransform = getComputedStyle(element).transform;
263
- const isReverse = options.direction === "reverse";
264
- return this.executeTransition(element, options, {
265
- setup: () => {
266
- if (!isReverse) {
267
- element.style.transform = `translateX(${distance}px)`;
268
- }
269
- },
270
- keyframes: [
271
- { translateX: isReverse ? 0 : distance },
272
- { translateX: isReverse ? distance : 0 }
273
- ],
274
- onUpdate: (progress) => {
275
- const currentTranslateX = isReverse ? distance * progress : distance * (1 - progress);
276
- element.style.transform = `translateX(${currentTranslateX}px)`;
277
- },
278
- onCleanup: () => {
279
- element.style.transform = initialTransform;
280
- }
281
- });
282
- }
283
- /**
284
- * 스케일 전환
285
- */
286
- async scale(element, options) {
287
- const scaleValue = options.scale || 0.8;
288
- const initialTransform = getComputedStyle(element).transform;
289
- const isReverse = options.direction === "reverse";
290
- return this.executeTransition(element, options, {
291
- setup: () => {
292
- if (!isReverse) {
293
- element.style.transform = `scale(${scaleValue})`;
294
- }
295
- },
296
- keyframes: [
297
- { scale: isReverse ? 1 : scaleValue },
298
- { scale: isReverse ? scaleValue : 1 }
299
- ],
300
- onUpdate: (progress) => {
301
- const currentScale = isReverse ? 1 - (1 - scaleValue) * progress : scaleValue + (1 - scaleValue) * progress;
302
- element.style.transform = `scale(${currentScale})`;
303
- },
304
- onCleanup: () => {
305
- element.style.transform = initialTransform;
306
- }
307
- });
308
- }
309
- /**
310
- * 플립 전환 (3D 회전)
311
- */
312
- async flip(element, options) {
313
- const perspective = options.perspective || 1e3;
314
- const initialTransform = getComputedStyle(element).transform;
315
- const isReverse = options.direction === "reverse";
316
- return this.executeTransition(element, options, {
317
- setup: () => {
318
- element.style.perspective = `${perspective}px`;
319
- element.style.transformStyle = "preserve-3d";
320
- if (!isReverse) {
321
- element.style.transform = `rotateY(90deg)`;
322
- }
323
- },
324
- keyframes: [
325
- { rotateY: isReverse ? 0 : 90 },
326
- { rotateY: isReverse ? 90 : 0 }
327
- ],
328
- onUpdate: (progress) => {
329
- const currentRotateY = isReverse ? 90 * progress : 90 * (1 - progress);
330
- element.style.transform = `rotateY(${currentRotateY}deg)`;
331
- },
332
- onCleanup: () => {
333
- element.style.transform = initialTransform;
334
- element.style.perspective = "";
335
- element.style.transformStyle = "";
336
- }
337
- });
338
- }
339
- /**
340
- * 큐브 전환 (3D 큐브 회전)
341
- */
342
- async cube(element, options) {
343
- const perspective = options.perspective || 1200;
344
- const initialTransform = getComputedStyle(element).transform;
345
- const isReverse = options.direction === "reverse";
346
- return this.executeTransition(element, options, {
347
- setup: () => {
348
- element.style.perspective = `${perspective}px`;
349
- element.style.transformStyle = "preserve-3d";
350
- if (!isReverse) {
351
- element.style.transform = `rotateX(90deg) rotateY(45deg)`;
352
- }
353
- },
354
- keyframes: [
355
- { rotateX: isReverse ? 0 : 90, rotateY: isReverse ? 0 : 45 },
356
- { rotateX: isReverse ? 90 : 0, rotateY: isReverse ? 45 : 0 }
357
- ],
358
- onUpdate: (progress) => {
359
- const currentRotateX = isReverse ? 90 * progress : 90 * (1 - progress);
360
- const currentRotateY = isReverse ? 45 * progress : 45 * (1 - progress);
361
- element.style.transform = `rotateX(${currentRotateX}deg) rotateY(${currentRotateY}deg)`;
362
- },
363
- onCleanup: () => {
364
- element.style.transform = initialTransform;
365
- element.style.perspective = "";
366
- element.style.transformStyle = "";
367
- }
368
- });
369
- }
370
- /**
371
- * 모프 전환 (복합 변형)
372
- */
373
- async morph(element, options) {
374
- const initialTransform = getComputedStyle(element).transform;
375
- const isReverse = options.direction === "reverse";
376
- return this.executeTransition(element, options, {
377
- setup: () => {
378
- if (!isReverse) {
379
- element.style.transform = `scale(0.9) rotate(5deg)`;
380
- }
381
- },
382
- keyframes: [
383
- { scale: isReverse ? 1 : 0.9, rotate: isReverse ? 0 : 5 },
384
- { scale: isReverse ? 0.9 : 1, rotate: isReverse ? 5 : 0 }
385
- ],
386
- onUpdate: (progress) => {
387
- const currentScale = isReverse ? 1 - 0.1 * progress : 0.9 + 0.1 * progress;
388
- const currentRotate = isReverse ? 5 * progress : 5 * (1 - progress);
389
- element.style.transform = `scale(${currentScale}) rotate(${currentRotate}deg)`;
390
- },
391
- onCleanup: () => {
392
- element.style.transform = initialTransform;
393
- }
394
- });
395
- }
396
- /**
397
- * 전환 중지
398
- */
399
- stopTransition(transitionId) {
400
- const motionId = this.activeTransitions.get(transitionId);
401
- if (motionId) {
402
- motionEngine.stop(motionId);
403
- this.activeTransitions.delete(transitionId);
404
- }
405
- }
406
- /**
407
- * 모든 전환 중지
408
- */
409
- stopAllTransitions() {
410
- this.activeTransitions.forEach((motionId) => {
411
- motionEngine.stop(motionId);
412
- });
413
- this.activeTransitions.clear();
414
- }
415
- /**
416
- * 활성 전환 수 확인
417
- */
418
- getActiveTransitionCount() {
419
- return this.activeTransitions.size;
420
- }
421
- /**
422
- * GPU 가속 활성화
423
- */
424
- enableGPUAcceleration(element) {
425
- element.style.willChange = "transform, opacity";
426
- const currentTransform = element.style.transform;
427
- if (currentTransform && currentTransform !== "none" && currentTransform !== "") {
428
- if (!currentTransform.includes("translateZ")) {
429
- element.style.transform = `${currentTransform} translateZ(0)`;
430
- }
431
- } else {
432
- element.style.transform = "translateZ(0)";
433
- }
434
- }
435
- /**
436
- * 기본 이징 함수
437
- */
438
- getDefaultEasing() {
439
- return (t) => t * t * (3 - 2 * t);
440
- }
441
- /**
442
- * 고유 전환 ID 생성
443
- */
444
- generateTransitionId() {
445
- return `transition_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
446
- }
447
- /**
448
- * 정리
449
- */
450
- destroy() {
451
- this.stopAllTransitions();
452
- }
453
- };
454
- var transitionEffects = TransitionEffects.getInstance();
455
-
456
- // src/presets/index.ts
457
- var MOTION_PRESETS = {
458
- hero: {
459
- entrance: "fadeIn",
460
- delay: 200,
461
- duration: 800,
462
- hover: false,
463
- click: false
464
- },
465
- title: {
466
- entrance: "slideUp",
467
- delay: 400,
468
- duration: 700,
469
- hover: false,
470
- click: false
471
- },
472
- button: {
473
- entrance: "scaleIn",
474
- delay: 600,
475
- duration: 300,
476
- hover: true,
477
- click: true
478
- },
479
- card: {
480
- entrance: "slideUp",
481
- delay: 800,
482
- duration: 500,
483
- hover: true,
484
- click: false
485
- },
486
- text: {
487
- entrance: "fadeIn",
488
- delay: 200,
489
- duration: 600,
490
- hover: false,
491
- click: false
492
- },
493
- image: {
494
- entrance: "scaleIn",
495
- delay: 400,
496
- duration: 600,
497
- hover: true,
498
- click: false
499
- }
500
- };
501
- var PAGE_MOTIONS = {
502
- // 홈페이지
503
- home: {
504
- hero: { type: "hero" },
505
- title: { type: "title" },
506
- description: { type: "text" },
507
- cta: { type: "button" },
508
- feature1: { type: "card" },
509
- feature2: { type: "card" },
510
- feature3: { type: "card" }
511
- },
512
- // 대시보드
513
- dashboard: {
514
- header: { type: "hero" },
515
- sidebar: { type: "card", entrance: "slideLeft" },
516
- main: { type: "text", entrance: "fadeIn" },
517
- card1: { type: "card" },
518
- card2: { type: "card" },
519
- card3: { type: "card" },
520
- chart: { type: "image" }
521
- },
522
- // 제품 페이지
523
- product: {
524
- hero: { type: "hero" },
525
- title: { type: "title" },
526
- image: { type: "image" },
527
- description: { type: "text" },
528
- price: { type: "text" },
529
- buyButton: { type: "button" },
530
- features: { type: "card" }
531
- },
532
- // 블로그
533
- blog: {
534
- header: { type: "hero" },
535
- title: { type: "title" },
536
- content: { type: "text" },
537
- sidebar: { type: "card", entrance: "slideRight" },
538
- related1: { type: "card" },
539
- related2: { type: "card" },
540
- related3: { type: "card" }
541
- }
542
- };
543
- function mergeWithPreset(preset, custom = {}) {
544
- return {
545
- ...preset,
546
- ...custom
547
- };
548
- }
549
- function getPagePreset(pageType) {
550
- return PAGE_MOTIONS[pageType];
551
- }
552
- function getMotionPreset(type) {
553
- return MOTION_PRESETS[type] || MOTION_PRESETS.text;
554
- }
555
-
556
- // src/hooks/useSimplePageMotion.ts
557
7
  function useSimplePageMotion(pageType) {
558
8
  const config = getPagePreset(pageType);
559
9
  return useSimplePageMotions(config);
@@ -658,156 +108,6 @@ function useSimplePageMotions(config) {
658
108
  }, [motions]);
659
109
  return getPageMotionRefs();
660
110
  }
661
-
662
- // src/managers/MotionStateManager.ts
663
- var MotionStateManager = class {
664
- constructor() {
665
- this.states = /* @__PURE__ */ new Map();
666
- this.listeners = /* @__PURE__ */ new Map();
667
- }
668
- /**
669
- * 요소의 상태를 초기화
670
- */
671
- initializeElement(elementId, config) {
672
- const initialState = {
673
- internalVisibility: false,
674
- // 초기에 숨김 상태로 시작 (스크롤 리빌용)
675
- triggeredVisibility: false,
676
- // Intersection Observer가 아직 트리거되지 않음
677
- finalVisibility: false,
678
- // 초기에 숨김 상태로 시작
679
- opacity: 0,
680
- // 초기에 투명 상태로 시작
681
- translateY: 20,
682
- // 초기에 아래로 이동된 상태로 시작
683
- translateX: 0,
684
- scale: 0.95,
685
- // 초기에 약간 축소된 상태로 시작
686
- rotation: 0,
687
- isHovered: false,
688
- isClicked: false,
689
- isAnimating: false
690
- };
691
- this.states.set(elementId, initialState);
692
- this.computeFinalState(elementId);
693
- }
694
- /**
695
- * 내부 가시성 상태 업데이트 (초기화, 리셋 등)
696
- */
697
- setInternalVisibility(elementId, visible) {
698
- const state = this.states.get(elementId);
699
- if (!state) return;
700
- state.internalVisibility = visible;
701
- this.computeFinalState(elementId);
702
- this.notifyListeners(elementId, state);
703
- }
704
- /**
705
- * 외부 트리거 가시성 상태 업데이트 (Intersection Observer)
706
- */
707
- setTriggeredVisibility(elementId, visible) {
708
- const state = this.states.get(elementId);
709
- if (!state) return;
710
- state.triggeredVisibility = visible;
711
- this.computeFinalState(elementId);
712
- this.notifyListeners(elementId, state);
713
- }
714
- /**
715
- * 모션 값 업데이트
716
- */
717
- updateMotionValues(elementId, values) {
718
- const state = this.states.get(elementId);
719
- if (!state) return;
720
- Object.assign(state, values);
721
- this.notifyListeners(elementId, state);
722
- }
723
- /**
724
- * 최종 상태 계산
725
- */
726
- computeFinalState(elementId) {
727
- const state = this.states.get(elementId);
728
- if (!state) return;
729
- state.finalVisibility = state.internalVisibility || state.triggeredVisibility;
730
- state.isAnimating = state.finalVisibility && (state.opacity < 1 || state.translateY > 0);
731
- }
732
- /**
733
- * 현재 상태 조회
734
- */
735
- getState(elementId) {
736
- return this.states.get(elementId);
737
- }
738
- /**
739
- * 모든 상태 조회
740
- */
741
- getAllStates() {
742
- return new Map(this.states);
743
- }
744
- /**
745
- * 상태 변경 리스너 등록
746
- */
747
- subscribe(elementId, listener) {
748
- if (!this.listeners.has(elementId)) {
749
- this.listeners.set(elementId, /* @__PURE__ */ new Set());
750
- }
751
- this.listeners.get(elementId).add(listener);
752
- return () => {
753
- const listeners = this.listeners.get(elementId);
754
- if (listeners) {
755
- listeners.delete(listener);
756
- }
757
- };
758
- }
759
- /**
760
- * 리스너들에게 상태 변경 알림
761
- */
762
- notifyListeners(elementId, state) {
763
- const listeners = this.listeners.get(elementId);
764
- if (!listeners) return;
765
- listeners.forEach((listener) => {
766
- try {
767
- listener(state);
768
- } catch (error) {
769
- if (process.env.NODE_ENV === "development") {
770
- console.error(`MotionStateManager listener error for ${elementId}:`, error);
771
- }
772
- }
773
- });
774
- }
775
- /**
776
- * 모든 상태 초기화
777
- */
778
- reset() {
779
- this.states.clear();
780
- this.listeners.clear();
781
- }
782
- /**
783
- * 특정 요소 상태 초기화
784
- */
785
- resetElement(elementId) {
786
- this.states.delete(elementId);
787
- this.listeners.delete(elementId);
788
- }
789
- /**
790
- * 디버그용 상태 출력
791
- */
792
- debug() {
793
- if (process.env.NODE_ENV === "development") {
794
- console.log("MotionStateManager Debug:");
795
- this.states.forEach((state, elementId) => {
796
- console.log(` ${elementId}:`, {
797
- internalVisibility: state.internalVisibility,
798
- triggeredVisibility: state.triggeredVisibility,
799
- finalVisibility: state.finalVisibility,
800
- opacity: state.opacity,
801
- translateY: state.translateY,
802
- isAnimating: state.isAnimating
803
- });
804
- });
805
- }
806
- }
807
- };
808
- var motionStateManager = new MotionStateManager();
809
-
810
- // src/hooks/usePageMotions.ts
811
111
  function usePageMotions(config) {
812
112
  const [motions, setMotions] = useState(/* @__PURE__ */ new Map());
813
113
  const observersRef = useRef(/* @__PURE__ */ new Map());
@@ -1300,155 +600,6 @@ function useSmartMotion(options = {}) {
1300
600
  };
1301
601
  }
1302
602
 
1303
- // src/profiles/neutral.ts
1304
- var neutral = {
1305
- name: "neutral",
1306
- base: {
1307
- duration: 700,
1308
- easing: "ease-out",
1309
- threshold: 0.1,
1310
- triggerOnce: true
1311
- },
1312
- entrance: {
1313
- slide: {
1314
- distance: 32,
1315
- easing: "ease-out"
1316
- },
1317
- fade: {
1318
- initialOpacity: 0
1319
- },
1320
- scale: {
1321
- from: 0.95
1322
- },
1323
- bounce: {
1324
- intensity: 0.3,
1325
- easing: "cubic-bezier(0.34, 1.56, 0.64, 1)"
1326
- }
1327
- },
1328
- stagger: {
1329
- perItem: 100,
1330
- baseDelay: 0
1331
- },
1332
- interaction: {
1333
- hover: {
1334
- scale: 1.05,
1335
- y: -2,
1336
- duration: 200,
1337
- easing: "ease-out"
1338
- }
1339
- },
1340
- spring: {
1341
- mass: 1,
1342
- stiffness: 100,
1343
- damping: 10,
1344
- restDelta: 0.01,
1345
- restSpeed: 0.01
1346
- },
1347
- reducedMotion: "fade-only"
1348
- };
1349
-
1350
- // src/profiles/hua.ts
1351
- var hua = {
1352
- name: "hua",
1353
- base: {
1354
- duration: 640,
1355
- easing: "cubic-bezier(0.22, 0.68, 0.35, 1.10)",
1356
- threshold: 0.12,
1357
- triggerOnce: true
1358
- },
1359
- entrance: {
1360
- slide: {
1361
- distance: 28,
1362
- easing: "cubic-bezier(0.22, 0.68, 0.35, 1.14)"
1363
- },
1364
- fade: {
1365
- initialOpacity: 0
1366
- },
1367
- scale: {
1368
- from: 0.97
1369
- },
1370
- bounce: {
1371
- intensity: 0.2,
1372
- easing: "cubic-bezier(0.22, 0.68, 0.35, 1.12)"
1373
- }
1374
- },
1375
- stagger: {
1376
- perItem: 80,
1377
- baseDelay: 0
1378
- },
1379
- interaction: {
1380
- hover: {
1381
- scale: 1.008,
1382
- y: -1,
1383
- duration: 180,
1384
- easing: "cubic-bezier(0.22, 0.68, 0.35, 1.10)"
1385
- }
1386
- },
1387
- spring: {
1388
- mass: 1,
1389
- stiffness: 180,
1390
- damping: 18,
1391
- restDelta: 5e-3,
1392
- restSpeed: 5e-3
1393
- },
1394
- reducedMotion: "fade-only"
1395
- };
1396
-
1397
- // src/profiles/index.ts
1398
- var PROFILES = {
1399
- neutral,
1400
- hua
1401
- };
1402
- function resolveProfile(profile) {
1403
- if (typeof profile === "string") {
1404
- return PROFILES[profile] ?? neutral;
1405
- }
1406
- return profile;
1407
- }
1408
- function mergeProfileOverrides(base, overrides) {
1409
- return deepMerge(
1410
- base,
1411
- overrides
1412
- );
1413
- }
1414
- function deepMerge(target, source) {
1415
- const result = { ...target };
1416
- for (const key of Object.keys(source)) {
1417
- const sourceVal = source[key];
1418
- const targetVal = result[key];
1419
- if (sourceVal !== null && sourceVal !== void 0 && typeof sourceVal === "object" && !Array.isArray(sourceVal) && typeof targetVal === "object" && targetVal !== null && !Array.isArray(targetVal)) {
1420
- result[key] = deepMerge(
1421
- targetVal,
1422
- sourceVal
1423
- );
1424
- } else if (sourceVal !== void 0) {
1425
- result[key] = sourceVal;
1426
- }
1427
- }
1428
- return result;
1429
- }
1430
-
1431
- // src/profiles/MotionProfileContext.ts
1432
- var MotionProfileContext = createContext(neutral);
1433
- function MotionProfileProvider({
1434
- profile = "neutral",
1435
- overrides,
1436
- children
1437
- }) {
1438
- const resolved = useMemo(() => {
1439
- const base = resolveProfile(profile);
1440
- return overrides ? mergeProfileOverrides(base, overrides) : base;
1441
- }, [profile, overrides]);
1442
- return createElement(
1443
- MotionProfileContext.Provider,
1444
- { value: resolved },
1445
- children
1446
- );
1447
- }
1448
- function useMotionProfile() {
1449
- return useContext(MotionProfileContext);
1450
- }
1451
-
1452
603
  // src/utils/sharedIntersectionObserver.ts
1453
604
  var pool = /* @__PURE__ */ new Map();
1454
605
  function makeKey(threshold, rootMargin) {
@@ -1541,8 +692,8 @@ function getInitialStyle(type, distance) {
1541
692
  function getVisibleStyle() {
1542
693
  return { opacity: 1, transform: "none" };
1543
694
  }
1544
- function getEasingForType(type, easing2) {
1545
- if (easing2) return easing2;
695
+ function getEasingForType(type, easing) {
696
+ if (easing) return easing;
1546
697
  if (type === "bounceIn") return "cubic-bezier(0.34, 1.56, 0.64, 1)";
1547
698
  return "ease-out";
1548
699
  }
@@ -1608,8 +759,8 @@ function getMultiEffectVisibleStyle(effects) {
1608
759
  }
1609
760
  return style;
1610
761
  }
1611
- function getMultiEffectEasing(effects, easing2) {
1612
- if (easing2) return easing2;
762
+ function getMultiEffectEasing(effects, easing) {
763
+ if (easing) return easing;
1613
764
  if (effects.bounce) return "cubic-bezier(0.34, 1.56, 0.64, 1)";
1614
765
  return "ease-out";
1615
766
  }
@@ -1621,7 +772,7 @@ function useUnifiedMotion(options) {
1621
772
  duration = profile.base.duration,
1622
773
  autoStart = true,
1623
774
  delay = 0,
1624
- easing: easing2,
775
+ easing,
1625
776
  threshold = profile.base.threshold,
1626
777
  triggerOnce = profile.base.triggerOnce,
1627
778
  distance = profile.entrance.slide.distance,
@@ -1631,7 +782,7 @@ function useUnifiedMotion(options) {
1631
782
  onReset
1632
783
  } = options;
1633
784
  const resolvedType = type ?? "fadeIn";
1634
- const resolvedEasing = getEasingForType(resolvedType, easing2);
785
+ const resolvedEasing = getEasingForType(resolvedType, easing);
1635
786
  const ref = useRef(null);
1636
787
  const [isVisible, setIsVisible] = useState(false);
1637
788
  const [isAnimating, setIsAnimating] = useState(false);
@@ -1683,7 +834,7 @@ function useUnifiedMotion(options) {
1683
834
  const style = useMemo(() => {
1684
835
  if (effects) {
1685
836
  const base2 = isVisible ? getMultiEffectVisibleStyle(effects) : getMultiEffectInitialStyle(effects, distance);
1686
- const resolvedEasingMulti = getMultiEffectEasing(effects, easing2);
837
+ const resolvedEasingMulti = getMultiEffectEasing(effects, easing);
1687
838
  return {
1688
839
  ...base2,
1689
840
  transition: `all ${duration}ms ${resolvedEasingMulti}`,
@@ -1702,7 +853,7 @@ function useUnifiedMotion(options) {
1702
853
  "--motion-easing": resolvedEasing,
1703
854
  "--motion-progress": `${progress}`
1704
855
  };
1705
- }, [isVisible, type, effects, distance, duration, resolvedEasing, easing2, delay, progress, resolvedType]);
856
+ }, [isVisible, type, effects, distance, duration, resolvedEasing, easing, delay, progress, resolvedType]);
1706
857
  return {
1707
858
  ref,
1708
859
  isVisible,
@@ -1721,7 +872,7 @@ function useFadeIn(options = {}) {
1721
872
  duration = profile.base.duration,
1722
873
  threshold = profile.base.threshold,
1723
874
  triggerOnce = profile.base.triggerOnce,
1724
- easing: easing2 = profile.base.easing,
875
+ easing = profile.base.easing,
1725
876
  autoStart = true,
1726
877
  initialOpacity = profile.entrance.fade.initialOpacity,
1727
878
  targetOpacity = 1,
@@ -1791,6 +942,10 @@ function useFadeIn(options = {}) {
1791
942
  setProgress(0);
1792
943
  onReset?.();
1793
944
  }, [stop, onReset]);
945
+ const pause = useCallback(() => {
946
+ }, []);
947
+ const resume = useCallback(() => {
948
+ }, []);
1794
949
  useEffect(() => {
1795
950
  if (!ref.current || !autoStart) return;
1796
951
  return observeElement(
@@ -1807,14 +962,25 @@ function useFadeIn(options = {}) {
1807
962
  stop();
1808
963
  };
1809
964
  }, [stop]);
1810
- const style = useMemo(() => ({
1811
- opacity: isVisible ? targetOpacity : initialOpacity,
1812
- transition: `opacity ${duration}ms ${easing2}`,
1813
- "--motion-delay": `${delay}ms`,
1814
- "--motion-duration": `${duration}ms`,
1815
- "--motion-easing": easing2,
1816
- "--motion-progress": `${progress}`
1817
- }), [isVisible, targetOpacity, initialOpacity, duration, easing2, delay, progress]);
965
+ const style = useMemo(
966
+ () => ({
967
+ opacity: isVisible ? targetOpacity : initialOpacity,
968
+ transition: `opacity ${duration}ms ${easing}`,
969
+ "--motion-delay": `${delay}ms`,
970
+ "--motion-duration": `${duration}ms`,
971
+ "--motion-easing": easing,
972
+ "--motion-progress": `${progress}`
973
+ }),
974
+ [
975
+ isVisible,
976
+ targetOpacity,
977
+ initialOpacity,
978
+ duration,
979
+ easing,
980
+ delay,
981
+ progress
982
+ ]
983
+ );
1818
984
  return {
1819
985
  ref,
1820
986
  isVisible,
@@ -1823,7 +989,9 @@ function useFadeIn(options = {}) {
1823
989
  progress,
1824
990
  start,
1825
991
  stop,
1826
- reset
992
+ reset,
993
+ pause,
994
+ resume
1827
995
  };
1828
996
  }
1829
997
  function useSlideUp(options = {}) {
@@ -1833,7 +1001,7 @@ function useSlideUp(options = {}) {
1833
1001
  duration = profile.base.duration,
1834
1002
  threshold = profile.base.threshold,
1835
1003
  triggerOnce = profile.base.triggerOnce,
1836
- easing: easing2 = profile.entrance.slide.easing,
1004
+ easing = profile.entrance.slide.easing,
1837
1005
  autoStart = true,
1838
1006
  direction = "up",
1839
1007
  distance = profile.entrance.slide.distance,
@@ -1912,6 +1080,10 @@ function useSlideUp(options = {}) {
1912
1080
  setProgress(0);
1913
1081
  onReset?.();
1914
1082
  }, [stop, onReset]);
1083
+ const pause = useCallback(() => {
1084
+ }, []);
1085
+ const resume = useCallback(() => {
1086
+ }, []);
1915
1087
  useEffect(() => {
1916
1088
  if (!ref.current || !autoStart) return;
1917
1089
  return observeElement(
@@ -1928,21 +1100,37 @@ function useSlideUp(options = {}) {
1928
1100
  stop();
1929
1101
  };
1930
1102
  }, [stop]);
1931
- const initialTransform = useMemo(() => getInitialTransform2(), [getInitialTransform2]);
1103
+ const initialTransform = useMemo(
1104
+ () => getInitialTransform2(),
1105
+ [getInitialTransform2]
1106
+ );
1932
1107
  const finalTransform = useMemo(() => {
1933
1108
  return direction === "left" || direction === "right" ? "translateX(0)" : "translateY(0)";
1934
1109
  }, [direction]);
1935
- const style = useMemo(() => ({
1936
- opacity: isVisible ? 1 : 0,
1937
- transform: isVisible ? finalTransform : initialTransform,
1938
- transition: `opacity ${duration}ms ${easing2}, transform ${duration}ms ${easing2}`,
1939
- "--motion-delay": `${delay}ms`,
1940
- "--motion-duration": `${duration}ms`,
1941
- "--motion-easing": easing2,
1942
- "--motion-progress": `${progress}`,
1943
- "--motion-direction": direction,
1944
- "--motion-distance": `${distance}px`
1945
- }), [isVisible, initialTransform, finalTransform, duration, easing2, delay, progress, direction, distance]);
1110
+ const style = useMemo(
1111
+ () => ({
1112
+ opacity: isVisible ? 1 : 0,
1113
+ transform: isVisible ? finalTransform : initialTransform,
1114
+ transition: `opacity ${duration}ms ${easing}, transform ${duration}ms ${easing}`,
1115
+ "--motion-delay": `${delay}ms`,
1116
+ "--motion-duration": `${duration}ms`,
1117
+ "--motion-easing": easing,
1118
+ "--motion-progress": `${progress}`,
1119
+ "--motion-direction": direction,
1120
+ "--motion-distance": `${distance}px`
1121
+ }),
1122
+ [
1123
+ isVisible,
1124
+ initialTransform,
1125
+ finalTransform,
1126
+ duration,
1127
+ easing,
1128
+ delay,
1129
+ progress,
1130
+ direction,
1131
+ distance
1132
+ ]
1133
+ );
1946
1134
  return {
1947
1135
  ref,
1948
1136
  isVisible,
@@ -1951,7 +1139,9 @@ function useSlideUp(options = {}) {
1951
1139
  progress,
1952
1140
  start,
1953
1141
  stop,
1954
- reset
1142
+ reset,
1143
+ pause,
1144
+ resume
1955
1145
  };
1956
1146
  }
1957
1147
 
@@ -1972,7 +1162,7 @@ function useScaleIn(options = {}) {
1972
1162
  duration = profile.base.duration,
1973
1163
  delay = 0,
1974
1164
  autoStart = true,
1975
- easing: easing2 = profile.base.easing,
1165
+ easing = profile.base.easing,
1976
1166
  threshold = profile.base.threshold,
1977
1167
  triggerOnce = profile.base.triggerOnce,
1978
1168
  onComplete,
@@ -2031,6 +1221,10 @@ function useScaleIn(options = {}) {
2031
1221
  }
2032
1222
  onReset?.();
2033
1223
  }, [stop, initialScale, onReset]);
1224
+ const pause = useCallback(() => {
1225
+ }, []);
1226
+ const resume = useCallback(() => {
1227
+ }, []);
2034
1228
  useEffect(() => {
2035
1229
  if (!ref.current || !autoStart) return;
2036
1230
  return observeElement(
@@ -2047,15 +1241,18 @@ function useScaleIn(options = {}) {
2047
1241
  stop();
2048
1242
  };
2049
1243
  }, [stop]);
2050
- const style = useMemo(() => ({
2051
- transform: `scale(${scale})`,
2052
- opacity,
2053
- transition: `all ${duration}ms ${easing2}`,
2054
- "--motion-delay": `${delay}ms`,
2055
- "--motion-duration": `${duration}ms`,
2056
- "--motion-easing": easing2,
2057
- "--motion-progress": `${progress}`
2058
- }), [scale, opacity, duration, easing2, delay, progress]);
1244
+ const style = useMemo(
1245
+ () => ({
1246
+ transform: `scale(${scale})`,
1247
+ opacity,
1248
+ transition: `all ${duration}ms ${easing}`,
1249
+ "--motion-delay": `${delay}ms`,
1250
+ "--motion-duration": `${duration}ms`,
1251
+ "--motion-easing": easing,
1252
+ "--motion-progress": `${progress}`
1253
+ }),
1254
+ [scale, opacity, duration, easing, delay, progress]
1255
+ );
2059
1256
  return {
2060
1257
  ref,
2061
1258
  isVisible,
@@ -2064,7 +1261,9 @@ function useScaleIn(options = {}) {
2064
1261
  progress,
2065
1262
  start,
2066
1263
  reset,
2067
- stop
1264
+ stop,
1265
+ pause,
1266
+ resume
2068
1267
  };
2069
1268
  }
2070
1269
  function useBounceIn(options = {}) {
@@ -2076,7 +1275,7 @@ function useBounceIn(options = {}) {
2076
1275
  intensity = profile.entrance.bounce.intensity,
2077
1276
  threshold = profile.base.threshold,
2078
1277
  triggerOnce = profile.base.triggerOnce,
2079
- easing: easing2 = profile.entrance.bounce.easing,
1278
+ easing = profile.entrance.bounce.easing,
2080
1279
  onComplete,
2081
1280
  onStart,
2082
1281
  onStop,
@@ -2142,6 +1341,10 @@ function useBounceIn(options = {}) {
2142
1341
  }
2143
1342
  onReset?.();
2144
1343
  }, [stop, onReset]);
1344
+ const pause = useCallback(() => {
1345
+ }, []);
1346
+ const resume = useCallback(() => {
1347
+ }, []);
2145
1348
  useEffect(() => {
2146
1349
  if (!ref.current || !autoStart) return;
2147
1350
  return observeElement(
@@ -2158,15 +1361,18 @@ function useBounceIn(options = {}) {
2158
1361
  stop();
2159
1362
  };
2160
1363
  }, [stop]);
2161
- const style = useMemo(() => ({
2162
- transform: `scale(${scale})`,
2163
- opacity,
2164
- transition: `all ${duration}ms ${easing2}`,
2165
- "--motion-delay": `${delay}ms`,
2166
- "--motion-duration": `${duration}ms`,
2167
- "--motion-easing": easing2,
2168
- "--motion-progress": `${progress}`
2169
- }), [scale, opacity, duration, easing2, delay, progress]);
1364
+ const style = useMemo(
1365
+ () => ({
1366
+ transform: `scale(${scale})`,
1367
+ opacity,
1368
+ transition: `all ${duration}ms ${easing}`,
1369
+ "--motion-delay": `${delay}ms`,
1370
+ "--motion-duration": `${duration}ms`,
1371
+ "--motion-easing": easing,
1372
+ "--motion-progress": `${progress}`
1373
+ }),
1374
+ [scale, opacity, duration, easing, delay, progress]
1375
+ );
2170
1376
  return {
2171
1377
  ref,
2172
1378
  isVisible,
@@ -2175,204 +1381,11 @@ function useBounceIn(options = {}) {
2175
1381
  progress,
2176
1382
  start,
2177
1383
  reset,
2178
- stop
1384
+ stop,
1385
+ pause,
1386
+ resume
2179
1387
  };
2180
1388
  }
2181
-
2182
- // src/utils/easing.ts
2183
- var linear = (t) => t;
2184
- var easeIn = (t) => t * t;
2185
- var easeOut = (t) => 1 - (1 - t) * (1 - t);
2186
- var easeInOut = (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
2187
- var easeInQuad = (t) => t * t;
2188
- var easeOutQuad = (t) => 1 - (1 - t) * (1 - t);
2189
- var easeInOutQuad = (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
2190
- var easeInCubic = (t) => t * t * t;
2191
- var easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
2192
- var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
2193
- var easeInQuart = (t) => t * t * t * t;
2194
- var easeOutQuart = (t) => 1 - Math.pow(1 - t, 4);
2195
- var easeInOutQuart = (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2;
2196
- var easeInQuint = (t) => t * t * t * t * t;
2197
- var easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
2198
- var easeInOutQuint = (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2;
2199
- var easeInSine = (t) => 1 - Math.cos(t * Math.PI / 2);
2200
- var easeOutSine = (t) => Math.sin(t * Math.PI / 2);
2201
- var easeInOutSine = (t) => -(Math.cos(Math.PI * t) - 1) / 2;
2202
- var easeInExpo = (t) => t === 0 ? 0 : Math.pow(2, 10 * t - 10);
2203
- var easeOutExpo = (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
2204
- var easeInOutExpo = (t) => {
2205
- if (t === 0) return 0;
2206
- if (t === 1) return 1;
2207
- if (t < 0.5) return Math.pow(2, 20 * t - 10) / 2;
2208
- return (2 - Math.pow(2, -20 * t + 10)) / 2;
2209
- };
2210
- var easeInCirc = (t) => 1 - Math.sqrt(1 - Math.pow(t, 2));
2211
- var easeOutCirc = (t) => Math.sqrt(1 - Math.pow(t - 1, 2));
2212
- var easeInOutCirc = (t) => {
2213
- if (t < 0.5) return (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2;
2214
- return (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2;
2215
- };
2216
- var easeInBounce = (t) => 1 - easeOutBounce(1 - t);
2217
- var easeOutBounce = (t) => {
2218
- const n1 = 7.5625;
2219
- const d1 = 2.75;
2220
- if (t < 1 / d1) {
2221
- return n1 * t * t;
2222
- } else if (t < 2 / d1) {
2223
- return n1 * (t -= 1.5 / d1) * t + 0.75;
2224
- } else if (t < 2.5 / d1) {
2225
- return n1 * (t -= 2.25 / d1) * t + 0.9375;
2226
- } else {
2227
- return n1 * (t -= 2.625 / d1) * t + 0.984375;
2228
- }
2229
- };
2230
- var easeInOutBounce = (t) => {
2231
- if (t < 0.5) return (1 - easeOutBounce(1 - 2 * t)) / 2;
2232
- return (1 + easeOutBounce(2 * t - 1)) / 2;
2233
- };
2234
- var easeInBack = (t) => {
2235
- const c1 = 1.70158;
2236
- const c3 = c1 + 1;
2237
- return c3 * t * t * t - c1 * t * t;
2238
- };
2239
- var easeOutBack = (t) => {
2240
- const c1 = 1.70158;
2241
- const c3 = c1 + 1;
2242
- return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
2243
- };
2244
- var easeInOutBack = (t) => {
2245
- const c1 = 1.70158;
2246
- const c2 = c1 * 1.525;
2247
- if (t < 0.5) {
2248
- return Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2) / 2;
2249
- } else {
2250
- return (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
2251
- }
2252
- };
2253
- var easeInElastic = (t) => {
2254
- const c4 = 2 * Math.PI / 3;
2255
- if (t === 0) return 0;
2256
- if (t === 1) return 1;
2257
- return -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 0.75) * c4);
2258
- };
2259
- var easeOutElastic = (t) => {
2260
- const c4 = 2 * Math.PI / 3;
2261
- if (t === 0) return 0;
2262
- if (t === 1) return 1;
2263
- return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
2264
- };
2265
- var easeInOutElastic = (t) => {
2266
- const c5 = 2 * Math.PI / 4.5;
2267
- if (t === 0) return 0;
2268
- if (t === 1) return 1;
2269
- if (t < 0.5) {
2270
- return -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * c5)) / 2;
2271
- } else {
2272
- return Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * c5) / 2 + 1;
2273
- }
2274
- };
2275
- var pulse = (t) => Math.sin(t * Math.PI) * 0.5 + 0.5;
2276
- var pulseSmooth = (t) => Math.sin(t * Math.PI * 2) * 0.3 + 0.7;
2277
- var skeletonWave = (t) => Math.sin((t - 0.5) * Math.PI * 2) * 0.5 + 0.5;
2278
- var blink = (t) => t < 0.5 ? 1 : 0;
2279
- var easing = {
2280
- linear,
2281
- easeIn,
2282
- easeOut,
2283
- easeInOut,
2284
- easeInQuad,
2285
- easeOutQuad,
2286
- easeInOutQuad,
2287
- easeInCubic,
2288
- easeOutCubic,
2289
- easeInOutCubic,
2290
- easeInQuart,
2291
- easeOutQuart,
2292
- easeInOutQuart,
2293
- easeInQuint,
2294
- easeOutQuint,
2295
- easeInOutQuint,
2296
- easeInSine,
2297
- easeOutSine,
2298
- easeInOutSine,
2299
- easeInExpo,
2300
- easeOutExpo,
2301
- easeInOutExpo,
2302
- easeInCirc,
2303
- easeOutCirc,
2304
- easeInOutCirc,
2305
- easeInBounce,
2306
- easeOutBounce,
2307
- easeInOutBounce,
2308
- easeInBack,
2309
- easeOutBack,
2310
- easeInOutBack,
2311
- easeInElastic,
2312
- easeOutElastic,
2313
- easeInOutElastic,
2314
- pulse,
2315
- pulseSmooth,
2316
- skeletonWave,
2317
- blink
2318
- };
2319
- function isValidEasing(easingName) {
2320
- return easingName in easing;
2321
- }
2322
- function getEasing(easingName) {
2323
- if (typeof easingName === "function") {
2324
- return easingName;
2325
- }
2326
- if (typeof easingName === "string") {
2327
- if (easingName in easing) {
2328
- return easing[easingName];
2329
- }
2330
- if (easingName === "bounce") {
2331
- return easing.easeOutBounce;
2332
- }
2333
- if (process.env.NODE_ENV === "development") {
2334
- console.warn(`[HUA Motion] Unknown easing "${easingName}", using default "easeOut".`);
2335
- }
2336
- }
2337
- return easeOut;
2338
- }
2339
- function applyEasing(t, easingName) {
2340
- const easingFn = getEasing(easingName);
2341
- return easingFn(t);
2342
- }
2343
- function safeApplyEasing(t, easingName) {
2344
- try {
2345
- const easingFn = getEasing(easingName);
2346
- return easingFn(t);
2347
- } catch (err) {
2348
- if (process.env.NODE_ENV === "development") {
2349
- console.error(`[HUA Motion] Failed to apply easing "${easingName}":`, err);
2350
- }
2351
- return easeOut(t);
2352
- }
2353
- }
2354
- function getAvailableEasings() {
2355
- return Object.keys(easing);
2356
- }
2357
- function isEasingFunction(value) {
2358
- return typeof value === "function";
2359
- }
2360
- var easingPresets = {
2361
- default: "easeOut",
2362
- smooth: "easeInOutCubic",
2363
- fast: "easeOutQuad",
2364
- slow: "easeInOutSine",
2365
- bouncy: "easeOutBounce",
2366
- elastic: "easeOutElastic",
2367
- fade: "easeInOut",
2368
- scale: "easeOutBack"
2369
- };
2370
- function getPresetEasing(preset) {
2371
- const easingName = easingPresets[preset];
2372
- return getEasing(easingName);
2373
- }
2374
-
2375
- // src/hooks/usePulse.ts
2376
1389
  function usePulse(options = {}) {
2377
1390
  const {
2378
1391
  duration = 3e3,
@@ -2476,20 +1489,6 @@ function usePulse(options = {}) {
2476
1489
  reset
2477
1490
  };
2478
1491
  }
2479
-
2480
- // src/utils/springPhysics.ts
2481
- function calculateSpring(currentValue, currentVelocity, targetValue, deltaTime, config) {
2482
- const { stiffness, damping, mass } = config;
2483
- const displacement = currentValue - targetValue;
2484
- const springForce = -stiffness * displacement;
2485
- const dampingForce = -damping * currentVelocity;
2486
- const acceleration = (springForce + dampingForce) / mass;
2487
- const newVelocity = currentVelocity + acceleration * deltaTime;
2488
- const newValue = currentValue + newVelocity * deltaTime;
2489
- return { value: newValue, velocity: newVelocity };
2490
- }
2491
-
2492
- // src/hooks/useSpringMotion.ts
2493
1492
  function useSpringMotion(options) {
2494
1493
  const profile = useMotionProfile();
2495
1494
  const {
@@ -2629,7 +1628,7 @@ function useGradient(options = {}) {
2629
1628
  duration = 6e3,
2630
1629
  direction = "diagonal",
2631
1630
  size = 300,
2632
- easing: easing2 = "ease-in-out",
1631
+ easing = "ease-in-out",
2633
1632
  autoStart = false
2634
1633
  } = options;
2635
1634
  const ref = useRef(null);
@@ -2646,10 +1645,10 @@ function useGradient(options = {}) {
2646
1645
  return {
2647
1646
  background,
2648
1647
  backgroundSize,
2649
- animation: isAnimating ? `gradientShift ${duration}ms ${easing2} infinite` : "none",
1648
+ animation: isAnimating ? `gradientShift ${duration}ms ${easing} infinite` : "none",
2650
1649
  backgroundPosition: isAnimating ? void 0 : `${motionProgress}% 50%`
2651
1650
  };
2652
- }, [colors, direction, size, duration, easing2, isAnimating, motionProgress]);
1651
+ }, [colors, direction, size, duration, easing, isAnimating, motionProgress]);
2653
1652
  const start = useCallback(() => {
2654
1653
  setIsAnimating(true);
2655
1654
  }, []);
@@ -2697,7 +1696,7 @@ function useHoverMotion(options = {}) {
2697
1696
  const profile = useMotionProfile();
2698
1697
  const {
2699
1698
  duration = profile.interaction.hover.duration,
2700
- easing: easing2 = profile.interaction.hover.easing,
1699
+ easing = profile.interaction.hover.easing,
2701
1700
  hoverScale = profile.interaction.hover.scale,
2702
1701
  hoverY = profile.interaction.hover.y,
2703
1702
  hoverOpacity = 1
@@ -2731,8 +1730,8 @@ function useHoverMotion(options = {}) {
2731
1730
  const style = useMemo(() => ({
2732
1731
  transform: isHovered ? `scale(${hoverScale}) translateY(${hoverY}px)` : "scale(1) translateY(0px)",
2733
1732
  opacity: isHovered ? hoverOpacity : 1,
2734
- transition: `transform ${duration}ms ${easing2}, opacity ${duration}ms ${easing2}`
2735
- }), [isHovered, hoverScale, hoverY, hoverOpacity, duration, easing2]);
1733
+ transition: `transform ${duration}ms ${easing}, opacity ${duration}ms ${easing}`
1734
+ }), [isHovered, hoverScale, hoverY, hoverOpacity, duration, easing]);
2736
1735
  const start = useCallback(() => {
2737
1736
  setIsHovered(true);
2738
1737
  setIsAnimating(true);
@@ -2990,7 +1989,7 @@ function useScrollReveal(options = {}) {
2990
1989
  triggerOnce = profile.base.triggerOnce,
2991
1990
  delay = 0,
2992
1991
  duration = profile.base.duration,
2993
- easing: easing2 = profile.base.easing,
1992
+ easing = profile.base.easing,
2994
1993
  motionType = "fadeIn",
2995
1994
  onComplete,
2996
1995
  onStart,
@@ -3028,7 +2027,7 @@ function useScrollReveal(options = {}) {
3028
2027
  const slideDistance = profile.entrance.slide.distance;
3029
2028
  const scaleFrom = profile.entrance.scale.from;
3030
2029
  const style = useMemo(() => {
3031
- const baseTransition = `all ${duration}ms ${easing2}`;
2030
+ const baseTransition = `all ${duration}ms ${easing}`;
3032
2031
  if (!isVisible) {
3033
2032
  switch (motionType) {
3034
2033
  case "fadeIn":
@@ -3078,7 +2077,7 @@ function useScrollReveal(options = {}) {
3078
2077
  transform: "none",
3079
2078
  transition: baseTransition
3080
2079
  };
3081
- }, [isVisible, motionType, duration, easing2, slideDistance, scaleFrom]);
2080
+ }, [isVisible, motionType, duration, easing, slideDistance, scaleFrom]);
3082
2081
  const start = useCallback(() => {
3083
2082
  setIsAnimating(true);
3084
2083
  onStart?.();
@@ -3300,14 +2299,7 @@ function useMotionState(options = {}) {
3300
2299
  const seek = useCallback((targetProgress) => {
3301
2300
  const clampedProgress = Math.max(0, Math.min(100, targetProgress));
3302
2301
  setProgress(clampedProgress);
3303
- let targetElapsed = 0;
3304
- if (currentDirection === "reverse") {
3305
- targetElapsed = (100 - clampedProgress) / 100 * duration;
3306
- } else if (currentDirection === "alternate") {
3307
- targetElapsed = clampedProgress / 100 * duration;
3308
- } else {
3309
- targetElapsed = clampedProgress / 100 * duration;
3310
- }
2302
+ const targetElapsed = currentDirection === "reverse" ? (100 - clampedProgress) / 100 * duration : clampedProgress / 100 * duration;
3311
2303
  setElapsed(targetElapsed);
3312
2304
  if (state === "playing" && startTimeRef.current) {
3313
2305
  const currentTime = performance.now();
@@ -3476,7 +2468,7 @@ function useRepeat(options = {}) {
3476
2468
  };
3477
2469
  }
3478
2470
  function useToggleMotion(options = {}) {
3479
- const { duration = 300, delay = 0, easing: easing2 = "ease-in-out" } = options;
2471
+ const { duration = 300, delay = 0, easing = "ease-in-out" } = options;
3480
2472
  const ref = useRef(null);
3481
2473
  const [isVisible, setIsVisible] = useState(false);
3482
2474
  const [isAnimating, setIsAnimating] = useState(false);
@@ -3506,8 +2498,8 @@ function useToggleMotion(options = {}) {
3506
2498
  const style = useMemo(() => ({
3507
2499
  opacity: isVisible ? 1 : 0,
3508
2500
  transform: isVisible ? "translateY(0) scale(1)" : "translateY(10px) scale(0.95)",
3509
- transition: `opacity ${duration}ms ${easing2} ${delay}ms, transform ${duration}ms ${easing2} ${delay}ms`
3510
- }), [isVisible, duration, easing2, delay]);
2501
+ transition: `opacity ${duration}ms ${easing} ${delay}ms, transform ${duration}ms ${easing} ${delay}ms`
2502
+ }), [isVisible, duration, easing, delay]);
3511
2503
  return {
3512
2504
  ref,
3513
2505
  isVisible,
@@ -3655,9 +2647,11 @@ function useReducedMotion() {
3655
2647
  mediaQuery.removeEventListener("change", handleChange);
3656
2648
  };
3657
2649
  }, []);
3658
- return {
3659
- prefersReducedMotion
3660
- };
2650
+ return prefersReducedMotion;
2651
+ }
2652
+ function useReducedMotionObject() {
2653
+ const prefersReducedMotion = useReducedMotion();
2654
+ return { prefersReducedMotion };
3661
2655
  }
3662
2656
  function useWindowSize(options = {}) {
3663
2657
  const {
@@ -3978,7 +2972,7 @@ function useGestureMotion(options) {
3978
2972
  const {
3979
2973
  gestureType,
3980
2974
  duration = 300,
3981
- easing: easing2 = "ease-out",
2975
+ easing = "ease-out",
3982
2976
  sensitivity = 1,
3983
2977
  enabled = true,
3984
2978
  onGestureStart,
@@ -4020,10 +3014,10 @@ function useGestureMotion(options) {
4020
3014
  }
4021
3015
  setMotionStyle({
4022
3016
  transform,
4023
- transition: isActive ? "none" : `all ${duration}ms ${easing2}`,
3017
+ transition: isActive ? "none" : `all ${duration}ms ${easing}`,
4024
3018
  cursor: gestureType === "drag" && isActive ? "grabbing" : "pointer"
4025
3019
  });
4026
- }, [gestureState, gestureType, enabled, duration, easing2, sensitivity]);
3020
+ }, [gestureState, gestureType, enabled, duration, easing, sensitivity]);
4027
3021
  const handleMouseDown = useCallback((e) => {
4028
3022
  if (!enabled || gestureType !== "drag") return;
4029
3023
  isDragging.current = true;
@@ -4122,7 +3116,7 @@ function useGestureMotion(options) {
4122
3116
  function useButtonEffect(options = {}) {
4123
3117
  const {
4124
3118
  duration = 200,
4125
- easing: easing2 = "ease-out",
3119
+ easing = "ease-out",
4126
3120
  type = "scale",
4127
3121
  scaleAmount = 0.95,
4128
3122
  rippleColor = "rgba(255, 255, 255, 0.6)",
@@ -4396,7 +3390,7 @@ function useButtonEffect(options = {}) {
4396
3390
  `,
4397
3391
  boxShadow,
4398
3392
  opacity: disabled ? disabledOpacity : 1,
4399
- transition: `all ${duration}ms ${easing2}`,
3393
+ transition: `all ${duration}ms ${easing}`,
4400
3394
  willChange: "transform, box-shadow, opacity",
4401
3395
  cursor: disabled ? "not-allowed" : "pointer",
4402
3396
  position: "relative",
@@ -4433,7 +3427,7 @@ function useButtonEffect(options = {}) {
4433
3427
  function useVisibilityToggle(options = {}) {
4434
3428
  const {
4435
3429
  duration = 300,
4436
- easing: easing2 = "ease-out",
3430
+ easing = "ease-out",
4437
3431
  showScale = 1,
4438
3432
  showOpacity = 1,
4439
3433
  showRotate = 0,
@@ -4521,7 +3515,7 @@ function useVisibilityToggle(options = {}) {
4521
3515
  translate(${isVisible ? showTranslateX : hideTranslateX}px, ${isVisible ? showTranslateY : hideTranslateY}px)
4522
3516
  `,
4523
3517
  opacity: isVisible ? showOpacity : hideOpacity,
4524
- transition: `all ${duration}ms ${easing2}`,
3518
+ transition: `all ${duration}ms ${easing}`,
4525
3519
  willChange: "transform, opacity"
4526
3520
  };
4527
3521
  return {
@@ -4544,7 +3538,7 @@ function useVisibilityToggle(options = {}) {
4544
3538
  function useScrollToggle(options = {}) {
4545
3539
  const {
4546
3540
  duration = 300,
4547
- easing: easing2 = "ease-out",
3541
+ easing = "ease-out",
4548
3542
  showScale = 1,
4549
3543
  showOpacity = 1,
4550
3544
  showRotate = 0,
@@ -4653,7 +3647,7 @@ function useScrollToggle(options = {}) {
4653
3647
  translate(${isVisible ? showTranslateX : hideTranslateX}px, ${isVisible ? showTranslateY : hideTranslateY}px)
4654
3648
  `,
4655
3649
  opacity: isVisible ? showOpacity : hideOpacity,
4656
- transition: `all ${duration}ms ${easing2}`,
3650
+ transition: `all ${duration}ms ${easing}`,
4657
3651
  willChange: "transform, opacity"
4658
3652
  };
4659
3653
  return {
@@ -4672,7 +3666,7 @@ function useScrollToggle(options = {}) {
4672
3666
  function useCardList(options = {}) {
4673
3667
  const {
4674
3668
  duration = 500,
4675
- easing: easing2 = "ease-out",
3669
+ easing = "ease-out",
4676
3670
  staggerDelay = 100,
4677
3671
  cardScale = 1,
4678
3672
  cardOpacity = 1,
@@ -4714,7 +3708,7 @@ function useCardList(options = {}) {
4714
3708
  translate(${isCardVisible ? cardTranslateX : initialTranslateX}px, ${isCardVisible ? cardTranslateY : initialTranslateY}px)
4715
3709
  `,
4716
3710
  opacity: isCardVisible ? cardOpacity : initialOpacity,
4717
- transition: `all ${duration}ms ${easing2} ${delay}ms`,
3711
+ transition: `all ${duration}ms ${easing} ${delay}ms`,
4718
3712
  willChange: "transform, opacity"
4719
3713
  };
4720
3714
  });
@@ -4793,7 +3787,7 @@ function useCardList(options = {}) {
4793
3787
  function useLoadingSpinner(options = {}) {
4794
3788
  const {
4795
3789
  duration = 1e3,
4796
- easing: easing2 = "linear",
3790
+ easing = "linear",
4797
3791
  type = "rotate",
4798
3792
  rotationSpeed = 1,
4799
3793
  pulseSpeed = 1,
@@ -4957,7 +3951,7 @@ function useLoadingSpinner(options = {}) {
4957
3951
  borderTop: `${thickness}px solid ${color}`,
4958
3952
  borderRadius: "50%",
4959
3953
  transform: `rotate(${rotationAngle}deg)`,
4960
- transition: `transform ${duration}ms ${easing2}`
3954
+ transition: `transform ${duration}ms ${easing}`
4961
3955
  };
4962
3956
  case "pulse":
4963
3957
  return {
@@ -4965,7 +3959,7 @@ function useLoadingSpinner(options = {}) {
4965
3959
  backgroundColor: color,
4966
3960
  borderRadius: "50%",
4967
3961
  transform: `scale(${pulseScale})`,
4968
- transition: `transform ${duration}ms ${easing2}`
3962
+ transition: `transform ${duration}ms ${easing}`
4969
3963
  };
4970
3964
  case "bounce":
4971
3965
  return {
@@ -4973,7 +3967,7 @@ function useLoadingSpinner(options = {}) {
4973
3967
  backgroundColor: color,
4974
3968
  borderRadius: "50%",
4975
3969
  transform: `translateY(${bounceOffset}px)`,
4976
- transition: `transform ${duration}ms ${easing2}`
3970
+ transition: `transform ${duration}ms ${easing}`
4977
3971
  };
4978
3972
  case "wave":
4979
3973
  return {
@@ -5028,7 +4022,7 @@ function useLoadingSpinner(options = {}) {
5028
4022
  function useNavigation(options = {}) {
5029
4023
  const {
5030
4024
  duration = 300,
5031
- easing: easing2 = "ease-out",
4025
+ easing = "ease-out",
5032
4026
  type = "slide",
5033
4027
  slideDirection = "left",
5034
4028
  staggerDelay = 50,
@@ -5184,14 +4178,14 @@ function useNavigation(options = {}) {
5184
4178
  translate(${translateX}px, ${translateY}px)
5185
4179
  `,
5186
4180
  opacity,
5187
- transition: `all ${duration}ms ${easing2} ${delay}ms`,
4181
+ transition: `all ${duration}ms ${easing} ${delay}ms`,
5188
4182
  willChange: "transform, opacity",
5189
4183
  cursor: "pointer"
5190
4184
  };
5191
4185
  });
5192
4186
  const getNavigationStyle = () => {
5193
4187
  const baseStyle = {
5194
- transition: `all ${duration}ms ${easing2}`,
4188
+ transition: `all ${duration}ms ${easing}`,
5195
4189
  willChange: "transform, opacity"
5196
4190
  };
5197
4191
  switch (type) {
@@ -5245,7 +4239,7 @@ function useSkeleton(options = {}) {
5245
4239
  const {
5246
4240
  delay = 0,
5247
4241
  duration = 1500,
5248
- easing: easing2 = "ease-in-out",
4242
+ easing = "ease-in-out",
5249
4243
  autoStart = true,
5250
4244
  backgroundColor = "#f0f0f0",
5251
4245
  highlightColor = "#e0e0e0",
@@ -5254,7 +4248,7 @@ function useSkeleton(options = {}) {
5254
4248
  width = "100%",
5255
4249
  borderRadius = 4,
5256
4250
  wave = true,
5257
- pulse: pulse2 = false,
4251
+ pulse = false,
5258
4252
  onComplete,
5259
4253
  onStart,
5260
4254
  onStop,
@@ -5337,13 +4331,13 @@ function useSkeleton(options = {}) {
5337
4331
  position: "relative",
5338
4332
  overflow: "hidden",
5339
4333
  opacity: isVisible ? 1 : 0,
5340
- transition: `opacity ${duration}ms ${easing2}`
4334
+ transition: `opacity ${duration}ms ${easing}`
5341
4335
  };
5342
4336
  if (wave && isAnimating) {
5343
4337
  baseStyle.background = `linear-gradient(90deg, ${backgroundColor} 25%, ${highlightColor} 50%, ${backgroundColor} 75%)`;
5344
4338
  baseStyle.backgroundSize = "200% 100%";
5345
4339
  baseStyle.animation = `skeleton-wave ${motionSpeed}ms infinite linear`;
5346
- } else if (pulse2 && isAnimating) {
4340
+ } else if (pulse && isAnimating) {
5347
4341
  baseStyle.animation = `skeleton-pulse ${motionSpeed}ms infinite ease-in-out`;
5348
4342
  }
5349
4343
  return baseStyle;
@@ -5668,16 +4662,2554 @@ function useElementProgress(options = {}) {
5668
4662
  }, [start, end, clamp]);
5669
4663
  return { ref, progress, isInView };
5670
4664
  }
5671
- function Motion({
5672
- as: Component = "div",
5673
- type,
5674
- effects,
5675
- scroll,
5676
- delay,
5677
- duration,
5678
- children,
5679
- className,
5680
- style: userStyle,
4665
+ function useAutoFade(options = {}) {
4666
+ const {
4667
+ initialOpacity = 0,
4668
+ targetOpacity = 1,
4669
+ duration = 1e3,
4670
+ delay = 0,
4671
+ repeat = false,
4672
+ repeatDelay = 1e3,
4673
+ repeatCount = -1,
4674
+ ease = "ease-in-out",
4675
+ autoStart = true,
4676
+ onComplete,
4677
+ onRepeat,
4678
+ showOnMount = false
4679
+ } = options;
4680
+ const [opacity, setOpacity] = useState(showOnMount ? initialOpacity : 0);
4681
+ const [isAnimating, setIsAnimating] = useState(false);
4682
+ const [isVisible, setIsVisible] = useState(
4683
+ showOnMount ? initialOpacity > 0 : false
4684
+ );
4685
+ const [mounted, setMounted] = useState(false);
4686
+ const motionRef = useRef(null);
4687
+ const timeoutRef = useRef(null);
4688
+ const repeatCountRef = useRef(0);
4689
+ const isFadingInRef = useRef(true);
4690
+ useEffect(() => {
4691
+ setMounted(true);
4692
+ }, []);
4693
+ const getEasing2 = useCallback(
4694
+ (t) => {
4695
+ switch (ease) {
4696
+ case "linear":
4697
+ return t;
4698
+ case "ease-in":
4699
+ return t * t;
4700
+ case "ease-out":
4701
+ return 1 - (1 - t) * (1 - t);
4702
+ case "ease-in-out":
4703
+ return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
4704
+ default:
4705
+ return t;
4706
+ }
4707
+ },
4708
+ [ease]
4709
+ );
4710
+ const animate = useCallback(
4711
+ (from, to, onFinish) => {
4712
+ if (!mounted) return;
4713
+ setIsAnimating(true);
4714
+ const startTime = performance.now();
4715
+ const startOpacity = from;
4716
+ const updateOpacity = (currentTime) => {
4717
+ const elapsed = currentTime - startTime;
4718
+ const progress = Math.min(elapsed / duration, 1);
4719
+ const easedProgress = getEasing2(progress);
4720
+ const currentOpacity = startOpacity + (to - startOpacity) * easedProgress;
4721
+ setOpacity(currentOpacity);
4722
+ setIsVisible(currentOpacity > 0);
4723
+ if (progress < 1) {
4724
+ motionRef.current = requestAnimationFrame(updateOpacity);
4725
+ } else {
4726
+ setIsAnimating(false);
4727
+ onFinish?.();
4728
+ }
4729
+ };
4730
+ motionRef.current = requestAnimationFrame(updateOpacity);
4731
+ },
4732
+ [mounted, duration, getEasing2]
4733
+ );
4734
+ const fadeIn = useCallback(() => {
4735
+ if (!mounted || isAnimating) return;
4736
+ animate(initialOpacity, targetOpacity, () => {
4737
+ onComplete?.();
4738
+ if (repeat && (repeatCount === -1 || repeatCountRef.current < repeatCount)) {
4739
+ repeatCountRef.current++;
4740
+ onRepeat?.(repeatCountRef.current);
4741
+ timeoutRef.current = window.setTimeout(() => {
4742
+ fadeOut();
4743
+ }, repeatDelay);
4744
+ }
4745
+ });
4746
+ }, [
4747
+ mounted,
4748
+ isAnimating,
4749
+ animate,
4750
+ initialOpacity,
4751
+ targetOpacity,
4752
+ onComplete,
4753
+ repeat,
4754
+ repeatCount,
4755
+ repeatDelay,
4756
+ onRepeat
4757
+ ]);
4758
+ const fadeOut = useCallback(() => {
4759
+ if (!mounted || isAnimating) return;
4760
+ animate(targetOpacity, initialOpacity, () => {
4761
+ onComplete?.();
4762
+ if (repeat && (repeatCount === -1 || repeatCountRef.current < repeatCount)) {
4763
+ repeatCountRef.current++;
4764
+ onRepeat?.(repeatCountRef.current);
4765
+ timeoutRef.current = window.setTimeout(() => {
4766
+ fadeIn();
4767
+ }, repeatDelay);
4768
+ }
4769
+ });
4770
+ }, [
4771
+ mounted,
4772
+ isAnimating,
4773
+ animate,
4774
+ targetOpacity,
4775
+ initialOpacity,
4776
+ onComplete,
4777
+ repeat,
4778
+ repeatCount,
4779
+ repeatDelay,
4780
+ onRepeat
4781
+ ]);
4782
+ const start = useCallback(() => {
4783
+ if (!mounted || isAnimating) return;
4784
+ if (delay > 0) {
4785
+ timeoutRef.current = window.setTimeout(() => {
4786
+ fadeIn();
4787
+ }, delay);
4788
+ } else {
4789
+ fadeIn();
4790
+ }
4791
+ }, [mounted, isAnimating, delay, fadeIn]);
4792
+ const stop = useCallback(() => {
4793
+ if (motionRef.current !== null) {
4794
+ cancelAnimationFrame(motionRef.current);
4795
+ motionRef.current = null;
4796
+ }
4797
+ if (timeoutRef.current !== null) {
4798
+ clearTimeout(timeoutRef.current);
4799
+ timeoutRef.current = null;
4800
+ }
4801
+ setIsAnimating(false);
4802
+ }, []);
4803
+ const reset = useCallback(() => {
4804
+ stop();
4805
+ setOpacity(initialOpacity);
4806
+ setIsVisible(initialOpacity > 0);
4807
+ repeatCountRef.current = 0;
4808
+ isFadingInRef.current = true;
4809
+ }, [stop, initialOpacity]);
4810
+ const toggle = useCallback(() => {
4811
+ if (isFadingInRef.current) {
4812
+ fadeOut();
4813
+ isFadingInRef.current = false;
4814
+ } else {
4815
+ fadeIn();
4816
+ isFadingInRef.current = true;
4817
+ }
4818
+ }, [fadeIn, fadeOut]);
4819
+ useEffect(() => {
4820
+ if (mounted && autoStart) {
4821
+ start();
4822
+ }
4823
+ }, [mounted, autoStart, start]);
4824
+ useEffect(() => {
4825
+ return () => {
4826
+ if (motionRef.current !== null) {
4827
+ cancelAnimationFrame(motionRef.current);
4828
+ }
4829
+ if (timeoutRef.current !== null) {
4830
+ clearTimeout(timeoutRef.current);
4831
+ }
4832
+ };
4833
+ }, []);
4834
+ return {
4835
+ opacity,
4836
+ isAnimating,
4837
+ isVisible,
4838
+ mounted,
4839
+ start,
4840
+ stop,
4841
+ reset,
4842
+ fadeIn,
4843
+ fadeOut,
4844
+ toggle
4845
+ };
4846
+ }
4847
+ function useAutoPlay(options = {}) {
4848
+ const {
4849
+ interval = 3e3,
4850
+ delay = 0,
4851
+ repeat = "infinite",
4852
+ autoStart = true,
4853
+ pauseOnHover = false,
4854
+ pauseOnBlur = true,
4855
+ showOnMount = false
4856
+ } = options;
4857
+ const [isPlaying, setIsPlaying] = useState(showOnMount ? autoStart : false);
4858
+ const [currentStep, setCurrentStep] = useState(0);
4859
+ const [mounted, setMounted] = useState(false);
4860
+ const [isPaused, setIsPaused] = useState(false);
4861
+ const intervalRef = useRef(null);
4862
+ const timeoutRef = useRef(null);
4863
+ const repeatCountRef = useRef(0);
4864
+ useEffect(() => {
4865
+ setMounted(true);
4866
+ }, []);
4867
+ const next = useCallback(() => {
4868
+ setCurrentStep((prev) => {
4869
+ const nextStep = prev + 1;
4870
+ if (repeat !== "infinite") {
4871
+ repeatCountRef.current += 1;
4872
+ if (repeatCountRef.current >= repeat) {
4873
+ stop();
4874
+ return prev;
4875
+ }
4876
+ }
4877
+ return nextStep;
4878
+ });
4879
+ }, [repeat]);
4880
+ const startInterval = useCallback(() => {
4881
+ if (intervalRef.current) {
4882
+ clearInterval(intervalRef.current);
4883
+ }
4884
+ intervalRef.current = window.setInterval(() => {
4885
+ next();
4886
+ }, interval);
4887
+ }, [interval, next]);
4888
+ const pause = useCallback(() => {
4889
+ if (!isPlaying) return;
4890
+ setIsPaused(true);
4891
+ if (intervalRef.current) {
4892
+ clearInterval(intervalRef.current);
4893
+ intervalRef.current = null;
4894
+ }
4895
+ }, [isPlaying]);
4896
+ const resume = useCallback(() => {
4897
+ if (!isPlaying || !isPaused) return;
4898
+ setIsPaused(false);
4899
+ startInterval();
4900
+ }, [isPlaying, isPaused, startInterval]);
4901
+ const stop = useCallback(() => {
4902
+ setIsPlaying(false);
4903
+ setIsPaused(false);
4904
+ setCurrentStep(0);
4905
+ repeatCountRef.current = 0;
4906
+ if (intervalRef.current) {
4907
+ clearInterval(intervalRef.current);
4908
+ intervalRef.current = null;
4909
+ }
4910
+ if (timeoutRef.current) {
4911
+ clearTimeout(timeoutRef.current);
4912
+ timeoutRef.current = null;
4913
+ }
4914
+ }, []);
4915
+ const start = useCallback(() => {
4916
+ if (!mounted) return;
4917
+ setIsPlaying(true);
4918
+ setIsPaused(false);
4919
+ setCurrentStep(0);
4920
+ repeatCountRef.current = 0;
4921
+ if (delay > 0) {
4922
+ timeoutRef.current = window.setTimeout(() => {
4923
+ startInterval();
4924
+ }, delay);
4925
+ } else {
4926
+ startInterval();
4927
+ }
4928
+ }, [mounted, delay, startInterval]);
4929
+ const previous = useCallback(() => {
4930
+ setCurrentStep((prev) => Math.max(0, prev - 1));
4931
+ }, []);
4932
+ const goTo = useCallback((step) => {
4933
+ setCurrentStep(Math.max(0, step));
4934
+ }, []);
4935
+ useEffect(() => {
4936
+ if (mounted && autoStart) {
4937
+ start();
4938
+ }
4939
+ }, [mounted, autoStart, start]);
4940
+ useEffect(() => {
4941
+ if (!pauseOnHover) return;
4942
+ const handleMouseEnter = () => {
4943
+ if (isPlaying && !isPaused) {
4944
+ pause();
4945
+ }
4946
+ };
4947
+ const handleMouseLeave = () => {
4948
+ if (isPlaying && isPaused) {
4949
+ resume();
4950
+ }
4951
+ };
4952
+ document.addEventListener("mouseenter", handleMouseEnter);
4953
+ document.addEventListener("mouseleave", handleMouseLeave);
4954
+ return () => {
4955
+ document.removeEventListener("mouseenter", handleMouseEnter);
4956
+ document.removeEventListener("mouseleave", handleMouseLeave);
4957
+ };
4958
+ }, [pauseOnHover, isPlaying, isPaused, pause, resume]);
4959
+ useEffect(() => {
4960
+ if (!pauseOnBlur) return;
4961
+ const handleBlur = () => {
4962
+ if (isPlaying && !isPaused) {
4963
+ pause();
4964
+ }
4965
+ };
4966
+ const handleFocus = () => {
4967
+ if (isPlaying && isPaused) {
4968
+ resume();
4969
+ }
4970
+ };
4971
+ window.addEventListener("blur", handleBlur);
4972
+ window.addEventListener("focus", handleFocus);
4973
+ return () => {
4974
+ window.removeEventListener("blur", handleBlur);
4975
+ window.removeEventListener("focus", handleFocus);
4976
+ };
4977
+ }, [pauseOnBlur, isPlaying, isPaused, pause, resume]);
4978
+ useEffect(() => {
4979
+ return () => {
4980
+ if (intervalRef.current) {
4981
+ clearInterval(intervalRef.current);
4982
+ }
4983
+ if (timeoutRef.current) {
4984
+ clearTimeout(timeoutRef.current);
4985
+ }
4986
+ };
4987
+ }, []);
4988
+ return {
4989
+ isPlaying,
4990
+ isPaused,
4991
+ currentStep,
4992
+ mounted,
4993
+ start,
4994
+ stop,
4995
+ pause,
4996
+ resume,
4997
+ next,
4998
+ previous,
4999
+ goTo
5000
+ };
5001
+ }
5002
+ function useAutoScale(options = {}) {
5003
+ const {
5004
+ initialScale = 0,
5005
+ targetScale = 1,
5006
+ duration = 1e3,
5007
+ delay = 0,
5008
+ repeat = false,
5009
+ repeatDelay = 1e3,
5010
+ repeatCount = -1,
5011
+ ease = "ease-in-out",
5012
+ autoStart = true,
5013
+ onComplete,
5014
+ onRepeat,
5015
+ showOnMount = false,
5016
+ centerTransform: _centerTransform = true
5017
+ } = options;
5018
+ const [scale, setScale] = useState(showOnMount ? initialScale : 0);
5019
+ const [isAnimating, setIsAnimating] = useState(false);
5020
+ const [isVisible, setIsVisible] = useState(
5021
+ showOnMount ? initialScale > 0 : false
5022
+ );
5023
+ const [mounted, setMounted] = useState(false);
5024
+ const motionRef = useRef(null);
5025
+ const timeoutRef = useRef(null);
5026
+ const repeatCountRef = useRef(0);
5027
+ const isScalingInRef = useRef(true);
5028
+ useEffect(() => {
5029
+ setMounted(true);
5030
+ }, []);
5031
+ const getEasing2 = useCallback(
5032
+ (t) => {
5033
+ switch (ease) {
5034
+ case "linear":
5035
+ return t;
5036
+ case "ease-in":
5037
+ return t * t;
5038
+ case "ease-out":
5039
+ return 1 - (1 - t) * (1 - t);
5040
+ case "ease-in-out":
5041
+ return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
5042
+ case "bounce":
5043
+ if (t < 1 / 2.75) {
5044
+ return 7.5625 * t * t;
5045
+ } else if (t < 2 / 2.75) {
5046
+ return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
5047
+ } else if (t < 2.5 / 2.75) {
5048
+ return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
5049
+ } else {
5050
+ return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
5051
+ }
5052
+ case "elastic":
5053
+ if (t === 0) return 0;
5054
+ if (t === 1) return 1;
5055
+ return Math.pow(2, -10 * t) * Math.sin((t - 0.075) * (2 * Math.PI) / 0.3) + 1;
5056
+ default:
5057
+ return t;
5058
+ }
5059
+ },
5060
+ [ease]
5061
+ );
5062
+ const animate = useCallback(
5063
+ (from, to, onFinish) => {
5064
+ if (!mounted) return;
5065
+ setIsAnimating(true);
5066
+ const startTime = performance.now();
5067
+ const startScale = from;
5068
+ const updateScale = (currentTime) => {
5069
+ const elapsed = currentTime - startTime;
5070
+ const progress = Math.min(elapsed / duration, 1);
5071
+ const easedProgress = getEasing2(progress);
5072
+ const currentScale = startScale + (to - startScale) * easedProgress;
5073
+ setScale(currentScale);
5074
+ setIsVisible(currentScale > 0);
5075
+ if (progress < 1) {
5076
+ motionRef.current = requestAnimationFrame(updateScale);
5077
+ } else {
5078
+ setIsAnimating(false);
5079
+ onFinish?.();
5080
+ }
5081
+ };
5082
+ motionRef.current = requestAnimationFrame(updateScale);
5083
+ },
5084
+ [mounted, duration, getEasing2]
5085
+ );
5086
+ const scaleIn = useCallback(() => {
5087
+ if (!mounted || isAnimating) return;
5088
+ animate(initialScale, targetScale, () => {
5089
+ onComplete?.();
5090
+ if (repeat && (repeatCount === -1 || repeatCountRef.current < repeatCount)) {
5091
+ repeatCountRef.current++;
5092
+ onRepeat?.(repeatCountRef.current);
5093
+ timeoutRef.current = window.setTimeout(() => {
5094
+ scaleOut();
5095
+ }, repeatDelay);
5096
+ }
5097
+ });
5098
+ }, [
5099
+ mounted,
5100
+ isAnimating,
5101
+ animate,
5102
+ initialScale,
5103
+ targetScale,
5104
+ onComplete,
5105
+ repeat,
5106
+ repeatCount,
5107
+ repeatDelay,
5108
+ onRepeat
5109
+ ]);
5110
+ const scaleOut = useCallback(() => {
5111
+ if (!mounted || isAnimating) return;
5112
+ animate(targetScale, initialScale, () => {
5113
+ onComplete?.();
5114
+ if (repeat && (repeatCount === -1 || repeatCountRef.current < repeatCount)) {
5115
+ repeatCountRef.current++;
5116
+ onRepeat?.(repeatCountRef.current);
5117
+ timeoutRef.current = window.setTimeout(() => {
5118
+ scaleIn();
5119
+ }, repeatDelay);
5120
+ }
5121
+ });
5122
+ }, [
5123
+ mounted,
5124
+ isAnimating,
5125
+ animate,
5126
+ targetScale,
5127
+ initialScale,
5128
+ onComplete,
5129
+ repeat,
5130
+ repeatCount,
5131
+ repeatDelay,
5132
+ onRepeat
5133
+ ]);
5134
+ const start = useCallback(() => {
5135
+ if (!mounted || isAnimating) return;
5136
+ if (delay > 0) {
5137
+ timeoutRef.current = window.setTimeout(() => {
5138
+ scaleIn();
5139
+ }, delay);
5140
+ } else {
5141
+ scaleIn();
5142
+ }
5143
+ }, [mounted, isAnimating, delay, scaleIn]);
5144
+ const stop = useCallback(() => {
5145
+ if (motionRef.current !== null) {
5146
+ cancelAnimationFrame(motionRef.current);
5147
+ motionRef.current = null;
5148
+ }
5149
+ if (timeoutRef.current !== null) {
5150
+ clearTimeout(timeoutRef.current);
5151
+ timeoutRef.current = null;
5152
+ }
5153
+ setIsAnimating(false);
5154
+ }, []);
5155
+ const reset = useCallback(() => {
5156
+ stop();
5157
+ setScale(initialScale);
5158
+ setIsVisible(initialScale > 0);
5159
+ repeatCountRef.current = 0;
5160
+ isScalingInRef.current = true;
5161
+ }, [stop, initialScale]);
5162
+ const toggle = useCallback(() => {
5163
+ if (isScalingInRef.current) {
5164
+ scaleOut();
5165
+ isScalingInRef.current = false;
5166
+ } else {
5167
+ scaleIn();
5168
+ isScalingInRef.current = true;
5169
+ }
5170
+ }, [scaleIn, scaleOut]);
5171
+ useEffect(() => {
5172
+ if (mounted && autoStart) {
5173
+ start();
5174
+ }
5175
+ }, [mounted, autoStart, start]);
5176
+ useEffect(() => {
5177
+ return () => {
5178
+ if (motionRef.current !== null) {
5179
+ cancelAnimationFrame(motionRef.current);
5180
+ }
5181
+ if (timeoutRef.current !== null) {
5182
+ clearTimeout(timeoutRef.current);
5183
+ }
5184
+ };
5185
+ }, []);
5186
+ return {
5187
+ scale,
5188
+ isAnimating,
5189
+ isVisible,
5190
+ mounted,
5191
+ start,
5192
+ stop,
5193
+ reset,
5194
+ scaleIn,
5195
+ scaleOut,
5196
+ toggle
5197
+ };
5198
+ }
5199
+ function useAutoSlide(options = {}) {
5200
+ const {
5201
+ direction = "left",
5202
+ distance = 100,
5203
+ initialPosition,
5204
+ targetPosition,
5205
+ duration = 1e3,
5206
+ delay = 0,
5207
+ repeat = false,
5208
+ repeatDelay = 1e3,
5209
+ repeatCount = -1,
5210
+ ease = "ease-in-out",
5211
+ autoStart = true,
5212
+ onComplete,
5213
+ onRepeat,
5214
+ showOnMount = false
5215
+ } = options;
5216
+ const getDefaultPositions = useCallback(() => {
5217
+ const defaultInitial = { x: 0, y: 0 };
5218
+ const defaultTarget = { x: 0, y: 0 };
5219
+ switch (direction) {
5220
+ case "left":
5221
+ defaultInitial.x = distance;
5222
+ defaultTarget.x = 0;
5223
+ break;
5224
+ case "right":
5225
+ defaultInitial.x = -distance;
5226
+ defaultTarget.x = 0;
5227
+ break;
5228
+ case "up":
5229
+ defaultInitial.y = distance;
5230
+ defaultTarget.y = 0;
5231
+ break;
5232
+ case "down":
5233
+ defaultInitial.y = -distance;
5234
+ defaultTarget.y = 0;
5235
+ break;
5236
+ case "left-up":
5237
+ defaultInitial.x = distance;
5238
+ defaultInitial.y = distance;
5239
+ defaultTarget.x = 0;
5240
+ defaultTarget.y = 0;
5241
+ break;
5242
+ case "left-down":
5243
+ defaultInitial.x = distance;
5244
+ defaultInitial.y = -distance;
5245
+ defaultTarget.x = 0;
5246
+ defaultTarget.y = 0;
5247
+ break;
5248
+ case "right-up":
5249
+ defaultInitial.x = -distance;
5250
+ defaultInitial.y = distance;
5251
+ defaultTarget.x = 0;
5252
+ defaultTarget.y = 0;
5253
+ break;
5254
+ case "right-down":
5255
+ defaultInitial.x = -distance;
5256
+ defaultInitial.y = -distance;
5257
+ defaultTarget.x = 0;
5258
+ defaultTarget.y = 0;
5259
+ break;
5260
+ }
5261
+ return {
5262
+ initial: initialPosition || defaultInitial,
5263
+ target: targetPosition || defaultTarget
5264
+ };
5265
+ }, [direction, distance, initialPosition, targetPosition]);
5266
+ const positions = getDefaultPositions();
5267
+ const [position, setPosition] = useState(
5268
+ showOnMount ? positions.initial : positions.target
5269
+ );
5270
+ const [isAnimating, setIsAnimating] = useState(false);
5271
+ const [isVisible, setIsVisible] = useState(showOnMount ? true : false);
5272
+ const [mounted, setMounted] = useState(false);
5273
+ const motionRef = useRef(null);
5274
+ const timeoutRef = useRef(null);
5275
+ const repeatCountRef = useRef(0);
5276
+ const isSlidingInRef = useRef(true);
5277
+ useEffect(() => {
5278
+ setMounted(true);
5279
+ }, []);
5280
+ const getEasing2 = useCallback(
5281
+ (t) => {
5282
+ switch (ease) {
5283
+ case "linear":
5284
+ return t;
5285
+ case "ease-in":
5286
+ return t * t;
5287
+ case "ease-out":
5288
+ return 1 - (1 - t) * (1 - t);
5289
+ case "ease-in-out":
5290
+ return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
5291
+ default:
5292
+ return t;
5293
+ }
5294
+ },
5295
+ [ease]
5296
+ );
5297
+ const animate = useCallback(
5298
+ (from, to, onFinish) => {
5299
+ if (!mounted) return;
5300
+ setIsAnimating(true);
5301
+ const startTime = performance.now();
5302
+ const startPosition = from;
5303
+ const updatePosition = (currentTime) => {
5304
+ const elapsed = currentTime - startTime;
5305
+ const progress = Math.min(elapsed / duration, 1);
5306
+ const easedProgress = getEasing2(progress);
5307
+ const currentX = startPosition.x + (to.x - startPosition.x) * easedProgress;
5308
+ const currentY = startPosition.y + (to.y - startPosition.y) * easedProgress;
5309
+ setPosition({ x: currentX, y: currentY });
5310
+ setIsVisible(true);
5311
+ if (progress < 1) {
5312
+ motionRef.current = requestAnimationFrame(updatePosition);
5313
+ } else {
5314
+ setIsAnimating(false);
5315
+ onFinish?.();
5316
+ }
5317
+ };
5318
+ motionRef.current = requestAnimationFrame(updatePosition);
5319
+ },
5320
+ [mounted, duration, getEasing2]
5321
+ );
5322
+ const slideIn = useCallback(() => {
5323
+ if (!mounted || isAnimating) return;
5324
+ animate(positions.initial, positions.target, () => {
5325
+ onComplete?.();
5326
+ if (repeat && (repeatCount === -1 || repeatCountRef.current < repeatCount)) {
5327
+ repeatCountRef.current++;
5328
+ onRepeat?.(repeatCountRef.current);
5329
+ timeoutRef.current = window.setTimeout(() => {
5330
+ slideOut();
5331
+ }, repeatDelay);
5332
+ }
5333
+ });
5334
+ }, [
5335
+ mounted,
5336
+ isAnimating,
5337
+ animate,
5338
+ positions.initial,
5339
+ positions.target,
5340
+ onComplete,
5341
+ repeat,
5342
+ repeatCount,
5343
+ repeatDelay,
5344
+ onRepeat
5345
+ ]);
5346
+ const slideOut = useCallback(() => {
5347
+ if (!mounted || isAnimating) return;
5348
+ animate(positions.target, positions.initial, () => {
5349
+ onComplete?.();
5350
+ if (repeat && (repeatCount === -1 || repeatCountRef.current < repeatCount)) {
5351
+ repeatCountRef.current++;
5352
+ onRepeat?.(repeatCountRef.current);
5353
+ timeoutRef.current = window.setTimeout(() => {
5354
+ slideIn();
5355
+ }, repeatDelay);
5356
+ }
5357
+ });
5358
+ }, [
5359
+ mounted,
5360
+ isAnimating,
5361
+ animate,
5362
+ positions.target,
5363
+ positions.initial,
5364
+ onComplete,
5365
+ repeat,
5366
+ repeatCount,
5367
+ repeatDelay,
5368
+ onRepeat
5369
+ ]);
5370
+ const start = useCallback(() => {
5371
+ if (!mounted || isAnimating) return;
5372
+ if (delay > 0) {
5373
+ timeoutRef.current = window.setTimeout(() => {
5374
+ slideIn();
5375
+ }, delay);
5376
+ } else {
5377
+ slideIn();
5378
+ }
5379
+ }, [mounted, isAnimating, delay, slideIn]);
5380
+ const stop = useCallback(() => {
5381
+ if (motionRef.current !== null) {
5382
+ cancelAnimationFrame(motionRef.current);
5383
+ motionRef.current = null;
5384
+ }
5385
+ if (timeoutRef.current !== null) {
5386
+ clearTimeout(timeoutRef.current);
5387
+ timeoutRef.current = null;
5388
+ }
5389
+ setIsAnimating(false);
5390
+ }, []);
5391
+ const reset = useCallback(() => {
5392
+ stop();
5393
+ setPosition(positions.initial);
5394
+ setIsVisible(showOnMount ? true : false);
5395
+ repeatCountRef.current = 0;
5396
+ isSlidingInRef.current = true;
5397
+ }, [stop, positions.initial, showOnMount]);
5398
+ const toggle = useCallback(() => {
5399
+ if (isSlidingInRef.current) {
5400
+ slideOut();
5401
+ isSlidingInRef.current = false;
5402
+ } else {
5403
+ slideIn();
5404
+ isSlidingInRef.current = true;
5405
+ }
5406
+ }, [slideIn, slideOut]);
5407
+ useEffect(() => {
5408
+ if (mounted && autoStart) {
5409
+ start();
5410
+ }
5411
+ }, [mounted, autoStart, start]);
5412
+ useEffect(() => {
5413
+ return () => {
5414
+ if (motionRef.current !== null) {
5415
+ cancelAnimationFrame(motionRef.current);
5416
+ }
5417
+ if (timeoutRef.current !== null) {
5418
+ clearTimeout(timeoutRef.current);
5419
+ }
5420
+ };
5421
+ }, []);
5422
+ return {
5423
+ position,
5424
+ isAnimating,
5425
+ isVisible,
5426
+ mounted,
5427
+ start,
5428
+ stop,
5429
+ reset,
5430
+ slideIn,
5431
+ slideOut,
5432
+ toggle
5433
+ };
5434
+ }
5435
+ function useMotionOrchestra(options = {}) {
5436
+ const {
5437
+ mode = "sequential",
5438
+ staggerDelay = 100,
5439
+ autoStart = false,
5440
+ loop = false,
5441
+ onComplete
5442
+ } = options;
5443
+ const [orchestraState, setOrchestraState] = useState({
5444
+ isPlaying: false,
5445
+ currentStep: 0,
5446
+ completedSteps: /* @__PURE__ */ new Set()
5447
+ });
5448
+ const motionsRef = useRef([]);
5449
+ const timeoutsRef = useRef([]);
5450
+ const addMotion = useCallback((step) => {
5451
+ motionsRef.current.push(step);
5452
+ }, []);
5453
+ const removeMotion = useCallback((id) => {
5454
+ motionsRef.current = motionsRef.current.filter((step) => step.id !== id);
5455
+ }, []);
5456
+ const clearTimeouts = useCallback(() => {
5457
+ timeoutsRef.current.forEach((timeout) => clearTimeout(timeout));
5458
+ timeoutsRef.current = [];
5459
+ }, []);
5460
+ const playSequential = useCallback(() => {
5461
+ if (motionsRef.current.length === 0) return;
5462
+ const playStep = (index) => {
5463
+ if (index >= motionsRef.current.length) {
5464
+ setOrchestraState((prev) => ({
5465
+ ...prev,
5466
+ isPlaying: false,
5467
+ currentStep: 0
5468
+ }));
5469
+ onComplete?.();
5470
+ if (loop) {
5471
+ setTimeout(() => {
5472
+ setOrchestraState((prev) => ({
5473
+ ...prev,
5474
+ isPlaying: true,
5475
+ completedSteps: /* @__PURE__ */ new Set()
5476
+ }));
5477
+ playSequential();
5478
+ }, 1e3);
5479
+ }
5480
+ return;
5481
+ }
5482
+ const step = motionsRef.current[index];
5483
+ setOrchestraState((prev) => ({
5484
+ ...prev,
5485
+ currentStep: index,
5486
+ completedSteps: /* @__PURE__ */ new Set([...prev.completedSteps, step.id])
5487
+ }));
5488
+ step.motion();
5489
+ if (step.onComplete) {
5490
+ step.onComplete();
5491
+ }
5492
+ const timeout = setTimeout(() => {
5493
+ playStep(index + 1);
5494
+ }, step.delay || 0);
5495
+ timeoutsRef.current.push(timeout);
5496
+ };
5497
+ playStep(0);
5498
+ }, [loop, onComplete]);
5499
+ const playParallel = useCallback(() => {
5500
+ if (motionsRef.current.length === 0) return;
5501
+ const completedSteps = /* @__PURE__ */ new Set();
5502
+ motionsRef.current.forEach((step) => {
5503
+ const timeout = setTimeout(() => {
5504
+ step.motion();
5505
+ completedSteps.add(step.id);
5506
+ if (step.onComplete) {
5507
+ step.onComplete();
5508
+ }
5509
+ if (completedSteps.size === motionsRef.current.length) {
5510
+ setOrchestraState((prev) => ({
5511
+ ...prev,
5512
+ isPlaying: false,
5513
+ currentStep: 0
5514
+ }));
5515
+ onComplete?.();
5516
+ if (loop) {
5517
+ setTimeout(() => {
5518
+ setOrchestraState((prev) => ({ ...prev, isPlaying: true }));
5519
+ playParallel();
5520
+ }, 1e3);
5521
+ }
5522
+ }
5523
+ }, step.delay || 0);
5524
+ timeoutsRef.current.push(timeout);
5525
+ });
5526
+ setOrchestraState((prev) => ({
5527
+ ...prev,
5528
+ completedSteps: new Set(completedSteps)
5529
+ }));
5530
+ }, [loop, onComplete]);
5531
+ const playStagger = useCallback(() => {
5532
+ if (motionsRef.current.length === 0) return;
5533
+ const completedSteps = /* @__PURE__ */ new Set();
5534
+ motionsRef.current.forEach((step, index) => {
5535
+ const timeout = setTimeout(
5536
+ () => {
5537
+ step.motion();
5538
+ completedSteps.add(step.id);
5539
+ if (step.onComplete) {
5540
+ step.onComplete();
5541
+ }
5542
+ setOrchestraState((prev) => ({
5543
+ ...prev,
5544
+ currentStep: index,
5545
+ completedSteps: /* @__PURE__ */ new Set([...prev.completedSteps, step.id])
5546
+ }));
5547
+ if (completedSteps.size === motionsRef.current.length) {
5548
+ setOrchestraState((prev) => ({
5549
+ ...prev,
5550
+ isPlaying: false,
5551
+ currentStep: 0
5552
+ }));
5553
+ onComplete?.();
5554
+ if (loop) {
5555
+ setTimeout(() => {
5556
+ setOrchestraState((prev) => ({
5557
+ ...prev,
5558
+ isPlaying: true,
5559
+ completedSteps: /* @__PURE__ */ new Set()
5560
+ }));
5561
+ playStagger();
5562
+ }, 1e3);
5563
+ }
5564
+ }
5565
+ },
5566
+ (step.delay || 0) + index * staggerDelay
5567
+ );
5568
+ timeoutsRef.current.push(timeout);
5569
+ });
5570
+ }, [staggerDelay, loop, onComplete]);
5571
+ const play = useCallback(() => {
5572
+ clearTimeouts();
5573
+ setOrchestraState((prev) => ({
5574
+ ...prev,
5575
+ isPlaying: true,
5576
+ currentStep: 0,
5577
+ completedSteps: /* @__PURE__ */ new Set()
5578
+ }));
5579
+ switch (mode) {
5580
+ case "sequential":
5581
+ playSequential();
5582
+ break;
5583
+ case "parallel":
5584
+ playParallel();
5585
+ break;
5586
+ case "stagger":
5587
+ playStagger();
5588
+ break;
5589
+ }
5590
+ }, [mode, clearTimeouts, playSequential, playParallel, playStagger]);
5591
+ const stop = useCallback(() => {
5592
+ clearTimeouts();
5593
+ setOrchestraState((prev) => ({
5594
+ ...prev,
5595
+ isPlaying: false,
5596
+ currentStep: 0
5597
+ }));
5598
+ }, [clearTimeouts]);
5599
+ const pause = useCallback(() => {
5600
+ setOrchestraState((prev) => ({ ...prev, isPlaying: false }));
5601
+ }, []);
5602
+ const resume = useCallback(() => {
5603
+ if (orchestraState.currentStep < motionsRef.current.length) {
5604
+ setOrchestraState((prev) => ({ ...prev, isPlaying: true }));
5605
+ switch (mode) {
5606
+ case "sequential":
5607
+ playSequential();
5608
+ break;
5609
+ case "parallel":
5610
+ playParallel();
5611
+ break;
5612
+ case "stagger":
5613
+ playStagger();
5614
+ break;
5615
+ }
5616
+ }
5617
+ }, [
5618
+ mode,
5619
+ orchestraState.currentStep,
5620
+ playSequential,
5621
+ playParallel,
5622
+ playStagger
5623
+ ]);
5624
+ useEffect(() => {
5625
+ if (autoStart && motionsRef.current.length > 0) {
5626
+ play();
5627
+ }
5628
+ }, [autoStart, play]);
5629
+ useEffect(() => {
5630
+ return () => {
5631
+ clearTimeouts();
5632
+ };
5633
+ }, [clearTimeouts]);
5634
+ return {
5635
+ addMotion,
5636
+ removeMotion,
5637
+ play,
5638
+ stop,
5639
+ pause,
5640
+ resume,
5641
+ isPlaying: orchestraState.isPlaying,
5642
+ currentStep: orchestraState.currentStep,
5643
+ completedSteps: orchestraState.completedSteps,
5644
+ totalSteps: motionsRef.current.length
5645
+ };
5646
+ }
5647
+ function useOrchestration(options = {}) {
5648
+ const {
5649
+ autoStart = false,
5650
+ loop = false,
5651
+ loopCount = -1,
5652
+ loopDelay = 1e3,
5653
+ timeline = [],
5654
+ duration: totalDuration,
5655
+ speed = 1,
5656
+ reverse = false,
5657
+ onStart,
5658
+ onComplete,
5659
+ onLoop,
5660
+ onError: _onError,
5661
+ onProgress,
5662
+ onStepStart,
5663
+ onStepComplete
5664
+ } = options;
5665
+ const [state, setState] = useState({
5666
+ isPlaying: false,
5667
+ isPaused: false,
5668
+ currentTime: 0,
5669
+ progress: 0,
5670
+ currentStep: null,
5671
+ loopCount: 0,
5672
+ error: null
5673
+ });
5674
+ const [steps, setSteps] = useState(timeline);
5675
+ const [currentSpeed, setCurrentSpeed] = useState(speed);
5676
+ const [isReversed, setIsReversed] = useState(reverse);
5677
+ const motionRef = useRef(null);
5678
+ const startTimeRef = useRef(0);
5679
+ const pauseTimeRef = useRef(0);
5680
+ const stepStartTimesRef = useRef(/* @__PURE__ */ new Map());
5681
+ const stepDurationsRef = useRef(/* @__PURE__ */ new Map());
5682
+ const getEasing2 = useCallback(
5683
+ (t, ease = "linear") => {
5684
+ switch (ease) {
5685
+ case "linear":
5686
+ return t;
5687
+ case "ease-in":
5688
+ return t * t;
5689
+ case "ease-out":
5690
+ return 1 - (1 - t) * (1 - t);
5691
+ case "ease-in-out":
5692
+ return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
5693
+ case "bounce":
5694
+ if (t < 1 / 2.75) {
5695
+ return 7.5625 * t * t;
5696
+ } else if (t < 2 / 2.75) {
5697
+ return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
5698
+ } else if (t < 2.5 / 2.75) {
5699
+ return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
5700
+ } else {
5701
+ return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
5702
+ }
5703
+ case "elastic":
5704
+ if (t === 0) return 0;
5705
+ if (t === 1) return 1;
5706
+ return Math.pow(2, -10 * t) * Math.sin((t - 0.075) * (2 * Math.PI) / 0.3) + 1;
5707
+ default:
5708
+ return t;
5709
+ }
5710
+ },
5711
+ []
5712
+ );
5713
+ const getTotalDuration = useCallback(() => {
5714
+ if (totalDuration) return totalDuration;
5715
+ let maxEndTime = 0;
5716
+ steps.forEach((step) => {
5717
+ const stepEndTime = (step.delay || 0) + step.duration;
5718
+ maxEndTime = Math.max(maxEndTime, stepEndTime);
5719
+ });
5720
+ return maxEndTime;
5721
+ }, [steps, totalDuration]);
5722
+ const calculateStepTimes = useCallback(() => {
5723
+ const stepTimes = /* @__PURE__ */ new Map();
5724
+ const stepDurations = /* @__PURE__ */ new Map();
5725
+ let currentTime = 0;
5726
+ steps.forEach((step) => {
5727
+ stepTimes.set(step.id, currentTime + (step.delay || 0));
5728
+ stepDurations.set(step.id, step.duration);
5729
+ currentTime += (step.delay || 0) + step.duration;
5730
+ });
5731
+ stepStartTimesRef.current = stepTimes;
5732
+ stepDurationsRef.current = stepDurations;
5733
+ }, [steps]);
5734
+ const getCurrentStep = useCallback(
5735
+ (time) => {
5736
+ for (const step of steps) {
5737
+ const startTime = stepStartTimesRef.current.get(step.id) || 0;
5738
+ const endTime = startTime + (stepDurationsRef.current.get(step.id) || 0);
5739
+ if (time >= startTime && time <= endTime) {
5740
+ return step.id;
5741
+ }
5742
+ }
5743
+ return null;
5744
+ },
5745
+ [steps]
5746
+ );
5747
+ const getStepProgress = useCallback(
5748
+ (stepId) => {
5749
+ const startTime = stepStartTimesRef.current.get(stepId) || 0;
5750
+ const duration = stepDurationsRef.current.get(stepId) || 0;
5751
+ const currentTime = state.currentTime;
5752
+ if (currentTime < startTime) return 0;
5753
+ if (currentTime > startTime + duration) return 1;
5754
+ const stepProgress = (currentTime - startTime) / duration;
5755
+ return Math.max(0, Math.min(1, stepProgress));
5756
+ },
5757
+ [state.currentTime]
5758
+ );
5759
+ const getStepTime = useCallback(
5760
+ (stepId) => {
5761
+ const startTime = stepStartTimesRef.current.get(stepId) || 0;
5762
+ const duration = stepDurationsRef.current.get(stepId) || 0;
5763
+ const currentTime = state.currentTime;
5764
+ if (currentTime < startTime) return 0;
5765
+ if (currentTime > startTime + duration) return duration;
5766
+ return currentTime - startTime;
5767
+ },
5768
+ [state.currentTime]
5769
+ );
5770
+ const updateMotion = useCallback(
5771
+ (currentTime) => {
5772
+ const total = getTotalDuration();
5773
+ const adjustedTime = isReversed ? total - currentTime : currentTime;
5774
+ const progress = Math.min(adjustedTime / total, 1);
5775
+ const currentStep = getCurrentStep(adjustedTime);
5776
+ setState((prev) => ({
5777
+ ...prev,
5778
+ currentTime: adjustedTime,
5779
+ progress,
5780
+ currentStep
5781
+ }));
5782
+ onProgress?.(progress);
5783
+ if (currentStep) {
5784
+ const step = steps.find((s) => s.id === currentStep);
5785
+ if (step) {
5786
+ const stepProgress = getStepProgress(currentStep);
5787
+ const easedProgress = getEasing2(stepProgress, step.ease);
5788
+ step.onUpdate?.(easedProgress);
5789
+ }
5790
+ }
5791
+ if (progress >= 1) {
5792
+ if (loop && (loopCount === -1 || state.loopCount < loopCount)) {
5793
+ setState((prev) => ({
5794
+ ...prev,
5795
+ loopCount: prev.loopCount + 1
5796
+ }));
5797
+ onLoop?.(state.loopCount + 1);
5798
+ setTimeout(() => {
5799
+ reset();
5800
+ play();
5801
+ }, loopDelay);
5802
+ } else {
5803
+ setState((prev) => ({
5804
+ ...prev,
5805
+ isPlaying: false,
5806
+ currentTime: isReversed ? 0 : total,
5807
+ progress: 1
5808
+ }));
5809
+ onComplete?.();
5810
+ }
5811
+ } else {
5812
+ motionRef.current = requestAnimationFrame(() => {
5813
+ const elapsed = (performance.now() - startTimeRef.current) * currentSpeed / 1e3;
5814
+ updateMotion(elapsed);
5815
+ });
5816
+ }
5817
+ },
5818
+ [
5819
+ getTotalDuration,
5820
+ isReversed,
5821
+ getCurrentStep,
5822
+ onProgress,
5823
+ steps,
5824
+ getStepProgress,
5825
+ getEasing2,
5826
+ loop,
5827
+ loopCount,
5828
+ state.loopCount,
5829
+ loopDelay,
5830
+ onLoop,
5831
+ onComplete,
5832
+ currentSpeed
5833
+ ]
5834
+ );
5835
+ const play = useCallback(() => {
5836
+ if (state.isPlaying) return;
5837
+ setState((prev) => ({
5838
+ ...prev,
5839
+ isPlaying: true,
5840
+ isPaused: false,
5841
+ error: null
5842
+ }));
5843
+ onStart?.();
5844
+ const startTime = performance.now() - state.currentTime * 1e3 / currentSpeed;
5845
+ startTimeRef.current = startTime;
5846
+ motionRef.current = requestAnimationFrame(() => {
5847
+ const elapsed = (performance.now() - startTimeRef.current) * currentSpeed / 1e3;
5848
+ updateMotion(elapsed);
5849
+ });
5850
+ }, [state.isPlaying, state.currentTime, currentSpeed, onStart, updateMotion]);
5851
+ const pause = useCallback(() => {
5852
+ if (!state.isPlaying || state.isPaused) return;
5853
+ setState((prev) => ({
5854
+ ...prev,
5855
+ isPaused: true
5856
+ }));
5857
+ if (motionRef.current) {
5858
+ cancelAnimationFrame(motionRef.current);
5859
+ motionRef.current = null;
5860
+ }
5861
+ pauseTimeRef.current = state.currentTime;
5862
+ }, [state.isPlaying, state.isPaused, state.currentTime]);
5863
+ const stop = useCallback(() => {
5864
+ setState((prev) => ({
5865
+ ...prev,
5866
+ isPlaying: false,
5867
+ isPaused: false,
5868
+ currentTime: 0,
5869
+ progress: 0,
5870
+ currentStep: null
5871
+ }));
5872
+ if (motionRef.current) {
5873
+ cancelAnimationFrame(motionRef.current);
5874
+ motionRef.current = null;
5875
+ }
5876
+ }, []);
5877
+ const reset = useCallback(() => {
5878
+ stop();
5879
+ setState((prev) => ({
5880
+ ...prev,
5881
+ currentTime: 0,
5882
+ progress: 0,
5883
+ currentStep: null,
5884
+ loopCount: 0
5885
+ }));
5886
+ }, [stop]);
5887
+ const seek = useCallback(
5888
+ (time) => {
5889
+ const total = getTotalDuration();
5890
+ const clampedTime = Math.max(0, Math.min(time, total));
5891
+ setState((prev) => ({
5892
+ ...prev,
5893
+ currentTime: clampedTime,
5894
+ progress: clampedTime / total,
5895
+ currentStep: getCurrentStep(clampedTime)
5896
+ }));
5897
+ },
5898
+ [getTotalDuration, getCurrentStep]
5899
+ );
5900
+ const setSpeed = useCallback((speed2) => {
5901
+ setCurrentSpeed(Math.max(0.1, speed2));
5902
+ }, []);
5903
+ const reverseDirection = useCallback(() => {
5904
+ setIsReversed((prev) => !prev);
5905
+ }, []);
5906
+ const addStep = useCallback((step) => {
5907
+ setSteps((prev) => [...prev, step]);
5908
+ }, []);
5909
+ const removeStep = useCallback((stepId) => {
5910
+ setSteps((prev) => prev.filter((step) => step.id !== stepId));
5911
+ }, []);
5912
+ const updateStep = useCallback(
5913
+ (stepId, updates) => {
5914
+ setSteps(
5915
+ (prev) => prev.map(
5916
+ (step) => step.id === stepId ? { ...step, ...updates } : step
5917
+ )
5918
+ );
5919
+ },
5920
+ []
5921
+ );
5922
+ const reorderSteps = useCallback((stepIds) => {
5923
+ setSteps((prev) => {
5924
+ const stepMap = new Map(prev.map((step) => [step.id, step]));
5925
+ return stepIds.map((id) => stepMap.get(id)).filter(Boolean);
5926
+ });
5927
+ }, []);
5928
+ useEffect(() => {
5929
+ const currentStep = state.currentStep;
5930
+ if (currentStep) {
5931
+ onStepStart?.(currentStep);
5932
+ const step = steps.find((s) => s.id === currentStep);
5933
+ step?.onStart?.();
5934
+ }
5935
+ }, [state.currentStep, steps, onStepStart]);
5936
+ useEffect(() => {
5937
+ const currentStep = state.currentStep;
5938
+ if (currentStep) {
5939
+ const stepProgress = getStepProgress(currentStep);
5940
+ if (stepProgress >= 1) {
5941
+ const step = steps.find((s) => s.id === currentStep);
5942
+ step?.onComplete?.();
5943
+ onStepComplete?.(currentStep);
5944
+ }
5945
+ }
5946
+ }, [
5947
+ state.currentTime,
5948
+ state.currentStep,
5949
+ steps,
5950
+ getStepProgress,
5951
+ onStepComplete
5952
+ ]);
5953
+ useEffect(() => {
5954
+ calculateStepTimes();
5955
+ }, [calculateStepTimes]);
5956
+ useEffect(() => {
5957
+ if (autoStart && steps.length > 0) {
5958
+ play();
5959
+ }
5960
+ }, [autoStart, steps.length, play]);
5961
+ useEffect(() => {
5962
+ return () => {
5963
+ if (motionRef.current) {
5964
+ cancelAnimationFrame(motionRef.current);
5965
+ }
5966
+ };
5967
+ }, []);
5968
+ return {
5969
+ // 상태
5970
+ isPlaying: state.isPlaying,
5971
+ isPaused: state.isPaused,
5972
+ currentTime: state.currentTime,
5973
+ progress: state.progress,
5974
+ currentStep: state.currentStep,
5975
+ loopCount: state.loopCount,
5976
+ error: state.error,
5977
+ // 제어
5978
+ play,
5979
+ pause,
5980
+ stop,
5981
+ reset,
5982
+ seek,
5983
+ setSpeed,
5984
+ reverse: reverseDirection,
5985
+ // 타임라인 관리
5986
+ addStep,
5987
+ removeStep,
5988
+ updateStep,
5989
+ reorderSteps,
5990
+ // 유틸리티
5991
+ getStepProgress,
5992
+ getStepTime,
5993
+ getTotalDuration
5994
+ };
5995
+ }
5996
+ function useSequence(sequence, options = {}) {
5997
+ const { autoStart = true, loop = false } = options;
5998
+ const [currentIndex, setCurrentIndex] = useState(0);
5999
+ const [isPlaying, setIsPlaying] = useState(false);
6000
+ const motionsRef = useRef([]);
6001
+ const timeoutsRef = useRef([]);
6002
+ const motions = sequence.map((item) => item.hook());
6003
+ const start = useCallback(() => {
6004
+ if (isPlaying) return;
6005
+ setIsPlaying(true);
6006
+ setCurrentIndex(0);
6007
+ motionsRef.current = motions;
6008
+ if (motionsRef.current[0]) {
6009
+ motionsRef.current[0].start();
6010
+ }
6011
+ sequence.forEach((item, index) => {
6012
+ if (index === 0) return;
6013
+ const timeout = window.setTimeout(() => {
6014
+ if (motionsRef.current[index]) {
6015
+ motionsRef.current[index].start();
6016
+ setCurrentIndex(index);
6017
+ }
6018
+ }, item.delay || 0);
6019
+ timeoutsRef.current.push(timeout);
6020
+ });
6021
+ const totalDuration = sequence.reduce((total, item) => {
6022
+ return total + (item.delay || 0);
6023
+ }, 0);
6024
+ const finalTimeout = window.setTimeout(() => {
6025
+ setIsPlaying(false);
6026
+ if (loop) {
6027
+ start();
6028
+ }
6029
+ }, totalDuration + 1e3);
6030
+ timeoutsRef.current.push(finalTimeout);
6031
+ }, [sequence, isPlaying, loop, motions]);
6032
+ const stop = useCallback(() => {
6033
+ setIsPlaying(false);
6034
+ setCurrentIndex(0);
6035
+ timeoutsRef.current.forEach((timeout) => window.clearTimeout(timeout));
6036
+ timeoutsRef.current = [];
6037
+ motionsRef.current.forEach((motion) => {
6038
+ if (motion && motion.stop) {
6039
+ motion.stop();
6040
+ }
6041
+ });
6042
+ }, []);
6043
+ const reset = useCallback(() => {
6044
+ stop();
6045
+ setCurrentIndex(0);
6046
+ motionsRef.current.forEach((motion) => {
6047
+ if (motion && motion.reset) {
6048
+ motion.reset();
6049
+ }
6050
+ });
6051
+ }, [stop]);
6052
+ const pause = useCallback(() => {
6053
+ setIsPlaying(false);
6054
+ if (motionsRef.current[currentIndex] && motionsRef.current[currentIndex].pause) {
6055
+ motionsRef.current[currentIndex].pause();
6056
+ }
6057
+ }, [currentIndex]);
6058
+ const resume = useCallback(() => {
6059
+ setIsPlaying(true);
6060
+ if (motionsRef.current[currentIndex] && motionsRef.current[currentIndex].resume) {
6061
+ motionsRef.current[currentIndex].resume();
6062
+ }
6063
+ }, [currentIndex]);
6064
+ useEffect(() => {
6065
+ if (autoStart && !isPlaying) {
6066
+ start();
6067
+ }
6068
+ }, [autoStart, isPlaying, start]);
6069
+ return {
6070
+ start,
6071
+ stop,
6072
+ pause,
6073
+ resume,
6074
+ reset,
6075
+ isPlaying,
6076
+ currentIndex,
6077
+ totalMotions: sequence.length,
6078
+ ref: motions[0]?.ref ?? { current: null }
6079
+ // 첫 번째 모션의 ref 반환
6080
+ };
6081
+ }
6082
+ function useLayoutMotion(config) {
6083
+ const {
6084
+ from,
6085
+ to,
6086
+ duration = 500,
6087
+ easing = "ease-in-out",
6088
+ autoStart = false,
6089
+ onComplete
6090
+ } = config;
6091
+ const ref = useRef(null);
6092
+ const [state, setState] = useState({
6093
+ isAnimating: false,
6094
+ progress: 0,
6095
+ currentStyle: {}
6096
+ });
6097
+ const motionFrameRef = useRef(null);
6098
+ const startTimeRef = useRef(0);
6099
+ const parseValue = useCallback(
6100
+ (value) => {
6101
+ if (typeof value === "number") return value;
6102
+ if (typeof value === "string") {
6103
+ const match = value.match(/^(\d+(?:\.\d+)?)(px|%|em|rem|vh|vw)?$/);
6104
+ return match ? parseFloat(match[1]) : 0;
6105
+ }
6106
+ return 0;
6107
+ },
6108
+ []
6109
+ );
6110
+ const interpolate = useCallback(
6111
+ (from2, to2, progress) => {
6112
+ return from2 + (to2 - from2) * progress;
6113
+ },
6114
+ []
6115
+ );
6116
+ const applyEasing2 = useCallback(
6117
+ (t) => {
6118
+ switch (easing) {
6119
+ case "ease-in":
6120
+ return t * t;
6121
+ case "ease-out":
6122
+ return 1 - (1 - t) * (1 - t);
6123
+ case "ease-in-out":
6124
+ return t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
6125
+ default:
6126
+ return t;
6127
+ }
6128
+ },
6129
+ [easing]
6130
+ );
6131
+ const calculateStyle = useCallback(
6132
+ (progress) => {
6133
+ const easedProgress = applyEasing2(progress);
6134
+ const style = {};
6135
+ if (from.width !== void 0 && to.width !== void 0) {
6136
+ const fromWidth = parseValue(from.width);
6137
+ const toWidth = parseValue(to.width);
6138
+ style.width = `${interpolate(fromWidth, toWidth, easedProgress)}px`;
6139
+ }
6140
+ if (from.height !== void 0 && to.height !== void 0) {
6141
+ const fromHeight = parseValue(from.height);
6142
+ const toHeight = parseValue(to.height);
6143
+ style.height = `${interpolate(fromHeight, toHeight, easedProgress)}px`;
6144
+ }
6145
+ if (from.flexDirection !== to.flexDirection) {
6146
+ style.flexDirection = progress < 0.5 ? from.flexDirection : to.flexDirection;
6147
+ }
6148
+ if (from.justifyContent !== to.justifyContent) {
6149
+ style.justifyContent = progress < 0.5 ? from.justifyContent : to.justifyContent;
6150
+ }
6151
+ if (from.alignItems !== to.alignItems) {
6152
+ style.alignItems = progress < 0.5 ? from.alignItems : to.alignItems;
6153
+ }
6154
+ if (from.gap !== void 0 && to.gap !== void 0) {
6155
+ const fromGap = parseValue(from.gap);
6156
+ const toGap = parseValue(to.gap);
6157
+ style.gap = `${interpolate(fromGap, toGap, easedProgress)}px`;
6158
+ }
6159
+ if (from.gridTemplateColumns !== to.gridTemplateColumns) {
6160
+ style.gridTemplateColumns = progress < 0.5 ? from.gridTemplateColumns : to.gridTemplateColumns;
6161
+ }
6162
+ if (from.gridTemplateRows !== to.gridTemplateRows) {
6163
+ style.gridTemplateRows = progress < 0.5 ? from.gridTemplateRows : to.gridTemplateRows;
6164
+ }
6165
+ if (from.gridGap !== void 0 && to.gridGap !== void 0) {
6166
+ const fromGridGap = parseValue(from.gridGap);
6167
+ const toGridGap = parseValue(to.gridGap);
6168
+ style.gridGap = `${interpolate(fromGridGap, toGridGap, easedProgress)}px`;
6169
+ }
6170
+ return style;
6171
+ },
6172
+ [from, to, applyEasing2, parseValue, interpolate]
6173
+ );
6174
+ const updateMotion = useCallback(() => {
6175
+ if (!state.isAnimating) return;
6176
+ const elapsed = Date.now() - startTimeRef.current;
6177
+ const progress = Math.min(elapsed / duration, 1);
6178
+ setState((prev) => ({
6179
+ ...prev,
6180
+ progress,
6181
+ currentStyle: calculateStyle(progress)
6182
+ }));
6183
+ if (progress < 1) {
6184
+ motionFrameRef.current = requestAnimationFrame(updateMotion);
6185
+ } else {
6186
+ setState((prev) => ({ ...prev, isAnimating: false }));
6187
+ onComplete?.();
6188
+ }
6189
+ }, [state.isAnimating, duration, calculateStyle, onComplete]);
6190
+ const start = useCallback(() => {
6191
+ setState((prev) => ({ ...prev, isAnimating: true, progress: 0 }));
6192
+ startTimeRef.current = Date.now();
6193
+ updateMotion();
6194
+ }, [updateMotion]);
6195
+ const stop = useCallback(() => {
6196
+ setState((prev) => ({ ...prev, isAnimating: false }));
6197
+ if (motionFrameRef.current) {
6198
+ cancelAnimationFrame(motionFrameRef.current);
6199
+ }
6200
+ }, []);
6201
+ const reset = useCallback(() => {
6202
+ setState({
6203
+ isAnimating: false,
6204
+ progress: 0,
6205
+ currentStyle: calculateStyle(0)
6206
+ });
6207
+ if (motionFrameRef.current) {
6208
+ cancelAnimationFrame(motionFrameRef.current);
6209
+ }
6210
+ }, [calculateStyle]);
6211
+ useEffect(() => {
6212
+ if (autoStart) {
6213
+ start();
6214
+ }
6215
+ return () => {
6216
+ if (motionFrameRef.current) {
6217
+ cancelAnimationFrame(motionFrameRef.current);
6218
+ }
6219
+ };
6220
+ }, [autoStart, start]);
6221
+ return {
6222
+ ref,
6223
+ state,
6224
+ start,
6225
+ stop,
6226
+ reset
6227
+ };
6228
+ }
6229
+ function createLayoutTransition(from, to, options = {}) {
6230
+ return {
6231
+ from,
6232
+ to,
6233
+ duration: options.duration || 500,
6234
+ easing: options.easing || "ease-in-out",
6235
+ autoStart: options.autoStart || false,
6236
+ onComplete: options.onComplete
6237
+ };
6238
+ }
6239
+ function useKeyboardToggle(options = {}) {
6240
+ const {
6241
+ initialState = false,
6242
+ keys = [" "],
6243
+ keyCode,
6244
+ keyCombo,
6245
+ toggleOnKeyDown = true,
6246
+ toggleOnKeyUp = false,
6247
+ toggleOnKeyPress = false,
6248
+ autoReset = false,
6249
+ resetDelay = 3e3,
6250
+ preventDefault = false,
6251
+ stopPropagation = false,
6252
+ requireFocus = false,
6253
+ showOnMount = false
6254
+ } = options;
6255
+ const [isActive, setIsActive] = useState(showOnMount ? initialState : false);
6256
+ const [mounted, setMounted] = useState(false);
6257
+ const resetTimeoutRef = useRef(null);
6258
+ const elementRef = useRef(null);
6259
+ const pressedKeysRef = useRef(/* @__PURE__ */ new Set());
6260
+ useEffect(() => {
6261
+ setMounted(true);
6262
+ }, []);
6263
+ const startResetTimer = useCallback(() => {
6264
+ if (!autoReset || resetDelay <= 0) return;
6265
+ if (resetTimeoutRef.current !== null) {
6266
+ clearTimeout(resetTimeoutRef.current);
6267
+ }
6268
+ resetTimeoutRef.current = window.setTimeout(() => {
6269
+ setIsActive(false);
6270
+ resetTimeoutRef.current = null;
6271
+ }, resetDelay);
6272
+ }, [autoReset, resetDelay]);
6273
+ const toggle = useCallback(() => {
6274
+ if (!mounted) return;
6275
+ setIsActive((prev) => {
6276
+ const newState = !prev;
6277
+ if (newState && autoReset) {
6278
+ startResetTimer();
6279
+ } else if (!newState && resetTimeoutRef.current !== null) {
6280
+ clearTimeout(resetTimeoutRef.current);
6281
+ resetTimeoutRef.current = null;
6282
+ }
6283
+ return newState;
6284
+ });
6285
+ }, [mounted, autoReset, startResetTimer]);
6286
+ const activate = useCallback(() => {
6287
+ if (!mounted || isActive) return;
6288
+ setIsActive(true);
6289
+ if (autoReset) {
6290
+ startResetTimer();
6291
+ }
6292
+ }, [mounted, isActive, autoReset, startResetTimer]);
6293
+ const deactivate = useCallback(() => {
6294
+ if (!mounted || !isActive) return;
6295
+ setIsActive(false);
6296
+ if (resetTimeoutRef.current !== null) {
6297
+ clearTimeout(resetTimeoutRef.current);
6298
+ resetTimeoutRef.current = null;
6299
+ }
6300
+ }, [mounted, isActive]);
6301
+ const reset = useCallback(() => {
6302
+ setIsActive(initialState);
6303
+ if (resetTimeoutRef.current !== null) {
6304
+ clearTimeout(resetTimeoutRef.current);
6305
+ resetTimeoutRef.current = null;
6306
+ }
6307
+ }, [initialState]);
6308
+ const isKeyMatch = useCallback(
6309
+ (event) => {
6310
+ if (keyCode !== void 0 && event.keyCode === keyCode) {
6311
+ return true;
6312
+ }
6313
+ if (keys.length > 0 && keys.includes(event.key)) {
6314
+ return true;
6315
+ }
6316
+ if (keyCombo && keyCombo.length > 0) {
6317
+ const pressedKeys = Array.from(pressedKeysRef.current);
6318
+ const comboMatch = keyCombo.every((key) => pressedKeys.includes(key));
6319
+ return comboMatch;
6320
+ }
6321
+ return false;
6322
+ },
6323
+ [keys, keyCode, keyCombo]
6324
+ );
6325
+ const isFocused = useCallback(() => {
6326
+ if (!requireFocus) return true;
6327
+ return document.activeElement === elementRef.current;
6328
+ }, [requireFocus]);
6329
+ const handleKeyDown = useCallback(
6330
+ (event) => {
6331
+ if (!toggleOnKeyDown || !isFocused()) return;
6332
+ pressedKeysRef.current.add(event.key);
6333
+ if (isKeyMatch(event)) {
6334
+ if (preventDefault) event.preventDefault();
6335
+ if (stopPropagation) event.stopPropagation();
6336
+ toggle();
6337
+ }
6338
+ },
6339
+ [
6340
+ toggleOnKeyDown,
6341
+ isFocused,
6342
+ isKeyMatch,
6343
+ preventDefault,
6344
+ stopPropagation,
6345
+ toggle
6346
+ ]
6347
+ );
6348
+ const handleKeyUp = useCallback(
6349
+ (event) => {
6350
+ if (!toggleOnKeyUp || !isFocused()) return;
6351
+ pressedKeysRef.current.delete(event.key);
6352
+ if (isKeyMatch(event)) {
6353
+ if (preventDefault) event.preventDefault();
6354
+ if (stopPropagation) event.stopPropagation();
6355
+ toggle();
6356
+ }
6357
+ },
6358
+ [
6359
+ toggleOnKeyUp,
6360
+ isFocused,
6361
+ isKeyMatch,
6362
+ preventDefault,
6363
+ stopPropagation,
6364
+ toggle
6365
+ ]
6366
+ );
6367
+ const handleKeyPress = useCallback(
6368
+ (event) => {
6369
+ if (!toggleOnKeyPress || !isFocused()) return;
6370
+ if (isKeyMatch(event)) {
6371
+ if (preventDefault) event.preventDefault();
6372
+ if (stopPropagation) event.stopPropagation();
6373
+ toggle();
6374
+ }
6375
+ },
6376
+ [
6377
+ toggleOnKeyPress,
6378
+ isFocused,
6379
+ isKeyMatch,
6380
+ preventDefault,
6381
+ stopPropagation,
6382
+ toggle
6383
+ ]
6384
+ );
6385
+ useEffect(() => {
6386
+ if (requireFocus || !mounted) return;
6387
+ const handleGlobalKeyDown = (event) => {
6388
+ pressedKeysRef.current.add(event.key);
6389
+ if (isKeyMatch(event)) {
6390
+ if (preventDefault) event.preventDefault();
6391
+ if (stopPropagation) event.stopPropagation();
6392
+ toggle();
6393
+ }
6394
+ };
6395
+ const handleGlobalKeyUp = (event) => {
6396
+ pressedKeysRef.current.delete(event.key);
6397
+ if (isKeyMatch(event)) {
6398
+ if (preventDefault) event.preventDefault();
6399
+ if (stopPropagation) event.stopPropagation();
6400
+ toggle();
6401
+ }
6402
+ };
6403
+ document.addEventListener("keydown", handleGlobalKeyDown);
6404
+ document.addEventListener("keyup", handleGlobalKeyUp);
6405
+ return () => {
6406
+ document.removeEventListener("keydown", handleGlobalKeyDown);
6407
+ document.removeEventListener("keyup", handleGlobalKeyUp);
6408
+ };
6409
+ }, [
6410
+ requireFocus,
6411
+ mounted,
6412
+ isKeyMatch,
6413
+ preventDefault,
6414
+ stopPropagation,
6415
+ toggle
6416
+ ]);
6417
+ useEffect(() => {
6418
+ return () => {
6419
+ if (resetTimeoutRef.current !== null) {
6420
+ clearTimeout(resetTimeoutRef.current);
6421
+ }
6422
+ };
6423
+ }, []);
6424
+ const keyboardHandlers = {
6425
+ ...toggleOnKeyDown && { onKeyDown: handleKeyDown },
6426
+ ...toggleOnKeyUp && { onKeyUp: handleKeyUp },
6427
+ ...toggleOnKeyPress && { onKeyPress: handleKeyPress }
6428
+ };
6429
+ return {
6430
+ isActive,
6431
+ mounted,
6432
+ toggle,
6433
+ activate,
6434
+ deactivate,
6435
+ reset,
6436
+ keyboardHandlers,
6437
+ ref: elementRef
6438
+ };
6439
+ }
6440
+ function useScrollDirection(options = {}) {
6441
+ const { threshold = 10, idleDelay = 150, showOnMount = false } = options;
6442
+ const [direction, setDirection] = useState(
6443
+ showOnMount ? "idle" : "idle"
6444
+ );
6445
+ const [mounted, setMounted] = useState(false);
6446
+ const [lastScrollY, setLastScrollY] = useState(0);
6447
+ const [idleTimeout, setIdleTimeout] = useState(null);
6448
+ useEffect(() => {
6449
+ setMounted(true);
6450
+ }, []);
6451
+ useEffect(() => {
6452
+ if (!mounted) return;
6453
+ const handleScroll = () => {
6454
+ if (typeof window !== "undefined") {
6455
+ const currentScrollY = window.pageYOffset;
6456
+ const scrollDifference = Math.abs(currentScrollY - lastScrollY);
6457
+ if (idleTimeout !== null) {
6458
+ clearTimeout(idleTimeout);
6459
+ }
6460
+ if (scrollDifference > threshold) {
6461
+ const newDirection = currentScrollY > lastScrollY ? "down" : "up";
6462
+ setDirection(newDirection);
6463
+ setLastScrollY(currentScrollY);
6464
+ const timeout = setTimeout(() => {
6465
+ setDirection("idle");
6466
+ }, idleDelay);
6467
+ setIdleTimeout(timeout);
6468
+ }
6469
+ }
6470
+ };
6471
+ if (typeof window !== "undefined") {
6472
+ setLastScrollY(window.pageYOffset);
6473
+ }
6474
+ window.addEventListener("scroll", handleScroll, { passive: true });
6475
+ return () => {
6476
+ window.removeEventListener("scroll", handleScroll);
6477
+ if (idleTimeout !== null) {
6478
+ clearTimeout(idleTimeout);
6479
+ }
6480
+ };
6481
+ }, [threshold, idleDelay, mounted, lastScrollY, idleTimeout]);
6482
+ return {
6483
+ direction,
6484
+ mounted
6485
+ };
6486
+ }
6487
+ function useStickyToggle(options = {}) {
6488
+ const {
6489
+ offset = 0,
6490
+ behavior: _behavior = "smooth",
6491
+ showOnMount = false
6492
+ } = options;
6493
+ const [isSticky, setIsSticky] = useState(showOnMount);
6494
+ const [mounted, setMounted] = useState(false);
6495
+ useEffect(() => {
6496
+ setMounted(true);
6497
+ }, []);
6498
+ useEffect(() => {
6499
+ if (!mounted) return;
6500
+ const toggleSticky = () => {
6501
+ if (typeof window !== "undefined") {
6502
+ if (window.pageYOffset > offset) {
6503
+ setIsSticky(true);
6504
+ } else {
6505
+ setIsSticky(false);
6506
+ }
6507
+ }
6508
+ };
6509
+ toggleSticky();
6510
+ window.addEventListener("scroll", toggleSticky, { passive: true });
6511
+ window.addEventListener("resize", toggleSticky, { passive: true });
6512
+ return () => {
6513
+ window.removeEventListener("scroll", toggleSticky);
6514
+ window.removeEventListener("resize", toggleSticky);
6515
+ };
6516
+ }, [offset, mounted]);
6517
+ return {
6518
+ isSticky,
6519
+ mounted
6520
+ };
6521
+ }
6522
+ function useInteractive(config = {}) {
6523
+ const {
6524
+ hoverScale = 1.05,
6525
+ clickScale = 0.95,
6526
+ duration: _duration = 200
6527
+ } = config;
6528
+ const ref = useRef(null);
6529
+ const [scale, setScale] = useState(1);
6530
+ const [isHovered, setIsHovered] = useState(false);
6531
+ const [isClicked, setIsClicked] = useState(false);
6532
+ const handleMouseEnter = useCallback(() => {
6533
+ setIsHovered(true);
6534
+ setScale(hoverScale);
6535
+ }, [hoverScale]);
6536
+ const handleMouseLeave = useCallback(() => {
6537
+ setIsHovered(false);
6538
+ setScale(1);
6539
+ }, []);
6540
+ const handleMouseDown = useCallback(() => {
6541
+ setIsClicked(true);
6542
+ setScale(clickScale);
6543
+ }, [clickScale]);
6544
+ const handleMouseUp = useCallback(() => {
6545
+ setIsClicked(false);
6546
+ setScale(isHovered ? hoverScale : 1);
6547
+ }, [isHovered, hoverScale]);
6548
+ const setRef = (element) => {
6549
+ if (ref.current !== element) {
6550
+ ref.current = element;
6551
+ }
6552
+ };
6553
+ return {
6554
+ ref: setRef,
6555
+ scale,
6556
+ isHovered,
6557
+ isClicked,
6558
+ handleMouseEnter,
6559
+ handleMouseLeave,
6560
+ handleMouseDown,
6561
+ handleMouseUp
6562
+ };
6563
+ }
6564
+ function usePerformanceMonitor(config = {}) {
6565
+ const { threshold = 30, onPerformanceIssue } = config;
6566
+ const ref = useRef(null);
6567
+ const [fps, setFps] = useState(60);
6568
+ const [isLowPerformance, setIsLowPerformance] = useState(false);
6569
+ const [frameCount, setFrameCount] = useState(0);
6570
+ const lastTime = useRef(performance.now());
6571
+ const frameCountRef = useRef(0);
6572
+ const measurePerformance = () => {
6573
+ const now = performance.now();
6574
+ frameCountRef.current++;
6575
+ if (now - lastTime.current >= 1e3) {
6576
+ const currentFps = Math.round(
6577
+ frameCountRef.current * 1e3 / (now - lastTime.current)
6578
+ );
6579
+ setFps(currentFps);
6580
+ setFrameCount(frameCountRef.current);
6581
+ const lowPerformance = currentFps < threshold;
6582
+ setIsLowPerformance(lowPerformance);
6583
+ if (lowPerformance && onPerformanceIssue) {
6584
+ onPerformanceIssue(currentFps);
6585
+ }
6586
+ frameCountRef.current = 0;
6587
+ lastTime.current = now;
6588
+ }
6589
+ requestAnimationFrame(measurePerformance);
6590
+ };
6591
+ useEffect(() => {
6592
+ const motionId = requestAnimationFrame(measurePerformance);
6593
+ return () => cancelAnimationFrame(motionId);
6594
+ }, []);
6595
+ const setRef = (element) => {
6596
+ if (ref.current !== element) {
6597
+ ref.current = element;
6598
+ }
6599
+ };
6600
+ return {
6601
+ ref: setRef,
6602
+ fps,
6603
+ isLowPerformance,
6604
+ frameCount
6605
+ };
6606
+ }
6607
+ function useLanguageAwareMotion(options) {
6608
+ const {
6609
+ motionType,
6610
+ duration = 700,
6611
+ delay = 0,
6612
+ threshold = 0.1,
6613
+ pauseOnLanguageChange = true,
6614
+ restartOnLanguageChange = false,
6615
+ currentLanguage: externalLanguage
6616
+ } = options;
6617
+ const elementRef = useRef(null);
6618
+ const [isVisible, setIsVisible] = useState(false);
6619
+ const [isPaused, setIsPaused] = useState(false);
6620
+ const [internalLanguage, setInternalLanguage] = useState("");
6621
+ const isVisibleRef = useRef(false);
6622
+ const isPausedRef = useRef(false);
6623
+ isVisibleRef.current = isVisible;
6624
+ isPausedRef.current = isPaused;
6625
+ useEffect(() => {
6626
+ if (externalLanguage && internalLanguage !== externalLanguage) {
6627
+ setInternalLanguage(externalLanguage);
6628
+ if (pauseOnLanguageChange && isVisible) {
6629
+ setIsPaused(true);
6630
+ setTimeout(() => {
6631
+ setIsPaused(false);
6632
+ }, 200);
6633
+ }
6634
+ if (restartOnLanguageChange && isVisible) {
6635
+ setIsVisible(false);
6636
+ setTimeout(() => {
6637
+ setIsVisible(true);
6638
+ }, 100);
6639
+ }
6640
+ }
6641
+ }, [
6642
+ externalLanguage,
6643
+ internalLanguage,
6644
+ isVisible,
6645
+ pauseOnLanguageChange,
6646
+ restartOnLanguageChange
6647
+ ]);
6648
+ useEffect(() => {
6649
+ if (!elementRef.current) return;
6650
+ const observer = new IntersectionObserver(
6651
+ (entries) => {
6652
+ entries.forEach((entry) => {
6653
+ if (entry.isIntersecting && !isVisibleRef.current && !isPausedRef.current) {
6654
+ setTimeout(() => {
6655
+ setIsVisible(true);
6656
+ }, delay);
6657
+ }
6658
+ });
6659
+ },
6660
+ { threshold }
6661
+ );
6662
+ observer.observe(elementRef.current);
6663
+ return () => {
6664
+ observer.disconnect();
6665
+ };
6666
+ }, [delay, threshold]);
6667
+ const getMotionStyle = useCallback(() => {
6668
+ const baseTransition = `all ${duration}ms ease-out`;
6669
+ if (isPaused) {
6670
+ return {
6671
+ opacity: 1,
6672
+ transform: "none",
6673
+ transition: baseTransition
6674
+ };
6675
+ }
6676
+ if (!isVisible) {
6677
+ switch (motionType) {
6678
+ case "fadeIn":
6679
+ return {
6680
+ opacity: 0,
6681
+ transition: baseTransition
6682
+ };
6683
+ case "slideUp":
6684
+ return {
6685
+ opacity: 0,
6686
+ transform: "translateY(32px)",
6687
+ transition: baseTransition
6688
+ };
6689
+ case "slideLeft":
6690
+ return {
6691
+ opacity: 0,
6692
+ transform: "translateX(-32px)",
6693
+ transition: baseTransition
6694
+ };
6695
+ case "slideRight":
6696
+ return {
6697
+ opacity: 0,
6698
+ transform: "translateX(32px)",
6699
+ transition: baseTransition
6700
+ };
6701
+ case "scaleIn":
6702
+ return {
6703
+ opacity: 0,
6704
+ transform: "scale(0.95)",
6705
+ transition: baseTransition
6706
+ };
6707
+ case "bounceIn":
6708
+ return {
6709
+ opacity: 0,
6710
+ transform: "scale(0.75)",
6711
+ transition: baseTransition
6712
+ };
6713
+ default:
6714
+ return {
6715
+ opacity: 0,
6716
+ transition: baseTransition
6717
+ };
6718
+ }
6719
+ }
6720
+ return {
6721
+ opacity: 1,
6722
+ transform: "none",
6723
+ transition: baseTransition
6724
+ };
6725
+ }, [isVisible, isPaused, motionType, duration]);
6726
+ const pauseMotion = useCallback(() => {
6727
+ setIsPaused(true);
6728
+ }, []);
6729
+ const resumeMotion = useCallback(() => {
6730
+ setIsPaused(false);
6731
+ }, []);
6732
+ const restartMotion = useCallback(() => {
6733
+ setIsVisible(false);
6734
+ setTimeout(() => {
6735
+ setIsVisible(true);
6736
+ }, 100);
6737
+ }, []);
6738
+ const motionStyle = useMemo(() => getMotionStyle(), [getMotionStyle]);
6739
+ return {
6740
+ ref: elementRef,
6741
+ isVisible,
6742
+ isPaused,
6743
+ style: motionStyle,
6744
+ pauseMotion,
6745
+ resumeMotion,
6746
+ restartMotion,
6747
+ currentLanguage: internalLanguage
6748
+ };
6749
+ }
6750
+ function useGameLoop(options = {}) {
6751
+ const {
6752
+ fps = 60,
6753
+ autoStart = false,
6754
+ maxFPS = 120,
6755
+ minFPS = 30,
6756
+ showOnMount = false
6757
+ } = options;
6758
+ const [isRunning, setIsRunning] = useState(showOnMount ? autoStart : false);
6759
+ const [isPaused, setIsPaused] = useState(false);
6760
+ const [currentFPS, setCurrentFPS] = useState(0);
6761
+ const [deltaTime, setDeltaTime] = useState(0);
6762
+ const [elapsedTime, setElapsedTime] = useState(0);
6763
+ const [frameCount, setFrameCount] = useState(0);
6764
+ const [mounted, setMounted] = useState(false);
6765
+ const motionRef = useRef(null);
6766
+ const lastTimeRef = useRef(null);
6767
+ const frameTimeRef = useRef(1e3 / fps);
6768
+ const fpsUpdateTimeRef = useRef(0);
6769
+ const fpsFrameCountRef = useRef(0);
6770
+ const updateCallbacksRef = useRef([]);
6771
+ const renderCallbacksRef = useRef([]);
6772
+ useEffect(() => {
6773
+ setMounted(true);
6774
+ }, []);
6775
+ const gameLoop = useCallback(
6776
+ (currentTime) => {
6777
+ if (!isRunning || isPaused) return;
6778
+ if (lastTimeRef.current === null) {
6779
+ lastTimeRef.current = currentTime;
6780
+ motionRef.current = requestAnimationFrame(gameLoop);
6781
+ return;
6782
+ }
6783
+ const delta = currentTime - lastTimeRef.current;
6784
+ const targetDelta = frameTimeRef.current;
6785
+ if (delta >= targetDelta) {
6786
+ updateCallbacksRef.current.forEach((callback) => {
6787
+ try {
6788
+ callback(delta, elapsedTime);
6789
+ } catch (error) {
6790
+ if (process.env.NODE_ENV === "development") {
6791
+ console.error("Game loop update error:", error);
6792
+ }
6793
+ }
6794
+ });
6795
+ renderCallbacksRef.current.forEach((callback) => {
6796
+ try {
6797
+ callback(delta, elapsedTime);
6798
+ } catch (error) {
6799
+ if (process.env.NODE_ENV === "development") {
6800
+ console.error("Game loop render error:", error);
6801
+ }
6802
+ }
6803
+ });
6804
+ setDeltaTime(delta);
6805
+ setElapsedTime((prev) => prev + delta);
6806
+ setFrameCount((prev) => prev + 1);
6807
+ lastTimeRef.current = currentTime;
6808
+ fpsFrameCountRef.current++;
6809
+ if (currentTime - fpsUpdateTimeRef.current >= 1e3) {
6810
+ const newFPS = Math.round(
6811
+ fpsFrameCountRef.current * 1e3 / (currentTime - fpsUpdateTimeRef.current)
6812
+ );
6813
+ setCurrentFPS(newFPS);
6814
+ fpsFrameCountRef.current = 0;
6815
+ fpsUpdateTimeRef.current = currentTime;
6816
+ if (process.env.NODE_ENV === "development" && typeof window !== "undefined" && window.location.hostname === "localhost") {
6817
+ if (newFPS < minFPS) {
6818
+ console.warn(`Low FPS detected: ${newFPS} (min: ${minFPS})`);
6819
+ }
6820
+ }
6821
+ }
6822
+ }
6823
+ motionRef.current = requestAnimationFrame(gameLoop);
6824
+ },
6825
+ [isRunning, isPaused, elapsedTime, minFPS]
6826
+ );
6827
+ const start = useCallback(() => {
6828
+ if (!mounted) return;
6829
+ setIsRunning(true);
6830
+ setIsPaused(false);
6831
+ setElapsedTime(0);
6832
+ setFrameCount(0);
6833
+ setDeltaTime(0);
6834
+ setCurrentFPS(0);
6835
+ lastTimeRef.current = null;
6836
+ fpsUpdateTimeRef.current = 0;
6837
+ fpsFrameCountRef.current = 0;
6838
+ if (!motionRef.current) {
6839
+ motionRef.current = requestAnimationFrame(gameLoop);
6840
+ }
6841
+ }, [mounted, gameLoop]);
6842
+ const stop = useCallback(() => {
6843
+ setIsRunning(false);
6844
+ setIsPaused(false);
6845
+ if (motionRef.current) {
6846
+ cancelAnimationFrame(motionRef.current);
6847
+ motionRef.current = null;
6848
+ }
6849
+ }, []);
6850
+ const pause = useCallback(() => {
6851
+ if (!isRunning) return;
6852
+ setIsPaused(true);
6853
+ }, [isRunning]);
6854
+ const resume = useCallback(() => {
6855
+ if (!isRunning) return;
6856
+ setIsPaused(false);
6857
+ if (!motionRef.current) {
6858
+ motionRef.current = requestAnimationFrame(gameLoop);
6859
+ }
6860
+ }, [isRunning, gameLoop]);
6861
+ const reset = useCallback(() => {
6862
+ setElapsedTime(0);
6863
+ setFrameCount(0);
6864
+ setDeltaTime(0);
6865
+ setCurrentFPS(0);
6866
+ lastTimeRef.current = null;
6867
+ fpsUpdateTimeRef.current = 0;
6868
+ fpsFrameCountRef.current = 0;
6869
+ }, []);
6870
+ const onUpdate = useCallback(
6871
+ (callback) => {
6872
+ updateCallbacksRef.current.push(callback);
6873
+ return () => {
6874
+ const index = updateCallbacksRef.current.indexOf(callback);
6875
+ if (index > -1) {
6876
+ updateCallbacksRef.current.splice(index, 1);
6877
+ }
6878
+ };
6879
+ },
6880
+ []
6881
+ );
6882
+ const onRender = useCallback(
6883
+ (callback) => {
6884
+ renderCallbacksRef.current.push(callback);
6885
+ return () => {
6886
+ const index = renderCallbacksRef.current.indexOf(callback);
6887
+ if (index > -1) {
6888
+ renderCallbacksRef.current.splice(index, 1);
6889
+ }
6890
+ };
6891
+ },
6892
+ []
6893
+ );
6894
+ useEffect(() => {
6895
+ frameTimeRef.current = 1e3 / Math.min(fps, maxFPS);
6896
+ }, [fps, maxFPS]);
6897
+ useEffect(() => {
6898
+ if (mounted && autoStart && !isRunning) {
6899
+ start();
6900
+ }
6901
+ }, [mounted, autoStart, isRunning, start]);
6902
+ useEffect(() => {
6903
+ return () => {
6904
+ if (motionRef.current) {
6905
+ cancelAnimationFrame(motionRef.current);
6906
+ }
6907
+ };
6908
+ }, []);
6909
+ return {
6910
+ isRunning,
6911
+ fps: currentFPS,
6912
+ deltaTime,
6913
+ elapsedTime,
6914
+ frameCount,
6915
+ mounted,
6916
+ start,
6917
+ stop,
6918
+ pause,
6919
+ resume,
6920
+ reset,
6921
+ onUpdate,
6922
+ onRender
6923
+ };
6924
+ }
6925
+ function useMotion(configOrFrom = {}, to, options) {
6926
+ let config;
6927
+ let fromValues;
6928
+ let toValues;
6929
+ if (to && options) {
6930
+ fromValues = configOrFrom;
6931
+ toValues = to;
6932
+ config = {
6933
+ duration: options.duration || 1e3,
6934
+ delay: options.delay || 0,
6935
+ autoStart: options.autoStart || false,
6936
+ easing: options.ease || "ease-out"
6937
+ };
6938
+ } else {
6939
+ config = configOrFrom;
6940
+ const { type = "fade" } = config;
6941
+ switch (type) {
6942
+ case "fade":
6943
+ fromValues = { opacity: 0 };
6944
+ toValues = { opacity: 1 };
6945
+ break;
6946
+ case "slide":
6947
+ fromValues = { opacity: 0, translateX: 100 };
6948
+ toValues = { opacity: 1, translateX: 0 };
6949
+ break;
6950
+ case "scale":
6951
+ fromValues = { opacity: 0, scale: 0 };
6952
+ toValues = { opacity: 1, scale: 1 };
6953
+ break;
6954
+ case "rotate":
6955
+ fromValues = { opacity: 0, rotate: 180 };
6956
+ toValues = { opacity: 1, rotate: 0 };
6957
+ break;
6958
+ default:
6959
+ fromValues = { opacity: 0 };
6960
+ toValues = { opacity: 1 };
6961
+ }
6962
+ }
6963
+ const {
6964
+ duration = 1e3,
6965
+ delay = 0,
6966
+ autoStart = true,
6967
+ easing = "ease-out"
6968
+ } = config;
6969
+ const ref = useRef(null);
6970
+ const fromValuesRef = useRef(fromValues);
6971
+ const toValuesRef = useRef(toValues);
6972
+ const initialBgColor = useRef(fromValues.backgroundColor);
6973
+ const [state, setState] = useState({
6974
+ transform: "",
6975
+ opacity: fromValues.opacity ?? 1,
6976
+ backgroundColor: fromValues.backgroundColor,
6977
+ isAnimating: false
6978
+ });
6979
+ const easingFunction = useCallback(
6980
+ (t) => {
6981
+ switch (easing) {
6982
+ case "ease-in":
6983
+ return t * t;
6984
+ case "ease-out":
6985
+ return 1 - (1 - t) * (1 - t);
6986
+ case "ease-in-out":
6987
+ return t < 0.5 ? 2 * t * t : 1 - 2 * (1 - t) * (1 - t);
6988
+ default:
6989
+ return t;
6990
+ }
6991
+ },
6992
+ [easing]
6993
+ );
6994
+ const interpolate = useCallback(
6995
+ (from, to2, progress) => {
6996
+ return from + (to2 - from) * progress;
6997
+ },
6998
+ []
6999
+ );
7000
+ const updateMotion = useCallback(
7001
+ (progress) => {
7002
+ const easedProgress = easingFunction(progress);
7003
+ const from = fromValuesRef.current;
7004
+ const to2 = toValuesRef.current;
7005
+ const newState = {
7006
+ transform: "",
7007
+ opacity: 1,
7008
+ backgroundColor: initialBgColor.current,
7009
+ isAnimating: true
7010
+ };
7011
+ if (from.opacity !== void 0 && to2.opacity !== void 0) {
7012
+ newState.opacity = interpolate(from.opacity, to2.opacity, easedProgress);
7013
+ }
7014
+ const transforms = [];
7015
+ if (from.translateX !== void 0 && to2.translateX !== void 0) {
7016
+ const translateX = interpolate(
7017
+ from.translateX,
7018
+ to2.translateX,
7019
+ easedProgress
7020
+ );
7021
+ transforms.push(`translateX(${translateX}px)`);
7022
+ }
7023
+ if (from.translateY !== void 0 && to2.translateY !== void 0) {
7024
+ const translateY = interpolate(
7025
+ from.translateY,
7026
+ to2.translateY,
7027
+ easedProgress
7028
+ );
7029
+ transforms.push(`translateY(${translateY}px)`);
7030
+ }
7031
+ if (from.scale !== void 0 && to2.scale !== void 0) {
7032
+ const scaleVal = interpolate(from.scale, to2.scale, easedProgress);
7033
+ transforms.push(`scale(${scaleVal})`);
7034
+ }
7035
+ if (from.rotate !== void 0 && to2.rotate !== void 0) {
7036
+ const rotate = interpolate(from.rotate, to2.rotate, easedProgress);
7037
+ transforms.push(`rotate(${rotate}deg)`);
7038
+ }
7039
+ if (transforms.length > 0) {
7040
+ newState.transform = transforms.join(" ");
7041
+ }
7042
+ if (from.backgroundColor && to2.backgroundColor) {
7043
+ newState.backgroundColor = easedProgress > 0.5 ? to2.backgroundColor : from.backgroundColor;
7044
+ }
7045
+ setState(newState);
7046
+ },
7047
+ [easingFunction, interpolate]
7048
+ );
7049
+ const start = useCallback(() => {
7050
+ setState((prev) => ({ ...prev, isAnimating: true }));
7051
+ const startTime = Date.now();
7052
+ const animate = () => {
7053
+ const elapsed = Date.now() - startTime;
7054
+ const progress = Math.min(elapsed / duration, 1);
7055
+ updateMotion(progress);
7056
+ if (progress < 1) {
7057
+ requestAnimationFrame(animate);
7058
+ } else {
7059
+ setState((prev) => ({ ...prev, isAnimating: false }));
7060
+ }
7061
+ };
7062
+ setTimeout(() => {
7063
+ requestAnimationFrame(animate);
7064
+ }, delay);
7065
+ }, [duration, delay, updateMotion]);
7066
+ const reset = useCallback(() => {
7067
+ const from = fromValuesRef.current;
7068
+ setState({
7069
+ transform: "",
7070
+ opacity: from.opacity ?? 1,
7071
+ backgroundColor: from.backgroundColor,
7072
+ isAnimating: false
7073
+ });
7074
+ }, []);
7075
+ const stop = useCallback(() => {
7076
+ setState((prev) => ({ ...prev, isAnimating: false }));
7077
+ }, []);
7078
+ useEffect(() => {
7079
+ if (autoStart) {
7080
+ start();
7081
+ }
7082
+ }, []);
7083
+ const setRef = (element) => {
7084
+ if (ref.current !== element) {
7085
+ ref.current = element;
7086
+ }
7087
+ };
7088
+ const style = {
7089
+ opacity: state.opacity,
7090
+ ...state.transform && { transform: state.transform },
7091
+ ...state.backgroundColor && { backgroundColor: state.backgroundColor }
7092
+ };
7093
+ return {
7094
+ ref: setRef,
7095
+ style,
7096
+ transform: state.transform,
7097
+ opacity: state.opacity,
7098
+ backgroundColor: state.backgroundColor,
7099
+ isAnimating: state.isAnimating,
7100
+ start,
7101
+ stop,
7102
+ reset
7103
+ };
7104
+ }
7105
+ function useViewportToggle(options = {}) {
7106
+ const {
7107
+ threshold = 0.1,
7108
+ rootMargin = "0px",
7109
+ trigger = "both",
7110
+ once = false,
7111
+ showOnMount = false
7112
+ } = options;
7113
+ const [isVisible, setIsVisible] = useState(showOnMount);
7114
+ const [mounted, setMounted] = useState(false);
7115
+ const elementRef = useRef(null);
7116
+ const hasTriggeredRef = useRef(false);
7117
+ const isVisibleRef = useRef(showOnMount);
7118
+ isVisibleRef.current = isVisible;
7119
+ useEffect(() => {
7120
+ setMounted(true);
7121
+ }, []);
7122
+ useEffect(() => {
7123
+ if (!mounted || !elementRef.current) return;
7124
+ const observer = new IntersectionObserver(
7125
+ (entries) => {
7126
+ entries.forEach((entry) => {
7127
+ const isIntersecting = entry.isIntersecting;
7128
+ if (once && hasTriggeredRef.current) return;
7129
+ let shouldBeVisible = isVisibleRef.current;
7130
+ if (trigger === "enter" && isIntersecting) {
7131
+ shouldBeVisible = true;
7132
+ if (once) hasTriggeredRef.current = true;
7133
+ } else if (trigger === "exit" && !isIntersecting) {
7134
+ shouldBeVisible = true;
7135
+ if (once) hasTriggeredRef.current = true;
7136
+ } else if (trigger === "both") {
7137
+ shouldBeVisible = isIntersecting;
7138
+ if (once && isIntersecting) hasTriggeredRef.current = true;
7139
+ }
7140
+ setIsVisible(shouldBeVisible);
7141
+ });
7142
+ },
7143
+ {
7144
+ threshold,
7145
+ rootMargin
7146
+ }
7147
+ );
7148
+ observer.observe(elementRef.current);
7149
+ return () => {
7150
+ observer.disconnect();
7151
+ };
7152
+ }, [threshold, rootMargin, trigger, once, mounted]);
7153
+ return {
7154
+ ref: elementRef,
7155
+ isVisible,
7156
+ mounted
7157
+ };
7158
+ }
7159
+ function useScrollPositionToggle(options = {}) {
7160
+ const { threshold = 400, showOnMount = false, smooth = true } = options;
7161
+ const [isVisible, setIsVisible] = useState(showOnMount);
7162
+ const [mounted, setMounted] = useState(false);
7163
+ useEffect(() => {
7164
+ setMounted(true);
7165
+ }, []);
7166
+ useEffect(() => {
7167
+ if (!mounted) return;
7168
+ const toggleVisibility = () => {
7169
+ if (typeof window !== "undefined") {
7170
+ if (window.pageYOffset > threshold) {
7171
+ setIsVisible(true);
7172
+ } else {
7173
+ setIsVisible(false);
7174
+ }
7175
+ }
7176
+ };
7177
+ toggleVisibility();
7178
+ window.addEventListener("scroll", toggleVisibility, { passive: true });
7179
+ window.addEventListener("resize", toggleVisibility, { passive: true });
7180
+ return () => {
7181
+ window.removeEventListener("scroll", toggleVisibility);
7182
+ window.removeEventListener("resize", toggleVisibility);
7183
+ };
7184
+ }, [threshold, mounted]);
7185
+ const scrollToTop = () => {
7186
+ if (typeof window !== "undefined") {
7187
+ if (smooth) {
7188
+ window.scrollTo({
7189
+ top: 0,
7190
+ behavior: "smooth"
7191
+ });
7192
+ } else {
7193
+ window.scrollTo(0, 0);
7194
+ }
7195
+ }
7196
+ };
7197
+ return {
7198
+ isVisible,
7199
+ scrollToTop,
7200
+ mounted
7201
+ };
7202
+ }
7203
+ function Motion({
7204
+ as: Component = "div",
7205
+ type,
7206
+ effects,
7207
+ scroll,
7208
+ delay,
7209
+ duration,
7210
+ children,
7211
+ className,
7212
+ style: userStyle,
5681
7213
  ...rest
5682
7214
  }) {
5683
7215
  const scrollOptions = useMemo(() => {
@@ -5715,6 +7247,87 @@ function Motion({
5715
7247
  }
5716
7248
  );
5717
7249
  }
7250
+ function useCountUp(options) {
7251
+ const {
7252
+ end,
7253
+ suffix = "",
7254
+ duration = 1500,
7255
+ delay = 0,
7256
+ active = true
7257
+ } = options;
7258
+ const [value, setValue] = useState(0);
7259
+ const startedRef = useRef(false);
7260
+ useEffect(() => {
7261
+ if (!active || startedRef.current) return;
7262
+ const timer = setTimeout(() => {
7263
+ startedRef.current = true;
7264
+ const startTime = performance.now();
7265
+ const animate = (now) => {
7266
+ const elapsed = now - startTime;
7267
+ const progress = Math.min(elapsed / duration, 1);
7268
+ const eased = 1 - Math.pow(1 - progress, 3);
7269
+ setValue(Math.round(eased * end));
7270
+ if (progress < 1) requestAnimationFrame(animate);
7271
+ };
7272
+ requestAnimationFrame(animate);
7273
+ }, delay);
7274
+ return () => clearTimeout(timer);
7275
+ }, [active, end, duration, delay]);
7276
+ return { value, display: `${value}${suffix}` };
7277
+ }
7278
+ var SPRING_EASING = "cubic-bezier(0.34, 1.56, 0.64, 1)";
7279
+ function useClipReveal(options = {}) {
7280
+ const {
7281
+ delay = 0,
7282
+ duration = 900,
7283
+ easing = SPRING_EASING,
7284
+ active = true
7285
+ } = options;
7286
+ const [triggered, setTriggered] = useState(false);
7287
+ useEffect(() => {
7288
+ if (active && !triggered) {
7289
+ setTriggered(true);
7290
+ }
7291
+ }, [active, triggered]);
7292
+ const containerStyle = useMemo(() => ({
7293
+ overflow: "hidden",
7294
+ display: "inline-block"
7295
+ }), []);
7296
+ const textStyle = useMemo(() => ({
7297
+ display: "block",
7298
+ transform: triggered ? "translateY(0)" : "translateY(110%)",
7299
+ transition: `transform ${duration}ms ${easing} ${delay}ms`
7300
+ }), [triggered, duration, easing, delay]);
7301
+ return { containerStyle, textStyle, isVisible: triggered };
7302
+ }
7303
+ var SMOOTH_EASING = "cubic-bezier(0.16, 1, 0.3, 1)";
7304
+ function useBlurIn(options = {}) {
7305
+ const {
7306
+ delay = 0,
7307
+ duration = 1200,
7308
+ blurAmount = 12,
7309
+ scale = 0.95,
7310
+ easing = SMOOTH_EASING,
7311
+ active = true
7312
+ } = options;
7313
+ const [triggered, setTriggered] = useState(false);
7314
+ useEffect(() => {
7315
+ if (active && !triggered) {
7316
+ setTriggered(true);
7317
+ }
7318
+ }, [active, triggered]);
7319
+ const style = useMemo(() => ({
7320
+ opacity: triggered ? 1 : 0,
7321
+ filter: triggered ? "blur(0px)" : `blur(${blurAmount}px)`,
7322
+ transform: triggered ? "scale(1)" : `scale(${scale})`,
7323
+ transition: [
7324
+ `opacity ${duration}ms ${easing} ${delay}ms`,
7325
+ `filter ${duration}ms ${easing} ${delay}ms`,
7326
+ `transform ${duration}ms ${easing} ${delay}ms`
7327
+ ].join(", ")
7328
+ }), [triggered, duration, blurAmount, scale, easing, delay]);
7329
+ return { style, isVisible: triggered };
7330
+ }
5718
7331
  function getInitialTransform(motionType, slideDistance, scaleFrom) {
5719
7332
  switch (motionType) {
5720
7333
  case "slideUp":
@@ -5741,7 +7354,7 @@ function useStagger(options) {
5741
7354
  duration = profile.base.duration,
5742
7355
  motionType = "fadeIn",
5743
7356
  threshold = profile.base.threshold,
5744
- easing: easing2 = profile.base.easing
7357
+ easing = profile.base.easing
5745
7358
  } = options;
5746
7359
  const containerRef = useRef(null);
5747
7360
  const [isVisible, setIsVisible] = useState(false);
@@ -5767,16 +7380,16 @@ function useStagger(options) {
5767
7380
  return {
5768
7381
  opacity: 0,
5769
7382
  transform: initialTransform,
5770
- transition: `opacity ${duration}ms ${easing2} ${itemDelay}ms, transform ${duration}ms ${easing2} ${itemDelay}ms`
7383
+ transition: `opacity ${duration}ms ${easing} ${itemDelay}ms, transform ${duration}ms ${easing} ${itemDelay}ms`
5771
7384
  };
5772
7385
  }
5773
7386
  return {
5774
7387
  opacity: 1,
5775
7388
  transform: "none",
5776
- transition: `opacity ${duration}ms ${easing2} ${itemDelay}ms, transform ${duration}ms ${easing2} ${itemDelay}ms`
7389
+ transition: `opacity ${duration}ms ${easing} ${itemDelay}ms, transform ${duration}ms ${easing} ${itemDelay}ms`
5777
7390
  };
5778
7391
  });
5779
- }, [count, isVisible, staggerDelay, baseDelay, duration, motionType, easing2, initialTransform]);
7392
+ }, [count, isVisible, staggerDelay, baseDelay, duration, motionType, easing, initialTransform]);
5780
7393
  return {
5781
7394
  containerRef,
5782
7395
  styles,
@@ -5784,6 +7397,6 @@ function useStagger(options) {
5784
7397
  };
5785
7398
  }
5786
7399
 
5787
- export { MOTION_PRESETS, Motion, MotionEngine, MotionProfileProvider, PAGE_MOTIONS, TransitionEffects, applyEasing, calculateSpring, easeIn, easeInOut, easeInOutQuad, easeInQuad, easeOut, easeOutQuad, easingPresets, getAvailableEasings, getEasing, getMotionPreset, getPagePreset, getPresetEasing, hua, isEasingFunction, isValidEasing, linear, mergeProfileOverrides, mergeWithPreset, motionEngine, neutral, observeElement, resolveProfile, safeApplyEasing, transitionEffects, useBounceIn, useButtonEffect, useCardList, useClickToggle, useCustomCursor, useElementProgress, useFadeIn, useFocusToggle, useGesture, useGestureMotion, useGradient, useHoverMotion, useInView, useLoadingSpinner, useMagneticCursor, useMotionProfile, useMotionState, useMouse, useNavigation, usePageMotions, usePulse, useReducedMotion, useRepeat, useScaleIn, useScrollProgress, useScrollReveal, useScrollToggle, useSimplePageMotion, useSkeleton, useSlideDown, useSlideLeft, useSlideRight, useSlideUp, useSmartMotion, useSmoothScroll, useSpringMotion, useStagger, useToggleMotion, useTypewriter, useUnifiedMotion, useVisibilityToggle, useWindowSize };
7400
+ export { Motion, createLayoutTransition, observeElement, useAutoFade, useAutoPlay, useAutoScale, useAutoSlide, useBlurIn, useBounceIn, useButtonEffect, useCardList, useClickToggle, useClipReveal, useCountUp, useCustomCursor, useElementProgress, useFadeIn, useFocusToggle, useGameLoop, useGesture, useGestureMotion, useGradient, useHoverMotion, useInView, useInteractive, useKeyboardToggle, useLanguageAwareMotion, useLayoutMotion, useLoadingSpinner, useMagneticCursor, useMotion, useMotionOrchestra, useMotionState, useMouse, useNavigation, useOrchestration, usePageMotions, usePerformanceMonitor, usePulse, useReducedMotion, useReducedMotionObject, useRepeat, useScaleIn, useScrollDirection, useScrollPositionToggle, useScrollProgress, useScrollReveal, useScrollToggle, useSequence, useSimplePageMotion, useSkeleton, useSlideDown, useSlideLeft, useSlideRight, useSlideUp, useSmartMotion, useSmoothScroll, useSpringMotion, useStagger, useStickyToggle, useToggleMotion, useTypewriter, useUnifiedMotion, useViewportToggle, useVisibilityToggle, useWindowSize };
5788
7401
  //# sourceMappingURL=index.mjs.map
5789
7402
  //# sourceMappingURL=index.mjs.map