@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.
- package/LICENSE +21 -0
- package/README.md +57 -2
- package/dist/components/data-table/content.d.ts +67 -0
- package/dist/components/data-table/content.js +278 -0
- package/dist/components/data-table/context.d.ts +23 -0
- package/dist/components/data-table/context.js +51 -0
- package/dist/components/data-table/create-data-table-hook.d.ts +78 -0
- package/dist/components/data-table/create-data-table-hook.js +103 -0
- package/dist/components/data-table/data-table.d.ts +76 -0
- package/dist/components/data-table/data-table.js +178 -0
- package/dist/components/data-table/header.d.ts +23 -0
- package/dist/components/data-table/header.js +120 -0
- package/dist/components/data-table/index.d.ts +11 -0
- package/dist/components/data-table/index.js +10 -0
- package/dist/components/data-table/labels.d.ts +50 -0
- package/dist/components/data-table/labels.js +35 -0
- package/dist/components/data-table/pagination.d.ts +18 -0
- package/dist/components/data-table/pagination.js +126 -0
- package/dist/components/data-table/selection.d.ts +48 -0
- package/dist/components/data-table/selection.js +153 -0
- package/dist/components/data-table/toolbar.d.ts +51 -0
- package/dist/components/data-table/toolbar.js +123 -0
- package/dist/components/data-table/use-data-table-request.d.ts +44 -0
- package/dist/components/data-table/use-data-table-request.js +72 -0
- package/dist/components/table/index.d.ts +2 -0
- package/dist/components/table/index.js +2 -0
- package/dist/components/table/table.d.ts +100 -0
- package/dist/components/table/table.js +130 -0
- package/dist/css/data-table.css +278 -0
- package/dist/css/table.css +164 -0
- package/dist/full.d.ts +264 -0
- package/dist/full.js +44 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +11 -0
- package/dist/styles.css +441 -0
- package/dist/utils/cx.js +6 -0
- package/dist/utils/use-shift-click.js +32 -0
- package/dist/virtual.d.ts +42 -0
- package/dist/virtual.js +133 -0
- 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
|
+
}
|