@stianlarsen/react-light-beam 2.1.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +419 -129
- package/dist/index.d.mts +111 -1
- package/dist/index.d.ts +111 -1
- package/dist/index.js +326 -103
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +317 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
package/dist/index.js
CHANGED
|
@@ -1,65 +1,249 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var gsap3 = require('gsap');
|
|
5
5
|
var ScrollTrigger = require('gsap/ScrollTrigger');
|
|
6
|
-
var react = require('react');
|
|
6
|
+
var react = require('@gsap/react');
|
|
7
|
+
var react$1 = require('react');
|
|
7
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
9
|
|
|
9
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
11
|
|
|
11
|
-
var
|
|
12
|
+
var gsap3__default = /*#__PURE__*/_interopDefault(gsap3);
|
|
12
13
|
|
|
13
|
-
var useIsomorphicLayoutEffect = typeof document !== "undefined" ? react.useLayoutEffect : react.useEffect;
|
|
14
|
-
var isConfig = (value) => value && !Array.isArray(value) && typeof value === "object";
|
|
15
|
-
var emptyArray = [];
|
|
16
|
-
var defaultConfig = {};
|
|
17
|
-
var _gsap = gsap2__default.default;
|
|
18
|
-
var useGSAP = (callback, dependencies = emptyArray) => {
|
|
19
|
-
let config = defaultConfig;
|
|
20
|
-
if (isConfig(callback)) {
|
|
21
|
-
config = callback;
|
|
22
|
-
callback = null;
|
|
23
|
-
dependencies = "dependencies" in config ? config.dependencies : emptyArray;
|
|
24
|
-
} else if (isConfig(dependencies)) {
|
|
25
|
-
config = dependencies;
|
|
26
|
-
dependencies = "dependencies" in config ? config.dependencies : emptyArray;
|
|
27
|
-
}
|
|
28
|
-
callback && typeof callback !== "function" && console.warn("First parameter must be a function or config object");
|
|
29
|
-
const { scope, revertOnUpdate } = config, mounted = react.useRef(false), context = react.useRef(_gsap.context(() => {
|
|
30
|
-
}, scope)), contextSafe = react.useRef((func) => context.current.add(null, func)), deferCleanup = dependencies && dependencies.length && !revertOnUpdate;
|
|
31
|
-
deferCleanup && useIsomorphicLayoutEffect(() => {
|
|
32
|
-
mounted.current = true;
|
|
33
|
-
return () => context.current.revert();
|
|
34
|
-
}, emptyArray);
|
|
35
|
-
useIsomorphicLayoutEffect(() => {
|
|
36
|
-
callback && context.current.add(callback, scope);
|
|
37
|
-
if (!deferCleanup || !mounted.current) {
|
|
38
|
-
return () => context.current.revert();
|
|
39
|
-
}
|
|
40
|
-
}, dependencies);
|
|
41
|
-
return { context: context.current, contextSafe: contextSafe.current };
|
|
42
|
-
};
|
|
43
|
-
useGSAP.register = (core) => {
|
|
44
|
-
_gsap = core;
|
|
45
|
-
};
|
|
46
|
-
useGSAP.headless = true;
|
|
47
14
|
var useIsDarkmode = () => {
|
|
48
|
-
const [isDarkmode, setIsDarkmodeActive] = react.useState(false);
|
|
49
|
-
react.useEffect(() => {
|
|
15
|
+
const [isDarkmode, setIsDarkmodeActive] = react$1.useState(false);
|
|
16
|
+
react$1.useEffect(() => {
|
|
50
17
|
const matchMedia = window.matchMedia("(prefers-color-scheme: dark)");
|
|
51
18
|
const handleChange = () => {
|
|
19
|
+
console.log("Darkmode match?", matchMedia.matches);
|
|
52
20
|
setIsDarkmodeActive(matchMedia.matches);
|
|
53
21
|
};
|
|
54
22
|
setIsDarkmodeActive(matchMedia.matches);
|
|
55
23
|
matchMedia.addEventListener("change", handleChange);
|
|
24
|
+
handleChange();
|
|
56
25
|
return () => {
|
|
57
26
|
matchMedia.removeEventListener("change", handleChange);
|
|
58
27
|
};
|
|
59
28
|
}, []);
|
|
60
29
|
return { isDarkmode };
|
|
61
30
|
};
|
|
62
|
-
|
|
31
|
+
var DustParticles = ({ config, beamColor }) => {
|
|
32
|
+
const {
|
|
33
|
+
enabled = false,
|
|
34
|
+
count = 30,
|
|
35
|
+
speed = 1,
|
|
36
|
+
sizeRange = [1, 3],
|
|
37
|
+
opacityRange = [0.2, 0.6],
|
|
38
|
+
color
|
|
39
|
+
} = config;
|
|
40
|
+
const particles = react$1.useMemo(() => {
|
|
41
|
+
if (!enabled) return [];
|
|
42
|
+
return Array.from({ length: count }, (_, i) => {
|
|
43
|
+
const x = Math.random() * 100;
|
|
44
|
+
const y = Math.random() * 100;
|
|
45
|
+
const size = sizeRange[0] + Math.random() * (sizeRange[1] - sizeRange[0]);
|
|
46
|
+
const opacity = opacityRange[0] + Math.random() * (opacityRange[1] - opacityRange[0]);
|
|
47
|
+
const duration = (3 + Math.random() * 4) / speed;
|
|
48
|
+
const delay = Math.random() * duration;
|
|
49
|
+
return {
|
|
50
|
+
id: `dust-${i}`,
|
|
51
|
+
x,
|
|
52
|
+
y,
|
|
53
|
+
size,
|
|
54
|
+
opacity,
|
|
55
|
+
duration,
|
|
56
|
+
delay
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
}, [enabled, count, sizeRange, opacityRange, speed]);
|
|
60
|
+
react.useGSAP(
|
|
61
|
+
() => {
|
|
62
|
+
if (!enabled || particles.length === 0) return;
|
|
63
|
+
const timelines = [];
|
|
64
|
+
particles.forEach((particle) => {
|
|
65
|
+
const element = document.getElementById(particle.id);
|
|
66
|
+
if (!element) return;
|
|
67
|
+
const tl = gsap3__default.default.timeline({
|
|
68
|
+
repeat: -1,
|
|
69
|
+
yoyo: true,
|
|
70
|
+
delay: particle.delay
|
|
71
|
+
});
|
|
72
|
+
tl.to(element, {
|
|
73
|
+
y: `-=${20 + Math.random() * 30}`,
|
|
74
|
+
// Float upward 20-50px
|
|
75
|
+
x: `+=${Math.random() * 20 - 10}`,
|
|
76
|
+
// Slight horizontal drift ±10px
|
|
77
|
+
opacity: particle.opacity * 0.5,
|
|
78
|
+
// Fade slightly
|
|
79
|
+
duration: particle.duration,
|
|
80
|
+
ease: "sine.inOut"
|
|
81
|
+
});
|
|
82
|
+
timelines.push(tl);
|
|
83
|
+
});
|
|
84
|
+
return () => {
|
|
85
|
+
timelines.forEach((tl) => tl.kill());
|
|
86
|
+
};
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
dependencies: [particles, enabled]
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
if (!enabled) return null;
|
|
93
|
+
const particleColor = color || beamColor;
|
|
94
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: particles.map((particle) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
95
|
+
"div",
|
|
96
|
+
{
|
|
97
|
+
id: particle.id,
|
|
98
|
+
style: {
|
|
99
|
+
position: "absolute",
|
|
100
|
+
left: `${particle.x}%`,
|
|
101
|
+
top: `${particle.y}%`,
|
|
102
|
+
width: `${particle.size}px`,
|
|
103
|
+
height: `${particle.size}px`,
|
|
104
|
+
borderRadius: "50%",
|
|
105
|
+
backgroundColor: particleColor,
|
|
106
|
+
opacity: particle.opacity,
|
|
107
|
+
pointerEvents: "none",
|
|
108
|
+
willChange: "transform, opacity"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
particle.id
|
|
112
|
+
)) });
|
|
113
|
+
};
|
|
114
|
+
var MistEffect = ({ config, beamColor }) => {
|
|
115
|
+
const {
|
|
116
|
+
enabled = false,
|
|
117
|
+
intensity = 0.3,
|
|
118
|
+
speed = 1,
|
|
119
|
+
layers = 2
|
|
120
|
+
} = config;
|
|
121
|
+
const mistLayers = react$1.useMemo(() => {
|
|
122
|
+
if (!enabled) return [];
|
|
123
|
+
return Array.from({ length: layers }, (_, i) => {
|
|
124
|
+
const layerOpacity = intensity * 0.6 / (i + 1);
|
|
125
|
+
const duration = (8 + i * 3) / speed;
|
|
126
|
+
const delay = i * 1.5 / speed;
|
|
127
|
+
const scale = 1 + i * 0.2;
|
|
128
|
+
return {
|
|
129
|
+
id: `mist-layer-${i}`,
|
|
130
|
+
opacity: layerOpacity,
|
|
131
|
+
duration,
|
|
132
|
+
delay,
|
|
133
|
+
scale
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
}, [enabled, intensity, speed, layers]);
|
|
137
|
+
react.useGSAP(
|
|
138
|
+
() => {
|
|
139
|
+
if (!enabled || mistLayers.length === 0) return;
|
|
140
|
+
const timelines = [];
|
|
141
|
+
mistLayers.forEach((layer) => {
|
|
142
|
+
const element = document.getElementById(layer.id);
|
|
143
|
+
if (!element) return;
|
|
144
|
+
const tl = gsap3__default.default.timeline({
|
|
145
|
+
repeat: -1,
|
|
146
|
+
yoyo: false
|
|
147
|
+
});
|
|
148
|
+
tl.fromTo(
|
|
149
|
+
element,
|
|
150
|
+
{
|
|
151
|
+
x: "-100%",
|
|
152
|
+
opacity: 0
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
x: "100%",
|
|
156
|
+
opacity: layer.opacity,
|
|
157
|
+
duration: layer.duration,
|
|
158
|
+
ease: "none",
|
|
159
|
+
delay: layer.delay
|
|
160
|
+
}
|
|
161
|
+
).to(element, {
|
|
162
|
+
opacity: 0,
|
|
163
|
+
duration: layer.duration * 0.2,
|
|
164
|
+
ease: "power1.in"
|
|
165
|
+
});
|
|
166
|
+
timelines.push(tl);
|
|
167
|
+
});
|
|
168
|
+
return () => {
|
|
169
|
+
timelines.forEach((tl) => tl.kill());
|
|
170
|
+
};
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
dependencies: [mistLayers, enabled]
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
if (!enabled) return null;
|
|
177
|
+
const mistColor = beamColor.replace(/[\d.]+\)$/g, `${intensity})`);
|
|
178
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: mistLayers.map((layer) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
179
|
+
"div",
|
|
180
|
+
{
|
|
181
|
+
id: layer.id,
|
|
182
|
+
style: {
|
|
183
|
+
position: "absolute",
|
|
184
|
+
top: 0,
|
|
185
|
+
left: 0,
|
|
186
|
+
width: "100%",
|
|
187
|
+
height: "100%",
|
|
188
|
+
background: `radial-gradient(ellipse 120% 80% at 50% 20%, ${mistColor}, transparent 70%)`,
|
|
189
|
+
opacity: 0,
|
|
190
|
+
pointerEvents: "none",
|
|
191
|
+
willChange: "transform, opacity",
|
|
192
|
+
transform: `scale(${layer.scale})`,
|
|
193
|
+
filter: "blur(40px)"
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
layer.id
|
|
197
|
+
)) });
|
|
198
|
+
};
|
|
199
|
+
var PulseEffect = ({ config, containerRef }) => {
|
|
200
|
+
const {
|
|
201
|
+
enabled = false,
|
|
202
|
+
duration = 2,
|
|
203
|
+
intensity = 0.2,
|
|
204
|
+
easing = "sine.inOut"
|
|
205
|
+
} = config;
|
|
206
|
+
react.useGSAP(
|
|
207
|
+
() => {
|
|
208
|
+
if (!enabled || !containerRef.current) return;
|
|
209
|
+
const element = containerRef.current;
|
|
210
|
+
const timeline = gsap3__default.default.timeline({
|
|
211
|
+
repeat: -1,
|
|
212
|
+
// Infinite loop
|
|
213
|
+
yoyo: true
|
|
214
|
+
// Reverse on each iteration
|
|
215
|
+
});
|
|
216
|
+
const maxMultiplier = Math.min(2, 1 + intensity);
|
|
217
|
+
timeline.fromTo(
|
|
218
|
+
element,
|
|
219
|
+
{
|
|
220
|
+
"--pulse-multiplier": 1
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"--pulse-multiplier": maxMultiplier,
|
|
224
|
+
duration,
|
|
225
|
+
ease: easing
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
const updateOpacity = () => {
|
|
229
|
+
const baseOpacity = getComputedStyle(element).getPropertyValue("--base-opacity") || "1";
|
|
230
|
+
const pulseMultiplier = getComputedStyle(element).getPropertyValue("--pulse-multiplier") || "1";
|
|
231
|
+
element.style.opacity = `calc(${baseOpacity} * ${pulseMultiplier})`;
|
|
232
|
+
};
|
|
233
|
+
const ticker = gsap3__default.default.ticker.add(updateOpacity);
|
|
234
|
+
return () => {
|
|
235
|
+
timeline.kill();
|
|
236
|
+
gsap3__default.default.ticker.remove(ticker);
|
|
237
|
+
};
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
dependencies: [enabled, duration, intensity, easing],
|
|
241
|
+
scope: containerRef
|
|
242
|
+
}
|
|
243
|
+
);
|
|
244
|
+
return null;
|
|
245
|
+
};
|
|
246
|
+
gsap3__default.default.registerPlugin(ScrollTrigger.ScrollTrigger, react.useGSAP);
|
|
63
247
|
var defaultStyles = {
|
|
64
248
|
height: "var(--react-light-beam-height, 500px)",
|
|
65
249
|
width: "var(--react-light-beam-width, 100vw)",
|
|
@@ -84,92 +268,135 @@ var LightBeam = ({
|
|
|
84
268
|
colorDarkmode = "rgba(255, 255, 255, 0.5)",
|
|
85
269
|
maskLightByProgress = false,
|
|
86
270
|
fullWidth = 1,
|
|
87
|
-
// Default to full width
|
|
271
|
+
// Default to full width range
|
|
88
272
|
invert = false,
|
|
89
273
|
id = void 0,
|
|
90
274
|
onLoaded = void 0,
|
|
91
275
|
scrollElement,
|
|
92
|
-
disableDefaultStyles = false
|
|
276
|
+
disableDefaultStyles = false,
|
|
277
|
+
scrollStart = "top bottom",
|
|
278
|
+
scrollEnd = "top top",
|
|
279
|
+
dustParticles = { enabled: false },
|
|
280
|
+
mist = { enabled: false },
|
|
281
|
+
pulse = { enabled: false }
|
|
93
282
|
}) => {
|
|
94
|
-
const elementRef = react.useRef(null);
|
|
283
|
+
const elementRef = react$1.useRef(null);
|
|
95
284
|
const { isDarkmode } = useIsDarkmode();
|
|
96
285
|
const chosenColor = isDarkmode ? colorDarkmode : colorLightmode;
|
|
97
|
-
const colorRef = react.useRef(chosenColor);
|
|
98
|
-
const invertRef = react.useRef(invert);
|
|
99
|
-
const maskByProgressRef = react.useRef(maskLightByProgress);
|
|
100
|
-
react.
|
|
286
|
+
const colorRef = react$1.useRef(chosenColor);
|
|
287
|
+
const invertRef = react$1.useRef(invert);
|
|
288
|
+
const maskByProgressRef = react$1.useRef(maskLightByProgress);
|
|
289
|
+
const scrollTriggerRef = react$1.useRef(null);
|
|
290
|
+
react$1.useEffect(() => {
|
|
101
291
|
colorRef.current = chosenColor;
|
|
292
|
+
if (elementRef.current) {
|
|
293
|
+
elementRef.current.style.setProperty("--beam-color", chosenColor);
|
|
294
|
+
}
|
|
295
|
+
}, [chosenColor, colorLightmode, colorDarkmode]);
|
|
296
|
+
react$1.useEffect(() => {
|
|
297
|
+
const prevInvert = invertRef.current;
|
|
102
298
|
invertRef.current = invert;
|
|
299
|
+
if (prevInvert !== invert && scrollTriggerRef.current && elementRef.current) {
|
|
300
|
+
const st = scrollTriggerRef.current;
|
|
301
|
+
elementRef.current;
|
|
302
|
+
st.refresh();
|
|
303
|
+
}
|
|
304
|
+
}, [invert]);
|
|
305
|
+
react$1.useEffect(() => {
|
|
306
|
+
const prevMaskByProgress = maskByProgressRef.current;
|
|
103
307
|
maskByProgressRef.current = maskLightByProgress;
|
|
104
|
-
|
|
105
|
-
|
|
308
|
+
if (prevMaskByProgress !== maskLightByProgress && elementRef.current) {
|
|
309
|
+
const element = elementRef.current;
|
|
310
|
+
if (maskLightByProgress) {
|
|
311
|
+
element.style.setProperty("--beam-mask-stop", "50%");
|
|
312
|
+
element.style.maskImage = `linear-gradient(to bottom, var(--beam-color) 0%, transparent var(--beam-mask-stop))`;
|
|
313
|
+
element.style.webkitMaskImage = `linear-gradient(to bottom, var(--beam-color) 0%, transparent var(--beam-mask-stop))`;
|
|
314
|
+
} else {
|
|
315
|
+
element.style.maskImage = `linear-gradient(to bottom, var(--beam-color) 25%, transparent 95%)`;
|
|
316
|
+
element.style.webkitMaskImage = `linear-gradient(to bottom, var(--beam-color) 25%, transparent 95%)`;
|
|
317
|
+
}
|
|
318
|
+
if (scrollTriggerRef.current) {
|
|
319
|
+
scrollTriggerRef.current.refresh();
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}, [maskLightByProgress]);
|
|
323
|
+
react$1.useEffect(() => {
|
|
106
324
|
onLoaded && onLoaded();
|
|
107
325
|
}, []);
|
|
108
|
-
useGSAP(
|
|
326
|
+
react.useGSAP(
|
|
109
327
|
() => {
|
|
110
328
|
const element = elementRef.current;
|
|
111
329
|
if (!element || typeof window === "undefined") return;
|
|
112
330
|
const opacityMin = 0.839322;
|
|
113
331
|
const opacityRange = 0.160678;
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
const rightPos = 10 + progress * 90;
|
|
117
|
-
const leftSize = 150 - progress * 50;
|
|
118
|
-
return `conic-gradient(from 90deg at ${leftPos}% 0%, ${color}, transparent 180deg) 0% 0% / 50% ${leftSize}% no-repeat, conic-gradient(from 270deg at ${rightPos}% 0%, transparent 180deg, ${color}) 100% 0% / 50% 100% no-repeat`;
|
|
332
|
+
const updateColorVar = (color) => {
|
|
333
|
+
element.style.setProperty("--beam-color", color);
|
|
119
334
|
};
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
335
|
+
const initGradientStructure = (color) => {
|
|
336
|
+
updateColorVar(color);
|
|
337
|
+
const baseGradient = `conic-gradient(from 90deg at var(--beam-left-pos) 0%, var(--beam-color), transparent 180deg) 0% 0% / 50% var(--beam-left-size) no-repeat, conic-gradient(from 270deg at var(--beam-right-pos) 0%, transparent 180deg, var(--beam-color)) 100% 0% / 50% 100% no-repeat`;
|
|
338
|
+
element.style.background = baseGradient;
|
|
339
|
+
if (maskByProgressRef.current) {
|
|
340
|
+
element.style.maskImage = `linear-gradient(to bottom, var(--beam-color) 0%, transparent var(--beam-mask-stop))`;
|
|
341
|
+
element.style.webkitMaskImage = `linear-gradient(to bottom, var(--beam-color) 0%, transparent var(--beam-mask-stop))`;
|
|
342
|
+
} else {
|
|
343
|
+
element.style.maskImage = `linear-gradient(to bottom, var(--beam-color) 25%, transparent 95%)`;
|
|
344
|
+
element.style.webkitMaskImage = `linear-gradient(to bottom, var(--beam-color) 25%, transparent 95%)`;
|
|
123
345
|
}
|
|
124
|
-
const stopPoint = 50 + progress * 45;
|
|
125
|
-
return `linear-gradient(to bottom, ${color} 0%, transparent ${stopPoint}%)`;
|
|
126
346
|
};
|
|
127
347
|
const adjustedFullWidth = 1 - fullWidth;
|
|
128
348
|
const calculateProgress = (rawProgress) => {
|
|
129
349
|
const normalizedPosition = Math.max(
|
|
130
350
|
adjustedFullWidth,
|
|
131
|
-
//
|
|
351
|
+
// Floor value (1 - fullWidth)
|
|
132
352
|
Math.min(1, 1 - rawProgress)
|
|
133
|
-
//
|
|
353
|
+
// Inverted GSAP progress
|
|
134
354
|
);
|
|
135
355
|
return invertRef.current ? normalizedPosition : 1 - normalizedPosition;
|
|
136
356
|
};
|
|
137
357
|
const scroller = scrollElement ? scrollElement : void 0;
|
|
358
|
+
const applyProgressState = (progress) => {
|
|
359
|
+
const leftPos = 90 - progress * 90;
|
|
360
|
+
const rightPos = 10 + progress * 90;
|
|
361
|
+
const leftSize = 150 - progress * 50;
|
|
362
|
+
const baseOpacity = opacityMin + opacityRange * progress;
|
|
363
|
+
const maskStop = maskByProgressRef.current ? 50 + progress * 45 : void 0;
|
|
364
|
+
const cssProps = {
|
|
365
|
+
"--beam-left-pos": `${leftPos}%`,
|
|
366
|
+
"--beam-right-pos": `${rightPos}%`,
|
|
367
|
+
"--beam-left-size": `${leftSize}%`,
|
|
368
|
+
"--base-opacity": baseOpacity
|
|
369
|
+
};
|
|
370
|
+
if (maskStop !== void 0) {
|
|
371
|
+
cssProps["--beam-mask-stop"] = `${maskStop}%`;
|
|
372
|
+
}
|
|
373
|
+
if (!pulse.enabled) {
|
|
374
|
+
cssProps.opacity = baseOpacity;
|
|
375
|
+
}
|
|
376
|
+
gsap3__default.default.set(element, cssProps);
|
|
377
|
+
};
|
|
378
|
+
initGradientStructure(colorRef.current);
|
|
138
379
|
const st = ScrollTrigger.ScrollTrigger.create({
|
|
139
380
|
trigger: element,
|
|
140
|
-
start:
|
|
141
|
-
//
|
|
142
|
-
end:
|
|
143
|
-
//
|
|
381
|
+
start: scrollStart,
|
|
382
|
+
// When to start the animation
|
|
383
|
+
end: scrollEnd,
|
|
384
|
+
// When to end the animation
|
|
144
385
|
scroller,
|
|
145
|
-
scrub:
|
|
146
|
-
//
|
|
386
|
+
scrub: 0.15,
|
|
387
|
+
// Fast catch-up (300ms) for responsive scroll without jitter
|
|
147
388
|
onUpdate: (self) => {
|
|
148
389
|
const progress = calculateProgress(self.progress);
|
|
149
|
-
|
|
150
|
-
background: interpolateBackground(progress, colorRef.current),
|
|
151
|
-
opacity: opacityMin + opacityRange * progress,
|
|
152
|
-
maskImage: interpolateMask(progress, colorRef.current),
|
|
153
|
-
webkitMaskImage: interpolateMask(progress, colorRef.current)
|
|
154
|
-
});
|
|
390
|
+
applyProgressState(progress);
|
|
155
391
|
},
|
|
156
392
|
onRefresh: (self) => {
|
|
157
393
|
const progress = calculateProgress(self.progress);
|
|
158
|
-
|
|
159
|
-
background: interpolateBackground(progress, colorRef.current),
|
|
160
|
-
opacity: opacityMin + opacityRange * progress,
|
|
161
|
-
maskImage: interpolateMask(progress, colorRef.current),
|
|
162
|
-
webkitMaskImage: interpolateMask(progress, colorRef.current)
|
|
163
|
-
});
|
|
394
|
+
applyProgressState(progress);
|
|
164
395
|
}
|
|
165
396
|
});
|
|
397
|
+
scrollTriggerRef.current = st;
|
|
166
398
|
const initialProgress = calculateProgress(st.progress);
|
|
167
|
-
|
|
168
|
-
background: interpolateBackground(initialProgress, colorRef.current),
|
|
169
|
-
opacity: opacityMin + opacityRange * initialProgress,
|
|
170
|
-
maskImage: interpolateMask(initialProgress, colorRef.current),
|
|
171
|
-
webkitMaskImage: interpolateMask(initialProgress, colorRef.current)
|
|
172
|
-
});
|
|
399
|
+
applyProgressState(initialProgress);
|
|
173
400
|
const refreshTimeout = setTimeout(() => {
|
|
174
401
|
ScrollTrigger.ScrollTrigger.refresh();
|
|
175
402
|
}, 100);
|
|
@@ -185,9 +412,13 @@ var LightBeam = ({
|
|
|
185
412
|
// Only include values that affect ScrollTrigger's position/range calculations
|
|
186
413
|
dependencies: [
|
|
187
414
|
fullWidth,
|
|
188
|
-
// Affects
|
|
189
|
-
scrollElement
|
|
415
|
+
// Affects progress range calculation
|
|
416
|
+
scrollElement,
|
|
190
417
|
// Affects which element to watch
|
|
418
|
+
scrollStart,
|
|
419
|
+
// Affects when animation starts
|
|
420
|
+
scrollEnd
|
|
421
|
+
// Affects when animation ends
|
|
191
422
|
],
|
|
192
423
|
scope: elementRef
|
|
193
424
|
}
|
|
@@ -205,29 +436,21 @@ var LightBeam = ({
|
|
|
205
436
|
...style
|
|
206
437
|
// User styles override everything
|
|
207
438
|
};
|
|
208
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
439
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
209
440
|
"div",
|
|
210
441
|
{
|
|
211
442
|
ref: elementRef,
|
|
212
443
|
className: combinedClassName,
|
|
213
444
|
style: finalStyles,
|
|
214
|
-
...id ? { id } : {}
|
|
445
|
+
...id ? { id } : {},
|
|
446
|
+
children: [
|
|
447
|
+
dustParticles.enabled && /* @__PURE__ */ jsxRuntime.jsx(DustParticles, { config: dustParticles, beamColor: chosenColor }),
|
|
448
|
+
mist.enabled && /* @__PURE__ */ jsxRuntime.jsx(MistEffect, { config: mist, beamColor: chosenColor }),
|
|
449
|
+
pulse.enabled && /* @__PURE__ */ jsxRuntime.jsx(PulseEffect, { config: pulse, containerRef: elementRef })
|
|
450
|
+
]
|
|
215
451
|
}
|
|
216
452
|
);
|
|
217
453
|
};
|
|
218
|
-
/*! Bundled license information:
|
|
219
|
-
|
|
220
|
-
@gsap/react/src/index.js:
|
|
221
|
-
(*!
|
|
222
|
-
* @gsap/react 2.1.2
|
|
223
|
-
* https://gsap.com
|
|
224
|
-
*
|
|
225
|
-
* Copyright 2008-2025, GreenSock. All rights reserved.
|
|
226
|
-
* Subject to the terms at https://gsap.com/standard-license or for
|
|
227
|
-
* Club GSAP members, the agreement issued with that membership.
|
|
228
|
-
* @author: Jack Doyle, jack@greensock.com
|
|
229
|
-
*)
|
|
230
|
-
*/
|
|
231
454
|
|
|
232
455
|
exports.LightBeam = LightBeam;
|
|
233
456
|
//# sourceMappingURL=index.js.map
|