@nuvui/table 0.0.0-stage → 0.1.0

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,100 @@
1
+ import { HTMLAttributes, TableHTMLAttributes, TdHTMLAttributes, ThHTMLAttributes } from "react";
2
+ //#region src/components/table/table.d.ts
3
+ export type TableContainerProps = HTMLAttributes<HTMLDivElement>;
4
+ /**
5
+ * The box a table scrolls in. A table wider than the box scrolls sideways
6
+ * inside it and leaves the page alone.
7
+ *
8
+ * While there's something to scroll, the box takes keyboard focus, so the
9
+ * arrow keys can scroll it. Give it `aria-label` or `aria-labelledby` and
10
+ * it's a region with that name for screen readers.
11
+ */
12
+ export declare const TableContainer: import("react").ForwardRefExoticComponent<TableContainerProps & import("react").RefAttributes<HTMLDivElement>>;
13
+ export interface TableOwnProps {
14
+ /**
15
+ * Shade every second row of the body.
16
+ * @default false
17
+ */
18
+ striped?: boolean;
19
+ /**
20
+ * Keep the header row in view while the body scrolls under it. It sticks
21
+ * to the top of the nearest thing that scrolls: a `TableContainer` with a
22
+ * height, or the page.
23
+ * @default false
24
+ */
25
+ stickyHeader?: boolean;
26
+ /**
27
+ * `"auto"` sizes each column to what's in it. `"fixed"` takes each
28
+ * column's width from its first row or its `col`, and is what a table
29
+ * with set column widths needs.
30
+ * @default "auto"
31
+ */
32
+ layout?: "auto" | "fixed";
33
+ }
34
+ export interface TableProps extends TableOwnProps, TableHTMLAttributes<HTMLTableElement> {}
35
+ export declare const Table: import("react").ForwardRefExoticComponent<TableProps & import("react").RefAttributes<HTMLTableElement>>;
36
+ export interface TableCaptionOwnProps {
37
+ /**
38
+ * Keep the caption for screen readers and show nothing. For a table whose
39
+ * heading is already on the page above it.
40
+ * @default false
41
+ */
42
+ visuallyHidden?: boolean;
43
+ }
44
+ export interface TableCaptionProps extends TableCaptionOwnProps, HTMLAttributes<HTMLTableCaptionElement> {}
45
+ /** The table's name. A screen reader reads it when it reaches the table. */
46
+ export declare const TableCaption: import("react").ForwardRefExoticComponent<TableCaptionProps & import("react").RefAttributes<HTMLTableCaptionElement>>;
47
+ export type TableHeaderProps = HTMLAttributes<HTMLTableSectionElement>;
48
+ export declare const TableHeader: import("react").ForwardRefExoticComponent<TableHeaderProps & import("react").RefAttributes<HTMLTableSectionElement>>;
49
+ export type TableBodyProps = HTMLAttributes<HTMLTableSectionElement>;
50
+ export declare const TableBody: import("react").ForwardRefExoticComponent<TableBodyProps & import("react").RefAttributes<HTMLTableSectionElement>>;
51
+ export type TableFooterProps = HTMLAttributes<HTMLTableSectionElement>;
52
+ export declare const TableFooter: import("react").ForwardRefExoticComponent<TableFooterProps & import("react").RefAttributes<HTMLTableSectionElement>>;
53
+ export interface TableRowOwnProps {
54
+ /**
55
+ * Mark the row as picked. It gets the selected background and
56
+ * `data-state="selected"`.
57
+ * @default false
58
+ */
59
+ selected?: boolean;
60
+ }
61
+ export interface TableRowProps extends TableRowOwnProps, HTMLAttributes<HTMLTableRowElement> {}
62
+ export declare const TableRow: import("react").ForwardRefExoticComponent<TableRowProps & import("react").RefAttributes<HTMLTableRowElement>>;
63
+ export interface TableCellOwnProps {
64
+ /**
65
+ * Which side the content sits on. `"end"` is for numbers, so their digits
66
+ * line up.
67
+ * @default "start"
68
+ */
69
+ align?: "start" | "center" | "end";
70
+ /**
71
+ * Keep the cell in view while the table scrolls sideways. Do it for every
72
+ * cell of the column, the header's too. With one pinned column a side
73
+ * that's all there is to it. With more, each one after the first needs an
74
+ * `inset-inline-start` or `inset-inline-end` of its own.
75
+ */
76
+ pinned?: "start" | "end";
77
+ /**
78
+ * Draw the line that separates pinned columns from the ones that scroll.
79
+ * For the last column pinned to the start and the first pinned to the end.
80
+ * @default false
81
+ */
82
+ pinnedEdge?: boolean;
83
+ }
84
+ export interface TableHeadProps extends TableCellOwnProps, Omit<ThHTMLAttributes<HTMLTableCellElement>, "align"> {}
85
+ /**
86
+ * A column's heading. It's a `th` with `scope="col"`, which is what ties
87
+ * every cell below it to its heading for a screen reader.
88
+ */
89
+ export declare const TableHead: import("react").ForwardRefExoticComponent<TableHeadProps & import("react").RefAttributes<HTMLTableCellElement>>;
90
+ export interface TableCellProps extends TableCellOwnProps, Omit<TdHTMLAttributes<HTMLTableCellElement>, "align"> {
91
+ /**
92
+ * Make this cell the heading of its row: a `th` with `scope="row"`. Do it
93
+ * for the cell that names the row, such as a person's name, and a screen
94
+ * reader reads it with every other cell in the row.
95
+ * @default false
96
+ */
97
+ rowHeader?: boolean;
98
+ }
99
+ export declare const TableCell: import("react").ForwardRefExoticComponent<TableCellProps & import("react").RefAttributes<HTMLTableCellElement>>;
100
+ //#endregion
@@ -0,0 +1,130 @@
1
+ "use client";
2
+ import { cx } from "../../utils/cx.js";
3
+ import { createContext, forwardRef, useCallback, useContext, useEffect, useRef, useState } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/components/table/table.tsx
6
+ /**
7
+ * The box a table scrolls in. A table wider than the box scrolls sideways
8
+ * inside it and leaves the page alone.
9
+ *
10
+ * While there's something to scroll, the box takes keyboard focus, so the
11
+ * arrow keys can scroll it. Give it `aria-label` or `aria-labelledby` and
12
+ * it's a region with that name for screen readers.
13
+ */
14
+ const TableContainer = forwardRef(function TableContainer({ className, tabIndex, role, ...props }, ref) {
15
+ const element = useRef(null);
16
+ const [scrollable, setScrollable] = useState(false);
17
+ const setRef = useCallback((node) => {
18
+ element.current = node;
19
+ if (typeof ref === "function") ref(node);
20
+ else if (ref) ref.current = node;
21
+ }, [ref]);
22
+ useEffect(() => {
23
+ const node = element.current;
24
+ if (!node || typeof ResizeObserver === "undefined") return;
25
+ const measure = () => setScrollable(node.scrollWidth > node.clientWidth || node.scrollHeight > node.clientHeight);
26
+ const observer = new ResizeObserver(measure);
27
+ observer.observe(node);
28
+ for (const child of node.children) observer.observe(child);
29
+ measure();
30
+ return () => observer.disconnect();
31
+ }, []);
32
+ const named = props["aria-label"] || props["aria-labelledby"];
33
+ return /* @__PURE__ */ jsx("div", {
34
+ ref: setRef,
35
+ className: cx("nuv-table-container", className),
36
+ tabIndex: tabIndex ?? (scrollable ? 0 : void 0),
37
+ role: role ?? (scrollable && named ? "region" : void 0),
38
+ "data-scrollable": scrollable ? "" : void 0,
39
+ ...props
40
+ });
41
+ });
42
+ const StripedContext = createContext(false);
43
+ const Table = forwardRef(function Table({ striped = false, stickyHeader = false, layout = "auto", className, ...props }, ref) {
44
+ return /* @__PURE__ */ jsx(StripedContext.Provider, {
45
+ value: striped,
46
+ children: /* @__PURE__ */ jsx("table", {
47
+ ref,
48
+ className: cx("nuv-table", stickyHeader && "nuv-table--sticky-header", layout === "fixed" && "nuv-table--fixed", className),
49
+ ...props
50
+ })
51
+ });
52
+ });
53
+ /** The table's name. A screen reader reads it when it reaches the table. */
54
+ const TableCaption = forwardRef(function TableCaption({ visuallyHidden = false, className, ...props }, ref) {
55
+ return /* @__PURE__ */ jsx("caption", {
56
+ ref,
57
+ className: cx("nuv-table__caption", visuallyHidden && "nuv-table__caption--hidden", className),
58
+ ...props
59
+ });
60
+ });
61
+ const TableHeader = forwardRef(function TableHeader({ className, ...props }, ref) {
62
+ return /* @__PURE__ */ jsx("thead", {
63
+ ref,
64
+ className: cx("nuv-table__header", className),
65
+ ...props
66
+ });
67
+ });
68
+ const TableBody = forwardRef(function TableBody({ className, ...props }, ref) {
69
+ const striped = useContext(StripedContext);
70
+ return /* @__PURE__ */ jsx("tbody", {
71
+ ref,
72
+ className: cx("nuv-table__body", striped && "nuv-table__body--striped", className),
73
+ ...props
74
+ });
75
+ });
76
+ const TableFooter = forwardRef(function TableFooter({ className, ...props }, ref) {
77
+ return /* @__PURE__ */ jsx("tfoot", {
78
+ ref,
79
+ className: cx("nuv-table__footer", className),
80
+ ...props
81
+ });
82
+ });
83
+ const TableRow = forwardRef(function TableRow({ selected = false, className, ...props }, ref) {
84
+ return /* @__PURE__ */ jsx("tr", {
85
+ ref,
86
+ className: cx("nuv-table__row", className),
87
+ "data-state": selected ? "selected" : void 0,
88
+ ...props
89
+ });
90
+ });
91
+ const cellClasses = (block, { align, pinned, pinnedEdge }) => [
92
+ align && align !== "start" && `${block}--align-${align}`,
93
+ pinned && `${block}--pinned-${pinned}`,
94
+ pinned && pinnedEdge && `${block}--pinned-edge`
95
+ ];
96
+ /**
97
+ * A column's heading. It's a `th` with `scope="col"`, which is what ties
98
+ * every cell below it to its heading for a screen reader.
99
+ */
100
+ const TableHead = forwardRef(function TableHead({ align, pinned, pinnedEdge, scope = "col", className, ...props }, ref) {
101
+ return /* @__PURE__ */ jsx("th", {
102
+ ref,
103
+ scope,
104
+ className: cx("nuv-table__head", ...cellClasses("nuv-table__head", {
105
+ align,
106
+ pinned,
107
+ pinnedEdge
108
+ }), className),
109
+ ...props
110
+ });
111
+ });
112
+ const TableCell = forwardRef(function TableCell({ align, pinned, pinnedEdge, rowHeader = false, className, ...props }, ref) {
113
+ const classes = cx("nuv-table__cell", rowHeader && "nuv-table__cell--row-header", ...cellClasses("nuv-table__cell", {
114
+ align,
115
+ pinned,
116
+ pinnedEdge
117
+ }), className);
118
+ return rowHeader ? /* @__PURE__ */ jsx("th", {
119
+ ref,
120
+ scope: "row",
121
+ className: classes,
122
+ ...props
123
+ }) : /* @__PURE__ */ jsx("td", {
124
+ ref,
125
+ className: classes,
126
+ ...props
127
+ });
128
+ });
129
+ //#endregion
130
+ export { Table, TableBody, TableCaption, TableCell, TableContainer, TableFooter, TableHead, TableHeader, TableRow };
@@ -0,0 +1,278 @@
1
+ @layer tokens, base, components;
2
+ @layer components {
3
+ .nuv-data-table {
4
+ display: flex;
5
+ flex-direction: column;
6
+ gap: var(--nuv-data-table-gap, calc(var(--spacing) * 3));
7
+ min-inline-size: 0;
8
+ color: var(--nuv-data-table-fg, var(--color-foreground));
9
+ font-size: var(--text-sm);
10
+ line-height: var(--text-sm--line-height);
11
+ }
12
+ .nuv-data-table__status {
13
+ position: absolute;
14
+ inline-size: 1px;
15
+ block-size: 1px;
16
+ margin: -1px;
17
+ overflow: hidden;
18
+ clip-path: inset(50%);
19
+ white-space: nowrap;
20
+ }
21
+ .nuv-data-table__toolbar {
22
+ display: flex;
23
+ flex-wrap: wrap;
24
+ gap: calc(var(--spacing) * 2);
25
+ align-items: center;
26
+ }
27
+ .nuv-data-table__toolbar-gap {
28
+ flex: 1 1 0;
29
+ }
30
+ .nuv-data-table__filter {
31
+ flex: 1 1 100%;
32
+ }
33
+ @media (width >= 40rem) {
34
+ .nuv-data-table__filter {
35
+ flex: 0 1 var(--nuv-data-table-filter-width, 16rem);
36
+ }
37
+ }
38
+ .nuv-data-table__column-filter {
39
+ inline-size: 100%;
40
+ min-inline-size: var(--nuv-data-table-column-filter-min-width, 6rem);
41
+ }
42
+ .nuv-data-table__bulk {
43
+ display: flex;
44
+ flex-wrap: wrap;
45
+ gap: calc(var(--spacing) * 2);
46
+ align-items: center;
47
+ padding: calc(var(--spacing) * 2) calc(var(--spacing) * 3);
48
+ border: var(--nuv-border-width) solid var(--nuv-data-table-bulk-border, var(--color-border));
49
+ border-radius: var(--nuv-data-table-bulk-radius, var(--radius-lg));
50
+ background-color: var(--nuv-data-table-bulk-bg, var(--color-muted));
51
+ }
52
+ .nuv-data-table__bulk[hidden] {
53
+ display: none;
54
+ }
55
+ .nuv-data-table__bulk-count {
56
+ font-weight: var(--font-weight-medium);
57
+ }
58
+ .nuv-data-table__bulk-actions {
59
+ display: flex;
60
+ flex: 1 1 auto;
61
+ flex-wrap: wrap;
62
+ gap: calc(var(--spacing) * 2);
63
+ align-items: center;
64
+ }
65
+ .nuv-data-table__heading {
66
+ min-inline-size: 0;
67
+ overflow: hidden;
68
+ text-overflow: ellipsis;
69
+ }
70
+ .nuv-data-table__sort {
71
+ display: inline-flex;
72
+ max-inline-size: 100%;
73
+ gap: calc(var(--spacing) * 1);
74
+ align-items: center;
75
+ min-block-size: var(--nuv-touch-size);
76
+ margin-block: calc(var(--spacing) * -1);
77
+ padding: 0;
78
+ border: 0;
79
+ border-radius: var(--radius-sm);
80
+ background: none;
81
+ color: inherit;
82
+ font: inherit;
83
+ text-align: inherit;
84
+ cursor: pointer;
85
+ -webkit-tap-highlight-color: transparent;
86
+ }
87
+ .nuv-data-table__sort:focus-visible {
88
+ outline: var(--nuv-focus-ring-width, 2px) solid var(--nuv-focus-ring-color, var(--color-ring));
89
+ outline-offset: var(--nuv-focus-ring-offset, 2px);
90
+ }
91
+ @media (pointer: fine) {
92
+ .nuv-data-table__sort {
93
+ min-block-size: var(--nuv-control-height-sm);
94
+ }
95
+ }
96
+ @media (hover: hover) {
97
+ .nuv-data-table__sort:hover {
98
+ color: var(--nuv-data-table-sort-hover-fg, var(--color-foreground));
99
+ }
100
+ }
101
+ .nuv-data-table__sort[data-sorted] {
102
+ color: var(--nuv-data-table-sorted-fg, var(--color-foreground));
103
+ }
104
+ .nuv-data-table__sort-icon {
105
+ flex: none;
106
+ opacity: 0.6;
107
+ }
108
+ .nuv-data-table__sort-icon[data-direction] {
109
+ opacity: 1;
110
+ }
111
+ .nuv-data-table__sort-index {
112
+ font-size: var(--text-xs);
113
+ }
114
+ .nuv-data-table__head--resizable {
115
+ position: relative;
116
+ }
117
+ .nuv-data-table__resize {
118
+ position: absolute;
119
+ inset-block: 0;
120
+ inset-inline-end: 0;
121
+ inline-size: calc(var(--spacing) * 4);
122
+ cursor: col-resize;
123
+ touch-action: none;
124
+ user-select: none;
125
+ }
126
+ .nuv-data-table__resize:focus-visible {
127
+ outline: var(--nuv-focus-ring-width, 2px) solid var(--nuv-focus-ring-color, var(--color-ring));
128
+ outline-offset: var(--nuv-focus-ring-offset, -2px);
129
+ }
130
+ @media (pointer: fine) {
131
+ .nuv-data-table__resize {
132
+ inline-size: calc(var(--spacing) * 2);
133
+ }
134
+ }
135
+ .nuv-data-table__resize::after {
136
+ position: absolute;
137
+ inset-block: 25%;
138
+ inset-inline-end: 0;
139
+ inline-size: 2px;
140
+ background-color: var(--nuv-data-table-resize-color, var(--color-border-strong));
141
+ content: "";
142
+ }
143
+ .nuv-data-table__resize[data-resizing]::after {
144
+ inset-block: 0;
145
+ background-color: var(--nuv-data-table-resize-active-color, var(--color-primary));
146
+ }
147
+ @media (hover: hover) {
148
+ .nuv-data-table__resize:hover::after {
149
+ inset-block: 0;
150
+ background-color: var(--nuv-data-table-resize-active-color, var(--color-primary));
151
+ }
152
+ }
153
+ .nuv-data-table__cell--control {
154
+ inline-size: 1%;
155
+ white-space: nowrap;
156
+ }
157
+ .nuv-data-table__expand,
158
+ .nuv-data-table__expand-gap {
159
+ display: inline-flex;
160
+ flex: none;
161
+ inline-size: var(--nuv-data-table-expand-size, 1.5rem);
162
+ block-size: var(--nuv-data-table-expand-size, 1.5rem);
163
+ margin-inline-start: calc(var(--nuv-data-table-indent, 1.25rem) * var(--nuv-data-table-depth, 0));
164
+ vertical-align: middle;
165
+ }
166
+ .nuv-data-table__expand {
167
+ position: relative;
168
+ align-items: center;
169
+ justify-content: center;
170
+ padding: 0;
171
+ border: 0;
172
+ border-radius: var(--radius-sm);
173
+ background: none;
174
+ color: var(--nuv-data-table-expand-fg, var(--color-muted-foreground));
175
+ cursor: pointer;
176
+ -webkit-tap-highlight-color: transparent;
177
+ }
178
+ .nuv-data-table__expand::after {
179
+ position: absolute;
180
+ top: 50%;
181
+ left: 50%;
182
+ inline-size: max(100%, var(--nuv-touch-size, 2.75rem));
183
+ block-size: max(100%, var(--nuv-touch-size, 2.75rem));
184
+ transform: translate(-50%, -50%);
185
+ content: "";
186
+ }
187
+ @media (pointer: fine) {
188
+ .nuv-data-table__expand::after {
189
+ content: none;
190
+ }
191
+ }
192
+ .nuv-data-table__expand:focus-visible {
193
+ outline: var(--nuv-focus-ring-width, 2px) solid var(--nuv-focus-ring-color, var(--color-ring));
194
+ outline-offset: var(--nuv-focus-ring-offset, 2px);
195
+ }
196
+ @media (hover: hover) {
197
+ .nuv-data-table__expand:hover {
198
+ color: var(--color-foreground);
199
+ }
200
+ }
201
+ @media (prefers-reduced-motion: no-preference) {
202
+ .nuv-data-table__expand-icon {
203
+ transition: transform var(--nuv-duration-fast) var(--ease-out);
204
+ }
205
+ }
206
+ .nuv-data-table__expand-icon:dir(rtl) {
207
+ transform: scaleX(-1);
208
+ }
209
+ .nuv-data-table__expand[aria-expanded=true] > .nuv-data-table__expand-icon {
210
+ transform: rotate(90deg);
211
+ }
212
+ .nuv-data-table__detail-row {
213
+ --nuv-table-row-bg: var(--nuv-data-table-detail-bg, var(--color-background));
214
+ --nuv-table-row-hover-bg: var(--nuv-data-table-detail-bg, var(--color-background));
215
+ }
216
+ .nuv-data-table__message-row,
217
+ .nuv-data-table__loading-row {
218
+ --nuv-table-row-hover-bg: var(--nuv-table-bg, var(--color-surface));
219
+ }
220
+ .nuv-data-table__detail {
221
+ --nuv-table-cell-padding-x: var(--nuv-data-table-detail-padding, calc(var(--spacing) * 4));
222
+ --nuv-table-cell-padding-y: var(--nuv-data-table-detail-padding, calc(var(--spacing) * 4));
223
+ }
224
+ .nuv-data-table__message {
225
+ --nuv-table-cell-padding-y: var(--nuv-data-table-message-padding, calc(var(--spacing) * 10));
226
+ color: var(--nuv-data-table-message-fg, var(--color-muted-foreground));
227
+ text-align: center;
228
+ }
229
+ .nuv-data-table__message > * + * {
230
+ margin-inline-start: calc(var(--spacing) * 3);
231
+ }
232
+ .nuv-data-table__pagination {
233
+ display: flex;
234
+ flex-wrap: wrap;
235
+ gap: calc(var(--spacing) * 2) calc(var(--spacing) * 4);
236
+ align-items: center;
237
+ justify-content: space-between;
238
+ color: var(--nuv-data-table-pagination-fg, var(--color-muted-foreground));
239
+ }
240
+ @media (width >= 40rem) {
241
+ .nuv-data-table__pagination {
242
+ justify-content: flex-end;
243
+ }
244
+ }
245
+ .nuv-data-table__page-size {
246
+ display: flex;
247
+ white-space: nowrap;
248
+ gap: calc(var(--spacing) * 2);
249
+ align-items: center;
250
+ }
251
+ .nuv-data-table__page-range,
252
+ .nuv-data-table__page {
253
+ white-space: nowrap;
254
+ }
255
+ .nuv-data-table__pages {
256
+ display: flex;
257
+ flex: 1 1 100%;
258
+ gap: calc(var(--spacing) * 1);
259
+ align-items: center;
260
+ justify-content: space-between;
261
+ }
262
+ @media (width >= 40rem) {
263
+ .nuv-data-table__pages {
264
+ flex: none;
265
+ justify-content: flex-start;
266
+ }
267
+ }
268
+ .nuv-data-table__page-button {
269
+ --nuv-button-padding-inline: 0;
270
+ }
271
+ .nuv-data-table__page-button[aria-disabled=true] {
272
+ opacity: var(--nuv-disabled-opacity);
273
+ cursor: not-allowed;
274
+ }
275
+ .nuv-data-table__page-icon:dir(rtl) {
276
+ transform: scaleX(-1);
277
+ }
278
+ }
@@ -0,0 +1,164 @@
1
+ @layer tokens, base, components;
2
+ @layer components {
3
+ .nuv-table-container {
4
+ position: relative;
5
+ max-inline-size: 100%;
6
+ max-block-size: var(--nuv-table-container-max-height, none);
7
+ overflow: auto;
8
+ border: var(--nuv-table-container-border-width, var(--nuv-border-width)) solid var(--nuv-table-border, var(--color-border));
9
+ border-radius: var(--nuv-table-container-radius, var(--radius-lg));
10
+ background-color: var(--nuv-table-bg, var(--color-surface));
11
+ }
12
+ .nuv-table-container:focus-visible {
13
+ outline: var(--nuv-focus-ring-width, 2px) solid var(--nuv-focus-ring-color, var(--color-ring));
14
+ outline-offset: var(--nuv-focus-ring-offset, -2px);
15
+ }
16
+ .nuv-table {
17
+ inline-size: 100%;
18
+ border-spacing: 0;
19
+ border-collapse: separate;
20
+ color: var(--nuv-table-fg, var(--color-surface-foreground));
21
+ font-size: var(--nuv-table-font-size, var(--text-sm));
22
+ line-height: var(--text-sm--line-height);
23
+ font-variant-numeric: tabular-nums;
24
+ text-align: start;
25
+ }
26
+ .nuv-table--fixed {
27
+ table-layout: fixed;
28
+ }
29
+ .nuv-table--fixed .nuv-table__head {
30
+ overflow: hidden;
31
+ text-overflow: ellipsis;
32
+ }
33
+ .nuv-table--fixed .nuv-table__cell {
34
+ overflow-wrap: anywhere;
35
+ }
36
+ .nuv-table__caption {
37
+ padding: var(--nuv-table-cell-padding-y, calc(var(--spacing) * 1.5)) var(--nuv-table-cell-padding-x, calc(var(--spacing) * 3));
38
+ color: var(--nuv-table-caption-fg, var(--color-muted-foreground));
39
+ text-align: start;
40
+ caption-side: var(--nuv-table-caption-side, bottom);
41
+ }
42
+ .nuv-table__caption--hidden {
43
+ position: absolute;
44
+ inline-size: 1px;
45
+ block-size: 1px;
46
+ margin: -1px;
47
+ padding: 0;
48
+ overflow: hidden;
49
+ clip-path: inset(50%);
50
+ white-space: nowrap;
51
+ }
52
+ .nuv-table__row {
53
+ background-color: var(--nuv-table-row-bg, var(--nuv-table-bg, var(--color-surface)));
54
+ }
55
+ .nuv-table__head,
56
+ .nuv-table__cell {
57
+ block-size: var(--nuv-table-row-height, var(--nuv-touch-size));
58
+ }
59
+ @media (pointer: fine) {
60
+ .nuv-table__head,
61
+ .nuv-table__cell {
62
+ block-size: var(--nuv-table-row-height, var(--nuv-control-height-md));
63
+ }
64
+ }
65
+ .nuv-table__head,
66
+ .nuv-table__cell {
67
+ padding: var(--nuv-table-cell-padding-y, calc(var(--spacing) * 1.5)) var(--nuv-table-cell-padding-x, calc(var(--spacing) * 3));
68
+ border-block-end: var(--nuv-border-width) solid var(--nuv-table-border, var(--color-border));
69
+ background-color: inherit;
70
+ vertical-align: middle;
71
+ }
72
+ .nuv-table__head {
73
+ background-color: var(--nuv-table-header-bg, var(--color-muted));
74
+ color: var(--nuv-table-header-fg, var(--color-muted-foreground));
75
+ font-weight: var(--font-weight-medium);
76
+ text-align: start;
77
+ white-space: nowrap;
78
+ }
79
+ .nuv-table__cell--row-header {
80
+ font-weight: var(--font-weight-medium);
81
+ text-align: start;
82
+ }
83
+ .nuv-table__head--align-center {
84
+ text-align: center;
85
+ }
86
+ .nuv-table__head--align-end {
87
+ text-align: end;
88
+ }
89
+ .nuv-table__cell--align-center {
90
+ text-align: center;
91
+ }
92
+ .nuv-table__cell--align-end {
93
+ text-align: end;
94
+ }
95
+ .nuv-table__head--pinned-start,
96
+ .nuv-table__head--pinned-end {
97
+ position: sticky;
98
+ z-index: 1;
99
+ }
100
+ .nuv-table__head--pinned-start {
101
+ inset-inline-start: 0;
102
+ }
103
+ .nuv-table__head--pinned-end {
104
+ inset-inline-end: 0;
105
+ }
106
+ .nuv-table__head--pinned-start.nuv-table__head--pinned-edge {
107
+ border-inline-end: var(--nuv-border-width) solid var(--nuv-table-border, var(--color-border));
108
+ }
109
+ .nuv-table__head--pinned-end.nuv-table__head--pinned-edge {
110
+ border-inline-start: var(--nuv-border-width) solid var(--nuv-table-border, var(--color-border));
111
+ }
112
+ .nuv-table__cell--pinned-start,
113
+ .nuv-table__cell--pinned-end {
114
+ position: sticky;
115
+ z-index: 1;
116
+ }
117
+ .nuv-table__cell--pinned-start {
118
+ inset-inline-start: 0;
119
+ }
120
+ .nuv-table__cell--pinned-end {
121
+ inset-inline-end: 0;
122
+ }
123
+ .nuv-table__cell--pinned-start.nuv-table__cell--pinned-edge {
124
+ border-inline-end: var(--nuv-border-width) solid var(--nuv-table-border, var(--color-border));
125
+ }
126
+ .nuv-table__cell--pinned-end.nuv-table__cell--pinned-edge {
127
+ border-inline-start: var(--nuv-border-width) solid var(--nuv-table-border, var(--color-border));
128
+ }
129
+ .nuv-table__row:last-child > .nuv-table__cell {
130
+ border-block-end-width: var(--nuv-table-last-row-border-width, 0);
131
+ }
132
+ .nuv-table__footer > .nuv-table__row {
133
+ background-color: var(--nuv-table-footer-bg, var(--color-muted));
134
+ font-weight: var(--font-weight-medium);
135
+ }
136
+ .nuv-table__footer .nuv-table__cell {
137
+ border-block-start: var(--nuv-border-width) solid var(--nuv-table-border, var(--color-border));
138
+ }
139
+ .nuv-table__body--striped > .nuv-table__row:nth-child(even) {
140
+ background-color: var(--nuv-table-stripe-bg, var(--color-muted));
141
+ }
142
+ @media (hover: hover) {
143
+ .nuv-table__body > .nuv-table__row:hover {
144
+ background-color: var(--nuv-table-row-hover-bg, var(--color-muted));
145
+ }
146
+ }
147
+ .nuv-table__body > .nuv-table__row[data-state=selected] {
148
+ background-color: var(--nuv-table-row-selected-bg, color-mix(in oklab, var(--color-primary) 12%, var(--color-surface)));
149
+ }
150
+ .nuv-table--sticky-header .nuv-table__head {
151
+ position: sticky;
152
+ inset-block-start: 0;
153
+ z-index: 2;
154
+ }
155
+ .nuv-table--sticky-header .nuv-table__head--pinned-start,
156
+ .nuv-table--sticky-header .nuv-table__head--pinned-end {
157
+ z-index: 3;
158
+ }
159
+ @media (forced-colors: active) {
160
+ .nuv-table__row[data-state=selected] > :first-child {
161
+ border-inline-start: calc(var(--spacing) * 1) solid Highlight;
162
+ }
163
+ }
164
+ }