import * as React from 'react'; import { createOverflowManager } from '@fluentui/priority-overflow'; import { canUseDOM, useEventCallback, useFirstMount, useIsomorphicLayoutEffect } from '@fluentui/react-utilities'; import { DATA_OVERFLOWING, DATA_OVERFLOW_DIVIDER, DATA_OVERFLOW_ITEM, DATA_OVERFLOW_MENU } from './constants'; const noop = ()=>null; /** * @internal * @param update - Callback when overflow state changes * @param options - Options to configure the overflow container * @returns - ref to attach to an intrinsic HTML element and imperative functions */ export const useOverflowContainer = (update, options)=>{ const { overflowAxis = 'horizontal', overflowDirection = 'end', padding = 10, minimumVisible = 0, onUpdateItemVisibility = noop } = options; const onUpdateOverflow = useEventCallback(update); const overflowOptions = React.useMemo(()=>({ overflowAxis, overflowDirection, padding, minimumVisible, onUpdateItemVisibility, onUpdateOverflow }), [ minimumVisible, onUpdateItemVisibility, overflowAxis, overflowDirection, padding, onUpdateOverflow ]); const firstMount = useFirstMount(); // DOM ref to the overflow container element const containerRef = React.useRef(null); const [overflowManager, setOverflowManager] = React.useState(()=>canUseDOM() ? createOverflowManager() : null); // On first mount there is no need to create an overflow manager and re-render useIsomorphicLayoutEffect(()=>{ if (firstMount && containerRef.current) { overflowManager === null || overflowManager === void 0 ? void 0 : overflowManager.observe(containerRef.current, overflowOptions); } }, [ firstMount, overflowManager, overflowOptions ]); useIsomorphicLayoutEffect(()=>{ if (!containerRef.current || !canUseDOM() || firstMount) { return; } const newOverflowManager = createOverflowManager(); newOverflowManager.observe(containerRef.current, overflowOptions); setOverflowManager(newOverflowManager); }, [ overflowOptions, firstMount ]); /* Clean up overflow manager on unmount */ React.useEffect(()=>()=>{ overflowManager === null || overflowManager === void 0 ? void 0 : overflowManager.disconnect(); }, [ overflowManager ]); const registerItem = React.useCallback((item)=>{ overflowManager === null || overflowManager === void 0 ? void 0 : overflowManager.addItem(item); item.element.setAttribute(DATA_OVERFLOW_ITEM, ''); return ()=>{ item.element.removeAttribute(DATA_OVERFLOWING); item.element.removeAttribute(DATA_OVERFLOW_ITEM); overflowManager === null || overflowManager === void 0 ? void 0 : overflowManager.removeItem(item.id); }; }, [ overflowManager ]); const registerDivider = React.useCallback((divider)=>{ const el = divider.element; overflowManager === null || overflowManager === void 0 ? void 0 : overflowManager.addDivider(divider); el.setAttribute(DATA_OVERFLOW_DIVIDER, ''); return ()=>{ divider.groupId && (overflowManager === null || overflowManager === void 0 ? void 0 : overflowManager.removeDivider(divider.groupId)); el.removeAttribute(DATA_OVERFLOW_DIVIDER); }; }, [ overflowManager ]); const registerOverflowMenu = React.useCallback((el)=>{ overflowManager === null || overflowManager === void 0 ? void 0 : overflowManager.addOverflowMenu(el); el.setAttribute(DATA_OVERFLOW_MENU, ''); return ()=>{ overflowManager === null || overflowManager === void 0 ? void 0 : overflowManager.removeOverflowMenu(); el.removeAttribute(DATA_OVERFLOW_MENU); }; }, [ overflowManager ]); const updateOverflow = React.useCallback(()=>{ overflowManager === null || overflowManager === void 0 ? void 0 : overflowManager.update(); }, [ overflowManager ]); return { registerItem, registerDivider, registerOverflowMenu, updateOverflow, containerRef }; }; export const updateVisibilityAttribute = ({ item, visible })=>{ if (visible) { item.element.removeAttribute(DATA_OVERFLOWING); } else { item.element.setAttribute(DATA_OVERFLOWING, ''); } };