import * as React from 'react'; import ResizeSensor, { ResizeSensorCallback } from 'css-element-queries/src/ResizeSensor'; import { Direction, getElement } from '../../utils'; export type EventProxyProps = { component?: React.ComponentType | string; direction: Direction; onResize?: boolean | ResizeSensorCallback; onMutation?: boolean | MutationCallback; onScroll?: boolean | ((event: Event) => void); onClick?: boolean | ((event: Event) => void); onClickCapture?: boolean | ((event: Event) => void); onFocus?: boolean | ((event: Event) => void); onBlur?: boolean | ((event: Event) => void); onMouseOver?: boolean | ((event: Event) => void); onMouseOut?: boolean | ((event: Event) => void); }; export const EventProxy = React.memo(function Spy({ component: Component = 'div', direction = 'child', children, onResize, onMutation, onScroll, onClick, onClickCapture, onFocus, onBlur, onMouseOver, onMouseOut, ...other }: React.PropsWithChildren) { const [, setState] = React.useState(Symbol('__')); const ref = React.useRef(null); const update = () => setState(Symbol('__')); React.useEffect(() => { if (!ref.current || typeof window === 'undefined') { return () => undefined; } const cleanUp: (() => void)[] = []; const element = getElement(ref.current, direction) as T; if (onResize) { const sensor = new ResizeSensor( element as T, typeof onResize === 'function' ? onResize : update, ); cleanUp.push(() => { sensor.detach(); }); } /* istanbul ignore next */ if (onMutation && typeof MutationObserver !== 'undefined') { /* istanbul ignore next */ const observer = new MutationObserver( typeof onMutation === 'function' ? onMutation : update, ); /* istanbul ignore next */ observer.observe(element as T, { attributes: true, childList: true, subtree: true, characterData: true, }); /* istanbul ignore next */ cleanUp.push(() => { observer.disconnect(); }); } [ { event: 'scroll', callback: onScroll }, { event: 'click', callback: onClick }, { event: 'click', callback: onClickCapture, options: true }, { event: 'blur', callback: onBlur }, { event: 'focus', callback: onFocus }, { event: 'mouseover', callback: onMouseOver }, { event: 'mouseout', callback: onMouseOut }, ].forEach(({ event, callback, options }) => { if (callback) { const eventListener = typeof callback === 'function' ? callback as EventListener : update; (element as T).addEventListener(event, eventListener, options); cleanUp.push(() => { (element as T).removeEventListener(event, eventListener, options); }); } }); return () => { cleanUp.forEach(callback => callback()); }; }, [ ref.current, direction, Component, onMutation, onResize, onScroll, onClick, onFocus, onBlur, onMouseOver, onMouseOut ]); return {children}; }); export default EventProxy;