@hua-labs/motion-core 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -39
- package/dist/chunk-47QAGQLN.mjs +1057 -0
- package/dist/chunk-47QAGQLN.mjs.map +1 -0
- package/dist/chunk-LSIP7MB5.cjs +1090 -0
- package/dist/chunk-LSIP7MB5.cjs.map +1 -0
- package/dist/index.cjs +7532 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +607 -676
- package/dist/index.d.ts +1558 -0
- package/dist/index.mjs +2732 -1177
- package/dist/index.mjs.map +1 -1
- package/dist/native.cjs +692 -0
- package/dist/native.cjs.map +1 -0
- package/dist/native.d.mts +177 -0
- package/dist/native.d.ts +177 -0
- package/dist/native.mjs +555 -0
- package/dist/native.mjs.map +1 -0
- package/dist/springPhysics-DLyZ4nbx.d.mts +687 -0
- package/dist/springPhysics-DLyZ4nbx.d.ts +687 -0
- package/package.json +28 -8
|
@@ -0,0 +1,1090 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
|
|
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/managers/MotionStateManager.ts
|
|
557
|
+
var MotionStateManager = class {
|
|
558
|
+
constructor() {
|
|
559
|
+
this.states = /* @__PURE__ */ new Map();
|
|
560
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* 요소의 상태를 초기화
|
|
564
|
+
*/
|
|
565
|
+
initializeElement(elementId, config) {
|
|
566
|
+
const initialState = {
|
|
567
|
+
internalVisibility: false,
|
|
568
|
+
// 초기에 숨김 상태로 시작 (스크롤 리빌용)
|
|
569
|
+
triggeredVisibility: false,
|
|
570
|
+
// Intersection Observer가 아직 트리거되지 않음
|
|
571
|
+
finalVisibility: false,
|
|
572
|
+
// 초기에 숨김 상태로 시작
|
|
573
|
+
opacity: 0,
|
|
574
|
+
// 초기에 투명 상태로 시작
|
|
575
|
+
translateY: 20,
|
|
576
|
+
// 초기에 아래로 이동된 상태로 시작
|
|
577
|
+
translateX: 0,
|
|
578
|
+
scale: 0.95,
|
|
579
|
+
// 초기에 약간 축소된 상태로 시작
|
|
580
|
+
rotation: 0,
|
|
581
|
+
isHovered: false,
|
|
582
|
+
isClicked: false,
|
|
583
|
+
isAnimating: false
|
|
584
|
+
};
|
|
585
|
+
this.states.set(elementId, initialState);
|
|
586
|
+
this.computeFinalState(elementId);
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* 내부 가시성 상태 업데이트 (초기화, 리셋 등)
|
|
590
|
+
*/
|
|
591
|
+
setInternalVisibility(elementId, visible) {
|
|
592
|
+
const state = this.states.get(elementId);
|
|
593
|
+
if (!state) return;
|
|
594
|
+
state.internalVisibility = visible;
|
|
595
|
+
this.computeFinalState(elementId);
|
|
596
|
+
this.notifyListeners(elementId, state);
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* 외부 트리거 가시성 상태 업데이트 (Intersection Observer)
|
|
600
|
+
*/
|
|
601
|
+
setTriggeredVisibility(elementId, visible) {
|
|
602
|
+
const state = this.states.get(elementId);
|
|
603
|
+
if (!state) return;
|
|
604
|
+
state.triggeredVisibility = visible;
|
|
605
|
+
this.computeFinalState(elementId);
|
|
606
|
+
this.notifyListeners(elementId, state);
|
|
607
|
+
}
|
|
608
|
+
/**
|
|
609
|
+
* 모션 값 업데이트
|
|
610
|
+
*/
|
|
611
|
+
updateMotionValues(elementId, values) {
|
|
612
|
+
const state = this.states.get(elementId);
|
|
613
|
+
if (!state) return;
|
|
614
|
+
Object.assign(state, values);
|
|
615
|
+
this.notifyListeners(elementId, state);
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* 최종 상태 계산
|
|
619
|
+
*/
|
|
620
|
+
computeFinalState(elementId) {
|
|
621
|
+
const state = this.states.get(elementId);
|
|
622
|
+
if (!state) return;
|
|
623
|
+
state.finalVisibility = state.internalVisibility || state.triggeredVisibility;
|
|
624
|
+
state.isAnimating = state.finalVisibility && (state.opacity < 1 || state.translateY > 0);
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* 현재 상태 조회
|
|
628
|
+
*/
|
|
629
|
+
getState(elementId) {
|
|
630
|
+
return this.states.get(elementId);
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* 모든 상태 조회
|
|
634
|
+
*/
|
|
635
|
+
getAllStates() {
|
|
636
|
+
return new Map(this.states);
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* 상태 변경 리스너 등록
|
|
640
|
+
*/
|
|
641
|
+
subscribe(elementId, listener) {
|
|
642
|
+
if (!this.listeners.has(elementId)) {
|
|
643
|
+
this.listeners.set(elementId, /* @__PURE__ */ new Set());
|
|
644
|
+
}
|
|
645
|
+
this.listeners.get(elementId).add(listener);
|
|
646
|
+
return () => {
|
|
647
|
+
const listeners = this.listeners.get(elementId);
|
|
648
|
+
if (listeners) {
|
|
649
|
+
listeners.delete(listener);
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* 리스너들에게 상태 변경 알림
|
|
655
|
+
*/
|
|
656
|
+
notifyListeners(elementId, state) {
|
|
657
|
+
const listeners = this.listeners.get(elementId);
|
|
658
|
+
if (!listeners) return;
|
|
659
|
+
listeners.forEach((listener) => {
|
|
660
|
+
try {
|
|
661
|
+
listener(state);
|
|
662
|
+
} catch (error) {
|
|
663
|
+
if (process.env.NODE_ENV === "development") {
|
|
664
|
+
console.error(`MotionStateManager listener error for ${elementId}:`, error);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* 모든 상태 초기화
|
|
671
|
+
*/
|
|
672
|
+
reset() {
|
|
673
|
+
this.states.clear();
|
|
674
|
+
this.listeners.clear();
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* 특정 요소 상태 초기화
|
|
678
|
+
*/
|
|
679
|
+
resetElement(elementId) {
|
|
680
|
+
this.states.delete(elementId);
|
|
681
|
+
this.listeners.delete(elementId);
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* 디버그용 상태 출력
|
|
685
|
+
*/
|
|
686
|
+
debug() {
|
|
687
|
+
if (process.env.NODE_ENV === "development") {
|
|
688
|
+
console.log("MotionStateManager Debug:");
|
|
689
|
+
this.states.forEach((state, elementId) => {
|
|
690
|
+
console.log(` ${elementId}:`, {
|
|
691
|
+
internalVisibility: state.internalVisibility,
|
|
692
|
+
triggeredVisibility: state.triggeredVisibility,
|
|
693
|
+
finalVisibility: state.finalVisibility,
|
|
694
|
+
opacity: state.opacity,
|
|
695
|
+
translateY: state.translateY,
|
|
696
|
+
isAnimating: state.isAnimating
|
|
697
|
+
});
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
var motionStateManager = new MotionStateManager();
|
|
703
|
+
|
|
704
|
+
// src/profiles/neutral.ts
|
|
705
|
+
var neutral = {
|
|
706
|
+
name: "neutral",
|
|
707
|
+
base: {
|
|
708
|
+
duration: 700,
|
|
709
|
+
easing: "ease-out",
|
|
710
|
+
threshold: 0.1,
|
|
711
|
+
triggerOnce: true
|
|
712
|
+
},
|
|
713
|
+
entrance: {
|
|
714
|
+
slide: {
|
|
715
|
+
distance: 32,
|
|
716
|
+
easing: "ease-out"
|
|
717
|
+
},
|
|
718
|
+
fade: {
|
|
719
|
+
initialOpacity: 0
|
|
720
|
+
},
|
|
721
|
+
scale: {
|
|
722
|
+
from: 0.95
|
|
723
|
+
},
|
|
724
|
+
bounce: {
|
|
725
|
+
intensity: 0.3,
|
|
726
|
+
easing: "cubic-bezier(0.34, 1.56, 0.64, 1)"
|
|
727
|
+
}
|
|
728
|
+
},
|
|
729
|
+
stagger: {
|
|
730
|
+
perItem: 100,
|
|
731
|
+
baseDelay: 0
|
|
732
|
+
},
|
|
733
|
+
interaction: {
|
|
734
|
+
hover: {
|
|
735
|
+
scale: 1.05,
|
|
736
|
+
y: -2,
|
|
737
|
+
duration: 200,
|
|
738
|
+
easing: "ease-out"
|
|
739
|
+
}
|
|
740
|
+
},
|
|
741
|
+
spring: {
|
|
742
|
+
mass: 1,
|
|
743
|
+
stiffness: 100,
|
|
744
|
+
damping: 10,
|
|
745
|
+
restDelta: 0.01,
|
|
746
|
+
restSpeed: 0.01
|
|
747
|
+
},
|
|
748
|
+
reducedMotion: "fade-only"
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
// src/profiles/hua.ts
|
|
752
|
+
var hua = {
|
|
753
|
+
name: "hua",
|
|
754
|
+
base: {
|
|
755
|
+
duration: 640,
|
|
756
|
+
easing: "cubic-bezier(0.22, 0.68, 0.35, 1.10)",
|
|
757
|
+
threshold: 0.12,
|
|
758
|
+
triggerOnce: true
|
|
759
|
+
},
|
|
760
|
+
entrance: {
|
|
761
|
+
slide: {
|
|
762
|
+
distance: 28,
|
|
763
|
+
easing: "cubic-bezier(0.22, 0.68, 0.35, 1.14)"
|
|
764
|
+
},
|
|
765
|
+
fade: {
|
|
766
|
+
initialOpacity: 0
|
|
767
|
+
},
|
|
768
|
+
scale: {
|
|
769
|
+
from: 0.97
|
|
770
|
+
},
|
|
771
|
+
bounce: {
|
|
772
|
+
intensity: 0.2,
|
|
773
|
+
easing: "cubic-bezier(0.22, 0.68, 0.35, 1.12)"
|
|
774
|
+
}
|
|
775
|
+
},
|
|
776
|
+
stagger: {
|
|
777
|
+
perItem: 80,
|
|
778
|
+
baseDelay: 0
|
|
779
|
+
},
|
|
780
|
+
interaction: {
|
|
781
|
+
hover: {
|
|
782
|
+
scale: 1.008,
|
|
783
|
+
y: -1,
|
|
784
|
+
duration: 180,
|
|
785
|
+
easing: "cubic-bezier(0.22, 0.68, 0.35, 1.10)"
|
|
786
|
+
}
|
|
787
|
+
},
|
|
788
|
+
spring: {
|
|
789
|
+
mass: 1,
|
|
790
|
+
stiffness: 180,
|
|
791
|
+
damping: 18,
|
|
792
|
+
restDelta: 5e-3,
|
|
793
|
+
restSpeed: 5e-3
|
|
794
|
+
},
|
|
795
|
+
reducedMotion: "fade-only"
|
|
796
|
+
};
|
|
797
|
+
var MotionProfileContext = react.createContext(neutral);
|
|
798
|
+
function MotionProfileProvider({
|
|
799
|
+
profile = "neutral",
|
|
800
|
+
overrides,
|
|
801
|
+
children
|
|
802
|
+
}) {
|
|
803
|
+
const resolved = react.useMemo(() => {
|
|
804
|
+
const base = resolveProfile(profile);
|
|
805
|
+
return overrides ? mergeProfileOverrides(base, overrides) : base;
|
|
806
|
+
}, [profile, overrides]);
|
|
807
|
+
return react.createElement(
|
|
808
|
+
MotionProfileContext.Provider,
|
|
809
|
+
{ value: resolved },
|
|
810
|
+
children
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
function useMotionProfile() {
|
|
814
|
+
return react.useContext(MotionProfileContext);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// src/profiles/index.ts
|
|
818
|
+
var PROFILES = {
|
|
819
|
+
neutral,
|
|
820
|
+
hua
|
|
821
|
+
};
|
|
822
|
+
function resolveProfile(profile) {
|
|
823
|
+
if (typeof profile === "string") {
|
|
824
|
+
return PROFILES[profile] ?? neutral;
|
|
825
|
+
}
|
|
826
|
+
return profile;
|
|
827
|
+
}
|
|
828
|
+
function mergeProfileOverrides(base, overrides) {
|
|
829
|
+
return deepMerge(
|
|
830
|
+
base,
|
|
831
|
+
overrides
|
|
832
|
+
);
|
|
833
|
+
}
|
|
834
|
+
function deepMerge(target, source) {
|
|
835
|
+
const result = { ...target };
|
|
836
|
+
for (const key of Object.keys(source)) {
|
|
837
|
+
const sourceVal = source[key];
|
|
838
|
+
const targetVal = result[key];
|
|
839
|
+
if (sourceVal !== null && sourceVal !== void 0 && typeof sourceVal === "object" && !Array.isArray(sourceVal) && typeof targetVal === "object" && targetVal !== null && !Array.isArray(targetVal)) {
|
|
840
|
+
result[key] = deepMerge(
|
|
841
|
+
targetVal,
|
|
842
|
+
sourceVal
|
|
843
|
+
);
|
|
844
|
+
} else if (sourceVal !== void 0) {
|
|
845
|
+
result[key] = sourceVal;
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
return result;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// src/utils/easing.ts
|
|
852
|
+
var linear = (t) => t;
|
|
853
|
+
var easeIn = (t) => t * t;
|
|
854
|
+
var easeOut = (t) => 1 - (1 - t) * (1 - t);
|
|
855
|
+
var easeInOut = (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
|
|
856
|
+
var easeInQuad = (t) => t * t;
|
|
857
|
+
var easeOutQuad = (t) => 1 - (1 - t) * (1 - t);
|
|
858
|
+
var easeInOutQuad = (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2;
|
|
859
|
+
var easeInCubic = (t) => t * t * t;
|
|
860
|
+
var easeOutCubic = (t) => 1 - Math.pow(1 - t, 3);
|
|
861
|
+
var easeInOutCubic = (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
|
862
|
+
var easeInQuart = (t) => t * t * t * t;
|
|
863
|
+
var easeOutQuart = (t) => 1 - Math.pow(1 - t, 4);
|
|
864
|
+
var easeInOutQuart = (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2;
|
|
865
|
+
var easeInQuint = (t) => t * t * t * t * t;
|
|
866
|
+
var easeOutQuint = (t) => 1 - Math.pow(1 - t, 5);
|
|
867
|
+
var easeInOutQuint = (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2;
|
|
868
|
+
var easeInSine = (t) => 1 - Math.cos(t * Math.PI / 2);
|
|
869
|
+
var easeOutSine = (t) => Math.sin(t * Math.PI / 2);
|
|
870
|
+
var easeInOutSine = (t) => -(Math.cos(Math.PI * t) - 1) / 2;
|
|
871
|
+
var easeInExpo = (t) => t === 0 ? 0 : Math.pow(2, 10 * t - 10);
|
|
872
|
+
var easeOutExpo = (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
|
|
873
|
+
var easeInOutExpo = (t) => {
|
|
874
|
+
if (t === 0) return 0;
|
|
875
|
+
if (t === 1) return 1;
|
|
876
|
+
if (t < 0.5) return Math.pow(2, 20 * t - 10) / 2;
|
|
877
|
+
return (2 - Math.pow(2, -20 * t + 10)) / 2;
|
|
878
|
+
};
|
|
879
|
+
var easeInCirc = (t) => 1 - Math.sqrt(1 - Math.pow(t, 2));
|
|
880
|
+
var easeOutCirc = (t) => Math.sqrt(1 - Math.pow(t - 1, 2));
|
|
881
|
+
var easeInOutCirc = (t) => {
|
|
882
|
+
if (t < 0.5) return (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2;
|
|
883
|
+
return (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2;
|
|
884
|
+
};
|
|
885
|
+
var easeInBounce = (t) => 1 - easeOutBounce(1 - t);
|
|
886
|
+
var easeOutBounce = (t) => {
|
|
887
|
+
const n1 = 7.5625;
|
|
888
|
+
const d1 = 2.75;
|
|
889
|
+
if (t < 1 / d1) {
|
|
890
|
+
return n1 * t * t;
|
|
891
|
+
} else if (t < 2 / d1) {
|
|
892
|
+
return n1 * (t -= 1.5 / d1) * t + 0.75;
|
|
893
|
+
} else if (t < 2.5 / d1) {
|
|
894
|
+
return n1 * (t -= 2.25 / d1) * t + 0.9375;
|
|
895
|
+
} else {
|
|
896
|
+
return n1 * (t -= 2.625 / d1) * t + 0.984375;
|
|
897
|
+
}
|
|
898
|
+
};
|
|
899
|
+
var easeInOutBounce = (t) => {
|
|
900
|
+
if (t < 0.5) return (1 - easeOutBounce(1 - 2 * t)) / 2;
|
|
901
|
+
return (1 + easeOutBounce(2 * t - 1)) / 2;
|
|
902
|
+
};
|
|
903
|
+
var easeInBack = (t) => {
|
|
904
|
+
const c1 = 1.70158;
|
|
905
|
+
const c3 = c1 + 1;
|
|
906
|
+
return c3 * t * t * t - c1 * t * t;
|
|
907
|
+
};
|
|
908
|
+
var easeOutBack = (t) => {
|
|
909
|
+
const c1 = 1.70158;
|
|
910
|
+
const c3 = c1 + 1;
|
|
911
|
+
return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
|
|
912
|
+
};
|
|
913
|
+
var easeInOutBack = (t) => {
|
|
914
|
+
const c1 = 1.70158;
|
|
915
|
+
const c2 = c1 * 1.525;
|
|
916
|
+
if (t < 0.5) {
|
|
917
|
+
return Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2) / 2;
|
|
918
|
+
} else {
|
|
919
|
+
return (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2;
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
var easeInElastic = (t) => {
|
|
923
|
+
const c4 = 2 * Math.PI / 3;
|
|
924
|
+
if (t === 0) return 0;
|
|
925
|
+
if (t === 1) return 1;
|
|
926
|
+
return -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 0.75) * c4);
|
|
927
|
+
};
|
|
928
|
+
var easeOutElastic = (t) => {
|
|
929
|
+
const c4 = 2 * Math.PI / 3;
|
|
930
|
+
if (t === 0) return 0;
|
|
931
|
+
if (t === 1) return 1;
|
|
932
|
+
return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
|
|
933
|
+
};
|
|
934
|
+
var easeInOutElastic = (t) => {
|
|
935
|
+
const c5 = 2 * Math.PI / 4.5;
|
|
936
|
+
if (t === 0) return 0;
|
|
937
|
+
if (t === 1) return 1;
|
|
938
|
+
if (t < 0.5) {
|
|
939
|
+
return -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * c5)) / 2;
|
|
940
|
+
} else {
|
|
941
|
+
return Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * c5) / 2 + 1;
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
var pulse = (t) => Math.sin(t * Math.PI) * 0.5 + 0.5;
|
|
945
|
+
var pulseSmooth = (t) => Math.sin(t * Math.PI * 2) * 0.3 + 0.7;
|
|
946
|
+
var skeletonWave = (t) => Math.sin((t - 0.5) * Math.PI * 2) * 0.5 + 0.5;
|
|
947
|
+
var blink = (t) => t < 0.5 ? 1 : 0;
|
|
948
|
+
var easing = {
|
|
949
|
+
linear,
|
|
950
|
+
easeIn,
|
|
951
|
+
easeOut,
|
|
952
|
+
easeInOut,
|
|
953
|
+
easeInQuad,
|
|
954
|
+
easeOutQuad,
|
|
955
|
+
easeInOutQuad,
|
|
956
|
+
easeInCubic,
|
|
957
|
+
easeOutCubic,
|
|
958
|
+
easeInOutCubic,
|
|
959
|
+
easeInQuart,
|
|
960
|
+
easeOutQuart,
|
|
961
|
+
easeInOutQuart,
|
|
962
|
+
easeInQuint,
|
|
963
|
+
easeOutQuint,
|
|
964
|
+
easeInOutQuint,
|
|
965
|
+
easeInSine,
|
|
966
|
+
easeOutSine,
|
|
967
|
+
easeInOutSine,
|
|
968
|
+
easeInExpo,
|
|
969
|
+
easeOutExpo,
|
|
970
|
+
easeInOutExpo,
|
|
971
|
+
easeInCirc,
|
|
972
|
+
easeOutCirc,
|
|
973
|
+
easeInOutCirc,
|
|
974
|
+
easeInBounce,
|
|
975
|
+
easeOutBounce,
|
|
976
|
+
easeInOutBounce,
|
|
977
|
+
easeInBack,
|
|
978
|
+
easeOutBack,
|
|
979
|
+
easeInOutBack,
|
|
980
|
+
easeInElastic,
|
|
981
|
+
easeOutElastic,
|
|
982
|
+
easeInOutElastic,
|
|
983
|
+
pulse,
|
|
984
|
+
pulseSmooth,
|
|
985
|
+
skeletonWave,
|
|
986
|
+
blink
|
|
987
|
+
};
|
|
988
|
+
function isValidEasing(easingName) {
|
|
989
|
+
return easingName in easing;
|
|
990
|
+
}
|
|
991
|
+
function getEasing(easingName) {
|
|
992
|
+
if (typeof easingName === "function") {
|
|
993
|
+
return easingName;
|
|
994
|
+
}
|
|
995
|
+
if (typeof easingName === "string") {
|
|
996
|
+
if (easingName in easing) {
|
|
997
|
+
return easing[easingName];
|
|
998
|
+
}
|
|
999
|
+
if (easingName === "bounce") {
|
|
1000
|
+
return easing.easeOutBounce;
|
|
1001
|
+
}
|
|
1002
|
+
if (process.env.NODE_ENV === "development") {
|
|
1003
|
+
console.warn(`[HUA Motion] Unknown easing "${easingName}", using default "easeOut".`);
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
return easeOut;
|
|
1007
|
+
}
|
|
1008
|
+
function applyEasing(t, easingName) {
|
|
1009
|
+
const easingFn = getEasing(easingName);
|
|
1010
|
+
return easingFn(t);
|
|
1011
|
+
}
|
|
1012
|
+
function safeApplyEasing(t, easingName) {
|
|
1013
|
+
try {
|
|
1014
|
+
const easingFn = getEasing(easingName);
|
|
1015
|
+
return easingFn(t);
|
|
1016
|
+
} catch (err) {
|
|
1017
|
+
if (process.env.NODE_ENV === "development") {
|
|
1018
|
+
console.error(`[HUA Motion] Failed to apply easing "${easingName}":`, err);
|
|
1019
|
+
}
|
|
1020
|
+
return easeOut(t);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
function getAvailableEasings() {
|
|
1024
|
+
return Object.keys(easing);
|
|
1025
|
+
}
|
|
1026
|
+
function isEasingFunction(value) {
|
|
1027
|
+
return typeof value === "function";
|
|
1028
|
+
}
|
|
1029
|
+
var easingPresets = {
|
|
1030
|
+
default: "easeOut",
|
|
1031
|
+
smooth: "easeInOutCubic",
|
|
1032
|
+
fast: "easeOutQuad",
|
|
1033
|
+
slow: "easeInOutSine",
|
|
1034
|
+
bouncy: "easeOutBounce",
|
|
1035
|
+
elastic: "easeOutElastic",
|
|
1036
|
+
fade: "easeInOut",
|
|
1037
|
+
scale: "easeOutBack"
|
|
1038
|
+
};
|
|
1039
|
+
function getPresetEasing(preset) {
|
|
1040
|
+
const easingName = easingPresets[preset];
|
|
1041
|
+
return getEasing(easingName);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// src/utils/springPhysics.ts
|
|
1045
|
+
function calculateSpring(currentValue, currentVelocity, targetValue, deltaTime, config) {
|
|
1046
|
+
const { stiffness, damping, mass } = config;
|
|
1047
|
+
const displacement = currentValue - targetValue;
|
|
1048
|
+
const springForce = -stiffness * displacement;
|
|
1049
|
+
const dampingForce = -damping * currentVelocity;
|
|
1050
|
+
const acceleration = (springForce + dampingForce) / mass;
|
|
1051
|
+
const newVelocity = currentVelocity + acceleration * deltaTime;
|
|
1052
|
+
const newValue = currentValue + newVelocity * deltaTime;
|
|
1053
|
+
return { value: newValue, velocity: newVelocity };
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
exports.MOTION_PRESETS = MOTION_PRESETS;
|
|
1057
|
+
exports.MotionEngine = MotionEngine;
|
|
1058
|
+
exports.MotionProfileProvider = MotionProfileProvider;
|
|
1059
|
+
exports.MotionStateManager = MotionStateManager;
|
|
1060
|
+
exports.PAGE_MOTIONS = PAGE_MOTIONS;
|
|
1061
|
+
exports.TransitionEffects = TransitionEffects;
|
|
1062
|
+
exports.applyEasing = applyEasing;
|
|
1063
|
+
exports.calculateSpring = calculateSpring;
|
|
1064
|
+
exports.easeIn = easeIn;
|
|
1065
|
+
exports.easeInOut = easeInOut;
|
|
1066
|
+
exports.easeInOutQuad = easeInOutQuad;
|
|
1067
|
+
exports.easeInQuad = easeInQuad;
|
|
1068
|
+
exports.easeOut = easeOut;
|
|
1069
|
+
exports.easeOutQuad = easeOutQuad;
|
|
1070
|
+
exports.easingPresets = easingPresets;
|
|
1071
|
+
exports.getAvailableEasings = getAvailableEasings;
|
|
1072
|
+
exports.getEasing = getEasing;
|
|
1073
|
+
exports.getMotionPreset = getMotionPreset;
|
|
1074
|
+
exports.getPagePreset = getPagePreset;
|
|
1075
|
+
exports.getPresetEasing = getPresetEasing;
|
|
1076
|
+
exports.hua = hua;
|
|
1077
|
+
exports.isEasingFunction = isEasingFunction;
|
|
1078
|
+
exports.isValidEasing = isValidEasing;
|
|
1079
|
+
exports.linear = linear;
|
|
1080
|
+
exports.mergeProfileOverrides = mergeProfileOverrides;
|
|
1081
|
+
exports.mergeWithPreset = mergeWithPreset;
|
|
1082
|
+
exports.motionEngine = motionEngine;
|
|
1083
|
+
exports.motionStateManager = motionStateManager;
|
|
1084
|
+
exports.neutral = neutral;
|
|
1085
|
+
exports.resolveProfile = resolveProfile;
|
|
1086
|
+
exports.safeApplyEasing = safeApplyEasing;
|
|
1087
|
+
exports.transitionEffects = transitionEffects;
|
|
1088
|
+
exports.useMotionProfile = useMotionProfile;
|
|
1089
|
+
//# sourceMappingURL=chunk-LSIP7MB5.cjs.map
|
|
1090
|
+
//# sourceMappingURL=chunk-LSIP7MB5.cjs.map
|