amis-rpc-design/node_modules/rc-menu/es/Menu.js
2023-10-07 19:42:30 +08:00

470 lines
18 KiB
JavaScript

import _extends from "@babel/runtime/helpers/esm/extends";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
var _excluded = ["prefixCls", "rootClassName", "style", "className", "tabIndex", "items", "children", "direction", "id", "mode", "inlineCollapsed", "disabled", "disabledOverflow", "subMenuOpenDelay", "subMenuCloseDelay", "forceSubMenuRender", "defaultOpenKeys", "openKeys", "activeKey", "defaultActiveFirst", "selectable", "multiple", "defaultSelectedKeys", "selectedKeys", "onSelect", "onDeselect", "inlineIndent", "motion", "defaultMotions", "triggerSubMenuAction", "builtinPlacements", "itemIcon", "expandIcon", "overflowedIndicator", "overflowedIndicatorPopupClassName", "getPopupContainer", "onClick", "onOpenChange", "onKeyDown", "openAnimation", "openTransitionName", "_internalRenderMenuItem", "_internalRenderSubMenuItem"];
import classNames from 'classnames';
import Overflow from 'rc-overflow';
import useMergedState from "rc-util/es/hooks/useMergedState";
import warning from "rc-util/es/warning";
import * as React from 'react';
import { useImperativeHandle } from 'react';
import { flushSync } from 'react-dom';
import isEqual from "rc-util/es/isEqual";
import { getMenuId, IdContext } from "./context/IdContext";
import MenuContextProvider from "./context/MenuContext";
import { PathRegisterContext, PathUserContext } from "./context/PathContext";
import PrivateContext from "./context/PrivateContext";
import useAccessibility from "./hooks/useAccessibility";
import useKeyRecords, { OVERFLOW_KEY } from "./hooks/useKeyRecords";
import useMemoCallback from "./hooks/useMemoCallback";
import useUUID from "./hooks/useUUID";
import MenuItem from "./MenuItem";
import SubMenu from "./SubMenu";
import { parseItems } from "./utils/nodeUtil";
import { warnItemProp } from "./utils/warnUtil";
/**
* Menu modify after refactor:
* ## Add
* - disabled
*
* ## Remove
* - openTransitionName
* - openAnimation
* - onDestroy
* - siderCollapsed: Seems antd do not use this prop (Need test in antd)
* - collapsedWidth: Seems this logic should be handle by antd Layout.Sider
*/
// optimize for render
var EMPTY_LIST = [];
var Menu = /*#__PURE__*/React.forwardRef(function (props, ref) {
var _childList$, _classNames;
var _ref = props,
_ref$prefixCls = _ref.prefixCls,
prefixCls = _ref$prefixCls === void 0 ? 'rc-menu' : _ref$prefixCls,
rootClassName = _ref.rootClassName,
style = _ref.style,
className = _ref.className,
_ref$tabIndex = _ref.tabIndex,
tabIndex = _ref$tabIndex === void 0 ? 0 : _ref$tabIndex,
items = _ref.items,
children = _ref.children,
direction = _ref.direction,
id = _ref.id,
_ref$mode = _ref.mode,
mode = _ref$mode === void 0 ? 'vertical' : _ref$mode,
inlineCollapsed = _ref.inlineCollapsed,
disabled = _ref.disabled,
disabledOverflow = _ref.disabledOverflow,
_ref$subMenuOpenDelay = _ref.subMenuOpenDelay,
subMenuOpenDelay = _ref$subMenuOpenDelay === void 0 ? 0.1 : _ref$subMenuOpenDelay,
_ref$subMenuCloseDela = _ref.subMenuCloseDelay,
subMenuCloseDelay = _ref$subMenuCloseDela === void 0 ? 0.1 : _ref$subMenuCloseDela,
forceSubMenuRender = _ref.forceSubMenuRender,
defaultOpenKeys = _ref.defaultOpenKeys,
openKeys = _ref.openKeys,
activeKey = _ref.activeKey,
defaultActiveFirst = _ref.defaultActiveFirst,
_ref$selectable = _ref.selectable,
selectable = _ref$selectable === void 0 ? true : _ref$selectable,
_ref$multiple = _ref.multiple,
multiple = _ref$multiple === void 0 ? false : _ref$multiple,
defaultSelectedKeys = _ref.defaultSelectedKeys,
selectedKeys = _ref.selectedKeys,
onSelect = _ref.onSelect,
onDeselect = _ref.onDeselect,
_ref$inlineIndent = _ref.inlineIndent,
inlineIndent = _ref$inlineIndent === void 0 ? 24 : _ref$inlineIndent,
motion = _ref.motion,
defaultMotions = _ref.defaultMotions,
_ref$triggerSubMenuAc = _ref.triggerSubMenuAction,
triggerSubMenuAction = _ref$triggerSubMenuAc === void 0 ? 'hover' : _ref$triggerSubMenuAc,
builtinPlacements = _ref.builtinPlacements,
itemIcon = _ref.itemIcon,
expandIcon = _ref.expandIcon,
_ref$overflowedIndica = _ref.overflowedIndicator,
overflowedIndicator = _ref$overflowedIndica === void 0 ? '...' : _ref$overflowedIndica,
overflowedIndicatorPopupClassName = _ref.overflowedIndicatorPopupClassName,
getPopupContainer = _ref.getPopupContainer,
onClick = _ref.onClick,
onOpenChange = _ref.onOpenChange,
onKeyDown = _ref.onKeyDown,
openAnimation = _ref.openAnimation,
openTransitionName = _ref.openTransitionName,
_internalRenderMenuItem = _ref._internalRenderMenuItem,
_internalRenderSubMenuItem = _ref._internalRenderSubMenuItem,
restProps = _objectWithoutProperties(_ref, _excluded);
var childList = React.useMemo(function () {
return parseItems(children, items, EMPTY_LIST);
}, [children, items]);
var _React$useState = React.useState(false),
_React$useState2 = _slicedToArray(_React$useState, 2),
mounted = _React$useState2[0],
setMounted = _React$useState2[1];
var containerRef = React.useRef();
var uuid = useUUID(id);
var isRtl = direction === 'rtl';
// ========================= Warn =========================
if (process.env.NODE_ENV !== 'production') {
warning(!openAnimation && !openTransitionName, '`openAnimation` and `openTransitionName` is removed. Please use `motion` or `defaultMotion` instead.');
}
// ========================= Open =========================
var _useMergedState = useMergedState(defaultOpenKeys, {
value: openKeys,
postState: function postState(keys) {
return keys || EMPTY_LIST;
}
}),
_useMergedState2 = _slicedToArray(_useMergedState, 2),
mergedOpenKeys = _useMergedState2[0],
setMergedOpenKeys = _useMergedState2[1];
// React 18 will merge mouse event which means we open key will not sync
// ref: https://github.com/ant-design/ant-design/issues/38818
var triggerOpenKeys = function triggerOpenKeys(keys) {
var forceFlush = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
function doUpdate() {
setMergedOpenKeys(keys);
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(keys);
}
if (forceFlush) {
flushSync(doUpdate);
} else {
doUpdate();
}
};
// >>>>> Cache & Reset open keys when inlineCollapsed changed
var _React$useState3 = React.useState(mergedOpenKeys),
_React$useState4 = _slicedToArray(_React$useState3, 2),
inlineCacheOpenKeys = _React$useState4[0],
setInlineCacheOpenKeys = _React$useState4[1];
var mountRef = React.useRef(false);
// ========================= Mode =========================
var _React$useMemo = React.useMemo(function () {
if ((mode === 'inline' || mode === 'vertical') && inlineCollapsed) {
return ['vertical', inlineCollapsed];
}
return [mode, false];
}, [mode, inlineCollapsed]),
_React$useMemo2 = _slicedToArray(_React$useMemo, 2),
mergedMode = _React$useMemo2[0],
mergedInlineCollapsed = _React$useMemo2[1];
var isInlineMode = mergedMode === 'inline';
var _React$useState5 = React.useState(mergedMode),
_React$useState6 = _slicedToArray(_React$useState5, 2),
internalMode = _React$useState6[0],
setInternalMode = _React$useState6[1];
var _React$useState7 = React.useState(mergedInlineCollapsed),
_React$useState8 = _slicedToArray(_React$useState7, 2),
internalInlineCollapsed = _React$useState8[0],
setInternalInlineCollapsed = _React$useState8[1];
React.useEffect(function () {
setInternalMode(mergedMode);
setInternalInlineCollapsed(mergedInlineCollapsed);
if (!mountRef.current) {
return;
}
// Synchronously update MergedOpenKeys
if (isInlineMode) {
setMergedOpenKeys(inlineCacheOpenKeys);
} else {
// Trigger open event in case its in control
triggerOpenKeys(EMPTY_LIST);
}
}, [mergedMode, mergedInlineCollapsed]);
// ====================== Responsive ======================
var _React$useState9 = React.useState(0),
_React$useState10 = _slicedToArray(_React$useState9, 2),
lastVisibleIndex = _React$useState10[0],
setLastVisibleIndex = _React$useState10[1];
var allVisible = lastVisibleIndex >= childList.length - 1 || internalMode !== 'horizontal' || disabledOverflow;
// Cache
React.useEffect(function () {
if (isInlineMode) {
setInlineCacheOpenKeys(mergedOpenKeys);
}
}, [mergedOpenKeys]);
React.useEffect(function () {
mountRef.current = true;
return function () {
mountRef.current = false;
};
}, []);
// ========================= Path =========================
var _useKeyRecords = useKeyRecords(),
registerPath = _useKeyRecords.registerPath,
unregisterPath = _useKeyRecords.unregisterPath,
refreshOverflowKeys = _useKeyRecords.refreshOverflowKeys,
isSubPathKey = _useKeyRecords.isSubPathKey,
getKeyPath = _useKeyRecords.getKeyPath,
getKeys = _useKeyRecords.getKeys,
getSubPathKeys = _useKeyRecords.getSubPathKeys;
var registerPathContext = React.useMemo(function () {
return {
registerPath: registerPath,
unregisterPath: unregisterPath
};
}, [registerPath, unregisterPath]);
var pathUserContext = React.useMemo(function () {
return {
isSubPathKey: isSubPathKey
};
}, [isSubPathKey]);
React.useEffect(function () {
refreshOverflowKeys(allVisible ? EMPTY_LIST : childList.slice(lastVisibleIndex + 1).map(function (child) {
return child.key;
}));
}, [lastVisibleIndex, allVisible]);
// ======================== Active ========================
var _useMergedState3 = useMergedState(activeKey || defaultActiveFirst && ((_childList$ = childList[0]) === null || _childList$ === void 0 ? void 0 : _childList$.key), {
value: activeKey
}),
_useMergedState4 = _slicedToArray(_useMergedState3, 2),
mergedActiveKey = _useMergedState4[0],
setMergedActiveKey = _useMergedState4[1];
var onActive = useMemoCallback(function (key) {
setMergedActiveKey(key);
});
var onInactive = useMemoCallback(function () {
setMergedActiveKey(undefined);
});
useImperativeHandle(ref, function () {
return {
list: containerRef.current,
focus: function focus(options) {
var _childList$find;
var shouldFocusKey = mergedActiveKey !== null && mergedActiveKey !== void 0 ? mergedActiveKey : (_childList$find = childList.find(function (node) {
return !node.props.disabled;
})) === null || _childList$find === void 0 ? void 0 : _childList$find.key;
if (shouldFocusKey) {
var _containerRef$current, _containerRef$current2, _containerRef$current3;
(_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : (_containerRef$current2 = _containerRef$current.querySelector("li[data-menu-id='".concat(getMenuId(uuid, shouldFocusKey), "']"))) === null || _containerRef$current2 === void 0 ? void 0 : (_containerRef$current3 = _containerRef$current2.focus) === null || _containerRef$current3 === void 0 ? void 0 : _containerRef$current3.call(_containerRef$current2, options);
}
}
};
});
// ======================== Select ========================
// >>>>> Select keys
var _useMergedState5 = useMergedState(defaultSelectedKeys || [], {
value: selectedKeys,
// Legacy convert key to array
postState: function postState(keys) {
if (Array.isArray(keys)) {
return keys;
}
if (keys === null || keys === undefined) {
return EMPTY_LIST;
}
return [keys];
}
}),
_useMergedState6 = _slicedToArray(_useMergedState5, 2),
mergedSelectKeys = _useMergedState6[0],
setMergedSelectKeys = _useMergedState6[1];
// >>>>> Trigger select
var triggerSelection = function triggerSelection(info) {
if (selectable) {
// Insert or Remove
var targetKey = info.key;
var exist = mergedSelectKeys.includes(targetKey);
var newSelectKeys;
if (multiple) {
if (exist) {
newSelectKeys = mergedSelectKeys.filter(function (key) {
return key !== targetKey;
});
} else {
newSelectKeys = [].concat(_toConsumableArray(mergedSelectKeys), [targetKey]);
}
} else {
newSelectKeys = [targetKey];
}
setMergedSelectKeys(newSelectKeys);
// Trigger event
var selectInfo = _objectSpread(_objectSpread({}, info), {}, {
selectedKeys: newSelectKeys
});
if (exist) {
onDeselect === null || onDeselect === void 0 ? void 0 : onDeselect(selectInfo);
} else {
onSelect === null || onSelect === void 0 ? void 0 : onSelect(selectInfo);
}
}
// Whatever selectable, always close it
if (!multiple && mergedOpenKeys.length && internalMode !== 'inline') {
triggerOpenKeys(EMPTY_LIST);
}
};
// ========================= Open =========================
/**
* Click for item. SubMenu do not have selection status
*/
var onInternalClick = useMemoCallback(function (info) {
onClick === null || onClick === void 0 ? void 0 : onClick(warnItemProp(info));
triggerSelection(info);
});
var onInternalOpenChange = useMemoCallback(function (key, open) {
var newOpenKeys = mergedOpenKeys.filter(function (k) {
return k !== key;
});
if (open) {
newOpenKeys.push(key);
} else if (internalMode !== 'inline') {
// We need find all related popup to close
var subPathKeys = getSubPathKeys(key);
newOpenKeys = newOpenKeys.filter(function (k) {
return !subPathKeys.has(k);
});
}
if (!isEqual(mergedOpenKeys, newOpenKeys, true)) {
triggerOpenKeys(newOpenKeys, true);
}
});
// ==================== Accessibility =====================
var triggerAccessibilityOpen = function triggerAccessibilityOpen(key, open) {
var nextOpen = open !== null && open !== void 0 ? open : !mergedOpenKeys.includes(key);
onInternalOpenChange(key, nextOpen);
};
var onInternalKeyDown = useAccessibility(internalMode, mergedActiveKey, isRtl, uuid, containerRef, getKeys, getKeyPath, setMergedActiveKey, triggerAccessibilityOpen, onKeyDown);
// ======================== Effect ========================
React.useEffect(function () {
setMounted(true);
}, []);
// ======================= Context ========================
var privateContext = React.useMemo(function () {
return {
_internalRenderMenuItem: _internalRenderMenuItem,
_internalRenderSubMenuItem: _internalRenderSubMenuItem
};
}, [_internalRenderMenuItem, _internalRenderSubMenuItem]);
// ======================== Render ========================
// >>>>> Children
var wrappedChildList = internalMode !== 'horizontal' || disabledOverflow ? childList :
// Need wrap for overflow dropdown that do not response for open
childList.map(function (child, index) {
return (
/*#__PURE__*/
// Always wrap provider to avoid sub node re-mount
React.createElement(MenuContextProvider, {
key: child.key,
overflowDisabled: index > lastVisibleIndex
}, child)
);
});
// >>>>> Container
var container = /*#__PURE__*/React.createElement(Overflow, _extends({
id: id,
ref: containerRef,
prefixCls: "".concat(prefixCls, "-overflow"),
component: "ul",
itemComponent: MenuItem,
className: classNames(prefixCls, "".concat(prefixCls, "-root"), "".concat(prefixCls, "-").concat(internalMode), className, (_classNames = {}, _defineProperty(_classNames, "".concat(prefixCls, "-inline-collapsed"), internalInlineCollapsed), _defineProperty(_classNames, "".concat(prefixCls, "-rtl"), isRtl), _classNames), rootClassName),
dir: direction,
style: style,
role: "menu",
tabIndex: tabIndex,
data: wrappedChildList,
renderRawItem: function renderRawItem(node) {
return node;
},
renderRawRest: function renderRawRest(omitItems) {
// We use origin list since wrapped list use context to prevent open
var len = omitItems.length;
var originOmitItems = len ? childList.slice(-len) : null;
return /*#__PURE__*/React.createElement(SubMenu, {
eventKey: OVERFLOW_KEY,
title: overflowedIndicator,
disabled: allVisible,
internalPopupClose: len === 0,
popupClassName: overflowedIndicatorPopupClassName
}, originOmitItems);
},
maxCount: internalMode !== 'horizontal' || disabledOverflow ? Overflow.INVALIDATE : Overflow.RESPONSIVE,
ssr: "full",
"data-menu-list": true,
onVisibleChange: function onVisibleChange(newLastIndex) {
setLastVisibleIndex(newLastIndex);
},
onKeyDown: onInternalKeyDown
}, restProps));
// >>>>> Render
return /*#__PURE__*/React.createElement(PrivateContext.Provider, {
value: privateContext
}, /*#__PURE__*/React.createElement(IdContext.Provider, {
value: uuid
}, /*#__PURE__*/React.createElement(MenuContextProvider, {
prefixCls: prefixCls,
rootClassName: rootClassName,
mode: internalMode,
openKeys: mergedOpenKeys,
rtl: isRtl
// Disabled
,
disabled: disabled
// Motion
,
motion: mounted ? motion : null,
defaultMotions: mounted ? defaultMotions : null
// Active
,
activeKey: mergedActiveKey,
onActive: onActive,
onInactive: onInactive
// Selection
,
selectedKeys: mergedSelectKeys
// Level
,
inlineIndent: inlineIndent
// Popup
,
subMenuOpenDelay: subMenuOpenDelay,
subMenuCloseDelay: subMenuCloseDelay,
forceSubMenuRender: forceSubMenuRender,
builtinPlacements: builtinPlacements,
triggerSubMenuAction: triggerSubMenuAction,
getPopupContainer: getPopupContainer
// Icon
,
itemIcon: itemIcon,
expandIcon: expandIcon
// Events
,
onItemClick: onInternalClick,
onOpenChange: onInternalOpenChange
}, /*#__PURE__*/React.createElement(PathUserContext.Provider, {
value: pathUserContext
}, container), /*#__PURE__*/React.createElement("div", {
style: {
display: 'none'
},
"aria-hidden": true
}, /*#__PURE__*/React.createElement(PathRegisterContext.Provider, {
value: registerPathContext
}, childList)))));
});
export default Menu;