UNPKG

@vectara/vectara-ui

Version:

Vectara's design system, codified as a React and Sass component library

130 lines (129 loc) 10.5 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; import { useState } from "react"; import classNames from "classnames"; import { VuiCheckbox, VuiTextInput } from "../form"; import { VuiSpacer } from "../spacer/Spacer"; import { VuiTableRowActions } from "./TableRowActions"; import { VuiTableCell } from "./TableCell"; import { VuiTableHeaderCell } from "./TableHeaderCell"; import { VuiTablePagination } from "./TablePagination"; import { VuiTablePager } from "./TablePager"; import { VuiFlexContainer } from "../flex/FlexContainer"; import { VuiFlexItem } from "../flex/FlexItem"; import { VuiText } from "../typography/Text"; import { VuiTableBulkActions } from "./TableBulkActions"; import { VuiSpinner } from "../spinner/Spinner"; import { VuiTableContent } from "./TableContent"; import { VuiButtonSecondary } from "../button/ButtonSecondary"; const verticalAlignToClass = { top: "vuiTable--verticalAlignTop", middle: "vuiTable--verticalAlignMiddle", bottom: "vuiTable--verticalAlignBottom" }; // Type guard to determine type of pagination. const isComplexPagination = (pagination) => { return pagination.onSelectPage !== undefined; }; const extractId = (row, idField) => { return typeof idField === "function" ? idField(row) : row[idField]; }; // https://github.com/typescript-eslint/typescript-eslint/issues/4062 // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint export const VuiTable = (_a) => { var { isLoading, idField, rowDecorator, columns, rows, actions, actionsTestIdProvider, pagination, selection, search, customControls, onSort, onReload, content, className, fluid, isDisabled = false, bodyStyle } = _a, rest = __rest(_a, ["isLoading", "idField", "rowDecorator", "columns", "rows", "actions", "actionsTestIdProvider", "pagination", "selection", "search", "customControls", "onSort", "onReload", "content", "className", "fluid", "isDisabled", "bodyStyle"]); const [rowBeingActedUpon, setRowBeingActedUpon] = useState(undefined); const { bulkActions, onSelectRow, selectedRows } = selection || {}; const { value: searchValue } = search || {}; const isEmpty = !isLoading && rows.length === 0; // The user interacts with the table rows by selecting them or performing actions on them. // This is only allowed if there is no “content” (which is an error or similar state that // replaces the rows), and if it’s not in a loading state or empty state. const isInteractive = Boolean(!content && !isLoading && !isEmpty); const allRowsSelected = (selectedRows === null || selectedRows === void 0 ? void 0 : selectedRows.length) === rows.length; const selectedIds = (selectedRows === null || selectedRows === void 0 ? void 0 : selectedRows.reduce((acc, row) => { acc[extractId(row, idField)] = true; return acc; }, {})) || {}; const hasSearch = search !== undefined; const hasBulkActions = bulkActions !== undefined; const columnCount = columns.length + (onSelectRow ? 1 : 0) + (actions ? 1 : 0); const classes = classNames("vuiTable", (bodyStyle === null || bodyStyle === void 0 ? void 0 : bodyStyle.verticalAlign) && verticalAlignToClass[bodyStyle.verticalAlign], { "vuiTable--fluid": fluid }, className); let tableContent; if (content) { tableContent = _jsx(VuiTableContent, Object.assign({ colSpan: columnCount }, { children: content })); } else if (isLoading) { tableContent = (_jsxs(VuiTableContent, Object.assign({ colSpan: columnCount }, { children: [_jsx(VuiFlexItem, Object.assign({ grow: false }, { children: _jsx(VuiSpinner, { size: "xs" }) })), _jsx(VuiFlexItem, Object.assign({ grow: false }, { children: _jsx(VuiText, { children: _jsx("p", { children: "Loading" }) }) }))] }))); } else if (searchValue && isEmpty) { tableContent = (_jsx(VuiTableContent, Object.assign({ colSpan: columnCount }, { children: _jsx(VuiFlexItem, Object.assign({ grow: false }, { children: _jsx(VuiText, { children: _jsx("p", { children: "No matches found" }) }) })) }))); } else { tableContent = rows.map((row, rowIndex) => { var _a, _b, _c; const rowId = extractId(row, idField); const rowAttributes = (_a = rowDecorator === null || rowDecorator === void 0 ? void 0 : rowDecorator(row)) !== null && _a !== void 0 ? _a : {}; const { className: rowClassNameAttribute } = rowAttributes, restRowAttributes = __rest(rowAttributes, ["className"]); const rowClassName = classNames(rowClassNameAttribute, { "vuiTableRow-isBeingActedUpon": rowBeingActedUpon === row }); return (_jsxs("tr", Object.assign({ className: rowClassName }, restRowAttributes, { children: [onSelectRow && (_jsx("td", { children: _jsx(VuiTableCell, { children: _jsx(VuiCheckbox, { checked: (_b = selectedIds[rowId]) !== null && _b !== void 0 ? _b : false, onChange: () => { if (selectedIds[rowId]) { delete selectedIds[rowId]; } else { selectedIds[rowId] = true; } const selectedRowIds = Object.keys(selectedIds); // Map selected row IDs to selected rows. const selectedRows = selectedRowIds.map((id) => rows.find((row) => row.id === id)); onSelectRow(selectedRows); } }) }) })), columns.map((column) => { const { name, render, className } = column; return (_jsx("td", Object.assign({ className: className }, { children: _jsx(VuiTableCell, { children: render ? render(row, rowIndex) : row[column.name] }) }), name)); }), actions && (_jsx("td", { children: _jsx(VuiTableRowActions, { row: row, actions: actions, onToggle: (isSelected) => { if (isSelected) { setRowBeingActedUpon(row); } else { setRowBeingActedUpon(undefined); } }, testId: (_c = actionsTestIdProvider === null || actionsTestIdProvider === void 0 ? void 0 : actionsTestIdProvider(row)) !== null && _c !== void 0 ? _c : undefined }) }))] }), rowId)); }); } return ( // @ts-expect-error React doesn't support inert yet _jsxs("div", Object.assign({ className: "vuiTableWrapper", inert: isDisabled ? "" : null }, { children: [isDisabled && _jsx("div", { className: "vuiTableBlock" }), (hasSearch || customControls || (hasBulkActions && selectedRows && selectedRows.length > 0) || Boolean(onReload)) && (_jsxs(_Fragment, { children: [_jsxs(VuiFlexContainer, Object.assign({ spacing: "s", alignItems: "center" }, { children: [selectedRows && selectedRows.length > 0 && hasBulkActions && (_jsx(VuiFlexItem, Object.assign({ grow: false, shrink: false }, { children: _jsx(VuiTableBulkActions, { selectedRows: selectedRows, actions: bulkActions }) }))), hasSearch && (_jsx(VuiFlexItem, Object.assign({ grow: 1, shrink: false }, { children: _jsx(VuiTextInput, Object.assign({ fullWidth: true }, search)) }))), customControls && (_jsx(VuiFlexItem, Object.assign({ grow: false, shrink: false }, { children: customControls }))), onReload && (_jsx(VuiFlexItem, Object.assign({ grow: 1, shrink: false }, { children: _jsx(VuiFlexContainer, Object.assign({ justifyContent: "end" }, { children: _jsx(VuiButtonSecondary, Object.assign({ color: "neutral", onClick: () => onReload() }, { children: "Reload" })) })) })))] })), _jsx(VuiSpacer, { size: "s" })] })), _jsxs("table", Object.assign({ className: classes }, rest, { children: [_jsx("thead", { children: _jsxs("tr", { children: [onSelectRow && (_jsx("th", Object.assign({ className: "vuiTableHeaderSelect" }, { children: _jsx(VuiTableCell, { children: _jsx(VuiCheckbox, { disabled: !isInteractive, checked: isInteractive ? allRowsSelected : false, onChange: () => { let newSelectedRows; if (allRowsSelected) { newSelectedRows = []; } else { newSelectedRows = rows.reduce((acc, row) => { acc.push(row); return acc; }, []); } onSelectRow(newSelectedRows); } }) }) }))), columns.map((column) => { const { name, header, width } = column; const styles = width ? { width } : undefined; return (_jsx("th", Object.assign({ style: styles }, { children: _jsx(VuiTableHeaderCell, { name: name, header: header, onSort: onSort }) }), name)); }), actions && _jsx("th", { className: "vuiTableHeaderActions" })] }) }), _jsx("tbody", { children: tableContent })] })), !pagination ? undefined : isComplexPagination(pagination) ? (_jsxs(_Fragment, { children: [_jsx(VuiSpacer, { size: "xs" }), _jsx(VuiTablePagination, Object.assign({ isDisabled: !isInteractive }, pagination))] })) : (_jsxs(_Fragment, { children: [_jsx(VuiSpacer, { size: "xs" }), _jsx(VuiTablePager, Object.assign({ isDisabled: !isInteractive }, pagination))] }))] }))); };