InternalTable.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. "use strict";
  2. "use client";
  3. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  4. var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
  5. Object.defineProperty(exports, "__esModule", {
  6. value: true
  7. });
  8. exports.default = void 0;
  9. var React = _interopRequireWildcard(require("react"));
  10. var _classnames = _interopRequireDefault(require("classnames"));
  11. var _rcTable = require("rc-table");
  12. var _useColumns = require("rc-table/lib/hooks/useColumns");
  13. var _omit = _interopRequireDefault(require("rc-util/lib/omit"));
  14. var _useProxyImperativeHandle = _interopRequireDefault(require("../_util/hooks/useProxyImperativeHandle"));
  15. var _scrollTo = _interopRequireDefault(require("../_util/scrollTo"));
  16. var _warning = require("../_util/warning");
  17. var _configProvider = _interopRequireDefault(require("../config-provider"));
  18. var _context = require("../config-provider/context");
  19. var _defaultRenderEmpty = _interopRequireDefault(require("../config-provider/defaultRenderEmpty"));
  20. var _useCSSVarCls = _interopRequireDefault(require("../config-provider/hooks/useCSSVarCls"));
  21. var _useSize = _interopRequireDefault(require("../config-provider/hooks/useSize"));
  22. var _useBreakpoint = _interopRequireDefault(require("../grid/hooks/useBreakpoint"));
  23. var _en_US = _interopRequireDefault(require("../locale/en_US"));
  24. var _pagination = _interopRequireDefault(require("../pagination"));
  25. var _spin = _interopRequireDefault(require("../spin"));
  26. var _internal = require("../theme/internal");
  27. var _ExpandIcon = _interopRequireDefault(require("./ExpandIcon"));
  28. var _useContainerWidth = _interopRequireDefault(require("./hooks/useContainerWidth"));
  29. var _useFilter = _interopRequireWildcard(require("./hooks/useFilter"));
  30. var _useLazyKVMap = _interopRequireDefault(require("./hooks/useLazyKVMap"));
  31. var _usePagination = _interopRequireWildcard(require("./hooks/usePagination"));
  32. var _useSelection = _interopRequireDefault(require("./hooks/useSelection"));
  33. var _useSorter = _interopRequireWildcard(require("./hooks/useSorter"));
  34. var _useTitleColumns = _interopRequireDefault(require("./hooks/useTitleColumns"));
  35. var _RcTable = _interopRequireDefault(require("./RcTable"));
  36. var _VirtualTable = _interopRequireDefault(require("./RcTable/VirtualTable"));
  37. var _style = _interopRequireDefault(require("./style"));
  38. const EMPTY_LIST = [];
  39. const InternalTable = (props, ref) => {
  40. var _a, _b;
  41. const {
  42. prefixCls: customizePrefixCls,
  43. className,
  44. rootClassName,
  45. style,
  46. size: customizeSize,
  47. bordered,
  48. dropdownPrefixCls: customizeDropdownPrefixCls,
  49. dataSource,
  50. pagination,
  51. rowSelection,
  52. rowKey = 'key',
  53. rowClassName,
  54. columns,
  55. children,
  56. childrenColumnName: legacyChildrenColumnName,
  57. onChange,
  58. getPopupContainer,
  59. loading,
  60. expandIcon,
  61. expandable,
  62. expandedRowRender,
  63. expandIconColumnIndex,
  64. indentSize,
  65. scroll,
  66. sortDirections,
  67. locale,
  68. showSorterTooltip = {
  69. target: 'full-header'
  70. },
  71. virtual
  72. } = props;
  73. const warning = (0, _warning.devUseWarning)('Table');
  74. if (process.env.NODE_ENV !== 'production') {
  75. process.env.NODE_ENV !== "production" ? warning(!(typeof rowKey === 'function' && rowKey.length > 1), 'usage', '`index` parameter of `rowKey` function is deprecated. There is no guarantee that it will work as expected.') : void 0;
  76. }
  77. const baseColumns = React.useMemo(() => columns || (0, _useColumns.convertChildrenToColumns)(children), [columns, children]);
  78. const needResponsive = React.useMemo(() => baseColumns.some(col => col.responsive), [baseColumns]);
  79. const screens = (0, _useBreakpoint.default)(needResponsive);
  80. const mergedColumns = React.useMemo(() => {
  81. const matched = new Set(Object.keys(screens).filter(m => screens[m]));
  82. return baseColumns.filter(c => !c.responsive || c.responsive.some(r => matched.has(r)));
  83. }, [baseColumns, screens]);
  84. const tableProps = (0, _omit.default)(props, ['className', 'style', 'columns']);
  85. const {
  86. locale: contextLocale = _en_US.default,
  87. direction,
  88. table,
  89. renderEmpty,
  90. getPrefixCls,
  91. getPopupContainer: getContextPopupContainer
  92. } = React.useContext(_context.ConfigContext);
  93. const mergedSize = (0, _useSize.default)(customizeSize);
  94. const tableLocale = Object.assign(Object.assign({}, contextLocale.Table), locale);
  95. const rawData = dataSource || EMPTY_LIST;
  96. const prefixCls = getPrefixCls('table', customizePrefixCls);
  97. const dropdownPrefixCls = getPrefixCls('dropdown', customizeDropdownPrefixCls);
  98. const [, token] = (0, _internal.useToken)();
  99. const rootCls = (0, _useCSSVarCls.default)(prefixCls);
  100. const [wrapCSSVar, hashId, cssVarCls] = (0, _style.default)(prefixCls, rootCls);
  101. const mergedExpandable = Object.assign(Object.assign({
  102. childrenColumnName: legacyChildrenColumnName,
  103. expandIconColumnIndex
  104. }, expandable), {
  105. expandIcon: (_a = expandable === null || expandable === void 0 ? void 0 : expandable.expandIcon) !== null && _a !== void 0 ? _a : (_b = table === null || table === void 0 ? void 0 : table.expandable) === null || _b === void 0 ? void 0 : _b.expandIcon
  106. });
  107. const {
  108. childrenColumnName = 'children'
  109. } = mergedExpandable;
  110. const expandType = React.useMemo(() => {
  111. if (rawData.some(item => item === null || item === void 0 ? void 0 : item[childrenColumnName])) {
  112. return 'nest';
  113. }
  114. if (expandedRowRender || (expandable === null || expandable === void 0 ? void 0 : expandable.expandedRowRender)) {
  115. return 'row';
  116. }
  117. return null;
  118. }, [rawData]);
  119. const internalRefs = {
  120. body: React.useRef(null)
  121. };
  122. // ============================ Width =============================
  123. const getContainerWidth = (0, _useContainerWidth.default)(prefixCls);
  124. // ============================= Refs =============================
  125. const rootRef = React.useRef(null);
  126. const tblRef = React.useRef(null);
  127. (0, _useProxyImperativeHandle.default)(ref, () => Object.assign(Object.assign({}, tblRef.current), {
  128. nativeElement: rootRef.current
  129. }));
  130. // ============================ RowKey ============================
  131. const getRowKey = React.useMemo(() => {
  132. if (typeof rowKey === 'function') {
  133. return rowKey;
  134. }
  135. return record => record === null || record === void 0 ? void 0 : record[rowKey];
  136. }, [rowKey]);
  137. const [getRecordByKey] = (0, _useLazyKVMap.default)(rawData, childrenColumnName, getRowKey);
  138. // ============================ Events =============================
  139. const changeEventInfo = {};
  140. const triggerOnChange = (info, action, reset = false) => {
  141. var _a, _b, _c, _d;
  142. const changeInfo = Object.assign(Object.assign({}, changeEventInfo), info);
  143. if (reset) {
  144. (_a = changeEventInfo.resetPagination) === null || _a === void 0 ? void 0 : _a.call(changeEventInfo);
  145. // Reset event param
  146. if ((_b = changeInfo.pagination) === null || _b === void 0 ? void 0 : _b.current) {
  147. changeInfo.pagination.current = 1;
  148. }
  149. // Trigger pagination events
  150. if (pagination) {
  151. (_c = pagination.onChange) === null || _c === void 0 ? void 0 : _c.call(pagination, 1, (_d = changeInfo.pagination) === null || _d === void 0 ? void 0 : _d.pageSize);
  152. }
  153. }
  154. if (scroll && scroll.scrollToFirstRowOnChange !== false && internalRefs.body.current) {
  155. (0, _scrollTo.default)(0, {
  156. getContainer: () => internalRefs.body.current
  157. });
  158. }
  159. onChange === null || onChange === void 0 ? void 0 : onChange(changeInfo.pagination, changeInfo.filters, changeInfo.sorter, {
  160. currentDataSource: (0, _useFilter.getFilterData)((0, _useSorter.getSortData)(rawData, changeInfo.sorterStates, childrenColumnName), changeInfo.filterStates, childrenColumnName),
  161. action
  162. });
  163. };
  164. /**
  165. * Controlled state in `columns` is not a good idea that makes too many code (1000+ line?) to read
  166. * state out and then put it back to title render. Move these code into `hooks` but still too
  167. * complex. We should provides Table props like `sorter` & `filter` to handle control in next big
  168. * version.
  169. */
  170. // ============================ Sorter =============================
  171. const onSorterChange = (sorter, sorterStates) => {
  172. triggerOnChange({
  173. sorter,
  174. sorterStates
  175. }, 'sort', false);
  176. };
  177. const [transformSorterColumns, sortStates, sorterTitleProps, getSorters] = (0, _useSorter.default)({
  178. prefixCls,
  179. mergedColumns,
  180. onSorterChange,
  181. sortDirections: sortDirections || ['ascend', 'descend'],
  182. tableLocale,
  183. showSorterTooltip
  184. });
  185. const sortedData = React.useMemo(() => (0, _useSorter.getSortData)(rawData, sortStates, childrenColumnName), [rawData, sortStates]);
  186. changeEventInfo.sorter = getSorters();
  187. changeEventInfo.sorterStates = sortStates;
  188. // ============================ Filter ============================
  189. const onFilterChange = (filters, filterStates) => {
  190. triggerOnChange({
  191. filters,
  192. filterStates
  193. }, 'filter', true);
  194. };
  195. const [transformFilterColumns, filterStates, filters] = (0, _useFilter.default)({
  196. prefixCls,
  197. locale: tableLocale,
  198. dropdownPrefixCls,
  199. mergedColumns,
  200. onFilterChange,
  201. getPopupContainer: getPopupContainer || getContextPopupContainer,
  202. rootClassName: (0, _classnames.default)(rootClassName, rootCls)
  203. });
  204. const mergedData = (0, _useFilter.getFilterData)(sortedData, filterStates, childrenColumnName);
  205. changeEventInfo.filters = filters;
  206. changeEventInfo.filterStates = filterStates;
  207. // ============================ Column ============================
  208. const columnTitleProps = React.useMemo(() => {
  209. const mergedFilters = {};
  210. Object.keys(filters).forEach(filterKey => {
  211. if (filters[filterKey] !== null) {
  212. mergedFilters[filterKey] = filters[filterKey];
  213. }
  214. });
  215. return Object.assign(Object.assign({}, sorterTitleProps), {
  216. filters: mergedFilters
  217. });
  218. }, [sorterTitleProps, filters]);
  219. const [transformTitleColumns] = (0, _useTitleColumns.default)(columnTitleProps);
  220. // ========================== Pagination ==========================
  221. const onPaginationChange = (current, pageSize) => {
  222. triggerOnChange({
  223. pagination: Object.assign(Object.assign({}, changeEventInfo.pagination), {
  224. current,
  225. pageSize
  226. })
  227. }, 'paginate');
  228. };
  229. const [mergedPagination, resetPagination] = (0, _usePagination.default)(mergedData.length, onPaginationChange, pagination);
  230. changeEventInfo.pagination = pagination === false ? {} : (0, _usePagination.getPaginationParam)(mergedPagination, pagination);
  231. changeEventInfo.resetPagination = resetPagination;
  232. // ============================= Data =============================
  233. const pageData = React.useMemo(() => {
  234. if (pagination === false || !mergedPagination.pageSize) {
  235. return mergedData;
  236. }
  237. const {
  238. current = 1,
  239. total,
  240. pageSize = _usePagination.DEFAULT_PAGE_SIZE
  241. } = mergedPagination;
  242. process.env.NODE_ENV !== "production" ? warning(current > 0, 'usage', '`current` should be positive number.') : void 0;
  243. // Dynamic table data
  244. if (mergedData.length < total) {
  245. if (mergedData.length > pageSize) {
  246. process.env.NODE_ENV !== "production" ? warning(false, 'usage', '`dataSource` length is less than `pagination.total` but large than `pagination.pageSize`. Please make sure your config correct data with async mode.') : void 0;
  247. return mergedData.slice((current - 1) * pageSize, current * pageSize);
  248. }
  249. return mergedData;
  250. }
  251. return mergedData.slice((current - 1) * pageSize, current * pageSize);
  252. }, [!!pagination, mergedData, mergedPagination === null || mergedPagination === void 0 ? void 0 : mergedPagination.current, mergedPagination === null || mergedPagination === void 0 ? void 0 : mergedPagination.pageSize, mergedPagination === null || mergedPagination === void 0 ? void 0 : mergedPagination.total]);
  253. // ========================== Selections ==========================
  254. const [transformSelectionColumns, selectedKeySet] = (0, _useSelection.default)({
  255. prefixCls,
  256. data: mergedData,
  257. pageData,
  258. getRowKey,
  259. getRecordByKey,
  260. expandType,
  261. childrenColumnName,
  262. locale: tableLocale,
  263. getPopupContainer: getPopupContainer || getContextPopupContainer
  264. }, rowSelection);
  265. const internalRowClassName = (record, index, indent) => {
  266. let mergedRowClassName;
  267. if (typeof rowClassName === 'function') {
  268. mergedRowClassName = (0, _classnames.default)(rowClassName(record, index, indent));
  269. } else {
  270. mergedRowClassName = (0, _classnames.default)(rowClassName);
  271. }
  272. return (0, _classnames.default)({
  273. [`${prefixCls}-row-selected`]: selectedKeySet.has(getRowKey(record, index))
  274. }, mergedRowClassName);
  275. };
  276. // ========================== Expandable ==========================
  277. // Pass origin render status into `rc-table`, this can be removed when refactor with `rc-table`
  278. mergedExpandable.__PARENT_RENDER_ICON__ = mergedExpandable.expandIcon;
  279. // Customize expandable icon
  280. mergedExpandable.expandIcon = mergedExpandable.expandIcon || expandIcon || (0, _ExpandIcon.default)(tableLocale);
  281. // Adjust expand icon index, no overwrite expandIconColumnIndex if set.
  282. if (expandType === 'nest' && mergedExpandable.expandIconColumnIndex === undefined) {
  283. mergedExpandable.expandIconColumnIndex = rowSelection ? 1 : 0;
  284. } else if (mergedExpandable.expandIconColumnIndex > 0 && rowSelection) {
  285. mergedExpandable.expandIconColumnIndex -= 1;
  286. }
  287. // Indent size
  288. if (typeof mergedExpandable.indentSize !== 'number') {
  289. mergedExpandable.indentSize = typeof indentSize === 'number' ? indentSize : 15;
  290. }
  291. // ============================ Render ============================
  292. const transformColumns = React.useCallback(innerColumns => transformTitleColumns(transformSelectionColumns(transformFilterColumns(transformSorterColumns(innerColumns)))), [transformSorterColumns, transformFilterColumns, transformSelectionColumns]);
  293. let topPaginationNode;
  294. let bottomPaginationNode;
  295. if (pagination !== false && (mergedPagination === null || mergedPagination === void 0 ? void 0 : mergedPagination.total)) {
  296. let paginationSize;
  297. if (mergedPagination.size) {
  298. paginationSize = mergedPagination.size;
  299. } else {
  300. paginationSize = mergedSize === 'small' || mergedSize === 'middle' ? 'small' : undefined;
  301. }
  302. const renderPagination = position => (/*#__PURE__*/React.createElement(_pagination.default, Object.assign({}, mergedPagination, {
  303. className: (0, _classnames.default)(`${prefixCls}-pagination ${prefixCls}-pagination-${position}`, mergedPagination.className),
  304. size: paginationSize
  305. })));
  306. const defaultPosition = direction === 'rtl' ? 'left' : 'right';
  307. const {
  308. position
  309. } = mergedPagination;
  310. if (position !== null && Array.isArray(position)) {
  311. const topPos = position.find(p => p.includes('top'));
  312. const bottomPos = position.find(p => p.includes('bottom'));
  313. const isDisable = position.every(p => `${p}` === 'none');
  314. if (!topPos && !bottomPos && !isDisable) {
  315. bottomPaginationNode = renderPagination(defaultPosition);
  316. }
  317. if (topPos) {
  318. topPaginationNode = renderPagination(topPos.toLowerCase().replace('top', ''));
  319. }
  320. if (bottomPos) {
  321. bottomPaginationNode = renderPagination(bottomPos.toLowerCase().replace('bottom', ''));
  322. }
  323. } else {
  324. bottomPaginationNode = renderPagination(defaultPosition);
  325. }
  326. }
  327. // >>>>>>>>> Spinning
  328. let spinProps;
  329. if (typeof loading === 'boolean') {
  330. spinProps = {
  331. spinning: loading
  332. };
  333. } else if (typeof loading === 'object') {
  334. spinProps = Object.assign({
  335. spinning: true
  336. }, loading);
  337. }
  338. const wrapperClassNames = (0, _classnames.default)(cssVarCls, rootCls, `${prefixCls}-wrapper`, table === null || table === void 0 ? void 0 : table.className, {
  339. [`${prefixCls}-wrapper-rtl`]: direction === 'rtl'
  340. }, className, rootClassName, hashId);
  341. const mergedStyle = Object.assign(Object.assign({}, table === null || table === void 0 ? void 0 : table.style), style);
  342. // ========== empty ==========
  343. const mergedEmptyNode = React.useMemo(() => {
  344. // When dataSource is null/undefined (detected by reference equality with EMPTY_LIST),
  345. // and the table is in a loading state, we only show the loading spinner without the empty placeholder.
  346. // For empty arrays (datasource={[]}), both loading and empty states would normally be shown.
  347. // discussion https://github.com/ant-design/ant-design/issues/54601#issuecomment-3158091383
  348. if ((spinProps === null || spinProps === void 0 ? void 0 : spinProps.spinning) && rawData === EMPTY_LIST) {
  349. return null;
  350. }
  351. if (typeof (locale === null || locale === void 0 ? void 0 : locale.emptyText) !== 'undefined') {
  352. return locale.emptyText;
  353. }
  354. return (renderEmpty === null || renderEmpty === void 0 ? void 0 : renderEmpty('Table')) || /*#__PURE__*/React.createElement(_defaultRenderEmpty.default, {
  355. componentName: "Table"
  356. });
  357. }, [spinProps === null || spinProps === void 0 ? void 0 : spinProps.spinning, rawData, locale === null || locale === void 0 ? void 0 : locale.emptyText, renderEmpty]);
  358. // ========================== Render ==========================
  359. const TableComponent = virtual ? _VirtualTable.default : _RcTable.default;
  360. // >>> Virtual Table props. We set height here since it will affect height collection
  361. const virtualProps = {};
  362. const listItemHeight = React.useMemo(() => {
  363. const {
  364. fontSize,
  365. lineHeight,
  366. lineWidth,
  367. padding,
  368. paddingXS,
  369. paddingSM
  370. } = token;
  371. const fontHeight = Math.floor(fontSize * lineHeight);
  372. switch (mergedSize) {
  373. case 'middle':
  374. return paddingSM * 2 + fontHeight + lineWidth;
  375. case 'small':
  376. return paddingXS * 2 + fontHeight + lineWidth;
  377. default:
  378. return padding * 2 + fontHeight + lineWidth;
  379. }
  380. }, [token, mergedSize]);
  381. if (virtual) {
  382. virtualProps.listItemHeight = listItemHeight;
  383. }
  384. return wrapCSSVar(/*#__PURE__*/React.createElement("div", {
  385. ref: rootRef,
  386. className: wrapperClassNames,
  387. style: mergedStyle
  388. }, /*#__PURE__*/React.createElement(_spin.default, Object.assign({
  389. spinning: false
  390. }, spinProps), topPaginationNode, /*#__PURE__*/React.createElement(TableComponent, Object.assign({}, virtualProps, tableProps, {
  391. ref: tblRef,
  392. columns: mergedColumns,
  393. direction: direction,
  394. expandable: mergedExpandable,
  395. prefixCls: prefixCls,
  396. className: (0, _classnames.default)({
  397. [`${prefixCls}-middle`]: mergedSize === 'middle',
  398. [`${prefixCls}-small`]: mergedSize === 'small',
  399. [`${prefixCls}-bordered`]: bordered,
  400. [`${prefixCls}-empty`]: rawData.length === 0
  401. }, cssVarCls, rootCls, hashId),
  402. data: pageData,
  403. rowKey: getRowKey,
  404. rowClassName: internalRowClassName,
  405. emptyText: mergedEmptyNode,
  406. // Internal
  407. internalHooks: _rcTable.INTERNAL_HOOKS,
  408. internalRefs: internalRefs,
  409. transformColumns: transformColumns,
  410. getContainerWidth: getContainerWidth,
  411. measureRowRender: measureRow => (/*#__PURE__*/React.createElement(_configProvider.default, {
  412. getPopupContainer: node => node
  413. }, measureRow))
  414. })), bottomPaginationNode)));
  415. };
  416. var _default = exports.default = /*#__PURE__*/React.forwardRef(InternalTable);