UNPKG

@awsui/components-react

Version:

AWS UI is a collection of [React](https://reactjs.org/) components that help create intuitive, responsive, and accessible user experiences for web applications. It is developed by Amazon Web Services (AWS). This work is available under the terms of the [A

121 lines (120 loc) • 10.6 kB
import { __assign, __rest } from "tslib"; import clsx from 'clsx'; import React, { useImperativeHandle, useRef } from 'react'; import Container from '../container/internal'; import { getBaseProps } from '../internal/base-component'; import ToolsHeader from './tools-header'; import Thead from './thead'; import StatusIndicator from '../status-indicator'; import { useContainerQuery } from '../internal/hooks/container-queries'; import { useTelemetry } from '../internal/hooks/use-telemetry'; import { supportsStickyPosition } from '../internal/utils/dom'; import SelectionControl from './selection-control'; import { getColumnKey, getItemKey } from './utils'; import { useRowEvents } from './use-row-events'; import { useFocusMove, useSelection, focusMarkers } from './use-selection'; import { useStickyHeader } from './use-sticky-header'; import { fireNonCancelableEvent } from '../internal/events'; import { isDevelopment } from '../internal/is-development'; import { useStickyScrollbar } from './use-sticky-scrollbar'; import { checkColumnWidths, ColumnWidthsProvider, DEFAULT_WIDTH } from './use-column-widths'; import { useAppLayoutContext } from '../internal/context/app-layout-context'; import { useScrollSync } from '../internal/hooks/use-scroll-sync'; import { ResizeTracker } from './resizer'; import styles from './styles.css.js'; var Table = React.forwardRef(function (_a, ref) { var header = _a.header, footer = _a.footer, empty = _a.empty, filter = _a.filter, pagination = _a.pagination, preferences = _a.preferences, _b = _a.items, items = _b === void 0 ? [] : _b, columnDefinitions = _a.columnDefinitions, trackBy = _a.trackBy, loading = _a.loading, loadingText = _a.loadingText, selectionType = _a.selectionType, _c = _a.selectedItems, selectedItems = _c === void 0 ? [] : _c, isItemDisabled = _a.isItemDisabled, ariaLabels = _a.ariaLabels, onSelectionChange = _a.onSelectionChange, onSortingChange = _a.onSortingChange, sortingColumn = _a.sortingColumn, sortingDescending = _a.sortingDescending, sortingDisabled = _a.sortingDisabled, visibleColumns = _a.visibleColumns, stickyHeader = _a.stickyHeader, stickyHeaderVerticalOffset = _a.stickyHeaderVerticalOffset, onRowClick = _a.onRowClick, onRowContextMenu = _a.onRowContextMenu, wrapLines = _a.wrapLines, resizableColumns = _a.resizableColumns, onColumnWidthsChange = _a.onColumnWidthsChange, rest = __rest(_a, ["header", "footer", "empty", "filter", "pagination", "preferences", "items", "columnDefinitions", "trackBy", "loading", "loadingText", "selectionType", "selectedItems", "isItemDisabled", "ariaLabels", "onSelectionChange", "onSortingChange", "sortingColumn", "sortingDescending", "sortingDisabled", "visibleColumns", "stickyHeader", "stickyHeaderVerticalOffset", "onRowClick", "onRowContextMenu", "wrapLines", "resizableColumns", "onColumnWidthsChange"]); useTelemetry('Table'); var _d = useContainerQuery(function (rect) { return rect.width; }), containerWidth = _d[0], wrapperRef = _d[1]; var baseProps = getBaseProps(rest); var _e = useFocusMove(selectionType, items.length), moveFocusDown = _e.moveFocusDown, moveFocusUp = _e.moveFocusUp, moveFocus = _e.moveFocus; var _f = useRowEvents({ onRowClick: onRowClick, onRowContextMenu: onRowContextMenu }), onRowClickHandler = _f.onRowClickHandler, onRowContextMenuHandler = _f.onRowContextMenuHandler; var visibleColumnDefinitions = visibleColumns ? columnDefinitions.filter(function (column) { return column.id && visibleColumns.indexOf(column.id) !== -1; }) : columnDefinitions; var _g = useSelection({ items: items, trackBy: trackBy, selectedItems: selectedItems, selectionType: selectionType, isItemDisabled: isItemDisabled, onSelectionChange: onSelectionChange, ariaLabels: ariaLabels }), isItemSelected = _g.isItemSelected, selectAllProps = _g.selectAllProps, getItemSelectionProps = _g.getItemSelectionProps, updateShiftToggle = _g.updateShiftToggle; if (loading) { selectAllProps.disabled = true; } stickyHeader = stickyHeader && supportsStickyPosition(); var theadRef = useRef(null); var secondaryTheadRef = useRef(null); var secondaryTableRef = useRef(null); var secondaryWrapperRef = useRef(null); var _h = useStickyHeader(theadRef, secondaryTheadRef, secondaryTableRef, wrapperRef, stickyHeader), scrollToRow = _h.scrollToRow, scrollToTop = _h.scrollToTop; useImperativeHandle(ref, function () { return ({ scrollToTop: scrollToTop }); }); var scrollbarRef = React.useRef(null); var scrollbarContentRef = React.useRef(null); var tableRef = React.useRef(null); var stickyOffsetBottom = useAppLayoutContext().stickyOffsetBottom; useStickyScrollbar(scrollbarRef, scrollbarContentRef, tableRef, wrapperRef, stickyOffsetBottom); useScrollSync([wrapperRef, scrollbarRef, secondaryWrapperRef], !supportsStickyPosition()); if (isDevelopment && resizableColumns) { checkColumnWidths(columnDefinitions); } var theadProps = { containerWidth: containerWidth, selectionType: selectionType, selectAllProps: selectAllProps, columnDefinitions: visibleColumnDefinitions, wrapLines: wrapLines, resizableColumns: resizableColumns, sortingColumn: sortingColumn, sortingDisabled: sortingDisabled, sortingDescending: sortingDescending, onSortingChange: onSortingChange, onFocusMove: moveFocus, onResizeFinish: function (newWidth) { var widthsDetail = columnDefinitions.map(function (column, index) { return newWidth[getColumnKey(column, index)] || column.width || DEFAULT_WIDTH; }); var widthsChanged = widthsDetail.some(function (width, index) { return columnDefinitions[index].width !== width; }); if (widthsChanged) { fireNonCancelableEvent(onColumnWidthsChange, { widths: widthsDetail }); } } }; return (React.createElement(ColumnWidthsProvider, { tableRef: tableRef, visibleColumnDefinitions: visibleColumnDefinitions, resizableColumns: resizableColumns, hasSelection: !!selectionType }, React.createElement(Container, __assign({}, baseProps, { className: clsx(baseProps.className, styles.root), header: React.createElement("div", null, (header || filter || pagination || preferences) && (React.createElement("div", { className: styles['header-controls'] }, React.createElement(ToolsHeader, { header: header, filter: filter, pagination: pagination, preferences: preferences }))), stickyHeader && (React.createElement("div", { className: styles['header-secondary'], ref: secondaryWrapperRef }, React.createElement("table", { "aria-hidden": true, className: clsx(styles.table, resizableColumns && styles['table-layout-fixed']), role: "table", ref: secondaryTableRef }, React.createElement(Thead, __assign({ ref: secondaryTheadRef, sticky: true }, theadProps)))))), disableHeaderPaddings: true, disableContentPaddings: true, footer: footer, __stickyHeader: stickyHeader, __stickyOffset: stickyHeaderVerticalOffset }, focusMarkers.root), React.createElement("div", null, React.createElement("div", { ref: wrapperRef, className: styles.wrapper }, React.createElement("table", { ref: tableRef, className: clsx(styles.table, resizableColumns && styles['table-layout-fixed']), role: "table" }, React.createElement(Thead, __assign({ ref: theadRef, hidden: stickyHeader }, theadProps)), React.createElement("tbody", null, loading || items.length === 0 ? (React.createElement("tr", null, React.createElement("td", { colSpan: selectionType ? visibleColumnDefinitions.length + 1 : visibleColumnDefinitions.length, className: styles['cell-merged'] }, React.createElement("div", { className: styles['cell-merged-content'], style: { width: (supportsStickyPosition() && containerWidth && Math.floor(containerWidth)) || undefined } }, loading ? (React.createElement(StatusIndicator, { type: "loading", className: styles.loading }, loadingText)) : (React.createElement("div", { className: styles.empty }, empty)))))) : (items.map(function (item, rowIndex) { var _a; var isSelected = selectionType && isItemSelected(item); return (React.createElement("tr", __assign({ key: getItemKey(trackBy, item, rowIndex), className: clsx(styles.row, (_a = {}, _a[styles['row-selected']] = isSelected, _a)), onFocus: function (_a) { var currentTarget = _a.currentTarget; return scrollToRow(currentTarget); } }, focusMarkers.item, { onClick: onRowClickHandler && onRowClickHandler.bind(null, rowIndex, item), onContextMenu: onRowContextMenuHandler && onRowContextMenuHandler.bind(null, rowIndex, item) }), selectionType !== undefined && (React.createElement(SelectionControl, __assign({ className: clsx(styles.cell, styles['body-cell'], styles['selection-control']), onFocusDown: moveFocusDown, onFocusUp: moveFocusUp, onShiftToggle: updateShiftToggle }, getItemSelectionProps(item)))), visibleColumnDefinitions.map(function (column, colIndex) { return (React.createElement("td", { key: getColumnKey(column, colIndex), style: resizableColumns ? {} : { width: column.width, minWidth: column.minWidth, maxWidth: column.maxWidth }, className: clsx(styles.cell, styles['body-cell'], wrapLines && styles['body-cell-wrap']) }, column.cell(item))); }))); })))), resizableColumns && React.createElement(ResizeTracker, null)), React.createElement("div", { ref: scrollbarRef, className: styles['sticky-scrollbar'] }, React.createElement("div", { ref: scrollbarContentRef, className: styles['sticky-scrollbar-content'] })))))); }); export default Table;