import { cloneElement, forwardRef, ReactElement, useCallback, useEffect, useId, useRef, } from 'react'; import { RtAnimatedIconProps } from './create-icon.types'; import classnames from 'classnames/bind'; import styles from '../styles/rt-animated-icons.module.css'; // eslint-disable-next-line @nx/enforce-module-boundaries import { _V_PREFIX_ } from '../../../../../../tools/constants'; const cn = classnames.bind(styles); type SVGNode = ({ id }: { id: string }) => ReactElement; export const createIcon = (svgNode: SVGNode) => { return forwardRef( ( { typography, scale = 'default', specification = 'main', animateStrategy = 'click', }: RtAnimatedIconProps, ref ) => { const isAnimationStarted = useRef(false); const svgRef = useRef(null); const id = useId(); const animate = useCallback(() => { if (!isAnimationStarted.current && svgRef.current) { const elements = [ ...Array.from( svgRef.current.querySelectorAll('animateTransform') || [] ), ...Array.from(svgRef.current.querySelectorAll('animate') || []), ...Array.from( svgRef.current.querySelectorAll('animateMotion') || [] ), ]; if (elements.length === 0) return; isAnimationStarted.current = true; elements.forEach((el, idx) => { if (typeof el.beginElement === 'function') { el.beginElement(); } if (animateStrategy !== 'infinite') el.setAttribute('repeatCount', '1'); else el.setAttribute('repeatCount', 'indefinite'); if (idx === 0) { const onEnd = () => { isAnimationStarted.current = false; el.removeEventListener('endEvent', onEnd); }; el.addEventListener('endEvent', onEnd); } }); } }, [animateStrategy]); useEffect(() => { if (animateStrategy === 'init') animate(); else if (animateStrategy === 'infinite') animate(); }, [animateStrategy, animate]); const hoverHandle = () => { if (animateStrategy === 'hover') animate(); }; const clickHandle = () => { if (animateStrategy === 'click') animate(); }; return ( {cloneElement(svgNode({ id }), { ref: svgRef })} ); } ); };