UNPKG

react-dvd-screensaver

Version:
152 lines (147 loc) 5.6 kB
import React, { useRef, useState, useEffect, useLayoutEffect, cloneElement } from 'react'; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); function useWindowSize() { const getSize = () => ({ width: window.innerWidth, height: window.innerHeight }); const [windowSize, setWindowSize] = React.useState(getSize); React.useLayoutEffect(() => { const onResize = () => setWindowSize(getSize); window.addEventListener("resize", onResize); return () => window.removeEventListener("resize", onResize); }, []); return windowSize; } // src/useDvdScreensaver.ts function useDvdScreensaver(options) { const { width: windowWidth } = useWindowSize(); const animationRef = useRef({ animationFrameId: 0, containerHeight: 0, containerWidth: 0, impactCount: 0, isPosXIncrement: true, isPosYIncrement: true, positionX: Math.random() * windowWidth, positionY: Math.random() * windowWidth }); const elementRef = useRef(null); const containerRef = useRef(null); const [impactCount, setImpactCount] = useState(0); const [hovered, setHovered] = useState(false); function updatePosition(containerSpan, delta, elementSpan, prevPos, toggleRefKey) { const parentBoundary = containerSpan - elementSpan; let newPos = prevPos + (animationRef.current[toggleRefKey] ? delta : -delta); if (newPos <= 0 || newPos >= parentBoundary) { animationRef.current[toggleRefKey] = !animationRef.current[toggleRefKey]; animationRef.current.impactCount += 1; setImpactCount(animationRef.current.impactCount); newPos = newPos <= 0 ? 0 : parentBoundary; } return newPos; } function animate() { if (elementRef.current && elementRef.current.parentElement) { const containerHeight = elementRef.current.parentElement.clientHeight; const containerWidth = elementRef.current.parentElement.clientWidth; const elementHeight = elementRef.current.clientHeight; const elementWidth = elementRef.current.clientWidth; const delta = (options == null ? void 0 : options.speed) || 2; const posX = updatePosition( containerWidth, delta, elementWidth, animationRef.current.positionX, "isPosXIncrement" ); const posY = updatePosition( containerHeight, delta, elementHeight, animationRef.current.positionY, "isPosYIncrement" ); elementRef.current.style.transform = `translate3d(${posX}px, ${posY}px, 0)`; animationRef.current.positionX = posX; animationRef.current.positionY = posY; } animationRef.current.animationFrameId = requestAnimationFrame(animate); } useEffect(() => { if (options == null ? void 0 : options.freezeOnHover) { if (hovered) { cancelAnimationFrame(animationRef.current.animationFrameId); animationRef.current.animationFrameId = 0; } if (!hovered && !animationRef.current.animationFrameId) { animationRef.current.animationFrameId = requestAnimationFrame(animate); } } if (options == null ? void 0 : options.hoverCallback) { options.hoverCallback(); } }, [hovered, options]); useLayoutEffect(() => { const element = elementRef.current; const handleMouseOver = () => setHovered(true); const handleMouseOut = () => setHovered(false); if (element) { element.style.willChange = "transform"; element.addEventListener("mouseover", handleMouseOver); element.addEventListener("mouseout", handleMouseOut); animationRef.current.animationFrameId = requestAnimationFrame(animate); } return () => { if (element) { element.removeEventListener("mouseover", handleMouseOver); element.removeEventListener("mouseout", handleMouseOut); } cancelAnimationFrame(animationRef.current.animationFrameId); }; }, []); return { containerRef, elementRef, hovered, impactCount }; } // src/DvdScreensaver.tsx function DvdScreensaver(props) { const { elementRef, impactCount } = useDvdScreensaver({ freezeOnHover: props.freezeOnHover, hoverCallback: props.hoverCallback, speed: props.speed }); useEffect(() => { if (props.impactCallback) { props.impactCallback(impactCount); } }, [impactCount, props.impactCallback]); const enhancedStyle = __spreadProps(__spreadValues({}, props.style), { width: (props == null ? void 0 : props.width) || "100%", height: (props == null ? void 0 : props.height) || "100%" }); const childWithRef = cloneElement(props.children, { ref: elementRef }); return /* @__PURE__ */ React.createElement("div", { className: props.className, style: enhancedStyle }, childWithRef); } export { DvdScreensaver, useDvdScreensaver };