@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
JavaScript
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;