@stianlarsen/react-light-beam 1.1.1 → 1.2.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 +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -142,7 +142,7 @@ Then provide all styles via CSS:
|
|
|
142
142
|
| `fullWidth` | `number` | `1.0` | Optional number between `0` and `1` representing the maximum width the light beam can reach. |
|
|
143
143
|
| `maskLightByProgress` | `boolean` | `false` | If `true`, the `mask-image`'s linear gradient will start with the chosen color at 0% and the transparent part starting at 50%. As the user scrolls, it will dynamically change to have the transparent part at 95%, reducing the glow effect. If `false`, it will default to `linear-gradient(to bottom, chosenColor 25%, transparent 95%)`. |
|
|
144
144
|
| `invert` | `boolean` | `false` | Optional boolean to invert the scroll progress calculation. |
|
|
145
|
-
| `scrollElement` | `EventTarget` or `undefined` | `
|
|
145
|
+
| `scrollElement` | `EventTarget` or `undefined` | `document.body` | Optional prop for which element to attach the scroll listener to. Defaults to `document.body` (the `<body>` element). Can be set to `document.documentElement`, `window`, or any scrollable element. |
|
|
146
146
|
| `onLoaded` | `undefined or () => void` | `undefined` | Optional function to run when the component has mounted |
|
|
147
147
|
| `disableDefaultStyles` | `boolean` | `false` | Disable default inline styles. Set to `true` if you want to provide all styles yourself via className. Gives you complete CSS control without any default styling. |
|
|
148
148
|
|
package/dist/index.js
CHANGED
|
@@ -66,7 +66,7 @@ var LightBeam = ({
|
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
68
|
const handleScrollThrottled = throttle(handleScroll);
|
|
69
|
-
const target = scrollElement ||
|
|
69
|
+
const target = scrollElement || document.body || document.documentElement;
|
|
70
70
|
target.addEventListener("scroll", handleScrollThrottled);
|
|
71
71
|
window.addEventListener("resize", handleScrollThrottled);
|
|
72
72
|
handleScroll();
|
|
@@ -75,7 +75,7 @@ var LightBeam = ({
|
|
|
75
75
|
window.removeEventListener("resize", handleScrollThrottled);
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
|
-
}, [inViewProgress, opacity, scrollElement]);
|
|
78
|
+
}, [inViewProgress, opacity, scrollElement, fullWidth, invert]);
|
|
79
79
|
const backgroundPosition = framerMotion.useTransform(
|
|
80
80
|
inViewProgress,
|
|
81
81
|
[0, 1],
|
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 const target = scrollElement || window;\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]);\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: \"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"]}
|
package/dist/index.mjs
CHANGED
|
@@ -64,7 +64,7 @@ var LightBeam = ({
|
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
66
|
const handleScrollThrottled = throttle(handleScroll);
|
|
67
|
-
const target = scrollElement ||
|
|
67
|
+
const target = scrollElement || document.body || document.documentElement;
|
|
68
68
|
target.addEventListener("scroll", handleScrollThrottled);
|
|
69
69
|
window.addEventListener("resize", handleScrollThrottled);
|
|
70
70
|
handleScroll();
|
|
@@ -73,7 +73,7 @@ var LightBeam = ({
|
|
|
73
73
|
window.removeEventListener("resize", handleScrollThrottled);
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
|
-
}, [inViewProgress, opacity, scrollElement]);
|
|
76
|
+
}, [inViewProgress, opacity, scrollElement, fullWidth, invert]);
|
|
77
77
|
const backgroundPosition = useTransform(
|
|
78
78
|
inViewProgress,
|
|
79
79
|
[0, 1],
|
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 const target = scrollElement || window;\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]);\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: \"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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stianlarsen/react-light-beam",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.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",
|