UNPKG

@atlaskit/dynamic-table

Version:

A dynamic table displays rows of data with built-in pagination, sorting, and re-ordering functionality.

274 lines (271 loc) 10.4 kB
import _extends from "@babel/runtime/helpers/extends"; import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties"; import _slicedToArray from "@babel/runtime/helpers/slicedToArray"; var _excluded = ["isRankable", "isRanking", "onRankStart", "onRankEnd", "isRankingDisabled"]; import React, { forwardRef, lazy, Suspense, useEffect, useRef, useState } from 'react'; import { usePlatformLeafEventHandler } from '@atlaskit/analytics-next/usePlatformLeafEventHandler'; import noop from '@atlaskit/ds-lib/noop'; import { assertIsSortable } from '../internal/assert-is-sortable'; import { getPageRows } from '../internal/get-page-rows'; import { validateSortKey } from '../internal/validate-sort-key'; import { Caption } from '../styled/caption'; import { EmptyViewContainer } from '../styled/empty-view-container'; import { EmptyViewWithFixedHeight } from '../styled/empty-view-with-fixed-height'; import { PaginationWrapper } from '../styled/pagination-wrapper'; import { Table } from '../styled/table'; import Body from './body'; import { ErrorBoundary } from './error-boundary'; import LoadingContainer from './loading-container'; import LoadingContainerAdvanced from './loading-container-advanced'; import ManagedPagination from './managed-pagination'; import TableHead from './table-head'; function toggleSortOrder(currentSortOrder) { switch (currentSortOrder) { case 'DESC': return 'ASC'; case 'ASC': return 'DESC'; default: return currentSortOrder; } } var DynamicTable = function DynamicTable(_ref) { var caption = _ref.caption, head = _ref.head, highlightedRowIndex = _ref.highlightedRowIndex, rows = _ref.rows, sortKey = _ref.sortKey, sortOrder = _ref.sortOrder, loadingLabel = _ref.loadingLabel, onPageRowsUpdate = _ref.onPageRowsUpdate, testId = _ref.testId, passedDownTotalRows = _ref.totalRows, label = _ref.label, _ref$isLoading = _ref.isLoading, isLoading = _ref$isLoading === void 0 ? false : _ref$isLoading, _ref$isFixedSize = _ref.isFixedSize, isFixedSize = _ref$isFixedSize === void 0 ? false : _ref$isFixedSize, _ref$rowsPerPage = _ref.rowsPerPage, rowsPerPage = _ref$rowsPerPage === void 0 ? Infinity : _ref$rowsPerPage, _ref$onSetPage = _ref.onSetPage, onSetPage = _ref$onSetPage === void 0 ? noop : _ref$onSetPage, _ref$onSort = _ref.onSort, providedOnSort = _ref$onSort === void 0 ? noop : _ref$onSort, _ref$page = _ref.page, page = _ref$page === void 0 ? 1 : _ref$page, emptyView = _ref.emptyView, _ref$isRankable = _ref.isRankable, isRankable = _ref$isRankable === void 0 ? false : _ref$isRankable, _ref$isRankingDisable = _ref.isRankingDisabled, isRankingDisabled = _ref$isRankingDisable === void 0 ? false : _ref$isRankingDisable, _ref$onRankStart = _ref.onRankStart, onRankStart = _ref$onRankStart === void 0 ? noop : _ref$onRankStart, _ref$onRankEnd = _ref.onRankEnd, providedOnRankEnd = _ref$onRankEnd === void 0 ? noop : _ref$onRankEnd, loadingSpinnerSize = _ref.loadingSpinnerSize, _ref$paginationi18n = _ref.paginationi18n, paginationi18n = _ref$paginationi18n === void 0 ? { prev: 'Previous Page', next: 'Next Page', label: 'Pagination', pageLabel: 'Page' } : _ref$paginationi18n; var _useState = useState(false), _useState2 = _slicedToArray(_useState, 2), isRanking = _useState2[0], setIsRanking = _useState2[1]; var tableBodyRef = useRef(null); var onSort = usePlatformLeafEventHandler({ fn: providedOnSort, action: 'sorted', componentName: 'dynamicTable', packageName: "@atlaskit/dynamic-table", packageVersion: "19.3.3" }); var onRankEnd = usePlatformLeafEventHandler({ fn: providedOnRankEnd, action: 'ranked', componentName: 'dynamicTable', packageName: "@atlaskit/dynamic-table", packageVersion: "19.3.3" }); useEffect(function () { validateSortKey(sortKey, head); assertIsSortable(head); }, [sortKey, head]); var onSortHandler = function onSortHandler(item) { return function () { var key = item.key; if (!key) { return; } if (onSort && isRankable && key === sortKey && sortOrder === 'DESC') { onSort({ key: null, sortOrder: null, item: item }); return; } var sortOrderFormatted = key !== sortKey ? 'ASC' : toggleSortOrder(sortOrder); if (onSort) { onSort({ key: key, item: item, sortOrder: sortOrderFormatted }); } }; }; var onSetPageHandler = function onSetPageHandler(page, event) { onSetPage(page, event); }; var onRankStartHandler = function onRankStartHandler(params) { setIsRanking(true); onRankStart(params); }; var onRankEndHandler = function onRankEndHandler(params) { setIsRanking(false); onRankEnd(params); }; var getSpinnerSize = function getSpinnerSize() { if (loadingSpinnerSize) { return loadingSpinnerSize; } return getPageRows(rows || [], page, rowsPerPage).length > 2 ? 'large' : 'small'; }; var renderEmptyBody = function renderEmptyBody() { if (isLoading) { return /*#__PURE__*/React.createElement(EmptyViewWithFixedHeight, { testId: testId }); } return emptyView && /*#__PURE__*/React.createElement(EmptyViewContainer, { testId: testId }, emptyView); }; var rowsLength = rows && rows.length; var totalPages; // set a flag to denote the dynamic table might get only one page of data // for paginated data var isTotalPagesControlledExternally = false; if (passedDownTotalRows && Number.isInteger(passedDownTotalRows) && rowsPerPage && rowsLength && rowsLength <= passedDownTotalRows) { /** * If total number of rows / records have been passed down as prop * Then table is being fed paginated data from server or other sources * In this case, we want to respect information passed down by server or external source * Rather than relying on our computation based on number of rows */ totalPages = Math.ceil(passedDownTotalRows / rowsPerPage); isTotalPagesControlledExternally = true; } else { totalPages = rowsLength && rowsPerPage ? Math.ceil(rowsLength / rowsPerPage) : 0; } totalPages = totalPages < 1 ? 1 : totalPages; var getPageNumber = page > totalPages ? totalPages : page; // page! required, because typescript can't yet see defaultProps to know that this won't be undefined var rowsExist = !!rowsLength; var spinnerSize = getSpinnerSize(); var emptyBody = renderEmptyBody(); return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(LoadingContainerAdvanced, { isLoading: isLoading && rowsExist, spinnerSize: spinnerSize, targetRef: function targetRef() { return tableBodyRef.current; }, testId: testId, loadingLabel: loadingLabel }, /*#__PURE__*/React.createElement(Table, { isFixedSize: isFixedSize, "aria-label": label, hasDataRow: rowsExist, testId: testId, isLoading: isLoading }, !!caption && /*#__PURE__*/React.createElement(Caption, null, caption), head && /*#__PURE__*/React.createElement(TableHead, { head: head, onSort: onSortHandler, sortKey: sortKey, sortOrder: sortOrder, isRanking: isRanking, isRankable: isRankable, isFixedSize: isFixedSize, testId: testId }), rowsExist && /*#__PURE__*/React.createElement(TableBody, { ref: tableBodyRef, highlightedRowIndex: highlightedRowIndex, rows: rows, head: head, sortKey: sortKey, sortOrder: sortOrder, rowsPerPage: rowsPerPage, page: getPageNumber, isFixedSize: isFixedSize || false, onPageRowsUpdate: onPageRowsUpdate, isTotalPagesControlledExternally: isTotalPagesControlledExternally, testId: testId, isRankable: isRankable, isRanking: isRanking, onRankStart: onRankStartHandler, onRankEnd: onRankEndHandler, isRankingDisabled: isRankingDisabled || isLoading || false }))), totalPages <= 1 ? null : /*#__PURE__*/ // only show pagination if there's MORE than 1 page React.createElement(PaginationWrapper, { testId: testId }, /*#__PURE__*/React.createElement(ManagedPagination, { value: getPageNumber, onChange: onSetPageHandler, total: totalPages, i18n: paginationi18n, isDisabled: isLoading, testId: testId })), !rowsExist && emptyBody && /*#__PURE__*/React.createElement(LoadingContainer, { isLoading: isLoading, spinnerSize: "large", testId: testId, loadingLabel: loadingLabel }, emptyBody)); }; var RankableTableBody = /*#__PURE__*/lazy(function () { return import( /* webpackChunkName: '@atlaskit-internal_dynamic-table' */'./rankable/body'); }); var TableBody = /*#__PURE__*/forwardRef(function TableBody(_ref2, ref) { var _ref2$isRankable = _ref2.isRankable, isRankable = _ref2$isRankable === void 0 ? false : _ref2$isRankable, isRanking = _ref2.isRanking, onRankStart = _ref2.onRankStart, onRankEnd = _ref2.onRankEnd, isRankingDisabled = _ref2.isRankingDisabled, bodyProps = _objectWithoutProperties(_ref2, _excluded); var canRank = isRankable && !bodyProps.sortKey; /** * React 16 does not support SSR for lazy components, * so we avoid rendering the `Suspense` on the server. */ var _useState3 = useState(false), _useState4 = _slicedToArray(_useState3, 2), canRenderRankable = _useState4[0], setCanRenderRankable = _useState4[1]; useEffect(function () { if (canRank) { setCanRenderRankable(true); } }, [canRank]); var nonRankableBody = /*#__PURE__*/React.createElement(Body, _extends({ ref: ref }, bodyProps)); return canRank && canRenderRankable ? /*#__PURE__*/React.createElement(ErrorBoundary, { fallback: nonRankableBody }, /*#__PURE__*/React.createElement(Suspense, { fallback: nonRankableBody }, /*#__PURE__*/React.createElement(RankableTableBody, _extends({ ref: ref }, bodyProps, { isRanking: isRanking, onRankStart: onRankStart, onRankEnd: onRankEnd, isRankingDisabled: isRankingDisabled })))) : nonRankableBody; }); // eslint-disable-next-line @repo/internal/react/require-jsdoc export default DynamicTable;