import React, { forwardRef, useEffect, useRef, useState } from 'react'; import { isString, useDeepCompareMemoize, useEvent, useForwardedRef, useInViewport, } from '@anton.bobrov/react-hooks'; import cn from 'classnames'; import { Marquee as VevetMarquee } from 'vevet'; import { IMarqueeProps } from './types'; import { prefixedClasNames } from '../../utils/prefixedClassNames'; /** * Marquee component for creating scrolling text or content. * * This component provides a simple way to display text or other elements that * scroll horizontally across the screen. It supports various features such as * customizable speed, direction, and behavior, allowing developers to create * engaging and dynamic content displays. The Marquee component is designed * to enhance user experience by providing an attention-grabbing method for * presenting important information or announcements while ensuring accessibility * and responsiveness across different devices and screen sizes. * * @link See examples https://antonbobrov.github.io/react-kit/?path=/docs/text-marquee--docs */ export const Marquee = forwardRef( ( { className, style, children, 'aria-label': ariaLabel, canCloneNodes = false, onInit: onInitProp, isEnabled = true, ...changeableProps }, forwardedRef, ) => { const ref = useForwardedRef(forwardedRef); const containerRef = useRef(null); const [marquee, setMarquee] = useState(); const onInit = useEvent(onInitProp); const initialPropsRef = useRef({ isEnabled, ...changeableProps }); // create the marquee useEffect(() => { if (!containerRef.current) { return undefined; } const instance = new VevetMarquee({ ...initialPropsRef.current, container: containerRef.current, canCloneNodes, }); setMarquee(instance); onInit?.(instance); return () => instance?.destroy(); }, [canCloneNodes, onInit, ref]); // viewport position state const { state } = useInViewport({ ref }); // enable or disable on viewport position change useEffect(() => { if (!marquee || !state) { return; } if (state === 'in' && isEnabled) { marquee.changeProps({ isEnabled: true }); } else { marquee.changeProps({ isEnabled: false }); } }, [marquee, state, isEnabled]); // change props useEffect(() => { if (!marquee) { return; } marquee.changeProps(changeableProps); // eslint-disable-next-line react-hooks/exhaustive-deps }, [marquee, useDeepCompareMemoize(changeableProps)]); return (
{children}
); }, ); Marquee.displayName = 'Marquee';