UNPKG

@geneui/components

Version:

The Gene UI components library designed for BI tools

223 lines (217 loc) 10.2 kB
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 };