Outlook_Addin_LLM/node_modules/@fluentui/react/lib-amd/utilities/useOverflow.js

127 lines
6.6 KiB
JavaScript

define(["require", "exports", "react", "@fluentui/react-hooks", "@fluentui/utilities", "./observeResize"], function (require, exports, React, react_hooks_1, utilities_1, observeResize_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useOverflow = void 0;
/**
* Track whether any items don't fit within their container, and move them to the overflow menu.
* Items are moved into the overflow menu from back to front, excluding pinned items.
*
* The overflow menu button must be the last sibling of all of the items that can be put into the overflow, and it
* must be hooked up to the `setMenuButtonRef` setter function that's returned by `useOverflow`:
* ```ts
* const overflow = useOverflow(...);
* ```
* ```jsx
* <Container>
* <Item /> // Index 0
* <Item /> // Index 1
* ...
* <Button ref={overflow.setMenuButtonRef} /> // Can be any React.Component or HTMLElement
* </Container>
* ```
*/
var useOverflow = function (_a) {
var onOverflowItemsChanged = _a.onOverflowItemsChanged, rtl = _a.rtl, pinnedIndex = _a.pinnedIndex;
var updateOverflowRef = React.useRef();
var containerWidthRef = React.useRef();
// Attach a resize observer to the container
var containerRef = (0, react_hooks_1.useRefEffect)(function (container) {
var cleanupObserver = (0, observeResize_1.observeResize)(container, function (entries) {
containerWidthRef.current = entries ? entries[0].contentRect.width : container.clientWidth;
if (updateOverflowRef.current) {
updateOverflowRef.current();
}
});
return function () {
cleanupObserver();
containerWidthRef.current = undefined;
};
});
var menuButtonRef = (0, react_hooks_1.useRefEffect)(function (menuButton) {
containerRef(menuButton.parentElement);
return function () { return containerRef(null); };
});
(0, react_hooks_1.useIsomorphicLayoutEffect)(function () {
var container = containerRef.current;
var menuButton = menuButtonRef.current;
if (!container || !menuButton) {
return;
}
// items contains the container's children, excluding the overflow menu button itself
var items = [];
for (var i = 0; i < container.children.length; i++) {
var item = container.children[i];
if (item instanceof HTMLElement && item !== menuButton) {
items.push(item);
}
}
// Keep track of the minimum width of the container to fit each child index.
// This cache is an integral part of the algorithm and not just a performance optimization: it allows us to
// recalculate the overflowIndex on subsequent resizes even if some items are already inside the overflow.
var minContainerWidth = [];
var extraWidth = 0; // The accumulated width of items that don't move into the overflow
updateOverflowRef.current = function () {
var containerWidth = containerWidthRef.current;
if (containerWidth === undefined) {
return;
}
// Iterate the items in reverse order until we find one that fits within the bounds of the container
for (var i = items.length - 1; i >= 0; i--) {
// Calculate the min container width for this item if we haven't done so yet
if (minContainerWidth[i] === undefined) {
var itemOffsetEnd = rtl ? containerWidth - items[i].offsetLeft : items[i].offsetLeft + items[i].offsetWidth;
// If the item after this one is pinned, reserve space for it
if (i + 1 < items.length && i + 1 === pinnedIndex) {
// Use distance between the end of the previous item and this one (rather than the
// pinned item's offsetWidth), to account for any margin between the items.
extraWidth = minContainerWidth[i + 1] - itemOffsetEnd;
}
// Reserve space for the menu button after the first item was added to the overflow
if (i === items.length - 2) {
extraWidth += menuButton.offsetWidth;
}
minContainerWidth[i] = itemOffsetEnd + extraWidth;
}
if (containerWidth > minContainerWidth[i]) {
setOverflowIndex(i + 1);
return;
}
}
// If we got here, nothing fits outside the overflow
setOverflowIndex(0);
};
var prevOverflowIndex = items.length;
var setOverflowIndex = function (overflowIndex) {
if (prevOverflowIndex !== overflowIndex) {
prevOverflowIndex = overflowIndex;
onOverflowItemsChanged(overflowIndex, items.map(function (ele, index) { return ({
ele: ele,
isOverflowing: index >= overflowIndex && index !== pinnedIndex,
}); }));
}
};
var cancelAnimationFrame = undefined;
// If the container width is already known from a previous render, update the overflow with its width.
// Do this in an animation frame to avoid forcing layout to happen early.
if (containerWidthRef.current !== undefined) {
var win_1 = (0, utilities_1.getWindow)(container);
if (win_1) {
var animationFrameId_1 = win_1.requestAnimationFrame(updateOverflowRef.current);
cancelAnimationFrame = function () { return win_1.cancelAnimationFrame(animationFrameId_1); };
}
}
return function () {
if (cancelAnimationFrame) {
cancelAnimationFrame();
}
// On cleanup, need to remove all items from the overflow
// so they don't have stale properties on the next render
setOverflowIndex(items.length);
updateOverflowRef.current = undefined;
};
});
return { menuButtonRef: menuButtonRef };
};
exports.useOverflow = useOverflow;
});
//# sourceMappingURL=useOverflow.js.map