UNPKG

preact-arco-design

Version:

Arco Design React UI Library.

189 lines (157 loc) 5.87 kB
var __assign = this && this.__assign || function () { __assign = Object.assign || function (t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } } return t; }; return __assign.apply(this, arguments); }; var __read = this && this.__read || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) { ar.push(r.value); } } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = this && this.__spreadArray || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; import React, { useState, useRef, useContext, useEffect } from "preact/compat"; import ResizeObserver from 'resize-observer-polyfill'; import SubMenu from "./sub-menu"; import { getStyle } from "../_util/style"; import MenuContext from "./context"; var OVERFLOW_THRESHOLD = 10; function getNodeWidth(node) { return node && +node.getBoundingClientRect().width.toFixed(2); } function translatePxToNumber(str) { var result = Number(str.replace('px', '')); return isNaN(result) ? 0 : result; } var OverflowWrap = function OverflowWrap(props) { var children = props.children; var prefixCls = useContext(MenuContext).prefixCls; var refUl = useRef(null); var refResizeObserver = useRef(null); var _a = __read(useState(null), 2), lastVisibleIndex = _a[0], setLastVisibleIndex = _a[1]; var overflowSubMenuClass = "".concat(prefixCls, "-overflow-sub-menu"); var overflowMenuItemClass = "".concat(prefixCls, "-overflow-hidden-menu-item"); var overflowSubMenuMirrorClass = "".concat(prefixCls, "-overflow-sub-menu-mirror"); useEffect(function () { var ulElement = refUl.current; computeLastVisibleIndex(); refResizeObserver.current = new ResizeObserver(function (entries) { entries.forEach(computeLastVisibleIndex); }); refResizeObserver.current.observe(ulElement); return function () { if (refResizeObserver.current) { refResizeObserver.current.disconnect(); } }; }, [children]); function computeLastVisibleIndex() { if (!refUl.current) { return; } var ulElement = refUl.current; var maxWidth = getNodeWidth(ulElement) - OVERFLOW_THRESHOLD; var childNodeList = [].slice.call(ulElement.children); var menuItemIndex = 0; var currentItemRight = 0; var overflowSubMenuWidth = 0; // 注意 childrenNodeList.length !== React.Children.count(children) 所以需要用 menuItemIndex 来标记真实的 MenuItem 下标 for (var i = 0; i < childNodeList.length; i++) { var node = childNodeList[i]; var classNames = node.className.split(' '); var isOverflowSubMenu = classNames.indexOf(overflowSubMenuClass) > -1; var isOverflowSubMenuMirror = classNames.indexOf(overflowSubMenuMirrorClass) > -1; // 忽略 overflowSubMenu 的宽度,其宽度测量交由 overflowSubMenuMirror if (isOverflowSubMenu) { continue; } var nodeWidth = getNodeWidth(node) + translatePxToNumber(getStyle(node, 'marginLeft')) + translatePxToNumber(getStyle(node, 'marginRight')); if (isOverflowSubMenuMirror) { overflowSubMenuWidth = nodeWidth; continue; } currentItemRight += nodeWidth; // 将要溢出的菜单项 if (currentItemRight > maxWidth) { setLastVisibleIndex( // 判断如果将最后一个菜单项换为 ... 是否会超出宽度 menuItemIndex - (currentItemRight - nodeWidth + overflowSubMenuWidth <= maxWidth ? 1 : 2)); return; } menuItemIndex++; } // 全部可见 setLastVisibleIndex(null); } var renderOverflowSubMenu = function renderOverflowSubMenu(children, isMirror) { if (isMirror === void 0) { isMirror = false; } return React.createElement(SubMenu, __assign({ title: React.createElement("span", null, "\xB7\xB7\xB7"), key: "arco-menu-overflow-sub-menu".concat(isMirror ? '-mirror' : ''), className: isMirror ? overflowSubMenuMirrorClass : overflowSubMenuClass }, props, { children: children })); }; var renderChildren = function renderChildren() { var overflowSubMenu = null; var overflowSubMenuMirror = renderOverflowSubMenu(null, true); var originMenuItems = React.Children.map(children, function (child, index) { var item = child; if (lastVisibleIndex !== null) { if (index > lastVisibleIndex) { item = React.cloneElement(child, { className: overflowMenuItemClass }); } if (index === lastVisibleIndex + 1) { var overflowedItems = React.Children.toArray(children).slice(lastVisibleIndex + 1).map(function (child) { return React.cloneElement(child, { key: child.props._key }); }); overflowSubMenu = renderOverflowSubMenu(overflowedItems); } } return item; }); return __spreadArray(__spreadArray([overflowSubMenuMirror], __read(originMenuItems), false), [overflowSubMenu], false); }; return React.createElement("div", { className: "".concat(prefixCls, "-overflow-wrap"), ref: refUl }, renderChildren()); }; export default OverflowWrap;