amis-rpc-design/node_modules/rc-overflow/es/Overflow.js

293 lines
12 KiB
JavaScript
Raw Normal View History

2023-10-07 19:42:30 +08:00
import _extends from "@babel/runtime/helpers/esm/extends";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
var _excluded = ["prefixCls", "data", "renderItem", "renderRawItem", "itemKey", "itemWidth", "ssr", "style", "className", "maxCount", "renderRest", "renderRawRest", "suffix", "component", "itemComponent", "onVisibleChange"];
import * as React from 'react';
import { useState, useMemo, useCallback } from 'react';
import classNames from 'classnames';
import ResizeObserver from 'rc-resize-observer';
import useLayoutEffect from "rc-util/es/hooks/useLayoutEffect";
import Item from './Item';
import useEffectState, { useBatcher } from './hooks/useEffectState';
import RawItem from './RawItem';
import { OverflowContext } from './context';
var RESPONSIVE = 'responsive';
var INVALIDATE = 'invalidate';
export { OverflowContext } from './context';
function defaultRenderRest(omittedItems) {
return "+ ".concat(omittedItems.length, " ...");
}
function Overflow(props, ref) {
var _props$prefixCls = props.prefixCls,
prefixCls = _props$prefixCls === void 0 ? 'rc-overflow' : _props$prefixCls,
_props$data = props.data,
data = _props$data === void 0 ? [] : _props$data,
renderItem = props.renderItem,
renderRawItem = props.renderRawItem,
itemKey = props.itemKey,
_props$itemWidth = props.itemWidth,
itemWidth = _props$itemWidth === void 0 ? 10 : _props$itemWidth,
ssr = props.ssr,
style = props.style,
className = props.className,
maxCount = props.maxCount,
renderRest = props.renderRest,
renderRawRest = props.renderRawRest,
suffix = props.suffix,
_props$component = props.component,
Component = _props$component === void 0 ? 'div' : _props$component,
itemComponent = props.itemComponent,
onVisibleChange = props.onVisibleChange,
restProps = _objectWithoutProperties(props, _excluded);
var fullySSR = ssr === 'full';
var notifyEffectUpdate = useBatcher();
var _useEffectState = useEffectState(notifyEffectUpdate, null),
_useEffectState2 = _slicedToArray(_useEffectState, 2),
containerWidth = _useEffectState2[0],
setContainerWidth = _useEffectState2[1];
var mergedContainerWidth = containerWidth || 0;
var _useEffectState3 = useEffectState(notifyEffectUpdate, new Map()),
_useEffectState4 = _slicedToArray(_useEffectState3, 2),
itemWidths = _useEffectState4[0],
setItemWidths = _useEffectState4[1];
var _useEffectState5 = useEffectState(notifyEffectUpdate, 0),
_useEffectState6 = _slicedToArray(_useEffectState5, 2),
prevRestWidth = _useEffectState6[0],
setPrevRestWidth = _useEffectState6[1];
var _useEffectState7 = useEffectState(notifyEffectUpdate, 0),
_useEffectState8 = _slicedToArray(_useEffectState7, 2),
restWidth = _useEffectState8[0],
setRestWidth = _useEffectState8[1];
var _useEffectState9 = useEffectState(notifyEffectUpdate, 0),
_useEffectState10 = _slicedToArray(_useEffectState9, 2),
suffixWidth = _useEffectState10[0],
setSuffixWidth = _useEffectState10[1];
var _useState = useState(null),
_useState2 = _slicedToArray(_useState, 2),
suffixFixedStart = _useState2[0],
setSuffixFixedStart = _useState2[1];
var _useState3 = useState(null),
_useState4 = _slicedToArray(_useState3, 2),
displayCount = _useState4[0],
setDisplayCount = _useState4[1];
var mergedDisplayCount = React.useMemo(function () {
if (displayCount === null && fullySSR) {
return Number.MAX_SAFE_INTEGER;
}
return displayCount || 0;
}, [displayCount, containerWidth]);
var _useState5 = useState(false),
_useState6 = _slicedToArray(_useState5, 2),
restReady = _useState6[0],
setRestReady = _useState6[1];
var itemPrefixCls = "".concat(prefixCls, "-item");
// Always use the max width to avoid blink
var mergedRestWidth = Math.max(prevRestWidth, restWidth);
// ================================= Data =================================
var isResponsive = maxCount === RESPONSIVE;
var shouldResponsive = data.length && isResponsive;
var invalidate = maxCount === INVALIDATE;
/**
* When is `responsive`, we will always render rest node to get the real width of it for calculation
*/
var showRest = shouldResponsive || typeof maxCount === 'number' && data.length > maxCount;
var mergedData = useMemo(function () {
var items = data;
if (shouldResponsive) {
if (containerWidth === null && fullySSR) {
items = data;
} else {
items = data.slice(0, Math.min(data.length, mergedContainerWidth / itemWidth));
}
} else if (typeof maxCount === 'number') {
items = data.slice(0, maxCount);
}
return items;
}, [data, itemWidth, containerWidth, maxCount, shouldResponsive]);
var omittedItems = useMemo(function () {
if (shouldResponsive) {
return data.slice(mergedDisplayCount + 1);
}
return data.slice(mergedData.length);
}, [data, mergedData, shouldResponsive, mergedDisplayCount]);
// ================================= Item =================================
var getKey = useCallback(function (item, index) {
var _ref;
if (typeof itemKey === 'function') {
return itemKey(item);
}
return (_ref = itemKey && (item === null || item === void 0 ? void 0 : item[itemKey])) !== null && _ref !== void 0 ? _ref : index;
}, [itemKey]);
var mergedRenderItem = useCallback(renderItem || function (item) {
return item;
}, [renderItem]);
function updateDisplayCount(count, suffixFixedStartVal, notReady) {
// React 18 will sync render even when the value is same in some case.
// We take `mergedData` as deps which may cause dead loop if it's dynamic generate.
// ref: https://github.com/ant-design/ant-design/issues/36559
if (displayCount === count && (suffixFixedStartVal === undefined || suffixFixedStartVal === suffixFixedStart)) {
return;
}
setDisplayCount(count);
if (!notReady) {
setRestReady(count < data.length - 1);
onVisibleChange === null || onVisibleChange === void 0 ? void 0 : onVisibleChange(count);
}
if (suffixFixedStartVal !== undefined) {
setSuffixFixedStart(suffixFixedStartVal);
}
}
// ================================= Size =================================
function onOverflowResize(_, element) {
setContainerWidth(element.clientWidth);
}
function registerSize(key, width) {
setItemWidths(function (origin) {
var clone = new Map(origin);
if (width === null) {
clone.delete(key);
} else {
clone.set(key, width);
}
return clone;
});
}
function registerOverflowSize(_, width) {
setRestWidth(width);
setPrevRestWidth(restWidth);
}
function registerSuffixSize(_, width) {
setSuffixWidth(width);
}
// ================================ Effect ================================
function getItemWidth(index) {
return itemWidths.get(getKey(mergedData[index], index));
}
useLayoutEffect(function () {
if (mergedContainerWidth && typeof mergedRestWidth === 'number' && mergedData) {
var totalWidth = suffixWidth;
var len = mergedData.length;
var lastIndex = len - 1;
// When data count change to 0, reset this since not loop will reach
if (!len) {
updateDisplayCount(0, null);
return;
}
for (var i = 0; i < len; i += 1) {
var currentItemWidth = getItemWidth(i);
// Fully will always render
if (fullySSR) {
currentItemWidth = currentItemWidth || 0;
}
// Break since data not ready
if (currentItemWidth === undefined) {
updateDisplayCount(i - 1, undefined, true);
break;
}
// Find best match
totalWidth += currentItemWidth;
if (
// Only one means `totalWidth` is the final width
lastIndex === 0 && totalWidth <= mergedContainerWidth ||
// Last two width will be the final width
i === lastIndex - 1 && totalWidth + getItemWidth(lastIndex) <= mergedContainerWidth) {
// Additional check if match the end
updateDisplayCount(lastIndex, null);
break;
} else if (totalWidth + mergedRestWidth > mergedContainerWidth) {
// Can not hold all the content to show rest
updateDisplayCount(i - 1, totalWidth - currentItemWidth - suffixWidth + restWidth);
break;
}
}
if (suffix && getItemWidth(0) + suffixWidth > mergedContainerWidth) {
setSuffixFixedStart(null);
}
}
}, [mergedContainerWidth, itemWidths, restWidth, suffixWidth, getKey, mergedData]);
// ================================ Render ================================
var displayRest = restReady && !!omittedItems.length;
var suffixStyle = {};
if (suffixFixedStart !== null && shouldResponsive) {
suffixStyle = {
position: 'absolute',
left: suffixFixedStart,
top: 0
};
}
var itemSharedProps = {
prefixCls: itemPrefixCls,
responsive: shouldResponsive,
component: itemComponent,
invalidate: invalidate
};
// >>>>> Choice render fun by `renderRawItem`
var internalRenderItemNode = renderRawItem ? function (item, index) {
var key = getKey(item, index);
return /*#__PURE__*/React.createElement(OverflowContext.Provider, {
key: key,
value: _objectSpread(_objectSpread({}, itemSharedProps), {}, {
order: index,
item: item,
itemKey: key,
registerSize: registerSize,
display: index <= mergedDisplayCount
})
}, renderRawItem(item, index));
} : function (item, index) {
var key = getKey(item, index);
return /*#__PURE__*/React.createElement(Item, _extends({}, itemSharedProps, {
order: index,
key: key,
item: item,
renderItem: mergedRenderItem,
itemKey: key,
registerSize: registerSize,
display: index <= mergedDisplayCount
}));
};
// >>>>> Rest node
var restNode;
var restContextProps = {
order: displayRest ? mergedDisplayCount : Number.MAX_SAFE_INTEGER,
className: "".concat(itemPrefixCls, "-rest"),
registerSize: registerOverflowSize,
display: displayRest
};
if (!renderRawRest) {
var mergedRenderRest = renderRest || defaultRenderRest;
restNode = /*#__PURE__*/React.createElement(Item, _extends({}, itemSharedProps, restContextProps), typeof mergedRenderRest === 'function' ? mergedRenderRest(omittedItems) : mergedRenderRest);
} else if (renderRawRest) {
restNode = /*#__PURE__*/React.createElement(OverflowContext.Provider, {
value: _objectSpread(_objectSpread({}, itemSharedProps), restContextProps)
}, renderRawRest(omittedItems));
}
var overflowNode = /*#__PURE__*/React.createElement(Component, _extends({
className: classNames(!invalidate && prefixCls, className),
style: style,
ref: ref
}, restProps), mergedData.map(internalRenderItemNode), showRest ? restNode : null, suffix && /*#__PURE__*/React.createElement(Item, _extends({}, itemSharedProps, {
responsive: isResponsive,
responsiveDisabled: !shouldResponsive,
order: mergedDisplayCount,
className: "".concat(itemPrefixCls, "-suffix"),
registerSize: registerSuffixSize,
display: true,
style: suffixStyle
}), suffix));
if (isResponsive) {
overflowNode = /*#__PURE__*/React.createElement(ResizeObserver, {
onResize: onOverflowResize,
disabled: !shouldResponsive
}, overflowNode);
}
return overflowNode;
}
var ForwardOverflow = /*#__PURE__*/React.forwardRef(Overflow);
ForwardOverflow.displayName = 'Overflow';
ForwardOverflow.Item = RawItem;
ForwardOverflow.RESPONSIVE = RESPONSIVE;
ForwardOverflow.INVALIDATE = INVALIDATE;
// Convert to generic type
export default ForwardOverflow;