@geneui/components
Version:
The Gene UI components library designed for BI tools
223 lines (217 loc) • 10.2 kB
JavaScript
import React__default, { memo, useState, useRef, useMemo, useCallback, useEffect } from 'react';
import PropTypes from 'prop-types';
import { n as noop } from '../index-a0e4e333.js';
import useDeviceType from '../hooks/useDeviceType.js';
import Icon from '../Icon/index.js';
import Option from '../Option/index.js';
import Popover from '../Popover/index.js';
import { _ as _extends } from '../_rollupPluginBabelHelpers-e8fb2e5c.js';
import '../dateValidation-67caec66.js';
import { d as debounce } from '../debounce-4419bc2f.js';
import 'react-dom';
import Menu from '../Menu/index.js';
import { s as styleInject } from '../style-inject.es-746bb8ed.js';
import '../configs-00612ce0.js';
import '../hooks/useWindowSize.js';
import '../hooks/useDebounce.js';
import '../index-031ff73c.js';
import '../useEllipsisDetection-4d997d5d.js';
import '../index-6d7e99cd.js';
import '../tslib.es6-f211516f.js';
import '../GeneUIProvider/index.js';
import '../_commonjsHelpers-24198af3.js';
import '../index-122432cd.js';
import '../hooks/useUpdatableRef.js';
import '../hooks/useForceUpdate.js';
import '../Portal/index.js';
import '../Scrollbar/index.js';
import '../guid-8ddf77b3.js';
const getTitle = (id, data) => {
if (data) {
const matchedDatum = data.find(datum => datum.id === id);
return matchedDatum && matchedDatum.title ? matchedDatum : data.map(datum => getTitle(id, datum.data)).filter(Boolean)[0];
}
};
const getTitlesArray = (ids, data) => ids.map(id => getTitle(id, data)).filter(Boolean);
const navigationOptionsToMenu = (navigationOptions, optionId) => navigationOptions.map(_ref => {
let {
data,
...rest
} = _ref;
return {
...rest,
active: (optionId === null || optionId === void 0 ? void 0 : optionId.toString()) === rest.id.toString(),
...(data ? {
children: navigationOptionsToMenu(data, optionId)
} : {})
};
});
const indexStackFromItems = (stack, items, selectedItemId) => {
if (!(items !== null && items !== void 0 && items.length)) {
return [];
}
for (const itemIndex in items) {
const item = items[itemIndex];
if (item.id === selectedItemId) {
return stack;
}
if (item.children) {
const currentIndexStack = indexStackFromItems([...stack, Number(itemIndex)], item.children, selectedItemId);
if (currentIndexStack.length) {
return currentIndexStack;
}
}
}
return [];
};
function NavigationMenuContent(_ref) {
let {
depth,
path,
options,
onChange,
splitedValue
} = _ref;
const [activeItem, setActiveItem] = useState();
const navigationRef = useRef(null);
const isHovered = useRef(true);
const optionId = useMemo(() => splitedValue === null || splitedValue === void 0 ? void 0 : splitedValue[depth], [depth, splitedValue]);
const isActiveItem = useMemo(() => (activeItem === null || activeItem === void 0 ? void 0 : activeItem.id) && optionId === activeItem.id, [activeItem, optionId]);
const mobileOptions = useMemo(() => options ? navigationOptionsToMenu(options, optionId) : undefined, [options, optionId]);
const initialIndexStack = useMemo(() => indexStackFromItems([], mobileOptions, optionId), [mobileOptions, activeItem]);
const {
isMobile
} = useDeviceType();
const onMouseEnterHandler = useCallback(debounce(_ref2 => {
let {
isColaps,
item
} = _ref2;
if (!isHovered.current) return;
isColaps ? setActiveItem(item) : setActiveItem(null);
}, 200), [isHovered, setActiveItem]);
useEffect(() => {
if (optionId && options !== null && options !== void 0 && options.length) {
const item = options.find(item => item.id === optionId);
item && setActiveItem(item);
}
}, [optionId, options]);
const onItemClick = item => {
onChange(path ? "".concat(path, "/").concat(item.id) : item.id, item);
setActiveItem(item);
};
if (isMobile) {
return /*#__PURE__*/React__default.createElement(Menu, {
data: mobileOptions,
onSelect: (_, item) => onItemClick(item),
selectedItem: activeItem,
initialIndexStack: initialIndexStack
});
}
return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, (options === null || options === void 0 ? void 0 : options.length) > 0 && /*#__PURE__*/React__default.createElement("div", {
className: "bc-navigation-menu_content-menu",
ref: navigationRef,
onMouseEnter: () => isHovered.current = true,
onMouseLeave: () => isHovered.current = false
}, options.map(item => {
const isColaps = !!(item.data && item.data.length);
return item.isHidden !== true && /*#__PURE__*/React__default.createElement(Option, _extends({}, item, {
key: item.id,
active: optionId === item.id,
forwardMark: isColaps,
onClick: () => !isColaps && onItemClick(item),
onMouseEnter: () => onMouseEnterHandler({
isColaps,
item
})
}));
})), activeItem && /*#__PURE__*/React__default.createElement(NavigationMenuContent, {
depth: depth + 1,
path: path ? "".concat(path, "/").concat(activeItem.id) : activeItem.id,
options: activeItem.data,
onChange: onChange,
splitedValue: isActiveItem && splitedValue
}));
}
NavigationMenuContent.defaultProps = {
depth: 0
};
var NavigationMenuContent$1 = /*#__PURE__*/memo(NavigationMenuContent);
var css_248z = "[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu{--size:3.6rem;align-items:center;border:1px solid #0000;border-radius:var(--button-external-size,var(--size));color:#fff;cursor:pointer;display:flex;font:600 1.4rem/2rem var(--font-family);justify-content:center;min-height:var(--button-external-size,var(--size));min-width:var(--button-external-size,var(--size));padding:0 1rem;position:relative;transition:color .3s,background .3s,opacity .2s;-webkit-user-select:none;user-select:none}@media (hover:hover){[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu:hover{background:#ffffff1a}}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu.active{background:#ffffff1a}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu:disabled{opacity:.5;pointer-events:none}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu_head{align-items:center;display:flex;justify-content:center;pointer-events:none}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu_layer{align-items:center;display:flex;margin:0 .8rem;opacity:.7}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu_layer.active,[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu_layer:last-child{opacity:1}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu_content{display:flex;padding:1rem 0}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu_content-menu{width:25.8rem}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu_content-menu:not(.bc-navigation-menu_content-menu:last-child){border-right:1px solid #0000001a}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu_title-wrapper{align-items:center;display:flex;justify-content:center}[data-gene-ui-version=\"2.16.5\"] .bc-navigation-menu_title-wrapper:not(.bc-navigation-menu_title-wrapper:last-child):after{background-color:#fff;content:\"\";display:block;height:2.3rem;margin-inline:.6rem;transform:rotate(15deg);width:1px}";
styleInject(css_248z);
function NavigationMenu(_ref) {
let {
data,
value,
onChange,
disabled
} = _ref;
const [isOpen, setIsOpen] = useState(false);
const {
isMobile
} = useDeviceType();
const splitedValue = useMemo(() => value && value.split('/').filter(Boolean), [value]);
const title = useMemo(() => getTitlesArray(splitedValue, data), [splitedValue, data]);
const handleChange = useCallback(function () {
setIsOpen(false);
onChange(...arguments);
}, [onChange]);
const handleToggle = useCallback(() => setIsOpen(prev => !prev), []);
return /*#__PURE__*/React__default.createElement(Popover, {
isOpen: isOpen,
extendTargetWidth: false,
toggleHandler: handleToggle,
fullHeight: true,
children: /*#__PURE__*/React__default.createElement("button", {
className: "bc-navigation-menu",
disabled: disabled
}, /*#__PURE__*/React__default.createElement("div", {
className: "bc-navigation-menu_head"
}, title.map((item, index) => /*#__PURE__*/React__default.createElement("div", {
className: "bc-navigation-menu_title-wrapper"
}, (item === null || item === void 0 ? void 0 : item.icon) && isMobile && /*#__PURE__*/React__default.createElement(Icon, {
type: item.icon
}), /*#__PURE__*/React__default.createElement("span", {
key: index,
className: "bc-navigation-menu_layer"
}, item.title)))), /*#__PURE__*/React__default.createElement(Icon, {
type: "bc-icon-arrow-down"
})),
Content: /*#__PURE__*/React__default.createElement("div", {
className: "bc-navigation-menu_content"
}, /*#__PURE__*/React__default.createElement(NavigationMenuContent$1, {
options: data,
onChange: handleChange,
splitedValue: splitedValue
}))
});
}
NavigationMenu.propTypes = {
/**
* This is where you send data (options) for the menu, if you need to send
* nested options, send the date to the option in the same structure as the options.
* example => data={[{ id: 'item_1', title: 'Item 1', isHidden: false, data: [ { id: 'item_1_1', title: 'Item 1.1', isHidden: false } ]}]}
*/
data: PropTypes.arrayOf(PropTypes.shape(Option.propTypes)).isRequired,
/**
* For value you need to send id selectable options id,
* and if you select the nested option, then you need to send the id to the hierarchy.
* example => 'item_1/item_1_1'
*/
value: PropTypes.string.isRequired,
/**
* onChange handler is called by clicking on the option
* This callback gives you the option you clicked on and its id and
* if it is nested then the give and parent option id are associated with a forward slash.
* (id: NavigationMenu.value, item: Option) => void
*/
onChange: PropTypes.func,
/**
* Disabled status for the navigation menu button
*/
disabled: PropTypes.bool
};
NavigationMenu.defaultProps = {
onChange: noop
};
export { NavigationMenu as default };