Overflow.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. var _typeof = require("@babel/runtime/helpers/typeof");
  4. Object.defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. Object.defineProperty(exports, "OverflowContext", {
  8. enumerable: true,
  9. get: function get() {
  10. return _context.OverflowContext;
  11. }
  12. });
  13. exports.default = void 0;
  14. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  15. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  16. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  17. var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
  18. var _react = _interopRequireWildcard(require("react"));
  19. var React = _react;
  20. var _classnames = _interopRequireDefault(require("classnames"));
  21. var _rcResizeObserver = _interopRequireDefault(require("rc-resize-observer"));
  22. var _useLayoutEffect = _interopRequireDefault(require("rc-util/lib/hooks/useLayoutEffect"));
  23. var _Item = _interopRequireDefault(require("./Item"));
  24. var _useEffectState11 = _interopRequireWildcard(require("./hooks/useEffectState"));
  25. var _RawItem = _interopRequireDefault(require("./RawItem"));
  26. var _context = require("./context");
  27. var _excluded = ["prefixCls", "data", "renderItem", "renderRawItem", "itemKey", "itemWidth", "ssr", "style", "className", "maxCount", "renderRest", "renderRawRest", "suffix", "component", "itemComponent", "onVisibleChange"];
  28. function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
  29. function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
  30. var RESPONSIVE = 'responsive';
  31. var INVALIDATE = 'invalidate';
  32. function defaultRenderRest(omittedItems) {
  33. return "+ ".concat(omittedItems.length, " ...");
  34. }
  35. function Overflow(props, ref) {
  36. var _props$prefixCls = props.prefixCls,
  37. prefixCls = _props$prefixCls === void 0 ? 'rc-overflow' : _props$prefixCls,
  38. _props$data = props.data,
  39. data = _props$data === void 0 ? [] : _props$data,
  40. renderItem = props.renderItem,
  41. renderRawItem = props.renderRawItem,
  42. itemKey = props.itemKey,
  43. _props$itemWidth = props.itemWidth,
  44. itemWidth = _props$itemWidth === void 0 ? 10 : _props$itemWidth,
  45. ssr = props.ssr,
  46. style = props.style,
  47. className = props.className,
  48. maxCount = props.maxCount,
  49. renderRest = props.renderRest,
  50. renderRawRest = props.renderRawRest,
  51. suffix = props.suffix,
  52. _props$component = props.component,
  53. Component = _props$component === void 0 ? 'div' : _props$component,
  54. itemComponent = props.itemComponent,
  55. onVisibleChange = props.onVisibleChange,
  56. restProps = (0, _objectWithoutProperties2.default)(props, _excluded);
  57. var fullySSR = ssr === 'full';
  58. var notifyEffectUpdate = (0, _useEffectState11.useBatcher)();
  59. var _useEffectState = (0, _useEffectState11.default)(notifyEffectUpdate, null),
  60. _useEffectState2 = (0, _slicedToArray2.default)(_useEffectState, 2),
  61. containerWidth = _useEffectState2[0],
  62. setContainerWidth = _useEffectState2[1];
  63. var mergedContainerWidth = containerWidth || 0;
  64. var _useEffectState3 = (0, _useEffectState11.default)(notifyEffectUpdate, new Map()),
  65. _useEffectState4 = (0, _slicedToArray2.default)(_useEffectState3, 2),
  66. itemWidths = _useEffectState4[0],
  67. setItemWidths = _useEffectState4[1];
  68. var _useEffectState5 = (0, _useEffectState11.default)(notifyEffectUpdate, 0),
  69. _useEffectState6 = (0, _slicedToArray2.default)(_useEffectState5, 2),
  70. prevRestWidth = _useEffectState6[0],
  71. setPrevRestWidth = _useEffectState6[1];
  72. var _useEffectState7 = (0, _useEffectState11.default)(notifyEffectUpdate, 0),
  73. _useEffectState8 = (0, _slicedToArray2.default)(_useEffectState7, 2),
  74. restWidth = _useEffectState8[0],
  75. setRestWidth = _useEffectState8[1];
  76. var _useEffectState9 = (0, _useEffectState11.default)(notifyEffectUpdate, 0),
  77. _useEffectState10 = (0, _slicedToArray2.default)(_useEffectState9, 2),
  78. suffixWidth = _useEffectState10[0],
  79. setSuffixWidth = _useEffectState10[1];
  80. var _useState = (0, _react.useState)(null),
  81. _useState2 = (0, _slicedToArray2.default)(_useState, 2),
  82. suffixFixedStart = _useState2[0],
  83. setSuffixFixedStart = _useState2[1];
  84. var _useState3 = (0, _react.useState)(null),
  85. _useState4 = (0, _slicedToArray2.default)(_useState3, 2),
  86. displayCount = _useState4[0],
  87. setDisplayCount = _useState4[1];
  88. var mergedDisplayCount = React.useMemo(function () {
  89. if (displayCount === null && fullySSR) {
  90. return Number.MAX_SAFE_INTEGER;
  91. }
  92. return displayCount || 0;
  93. }, [displayCount, containerWidth]);
  94. var _useState5 = (0, _react.useState)(false),
  95. _useState6 = (0, _slicedToArray2.default)(_useState5, 2),
  96. restReady = _useState6[0],
  97. setRestReady = _useState6[1];
  98. var itemPrefixCls = "".concat(prefixCls, "-item");
  99. // Always use the max width to avoid blink
  100. var mergedRestWidth = Math.max(prevRestWidth, restWidth);
  101. // ================================= Data =================================
  102. var isResponsive = maxCount === RESPONSIVE;
  103. var shouldResponsive = data.length && isResponsive;
  104. var invalidate = maxCount === INVALIDATE;
  105. /**
  106. * When is `responsive`, we will always render rest node to get the real width of it for calculation
  107. */
  108. var showRest = shouldResponsive || typeof maxCount === 'number' && data.length > maxCount;
  109. var mergedData = (0, _react.useMemo)(function () {
  110. var items = data;
  111. if (shouldResponsive) {
  112. if (containerWidth === null && fullySSR) {
  113. items = data;
  114. } else {
  115. items = data.slice(0, Math.min(data.length, mergedContainerWidth / itemWidth));
  116. }
  117. } else if (typeof maxCount === 'number') {
  118. items = data.slice(0, maxCount);
  119. }
  120. return items;
  121. }, [data, itemWidth, containerWidth, maxCount, shouldResponsive]);
  122. var omittedItems = (0, _react.useMemo)(function () {
  123. if (shouldResponsive) {
  124. return data.slice(mergedDisplayCount + 1);
  125. }
  126. return data.slice(mergedData.length);
  127. }, [data, mergedData, shouldResponsive, mergedDisplayCount]);
  128. // ================================= Item =================================
  129. var getKey = (0, _react.useCallback)(function (item, index) {
  130. var _ref;
  131. if (typeof itemKey === 'function') {
  132. return itemKey(item);
  133. }
  134. return (_ref = itemKey && (item === null || item === void 0 ? void 0 : item[itemKey])) !== null && _ref !== void 0 ? _ref : index;
  135. }, [itemKey]);
  136. var mergedRenderItem = (0, _react.useCallback)(renderItem || function (item) {
  137. return item;
  138. }, [renderItem]);
  139. function updateDisplayCount(count, suffixFixedStartVal, notReady) {
  140. // React 18 will sync render even when the value is same in some case.
  141. // We take `mergedData` as deps which may cause dead loop if it's dynamic generate.
  142. // ref: https://github.com/ant-design/ant-design/issues/36559
  143. if (displayCount === count && (suffixFixedStartVal === undefined || suffixFixedStartVal === suffixFixedStart)) {
  144. return;
  145. }
  146. setDisplayCount(count);
  147. if (!notReady) {
  148. setRestReady(count < data.length - 1);
  149. onVisibleChange === null || onVisibleChange === void 0 || onVisibleChange(count);
  150. }
  151. if (suffixFixedStartVal !== undefined) {
  152. setSuffixFixedStart(suffixFixedStartVal);
  153. }
  154. }
  155. // ================================= Size =================================
  156. function onOverflowResize(_, element) {
  157. setContainerWidth(element.clientWidth);
  158. }
  159. function registerSize(key, width) {
  160. setItemWidths(function (origin) {
  161. var clone = new Map(origin);
  162. if (width === null) {
  163. clone.delete(key);
  164. } else {
  165. clone.set(key, width);
  166. }
  167. return clone;
  168. });
  169. }
  170. function registerOverflowSize(_, width) {
  171. setRestWidth(width);
  172. setPrevRestWidth(restWidth);
  173. }
  174. function registerSuffixSize(_, width) {
  175. setSuffixWidth(width);
  176. }
  177. // ================================ Effect ================================
  178. function getItemWidth(index) {
  179. return itemWidths.get(getKey(mergedData[index], index));
  180. }
  181. (0, _useLayoutEffect.default)(function () {
  182. if (mergedContainerWidth && typeof mergedRestWidth === 'number' && mergedData) {
  183. var totalWidth = suffixWidth;
  184. var len = mergedData.length;
  185. var lastIndex = len - 1;
  186. // When data count change to 0, reset this since not loop will reach
  187. if (!len) {
  188. updateDisplayCount(0, null);
  189. return;
  190. }
  191. for (var i = 0; i < len; i += 1) {
  192. var currentItemWidth = getItemWidth(i);
  193. // Fully will always render
  194. if (fullySSR) {
  195. currentItemWidth = currentItemWidth || 0;
  196. }
  197. // Break since data not ready
  198. if (currentItemWidth === undefined) {
  199. updateDisplayCount(i - 1, undefined, true);
  200. break;
  201. }
  202. // Find best match
  203. totalWidth += currentItemWidth;
  204. if (
  205. // Only one means `totalWidth` is the final width
  206. lastIndex === 0 && totalWidth <= mergedContainerWidth ||
  207. // Last two width will be the final width
  208. i === lastIndex - 1 && totalWidth + getItemWidth(lastIndex) <= mergedContainerWidth) {
  209. // Additional check if match the end
  210. updateDisplayCount(lastIndex, null);
  211. break;
  212. } else if (totalWidth + mergedRestWidth > mergedContainerWidth) {
  213. // Can not hold all the content to show rest
  214. updateDisplayCount(i - 1, totalWidth - currentItemWidth - suffixWidth + restWidth);
  215. break;
  216. }
  217. }
  218. if (suffix && getItemWidth(0) + suffixWidth > mergedContainerWidth) {
  219. setSuffixFixedStart(null);
  220. }
  221. }
  222. }, [mergedContainerWidth, itemWidths, restWidth, suffixWidth, getKey, mergedData]);
  223. // ================================ Render ================================
  224. var displayRest = restReady && !!omittedItems.length;
  225. var suffixStyle = {};
  226. if (suffixFixedStart !== null && shouldResponsive) {
  227. suffixStyle = {
  228. position: 'absolute',
  229. left: suffixFixedStart,
  230. top: 0
  231. };
  232. }
  233. var itemSharedProps = {
  234. prefixCls: itemPrefixCls,
  235. responsive: shouldResponsive,
  236. component: itemComponent,
  237. invalidate: invalidate
  238. };
  239. // >>>>> Choice render fun by `renderRawItem`
  240. var internalRenderItemNode = renderRawItem ? function (item, index) {
  241. var key = getKey(item, index);
  242. return /*#__PURE__*/React.createElement(_context.OverflowContext.Provider, {
  243. key: key,
  244. value: (0, _objectSpread2.default)((0, _objectSpread2.default)({}, itemSharedProps), {}, {
  245. order: index,
  246. item: item,
  247. itemKey: key,
  248. registerSize: registerSize,
  249. display: index <= mergedDisplayCount
  250. })
  251. }, renderRawItem(item, index));
  252. } : function (item, index) {
  253. var key = getKey(item, index);
  254. return /*#__PURE__*/React.createElement(_Item.default, (0, _extends2.default)({}, itemSharedProps, {
  255. order: index,
  256. key: key,
  257. item: item,
  258. renderItem: mergedRenderItem,
  259. itemKey: key,
  260. registerSize: registerSize,
  261. display: index <= mergedDisplayCount
  262. }));
  263. };
  264. // >>>>> Rest node
  265. var restContextProps = {
  266. order: displayRest ? mergedDisplayCount : Number.MAX_SAFE_INTEGER,
  267. className: "".concat(itemPrefixCls, "-rest"),
  268. registerSize: registerOverflowSize,
  269. display: displayRest
  270. };
  271. var mergedRenderRest = renderRest || defaultRenderRest;
  272. var restNode = renderRawRest ? /*#__PURE__*/React.createElement(_context.OverflowContext.Provider, {
  273. value: (0, _objectSpread2.default)((0, _objectSpread2.default)({}, itemSharedProps), restContextProps)
  274. }, renderRawRest(omittedItems)) : /*#__PURE__*/React.createElement(_Item.default, (0, _extends2.default)({}, itemSharedProps, restContextProps), typeof mergedRenderRest === 'function' ? mergedRenderRest(omittedItems) : mergedRenderRest);
  275. var overflowNode = /*#__PURE__*/React.createElement(Component, (0, _extends2.default)({
  276. className: (0, _classnames.default)(!invalidate && prefixCls, className),
  277. style: style,
  278. ref: ref
  279. }, restProps), mergedData.map(internalRenderItemNode), showRest ? restNode : null, suffix && /*#__PURE__*/React.createElement(_Item.default, (0, _extends2.default)({}, itemSharedProps, {
  280. responsive: isResponsive,
  281. responsiveDisabled: !shouldResponsive,
  282. order: mergedDisplayCount,
  283. className: "".concat(itemPrefixCls, "-suffix"),
  284. registerSize: registerSuffixSize,
  285. display: true,
  286. style: suffixStyle
  287. }), suffix));
  288. return isResponsive ? /*#__PURE__*/React.createElement(_rcResizeObserver.default, {
  289. onResize: onOverflowResize,
  290. disabled: !shouldResponsive
  291. }, overflowNode) : overflowNode;
  292. }
  293. var ForwardOverflow = /*#__PURE__*/React.forwardRef(Overflow);
  294. ForwardOverflow.displayName = 'Overflow';
  295. ForwardOverflow.Item = _RawItem.default;
  296. ForwardOverflow.RESPONSIVE = RESPONSIVE;
  297. ForwardOverflow.INVALIDATE = INVALIDATE;
  298. // Convert to generic type
  299. var _default = exports.default = ForwardOverflow;