UNPKG

@kwiz/fluentui

Version:
135 lines 7.58 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { makeStyles, tabClassNames } from "@fluentui/react-components"; import { MoreVerticalRegular } from "@fluentui/react-icons"; import { CommonLogger, debounce, isNotEmptyArray, isNullOrEmptyString, isNumber } from "@kwiz/common"; import { useCallback, useEffect, useRef, useState } from "react"; import { useElementSize, useRefWithState } from "../helpers"; import { useKWIZFluentContext } from "../helpers/context-internal"; import { KnownClassNames } from "../styles"; import { Horizontal } from "./horizontal"; import { MenuEx } from "./menu"; import { Section } from "./section"; import { Vertical } from "./vertical"; const logger = new CommonLogger("OverflowV2"); export const kwizOVerflowMoreMenuCSSName = "kfui-overflow-more"; const OverflowMenu = (props) => { var _a, _b, _c, _d; const ctx = useKWIZFluentContext(); const closeMenu = useRef(); if (props.overflowItems.length === 0) return undefined; else if (props.renderOverflowMenuButton) return props.renderOverflowMenuButton(props); const moreText = ((_b = (_a = ctx.strings) === null || _a === void 0 ? void 0 : _a.more_param) === null || _b === void 0 ? void 0 : _b.call(_a, { cap: true, param: ((_d = (_c = ctx.strings) === null || _c === void 0 ? void 0 : _c.items) === null || _d === void 0 ? void 0 : _d.call(_c)) || "items" })) || "More items"; return _jsx(MenuEx, { menuProps: props.menu, closeMenu: closeMenu, trigger: Object.assign({ className: kwizOVerflowMoreMenuCSSName, icon: props.menuIcon || _jsx(MoreVerticalRegular, {}), title: moreText, showTitleWithIcon: props.vertical, dontStretch: true, dontCenterText: true, iconPosition: props.vertical ? "after" : "before" }, (props.overflowButtonProps || {})), items: props.overflowItems.map((oItem) => ({ title: `s${oItem.$originalIndex}`, onClick: () => { }, as: _jsx(Section, { onClick: () => { var _a; return (_a = closeMenu.current) === null || _a === void 0 ? void 0 : _a.call(closeMenu); }, children: props.renderItem(oItem.item, oItem.$originalIndex, true) }, `s${oItem.$originalIndex}`) })) }); }; const useStyles = makeStyles({ root: { overflow: "hidden", width: "100%", maxWidth: "100%" }, nowrap: { whiteSpace: "nowrap", }, nowrapTabs: { [`& .${tabClassNames.content}`]: { overflow: "visible", } }, rootVertical: { overflow: "hidden", height: "100%", maxHeight: "100%" } }); export const KWIZOverflowV2 = (props) => { var _a; const css = useStyles(); const wrapperRef = useRefWithState(undefined, undefined, props.ref); const size = useElementSize(wrapperRef.ref.current); const [overflowIndexes, setOverflowIndexes] = useState([]); const getPriority = useCallback((item, index) => { var _a; const p = ((_a = props === null || props === void 0 ? void 0 : props.priority) === null || _a === void 0 ? void 0 : _a.call(props, item, index)) || 0; if (!isNumber(p) || p < 0) return 0; else return p; }, [props.priority]); function tooBig(div) { return props.vertical ? div.scrollHeight > div.clientHeight : div.scrollWidth > div.clientWidth; } const resize = useCallback(debounce((info) => { if (info.div) { const divContainer = info.div; const childrenE = divContainer.querySelectorAll(`:scope>.${KnownClassNames.section}`); const overflowMenu = divContainer.querySelector(`.${kwizOVerflowMoreMenuCSSName}`); let allChildren = []; let highestPriority = 0; childrenE.forEach(e => { const divItem = e; const itemIndex = Number(divItem.dataset.itemIndex); if (itemIndex >= 0 && itemIndex <= info.items.length) { const priority = getPriority(info.items[itemIndex], itemIndex); divItem.dataset.itemPriority = priority.toString(10); //allows easier debugging on caller, but we don't rely on this value if (priority > highestPriority) highestPriority = priority; allChildren.push({ div: divItem, priority, itemIndex }); } }); //show all items to provoke overflow allChildren.forEach(c => c.div.style.display = ""); //reverse order so we start hiding last items allChildren.reverse(); //collect hidden items indexes here const newOverflowIndexes = []; let currentPriority = 0; //exit loop while ( //have more higher priority items to hide currentPriority <= highestPriority //still need to hide items && tooBig(divContainer)) { const currentLevelChildren = allChildren.filter(c => c.priority === currentPriority); currentPriority++; let currentChild = 0; //exit loop while ( //have more children currentChild < currentLevelChildren.length //still need to hide items && tooBig(divContainer)) { const child = currentLevelChildren[currentChild++]; newOverflowIndexes.push(child.itemIndex); child.div.style.display = "none"; } } // if (currentPriority > highestPriority)//we progressed beyond the items we have and could not get rid of the scroll // logger.warn("no more items to hide, can't overflow"); //set the hidden indexes, in their correct order (reverse back) setOverflowIndexes(newOverflowIndexes.reverse()); //did not have the overflow menu, but have newOverflowIndexes -> call this again after we render with the menu if (!overflowMenu && isNotEmptyArray(newOverflowIndexes)) window.setTimeout(() => resize(info), 100); } }, 100), [getPriority]); useEffect(() => { resize({ div: wrapperRef.ref.current, items: props.items }); }, [size.height, size.width, wrapperRef.value, props.items, props.children, props.childrenBefore, props.size, props.selection]); const cssClasses = [props.vertical ? css.rootVertical : css.root, (props.nowrap || props.nowrapTabs) && css.nowrap, props.nowrapTabs && css.nowrapTabs, ...(((_a = props.root) === null || _a === void 0 ? void 0 : _a.css) || []) ]; const Wrapper = (props.vertical ? Vertical : Horizontal); useEffect(() => { setOverflowIndexes([]); }, [props.items]); return (_jsxs(Wrapper, Object.assign({ ref: wrapperRef.set }, props.root, { css: cssClasses, style: isNullOrEmptyString(props.size) ? undefined : props.vertical ? { minHeight: props.size, maxHeight: props.size } : { width: props.size }, children: [props.childrenBefore, props.items.map((item, index) => _jsx(Section, { rootProps: { "data-item-index": index //set the item id - we use it using dataset.itemIndex }, children: props.renderItem(item, index, false) }, `s${index}`)), _jsx(OverflowMenu, Object.assign({}, props, { overflowItems: overflowIndexes.map(itemIndex => ({ item: props.items[itemIndex], $originalIndex: itemIndex })) })), props.children] }))); }; //# sourceMappingURL=kwizoverflow2.js.map