@kwiz/fluentui
Version:
KWIZ common controls for FluentUI
135 lines • 7.58 kB
JavaScript
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