@vectara/vectara-ui
Version:
Vectara's design system, codified as a React and Sass component library
130 lines (129 loc) • 10.5 kB
JavaScript
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))] }))] })));
};