import { useMemo, useState, useEffect } from '@wordpress/element';
import classnames from 'classnames';
import { usePopper } from 'react-popper';
import { LiveResizeConfiguration, liveResizeModifier } from '../utils/live-resize-modifier';
import Overlay from './tour-kit-overlay';
import {
SpotlightInteractivity,
SpotlightInteractivityConfiguration,
} from './tour-kit-spotlight-interactivity';
import type { Rect, Placement } from '@popperjs/core';
export const SPOTLIT_ELEMENT_CLASS = 'wp-tour-kit-spotlit';
interface Props {
referenceElement: HTMLElement | null;
styles?: React.CSSProperties;
interactivity?: SpotlightInteractivityConfiguration;
liveResize?: LiveResizeConfiguration;
}
const TourKitSpotlight: React.FunctionComponent< Props > = ( {
referenceElement,
styles,
interactivity,
liveResize,
} ) => {
const [ popperElement, sePopperElement ] = useState< HTMLElement | null >( null );
const referenceRect = referenceElement?.getBoundingClientRect();
const modifiers = [
{
name: 'flip',
enabled: false,
},
{
name: 'preventOverflow',
options: {
mainAxis: false, // true by default
},
},
useMemo(
() => ( {
name: 'offset',
options: {
offset: ( {
placement,
reference,
popper,
}: {
placement: Placement;
reference: Rect;
popper: Rect;
} ): [ number, number ] => {
if ( placement === 'bottom' ) {
return [ 0, -( reference.height + ( popper.height - reference.height ) / 2 ) ];
}
return [ 0, 0 ];
},
},
} ),
[]
),
// useMemo because https://popper.js.org/react-popper/v2/faq/#why-i-get-render-loop-whenever-i-put-a-function-inside-the-popper-configuration
useMemo( () => {
return liveResizeModifier( liveResize );
}, [ liveResize ] ),
];
const { styles: popperStyles, attributes: popperAttributes } = usePopper(
referenceElement,
popperElement,
{
strategy: 'fixed',
placement: 'bottom',
modifiers,
}
);
const clipDimensions = referenceRect
? {
width: `${ referenceRect.width }px`,
height: `${ referenceRect.height }px`,
}
: null;
const clipRepositionProps = referenceElement
? {
style: {
...( clipDimensions && clipDimensions ),
...popperStyles?.popper,
...( styles && styles ),
},
...popperAttributes?.popper,
}
: null;
/**
* Add a .wp-spotlit class to the referenced element so that we can
* apply CSS styles to it, for whatever purposes such as interactivity
*/
useEffect( () => {
referenceElement?.classList.add( SPOTLIT_ELEMENT_CLASS );
return () => {
referenceElement?.classList.remove( SPOTLIT_ELEMENT_CLASS );
};
}, [ referenceElement ] );
return (
<>