@nuvui/table 0.0.0-stage → 0.1.1

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.
Files changed (40) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -2
  3. package/dist/components/data-table/content.d.ts +67 -0
  4. package/dist/components/data-table/content.js +278 -0
  5. package/dist/components/data-table/context.d.ts +23 -0
  6. package/dist/components/data-table/context.js +51 -0
  7. package/dist/components/data-table/create-data-table-hook.d.ts +78 -0
  8. package/dist/components/data-table/create-data-table-hook.js +103 -0
  9. package/dist/components/data-table/data-table.d.ts +76 -0
  10. package/dist/components/data-table/data-table.js +178 -0
  11. package/dist/components/data-table/header.d.ts +23 -0
  12. package/dist/components/data-table/header.js +120 -0
  13. package/dist/components/data-table/index.d.ts +11 -0
  14. package/dist/components/data-table/index.js +10 -0
  15. package/dist/components/data-table/labels.d.ts +50 -0
  16. package/dist/components/data-table/labels.js +35 -0
  17. package/dist/components/data-table/pagination.d.ts +18 -0
  18. package/dist/components/data-table/pagination.js +126 -0
  19. package/dist/components/data-table/selection.d.ts +48 -0
  20. package/dist/components/data-table/selection.js +153 -0
  21. package/dist/components/data-table/toolbar.d.ts +51 -0
  22. package/dist/components/data-table/toolbar.js +123 -0
  23. package/dist/components/data-table/use-data-table-request.d.ts +44 -0
  24. package/dist/components/data-table/use-data-table-request.js +72 -0
  25. package/dist/components/table/index.d.ts +2 -0
  26. package/dist/components/table/index.js +2 -0
  27. package/dist/components/table/table.d.ts +100 -0
  28. package/dist/components/table/table.js +130 -0
  29. package/dist/css/data-table.css +278 -0
  30. package/dist/css/table.css +164 -0
  31. package/dist/full.d.ts +264 -0
  32. package/dist/full.js +44 -0
  33. package/dist/index.d.ts +14 -0
  34. package/dist/index.js +11 -0
  35. package/dist/styles.css +441 -0
  36. package/dist/utils/cx.js +6 -0
  37. package/dist/utils/use-shift-click.js +32 -0
  38. package/dist/virtual.d.ts +42 -0
  39. package/dist/virtual.js +133 -0
  40. package/package.json +101 -3
@@ -0,0 +1,126 @@
1
+ "use client";
2
+ import { supports, useDataTableView } from "./context.js";
3
+ import { cx } from "../../utils/cx.js";
4
+ import { useId } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { Button } from "@nuvui/react/button";
7
+ import { NativeSelect } from "@nuvui/react/native-select";
8
+ //#region src/components/data-table/pagination.tsx
9
+ const paths = {
10
+ first: "M11 4l-4 4 4 4M5 4v8",
11
+ previous: "M10 4l-4 4 4 4",
12
+ next: "M6 4l4 4-4 4",
13
+ last: "M5 4l4 4-4 4M11 4v8"
14
+ };
15
+ function PageButton({ icon, label, disabled, onClick }) {
16
+ return /* @__PURE__ */ jsx(Button, {
17
+ intent: "ghost",
18
+ size: "sm",
19
+ className: "nuv-data-table__page-button",
20
+ "aria-label": label,
21
+ "aria-disabled": disabled || void 0,
22
+ onClick: () => {
23
+ if (!disabled) onClick();
24
+ },
25
+ children: /* @__PURE__ */ jsx("svg", {
26
+ "aria-hidden": "true",
27
+ className: "nuv-data-table__page-icon",
28
+ viewBox: "0 0 16 16",
29
+ width: "16",
30
+ height: "16",
31
+ fill: "none",
32
+ stroke: "currentColor",
33
+ strokeWidth: "1.5",
34
+ strokeLinecap: "round",
35
+ strokeLinejoin: "round",
36
+ children: /* @__PURE__ */ jsx("path", { d: paths[icon] })
37
+ })
38
+ });
39
+ }
40
+ const defaultSizes = [
41
+ 10,
42
+ 20,
43
+ 50,
44
+ 100
45
+ ];
46
+ /**
47
+ * The bar under the table: rows per page, which rows are showing out of
48
+ * how many, and buttons for the first, previous, next and last page. It
49
+ * needs `rowPaginationFeature`, and shows nothing without it.
50
+ */
51
+ function DataTablePagination({ pageSizes = defaultSizes, className, ...props }) {
52
+ const { table, labels } = useDataTableView("DataTablePagination");
53
+ const id = useId();
54
+ if (!supports.pagination(table)) return null;
55
+ const { pageIndex, pageSize } = table.atoms.pagination.get();
56
+ const total = table.getRowCount();
57
+ const pages = Math.max(table.getPageCount(), 1);
58
+ const from = total === 0 ? 0 : pageIndex * pageSize + 1;
59
+ const to = Math.min((pageIndex + 1) * pageSize, total);
60
+ const sizes = pageSizes.includes(pageSize) ? pageSizes : [...pageSizes, pageSize].sort((a, b) => a - b);
61
+ const back = table.getCanPreviousPage();
62
+ const forward = table.getCanNextPage();
63
+ return /* @__PURE__ */ jsxs("div", {
64
+ role: "group",
65
+ "aria-label": labels.pagination,
66
+ className: cx("nuv-data-table__pagination", className),
67
+ ...props,
68
+ children: [
69
+ pageSizes.length > 0 ? /* @__PURE__ */ jsxs("div", {
70
+ className: "nuv-data-table__page-size",
71
+ children: [/* @__PURE__ */ jsx("label", {
72
+ htmlFor: id,
73
+ className: "nuv-data-table__page-size-label",
74
+ children: labels.rowsPerPage
75
+ }), /* @__PURE__ */ jsx(NativeSelect, {
76
+ id,
77
+ value: pageSize,
78
+ onChange: (event) => table.setPageSize(Number(event.target.value)),
79
+ children: sizes.map((size) => /* @__PURE__ */ jsx("option", {
80
+ value: size,
81
+ children: size
82
+ }, size))
83
+ })]
84
+ }) : null,
85
+ /* @__PURE__ */ jsx("span", {
86
+ className: "nuv-data-table__page-range",
87
+ children: labels.pageRange(from, to, total)
88
+ }),
89
+ /* @__PURE__ */ jsxs("div", {
90
+ className: "nuv-data-table__pages",
91
+ children: [
92
+ /* @__PURE__ */ jsx(PageButton, {
93
+ icon: "first",
94
+ label: labels.firstPage,
95
+ disabled: !back,
96
+ onClick: () => table.firstPage()
97
+ }),
98
+ /* @__PURE__ */ jsx(PageButton, {
99
+ icon: "previous",
100
+ label: labels.previousPage,
101
+ disabled: !back,
102
+ onClick: () => table.previousPage()
103
+ }),
104
+ /* @__PURE__ */ jsx("span", {
105
+ className: "nuv-data-table__page",
106
+ children: labels.page(pageIndex + 1, pages)
107
+ }),
108
+ /* @__PURE__ */ jsx(PageButton, {
109
+ icon: "next",
110
+ label: labels.nextPage,
111
+ disabled: !forward,
112
+ onClick: () => table.nextPage()
113
+ }),
114
+ /* @__PURE__ */ jsx(PageButton, {
115
+ icon: "last",
116
+ label: labels.lastPage,
117
+ disabled: !forward,
118
+ onClick: () => table.lastPage()
119
+ })
120
+ ]
121
+ })
122
+ ]
123
+ });
124
+ }
125
+ //#endregion
126
+ export { DataTablePagination };
@@ -0,0 +1,48 @@
1
+ import { Row, RowData, TableFeatures } from "@tanstack/react-table";
2
+ import { HTMLAttributes, ReactNode } from "react";
3
+ //#region src/components/data-table/selection.d.ts
4
+ export interface DataTableSelectAllProps {
5
+ className?: string;
6
+ }
7
+ /**
8
+ * The checkbox in the heading of the selection column. In a table with
9
+ * pages it selects the rows on the page. Without pages, all of them. It
10
+ * shows a dash while some are selected and not all.
11
+ */
12
+ export declare function DataTableSelectAll({ className }: DataTableSelectAllProps): import("react").JSX.Element | null;
13
+ export interface DataTableSelectRowProps<TFeatures extends TableFeatures = any, TData extends RowData = any> {
14
+ /** The row. Inside a column's `cell` it's found without being passed. */
15
+ row?: Row<TFeatures, TData>;
16
+ className?: string;
17
+ }
18
+ /**
19
+ * A row's checkbox. Shift and a click selects every row from the last one
20
+ * clicked to this one.
21
+ */
22
+ export declare function DataTableSelectRow<TFeatures extends TableFeatures, TData extends RowData>({ row: given, className }: DataTableSelectRowProps<TFeatures, TData>): import("react").JSX.Element | null;
23
+ export interface DataTableExpandToggleProps<TFeatures extends TableFeatures = any, TData extends RowData = any> {
24
+ /** The row. Inside a column's `cell` it's found without being passed. */
25
+ row?: Row<TFeatures, TData>;
26
+ className?: string;
27
+ }
28
+ /**
29
+ * The button that opens and closes a row: its detail panel, or the rows
30
+ * under it. In a tree it's indented by how deep the row is, and a row with
31
+ * nothing under it gets a gap of the same width, so the text after it
32
+ * lines up.
33
+ */
34
+ export declare function DataTableExpandToggle<TFeatures extends TableFeatures, TData extends RowData>({ row: given, className }: DataTableExpandToggleProps<TFeatures, TData>): import("react").JSX.Element;
35
+ export interface DataTableBulkActionsProps<TFeatures extends TableFeatures = any, TData extends RowData = any> extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
36
+ /**
37
+ * The actions, usually buttons. As a function it's given the selected
38
+ * rows that are loaded. With a server doing the paging those are only
39
+ * the ones on this page: use `table.getSelectedRowIds()` for all of them.
40
+ */
41
+ children?: ReactNode | ((rows: Row<TFeatures, TData>[]) => ReactNode);
42
+ }
43
+ /**
44
+ * A bar that's there while rows are selected. It says how many, holds the
45
+ * actions you give it, and has a button that clears the selection.
46
+ */
47
+ export declare function DataTableBulkActions<TFeatures extends TableFeatures, TData extends RowData>({ children, className, ...props }: DataTableBulkActionsProps<TFeatures, TData>): import("react").JSX.Element | null;
48
+ //#endregion
@@ -0,0 +1,153 @@
1
+ "use client";
2
+ import { canExpand, expanded, supports, useCell, useDataTableView } from "./context.js";
3
+ import { cx } from "../../utils/cx.js";
4
+ import { useShiftClick } from "../../utils/use-shift-click.js";
5
+ import { useLayoutEffect, useRef } from "react";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
+ import { Button } from "@nuvui/react/button";
8
+ import { Checkbox } from "@nuvui/react/checkbox";
9
+ //#region src/components/data-table/selection.tsx
10
+ const keepText = (event) => {
11
+ if (event.shiftKey) event.preventDefault();
12
+ };
13
+ /**
14
+ * The checkbox in the heading of the selection column. In a table with
15
+ * pages it selects the rows on the page. Without pages, all of them. It
16
+ * shows a dash while some are selected and not all.
17
+ */
18
+ function DataTableSelectAll({ className }) {
19
+ const { table, labels } = useDataTableView("DataTableSelectAll");
20
+ if (!supports.selection(table)) return null;
21
+ const paged = supports.pagination(table);
22
+ const all = paged ? table.getIsAllPageRowsSelected() : table.getIsAllRowsSelected();
23
+ const some = paged ? table.getIsSomePageRowsSelected() : table.getIsSomeRowsSelected();
24
+ const none = table.getRowModel().rows.length === 0;
25
+ return /* @__PURE__ */ jsx(Checkbox, {
26
+ className,
27
+ "data-nuv-select-all": "",
28
+ "aria-label": paged ? labels.selectPage : labels.selectAll,
29
+ disabled: none,
30
+ checked: all ? true : some ? "indeterminate" : false,
31
+ onClick: () => paged ? table.toggleAllPageRowsSelected(!all) : table.toggleAllRowsSelected(!all)
32
+ });
33
+ }
34
+ /**
35
+ * A row's checkbox. Shift and a click selects every row from the last one
36
+ * clicked to this one.
37
+ */
38
+ function DataTableSelectRow({ row: given, className }) {
39
+ const { labels, rowName } = useDataTableView("DataTableSelectRow");
40
+ const click = useShiftClick();
41
+ const cell = useCell();
42
+ const row = given ?? cell?.row;
43
+ if (!row) throw new Error("DataTableSelectRow needs a row, or to be inside a column's cell.");
44
+ if (typeof row.getIsSelected !== "function") return null;
45
+ const checked = row.getIsSelected();
46
+ return /* @__PURE__ */ jsx(Checkbox, {
47
+ className,
48
+ "aria-label": labels.selectRow(rowName(row)),
49
+ disabled: !row.getCanSelect(),
50
+ checked: checked ? true : row.getIsSomeSelected() ? "indeterminate" : false,
51
+ onMouseDown: keepText,
52
+ ...click.props,
53
+ onClick: (event) => row.getToggleSelectedHandler()({
54
+ target: { checked: !checked },
55
+ shiftKey: click.shift(event)
56
+ })
57
+ });
58
+ }
59
+ /**
60
+ * The button that opens and closes a row: its detail panel, or the rows
61
+ * under it. In a tree it's indented by how deep the row is, and a row with
62
+ * nothing under it gets a gap of the same width, so the text after it
63
+ * lines up.
64
+ */
65
+ function DataTableExpandToggle({ row: given, className }) {
66
+ const { labels, rowName } = useDataTableView("DataTableExpandToggle");
67
+ const cell = useCell();
68
+ const row = given ?? cell?.row;
69
+ if (!row) throw new Error("DataTableExpandToggle needs a row, or to be inside a column's cell.");
70
+ const indent = { "--nuv-data-table-depth": row.depth };
71
+ if (!canExpand(row)) return /* @__PURE__ */ jsx("span", {
72
+ className: cx("nuv-data-table__expand-gap", className),
73
+ style: indent
74
+ });
75
+ const open = expanded(row);
76
+ const name = rowName(row);
77
+ return /* @__PURE__ */ jsx("button", {
78
+ type: "button",
79
+ className: cx("nuv-data-table__expand", className),
80
+ style: indent,
81
+ "aria-expanded": open,
82
+ "aria-label": open ? labels.collapseRow(name) : labels.expandRow(name),
83
+ onClick: row.getToggleExpandedHandler(),
84
+ children: /* @__PURE__ */ jsx("svg", {
85
+ "aria-hidden": "true",
86
+ className: "nuv-data-table__expand-icon",
87
+ viewBox: "0 0 16 16",
88
+ width: "16",
89
+ height: "16",
90
+ fill: "none",
91
+ stroke: "currentColor",
92
+ strokeWidth: "1.5",
93
+ strokeLinecap: "round",
94
+ strokeLinejoin: "round",
95
+ children: /* @__PURE__ */ jsx("path", { d: "M6 4l4 4-4 4" })
96
+ })
97
+ });
98
+ }
99
+ /**
100
+ * A bar that's there while rows are selected. It says how many, holds the
101
+ * actions you give it, and has a button that clears the selection.
102
+ */
103
+ function DataTableBulkActions({ children, className, ...props }) {
104
+ const { table, labels } = useDataTableView("DataTableBulkActions");
105
+ const bar = useRef(null);
106
+ const heldFocus = useRef(false);
107
+ const available = supports.selection(table);
108
+ const count = available ? table.getSelectedRowIds().length : 0;
109
+ useLayoutEffect(() => {
110
+ if (count > 0 || !heldFocus.current) return;
111
+ heldFocus.current = false;
112
+ const active = document.activeElement;
113
+ if (active && active !== document.body) return;
114
+ const root = bar.current?.closest(".nuv-data-table");
115
+ const target = root?.querySelector("[data-nuv-select-all]:not(:disabled)") ?? root?.querySelector(".nuv-table-container");
116
+ if (!target) return;
117
+ if (!target.hasAttribute("tabindex") && target.tagName === "DIV") target.setAttribute("tabindex", "-1");
118
+ target.focus();
119
+ }, [count]);
120
+ if (!available) return null;
121
+ return /* @__PURE__ */ jsx("div", {
122
+ ref: bar,
123
+ role: "group",
124
+ "aria-label": labels.bulkActions,
125
+ className: cx("nuv-data-table__bulk", className),
126
+ hidden: count === 0,
127
+ onFocus: () => {
128
+ heldFocus.current = true;
129
+ },
130
+ onBlur: (event) => {
131
+ if (event.relatedTarget) heldFocus.current = false;
132
+ },
133
+ ...props,
134
+ children: count > 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
135
+ /* @__PURE__ */ jsx("span", {
136
+ className: "nuv-data-table__bulk-count",
137
+ children: labels.selected(count)
138
+ }),
139
+ /* @__PURE__ */ jsx("div", {
140
+ className: "nuv-data-table__bulk-actions",
141
+ children: typeof children === "function" ? children(table.getSelectedRowModel().rows) : children
142
+ }),
143
+ /* @__PURE__ */ jsx(Button, {
144
+ intent: "ghost",
145
+ size: "sm",
146
+ onClick: () => table.resetRowSelection(true),
147
+ children: labels.clearSelection
148
+ })
149
+ ] }) : null
150
+ });
151
+ }
152
+ //#endregion
153
+ export { DataTableBulkActions, DataTableExpandToggle, DataTableSelectAll, DataTableSelectRow };
@@ -0,0 +1,51 @@
1
+ import { Column, RowData, TableFeatures } from "@tanstack/react-table";
2
+ import { HTMLAttributes } from "react";
3
+ import { InputProps } from "@nuvui/react/input";
4
+ //#region src/components/data-table/toolbar.d.ts
5
+ export interface DataTableFilterOwnProps {
6
+ /**
7
+ * How long to wait after the last keystroke before filtering, in
8
+ * milliseconds. Set it when each change asks a server.
9
+ * @default 0
10
+ */
11
+ debounce?: number;
12
+ }
13
+ export interface DataTableFilterProps extends DataTableFilterOwnProps, Omit<InputProps, "value" | "defaultValue" | "onChange" | "type"> {}
14
+ /**
15
+ * A search field over every column that can be searched. It's the table's
16
+ * global filter. It needs `globalFilteringFeature`, and shows nothing
17
+ * without it.
18
+ */
19
+ export declare function DataTableFilter({ debounce, className, ...props }: DataTableFilterProps): import("react").JSX.Element | null;
20
+ export interface DataTableColumnFilterProps<TFeatures extends TableFeatures = any, TData extends RowData = any> extends Omit<InputProps, "value" | "defaultValue" | "onChange"> {
21
+ /**
22
+ * The column to filter. Inside a column's `header` it's found without
23
+ * being passed.
24
+ */
25
+ column?: Column<TFeatures, TData, any>;
26
+ /** @default 0 */
27
+ debounce?: number;
28
+ }
29
+ /**
30
+ * A text field that filters one column. For a filter that isn't text, such
31
+ * as a select of statuses, use any control and call
32
+ * `column.setFilterValue`.
33
+ */
34
+ export declare function DataTableColumnFilter<TFeatures extends TableFeatures, TData extends RowData>({ column: given, debounce, className, ...props }: DataTableColumnFilterProps<TFeatures, TData>): import("react").JSX.Element | null;
35
+ export interface DataTableColumnChooserProps {
36
+ className?: string;
37
+ }
38
+ /**
39
+ * A button that opens a list of the columns, each with a tick that shows
40
+ * or hides it. Columns with `enableHiding: false` aren't in the list. It
41
+ * needs `columnVisibilityFeature`, and shows nothing without it.
42
+ */
43
+ export declare function DataTableColumnChooser({ className }: DataTableColumnChooserProps): import("react").JSX.Element | null;
44
+ export type DataTableToolbarProps = HTMLAttributes<HTMLDivElement>;
45
+ /**
46
+ * The row of controls above the table. With no children it holds the
47
+ * search field and the column chooser, each only if the table has the
48
+ * feature for it, and is left out when it has neither.
49
+ */
50
+ export declare function DataTableToolbar({ className, children, ...props }: DataTableToolbarProps): import("react").JSX.Element | null;
51
+ //#endregion
@@ -0,0 +1,123 @@
1
+ "use client";
2
+ import { canHide, columnLabel, supports, useDataTableView, useHeader } from "./context.js";
3
+ import { cx } from "../../utils/cx.js";
4
+ import { useEffect, useRef, useState } from "react";
5
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
+ import { Button } from "@nuvui/react/button";
7
+ import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger } from "@nuvui/react/dropdown-menu";
8
+ import { Input } from "@nuvui/react/input";
9
+ //#region src/components/data-table/toolbar.tsx
10
+ function useDebounced(value, commit, debounce) {
11
+ const [text, setText] = useState(value);
12
+ const sent = useRef(value);
13
+ const timer = useRef(void 0);
14
+ useEffect(() => {
15
+ if (value !== sent.current) {
16
+ sent.current = value;
17
+ setText(value);
18
+ }
19
+ }, [value]);
20
+ useEffect(() => () => clearTimeout(timer.current), []);
21
+ const change = (next) => {
22
+ setText(next);
23
+ clearTimeout(timer.current);
24
+ const send = () => {
25
+ sent.current = next;
26
+ commit(next);
27
+ };
28
+ if (debounce > 0) timer.current = setTimeout(send, debounce);
29
+ else send();
30
+ };
31
+ return [text, change];
32
+ }
33
+ /**
34
+ * A search field over every column that can be searched. It's the table's
35
+ * global filter. It needs `globalFilteringFeature`, and shows nothing
36
+ * without it.
37
+ */
38
+ function DataTableFilter({ debounce = 0, className, ...props }) {
39
+ const { table, labels } = useDataTableView("DataTableFilter");
40
+ const available = supports.globalFilter(table);
41
+ const [text, change] = useDebounced(available ? String(table.atoms.globalFilter.get() ?? "") : "", (next) => table.setGlobalFilter(next), debounce);
42
+ if (!available) return null;
43
+ return /* @__PURE__ */ jsx(Input, {
44
+ type: "search",
45
+ "aria-label": labels.search,
46
+ placeholder: labels.search,
47
+ className: cx("nuv-data-table__filter", className),
48
+ ...props,
49
+ value: text,
50
+ onChange: (event) => change(event.target.value)
51
+ });
52
+ }
53
+ /**
54
+ * A text field that filters one column. For a filter that isn't text, such
55
+ * as a select of statuses, use any control and call
56
+ * `column.setFilterValue`.
57
+ */
58
+ function DataTableColumnFilter({ column: given, debounce = 0, className, ...props }) {
59
+ const { labels } = useDataTableView("DataTableColumnFilter");
60
+ const header = useHeader();
61
+ const column = given ?? header?.column;
62
+ if (!column) throw new Error("DataTableColumnFilter needs a column, or to be inside a column's header.");
63
+ const available = typeof column.getCanFilter === "function" && column.getCanFilter();
64
+ const [text, change] = useDebounced(available ? String(column.getFilterValue() ?? "") : "", (next) => column.setFilterValue(next === "" ? void 0 : next), debounce);
65
+ if (!available) return null;
66
+ return /* @__PURE__ */ jsx(Input, {
67
+ type: "search",
68
+ "aria-label": labels.filterColumn(columnLabel(column)),
69
+ className: cx("nuv-data-table__column-filter", className),
70
+ ...props,
71
+ value: text,
72
+ onChange: (event) => change(event.target.value)
73
+ });
74
+ }
75
+ /**
76
+ * A button that opens a list of the columns, each with a tick that shows
77
+ * or hides it. Columns with `enableHiding: false` aren't in the list. It
78
+ * needs `columnVisibilityFeature`, and shows nothing without it.
79
+ */
80
+ function DataTableColumnChooser({ className }) {
81
+ const { table, labels } = useDataTableView("DataTableColumnChooser");
82
+ if (!supports.visibility(table)) return null;
83
+ const columns = table.getAllLeafColumns().filter(canHide);
84
+ if (columns.length === 0) return null;
85
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
86
+ asChild: true,
87
+ children: /* @__PURE__ */ jsx(Button, {
88
+ intent: "secondary",
89
+ size: "sm",
90
+ className: cx("nuv-data-table__chooser", className),
91
+ children: labels.columns
92
+ })
93
+ }), /* @__PURE__ */ jsx(DropdownMenuContent, {
94
+ align: "end",
95
+ children: columns.map((column) => /* @__PURE__ */ jsx(DropdownMenuCheckboxItem, {
96
+ checked: column.getIsVisible(),
97
+ onCheckedChange: (checked) => column.toggleVisibility(checked),
98
+ onSelect: (event) => event.preventDefault(),
99
+ children: columnLabel(column)
100
+ }, column.id))
101
+ })] });
102
+ }
103
+ /**
104
+ * The row of controls above the table. With no children it holds the
105
+ * search field and the column chooser, each only if the table has the
106
+ * feature for it, and is left out when it has neither.
107
+ */
108
+ function DataTableToolbar({ className, children, ...props }) {
109
+ const { table } = useDataTableView("DataTableToolbar");
110
+ const standard = supports.globalFilter(table) || supports.visibility(table) && table.getAllLeafColumns().some(canHide);
111
+ if (children == null && !standard) return null;
112
+ return /* @__PURE__ */ jsx("div", {
113
+ className: cx("nuv-data-table__toolbar", className),
114
+ ...props,
115
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
116
+ /* @__PURE__ */ jsx(DataTableFilter, {}),
117
+ /* @__PURE__ */ jsx("span", { className: "nuv-data-table__toolbar-gap" }),
118
+ /* @__PURE__ */ jsx(DataTableColumnChooser, {})
119
+ ] })
120
+ });
121
+ }
122
+ //#endregion
123
+ export { DataTableColumnChooser, DataTableColumnFilter, DataTableFilter, DataTableToolbar };
@@ -0,0 +1,44 @@
1
+ import { ColumnFiltersState, PaginationState, SortingState, Updater } from "@tanstack/react-table";
2
+ //#region src/components/data-table/use-data-table-request.d.ts
3
+ /** What a server is asked for: which page, in what order, filtered how. */
4
+ export interface DataTableRequest {
5
+ pagination: PaginationState;
6
+ sorting: SortingState;
7
+ columnFilters: ColumnFiltersState;
8
+ globalFilter: string;
9
+ }
10
+ export interface DataTableRequestOptions {
11
+ state: DataTableRequest;
12
+ onPaginationChange: (updater: Updater<PaginationState>) => void;
13
+ onSortingChange: (updater: Updater<SortingState>) => void;
14
+ onColumnFiltersChange: (updater: Updater<ColumnFiltersState>) => void;
15
+ onGlobalFilterChange: (updater: Updater<string>) => void;
16
+ manualPagination: true;
17
+ manualSorting: true;
18
+ manualFiltering: true;
19
+ }
20
+ /**
21
+ * For a table whose sorting, filtering and paging are done by a server.
22
+ *
23
+ * It holds what the table is asking for, and returns it with the options
24
+ * that make the table ask and not do the work itself. Spread the options
25
+ * into `useDataTable`, fetch with the request, and pass the rows you get
26
+ * back as `data` with the total as `rowCount`.
27
+ *
28
+ * A new sort or filter goes back to the first page. TanStack does that
29
+ * itself when it does the paging, and not when a server does.
30
+ *
31
+ * @example
32
+ * const [request, options] = useDataTableRequest({
33
+ * pagination: { pageIndex: 0, pageSize: 20 },
34
+ * });
35
+ * const page = useQuery({ queryKey: ["people", request], ... });
36
+ * const table = useDataTable({
37
+ * columns,
38
+ * data: page.data?.rows ?? none,
39
+ * rowCount: page.data?.total,
40
+ * ...options,
41
+ * });
42
+ */
43
+ export declare function useDataTableRequest(initial?: Partial<DataTableRequest>): [request: DataTableRequest, options: DataTableRequestOptions];
44
+ //#endregion
@@ -0,0 +1,72 @@
1
+ "use client";
2
+ import { functionalUpdate } from "@tanstack/react-table";
3
+ import { useMemo, useState } from "react";
4
+ //#region src/components/data-table/use-data-table-request.ts
5
+ const firstPage = (request) => ({
6
+ ...request,
7
+ pagination: {
8
+ ...request.pagination,
9
+ pageIndex: 0
10
+ }
11
+ });
12
+ /**
13
+ * For a table whose sorting, filtering and paging are done by a server.
14
+ *
15
+ * It holds what the table is asking for, and returns it with the options
16
+ * that make the table ask and not do the work itself. Spread the options
17
+ * into `useDataTable`, fetch with the request, and pass the rows you get
18
+ * back as `data` with the total as `rowCount`.
19
+ *
20
+ * A new sort or filter goes back to the first page. TanStack does that
21
+ * itself when it does the paging, and not when a server does.
22
+ *
23
+ * @example
24
+ * const [request, options] = useDataTableRequest({
25
+ * pagination: { pageIndex: 0, pageSize: 20 },
26
+ * });
27
+ * const page = useQuery({ queryKey: ["people", request], ... });
28
+ * const table = useDataTable({
29
+ * columns,
30
+ * data: page.data?.rows ?? none,
31
+ * rowCount: page.data?.total,
32
+ * ...options,
33
+ * });
34
+ */
35
+ function useDataTableRequest(initial = {}) {
36
+ const [request, setRequest] = useState(() => ({
37
+ pagination: {
38
+ pageIndex: 0,
39
+ pageSize: 10
40
+ },
41
+ sorting: [],
42
+ columnFilters: [],
43
+ globalFilter: "",
44
+ ...initial
45
+ }));
46
+ return [request, {
47
+ state: request,
48
+ ...useMemo(() => ({
49
+ onPaginationChange: (updater) => setRequest((old) => ({
50
+ ...old,
51
+ pagination: functionalUpdate(updater, old.pagination)
52
+ })),
53
+ onSortingChange: (updater) => setRequest((old) => firstPage({
54
+ ...old,
55
+ sorting: functionalUpdate(updater, old.sorting)
56
+ })),
57
+ onColumnFiltersChange: (updater) => setRequest((old) => firstPage({
58
+ ...old,
59
+ columnFilters: functionalUpdate(updater, old.columnFilters)
60
+ })),
61
+ onGlobalFilterChange: (updater) => setRequest((old) => firstPage({
62
+ ...old,
63
+ globalFilter: functionalUpdate(updater, old.globalFilter) ?? ""
64
+ })),
65
+ manualPagination: true,
66
+ manualSorting: true,
67
+ manualFiltering: true
68
+ }), [])
69
+ }];
70
+ }
71
+ //#endregion
72
+ export { useDataTableRequest };
@@ -0,0 +1,2 @@
1
+ import { Table, TableBody, TableBodyProps, TableCaption, TableCaptionOwnProps, TableCaptionProps, TableCell, TableCellOwnProps, TableCellProps, TableContainer, TableContainerProps, TableFooter, TableFooterProps, TableHead, TableHeadProps, TableHeader, TableHeaderProps, TableOwnProps, TableProps, TableRow, TableRowOwnProps, TableRowProps } from "./table.js";
2
+ export { Table, TableBody, type TableBodyProps, TableCaption, type TableCaptionOwnProps, type TableCaptionProps, TableCell, type TableCellOwnProps, type TableCellProps, TableContainer, type TableContainerProps, TableFooter, type TableFooterProps, TableHead, type TableHeadProps, TableHeader, type TableHeaderProps, type TableOwnProps, type TableProps, TableRow, type TableRowOwnProps, type TableRowProps };
@@ -0,0 +1,2 @@
1
+ import { Table, TableBody, TableCaption, TableCell, TableContainer, TableFooter, TableHead, TableHeader, TableRow } from "./table.js";
2
+ export { Table, TableBody, TableCaption, TableCell, TableContainer, TableFooter, TableHead, TableHeader, TableRow };