@hua-labs/motion-core 2.2.1 → 2.2.3
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 +27 -100
- package/dist/index.d.mts +283 -6
- package/dist/index.d.ts +283 -6
- package/dist/index.js +715 -207
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +709 -208
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
4
|
|
|
4
5
|
// src/core/MotionEngine.ts
|
|
5
6
|
var MotionEngine = class {
|
|
@@ -198,39 +199,42 @@ var TransitionEffects = class _TransitionEffects {
|
|
|
198
199
|
*/
|
|
199
200
|
async fade(element, options) {
|
|
200
201
|
const transitionId = this.generateTransitionId();
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
[
|
|
213
|
-
{ progress: 0, properties: { opacity: options.direction === "reverse" ? initialOpacity : 0 } },
|
|
214
|
-
{ progress: 1, properties: { opacity: targetOpacity } }
|
|
215
|
-
],
|
|
216
|
-
{
|
|
217
|
-
duration: options.duration,
|
|
218
|
-
easing: options.easing || this.getDefaultEasing(),
|
|
219
|
-
delay: options.delay,
|
|
220
|
-
onStart: options.onTransitionStart,
|
|
221
|
-
onUpdate: (progress) => {
|
|
222
|
-
const currentOpacity = options.direction === "reverse" ? initialOpacity * (1 - progress) : targetOpacity * progress;
|
|
223
|
-
element.style.opacity = currentOpacity.toString();
|
|
224
|
-
},
|
|
225
|
-
onComplete: () => {
|
|
226
|
-
options.onTransitionComplete?.();
|
|
227
|
-
this.activeTransitions.delete(transitionId);
|
|
228
|
-
resolve();
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
);
|
|
232
|
-
this.activeTransitions.set(transitionId, motionId);
|
|
202
|
+
const initialOpacity = parseFloat(getComputedStyle(element).opacity) || 1;
|
|
203
|
+
const targetOpacity = options.direction === "reverse" ? 0 : 1;
|
|
204
|
+
if (options.direction === "reverse") {
|
|
205
|
+
element.style.opacity = initialOpacity.toString();
|
|
206
|
+
} else {
|
|
207
|
+
element.style.opacity = "0";
|
|
208
|
+
}
|
|
209
|
+
this.enableGPUAcceleration(element);
|
|
210
|
+
let resolveTransition;
|
|
211
|
+
const completed = new Promise((resolve) => {
|
|
212
|
+
resolveTransition = resolve;
|
|
233
213
|
});
|
|
214
|
+
const motionId = await motionEngine.motion(
|
|
215
|
+
element,
|
|
216
|
+
[
|
|
217
|
+
{ progress: 0, properties: { opacity: options.direction === "reverse" ? initialOpacity : 0 } },
|
|
218
|
+
{ progress: 1, properties: { opacity: targetOpacity } }
|
|
219
|
+
],
|
|
220
|
+
{
|
|
221
|
+
duration: options.duration,
|
|
222
|
+
easing: options.easing || this.getDefaultEasing(),
|
|
223
|
+
delay: options.delay,
|
|
224
|
+
onStart: options.onTransitionStart,
|
|
225
|
+
onUpdate: (progress) => {
|
|
226
|
+
const currentOpacity = options.direction === "reverse" ? initialOpacity * (1 - progress) : targetOpacity * progress;
|
|
227
|
+
element.style.opacity = currentOpacity.toString();
|
|
228
|
+
},
|
|
229
|
+
onComplete: () => {
|
|
230
|
+
options.onTransitionComplete?.();
|
|
231
|
+
this.activeTransitions.delete(transitionId);
|
|
232
|
+
resolveTransition();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
this.activeTransitions.set(transitionId, motionId);
|
|
237
|
+
return completed;
|
|
234
238
|
}
|
|
235
239
|
/**
|
|
236
240
|
* 슬라이드 전환
|
|
@@ -238,38 +242,41 @@ var TransitionEffects = class _TransitionEffects {
|
|
|
238
242
|
async slide(element, options) {
|
|
239
243
|
const transitionId = this.generateTransitionId();
|
|
240
244
|
const distance = options.distance || 100;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
[
|
|
251
|
-
{ progress: 0, properties: { translateX: isReverse ? 0 : distance } },
|
|
252
|
-
{ progress: 1, properties: { translateX: isReverse ? distance : 0 } }
|
|
253
|
-
],
|
|
254
|
-
{
|
|
255
|
-
duration: options.duration,
|
|
256
|
-
easing: options.easing || this.getDefaultEasing(),
|
|
257
|
-
delay: options.delay,
|
|
258
|
-
onStart: options.onTransitionStart,
|
|
259
|
-
onUpdate: (progress) => {
|
|
260
|
-
const currentTranslateX = isReverse ? distance * progress : distance * (1 - progress);
|
|
261
|
-
element.style.transform = `translateX(${currentTranslateX}px)`;
|
|
262
|
-
},
|
|
263
|
-
onComplete: () => {
|
|
264
|
-
element.style.transform = initialTransform;
|
|
265
|
-
options.onTransitionComplete?.();
|
|
266
|
-
this.activeTransitions.delete(transitionId);
|
|
267
|
-
resolve();
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
);
|
|
271
|
-
this.activeTransitions.set(transitionId, motionId);
|
|
245
|
+
const initialTransform = getComputedStyle(element).transform;
|
|
246
|
+
const isReverse = options.direction === "reverse";
|
|
247
|
+
if (!isReverse) {
|
|
248
|
+
element.style.transform = `translateX(${distance}px)`;
|
|
249
|
+
}
|
|
250
|
+
this.enableGPUAcceleration(element);
|
|
251
|
+
let resolveTransition;
|
|
252
|
+
const completed = new Promise((resolve) => {
|
|
253
|
+
resolveTransition = resolve;
|
|
272
254
|
});
|
|
255
|
+
const motionId = await motionEngine.motion(
|
|
256
|
+
element,
|
|
257
|
+
[
|
|
258
|
+
{ progress: 0, properties: { translateX: isReverse ? 0 : distance } },
|
|
259
|
+
{ progress: 1, properties: { translateX: isReverse ? distance : 0 } }
|
|
260
|
+
],
|
|
261
|
+
{
|
|
262
|
+
duration: options.duration,
|
|
263
|
+
easing: options.easing || this.getDefaultEasing(),
|
|
264
|
+
delay: options.delay,
|
|
265
|
+
onStart: options.onTransitionStart,
|
|
266
|
+
onUpdate: (progress) => {
|
|
267
|
+
const currentTranslateX = isReverse ? distance * progress : distance * (1 - progress);
|
|
268
|
+
element.style.transform = `translateX(${currentTranslateX}px)`;
|
|
269
|
+
},
|
|
270
|
+
onComplete: () => {
|
|
271
|
+
element.style.transform = initialTransform;
|
|
272
|
+
options.onTransitionComplete?.();
|
|
273
|
+
this.activeTransitions.delete(transitionId);
|
|
274
|
+
resolveTransition();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
this.activeTransitions.set(transitionId, motionId);
|
|
279
|
+
return completed;
|
|
273
280
|
}
|
|
274
281
|
/**
|
|
275
282
|
* 스케일 전환
|
|
@@ -277,38 +284,41 @@ var TransitionEffects = class _TransitionEffects {
|
|
|
277
284
|
async scale(element, options) {
|
|
278
285
|
const transitionId = this.generateTransitionId();
|
|
279
286
|
const scaleValue = options.scale || 0.8;
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
[
|
|
290
|
-
{ progress: 0, properties: { scale: isReverse ? 1 : scaleValue } },
|
|
291
|
-
{ progress: 1, properties: { scale: isReverse ? scaleValue : 1 } }
|
|
292
|
-
],
|
|
293
|
-
{
|
|
294
|
-
duration: options.duration,
|
|
295
|
-
easing: options.easing || this.getDefaultEasing(),
|
|
296
|
-
delay: options.delay,
|
|
297
|
-
onStart: options.onTransitionStart,
|
|
298
|
-
onUpdate: (progress) => {
|
|
299
|
-
const currentScale = isReverse ? 1 - (1 - scaleValue) * progress : scaleValue + (1 - scaleValue) * progress;
|
|
300
|
-
element.style.transform = `scale(${currentScale})`;
|
|
301
|
-
},
|
|
302
|
-
onComplete: () => {
|
|
303
|
-
element.style.transform = initialTransform;
|
|
304
|
-
options.onTransitionComplete?.();
|
|
305
|
-
this.activeTransitions.delete(transitionId);
|
|
306
|
-
resolve();
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
);
|
|
310
|
-
this.activeTransitions.set(transitionId, motionId);
|
|
287
|
+
const initialTransform = getComputedStyle(element).transform;
|
|
288
|
+
const isReverse = options.direction === "reverse";
|
|
289
|
+
if (!isReverse) {
|
|
290
|
+
element.style.transform = `scale(${scaleValue})`;
|
|
291
|
+
}
|
|
292
|
+
this.enableGPUAcceleration(element);
|
|
293
|
+
let resolveTransition;
|
|
294
|
+
const completed = new Promise((resolve) => {
|
|
295
|
+
resolveTransition = resolve;
|
|
311
296
|
});
|
|
297
|
+
const motionId = await motionEngine.motion(
|
|
298
|
+
element,
|
|
299
|
+
[
|
|
300
|
+
{ progress: 0, properties: { scale: isReverse ? 1 : scaleValue } },
|
|
301
|
+
{ progress: 1, properties: { scale: isReverse ? scaleValue : 1 } }
|
|
302
|
+
],
|
|
303
|
+
{
|
|
304
|
+
duration: options.duration,
|
|
305
|
+
easing: options.easing || this.getDefaultEasing(),
|
|
306
|
+
delay: options.delay,
|
|
307
|
+
onStart: options.onTransitionStart,
|
|
308
|
+
onUpdate: (progress) => {
|
|
309
|
+
const currentScale = isReverse ? 1 - (1 - scaleValue) * progress : scaleValue + (1 - scaleValue) * progress;
|
|
310
|
+
element.style.transform = `scale(${currentScale})`;
|
|
311
|
+
},
|
|
312
|
+
onComplete: () => {
|
|
313
|
+
element.style.transform = initialTransform;
|
|
314
|
+
options.onTransitionComplete?.();
|
|
315
|
+
this.activeTransitions.delete(transitionId);
|
|
316
|
+
resolveTransition();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
);
|
|
320
|
+
this.activeTransitions.set(transitionId, motionId);
|
|
321
|
+
return completed;
|
|
312
322
|
}
|
|
313
323
|
/**
|
|
314
324
|
* 플립 전환 (3D 회전)
|
|
@@ -316,42 +326,45 @@ var TransitionEffects = class _TransitionEffects {
|
|
|
316
326
|
async flip(element, options) {
|
|
317
327
|
const transitionId = this.generateTransitionId();
|
|
318
328
|
const perspective = options.perspective || 1e3;
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
[
|
|
331
|
-
{ progress: 0, properties: { rotateY: isReverse ? 0 : 90 } },
|
|
332
|
-
{ progress: 1, properties: { rotateY: isReverse ? 90 : 0 } }
|
|
333
|
-
],
|
|
334
|
-
{
|
|
335
|
-
duration: options.duration,
|
|
336
|
-
easing: options.easing || this.getDefaultEasing(),
|
|
337
|
-
delay: options.delay,
|
|
338
|
-
onStart: options.onTransitionStart,
|
|
339
|
-
onUpdate: (progress) => {
|
|
340
|
-
const currentRotateY = isReverse ? 90 * progress : 90 * (1 - progress);
|
|
341
|
-
element.style.transform = `rotateY(${currentRotateY}deg)`;
|
|
342
|
-
},
|
|
343
|
-
onComplete: () => {
|
|
344
|
-
element.style.transform = initialTransform;
|
|
345
|
-
element.style.perspective = "";
|
|
346
|
-
element.style.transformStyle = "";
|
|
347
|
-
options.onTransitionComplete?.();
|
|
348
|
-
this.activeTransitions.delete(transitionId);
|
|
349
|
-
resolve();
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
);
|
|
353
|
-
this.activeTransitions.set(transitionId, motionId);
|
|
329
|
+
const initialTransform = getComputedStyle(element).transform;
|
|
330
|
+
const isReverse = options.direction === "reverse";
|
|
331
|
+
element.style.perspective = `${perspective}px`;
|
|
332
|
+
element.style.transformStyle = "preserve-3d";
|
|
333
|
+
if (!isReverse) {
|
|
334
|
+
element.style.transform = `rotateY(90deg)`;
|
|
335
|
+
}
|
|
336
|
+
this.enableGPUAcceleration(element);
|
|
337
|
+
let resolveTransition;
|
|
338
|
+
const completed = new Promise((resolve) => {
|
|
339
|
+
resolveTransition = resolve;
|
|
354
340
|
});
|
|
341
|
+
const motionId = await motionEngine.motion(
|
|
342
|
+
element,
|
|
343
|
+
[
|
|
344
|
+
{ progress: 0, properties: { rotateY: isReverse ? 0 : 90 } },
|
|
345
|
+
{ progress: 1, properties: { rotateY: isReverse ? 90 : 0 } }
|
|
346
|
+
],
|
|
347
|
+
{
|
|
348
|
+
duration: options.duration,
|
|
349
|
+
easing: options.easing || this.getDefaultEasing(),
|
|
350
|
+
delay: options.delay,
|
|
351
|
+
onStart: options.onTransitionStart,
|
|
352
|
+
onUpdate: (progress) => {
|
|
353
|
+
const currentRotateY = isReverse ? 90 * progress : 90 * (1 - progress);
|
|
354
|
+
element.style.transform = `rotateY(${currentRotateY}deg)`;
|
|
355
|
+
},
|
|
356
|
+
onComplete: () => {
|
|
357
|
+
element.style.transform = initialTransform;
|
|
358
|
+
element.style.perspective = "";
|
|
359
|
+
element.style.transformStyle = "";
|
|
360
|
+
options.onTransitionComplete?.();
|
|
361
|
+
this.activeTransitions.delete(transitionId);
|
|
362
|
+
resolveTransition();
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
);
|
|
366
|
+
this.activeTransitions.set(transitionId, motionId);
|
|
367
|
+
return completed;
|
|
355
368
|
}
|
|
356
369
|
/**
|
|
357
370
|
* 큐브 전환 (3D 큐브 회전)
|
|
@@ -359,82 +372,88 @@ var TransitionEffects = class _TransitionEffects {
|
|
|
359
372
|
async cube(element, options) {
|
|
360
373
|
const transitionId = this.generateTransitionId();
|
|
361
374
|
const perspective = options.perspective || 1200;
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
[
|
|
374
|
-
{ progress: 0, properties: { rotateX: isReverse ? 0 : 90, rotateY: isReverse ? 0 : 45 } },
|
|
375
|
-
{ progress: 1, properties: { rotateX: isReverse ? 90 : 0, rotateY: isReverse ? 45 : 0 } }
|
|
376
|
-
],
|
|
377
|
-
{
|
|
378
|
-
duration: options.duration,
|
|
379
|
-
easing: options.easing || this.getDefaultEasing(),
|
|
380
|
-
delay: options.delay,
|
|
381
|
-
onStart: options.onTransitionStart,
|
|
382
|
-
onUpdate: (progress) => {
|
|
383
|
-
const currentRotateX = isReverse ? 90 * progress : 90 * (1 - progress);
|
|
384
|
-
const currentRotateY = isReverse ? 45 * progress : 45 * (1 - progress);
|
|
385
|
-
element.style.transform = `rotateX(${currentRotateX}deg) rotateY(${currentRotateY}deg)`;
|
|
386
|
-
},
|
|
387
|
-
onComplete: () => {
|
|
388
|
-
element.style.transform = initialTransform;
|
|
389
|
-
element.style.perspective = "";
|
|
390
|
-
element.style.transformStyle = "";
|
|
391
|
-
options.onTransitionComplete?.();
|
|
392
|
-
this.activeTransitions.delete(transitionId);
|
|
393
|
-
resolve();
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
);
|
|
397
|
-
this.activeTransitions.set(transitionId, motionId);
|
|
375
|
+
const initialTransform = getComputedStyle(element).transform;
|
|
376
|
+
const isReverse = options.direction === "reverse";
|
|
377
|
+
element.style.perspective = `${perspective}px`;
|
|
378
|
+
element.style.transformStyle = "preserve-3d";
|
|
379
|
+
if (!isReverse) {
|
|
380
|
+
element.style.transform = `rotateX(90deg) rotateY(45deg)`;
|
|
381
|
+
}
|
|
382
|
+
this.enableGPUAcceleration(element);
|
|
383
|
+
let resolveTransition;
|
|
384
|
+
const completed = new Promise((resolve) => {
|
|
385
|
+
resolveTransition = resolve;
|
|
398
386
|
});
|
|
387
|
+
const motionId = await motionEngine.motion(
|
|
388
|
+
element,
|
|
389
|
+
[
|
|
390
|
+
{ progress: 0, properties: { rotateX: isReverse ? 0 : 90, rotateY: isReverse ? 0 : 45 } },
|
|
391
|
+
{ progress: 1, properties: { rotateX: isReverse ? 90 : 0, rotateY: isReverse ? 45 : 0 } }
|
|
392
|
+
],
|
|
393
|
+
{
|
|
394
|
+
duration: options.duration,
|
|
395
|
+
easing: options.easing || this.getDefaultEasing(),
|
|
396
|
+
delay: options.delay,
|
|
397
|
+
onStart: options.onTransitionStart,
|
|
398
|
+
onUpdate: (progress) => {
|
|
399
|
+
const currentRotateX = isReverse ? 90 * progress : 90 * (1 - progress);
|
|
400
|
+
const currentRotateY = isReverse ? 45 * progress : 45 * (1 - progress);
|
|
401
|
+
element.style.transform = `rotateX(${currentRotateX}deg) rotateY(${currentRotateY}deg)`;
|
|
402
|
+
},
|
|
403
|
+
onComplete: () => {
|
|
404
|
+
element.style.transform = initialTransform;
|
|
405
|
+
element.style.perspective = "";
|
|
406
|
+
element.style.transformStyle = "";
|
|
407
|
+
options.onTransitionComplete?.();
|
|
408
|
+
this.activeTransitions.delete(transitionId);
|
|
409
|
+
resolveTransition();
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
);
|
|
413
|
+
this.activeTransitions.set(transitionId, motionId);
|
|
414
|
+
return completed;
|
|
399
415
|
}
|
|
400
416
|
/**
|
|
401
417
|
* 모프 전환 (복합 변형)
|
|
402
418
|
*/
|
|
403
419
|
async morph(element, options) {
|
|
404
420
|
const transitionId = this.generateTransitionId();
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
[
|
|
415
|
-
{ progress: 0, properties: { scale: isReverse ? 1 : 0.9, rotate: isReverse ? 0 : 5 } },
|
|
416
|
-
{ progress: 1, properties: { scale: isReverse ? 0.9 : 1, rotate: isReverse ? 5 : 0 } }
|
|
417
|
-
],
|
|
418
|
-
{
|
|
419
|
-
duration: options.duration,
|
|
420
|
-
easing: options.easing || this.getDefaultEasing(),
|
|
421
|
-
delay: options.delay,
|
|
422
|
-
onStart: options.onTransitionStart,
|
|
423
|
-
onUpdate: (progress) => {
|
|
424
|
-
const currentScale = isReverse ? 1 - 0.1 * progress : 0.9 + 0.1 * progress;
|
|
425
|
-
const currentRotate = isReverse ? 5 * progress : 5 * (1 - progress);
|
|
426
|
-
element.style.transform = `scale(${currentScale}) rotate(${currentRotate}deg)`;
|
|
427
|
-
},
|
|
428
|
-
onComplete: () => {
|
|
429
|
-
element.style.transform = initialTransform;
|
|
430
|
-
options.onTransitionComplete?.();
|
|
431
|
-
this.activeTransitions.delete(transitionId);
|
|
432
|
-
resolve();
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
);
|
|
436
|
-
this.activeTransitions.set(transitionId, motionId);
|
|
421
|
+
const initialTransform = getComputedStyle(element).transform;
|
|
422
|
+
const isReverse = options.direction === "reverse";
|
|
423
|
+
if (!isReverse) {
|
|
424
|
+
element.style.transform = `scale(0.9) rotate(5deg)`;
|
|
425
|
+
}
|
|
426
|
+
this.enableGPUAcceleration(element);
|
|
427
|
+
let resolveTransition;
|
|
428
|
+
const completed = new Promise((resolve) => {
|
|
429
|
+
resolveTransition = resolve;
|
|
437
430
|
});
|
|
431
|
+
const motionId = await motionEngine.motion(
|
|
432
|
+
element,
|
|
433
|
+
[
|
|
434
|
+
{ progress: 0, properties: { scale: isReverse ? 1 : 0.9, rotate: isReverse ? 0 : 5 } },
|
|
435
|
+
{ progress: 1, properties: { scale: isReverse ? 0.9 : 1, rotate: isReverse ? 5 : 0 } }
|
|
436
|
+
],
|
|
437
|
+
{
|
|
438
|
+
duration: options.duration,
|
|
439
|
+
easing: options.easing || this.getDefaultEasing(),
|
|
440
|
+
delay: options.delay,
|
|
441
|
+
onStart: options.onTransitionStart,
|
|
442
|
+
onUpdate: (progress) => {
|
|
443
|
+
const currentScale = isReverse ? 1 - 0.1 * progress : 0.9 + 0.1 * progress;
|
|
444
|
+
const currentRotate = isReverse ? 5 * progress : 5 * (1 - progress);
|
|
445
|
+
element.style.transform = `scale(${currentScale}) rotate(${currentRotate}deg)`;
|
|
446
|
+
},
|
|
447
|
+
onComplete: () => {
|
|
448
|
+
element.style.transform = initialTransform;
|
|
449
|
+
options.onTransitionComplete?.();
|
|
450
|
+
this.activeTransitions.delete(transitionId);
|
|
451
|
+
resolveTransition();
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
this.activeTransitions.set(transitionId, motionId);
|
|
456
|
+
return completed;
|
|
438
457
|
}
|
|
439
458
|
/**
|
|
440
459
|
* 전환 중지
|
|
@@ -906,10 +925,10 @@ function useSimplePageMotions(config) {
|
|
|
906
925
|
const calculateMotionValues = useCallback((isVisible, elementConfig) => {
|
|
907
926
|
const preset = getMotionPreset(elementConfig.type);
|
|
908
927
|
mergeWithPreset(preset, elementConfig);
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
928
|
+
const opacity = isVisible ? 1 : 0;
|
|
929
|
+
const translateY = isVisible ? 0 : 20;
|
|
930
|
+
const translateX = 0;
|
|
931
|
+
const scale = isVisible ? 1 : 0.95;
|
|
913
932
|
return { opacity, translateY, translateX, scale };
|
|
914
933
|
}, []);
|
|
915
934
|
useEffect(() => {
|
|
@@ -1169,7 +1188,7 @@ function usePageMotions(config) {
|
|
|
1169
1188
|
const mergedConfig = mergeWithPreset(preset, elementConfig);
|
|
1170
1189
|
let opacity = state.finalVisibility ? 1 : 0;
|
|
1171
1190
|
let translateY = state.finalVisibility ? 0 : 20;
|
|
1172
|
-
|
|
1191
|
+
const translateX = 0;
|
|
1173
1192
|
let scale = state.finalVisibility ? 1 : 0.95;
|
|
1174
1193
|
if (mergedConfig.hover && state.isHovered) {
|
|
1175
1194
|
scale *= 1.1;
|
|
@@ -1666,9 +1685,77 @@ function getEasingForType(type, easing2) {
|
|
|
1666
1685
|
if (type === "bounceIn") return "cubic-bezier(0.34, 1.56, 0.64, 1)";
|
|
1667
1686
|
return "ease-out";
|
|
1668
1687
|
}
|
|
1688
|
+
function getMultiEffectInitialStyle(effects, defaultDistance) {
|
|
1689
|
+
const style = {};
|
|
1690
|
+
const transforms = [];
|
|
1691
|
+
if (effects.fade) {
|
|
1692
|
+
style.opacity = 0;
|
|
1693
|
+
}
|
|
1694
|
+
if (effects.slide) {
|
|
1695
|
+
const config = typeof effects.slide === "object" ? effects.slide : {};
|
|
1696
|
+
const direction = config.direction ?? "up";
|
|
1697
|
+
const distance = config.distance ?? defaultDistance;
|
|
1698
|
+
switch (direction) {
|
|
1699
|
+
case "up":
|
|
1700
|
+
transforms.push(`translateY(${distance}px)`);
|
|
1701
|
+
break;
|
|
1702
|
+
case "down":
|
|
1703
|
+
transforms.push(`translateY(-${distance}px)`);
|
|
1704
|
+
break;
|
|
1705
|
+
case "left":
|
|
1706
|
+
transforms.push(`translateX(${distance}px)`);
|
|
1707
|
+
break;
|
|
1708
|
+
case "right":
|
|
1709
|
+
transforms.push(`translateX(-${distance}px)`);
|
|
1710
|
+
break;
|
|
1711
|
+
}
|
|
1712
|
+
if (!effects.fade) style.opacity = 0;
|
|
1713
|
+
}
|
|
1714
|
+
if (effects.scale) {
|
|
1715
|
+
const config = typeof effects.scale === "object" ? effects.scale : {};
|
|
1716
|
+
const from = config.from ?? 0.95;
|
|
1717
|
+
transforms.push(`scale(${from})`);
|
|
1718
|
+
if (!effects.fade && !effects.slide) style.opacity = 0;
|
|
1719
|
+
}
|
|
1720
|
+
if (effects.bounce) {
|
|
1721
|
+
transforms.push("scale(0)");
|
|
1722
|
+
if (!effects.fade && !effects.slide && !effects.scale) style.opacity = 0;
|
|
1723
|
+
}
|
|
1724
|
+
if (transforms.length > 0) {
|
|
1725
|
+
style.transform = transforms.join(" ");
|
|
1726
|
+
} else {
|
|
1727
|
+
style.transform = "none";
|
|
1728
|
+
}
|
|
1729
|
+
if (effects.fade && transforms.length === 0) {
|
|
1730
|
+
style.transform = "none";
|
|
1731
|
+
}
|
|
1732
|
+
return style;
|
|
1733
|
+
}
|
|
1734
|
+
function getMultiEffectVisibleStyle(effects) {
|
|
1735
|
+
const style = {};
|
|
1736
|
+
if (effects.fade) {
|
|
1737
|
+
const config = typeof effects.fade === "object" ? effects.fade : {};
|
|
1738
|
+
style.opacity = config.targetOpacity ?? 1;
|
|
1739
|
+
} else {
|
|
1740
|
+
style.opacity = 1;
|
|
1741
|
+
}
|
|
1742
|
+
if (effects.scale) {
|
|
1743
|
+
const config = typeof effects.scale === "object" ? effects.scale : {};
|
|
1744
|
+
style.transform = `scale(${config.to ?? 1})`;
|
|
1745
|
+
} else {
|
|
1746
|
+
style.transform = "none";
|
|
1747
|
+
}
|
|
1748
|
+
return style;
|
|
1749
|
+
}
|
|
1750
|
+
function getMultiEffectEasing(effects, easing2) {
|
|
1751
|
+
if (easing2) return easing2;
|
|
1752
|
+
if (effects.bounce) return "cubic-bezier(0.34, 1.56, 0.64, 1)";
|
|
1753
|
+
return "ease-out";
|
|
1754
|
+
}
|
|
1669
1755
|
function useUnifiedMotion(options) {
|
|
1670
1756
|
const {
|
|
1671
1757
|
type,
|
|
1758
|
+
effects,
|
|
1672
1759
|
duration = 600,
|
|
1673
1760
|
autoStart = true,
|
|
1674
1761
|
delay = 0,
|
|
@@ -1681,7 +1768,8 @@ function useUnifiedMotion(options) {
|
|
|
1681
1768
|
onStop,
|
|
1682
1769
|
onReset
|
|
1683
1770
|
} = options;
|
|
1684
|
-
const
|
|
1771
|
+
const resolvedType = type ?? "fadeIn";
|
|
1772
|
+
const resolvedEasing = getEasingForType(resolvedType, easing2);
|
|
1685
1773
|
const ref = useRef(null);
|
|
1686
1774
|
const [isVisible, setIsVisible] = useState(false);
|
|
1687
1775
|
const [isAnimating, setIsAnimating] = useState(false);
|
|
@@ -1741,7 +1829,19 @@ function useUnifiedMotion(options) {
|
|
|
1741
1829
|
return () => stop();
|
|
1742
1830
|
}, [stop]);
|
|
1743
1831
|
const style = useMemo(() => {
|
|
1744
|
-
|
|
1832
|
+
if (effects) {
|
|
1833
|
+
const base2 = isVisible ? getMultiEffectVisibleStyle(effects) : getMultiEffectInitialStyle(effects, distance);
|
|
1834
|
+
const resolvedEasingMulti = getMultiEffectEasing(effects, easing2);
|
|
1835
|
+
return {
|
|
1836
|
+
...base2,
|
|
1837
|
+
transition: `all ${duration}ms ${resolvedEasingMulti}`,
|
|
1838
|
+
"--motion-delay": `${delay}ms`,
|
|
1839
|
+
"--motion-duration": `${duration}ms`,
|
|
1840
|
+
"--motion-easing": resolvedEasingMulti,
|
|
1841
|
+
"--motion-progress": `${progress}`
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1844
|
+
const base = isVisible ? getVisibleStyle() : getInitialStyle(resolvedType, distance);
|
|
1745
1845
|
return {
|
|
1746
1846
|
...base,
|
|
1747
1847
|
transition: `all ${duration}ms ${resolvedEasing}`,
|
|
@@ -1750,7 +1850,7 @@ function useUnifiedMotion(options) {
|
|
|
1750
1850
|
"--motion-easing": resolvedEasing,
|
|
1751
1851
|
"--motion-progress": `${progress}`
|
|
1752
1852
|
};
|
|
1753
|
-
}, [isVisible, type, distance, duration, resolvedEasing, delay, progress]);
|
|
1853
|
+
}, [isVisible, type, effects, distance, duration, resolvedEasing, easing2, delay, progress, resolvedType]);
|
|
1754
1854
|
return {
|
|
1755
1855
|
ref,
|
|
1756
1856
|
isVisible,
|
|
@@ -1928,7 +2028,7 @@ function useSlideUp(options = {}) {
|
|
|
1928
2028
|
}, 50);
|
|
1929
2029
|
return () => clearInterval(id);
|
|
1930
2030
|
}, [nodeReady]);
|
|
1931
|
-
const
|
|
2031
|
+
const getInitialTransform2 = useCallback(() => {
|
|
1932
2032
|
switch (direction) {
|
|
1933
2033
|
case "up":
|
|
1934
2034
|
return `translateY(${distance}px)`;
|
|
@@ -2008,7 +2108,7 @@ function useSlideUp(options = {}) {
|
|
|
2008
2108
|
stop();
|
|
2009
2109
|
};
|
|
2010
2110
|
}, [stop]);
|
|
2011
|
-
const initialTransform = useMemo(() =>
|
|
2111
|
+
const initialTransform = useMemo(() => getInitialTransform2(), [getInitialTransform2]);
|
|
2012
2112
|
const finalTransform = useMemo(() => {
|
|
2013
2113
|
return direction === "left" || direction === "right" ? "translateX(0)" : "translateY(0)";
|
|
2014
2114
|
}, [direction]);
|
|
@@ -4188,7 +4288,408 @@ function useGestureMotion(options) {
|
|
|
4188
4288
|
isActive: gestureState.isActive
|
|
4189
4289
|
};
|
|
4190
4290
|
}
|
|
4291
|
+
function useTypewriter(options) {
|
|
4292
|
+
const { text, speed = 50, delay = 0, enabled = true, onComplete } = options;
|
|
4293
|
+
const [index, setIndex] = useState(0);
|
|
4294
|
+
const [started, setStarted] = useState(false);
|
|
4295
|
+
const timerRef = useRef(null);
|
|
4296
|
+
const restart = useCallback(() => {
|
|
4297
|
+
setIndex(0);
|
|
4298
|
+
setStarted(false);
|
|
4299
|
+
}, []);
|
|
4300
|
+
useEffect(() => {
|
|
4301
|
+
if (!enabled) return;
|
|
4302
|
+
const id = setTimeout(() => setStarted(true), delay);
|
|
4303
|
+
return () => clearTimeout(id);
|
|
4304
|
+
}, [enabled, delay]);
|
|
4305
|
+
useEffect(() => {
|
|
4306
|
+
if (!started || !enabled) return;
|
|
4307
|
+
if (index >= text.length) {
|
|
4308
|
+
onComplete?.();
|
|
4309
|
+
return;
|
|
4310
|
+
}
|
|
4311
|
+
timerRef.current = setTimeout(() => {
|
|
4312
|
+
setIndex((prev) => prev + 1);
|
|
4313
|
+
}, speed);
|
|
4314
|
+
return () => {
|
|
4315
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
4316
|
+
};
|
|
4317
|
+
}, [started, enabled, index, text.length, speed, onComplete]);
|
|
4318
|
+
useEffect(() => {
|
|
4319
|
+
setIndex(0);
|
|
4320
|
+
setStarted(false);
|
|
4321
|
+
}, [text]);
|
|
4322
|
+
return {
|
|
4323
|
+
displayText: text.slice(0, index),
|
|
4324
|
+
isTyping: started && index < text.length,
|
|
4325
|
+
progress: text.length > 0 ? index / text.length : 0,
|
|
4326
|
+
restart
|
|
4327
|
+
};
|
|
4328
|
+
}
|
|
4329
|
+
function useCustomCursor(options = {}) {
|
|
4330
|
+
const {
|
|
4331
|
+
enabled = true,
|
|
4332
|
+
size = 32,
|
|
4333
|
+
smoothing = 0.15,
|
|
4334
|
+
hoverScale = 1.5,
|
|
4335
|
+
detectLabels = true
|
|
4336
|
+
} = options;
|
|
4337
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
4338
|
+
const [label, setLabel] = useState(null);
|
|
4339
|
+
const [isHovering, setIsHovering] = useState(false);
|
|
4340
|
+
const targetRef = useRef({ x: 0, y: 0 });
|
|
4341
|
+
const currentRef = useRef({ x: 0, y: 0 });
|
|
4342
|
+
const [pos, setPos] = useState({ x: 0, y: 0 });
|
|
4343
|
+
const rafRef = useRef(null);
|
|
4344
|
+
const animate = useCallback(() => {
|
|
4345
|
+
const dx = targetRef.current.x - currentRef.current.x;
|
|
4346
|
+
const dy = targetRef.current.y - currentRef.current.y;
|
|
4347
|
+
currentRef.current.x += dx * smoothing;
|
|
4348
|
+
currentRef.current.y += dy * smoothing;
|
|
4349
|
+
setPos({ x: currentRef.current.x, y: currentRef.current.y });
|
|
4350
|
+
if (Math.abs(dx) > 0.1 || Math.abs(dy) > 0.1) {
|
|
4351
|
+
rafRef.current = requestAnimationFrame(animate);
|
|
4352
|
+
}
|
|
4353
|
+
}, [smoothing]);
|
|
4354
|
+
useEffect(() => {
|
|
4355
|
+
if (!enabled || typeof window === "undefined") return;
|
|
4356
|
+
const handleMouseMove = (e) => {
|
|
4357
|
+
targetRef.current = { x: e.clientX, y: e.clientY };
|
|
4358
|
+
setIsVisible(true);
|
|
4359
|
+
if (!rafRef.current) {
|
|
4360
|
+
rafRef.current = requestAnimationFrame(animate);
|
|
4361
|
+
}
|
|
4362
|
+
if (detectLabels) {
|
|
4363
|
+
const target = e.target;
|
|
4364
|
+
const cursorEl = target.closest("[data-cursor]");
|
|
4365
|
+
if (cursorEl) {
|
|
4366
|
+
setLabel(cursorEl.dataset.cursor || null);
|
|
4367
|
+
setIsHovering(true);
|
|
4368
|
+
} else {
|
|
4369
|
+
setLabel(null);
|
|
4370
|
+
setIsHovering(false);
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
4373
|
+
};
|
|
4374
|
+
const handleMouseLeave = () => {
|
|
4375
|
+
setIsVisible(false);
|
|
4376
|
+
setLabel(null);
|
|
4377
|
+
setIsHovering(false);
|
|
4378
|
+
};
|
|
4379
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
4380
|
+
document.addEventListener("mouseleave", handleMouseLeave);
|
|
4381
|
+
return () => {
|
|
4382
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
4383
|
+
document.removeEventListener("mouseleave", handleMouseLeave);
|
|
4384
|
+
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
4385
|
+
};
|
|
4386
|
+
}, [enabled, detectLabels, animate]);
|
|
4387
|
+
const scale = isHovering ? hoverScale : 1;
|
|
4388
|
+
const style = useMemo(() => ({
|
|
4389
|
+
"--cursor-x": `${pos.x}px`,
|
|
4390
|
+
"--cursor-y": `${pos.y}px`,
|
|
4391
|
+
"--cursor-size": `${size}px`,
|
|
4392
|
+
"--cursor-scale": `${scale}`,
|
|
4393
|
+
position: "fixed",
|
|
4394
|
+
left: pos.x - size * scale / 2,
|
|
4395
|
+
top: pos.y - size * scale / 2,
|
|
4396
|
+
width: size * scale,
|
|
4397
|
+
height: size * scale,
|
|
4398
|
+
pointerEvents: "none",
|
|
4399
|
+
zIndex: 9999,
|
|
4400
|
+
transition: "width 0.2s, height 0.2s, left 0.05s, top 0.05s"
|
|
4401
|
+
}), [pos.x, pos.y, size, scale]);
|
|
4402
|
+
return { x: pos.x, y: pos.y, label, isHovering, style, isVisible };
|
|
4403
|
+
}
|
|
4404
|
+
function useMagneticCursor(options = {}) {
|
|
4405
|
+
const { strength = 0.3, radius = 100, enabled = true } = options;
|
|
4406
|
+
const ref = useRef(null);
|
|
4407
|
+
const transformRef = useRef({ x: 0, y: 0 });
|
|
4408
|
+
const styleRef = useRef({
|
|
4409
|
+
transition: "transform 0.3s cubic-bezier(0.22, 1, 0.36, 1)",
|
|
4410
|
+
transform: "translate(0px, 0px)"
|
|
4411
|
+
});
|
|
4412
|
+
const onMouseMove = useCallback((e) => {
|
|
4413
|
+
if (!enabled || !ref.current) return;
|
|
4414
|
+
const rect = ref.current.getBoundingClientRect();
|
|
4415
|
+
const centerX = rect.left + rect.width / 2;
|
|
4416
|
+
const centerY = rect.top + rect.height / 2;
|
|
4417
|
+
const dx = e.clientX - centerX;
|
|
4418
|
+
const dy = e.clientY - centerY;
|
|
4419
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
4420
|
+
if (dist < radius) {
|
|
4421
|
+
const pull = (1 - dist / radius) * strength;
|
|
4422
|
+
transformRef.current = { x: dx * pull, y: dy * pull };
|
|
4423
|
+
} else {
|
|
4424
|
+
transformRef.current = { x: 0, y: 0 };
|
|
4425
|
+
}
|
|
4426
|
+
ref.current.style.transform = `translate(${transformRef.current.x}px, ${transformRef.current.y}px)`;
|
|
4427
|
+
}, [enabled, strength, radius]);
|
|
4428
|
+
const onMouseLeave = useCallback(() => {
|
|
4429
|
+
if (!ref.current) return;
|
|
4430
|
+
transformRef.current = { x: 0, y: 0 };
|
|
4431
|
+
ref.current.style.transform = "translate(0px, 0px)";
|
|
4432
|
+
}, []);
|
|
4433
|
+
const handlers = useMemo(() => ({ onMouseMove, onMouseLeave }), [onMouseMove, onMouseLeave]);
|
|
4434
|
+
return { ref, handlers, style: styleRef.current };
|
|
4435
|
+
}
|
|
4436
|
+
function useSmoothScroll(options = {}) {
|
|
4437
|
+
const {
|
|
4438
|
+
enabled = true,
|
|
4439
|
+
lerp = 0.1,
|
|
4440
|
+
wheelMultiplier = 1,
|
|
4441
|
+
touchMultiplier = 2,
|
|
4442
|
+
direction = "vertical",
|
|
4443
|
+
onScroll
|
|
4444
|
+
} = options;
|
|
4445
|
+
const [scroll, setScroll] = useState(0);
|
|
4446
|
+
const [progress, setProgress] = useState(0);
|
|
4447
|
+
const targetRef = useRef(0);
|
|
4448
|
+
const currentRef = useRef(0);
|
|
4449
|
+
const rafRef = useRef(null);
|
|
4450
|
+
const isRunningRef = useRef(false);
|
|
4451
|
+
const touchStartRef = useRef(0);
|
|
4452
|
+
const getMaxScroll = useCallback(() => {
|
|
4453
|
+
if (typeof document === "undefined") return 0;
|
|
4454
|
+
return direction === "vertical" ? document.documentElement.scrollHeight - window.innerHeight : document.documentElement.scrollWidth - window.innerWidth;
|
|
4455
|
+
}, [direction]);
|
|
4456
|
+
const clamp = useCallback((val) => {
|
|
4457
|
+
return Math.max(0, Math.min(val, getMaxScroll()));
|
|
4458
|
+
}, [getMaxScroll]);
|
|
4459
|
+
const animate = useCallback(() => {
|
|
4460
|
+
const dx = targetRef.current - currentRef.current;
|
|
4461
|
+
if (Math.abs(dx) < 0.5) {
|
|
4462
|
+
currentRef.current = targetRef.current;
|
|
4463
|
+
setScroll(currentRef.current);
|
|
4464
|
+
isRunningRef.current = false;
|
|
4465
|
+
return;
|
|
4466
|
+
}
|
|
4467
|
+
currentRef.current += dx * lerp;
|
|
4468
|
+
setScroll(currentRef.current);
|
|
4469
|
+
const max = getMaxScroll();
|
|
4470
|
+
setProgress(max > 0 ? currentRef.current / max : 0);
|
|
4471
|
+
onScroll?.(currentRef.current);
|
|
4472
|
+
if (direction === "vertical") {
|
|
4473
|
+
window.scrollTo(0, currentRef.current);
|
|
4474
|
+
} else {
|
|
4475
|
+
window.scrollTo(currentRef.current, 0);
|
|
4476
|
+
}
|
|
4477
|
+
rafRef.current = requestAnimationFrame(animate);
|
|
4478
|
+
}, [lerp, direction, getMaxScroll, onScroll]);
|
|
4479
|
+
const startAnimation = useCallback(() => {
|
|
4480
|
+
if (isRunningRef.current) return;
|
|
4481
|
+
isRunningRef.current = true;
|
|
4482
|
+
rafRef.current = requestAnimationFrame(animate);
|
|
4483
|
+
}, [animate]);
|
|
4484
|
+
useEffect(() => {
|
|
4485
|
+
if (!enabled || typeof window === "undefined") return;
|
|
4486
|
+
document.documentElement.style.scrollBehavior = "auto";
|
|
4487
|
+
currentRef.current = direction === "vertical" ? window.scrollY : window.scrollX;
|
|
4488
|
+
targetRef.current = currentRef.current;
|
|
4489
|
+
const handleWheel = (e) => {
|
|
4490
|
+
e.preventDefault();
|
|
4491
|
+
const delta = direction === "vertical" ? e.deltaY : e.deltaX;
|
|
4492
|
+
targetRef.current = clamp(targetRef.current + delta * wheelMultiplier);
|
|
4493
|
+
startAnimation();
|
|
4494
|
+
};
|
|
4495
|
+
const handleTouchStart = (e) => {
|
|
4496
|
+
touchStartRef.current = direction === "vertical" ? e.touches[0].clientY : e.touches[0].clientX;
|
|
4497
|
+
};
|
|
4498
|
+
const handleTouchMove = (e) => {
|
|
4499
|
+
const current = direction === "vertical" ? e.touches[0].clientY : e.touches[0].clientX;
|
|
4500
|
+
const delta = (touchStartRef.current - current) * touchMultiplier;
|
|
4501
|
+
touchStartRef.current = current;
|
|
4502
|
+
targetRef.current = clamp(targetRef.current + delta);
|
|
4503
|
+
startAnimation();
|
|
4504
|
+
};
|
|
4505
|
+
window.addEventListener("wheel", handleWheel, { passive: false });
|
|
4506
|
+
window.addEventListener("touchstart", handleTouchStart, { passive: true });
|
|
4507
|
+
window.addEventListener("touchmove", handleTouchMove, { passive: true });
|
|
4508
|
+
return () => {
|
|
4509
|
+
window.removeEventListener("wheel", handleWheel);
|
|
4510
|
+
window.removeEventListener("touchstart", handleTouchStart);
|
|
4511
|
+
window.removeEventListener("touchmove", handleTouchMove);
|
|
4512
|
+
if (rafRef.current) cancelAnimationFrame(rafRef.current);
|
|
4513
|
+
document.documentElement.style.scrollBehavior = "";
|
|
4514
|
+
};
|
|
4515
|
+
}, [enabled, direction, wheelMultiplier, touchMultiplier, clamp, startAnimation]);
|
|
4516
|
+
const scrollTo = useCallback((target, opts) => {
|
|
4517
|
+
const offset = opts?.offset ?? 0;
|
|
4518
|
+
if (typeof target === "number") {
|
|
4519
|
+
targetRef.current = clamp(target + offset);
|
|
4520
|
+
} else {
|
|
4521
|
+
const rect = target.getBoundingClientRect();
|
|
4522
|
+
const pos = direction === "vertical" ? rect.top + currentRef.current + offset : rect.left + currentRef.current + offset;
|
|
4523
|
+
targetRef.current = clamp(pos);
|
|
4524
|
+
}
|
|
4525
|
+
startAnimation();
|
|
4526
|
+
}, [clamp, direction, startAnimation]);
|
|
4527
|
+
const stop = useCallback(() => {
|
|
4528
|
+
if (rafRef.current) {
|
|
4529
|
+
cancelAnimationFrame(rafRef.current);
|
|
4530
|
+
rafRef.current = null;
|
|
4531
|
+
}
|
|
4532
|
+
isRunningRef.current = false;
|
|
4533
|
+
targetRef.current = currentRef.current;
|
|
4534
|
+
}, []);
|
|
4535
|
+
return {
|
|
4536
|
+
scroll,
|
|
4537
|
+
targetScroll: targetRef.current,
|
|
4538
|
+
progress,
|
|
4539
|
+
scrollTo,
|
|
4540
|
+
stop
|
|
4541
|
+
};
|
|
4542
|
+
}
|
|
4543
|
+
function useElementProgress(options = {}) {
|
|
4544
|
+
const { start = 0, end = 1, clamp = true } = options;
|
|
4545
|
+
const ref = useRef(null);
|
|
4546
|
+
const [progress, setProgress] = useState(0);
|
|
4547
|
+
const [isInView, setIsInView] = useState(false);
|
|
4548
|
+
useEffect(() => {
|
|
4549
|
+
const el = ref.current;
|
|
4550
|
+
if (!el || typeof window === "undefined") return;
|
|
4551
|
+
const calculate = () => {
|
|
4552
|
+
const rect = el.getBoundingClientRect();
|
|
4553
|
+
const vh = window.innerHeight;
|
|
4554
|
+
const elementTop = rect.top;
|
|
4555
|
+
const elementBottom = rect.bottom;
|
|
4556
|
+
const trackStart = vh * (1 - start);
|
|
4557
|
+
const trackEnd = vh * end * -1 + vh;
|
|
4558
|
+
const range = trackStart - trackEnd;
|
|
4559
|
+
const raw = range > 0 ? (trackStart - elementTop) / range : 0;
|
|
4560
|
+
const clamped = clamp ? Math.max(0, Math.min(1, raw)) : raw;
|
|
4561
|
+
setProgress(clamped);
|
|
4562
|
+
setIsInView(elementBottom > 0 && elementTop < vh);
|
|
4563
|
+
};
|
|
4564
|
+
calculate();
|
|
4565
|
+
window.addEventListener("scroll", calculate, { passive: true });
|
|
4566
|
+
window.addEventListener("resize", calculate, { passive: true });
|
|
4567
|
+
return () => {
|
|
4568
|
+
window.removeEventListener("scroll", calculate);
|
|
4569
|
+
window.removeEventListener("resize", calculate);
|
|
4570
|
+
};
|
|
4571
|
+
}, [start, end, clamp]);
|
|
4572
|
+
return { ref, progress, isInView };
|
|
4573
|
+
}
|
|
4574
|
+
function Motion({
|
|
4575
|
+
as: Component = "div",
|
|
4576
|
+
type,
|
|
4577
|
+
effects,
|
|
4578
|
+
scroll,
|
|
4579
|
+
delay,
|
|
4580
|
+
duration,
|
|
4581
|
+
children,
|
|
4582
|
+
className,
|
|
4583
|
+
style: userStyle,
|
|
4584
|
+
...rest
|
|
4585
|
+
}) {
|
|
4586
|
+
const scrollOptions = useMemo(() => {
|
|
4587
|
+
if (!scroll) return null;
|
|
4588
|
+
const base = typeof scroll === "object" ? scroll : {};
|
|
4589
|
+
return {
|
|
4590
|
+
...base,
|
|
4591
|
+
...delay != null && { delay },
|
|
4592
|
+
...duration != null && { duration },
|
|
4593
|
+
...type != null && { motionType: type }
|
|
4594
|
+
};
|
|
4595
|
+
}, [scroll, delay, duration, type]);
|
|
4596
|
+
const scrollMotion = useScrollReveal(scrollOptions ?? { delay: 0 });
|
|
4597
|
+
const unifiedMotion = useUnifiedMotion({
|
|
4598
|
+
type: type ?? "fadeIn",
|
|
4599
|
+
effects,
|
|
4600
|
+
delay,
|
|
4601
|
+
duration,
|
|
4602
|
+
autoStart: true
|
|
4603
|
+
});
|
|
4604
|
+
const isScroll = scroll != null && scroll !== false;
|
|
4605
|
+
const motion = isScroll ? scrollMotion : unifiedMotion;
|
|
4606
|
+
const mergedStyle = useMemo(() => {
|
|
4607
|
+
if (!userStyle) return motion.style;
|
|
4608
|
+
return { ...motion.style, ...userStyle };
|
|
4609
|
+
}, [motion.style, userStyle]);
|
|
4610
|
+
return /* @__PURE__ */ jsx(
|
|
4611
|
+
Component,
|
|
4612
|
+
{
|
|
4613
|
+
ref: motion.ref,
|
|
4614
|
+
className,
|
|
4615
|
+
style: mergedStyle,
|
|
4616
|
+
...rest,
|
|
4617
|
+
children
|
|
4618
|
+
}
|
|
4619
|
+
);
|
|
4620
|
+
}
|
|
4621
|
+
function getInitialTransform(motionType) {
|
|
4622
|
+
switch (motionType) {
|
|
4623
|
+
case "slideUp":
|
|
4624
|
+
return "translateY(32px)";
|
|
4625
|
+
case "slideLeft":
|
|
4626
|
+
return "translateX(-32px)";
|
|
4627
|
+
case "slideRight":
|
|
4628
|
+
return "translateX(32px)";
|
|
4629
|
+
case "scaleIn":
|
|
4630
|
+
return "scale(0.95)";
|
|
4631
|
+
case "bounceIn":
|
|
4632
|
+
return "scale(0.75)";
|
|
4633
|
+
case "fadeIn":
|
|
4634
|
+
default:
|
|
4635
|
+
return "none";
|
|
4636
|
+
}
|
|
4637
|
+
}
|
|
4638
|
+
function useStagger(options) {
|
|
4639
|
+
const {
|
|
4640
|
+
count,
|
|
4641
|
+
staggerDelay = 100,
|
|
4642
|
+
baseDelay = 0,
|
|
4643
|
+
duration = 700,
|
|
4644
|
+
motionType = "fadeIn",
|
|
4645
|
+
threshold = 0.1,
|
|
4646
|
+
easing: easing2 = "ease-out"
|
|
4647
|
+
} = options;
|
|
4648
|
+
const containerRef = useRef(null);
|
|
4649
|
+
const [isVisible, setIsVisible] = useState(false);
|
|
4650
|
+
useEffect(() => {
|
|
4651
|
+
if (!containerRef.current) return;
|
|
4652
|
+
const observer = new IntersectionObserver(
|
|
4653
|
+
(entries) => {
|
|
4654
|
+
entries.forEach((entry) => {
|
|
4655
|
+
if (entry.isIntersecting) {
|
|
4656
|
+
setIsVisible(true);
|
|
4657
|
+
observer.disconnect();
|
|
4658
|
+
}
|
|
4659
|
+
});
|
|
4660
|
+
},
|
|
4661
|
+
{ threshold }
|
|
4662
|
+
);
|
|
4663
|
+
observer.observe(containerRef.current);
|
|
4664
|
+
return () => {
|
|
4665
|
+
observer.disconnect();
|
|
4666
|
+
};
|
|
4667
|
+
}, [threshold]);
|
|
4668
|
+
const initialTransform = useMemo(() => getInitialTransform(motionType), [motionType]);
|
|
4669
|
+
const styles = useMemo(() => {
|
|
4670
|
+
return Array.from({ length: count }, (_, i) => {
|
|
4671
|
+
const itemDelay = baseDelay + i * staggerDelay;
|
|
4672
|
+
if (!isVisible) {
|
|
4673
|
+
return {
|
|
4674
|
+
opacity: 0,
|
|
4675
|
+
transform: initialTransform,
|
|
4676
|
+
transition: `opacity ${duration}ms ${easing2} ${itemDelay}ms, transform ${duration}ms ${easing2} ${itemDelay}ms`
|
|
4677
|
+
};
|
|
4678
|
+
}
|
|
4679
|
+
return {
|
|
4680
|
+
opacity: 1,
|
|
4681
|
+
transform: "none",
|
|
4682
|
+
transition: `opacity ${duration}ms ${easing2} ${itemDelay}ms, transform ${duration}ms ${easing2} ${itemDelay}ms`
|
|
4683
|
+
};
|
|
4684
|
+
});
|
|
4685
|
+
}, [count, isVisible, staggerDelay, baseDelay, duration, motionType, easing2, initialTransform]);
|
|
4686
|
+
return {
|
|
4687
|
+
containerRef,
|
|
4688
|
+
styles,
|
|
4689
|
+
isVisible
|
|
4690
|
+
};
|
|
4691
|
+
}
|
|
4191
4692
|
|
|
4192
|
-
export { MOTION_PRESETS, MotionEngine, PAGE_MOTIONS, PerformanceOptimizer, TransitionEffects, applyEasing, easeIn, easeInOut, easeInOutQuad, easeInQuad, easeOut, easeOutQuad, easingPresets, getAvailableEasings, getEasing, getMotionPreset, getPagePreset, getPresetEasing, isEasingFunction, isValidEasing, linear, mergeWithPreset, motionEngine, performanceOptimizer, safeApplyEasing, transitionEffects, useBounceIn, useClickToggle, useFadeIn, useFocusToggle, useGesture, useGestureMotion, useGradient, useHoverMotion, useInView, useMotionState, useMouse, usePageMotions, usePulse, useReducedMotion, useRepeat, useScaleIn, useScrollProgress, useScrollReveal, useSimplePageMotion, useSlideDown, useSlideLeft, useSlideRight, useSlideUp, useSmartMotion, useSpringMotion, useToggleMotion, useUnifiedMotion, useWindowSize };
|
|
4693
|
+
export { MOTION_PRESETS, Motion, MotionEngine, PAGE_MOTIONS, PerformanceOptimizer, TransitionEffects, applyEasing, easeIn, easeInOut, easeInOutQuad, easeInQuad, easeOut, easeOutQuad, easingPresets, getAvailableEasings, getEasing, getMotionPreset, getPagePreset, getPresetEasing, isEasingFunction, isValidEasing, linear, mergeWithPreset, motionEngine, performanceOptimizer, safeApplyEasing, transitionEffects, useBounceIn, useClickToggle, useCustomCursor, useElementProgress, useFadeIn, useFocusToggle, useGesture, useGestureMotion, useGradient, useHoverMotion, useInView, useMagneticCursor, useMotionState, useMouse, usePageMotions, usePulse, useReducedMotion, useRepeat, useScaleIn, useScrollProgress, useScrollReveal, useSimplePageMotion, useSlideDown, useSlideLeft, useSlideRight, useSlideUp, useSmartMotion, useSmoothScroll, useSpringMotion, useStagger, useToggleMotion, useTypewriter, useUnifiedMotion, useWindowSize };
|
|
4193
4694
|
//# sourceMappingURL=index.mjs.map
|
|
4194
4695
|
//# sourceMappingURL=index.mjs.map
|