@atlaskit/navigation-system
Version:
The latest navigation system for Atlassian apps.
73 lines • 2.83 kB
JavaScript
import { useEffect, useState } from 'react';
import { bindAll } from 'bind-event-listener';
/**
* Observe CSS's responsive modes without loading the drag allocator or publishing
* measured widths back into CSS. Observe the host and independent occupied tracks;
* managed panels, TopNav and Banner are deliberately not observed during dragging.
*/
export function useCssLayoutAreaStates(layoutRef, revision, isEnabled) {
const [modes, setModes] = useState({});
useEffect(() => {
const root = layoutRef === null || layoutRef === void 0 ? void 0 : layoutRef.current;
if (!root || !isEnabled) {
return;
}
const measure = () => {
const selectors = {
'side-nav': ':scope > nav[data-layout-slot]',
panel: '[data-layout-with-panel-slot]',
'chat-panel': ':scope > [data-layout-chat-panel]'
};
const next = {};
for (const area of ['side-nav', 'panel', 'chat-panel']) {
const element = root.querySelector(selectors[area]);
if (element) {
next[area] = getComputedStyle(element).gridArea.split('/')[0].trim() === area ? 'inline' : 'overlay';
}
}
setModes(previous => ['side-nav', 'panel', 'chat-panel'].every(area => previous[area] === next[area]) ? previous : next);
};
const widths = new Map();
const observer = new ResizeObserver(entries => {
let changed = false;
for (const entry of entries) {
if (widths.get(entry.target) !== entry.contentRect.width) {
widths.set(entry.target, entry.contentRect.width);
changed = true;
}
}
if (changed) {
measure();
}
});
const observeSlots = () => {
observer.disconnect();
widths.clear();
const occupied = Array.from(root.children).filter(element => element.matches('[data-layout-slot]:not(nav):not(header):not([role="main"]):not([data-layout-chat-panel])') && ['aside', 'ribbon', 'panel'].includes(getComputedStyle(element).gridArea.split('/')[0].trim()));
for (const element of [root, ...occupied]) {
widths.set(element, element.getBoundingClientRect().width);
observer.observe(element);
}
measure();
};
observeSlots();
const mutations = new MutationObserver(observeSlots);
mutations.observe(root, {
childList: true
});
const queries = [window.matchMedia('(min-width: 40rem)'), window.matchMedia('(min-width: 64rem)')];
const unbind = [bindAll(window, [{
type: 'resize',
listener: measure
}]), ...queries.map(query => bindAll(query, [{
type: 'change',
listener: measure
}]))];
return () => {
observer.disconnect();
mutations.disconnect();
unbind.forEach(cleanup => cleanup());
};
}, [isEnabled, layoutRef, revision]);
return modes;
}