import { type MouseEventHandler, useEffect, useRef } from 'react'; import is from 'is-lite'; import { getReactNodeText, noop } from '~/modules/helpers'; import type { BeaconRenderProps, Locale, Props, Simplify, Styles } from '~/types'; type BeaconProps = Simplify< Pick & BeaconRenderProps & { locale: Locale; onInteract: MouseEventHandler; shouldFocus: boolean; styles: Styles; } >; export default function JoyrideBeacon(props: BeaconProps) { const { beaconComponent, continuous, index, isLastStep, locale, nonce, onInteract, shouldFocus, size, step, styles, } = props; const beaconRef = useRef(null); const hasBeaconComponent = Boolean(beaconComponent); useEffect(() => { if (hasBeaconComponent) { return noop; } if (document.getElementById('joyride-beacon-animation')) { return noop; } const style = document.createElement('style'); style.id = 'joyride-beacon-animation'; if (nonce) { style.setAttribute('nonce', nonce); } const css = ` @keyframes joyride-beacon-inner { 20% { opacity: 0.9; } 90% { opacity: 0.7; } } @keyframes joyride-beacon-outer { 0% { transform: scale(1); } 45% { opacity: 0.7; transform: scale(0.75); } 100% { opacity: 0.9; transform: scale(1); } } `; style.appendChild(document.createTextNode(css)); document.head.appendChild(style); const focusTimer = setTimeout(() => { if (is.domElement(beaconRef.current) && shouldFocus) { beaconRef.current.focus(); } }, 0); return () => { clearTimeout(focusTimer); const insertedStyle = document.getElementById('joyride-beacon-animation'); if (insertedStyle?.parentNode) { insertedStyle.parentNode.removeChild(insertedStyle); } }; }, [hasBeaconComponent, nonce, shouldFocus]); const title = getReactNodeText(locale.open); let content; if (beaconComponent) { const BeaconComponent = beaconComponent; content = ( ); } else { content = ( ); } return ( ); }