UNPKG

@atlaskit/navigation-system

Version:

The latest navigation system for Atlassian apps.

67 lines (66 loc) • 3.08 kB
import { useEffect, useState } from 'react'; import { bind } from 'bind-event-listener'; /** * Measures the existing Root slots that are not managed by the chat-layout allocator. * Only count separate inline columns: Aside stacks below Main on mobile, and the * legacy Panel spans other areas while overlaying. Read the grid rather than duplicating * its responsive breakpoints. Border boxes include slot borders and live splitter widths. */ export function useOccupiedLayoutWidth(layoutRef) { const [width, setWidth] = useState(0); useEffect(() => { const root = layoutRef === null || layoutRef === void 0 ? void 0 : layoutRef.current; if (!root) { return; } let occupiedSlots = []; const measure = () => { var _getComputedStyle$gri, _rows$map$find; if (occupiedSlots.length === 0) { setWidth(0); return; } const rows = (_getComputedStyle$gri = getComputedStyle(root).gridTemplateAreas.match(/"[^"]+"/g)) !== null && _getComputedStyle$gri !== void 0 ? _getComputedStyle$gri : []; const mainRow = (_rows$map$find = rows.map(row => row.replace(/"/g, '').split(/\s+/)).find(row => row.includes('main'))) !== null && _rows$map$find !== void 0 ? _rows$map$find : []; let occupiedWidth = 0; for (const child of occupiedSlots) { const style = getComputedStyle(child); const area = style.gridArea.split('/').map(part => part.trim()); const slot = area[0]; if (['ribbon', 'aside', 'panel'].includes(slot) && area.every(part => part === slot) && mainRow.includes(slot) && style.display !== 'none' && style.position !== 'absolute' && style.position !== 'fixed') { occupiedWidth += child.getBoundingClientRect().width; } } setWidth(occupiedWidth); }; const resizeObserver = new ResizeObserver(measure); const observeSlots = () => { resizeObserver.disconnect(); resizeObserver.observe(root); // Managed regions resize on every drag frame but cannot consume extra tracks. // Keep them out of both the observer and the measurement loop. Slot identity, // unlike gridArea, remains stable when a region switches to overlay mode. // TopNav and Banner also span columns rather than consuming independent tracks. occupiedSlots = Array.from(root.children).filter(child => child instanceof HTMLElement && child.hasAttribute('data-layout-slot') && !child.matches('nav, header, [role="main"], [data-layout-chat-panel]') && getComputedStyle(child).gridArea.split('/')[0].trim() !== 'banner'); for (const child of occupiedSlots) { resizeObserver.observe(child); } measure(); }; const mutationObserver = new MutationObserver(observeSlots); mutationObserver.observe(root, { childList: true }); observeSlots(); const unbind = bind(window, { type: 'resize', listener: measure }); return () => { unbind(); resizeObserver.disconnect(); mutationObserver.disconnect(); }; }, [layoutRef]); return width; }