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