@stianlarsen/react-light-beam 1.2.0 → 1.3.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/dist/index.js +39 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +39 -21
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24,9 +24,12 @@ var defaultStyles = {
|
|
|
24
24
|
height: "var(--react-light-beam-height, 500px)",
|
|
25
25
|
width: "var(--react-light-beam-width, 100vw)",
|
|
26
26
|
transition: "var(--react-light-beam-transition, all 0.25s ease)",
|
|
27
|
-
willChange: "
|
|
27
|
+
willChange: "background, opacity",
|
|
28
|
+
// Specific properties for better performance
|
|
28
29
|
userSelect: "none",
|
|
29
30
|
pointerEvents: "none",
|
|
31
|
+
contain: "layout style paint",
|
|
32
|
+
// CSS containment for better performance
|
|
30
33
|
WebkitTransition: "var(--react-light-beam-transition, all 0.25s ease)",
|
|
31
34
|
WebkitUserSelect: "none",
|
|
32
35
|
MozUserSelect: "none"
|
|
@@ -54,27 +57,40 @@ var LightBeam = ({
|
|
|
54
57
|
onLoaded && onLoaded();
|
|
55
58
|
}, []);
|
|
56
59
|
react.useEffect(() => {
|
|
57
|
-
if (typeof window
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
if (typeof window === "undefined") return;
|
|
61
|
+
let cachedWindowHeight = window.innerHeight;
|
|
62
|
+
const adjustedFullWidth = 1 - fullWidth;
|
|
63
|
+
const opacityMin = 0.839322;
|
|
64
|
+
const opacityRange = 1 - opacityMin;
|
|
65
|
+
let lastProgress = -1;
|
|
66
|
+
const handleScroll = () => {
|
|
67
|
+
if (!elementRef.current) return;
|
|
68
|
+
const rect = elementRef.current.getBoundingClientRect();
|
|
69
|
+
const normalizedPosition = Math.max(
|
|
70
|
+
adjustedFullWidth,
|
|
71
|
+
Math.min(1, rect.top / cachedWindowHeight)
|
|
72
|
+
);
|
|
73
|
+
const progress = invert ? normalizedPosition : 1 - normalizedPosition;
|
|
74
|
+
if (Math.abs(progress - lastProgress) > 1e-3) {
|
|
75
|
+
lastProgress = progress;
|
|
76
|
+
inViewProgress.set(progress);
|
|
77
|
+
opacity.set(opacityMin + opacityRange * progress);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const handleResize = () => {
|
|
81
|
+
cachedWindowHeight = window.innerHeight;
|
|
72
82
|
handleScroll();
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
83
|
+
};
|
|
84
|
+
const handleScrollThrottled = throttle(handleScroll);
|
|
85
|
+
const handleResizeThrottled = throttle(handleResize);
|
|
86
|
+
const target = scrollElement || document.body || document.documentElement;
|
|
87
|
+
target.addEventListener("scroll", handleScrollThrottled, { passive: true });
|
|
88
|
+
window.addEventListener("resize", handleResizeThrottled, { passive: true });
|
|
89
|
+
handleScroll();
|
|
90
|
+
return () => {
|
|
91
|
+
target.removeEventListener("scroll", handleScrollThrottled);
|
|
92
|
+
window.removeEventListener("resize", handleResizeThrottled);
|
|
93
|
+
};
|
|
78
94
|
}, [inViewProgress, opacity, scrollElement, fullWidth, invert]);
|
|
79
95
|
const backgroundPosition = framerMotion.useTransform(
|
|
80
96
|
inViewProgress,
|
|
@@ -101,6 +117,8 @@ var LightBeam = ({
|
|
|
101
117
|
maskImage,
|
|
102
118
|
WebkitMaskImage: maskImage,
|
|
103
119
|
willChange: "background, opacity",
|
|
120
|
+
contain: "layout style paint",
|
|
121
|
+
// CSS containment for better performance
|
|
104
122
|
...style
|
|
105
123
|
// User styles override
|
|
106
124
|
} : {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useDarkmode.tsx","../src/index.tsx"],"names":["useState","useEffect","useRef","useMotionValue","useTransform","jsx","motion"],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\nimport { useEffect, useState } from \"react\";\n\nexport const useIsDarkmode = () => {\n const [isDarkmode, setIsDarkmodeActive] = useState(false);\n\n useEffect(() => {\n const matchMedia = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\n const handleChange = () => {\n setIsDarkmodeActive(matchMedia.matches);\n };\n\n // Set the initial value\n setIsDarkmodeActive(matchMedia.matches);\n\n // Listen for changes\n matchMedia.addEventListener(\"change\", handleChange);\n\n // Cleanup listener on unmount\n return () => {\n matchMedia.removeEventListener(\"change\", handleChange);\n };\n }, []);\n\n return { isDarkmode };\n};\n","\"use client\";\nimport {motion, useMotionValue, useTransform} from \"framer-motion\";\nimport React, {useEffect, useRef} from \"react\";\nimport {LightBeamProps} from \"../types/types\";\nimport {useIsDarkmode} from \"./hooks/useDarkmode\";\n\n// Default inline styles using CSS variables for easy customization\n// Users can override via className by setting CSS variables\nconst defaultStyles: React.CSSProperties = {\n height: \"var(--react-light-beam-height, 500px)\",\n width: \"var(--react-light-beam-width, 100vw)\",\n transition: \"var(--react-light-beam-transition, all 0.25s ease)\",\n willChange: \"all\",\n userSelect: \"none\",\n pointerEvents: \"none\",\n WebkitTransition: \"var(--react-light-beam-transition, all 0.25s ease)\",\n WebkitUserSelect: \"none\",\n MozUserSelect: \"none\",\n};\n\nexport const LightBeam = ({\n className,\n style,\n colorLightmode = \"rgba(0,0,0, 0.5)\",\n colorDarkmode = \"rgba(255, 255, 255, 0.5)\",\n maskLightByProgress = false,\n fullWidth = 1.0, // Default to full width\n invert = false,\n id = undefined,\n onLoaded = undefined,\n scrollElement,\n disableDefaultStyles = false,\n}: LightBeamProps) => {\n const elementRef = useRef<HTMLDivElement>(null);\n const inViewProgress = useMotionValue(0);\n const opacity = useMotionValue(0.839322);\n const { isDarkmode } = useIsDarkmode();\n const chosenColor = isDarkmode ? colorDarkmode : colorLightmode;\n\n useEffect(() => {\n onLoaded && onLoaded();\n }, []);\n\n useEffect(() => {\n if (typeof window !== \"undefined\") {\n const handleScroll = () => {\n if (elementRef.current) {\n const rect = elementRef.current.getBoundingClientRect();\n const windowHeight = window.innerHeight;\n\n // Invert the fullWidth value: 1 becomes 0, and 0 becomes 1\n const adjustedFullWidth = 1 - fullWidth;\n\n // Calculate progress\n const progress = invert\n ? 0 +\n Math.max(adjustedFullWidth, Math.min(1, rect.top / windowHeight))\n : 1 -\n Math.max(adjustedFullWidth, Math.min(1, rect.top / windowHeight));\n\n // Update motion values\n inViewProgress.set(progress);\n opacity.set(0.839322 + (1 - 0.839322) * progress);\n }\n };\n\n const handleScrollThrottled = throttle(handleScroll); // Approx 60fps\n\n // Default to document.body (works in modern React/Next.js setups)\n // window doesn't fire scroll events in many modern setups!\n const target = scrollElement || document.body || document.documentElement;\n\n target.addEventListener(\"scroll\", handleScrollThrottled);\n window.addEventListener(\"resize\", handleScrollThrottled);\n\n // Initial call to handleScroll to set initial state\n handleScroll();\n\n return () => {\n target.removeEventListener(\"scroll\", handleScrollThrottled);\n window.removeEventListener(\"resize\", handleScrollThrottled);\n };\n }\n }, [inViewProgress, opacity, scrollElement, fullWidth, invert]);\n\n const backgroundPosition = useTransform(\n inViewProgress,\n [0, 1],\n [\n `conic-gradient(from 90deg at 90% 0%, ${chosenColor}, transparent 180deg) 0% 0% / 50% 150% no-repeat, conic-gradient(from 270deg at 10% 0%, transparent 180deg, ${chosenColor}) 100% 0% / 50% 100% no-repeat`,\n `conic-gradient(from 90deg at 0% 0%, ${chosenColor}, transparent 180deg) 0% 0% / 50% 100% no-repeat, conic-gradient(from 270deg at 100% 0%, transparent 180deg, ${chosenColor}) 100% 0% / 50% 100% no-repeat`,\n ]\n );\n const maskImageOpacity = useTransform(\n inViewProgress,\n [0, 1],\n [\n `linear-gradient(to bottom, ${chosenColor} 0%, transparent 50%)`,\n `linear-gradient(to bottom, ${chosenColor} 0%, transparent 95%)`,\n ]\n );\n\n const maskImage = maskLightByProgress\n ? maskImageOpacity\n : `linear-gradient(to bottom, ${chosenColor} 25%, transparent 95%)`;\n\n const combinedClassName = `react-light-beam ${className || \"\"}`.trim();\n\n // CRITICAL: MotionValues must be passed directly to motion.div style prop\n // Don't spread them into plain objects or reactivity breaks!\n const finalStyles = disableDefaultStyles\n ? {\n // No default styles, only motion values and user styles\n background: backgroundPosition,\n opacity: opacity,\n maskImage: maskImage,\n WebkitMaskImage: maskImage,\n willChange: \"background, opacity\",\n ...style, // User styles override\n }\n : {\n // Merge default styles with motion values\n ...defaultStyles,\n background: backgroundPosition, // MotionValue (overrides default)\n opacity: opacity, // MotionValue (overrides default)\n maskImage: maskImage, // MotionValue or string\n WebkitMaskImage: maskImage,\n willChange: \"background, opacity\",\n ...style, // User styles override everything\n };\n\n const motionProps: any = {\n style: finalStyles,\n ref: elementRef,\n className: combinedClassName,\n ...(id ? { id } : {}),\n };\n\n return <motion.div {...motionProps} />;\n};\n\nconst throttle = (func: Function) => {\n let ticking = false;\n return function (this: any, ...args: any[]) {\n if (!ticking) {\n requestAnimationFrame(() => {\n func.apply(this, args);\n ticking = false;\n });\n ticking = true;\n }\n };\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useDarkmode.tsx","../src/index.tsx"],"names":["useState","useEffect","useRef","useMotionValue","useTransform","jsx","motion"],"mappings":"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","file":"index.js","sourcesContent":["\"use client\";\nimport { useEffect, useState } from \"react\";\n\nexport const useIsDarkmode = () => {\n const [isDarkmode, setIsDarkmodeActive] = useState(false);\n\n useEffect(() => {\n const matchMedia = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\n const handleChange = () => {\n setIsDarkmodeActive(matchMedia.matches);\n };\n\n // Set the initial value\n setIsDarkmodeActive(matchMedia.matches);\n\n // Listen for changes\n matchMedia.addEventListener(\"change\", handleChange);\n\n // Cleanup listener on unmount\n return () => {\n matchMedia.removeEventListener(\"change\", handleChange);\n };\n }, []);\n\n return { isDarkmode };\n};\n","\"use client\";\nimport {motion, useMotionValue, useTransform} from \"framer-motion\";\nimport React, {useEffect, useRef} from \"react\";\nimport {LightBeamProps} from \"../types/types\";\nimport {useIsDarkmode} from \"./hooks/useDarkmode\";\n\n// Default inline styles using CSS variables for easy customization\n// Users can override via className by setting CSS variables\nconst defaultStyles: React.CSSProperties = {\n height: \"var(--react-light-beam-height, 500px)\",\n width: \"var(--react-light-beam-width, 100vw)\",\n transition: \"var(--react-light-beam-transition, all 0.25s ease)\",\n willChange: \"background, opacity\", // Specific properties for better performance\n userSelect: \"none\",\n pointerEvents: \"none\",\n contain: \"layout style paint\", // CSS containment for better performance\n WebkitTransition: \"var(--react-light-beam-transition, all 0.25s ease)\",\n WebkitUserSelect: \"none\",\n MozUserSelect: \"none\",\n};\n\nexport const LightBeam = ({\n className,\n style,\n colorLightmode = \"rgba(0,0,0, 0.5)\",\n colorDarkmode = \"rgba(255, 255, 255, 0.5)\",\n maskLightByProgress = false,\n fullWidth = 1.0, // Default to full width\n invert = false,\n id = undefined,\n onLoaded = undefined,\n scrollElement,\n disableDefaultStyles = false,\n }: LightBeamProps) => {\n const elementRef = useRef<HTMLDivElement>(null);\n const inViewProgress = useMotionValue(0);\n const opacity = useMotionValue(0.839322);\n const {isDarkmode} = useIsDarkmode();\n const chosenColor = isDarkmode ? colorDarkmode : colorLightmode;\n\n useEffect(() => {\n onLoaded && onLoaded();\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return\n\n // Cache values that don't change during scroll (MAJOR OPTIMIZATION)\n let cachedWindowHeight = window.innerHeight;\n const adjustedFullWidth = 1 - fullWidth; // Only calculate once\n const opacityMin = 0.839322;\n const opacityRange = 1 - opacityMin; // Pre-calculate: 0.160678\n let lastProgress = -1;\n\n const handleScroll = () => {\n if (!elementRef.current) return;\n\n // OPTIMIZATION: Only call getBoundingClientRect (expensive!)\n const rect = elementRef.current.getBoundingClientRect();\n\n // Calculate normalized position (0-1 range)\n const normalizedPosition = Math.max(\n adjustedFullWidth,\n Math.min(1, rect.top / cachedWindowHeight)\n );\n\n // Calculate progress (only once, not twice like before!)\n const progress = invert ? normalizedPosition : 1 - normalizedPosition;\n\n // Only update if change is significant (avoid micro-updates)\n if (Math.abs(progress - lastProgress) > 0.001) {\n lastProgress = progress;\n // Batch updates together\n inViewProgress.set(progress);\n opacity.set(opacityMin + opacityRange * progress);\n }\n };\n\n const handleResize = () => {\n cachedWindowHeight = window.innerHeight; // Update cache on resize\n handleScroll(); // Recalculate immediately\n };\n\n const handleScrollThrottled = throttle(handleScroll);\n const handleResizeThrottled = throttle(handleResize);\n\n // Default to document.body (works in modern React/Next.js setups)\n const target = scrollElement || document.body || document.documentElement;\n\n // Passive listeners improve scroll performance significantly\n target.addEventListener(\"scroll\", handleScrollThrottled, {passive: true});\n window.addEventListener(\"resize\", handleResizeThrottled, {passive: true});\n\n // Initial call to set state\n handleScroll();\n\n return () => {\n target.removeEventListener(\"scroll\", handleScrollThrottled);\n window.removeEventListener(\"resize\", handleResizeThrottled);\n };\n }, [inViewProgress, opacity, scrollElement, fullWidth, invert]);\n\n const backgroundPosition = useTransform(\n inViewProgress,\n [0, 1],\n [\n `conic-gradient(from 90deg at 90% 0%, ${chosenColor}, transparent 180deg) 0% 0% / 50% 150% no-repeat, conic-gradient(from 270deg at 10% 0%, transparent 180deg, ${chosenColor}) 100% 0% / 50% 100% no-repeat`,\n `conic-gradient(from 90deg at 0% 0%, ${chosenColor}, transparent 180deg) 0% 0% / 50% 100% no-repeat, conic-gradient(from 270deg at 100% 0%, transparent 180deg, ${chosenColor}) 100% 0% / 50% 100% no-repeat`,\n ]\n );\n const maskImageOpacity = useTransform(\n inViewProgress,\n [0, 1],\n [\n `linear-gradient(to bottom, ${chosenColor} 0%, transparent 50%)`,\n `linear-gradient(to bottom, ${chosenColor} 0%, transparent 95%)`,\n ]\n );\n\n const maskImage = maskLightByProgress\n ? maskImageOpacity\n : `linear-gradient(to bottom, ${chosenColor} 25%, transparent 95%)`;\n\n const combinedClassName = `react-light-beam ${className || \"\"}`.trim();\n\n // CRITICAL: MotionValues must be passed directly to motion.div style prop\n // Don't spread them into plain objects or reactivity breaks!\n const finalStyles = disableDefaultStyles\n ? {\n // No default styles, only motion values and user styles\n background: backgroundPosition,\n opacity: opacity,\n maskImage: maskImage,\n WebkitMaskImage: maskImage,\n willChange: \"background, opacity\",\n contain: \"layout style paint\", // CSS containment for better performance\n ...style, // User styles override\n }\n : {\n // Merge default styles with motion values\n ...defaultStyles,\n background: backgroundPosition, // MotionValue (overrides default)\n opacity: opacity, // MotionValue (overrides default)\n maskImage: maskImage, // MotionValue or string\n WebkitMaskImage: maskImage,\n willChange: \"background, opacity\",\n ...style, // User styles override everything\n };\n\n const motionProps: any = {\n style: finalStyles,\n ref: elementRef,\n className: combinedClassName,\n ...(id ? {id} : {}),\n };\n\n return <motion.div {...motionProps} />;\n};\n\nconst throttle = (func: Function) => {\n let ticking = false;\n return function (this: any, ...args: any[]) {\n if (!ticking) {\n requestAnimationFrame(() => {\n func.apply(this, args);\n ticking = false;\n });\n ticking = true;\n }\n };\n};\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -22,9 +22,12 @@ var defaultStyles = {
|
|
|
22
22
|
height: "var(--react-light-beam-height, 500px)",
|
|
23
23
|
width: "var(--react-light-beam-width, 100vw)",
|
|
24
24
|
transition: "var(--react-light-beam-transition, all 0.25s ease)",
|
|
25
|
-
willChange: "
|
|
25
|
+
willChange: "background, opacity",
|
|
26
|
+
// Specific properties for better performance
|
|
26
27
|
userSelect: "none",
|
|
27
28
|
pointerEvents: "none",
|
|
29
|
+
contain: "layout style paint",
|
|
30
|
+
// CSS containment for better performance
|
|
28
31
|
WebkitTransition: "var(--react-light-beam-transition, all 0.25s ease)",
|
|
29
32
|
WebkitUserSelect: "none",
|
|
30
33
|
MozUserSelect: "none"
|
|
@@ -52,27 +55,40 @@ var LightBeam = ({
|
|
|
52
55
|
onLoaded && onLoaded();
|
|
53
56
|
}, []);
|
|
54
57
|
useEffect(() => {
|
|
55
|
-
if (typeof window
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
if (typeof window === "undefined") return;
|
|
59
|
+
let cachedWindowHeight = window.innerHeight;
|
|
60
|
+
const adjustedFullWidth = 1 - fullWidth;
|
|
61
|
+
const opacityMin = 0.839322;
|
|
62
|
+
const opacityRange = 1 - opacityMin;
|
|
63
|
+
let lastProgress = -1;
|
|
64
|
+
const handleScroll = () => {
|
|
65
|
+
if (!elementRef.current) return;
|
|
66
|
+
const rect = elementRef.current.getBoundingClientRect();
|
|
67
|
+
const normalizedPosition = Math.max(
|
|
68
|
+
adjustedFullWidth,
|
|
69
|
+
Math.min(1, rect.top / cachedWindowHeight)
|
|
70
|
+
);
|
|
71
|
+
const progress = invert ? normalizedPosition : 1 - normalizedPosition;
|
|
72
|
+
if (Math.abs(progress - lastProgress) > 1e-3) {
|
|
73
|
+
lastProgress = progress;
|
|
74
|
+
inViewProgress.set(progress);
|
|
75
|
+
opacity.set(opacityMin + opacityRange * progress);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const handleResize = () => {
|
|
79
|
+
cachedWindowHeight = window.innerHeight;
|
|
70
80
|
handleScroll();
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
81
|
+
};
|
|
82
|
+
const handleScrollThrottled = throttle(handleScroll);
|
|
83
|
+
const handleResizeThrottled = throttle(handleResize);
|
|
84
|
+
const target = scrollElement || document.body || document.documentElement;
|
|
85
|
+
target.addEventListener("scroll", handleScrollThrottled, { passive: true });
|
|
86
|
+
window.addEventListener("resize", handleResizeThrottled, { passive: true });
|
|
87
|
+
handleScroll();
|
|
88
|
+
return () => {
|
|
89
|
+
target.removeEventListener("scroll", handleScrollThrottled);
|
|
90
|
+
window.removeEventListener("resize", handleResizeThrottled);
|
|
91
|
+
};
|
|
76
92
|
}, [inViewProgress, opacity, scrollElement, fullWidth, invert]);
|
|
77
93
|
const backgroundPosition = useTransform(
|
|
78
94
|
inViewProgress,
|
|
@@ -99,6 +115,8 @@ var LightBeam = ({
|
|
|
99
115
|
maskImage,
|
|
100
116
|
WebkitMaskImage: maskImage,
|
|
101
117
|
willChange: "background, opacity",
|
|
118
|
+
contain: "layout style paint",
|
|
119
|
+
// CSS containment for better performance
|
|
102
120
|
...style
|
|
103
121
|
// User styles override
|
|
104
122
|
} : {
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useDarkmode.tsx","../src/index.tsx"],"names":["useEffect"],"mappings":"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","file":"index.mjs","sourcesContent":["\"use client\";\nimport { useEffect, useState } from \"react\";\n\nexport const useIsDarkmode = () => {\n const [isDarkmode, setIsDarkmodeActive] = useState(false);\n\n useEffect(() => {\n const matchMedia = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\n const handleChange = () => {\n setIsDarkmodeActive(matchMedia.matches);\n };\n\n // Set the initial value\n setIsDarkmodeActive(matchMedia.matches);\n\n // Listen for changes\n matchMedia.addEventListener(\"change\", handleChange);\n\n // Cleanup listener on unmount\n return () => {\n matchMedia.removeEventListener(\"change\", handleChange);\n };\n }, []);\n\n return { isDarkmode };\n};\n","\"use client\";\nimport {motion, useMotionValue, useTransform} from \"framer-motion\";\nimport React, {useEffect, useRef} from \"react\";\nimport {LightBeamProps} from \"../types/types\";\nimport {useIsDarkmode} from \"./hooks/useDarkmode\";\n\n// Default inline styles using CSS variables for easy customization\n// Users can override via className by setting CSS variables\nconst defaultStyles: React.CSSProperties = {\n height: \"var(--react-light-beam-height, 500px)\",\n width: \"var(--react-light-beam-width, 100vw)\",\n transition: \"var(--react-light-beam-transition, all 0.25s ease)\",\n willChange: \"all\",\n userSelect: \"none\",\n pointerEvents: \"none\",\n WebkitTransition: \"var(--react-light-beam-transition, all 0.25s ease)\",\n WebkitUserSelect: \"none\",\n MozUserSelect: \"none\",\n};\n\nexport const LightBeam = ({\n className,\n style,\n colorLightmode = \"rgba(0,0,0, 0.5)\",\n colorDarkmode = \"rgba(255, 255, 255, 0.5)\",\n maskLightByProgress = false,\n fullWidth = 1.0, // Default to full width\n invert = false,\n id = undefined,\n onLoaded = undefined,\n scrollElement,\n disableDefaultStyles = false,\n}: LightBeamProps) => {\n const elementRef = useRef<HTMLDivElement>(null);\n const inViewProgress = useMotionValue(0);\n const opacity = useMotionValue(0.839322);\n const { isDarkmode } = useIsDarkmode();\n const chosenColor = isDarkmode ? colorDarkmode : colorLightmode;\n\n useEffect(() => {\n onLoaded && onLoaded();\n }, []);\n\n useEffect(() => {\n if (typeof window !== \"undefined\") {\n const handleScroll = () => {\n if (elementRef.current) {\n const rect = elementRef.current.getBoundingClientRect();\n const windowHeight = window.innerHeight;\n\n // Invert the fullWidth value: 1 becomes 0, and 0 becomes 1\n const adjustedFullWidth = 1 - fullWidth;\n\n // Calculate progress\n const progress = invert\n ? 0 +\n Math.max(adjustedFullWidth, Math.min(1, rect.top / windowHeight))\n : 1 -\n Math.max(adjustedFullWidth, Math.min(1, rect.top / windowHeight));\n\n // Update motion values\n inViewProgress.set(progress);\n opacity.set(0.839322 + (1 - 0.839322) * progress);\n }\n };\n\n const handleScrollThrottled = throttle(handleScroll); // Approx 60fps\n\n // Default to document.body (works in modern React/Next.js setups)\n // window doesn't fire scroll events in many modern setups!\n const target = scrollElement || document.body || document.documentElement;\n\n target.addEventListener(\"scroll\", handleScrollThrottled);\n window.addEventListener(\"resize\", handleScrollThrottled);\n\n // Initial call to handleScroll to set initial state\n handleScroll();\n\n return () => {\n target.removeEventListener(\"scroll\", handleScrollThrottled);\n window.removeEventListener(\"resize\", handleScrollThrottled);\n };\n }\n }, [inViewProgress, opacity, scrollElement, fullWidth, invert]);\n\n const backgroundPosition = useTransform(\n inViewProgress,\n [0, 1],\n [\n `conic-gradient(from 90deg at 90% 0%, ${chosenColor}, transparent 180deg) 0% 0% / 50% 150% no-repeat, conic-gradient(from 270deg at 10% 0%, transparent 180deg, ${chosenColor}) 100% 0% / 50% 100% no-repeat`,\n `conic-gradient(from 90deg at 0% 0%, ${chosenColor}, transparent 180deg) 0% 0% / 50% 100% no-repeat, conic-gradient(from 270deg at 100% 0%, transparent 180deg, ${chosenColor}) 100% 0% / 50% 100% no-repeat`,\n ]\n );\n const maskImageOpacity = useTransform(\n inViewProgress,\n [0, 1],\n [\n `linear-gradient(to bottom, ${chosenColor} 0%, transparent 50%)`,\n `linear-gradient(to bottom, ${chosenColor} 0%, transparent 95%)`,\n ]\n );\n\n const maskImage = maskLightByProgress\n ? maskImageOpacity\n : `linear-gradient(to bottom, ${chosenColor} 25%, transparent 95%)`;\n\n const combinedClassName = `react-light-beam ${className || \"\"}`.trim();\n\n // CRITICAL: MotionValues must be passed directly to motion.div style prop\n // Don't spread them into plain objects or reactivity breaks!\n const finalStyles = disableDefaultStyles\n ? {\n // No default styles, only motion values and user styles\n background: backgroundPosition,\n opacity: opacity,\n maskImage: maskImage,\n WebkitMaskImage: maskImage,\n willChange: \"background, opacity\",\n ...style, // User styles override\n }\n : {\n // Merge default styles with motion values\n ...defaultStyles,\n background: backgroundPosition, // MotionValue (overrides default)\n opacity: opacity, // MotionValue (overrides default)\n maskImage: maskImage, // MotionValue or string\n WebkitMaskImage: maskImage,\n willChange: \"background, opacity\",\n ...style, // User styles override everything\n };\n\n const motionProps: any = {\n style: finalStyles,\n ref: elementRef,\n className: combinedClassName,\n ...(id ? { id } : {}),\n };\n\n return <motion.div {...motionProps} />;\n};\n\nconst throttle = (func: Function) => {\n let ticking = false;\n return function (this: any, ...args: any[]) {\n if (!ticking) {\n requestAnimationFrame(() => {\n func.apply(this, args);\n ticking = false;\n });\n ticking = true;\n }\n };\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useDarkmode.tsx","../src/index.tsx"],"names":["useEffect"],"mappings":"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","file":"index.mjs","sourcesContent":["\"use client\";\nimport { useEffect, useState } from \"react\";\n\nexport const useIsDarkmode = () => {\n const [isDarkmode, setIsDarkmodeActive] = useState(false);\n\n useEffect(() => {\n const matchMedia = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\n const handleChange = () => {\n setIsDarkmodeActive(matchMedia.matches);\n };\n\n // Set the initial value\n setIsDarkmodeActive(matchMedia.matches);\n\n // Listen for changes\n matchMedia.addEventListener(\"change\", handleChange);\n\n // Cleanup listener on unmount\n return () => {\n matchMedia.removeEventListener(\"change\", handleChange);\n };\n }, []);\n\n return { isDarkmode };\n};\n","\"use client\";\nimport {motion, useMotionValue, useTransform} from \"framer-motion\";\nimport React, {useEffect, useRef} from \"react\";\nimport {LightBeamProps} from \"../types/types\";\nimport {useIsDarkmode} from \"./hooks/useDarkmode\";\n\n// Default inline styles using CSS variables for easy customization\n// Users can override via className by setting CSS variables\nconst defaultStyles: React.CSSProperties = {\n height: \"var(--react-light-beam-height, 500px)\",\n width: \"var(--react-light-beam-width, 100vw)\",\n transition: \"var(--react-light-beam-transition, all 0.25s ease)\",\n willChange: \"background, opacity\", // Specific properties for better performance\n userSelect: \"none\",\n pointerEvents: \"none\",\n contain: \"layout style paint\", // CSS containment for better performance\n WebkitTransition: \"var(--react-light-beam-transition, all 0.25s ease)\",\n WebkitUserSelect: \"none\",\n MozUserSelect: \"none\",\n};\n\nexport const LightBeam = ({\n className,\n style,\n colorLightmode = \"rgba(0,0,0, 0.5)\",\n colorDarkmode = \"rgba(255, 255, 255, 0.5)\",\n maskLightByProgress = false,\n fullWidth = 1.0, // Default to full width\n invert = false,\n id = undefined,\n onLoaded = undefined,\n scrollElement,\n disableDefaultStyles = false,\n }: LightBeamProps) => {\n const elementRef = useRef<HTMLDivElement>(null);\n const inViewProgress = useMotionValue(0);\n const opacity = useMotionValue(0.839322);\n const {isDarkmode} = useIsDarkmode();\n const chosenColor = isDarkmode ? colorDarkmode : colorLightmode;\n\n useEffect(() => {\n onLoaded && onLoaded();\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return\n\n // Cache values that don't change during scroll (MAJOR OPTIMIZATION)\n let cachedWindowHeight = window.innerHeight;\n const adjustedFullWidth = 1 - fullWidth; // Only calculate once\n const opacityMin = 0.839322;\n const opacityRange = 1 - opacityMin; // Pre-calculate: 0.160678\n let lastProgress = -1;\n\n const handleScroll = () => {\n if (!elementRef.current) return;\n\n // OPTIMIZATION: Only call getBoundingClientRect (expensive!)\n const rect = elementRef.current.getBoundingClientRect();\n\n // Calculate normalized position (0-1 range)\n const normalizedPosition = Math.max(\n adjustedFullWidth,\n Math.min(1, rect.top / cachedWindowHeight)\n );\n\n // Calculate progress (only once, not twice like before!)\n const progress = invert ? normalizedPosition : 1 - normalizedPosition;\n\n // Only update if change is significant (avoid micro-updates)\n if (Math.abs(progress - lastProgress) > 0.001) {\n lastProgress = progress;\n // Batch updates together\n inViewProgress.set(progress);\n opacity.set(opacityMin + opacityRange * progress);\n }\n };\n\n const handleResize = () => {\n cachedWindowHeight = window.innerHeight; // Update cache on resize\n handleScroll(); // Recalculate immediately\n };\n\n const handleScrollThrottled = throttle(handleScroll);\n const handleResizeThrottled = throttle(handleResize);\n\n // Default to document.body (works in modern React/Next.js setups)\n const target = scrollElement || document.body || document.documentElement;\n\n // Passive listeners improve scroll performance significantly\n target.addEventListener(\"scroll\", handleScrollThrottled, {passive: true});\n window.addEventListener(\"resize\", handleResizeThrottled, {passive: true});\n\n // Initial call to set state\n handleScroll();\n\n return () => {\n target.removeEventListener(\"scroll\", handleScrollThrottled);\n window.removeEventListener(\"resize\", handleResizeThrottled);\n };\n }, [inViewProgress, opacity, scrollElement, fullWidth, invert]);\n\n const backgroundPosition = useTransform(\n inViewProgress,\n [0, 1],\n [\n `conic-gradient(from 90deg at 90% 0%, ${chosenColor}, transparent 180deg) 0% 0% / 50% 150% no-repeat, conic-gradient(from 270deg at 10% 0%, transparent 180deg, ${chosenColor}) 100% 0% / 50% 100% no-repeat`,\n `conic-gradient(from 90deg at 0% 0%, ${chosenColor}, transparent 180deg) 0% 0% / 50% 100% no-repeat, conic-gradient(from 270deg at 100% 0%, transparent 180deg, ${chosenColor}) 100% 0% / 50% 100% no-repeat`,\n ]\n );\n const maskImageOpacity = useTransform(\n inViewProgress,\n [0, 1],\n [\n `linear-gradient(to bottom, ${chosenColor} 0%, transparent 50%)`,\n `linear-gradient(to bottom, ${chosenColor} 0%, transparent 95%)`,\n ]\n );\n\n const maskImage = maskLightByProgress\n ? maskImageOpacity\n : `linear-gradient(to bottom, ${chosenColor} 25%, transparent 95%)`;\n\n const combinedClassName = `react-light-beam ${className || \"\"}`.trim();\n\n // CRITICAL: MotionValues must be passed directly to motion.div style prop\n // Don't spread them into plain objects or reactivity breaks!\n const finalStyles = disableDefaultStyles\n ? {\n // No default styles, only motion values and user styles\n background: backgroundPosition,\n opacity: opacity,\n maskImage: maskImage,\n WebkitMaskImage: maskImage,\n willChange: \"background, opacity\",\n contain: \"layout style paint\", // CSS containment for better performance\n ...style, // User styles override\n }\n : {\n // Merge default styles with motion values\n ...defaultStyles,\n background: backgroundPosition, // MotionValue (overrides default)\n opacity: opacity, // MotionValue (overrides default)\n maskImage: maskImage, // MotionValue or string\n WebkitMaskImage: maskImage,\n willChange: \"background, opacity\",\n ...style, // User styles override everything\n };\n\n const motionProps: any = {\n style: finalStyles,\n ref: elementRef,\n className: combinedClassName,\n ...(id ? {id} : {}),\n };\n\n return <motion.div {...motionProps} />;\n};\n\nconst throttle = (func: Function) => {\n let ticking = false;\n return function (this: any, ...args: any[]) {\n if (!ticking) {\n requestAnimationFrame(() => {\n func.apply(this, args);\n ticking = false;\n });\n ticking = true;\n }\n };\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stianlarsen/react-light-beam",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "A customizable React component that creates a light beam effect using conic gradients. Supports dark mode and various customization options.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|