UNPKG

react-fast-marquee-shadow-dom

Version:

A lightweight React component that utilizes the power of CSS animations to create silky smooth marquees.

159 lines (153 loc) 5.78 kB
'use strict'; var React = require('react'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); function Marquee({ style = {}, className = "", autoFill = false, play = true, pauseOnHover = false, pauseOnClick = false, direction = "left", speed = 50, delay = 0, loop = 0, gradient = false, gradientColor = "white", gradientWidth = 200, onFinish, onCycleComplete, onMount, children }) { const [containerWidth, setContainerWidth] = React.useState(0); const [marqueeWidth, setMarqueeWidth] = React.useState(0); const [multiplier, setMultiplier] = React.useState(1); const [isMounted, setIsMounted] = React.useState(false); const containerRef = React.useRef(null); const marqueeRef = React.useRef(null); const calculateWidth = React.useCallback(() => { if (marqueeRef.current && containerRef.current) { const containerRect = containerRef.current.getBoundingClientRect(); const marqueeRect = marqueeRef.current.getBoundingClientRect(); let containerWidth2 = containerRect.width; let marqueeWidth2 = marqueeRect.width; if (direction === "up" || direction === "down") { containerWidth2 = containerRect.height; marqueeWidth2 = marqueeRect.height; } if (autoFill && containerWidth2 && marqueeWidth2) { setMultiplier( marqueeWidth2 < containerWidth2 ? Math.ceil(containerWidth2 / marqueeWidth2) : 1 ); } else { setMultiplier(1); } setContainerWidth(containerWidth2); setMarqueeWidth(marqueeWidth2); } }, [autoFill, containerRef, direction]); React.useEffect(() => { if (!isMounted) return; calculateWidth(); if (marqueeRef.current && containerRef.current) { const resizeObserver = new ResizeObserver(() => calculateWidth()); resizeObserver.observe(containerRef.current); resizeObserver.observe(marqueeRef.current); return () => { if (!resizeObserver) return; resizeObserver.disconnect(); }; } }, [calculateWidth, containerRef, isMounted]); React.useEffect(() => { calculateWidth(); }, [calculateWidth, children]); React.useEffect(() => { setIsMounted(true); }, []); React.useEffect(() => { if (typeof onMount === "function") { onMount(); } }, []); const duration = React.useMemo(() => { if (autoFill) { return marqueeWidth * multiplier / speed; } else { return marqueeWidth < containerWidth ? containerWidth / speed : marqueeWidth / speed; } }, [autoFill, containerWidth, marqueeWidth, multiplier, speed]); const containerStyle = React.useMemo( () => ({ ...style, ["--pause-on-hover"]: !play || pauseOnHover ? "paused" : "running", ["--pause-on-click"]: !play || pauseOnHover && !pauseOnClick || pauseOnClick ? "paused" : "running", ["--width"]: direction === "up" || direction === "down" ? `100vh` : "100%", ["--transform"]: direction === "up" ? "rotate(-90deg)" : direction === "down" ? "rotate(90deg)" : "none" }), [style, play, pauseOnHover, pauseOnClick, direction] ); const gradientStyle = React.useMemo( () => ({ ["--gradient-color"]: gradientColor, ["--gradient-width"]: typeof gradientWidth === "number" ? `${gradientWidth}px` : gradientWidth }), [gradientColor, gradientWidth] ); const marqueeStyle = React.useMemo( () => ({ ["--play"]: play ? "running" : "paused", ["--direction"]: direction === "left" ? "normal" : "reverse", ["--duration"]: `${duration}s`, ["--delay"]: `${delay}s`, ["--iteration-count"]: !!loop ? `${loop}` : "infinite", ["--min-width"]: autoFill ? `auto` : "100%" }), [play, direction, duration, delay, loop, autoFill] ); const childStyle = React.useMemo( () => ({ ["--transform"]: direction === "up" ? "rotate(90deg)" : direction === "down" ? "rotate(-90deg)" : "none" }), [direction] ); const multiplyChildren = React.useCallback( (multiplier2) => { return [ ...Array( Number.isFinite(multiplier2) && multiplier2 >= 0 ? multiplier2 : 0 ) ].map((_, i) => /* @__PURE__ */ React__default["default"].createElement(React.Fragment, { key: i }, React.Children.map(children, (child) => { return /* @__PURE__ */ React__default["default"].createElement("div", { style: childStyle, className: "rfm-child" }, child); }))); }, [childStyle, children] ); return !isMounted ? null : /* @__PURE__ */ React__default["default"].createElement( "div", { ref: containerRef, style: containerStyle, className: "rfm-marquee-container " + className }, gradient && /* @__PURE__ */ React__default["default"].createElement("div", { style: gradientStyle, className: "rfm-overlay" }), /* @__PURE__ */ React__default["default"].createElement( "div", { className: "rfm-marquee", style: marqueeStyle, onAnimationIteration: onCycleComplete, onAnimationEnd: onFinish }, /* @__PURE__ */ React__default["default"].createElement("div", { className: "rfm-initial-child-container", ref: marqueeRef }, React.Children.map(children, (child) => { return /* @__PURE__ */ React__default["default"].createElement("div", { style: childStyle, className: "rfm-child" }, child); })), multiplyChildren(multiplier - 1) ), /* @__PURE__ */ React__default["default"].createElement("div", { className: "rfm-marquee", style: marqueeStyle }, multiplyChildren(multiplier)) ); } module.exports = Marquee; //# sourceMappingURL=index.cjs.map