ugly-app 0.1.621 → 0.1.622
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/version.d.ts +1 -1
- package/dist/cli/version.js +1 -1
- package/dist/client/animation/useScrollAnimation.d.ts +10 -0
- package/dist/client/animation/useScrollAnimation.d.ts.map +1 -1
- package/dist/client/animation/useScrollAnimation.js +64 -59
- package/dist/client/animation/useScrollAnimation.js.map +1 -1
- package/dist/client/components/ScrollAnimatedView.d.ts.map +1 -1
- package/dist/client/components/ScrollAnimatedView.js +3 -2
- package/dist/client/components/ScrollAnimatedView.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/version.ts +1 -1
- package/src/client/animation/useScrollAnimation.ts +72 -74
- package/src/client/components/ScrollAnimatedView.tsx +3 -6
package/dist/cli/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const CLI_VERSION = "0.1.
|
|
1
|
+
export declare const CLI_VERSION = "0.1.622";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cli/version.js
CHANGED
|
@@ -15,7 +15,17 @@ export interface ScrollAnimationStyle {
|
|
|
15
15
|
opacity: number;
|
|
16
16
|
transform: string;
|
|
17
17
|
transition?: string;
|
|
18
|
+
willChange?: string;
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Reveal-on-scroll hook driven entirely by CSS transitions.
|
|
22
|
+
*
|
|
23
|
+
* The element renders ONCE in its hidden state and ONCE in its visible state;
|
|
24
|
+
* the GPU interpolates opacity/transform between them. There is no per-frame
|
|
25
|
+
* React re-render (the previous implementation ran a requestAnimationFrame loop
|
|
26
|
+
* that called forceUpdate() every frame, per instance — with several staggered
|
|
27
|
+
* items on screen that re-render storm caused the visible jank).
|
|
28
|
+
*/
|
|
19
29
|
export declare function useScrollAnimation<T extends HTMLElement = HTMLDivElement>(config?: ScrollAnimationConfig): {
|
|
20
30
|
ref: import("react").RefObject<T | null>;
|
|
21
31
|
style: ScrollAnimationStyle;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScrollAnimation.d.ts","sourceRoot":"","sources":["../../../src/client/animation/useScrollAnimation.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useScrollAnimation.d.ts","sourceRoot":"","sources":["../../../src/client/animation/useScrollAnimation.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,mBAAmB,GAC3B,QAAQ,GACR,SAAS,GACT,WAAW,GACX,WAAW,GACX,YAAY,GACZ,OAAO,GACP,MAAM,CAAC;AAEX,MAAM,WAAW,qBAAqB;IACpC,8BAA8B;IAC9B,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAiCD;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,cAAc,EACvE,MAAM,GAAE,qBAA0B;;;;;EAoDnC;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,IASS,OAAO,MAAM,KAAG,qBAAqB,CAM9C"}
|
|
@@ -1,82 +1,87 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
// Smooth ease-out (no overshoot/bounce — the old springBouncy easing read as
|
|
3
|
+
// "jerky" once many items animated at once). Compositor-friendly.
|
|
4
|
+
const EASE = 'cubic-bezier(0.16, 1, 0.3, 1)';
|
|
5
|
+
function hiddenTransform(animation) {
|
|
6
|
+
switch (animation) {
|
|
7
|
+
case 'slideUp':
|
|
8
|
+
return 'translateY(40px)';
|
|
9
|
+
case 'slideDown':
|
|
10
|
+
return 'translateY(-40px)';
|
|
11
|
+
case 'slideLeft':
|
|
12
|
+
return 'translateX(40px)';
|
|
13
|
+
case 'slideRight':
|
|
14
|
+
return 'translateX(-40px)';
|
|
15
|
+
case 'scale':
|
|
16
|
+
return 'scale(0.92)';
|
|
17
|
+
case 'fadeIn':
|
|
18
|
+
case 'none':
|
|
19
|
+
default:
|
|
20
|
+
return 'none';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function prefersReducedMotion() {
|
|
24
|
+
return (typeof window !== 'undefined' &&
|
|
25
|
+
typeof window.matchMedia === 'function' &&
|
|
26
|
+
window.matchMedia('(prefers-reduced-motion: reduce)').matches);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Reveal-on-scroll hook driven entirely by CSS transitions.
|
|
30
|
+
*
|
|
31
|
+
* The element renders ONCE in its hidden state and ONCE in its visible state;
|
|
32
|
+
* the GPU interpolates opacity/transform between them. There is no per-frame
|
|
33
|
+
* React re-render (the previous implementation ran a requestAnimationFrame loop
|
|
34
|
+
* that called forceUpdate() every frame, per instance — with several staggered
|
|
35
|
+
* items on screen that re-render storm caused the visible jank).
|
|
36
|
+
*/
|
|
3
37
|
export function useScrollAnimation(config = {}) {
|
|
4
|
-
const { animation = 'fadeIn', delay = 0, duration, threshold = 0.2, once = true, } = config;
|
|
38
|
+
const { animation = 'fadeIn', delay = 0, duration = 600, threshold = 0.2, once = true, } = config;
|
|
5
39
|
const ref = useRef(null);
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
useLayoutEffect(() => {
|
|
11
|
-
const element = ref.current;
|
|
12
|
-
if (!element)
|
|
13
|
-
return;
|
|
14
|
-
const rect = element.getBoundingClientRect();
|
|
15
|
-
if (rect.top >= window.innerHeight) {
|
|
16
|
-
animatedValue.set(0);
|
|
17
|
-
setIsVisible(false);
|
|
18
|
-
hasAnimated.current = false;
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
hasAnimated.current = true;
|
|
22
|
-
}
|
|
23
|
-
}, [animatedValue]);
|
|
40
|
+
const reduce = animation === 'none' || prefersReducedMotion();
|
|
41
|
+
// Hidden until revealed (unless there's nothing to animate).
|
|
42
|
+
const [visible, setVisible] = useState(reduce);
|
|
43
|
+
const hasAnimated = useRef(reduce);
|
|
24
44
|
useEffect(() => {
|
|
45
|
+
if (reduce)
|
|
46
|
+
return;
|
|
25
47
|
const element = ref.current;
|
|
26
48
|
if (!element)
|
|
27
49
|
return;
|
|
28
50
|
const observer = new IntersectionObserver((entries) => {
|
|
29
|
-
|
|
51
|
+
for (const entry of entries) {
|
|
30
52
|
if (entry.isIntersecting) {
|
|
31
|
-
if (once && hasAnimated.current)
|
|
32
|
-
return;
|
|
33
53
|
hasAnimated.current = true;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
duration,
|
|
38
|
-
easing: easingFunctions.springBouncy,
|
|
39
|
-
});
|
|
40
|
-
}, delay);
|
|
54
|
+
setVisible(true);
|
|
55
|
+
if (once)
|
|
56
|
+
observer.disconnect();
|
|
41
57
|
}
|
|
42
|
-
else if (!once) {
|
|
43
|
-
|
|
44
|
-
animatedValue.set(0);
|
|
58
|
+
else if (!once && !hasAnimated.current) {
|
|
59
|
+
setVisible(false);
|
|
45
60
|
}
|
|
46
|
-
}
|
|
61
|
+
}
|
|
47
62
|
}, { threshold });
|
|
48
63
|
observer.observe(element);
|
|
49
64
|
return () => observer.disconnect();
|
|
50
|
-
}, [
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
case 'slideRight':
|
|
63
|
-
return { opacity: p, transform: `translateX(${-40 * (1 - p)}px)` };
|
|
64
|
-
case 'scale':
|
|
65
|
-
return { opacity: p, transform: `scale(${0.9 + 0.1 * p})` };
|
|
66
|
-
case 'none':
|
|
67
|
-
default:
|
|
68
|
-
return { opacity: 1, transform: 'none' };
|
|
69
|
-
}
|
|
70
|
-
}, [animation, progress]);
|
|
71
|
-
return { ref, style: getStyle(), isVisible, progress };
|
|
65
|
+
}, [reduce, once, threshold]);
|
|
66
|
+
const transitionDelay = delay > 0 ? ` ${delay}ms` : '';
|
|
67
|
+
const style = {
|
|
68
|
+
opacity: visible ? 1 : 0,
|
|
69
|
+
transform: visible ? 'none' : hiddenTransform(animation),
|
|
70
|
+
transition: reduce
|
|
71
|
+
? undefined
|
|
72
|
+
: `opacity ${duration}ms ${EASE}${transitionDelay}, transform ${duration}ms ${EASE}${transitionDelay}`,
|
|
73
|
+
// GPU-hint only while waiting to animate in; drop it once shown.
|
|
74
|
+
willChange: visible ? undefined : 'opacity, transform',
|
|
75
|
+
};
|
|
76
|
+
return { ref, style, isVisible: visible, progress: visible ? 1 : 0 };
|
|
72
77
|
}
|
|
73
78
|
export function useStaggerAnimation(config) {
|
|
74
79
|
const { baseDelay = 100, startDelay = 0, animation = 'slideUp', duration = 600, threshold = 0.2, } = config;
|
|
75
|
-
return
|
|
80
|
+
return (index) => ({
|
|
76
81
|
animation,
|
|
77
82
|
delay: startDelay + index * baseDelay,
|
|
78
83
|
duration,
|
|
79
84
|
threshold,
|
|
80
|
-
})
|
|
85
|
+
});
|
|
81
86
|
}
|
|
82
87
|
//# sourceMappingURL=useScrollAnimation.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useScrollAnimation.js","sourceRoot":"","sources":["../../../src/client/animation/useScrollAnimation.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"useScrollAnimation.js","sourceRoot":"","sources":["../../../src/client/animation/useScrollAnimation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrollAnimatedView.d.ts","sourceRoot":"","sources":["../../../src/client/components/ScrollAnimatedView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,qBAAqB,EAEtB,MAAM,oCAAoC,CAAC;AAG5C,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,KAAK,EACL,SAAoB,EACpB,KAAS,EACT,QAAQ,EACR,SAAe,EACf,IAAW,GACZ,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"ScrollAnimatedView.d.ts","sourceRoot":"","sources":["../../../src/client/components/ScrollAnimatedView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EACL,qBAAqB,EAEtB,MAAM,oCAAoC,CAAC;AAG5C,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB;IACpE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B;AAED,wBAAgB,kBAAkB,CAAC,EACjC,QAAQ,EACR,KAAK,EACL,SAAoB,EACpB,KAAS,EACT,QAAQ,EACR,SAAe,EACf,IAAW,GACZ,EAAE,uBAAuB,qBAyBzB;AAED,wBAAgB,2BAA2B,CAAC,EAC1C,QAAQ,EACR,SAAqB,EACrB,SAAe,EACf,UAAc,EACd,QAAQ,EACR,SAAe,EACf,KAAK,GACN,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,SAAS,CAAC,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,qBAkBA"}
|
|
@@ -3,7 +3,7 @@ import React from 'react';
|
|
|
3
3
|
import { useScrollAnimation, } from '../animation/useScrollAnimation.js';
|
|
4
4
|
import { View } from './View.js';
|
|
5
5
|
export function ScrollAnimatedView({ children, style, animation = 'fadeIn', delay = 0, duration, threshold = 0.2, once = true, }) {
|
|
6
|
-
const { ref, style: animationStyle
|
|
6
|
+
const { ref, style: animationStyle } = useScrollAnimation({
|
|
7
7
|
animation,
|
|
8
8
|
delay,
|
|
9
9
|
duration,
|
|
@@ -14,7 +14,8 @@ export function ScrollAnimatedView({ children, style, animation = 'fadeIn', dela
|
|
|
14
14
|
...Object(style),
|
|
15
15
|
opacity: animationStyle.opacity,
|
|
16
16
|
transform: animationStyle.transform,
|
|
17
|
-
|
|
17
|
+
transition: animationStyle.transition,
|
|
18
|
+
willChange: animationStyle.willChange,
|
|
18
19
|
width: '100%',
|
|
19
20
|
alignItems: 'center',
|
|
20
21
|
}, children: children }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrollAnimatedView.js","sourceRoot":"","sources":["../../../src/client/components/ScrollAnimatedView.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,kBAAkB,GACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAOjC,MAAM,UAAU,kBAAkB,CAAC,EACjC,QAAQ,EACR,KAAK,EACL,SAAS,GAAG,QAAQ,EACpB,KAAK,GAAG,CAAC,EACT,QAAQ,EACR,SAAS,GAAG,GAAG,EACf,IAAI,GAAG,IAAI,GACa;IACxB,MAAM,
|
|
1
|
+
{"version":3,"file":"ScrollAnimatedView.js","sourceRoot":"","sources":["../../../src/client/components/ScrollAnimatedView.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAEL,kBAAkB,GACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAOjC,MAAM,UAAU,kBAAkB,CAAC,EACjC,QAAQ,EACR,KAAK,EACL,SAAS,GAAG,QAAQ,EACpB,KAAK,GAAG,CAAC,EACT,QAAQ,EACR,SAAS,GAAG,GAAG,EACf,IAAI,GAAG,IAAI,GACa;IACxB,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,kBAAkB,CAAC;QACxD,SAAS;QACT,KAAK;QACL,QAAQ;QACR,SAAS;QACT,IAAI;KACL,CAAC,CAAC;IAEH,OAAO,CACL,KAAC,IAAI,IACH,OAAO,EAAE,GAAG,EACZ,KAAK,EAAE;YACL,GAAG,MAAM,CAAC,KAAK,CAAC;YAChB,OAAO,EAAE,cAAc,CAAC,OAAO;YAC/B,SAAS,EAAE,cAAc,CAAC,SAAS;YACnC,UAAU,EAAE,cAAc,CAAC,UAAU;YACrC,UAAU,EAAE,cAAc,CAAC,UAAU;YACrC,KAAK,EAAE,MAAM;YACb,UAAU,EAAE,QAAQ;SACrB,YAEA,QAAQ,GACJ,CACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,EAC1C,QAAQ,EACR,SAAS,GAAG,SAAS,EACrB,SAAS,GAAG,GAAG,EACf,UAAU,GAAG,CAAC,EACd,QAAQ,EACR,SAAS,GAAG,GAAG,EACf,KAAK,GASN;IACC,MAAM,UAAU,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEpD,OAAO,CACL,KAAC,IAAI,IAAC,KAAK,EAAE,KAAK,YACf,UAAU,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAChC,KAAC,kBAAkB,IAEjB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,UAAU,GAAG,KAAK,GAAG,SAAS,EACrC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,YAEnB,KAAK,IAND,KAAK,CAOS,CACtB,CAAC,GACG,CACR,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ugly-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.622",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"comment:files": "Allowlist what ships to npm. dist = runtime; src = sourcemap targets (dist/*.js.map reference ../../src/); templates = CLI scaffold. Everything else at repo root (.pgdata local Postgres, coverage, assets/icons sources, test/, test-results/) is excluded by omission. The !negations strip the scaffold's installed deps + cruft (templates/node_modules is 200MB+ and must never ship). package.json/README/LICENSE ship automatically.",
|
|
6
6
|
"files": [
|
package/src/cli/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Auto-generated by prebuild — do not edit manually
|
|
2
|
-
export const CLI_VERSION = "0.1.
|
|
2
|
+
export const CLI_VERSION = "0.1.622";
|
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useCallback,
|
|
3
|
-
useEffect,
|
|
4
|
-
useLayoutEffect,
|
|
5
|
-
useRef,
|
|
6
|
-
useState,
|
|
7
|
-
} from 'react';
|
|
8
|
-
import {
|
|
9
|
-
easingFunctions,
|
|
10
|
-
useAnimatedValue,
|
|
11
|
-
useAnimatedValueTracker,
|
|
12
|
-
} from './animatedValue.js';
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
13
2
|
|
|
14
3
|
export type ScrollAnimationType =
|
|
15
4
|
| 'fadeIn'
|
|
@@ -37,90 +26,102 @@ export interface ScrollAnimationStyle {
|
|
|
37
26
|
opacity: number;
|
|
38
27
|
transform: string;
|
|
39
28
|
transition?: string;
|
|
29
|
+
willChange?: string;
|
|
40
30
|
}
|
|
41
31
|
|
|
32
|
+
// Smooth ease-out (no overshoot/bounce — the old springBouncy easing read as
|
|
33
|
+
// "jerky" once many items animated at once). Compositor-friendly.
|
|
34
|
+
const EASE = 'cubic-bezier(0.16, 1, 0.3, 1)';
|
|
35
|
+
|
|
36
|
+
function hiddenTransform(animation: ScrollAnimationType): string {
|
|
37
|
+
switch (animation) {
|
|
38
|
+
case 'slideUp':
|
|
39
|
+
return 'translateY(40px)';
|
|
40
|
+
case 'slideDown':
|
|
41
|
+
return 'translateY(-40px)';
|
|
42
|
+
case 'slideLeft':
|
|
43
|
+
return 'translateX(40px)';
|
|
44
|
+
case 'slideRight':
|
|
45
|
+
return 'translateX(-40px)';
|
|
46
|
+
case 'scale':
|
|
47
|
+
return 'scale(0.92)';
|
|
48
|
+
case 'fadeIn':
|
|
49
|
+
case 'none':
|
|
50
|
+
default:
|
|
51
|
+
return 'none';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function prefersReducedMotion(): boolean {
|
|
56
|
+
return (
|
|
57
|
+
typeof window !== 'undefined' &&
|
|
58
|
+
typeof window.matchMedia === 'function' &&
|
|
59
|
+
window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Reveal-on-scroll hook driven entirely by CSS transitions.
|
|
65
|
+
*
|
|
66
|
+
* The element renders ONCE in its hidden state and ONCE in its visible state;
|
|
67
|
+
* the GPU interpolates opacity/transform between them. There is no per-frame
|
|
68
|
+
* React re-render (the previous implementation ran a requestAnimationFrame loop
|
|
69
|
+
* that called forceUpdate() every frame, per instance — with several staggered
|
|
70
|
+
* items on screen that re-render storm caused the visible jank).
|
|
71
|
+
*/
|
|
42
72
|
export function useScrollAnimation<T extends HTMLElement = HTMLDivElement>(
|
|
43
73
|
config: ScrollAnimationConfig = {},
|
|
44
74
|
) {
|
|
45
75
|
const {
|
|
46
76
|
animation = 'fadeIn',
|
|
47
77
|
delay = 0,
|
|
48
|
-
duration,
|
|
78
|
+
duration = 600,
|
|
49
79
|
threshold = 0.2,
|
|
50
80
|
once = true,
|
|
51
81
|
} = config;
|
|
52
82
|
|
|
53
83
|
const ref = useRef<T>(null);
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
useLayoutEffect(() => {
|
|
60
|
-
const element = ref.current;
|
|
61
|
-
if (!element) return;
|
|
62
|
-
const rect = element.getBoundingClientRect();
|
|
63
|
-
if (rect.top >= window.innerHeight) {
|
|
64
|
-
animatedValue.set(0);
|
|
65
|
-
setIsVisible(false);
|
|
66
|
-
hasAnimated.current = false;
|
|
67
|
-
} else {
|
|
68
|
-
hasAnimated.current = true;
|
|
69
|
-
}
|
|
70
|
-
}, [animatedValue]);
|
|
84
|
+
const reduce = animation === 'none' || prefersReducedMotion();
|
|
85
|
+
// Hidden until revealed (unless there's nothing to animate).
|
|
86
|
+
const [visible, setVisible] = useState(reduce);
|
|
87
|
+
const hasAnimated = useRef(reduce);
|
|
71
88
|
|
|
72
89
|
useEffect(() => {
|
|
90
|
+
if (reduce) return;
|
|
73
91
|
const element = ref.current;
|
|
74
92
|
if (!element) return;
|
|
75
93
|
|
|
76
94
|
const observer = new IntersectionObserver(
|
|
77
95
|
(entries) => {
|
|
78
|
-
|
|
96
|
+
for (const entry of entries) {
|
|
79
97
|
if (entry.isIntersecting) {
|
|
80
|
-
if (once && hasAnimated.current) return;
|
|
81
98
|
hasAnimated.current = true;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
easing: easingFunctions.springBouncy,
|
|
87
|
-
});
|
|
88
|
-
}, delay);
|
|
89
|
-
} else if (!once) {
|
|
90
|
-
setIsVisible(false);
|
|
91
|
-
animatedValue.set(0);
|
|
99
|
+
setVisible(true);
|
|
100
|
+
if (once) observer.disconnect();
|
|
101
|
+
} else if (!once && !hasAnimated.current) {
|
|
102
|
+
setVisible(false);
|
|
92
103
|
}
|
|
93
|
-
}
|
|
104
|
+
}
|
|
94
105
|
},
|
|
95
106
|
{ threshold },
|
|
96
107
|
);
|
|
97
108
|
|
|
98
109
|
observer.observe(element);
|
|
99
110
|
return () => observer.disconnect();
|
|
100
|
-
}, [
|
|
111
|
+
}, [reduce, once, threshold]);
|
|
101
112
|
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return { opacity: p, transform: `translateX(${40 * (1 - p)}px)` };
|
|
113
|
-
case 'slideRight':
|
|
114
|
-
return { opacity: p, transform: `translateX(${-40 * (1 - p)}px)` };
|
|
115
|
-
case 'scale':
|
|
116
|
-
return { opacity: p, transform: `scale(${0.9 + 0.1 * p})` };
|
|
117
|
-
case 'none':
|
|
118
|
-
default:
|
|
119
|
-
return { opacity: 1, transform: 'none' };
|
|
120
|
-
}
|
|
121
|
-
}, [animation, progress]);
|
|
113
|
+
const transitionDelay = delay > 0 ? ` ${delay}ms` : '';
|
|
114
|
+
const style: ScrollAnimationStyle = {
|
|
115
|
+
opacity: visible ? 1 : 0,
|
|
116
|
+
transform: visible ? 'none' : hiddenTransform(animation),
|
|
117
|
+
transition: reduce
|
|
118
|
+
? undefined
|
|
119
|
+
: `opacity ${duration}ms ${EASE}${transitionDelay}, transform ${duration}ms ${EASE}${transitionDelay}`,
|
|
120
|
+
// GPU-hint only while waiting to animate in; drop it once shown.
|
|
121
|
+
willChange: visible ? undefined : 'opacity, transform',
|
|
122
|
+
};
|
|
122
123
|
|
|
123
|
-
return { ref, style
|
|
124
|
+
return { ref, style, isVisible: visible, progress: visible ? 1 : 0 };
|
|
124
125
|
}
|
|
125
126
|
|
|
126
127
|
export function useStaggerAnimation(config: {
|
|
@@ -138,13 +139,10 @@ export function useStaggerAnimation(config: {
|
|
|
138
139
|
threshold = 0.2,
|
|
139
140
|
} = config;
|
|
140
141
|
|
|
141
|
-
return
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}),
|
|
148
|
-
[animation, baseDelay, duration, startDelay, threshold],
|
|
149
|
-
);
|
|
142
|
+
return (index: number): ScrollAnimationConfig => ({
|
|
143
|
+
animation,
|
|
144
|
+
delay: startDelay + index * baseDelay,
|
|
145
|
+
duration,
|
|
146
|
+
threshold,
|
|
147
|
+
});
|
|
150
148
|
}
|
|
@@ -19,11 +19,7 @@ export function ScrollAnimatedView({
|
|
|
19
19
|
threshold = 0.2,
|
|
20
20
|
once = true,
|
|
21
21
|
}: ScrollAnimatedViewProps) {
|
|
22
|
-
const {
|
|
23
|
-
ref,
|
|
24
|
-
style: animationStyle,
|
|
25
|
-
isVisible,
|
|
26
|
-
} = useScrollAnimation({
|
|
22
|
+
const { ref, style: animationStyle } = useScrollAnimation({
|
|
27
23
|
animation,
|
|
28
24
|
delay,
|
|
29
25
|
duration,
|
|
@@ -38,7 +34,8 @@ export function ScrollAnimatedView({
|
|
|
38
34
|
...Object(style),
|
|
39
35
|
opacity: animationStyle.opacity,
|
|
40
36
|
transform: animationStyle.transform,
|
|
41
|
-
|
|
37
|
+
transition: animationStyle.transition,
|
|
38
|
+
willChange: animationStyle.willChange,
|
|
42
39
|
width: '100%',
|
|
43
40
|
alignItems: 'center',
|
|
44
41
|
}}
|