@rovula/ui 0.1.39 → 0.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/bundle.js +1 -1
- package/dist/cjs/bundle.js.map +1 -1
- package/dist/cjs/types/components/DataTable/DataTable.d.ts +10 -1
- package/dist/cjs/types/components/DataTable/DataTable.stories.d.ts +8 -0
- package/dist/components/DataTable/DataTable.js +16 -2
- package/dist/components/DataTable/DataTable.stories.js +15 -0
- package/dist/esm/bundle.js +1 -1
- package/dist/esm/bundle.js.map +1 -1
- package/dist/esm/types/components/DataTable/DataTable.d.ts +10 -1
- package/dist/esm/types/components/DataTable/DataTable.stories.d.ts +8 -0
- package/dist/index.d.ts +10 -1
- package/dist/src/theme/global.css +31 -31
- package/package.json +1 -1
- package/src/components/DataTable/DataTable.stories.tsx +53 -0
- package/src/components/DataTable/DataTable.tsx +41 -2
- package/src/theme/main-preset.js +4 -0
- package/src/theme/themes/variable.css +31 -31
|
@@ -52,6 +52,15 @@ export interface DataTableProps<TData, TValue> extends DataTableEditingProps<TDa
|
|
|
52
52
|
loading?: boolean;
|
|
53
53
|
/** Label for the initial-loading state (default: "Loading…"). */
|
|
54
54
|
loadingLabel?: string;
|
|
55
|
+
/** Icon rendered in the empty-state placeholder. Replaces the default `ClipboardList` icon. */
|
|
56
|
+
emptyIcon?: React.ReactNode;
|
|
57
|
+
/** Text rendered in the empty-state placeholder (default: "There is no information yet."). */
|
|
58
|
+
emptyText?: React.ReactNode;
|
|
59
|
+
/**
|
|
60
|
+
* Fully replaces the empty-state cell content. When provided, `emptyIcon` and
|
|
61
|
+
* `emptyText` are ignored.
|
|
62
|
+
*/
|
|
63
|
+
renderEmpty?: () => React.ReactNode;
|
|
55
64
|
/**
|
|
56
65
|
* When true, DataTable will only render a vertical window of rows based on
|
|
57
66
|
* the scroll position of its internal scroll container. This is a basic
|
|
@@ -197,4 +206,4 @@ export interface ColumnManagementOptions {
|
|
|
197
206
|
/** Show "Show all" button. @default true */
|
|
198
207
|
showAll?: boolean;
|
|
199
208
|
}
|
|
200
|
-
export declare function DataTable<TData, TValue>({ data, columns, manualSorting, onSorting, paginationMode, totalCount, pageIndex: controlledPageIndex, pageSize: controlledPageSize, onPaginationChange, pageSizeOptions, fetchMoreData, fetchMoreOffset, fetchingMore, fetchingMoreLabel, loading, loadingLabel, highlightRowId, scrollToHighlightOnMouseLeave, selectable, onRowSelectionChange, rowActions, reorderable, getRowId: getRowIdProp, onRowReorder, isRowReorderLocked, onRowClick, onCellClick, getSubRows, defaultExpanded, expanded: controlledExpanded, onExpandedChange, bordered, surface, striped, divided, rowClassName, cellClassName, headerCellClassName, headerClassName, headerRowClassName, sortIndicatorVisibility, tableLayout, columnManagement: columnManagementProp, resizable, columnMinSize, columnMaxSize, virtualized, virtualRowEstimate, className, enableEditing, editDisplayMode, editTrigger, onCellCommit, alwaysEditing, enableCellTabTraversal, editableColumnIds: editableColumnIdsProp, testId, }: DataTableProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
|
|
209
|
+
export declare function DataTable<TData, TValue>({ data, columns, manualSorting, onSorting, paginationMode, totalCount, pageIndex: controlledPageIndex, pageSize: controlledPageSize, onPaginationChange, pageSizeOptions, fetchMoreData, fetchMoreOffset, fetchingMore, fetchingMoreLabel, loading, loadingLabel, emptyIcon, emptyText, renderEmpty, highlightRowId, scrollToHighlightOnMouseLeave, selectable, onRowSelectionChange, rowActions, reorderable, getRowId: getRowIdProp, onRowReorder, isRowReorderLocked, onRowClick, onCellClick, getSubRows, defaultExpanded, expanded: controlledExpanded, onExpandedChange, bordered, surface, striped, divided, rowClassName, cellClassName, headerCellClassName, headerClassName, headerRowClassName, sortIndicatorVisibility, tableLayout, columnManagement: columnManagementProp, resizable, columnMinSize, columnMaxSize, virtualized, virtualRowEstimate, className, enableEditing, editDisplayMode, editTrigger, onCellCommit, alwaysEditing, enableCellTabTraversal, editableColumnIds: editableColumnIdsProp, testId, }: DataTableProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -48,6 +48,9 @@ declare const meta: {
|
|
|
48
48
|
fetchingMoreLabel?: string | undefined;
|
|
49
49
|
loading?: boolean | undefined;
|
|
50
50
|
loadingLabel?: string | undefined;
|
|
51
|
+
emptyIcon?: React.ReactNode;
|
|
52
|
+
emptyText?: React.ReactNode;
|
|
53
|
+
renderEmpty?: (() => React.ReactNode) | undefined;
|
|
51
54
|
virtualized?: boolean | undefined;
|
|
52
55
|
virtualRowEstimate?: number | undefined;
|
|
53
56
|
highlightRowId?: string | string[] | undefined;
|
|
@@ -165,6 +168,11 @@ export declare const PerformanceLargeDataset: StoryObj;
|
|
|
165
168
|
export declare const WithVirtualizedRows: StoryObj;
|
|
166
169
|
/** Checkbox selection — header checkbox selects all; row checkboxes select individually. */
|
|
167
170
|
export declare const WithSelection: StoryObj;
|
|
171
|
+
/**
|
|
172
|
+
* Select rows then hit "Delete selected" — the header checkbox should clear
|
|
173
|
+
* automatically once the rows are gone (regression test for stale selection state).
|
|
174
|
+
*/
|
|
175
|
+
export declare const WithSelectionAndDelete: StoryObj;
|
|
168
176
|
/**
|
|
169
177
|
* Row highlight + scroll — use `highlightRowId` to visually mark important rows
|
|
170
178
|
* (uses the same token as selected rows) and automatically scroll them into view.
|
|
@@ -336,7 +336,7 @@ function ManageColumnPanel({ table, onClose, maxListHeight = 400, options = {},
|
|
|
336
336
|
// ---------------------------------------------------------------------------
|
|
337
337
|
// DataTable
|
|
338
338
|
// ---------------------------------------------------------------------------
|
|
339
|
-
export function DataTable({ data, columns, manualSorting = false, onSorting, paginationMode = "infinite", totalCount, pageIndex: controlledPageIndex, pageSize: controlledPageSize, onPaginationChange, pageSizeOptions, fetchMoreData, fetchMoreOffset, fetchingMore = false, fetchingMoreLabel = "Loading more…", loading = false, loadingLabel = "Loading…", highlightRowId, scrollToHighlightOnMouseLeave = false, selectable = false, onRowSelectionChange, rowActions, reorderable = false, getRowId: getRowIdProp, onRowReorder, isRowReorderLocked, onRowClick, onCellClick, getSubRows, defaultExpanded, expanded: controlledExpanded, onExpandedChange, bordered = true, surface = "default", striped = false, divided = true, rowClassName, cellClassName, headerCellClassName, headerClassName, headerRowClassName, sortIndicatorVisibility = "hover", tableLayout = "auto", columnManagement: columnManagementProp = false, resizable = false, columnMinSize = 60, columnMaxSize = Number.MAX_SAFE_INTEGER, virtualized = false, virtualRowEstimate, className, enableEditing = false, editDisplayMode = "cell", editTrigger = "click", onCellCommit, alwaysEditing, enableCellTabTraversal, editableColumnIds: editableColumnIdsProp, testId, }) {
|
|
339
|
+
export function DataTable({ data, columns, manualSorting = false, onSorting, paginationMode = "infinite", totalCount, pageIndex: controlledPageIndex, pageSize: controlledPageSize, onPaginationChange, pageSizeOptions, fetchMoreData, fetchMoreOffset, fetchingMore = false, fetchingMoreLabel = "Loading more…", loading = false, loadingLabel = "Loading…", emptyIcon, emptyText = "There is no information yet.", renderEmpty, highlightRowId, scrollToHighlightOnMouseLeave = false, selectable = false, onRowSelectionChange, rowActions, reorderable = false, getRowId: getRowIdProp, onRowReorder, isRowReorderLocked, onRowClick, onCellClick, getSubRows, defaultExpanded, expanded: controlledExpanded, onExpandedChange, bordered = true, surface = "default", striped = false, divided = true, rowClassName, cellClassName, headerCellClassName, headerClassName, headerRowClassName, sortIndicatorVisibility = "hover", tableLayout = "auto", columnManagement: columnManagementProp = false, resizable = false, columnMinSize = 60, columnMaxSize = Number.MAX_SAFE_INTEGER, virtualized = false, virtualRowEstimate, className, enableEditing = false, editDisplayMode = "cell", editTrigger = "click", onCellCommit, alwaysEditing, enableCellTabTraversal, editableColumnIds: editableColumnIdsProp, testId, }) {
|
|
340
340
|
var _a;
|
|
341
341
|
// scrollable container ref — lives on the wrapper div, not tbody
|
|
342
342
|
const scrollRef = useRef(null);
|
|
@@ -538,6 +538,20 @@ export function DataTable({ data, columns, manualSorting = false, onSorting, pag
|
|
|
538
538
|
useEffect(() => {
|
|
539
539
|
onRowSelectionChange === null || onRowSelectionChange === void 0 ? void 0 : onRowSelectionChange(rowSelection);
|
|
540
540
|
}, [rowSelection, onRowSelectionChange]);
|
|
541
|
+
// Prune stale selection keys when rows are removed (e.g. after deleting selected rows).
|
|
542
|
+
useEffect(() => {
|
|
543
|
+
if (!selectable)
|
|
544
|
+
return;
|
|
545
|
+
const currentIds = new Set(table.getRowModel().rows.map((r) => r.id));
|
|
546
|
+
setRowSelection((prev) => {
|
|
547
|
+
const pruned = Object.fromEntries(Object.entries(prev).filter(([id]) => currentIds.has(id)));
|
|
548
|
+
// Avoid re-render if nothing changed.
|
|
549
|
+
if (Object.keys(pruned).length === Object.keys(prev).length)
|
|
550
|
+
return prev;
|
|
551
|
+
return pruned;
|
|
552
|
+
});
|
|
553
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
554
|
+
}, [data, selectable]);
|
|
541
555
|
// Infinite scroll — listener on the wrapper div
|
|
542
556
|
useEffect(() => {
|
|
543
557
|
if (paginationMode !== "infinite")
|
|
@@ -1003,7 +1017,7 @@ export function DataTable({ data, columns, manualSorting = false, onSorting, pag
|
|
|
1003
1017
|
cellClassName,
|
|
1004
1018
|
onCellClick,
|
|
1005
1019
|
}) }, row.id));
|
|
1006
|
-
}))) : loading ? (_jsx(TableRow, { className: "h-full hover:bg-transparent", divided: false, children: _jsx(TableCell, { colSpan: finalColumns.length, className: "typography-body1 text-text-g-contrast-medium text-center h-full min-h-[200px]", children: _jsxs("div", { className: "flex flex-1 min-h-[200px] h-full flex-col items-center justify-center gap-3 py-16", role: "status", "aria-live": "polite", "aria-busy": "true", children: [_jsx(Loader2, { className: "size-8 shrink-0 animate-spin text-secondary-120", "aria-hidden": true }), loadingLabel] }) }) })) : (_jsx(TableRow, { className: "h-full hover:bg-transparent", divided: false, children: _jsx(TableCell, { colSpan: finalColumns.length, className: "typography-body1 text-text-g-contrast-medium text-center h-full", children:
|
|
1020
|
+
}))) : loading ? (_jsx(TableRow, { className: "h-full hover:bg-transparent", divided: false, children: _jsx(TableCell, { colSpan: finalColumns.length, className: "typography-body1 text-text-g-contrast-medium text-center h-full min-h-[200px]", children: _jsxs("div", { className: "flex flex-1 min-h-[200px] h-full flex-col items-center justify-center gap-3 py-16", role: "status", "aria-live": "polite", "aria-busy": "true", children: [_jsx(Loader2, { className: "size-8 shrink-0 animate-spin text-secondary-120", "aria-hidden": true }), loadingLabel] }) }) })) : (_jsx(TableRow, { className: "h-full hover:bg-transparent", divided: false, children: _jsx(TableCell, { colSpan: finalColumns.length, className: "typography-body1 text-text-g-contrast-medium text-center h-full", children: _jsx("div", { className: "flex flex-1 h-full flex-col items-center justify-center gap-3 py-16", children: renderEmpty ? (renderEmpty()) : (_jsxs(_Fragment, { children: [emptyIcon !== undefined ? (emptyIcon) : (_jsx(ClipboardList, { className: "w-8 text-secondary-120" })), emptyText] })) }) }) })) }), paginationMode === "infinite" &&
|
|
1007
1021
|
fetchingMore &&
|
|
1008
1022
|
!isEmpty &&
|
|
1009
1023
|
table.getVisibleLeafColumns().length > 0 && (_jsx("tfoot", { className: "[&_tr]:bg-table-c-row-bg", children: _jsx(TableRow, { divided: false, className: "hover:!bg-table-c-row-bg border-t border-t-table-c-row-line", children: _jsx(TableCell, { colSpan: table.getVisibleLeafColumns().length, className: "py-3 text-center typography-body3 text-text-g-contrast-medium bg-inherit", children: _jsxs("span", { role: "status", "aria-live": "polite", className: "inline-flex items-center justify-center gap-2", children: [_jsx(Loader2, { className: "size-4 shrink-0 animate-spin", "aria-hidden": true }), fetchingMoreLabel] }) }) }) }))] }) }), isPaginated && _jsx(TablePagination, Object.assign({}, paginationBarProps)), columnManagement && manageOpen && (_jsxs(Portal.Root, { children: [_jsx("div", { className: "fixed inset-0 z-40", onClick: () => setManageOpen(false) }), _jsx("div", { className: "fixed z-50 w-[460px] rounded-lg bg-modal-surface shadow-[0px_12px_24px_-4px_rgba(0,0,0,0.12)] overflow-hidden", style: {
|
|
@@ -417,6 +417,21 @@ export const WithSelection = {
|
|
|
417
417
|
.join(", ") || "–"] }), _jsx(DataTable, { columns: projectColumns, data: projectData, selectable: true, onRowSelectionChange: setSelected, striped: true, divided: true })] }));
|
|
418
418
|
},
|
|
419
419
|
};
|
|
420
|
+
/**
|
|
421
|
+
* Select rows then hit "Delete selected" — the header checkbox should clear
|
|
422
|
+
* automatically once the rows are gone (regression test for stale selection state).
|
|
423
|
+
*/
|
|
424
|
+
export const WithSelectionAndDelete = {
|
|
425
|
+
render: () => {
|
|
426
|
+
const [rows, setRows] = React.useState(projectData);
|
|
427
|
+
const [selected, setSelected] = React.useState({});
|
|
428
|
+
const selectedIds = Object.keys(selected).filter((k) => selected[k]);
|
|
429
|
+
const handleDelete = () => {
|
|
430
|
+
setRows((prev) => prev.filter((r) => !selected[r.id]));
|
|
431
|
+
};
|
|
432
|
+
return (_jsxs("div", { className: "flex flex-col gap-3 w-full h-full", children: [_jsxs("div", { className: "flex items-center gap-3 px-1", children: [_jsxs("p", { className: "typography-small2 text-text-g-contrast-high flex-1", children: ["Selected IDs: ", selectedIds.join(", ") || "–"] }), _jsxs(Button, { size: "sm", variant: "solid", color: "error", disabled: selectedIds.length === 0, onClick: handleDelete, startIcon: _jsx(Trash2, { className: "size-4" }), children: ["Delete selected (", selectedIds.length, ")"] }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => setRows(projectData), children: "Reset" })] }), _jsx(DataTable, { columns: projectColumns, data: rows, getRowId: (r) => r.id, selectable: true, onRowSelectionChange: setSelected, striped: true, divided: true })] }));
|
|
433
|
+
},
|
|
434
|
+
};
|
|
420
435
|
/**
|
|
421
436
|
* Row highlight + scroll — use `highlightRowId` to visually mark important rows
|
|
422
437
|
* (uses the same token as selected rows) and automatically scroll them into view.
|