@surflane/ui 0.2.0 → 0.3.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/dist/app-shell.d.ts +2 -1
- package/dist/app-shell.js +18 -2
- package/dist/data.d.ts +57 -12
- package/dist/data.js +48 -6
- package/dist/icon.d.ts +1 -0
- package/dist/icon.js +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/table-selection.d.ts +31 -0
- package/dist/table-selection.js +50 -0
- package/package.json +2 -2
- package/src/styles.css +33 -0
package/dist/app-shell.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export declare const AppShell: {
|
|
|
7
7
|
Header: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
8
8
|
Sidebar: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>;
|
|
9
9
|
Content: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
10
|
+
Page: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
10
11
|
Footer: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
11
12
|
Label: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
12
13
|
Link: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "ref">, "children"> & {
|
|
@@ -17,7 +18,7 @@ export declare const AppShell: {
|
|
|
17
18
|
export declare const AppShellRoot: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & {
|
|
18
19
|
collapsed?: boolean;
|
|
19
20
|
layout?: "header" | "workspace";
|
|
20
|
-
} & React.RefAttributes<HTMLDivElement>>, AppShellHeader: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>, AppShellSidebar: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>, AppShellContent: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>, AppShellFooter: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>, AppShellLabel: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>, AppShellLink: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "ref">, "children"> & {
|
|
21
|
+
} & React.RefAttributes<HTMLDivElement>>, AppShellHeader: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>, AppShellSidebar: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>, AppShellContent: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>, AppShellPage: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>, AppShellFooter: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>, AppShellLabel: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>, AppShellLink: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "ref">, "children"> & {
|
|
21
22
|
icon: React.ReactNode;
|
|
22
23
|
label: string;
|
|
23
24
|
} & React.RefAttributes<HTMLAnchorElement>>;
|
package/dist/app-shell.js
CHANGED
|
@@ -15,6 +15,13 @@ const Sidebar = React.forwardRef(function AppShellSidebar({ className, ...props
|
|
|
15
15
|
const Content = React.forwardRef(function AppShellContent({ className, ...props }, ref) {
|
|
16
16
|
return (_jsx("div", { ...props, ref: ref, className: skin('pui-app-shell-content', className) }));
|
|
17
17
|
});
|
|
18
|
+
/**
|
|
19
|
+
* The page surface inside a workspace Content. It insets from the shell on every
|
|
20
|
+
* side but the sidebar's; without the sidebar, on narrow screens, it insets evenly.
|
|
21
|
+
*/
|
|
22
|
+
const Page = React.forwardRef(function AppShellPage({ className, ...props }, ref) {
|
|
23
|
+
return (_jsx("div", { ...props, ref: ref, className: skin('pui-app-shell-page', className) }));
|
|
24
|
+
});
|
|
18
25
|
const Footer = React.forwardRef(function AppShellFooter({ className, ...props }, ref) {
|
|
19
26
|
return (_jsx("div", { ...props, ref: ref, className: skin('pui-app-shell-footer', className) }));
|
|
20
27
|
});
|
|
@@ -24,6 +31,15 @@ const Label = React.forwardRef(function AppShellLabel({ className, ...props }, r
|
|
|
24
31
|
const Link = React.forwardRef(function AppShellLink({ icon, label, className, ...props }, ref) {
|
|
25
32
|
return (_jsxs("a", { ...props, ref: ref, "aria-label": props['aria-label'] ?? label, className: skin('pui-app-shell-link', className), children: [_jsx("span", { className: 'pui-app-shell-icon', "aria-hidden": 'true', children: icon }), _jsx(Label, { "aria-hidden": 'true', children: label })] }));
|
|
26
33
|
});
|
|
27
|
-
export const AppShell = {
|
|
34
|
+
export const AppShell = {
|
|
35
|
+
Root,
|
|
36
|
+
Header,
|
|
37
|
+
Sidebar,
|
|
38
|
+
Content,
|
|
39
|
+
Page,
|
|
40
|
+
Footer,
|
|
41
|
+
Label,
|
|
42
|
+
Link,
|
|
43
|
+
};
|
|
28
44
|
// Flat names for React Server Components, which cannot dot into client exports.
|
|
29
|
-
export const { Root: AppShellRoot, Header: AppShellHeader, Sidebar: AppShellSidebar, Content: AppShellContent, Footer: AppShellFooter, Label: AppShellLabel, Link: AppShellLink, } = AppShell;
|
|
45
|
+
export const { Root: AppShellRoot, Header: AppShellHeader, Sidebar: AppShellSidebar, Content: AppShellContent, Page: AppShellPage, Footer: AppShellFooter, Label: AppShellLabel, Link: AppShellLink, } = AppShell;
|
package/dist/data.d.ts
CHANGED
|
@@ -8,6 +8,41 @@ declare const TableContainer: React.ForwardRefExoticComponent<Omit<Omit<React.De
|
|
|
8
8
|
} & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
9
9
|
label: string;
|
|
10
10
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
11
|
+
export type TableDensity = 'default' | 'compact';
|
|
12
|
+
declare const TableRoot: React.ForwardRefExoticComponent<Omit<Omit<Omit<React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "ref">, "size"> & {
|
|
13
|
+
size?: import("./sizing.js").ComponentSize;
|
|
14
|
+
} & React.RefAttributes<HTMLTableElement>, "ref"> & {
|
|
15
|
+
/** compact tightens rows for scanning many records with a pointer. */
|
|
16
|
+
density?: TableDensity;
|
|
17
|
+
/** Keeps the header visible while a bounded Container scrolls vertically. */
|
|
18
|
+
stickyHeader?: boolean;
|
|
19
|
+
} & React.RefAttributes<HTMLTableElement>>;
|
|
20
|
+
type CellLayout = {
|
|
21
|
+
align?: 'start' | 'center' | 'end';
|
|
22
|
+
/** Aligns to the end with tabular figures, so digits line up down the column. */
|
|
23
|
+
numeric?: boolean;
|
|
24
|
+
};
|
|
25
|
+
declare const TableHeaderCell: React.ForwardRefExoticComponent<Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>, "ref">, "size"> & {
|
|
26
|
+
size?: import("./sizing.js").ComponentSize;
|
|
27
|
+
} & React.RefAttributes<HTMLTableCellElement>, "ref">, "align"> & CellLayout & React.RefAttributes<HTMLTableCellElement>>;
|
|
28
|
+
declare const TableCell: React.ForwardRefExoticComponent<Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>, "ref">, "size"> & {
|
|
29
|
+
size?: import("./sizing.js").ComponentSize;
|
|
30
|
+
} & React.RefAttributes<HTMLTableCellElement>, "ref">, "align"> & CellLayout & React.RefAttributes<HTMLTableCellElement>>;
|
|
31
|
+
export type TableSort = 'ascending' | 'descending';
|
|
32
|
+
/** A column header whose button sorts the column. aria-sort names the order on the sorted column only. */
|
|
33
|
+
declare const TableSortHeader: React.ForwardRefExoticComponent<Omit<Omit<Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>, "ref">, "size"> & {
|
|
34
|
+
size?: import("./sizing.js").ComponentSize;
|
|
35
|
+
} & React.RefAttributes<HTMLTableCellElement>, "ref">, "align"> & CellLayout & React.RefAttributes<HTMLTableCellElement>, "ref">, "scope" | "aria-sort" | "onClick"> & {
|
|
36
|
+
sort?: TableSort;
|
|
37
|
+
onSort: () => void;
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
} & React.RefAttributes<HTMLTableCellElement>>;
|
|
40
|
+
/** One-line text that ends in an ellipsis. String content also becomes the title. */
|
|
41
|
+
declare const TableTruncate: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
42
|
+
/** A full-width body row for loading, empty, error and permission messages. It has no hover. */
|
|
43
|
+
declare const TableMessage: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>, "ref"> & {
|
|
44
|
+
colSpan: number;
|
|
45
|
+
} & React.RefAttributes<HTMLTableCellElement>>;
|
|
11
46
|
declare const TableRow: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>, "ref"> & {
|
|
12
47
|
selected?: boolean;
|
|
13
48
|
} & React.RefAttributes<HTMLTableRowElement>>;
|
|
@@ -21,8 +56,13 @@ export declare const Table: {
|
|
|
21
56
|
} & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
22
57
|
label: string;
|
|
23
58
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
24
|
-
Root: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "ref">, "size"> & {
|
|
59
|
+
Root: React.ForwardRefExoticComponent<Omit<Omit<Omit<React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "ref">, "size"> & {
|
|
25
60
|
size?: import("./sizing.js").ComponentSize;
|
|
61
|
+
} & React.RefAttributes<HTMLTableElement>, "ref"> & {
|
|
62
|
+
/** compact tightens rows for scanning many records with a pointer. */
|
|
63
|
+
density?: TableDensity;
|
|
64
|
+
/** Keeps the header visible while a bounded Container scrolls vertically. */
|
|
65
|
+
stickyHeader?: boolean;
|
|
26
66
|
} & React.RefAttributes<HTMLTableElement>>;
|
|
27
67
|
Caption: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref">, "size"> & {
|
|
28
68
|
size?: import("./sizing.js").ComponentSize;
|
|
@@ -39,11 +79,22 @@ export declare const Table: {
|
|
|
39
79
|
Row: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>, "ref"> & {
|
|
40
80
|
selected?: boolean;
|
|
41
81
|
} & React.RefAttributes<HTMLTableRowElement>>;
|
|
42
|
-
HeaderCell: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>, "ref">, "size"> & {
|
|
82
|
+
HeaderCell: React.ForwardRefExoticComponent<Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>, "ref">, "size"> & {
|
|
83
|
+
size?: import("./sizing.js").ComponentSize;
|
|
84
|
+
} & React.RefAttributes<HTMLTableCellElement>, "ref">, "align"> & CellLayout & React.RefAttributes<HTMLTableCellElement>>;
|
|
85
|
+
SortHeader: React.ForwardRefExoticComponent<Omit<Omit<Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>, "ref">, "size"> & {
|
|
43
86
|
size?: import("./sizing.js").ComponentSize;
|
|
87
|
+
} & React.RefAttributes<HTMLTableCellElement>, "ref">, "align"> & CellLayout & React.RefAttributes<HTMLTableCellElement>, "ref">, "scope" | "aria-sort" | "onClick"> & {
|
|
88
|
+
sort?: TableSort;
|
|
89
|
+
onSort: () => void;
|
|
90
|
+
disabled?: boolean;
|
|
44
91
|
} & React.RefAttributes<HTMLTableCellElement>>;
|
|
45
|
-
Cell: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>, "ref">, "size"> & {
|
|
92
|
+
Cell: React.ForwardRefExoticComponent<Omit<Omit<Omit<Omit<React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>, "ref">, "size"> & {
|
|
46
93
|
size?: import("./sizing.js").ComponentSize;
|
|
94
|
+
} & React.RefAttributes<HTMLTableCellElement>, "ref">, "align"> & CellLayout & React.RefAttributes<HTMLTableCellElement>>;
|
|
95
|
+
Truncate: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
|
|
96
|
+
Message: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>, "ref"> & {
|
|
97
|
+
colSpan: number;
|
|
47
98
|
} & React.RefAttributes<HTMLTableCellElement>>;
|
|
48
99
|
};
|
|
49
100
|
declare const ListRoot: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLUListElement>, HTMLUListElement>, "ref"> & React.RefAttributes<HTMLUListElement>>;
|
|
@@ -68,7 +119,7 @@ export declare const List: {
|
|
|
68
119
|
size?: import("./sizing.js").ComponentSize;
|
|
69
120
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
70
121
|
};
|
|
71
|
-
export { ListRoot, ListItem, TableContainer, TableRow };
|
|
122
|
+
export { ListRoot, ListItem, TableContainer, TableRoot, TableRow, TableHeaderCell, TableSortHeader, TableCell, TableTruncate, TableMessage, };
|
|
72
123
|
export declare const ListContent: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "size"> & {
|
|
73
124
|
size?: import("./sizing.js").ComponentSize;
|
|
74
125
|
} & React.RefAttributes<HTMLDivElement>>, ListTitle: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "size"> & {
|
|
@@ -78,9 +129,7 @@ export declare const ListContent: React.ForwardRefExoticComponent<Omit<Omit<Reac
|
|
|
78
129
|
} & React.RefAttributes<HTMLParagraphElement>>, ListActions: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "size"> & {
|
|
79
130
|
size?: import("./sizing.js").ComponentSize;
|
|
80
131
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
81
|
-
export declare const
|
|
82
|
-
size?: import("./sizing.js").ComponentSize;
|
|
83
|
-
} & React.RefAttributes<HTMLTableElement>>, TableCaption: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref">, "size"> & {
|
|
132
|
+
export declare const TableCaption: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref">, "size"> & {
|
|
84
133
|
size?: import("./sizing.js").ComponentSize;
|
|
85
134
|
} & React.RefAttributes<HTMLTableCaptionElement>>, TableHead: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref">, "size"> & {
|
|
86
135
|
size?: import("./sizing.js").ComponentSize;
|
|
@@ -88,8 +137,4 @@ export declare const TableRoot: React.ForwardRefExoticComponent<Omit<Omit<React.
|
|
|
88
137
|
size?: import("./sizing.js").ComponentSize;
|
|
89
138
|
} & React.RefAttributes<HTMLTableSectionElement>>, TableFoot: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref">, "size"> & {
|
|
90
139
|
size?: import("./sizing.js").ComponentSize;
|
|
91
|
-
} & React.RefAttributes<HTMLTableSectionElement
|
|
92
|
-
size?: import("./sizing.js").ComponentSize;
|
|
93
|
-
} & React.RefAttributes<HTMLTableCellElement>>, TableCell: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>, "ref">, "size"> & {
|
|
94
|
-
size?: import("./sizing.js").ComponentSize;
|
|
95
|
-
} & React.RefAttributes<HTMLTableCellElement>>;
|
|
140
|
+
} & React.RefAttributes<HTMLTableSectionElement>>;
|
package/dist/data.js
CHANGED
|
@@ -1,24 +1,66 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from 'react';
|
|
4
|
+
import { Button } from './button.js';
|
|
4
5
|
import { part } from './parts.js';
|
|
5
6
|
import { ScrollArea } from './scroll-area.js';
|
|
6
7
|
const TableContainer = React.forwardRef(function TableContainer(props, ref) {
|
|
7
8
|
return _jsx(ScrollArea, { ...props, ref: ref });
|
|
8
9
|
});
|
|
10
|
+
const RootPart = part('table', 'pui-table');
|
|
11
|
+
const TableRoot = React.forwardRef(function TableRoot({ density, stickyHeader, ...props }, ref) {
|
|
12
|
+
return (_jsx(RootPart, { ...props, ref: ref, "data-density": density === 'compact' ? 'compact' : undefined, "data-sticky-header": stickyHeader || undefined }));
|
|
13
|
+
});
|
|
14
|
+
const layout = ({ align, numeric }) => ({
|
|
15
|
+
'data-align': numeric ? 'end' : align,
|
|
16
|
+
'data-numeric': numeric || undefined,
|
|
17
|
+
});
|
|
18
|
+
const HeaderCellPart = part('th', 'pui-table-cell pui-table-header');
|
|
19
|
+
const CellPart = part('td', 'pui-table-cell');
|
|
20
|
+
// align replaces the obsolete HTML align attribute of th and td.
|
|
21
|
+
const TableHeaderCell = React.forwardRef(function TableHeaderCell({ align, numeric, ...props }, ref) {
|
|
22
|
+
return _jsx(HeaderCellPart, { ...props, ...layout({ align, numeric }), ref: ref });
|
|
23
|
+
});
|
|
24
|
+
const TableCell = React.forwardRef(function TableCell({ align, numeric, ...props }, ref) {
|
|
25
|
+
return _jsx(CellPart, { ...props, ...layout({ align, numeric }), ref: ref });
|
|
26
|
+
});
|
|
27
|
+
function SortIcon({ sort }) {
|
|
28
|
+
return (_jsx("svg", { className: 'pui-table-sort-icon', width: '16', height: '16', viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', strokeWidth: '1.6', strokeLinecap: 'round', strokeLinejoin: 'round', "aria-hidden": 'true', children: _jsx("path", { d: sort === 'ascending'
|
|
29
|
+
? 'M12 19V5m-6 6 6-6 6 6'
|
|
30
|
+
: sort === 'descending'
|
|
31
|
+
? 'M12 5v14m-6-6 6 6 6-6'
|
|
32
|
+
: 'm8 9 4-4 4 4m-8 6 4 4 4-4' }) }));
|
|
33
|
+
}
|
|
34
|
+
/** A column header whose button sorts the column. aria-sort names the order on the sorted column only. */
|
|
35
|
+
const TableSortHeader = React.forwardRef(function TableSortHeader({ sort, onSort, disabled, children, className, ...props }, ref) {
|
|
36
|
+
return (_jsx(TableHeaderCell, { ...props, ref: ref, scope: 'col', "aria-sort": sort, className: ['pui-table-sort-header', className].filter(Boolean).join(' '), children: _jsxs(Button, { variant: 'ghost', className: 'pui-table-sort', "data-sort": sort, disabled: disabled, onClick: onSort, children: [_jsx("span", { children: children }), _jsx(SortIcon, { sort: sort })] }) }));
|
|
37
|
+
});
|
|
38
|
+
/** One-line text that ends in an ellipsis. String content also becomes the title. */
|
|
39
|
+
const TableTruncate = React.forwardRef(function TableTruncate({ className, title, children, ...props }, ref) {
|
|
40
|
+
return (_jsx("span", { ...props, ref: ref, title: title ?? (typeof children === 'string' ? children : undefined), className: ['pui-table-truncate', className].filter(Boolean).join(' '), children: children }));
|
|
41
|
+
});
|
|
42
|
+
/** A full-width body row for loading, empty, error and permission messages. It has no hover. */
|
|
43
|
+
const TableMessage = React.forwardRef(function TableMessage({ className, ...props }, ref) {
|
|
44
|
+
return (_jsx("tr", { className: 'pui-table-row pui-table-message-row', children: _jsx("td", { ...props, ref: ref, className: ['pui-table-cell pui-table-message', className]
|
|
45
|
+
.filter(Boolean)
|
|
46
|
+
.join(' ') }) }));
|
|
47
|
+
});
|
|
9
48
|
const TableRow = React.forwardRef(function TableRow({ selected, className, ...props }, ref) {
|
|
10
49
|
return (_jsx("tr", { ...props, ref: ref, "data-selected": selected || undefined, className: ['pui-table-row', className].filter(Boolean).join(' ') }));
|
|
11
50
|
});
|
|
12
51
|
export const Table = {
|
|
13
52
|
Container: TableContainer,
|
|
14
|
-
Root:
|
|
53
|
+
Root: TableRoot,
|
|
15
54
|
Caption: part('caption', 'pui-table-caption'),
|
|
16
55
|
Head: part('thead', 'pui-table-head'),
|
|
17
56
|
Body: part('tbody', 'pui-table-body'),
|
|
18
57
|
Foot: part('tfoot', 'pui-table-foot'),
|
|
19
58
|
Row: TableRow,
|
|
20
|
-
HeaderCell:
|
|
21
|
-
|
|
59
|
+
HeaderCell: TableHeaderCell,
|
|
60
|
+
SortHeader: TableSortHeader,
|
|
61
|
+
Cell: TableCell,
|
|
62
|
+
Truncate: TableTruncate,
|
|
63
|
+
Message: TableMessage,
|
|
22
64
|
};
|
|
23
65
|
const ListRoot = React.forwardRef(function ListRoot({ className, ...props }, ref) {
|
|
24
66
|
return (_jsx("ul", { role: 'list', ...props, ref: ref, className: ['pui-list', className].filter(Boolean).join(' ') }));
|
|
@@ -35,6 +77,6 @@ export const List = {
|
|
|
35
77
|
Actions: part('div', 'pui-list-actions'),
|
|
36
78
|
};
|
|
37
79
|
// Flat names for React Server Components, which cannot dot into client exports.
|
|
38
|
-
export { ListRoot, ListItem, TableContainer, TableRow };
|
|
80
|
+
export { ListRoot, ListItem, TableContainer, TableRoot, TableRow, TableHeaderCell, TableSortHeader, TableCell, TableTruncate, TableMessage, };
|
|
39
81
|
export const { Content: ListContent, Title: ListTitle, Description: ListDescription, Actions: ListActions, } = List;
|
|
40
|
-
export const {
|
|
82
|
+
export const { Caption: TableCaption, Head: TableHead, Body: TableBody, Foot: TableFoot, } = Table;
|
package/dist/icon.d.ts
CHANGED
package/dist/icon.js
CHANGED
|
@@ -10,6 +10,7 @@ const shapes = {
|
|
|
10
10
|
alert: (_jsxs(_Fragment, { children: [_jsx("circle", { cx: '12', cy: '12', r: '9' }), _jsx("path", { d: 'M12 7v6m0 3v1' })] })),
|
|
11
11
|
warning: (_jsxs(_Fragment, { children: [_jsx("path", { d: 'm12 3 10 18H2L12 3Z' }), _jsx("path", { d: 'M12 9v4m0 3v1' })] })),
|
|
12
12
|
menu: _jsx("path", { d: 'M4 6h16M4 12h16M4 18h16' }),
|
|
13
|
+
more: (_jsxs(_Fragment, { children: [_jsx("circle", { cx: '5', cy: '12', r: '1' }), _jsx("circle", { cx: '12', cy: '12', r: '1' }), _jsx("circle", { cx: '19', cy: '12', r: '1' })] })),
|
|
13
14
|
sun: (_jsxs(_Fragment, { children: [_jsx("circle", { cx: '12', cy: '12', r: '4' }), _jsx("path", { d: 'M12 2v2m0 16v2M2 12h2m16 0h2M5 5l1.5 1.5m11 11L19 19M5 19l1.5-1.5m11-11L19 5' })] })),
|
|
14
15
|
moon: _jsx("path", { d: 'M20.5 13.2A8.5 8.5 0 0 1 10.8 3.5 8.5 8.5 0 1 0 20.5 13.2Z' }),
|
|
15
16
|
monitor: (_jsxs(_Fragment, { children: [_jsx("rect", { x: '3', y: '4', width: '18', height: '13', rx: '2' }), _jsx("path", { d: 'M8 21h8m-4-4v4' })] })),
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,8 @@ export { Field, Fieldset, Form, Textarea, Checkbox, CheckboxGroup, Radio, RadioG
|
|
|
14
14
|
export { Tabs, Accordion, Collapsible, Avatar, Separator, Link, Breadcrumbs, TabsIndicator, TabsList, TabsPanel, TabsRoot, TabsTab, AccordionHeader, AccordionItem, AccordionPanel, AccordionRoot, AccordionTrigger, CollapsiblePanel, CollapsibleRoot, CollapsibleTrigger, AvatarFallback, AvatarImage, AvatarRoot, AvatarStatus, BreadcrumbsRoot, BreadcrumbsList, BreadcrumbsItem, BreadcrumbsLink, BreadcrumbsSeparator, BreadcrumbsCurrent, } from './navigation.js';
|
|
15
15
|
export { Badge, StatusBadge, type BadgeProps, type StatusTone, } from './status.js';
|
|
16
16
|
export { Progress, Meter, Spinner, Skeleton, type SpinnerProps, type SkeletonProps, ProgressIndicator, ProgressLabel, ProgressRoot, ProgressTrack, ProgressValue, MeterIndicator, MeterLabel, MeterRoot, MeterTrack, MeterValue, } from './feedback.js';
|
|
17
|
-
export { Table, List, TableContainer, TableRoot, TableCaption, TableHead, TableBody, TableFoot, TableRow, TableHeaderCell, TableCell, ListRoot, ListItem, ListContent, ListTitle, ListDescription, ListActions, } from './data.js';
|
|
17
|
+
export { Table, List, TableContainer, TableRoot, TableCaption, TableHead, TableBody, TableFoot, TableRow, TableHeaderCell, TableSortHeader, TableCell, TableTruncate, TableMessage, ListRoot, ListItem, ListContent, ListTitle, ListDescription, ListActions, type TableDensity, type TableSort, } from './data.js';
|
|
18
|
+
export { useTableSelection, type TableSelectionOptions, type TableSelectionCheckbox, } from './table-selection.js';
|
|
18
19
|
export { InlineMessage, EmptyState, InlineMessageRoot, InlineMessageIcon, InlineMessageContent, InlineMessageTitle, InlineMessageDescription, InlineMessageActions, EmptyStateRoot, EmptyStateIcon, EmptyStateTitle, EmptyStateDescription, EmptyStateActions, } from './messages.js';
|
|
19
20
|
export { Card, CodeBlock, type CodeBlockProps, CardRoot, CardHeader, CardTitle, CardDescription, CardBody, CardFooter, } from './content.js';
|
|
20
21
|
export { Pagination, type PaginationProps } from './pagination.js';
|
|
@@ -29,7 +30,7 @@ export { Toast, type ToastRootProps, type ToastViewportProps, ToastAction, Toast
|
|
|
29
30
|
export { FileUpload, type FileUploadProps, type UploadTransport, type FileUploadLabels, type FileChangeDetails, type FileRejection, type UploadState, } from './file-upload.js';
|
|
30
31
|
export { Icon, iconNames, type IconName, type IconProps } from './icon.js';
|
|
31
32
|
export { FilterBar, FilterBarRoot, FilterBarControls, FilterBarField, FilterBarActions, FilterBarSummary, } from './filter-bar.js';
|
|
32
|
-
export { AppShell, AppShellRoot, AppShellHeader, AppShellSidebar, AppShellContent, AppShellFooter, AppShellLabel, AppShellLink, } from './app-shell.js';
|
|
33
|
+
export { AppShell, AppShellRoot, AppShellHeader, AppShellSidebar, AppShellContent, AppShellPage, AppShellFooter, AppShellLabel, AppShellLink, } from './app-shell.js';
|
|
33
34
|
export { Tree, type TreeNode, type TreeProps } from './tree.js';
|
|
34
35
|
export { DatePicker, DateRangePicker, TimeField, DateLocaleProvider, type DatePickerProps, type DateRangePickerProps, type TimeFieldProps, type DateValue, type TimeValue, } from './date-picker.js';
|
|
35
36
|
export { Chart, type ChartDatum, type ChartSeries, type ChartProps, } from './chart.js';
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,8 @@ export { Field, Fieldset, Form, Textarea, Checkbox, CheckboxGroup, Radio, RadioG
|
|
|
15
15
|
export { Tabs, Accordion, Collapsible, Avatar, Separator, Link, Breadcrumbs, TabsIndicator, TabsList, TabsPanel, TabsRoot, TabsTab, AccordionHeader, AccordionItem, AccordionPanel, AccordionRoot, AccordionTrigger, CollapsiblePanel, CollapsibleRoot, CollapsibleTrigger, AvatarFallback, AvatarImage, AvatarRoot, AvatarStatus, BreadcrumbsRoot, BreadcrumbsList, BreadcrumbsItem, BreadcrumbsLink, BreadcrumbsSeparator, BreadcrumbsCurrent, } from './navigation.js';
|
|
16
16
|
export { Badge, StatusBadge, } from './status.js';
|
|
17
17
|
export { Progress, Meter, Spinner, Skeleton, ProgressIndicator, ProgressLabel, ProgressRoot, ProgressTrack, ProgressValue, MeterIndicator, MeterLabel, MeterRoot, MeterTrack, MeterValue, } from './feedback.js';
|
|
18
|
-
export { Table, List, TableContainer, TableRoot, TableCaption, TableHead, TableBody, TableFoot, TableRow, TableHeaderCell, TableCell, ListRoot, ListItem, ListContent, ListTitle, ListDescription, ListActions, } from './data.js';
|
|
18
|
+
export { Table, List, TableContainer, TableRoot, TableCaption, TableHead, TableBody, TableFoot, TableRow, TableHeaderCell, TableSortHeader, TableCell, TableTruncate, TableMessage, ListRoot, ListItem, ListContent, ListTitle, ListDescription, ListActions, } from './data.js';
|
|
19
|
+
export { useTableSelection, } from './table-selection.js';
|
|
19
20
|
export { InlineMessage, EmptyState, InlineMessageRoot, InlineMessageIcon, InlineMessageContent, InlineMessageTitle, InlineMessageDescription, InlineMessageActions, EmptyStateRoot, EmptyStateIcon, EmptyStateTitle, EmptyStateDescription, EmptyStateActions, } from './messages.js';
|
|
20
21
|
export { Card, CodeBlock, CardRoot, CardHeader, CardTitle, CardDescription, CardBody, CardFooter, } from './content.js';
|
|
21
22
|
export { Pagination } from './pagination.js';
|
|
@@ -30,7 +31,7 @@ export { Toast, ToastAction, ToastArrow, ToastClose, ToastContent, ToastDescript
|
|
|
30
31
|
export { FileUpload, } from './file-upload.js';
|
|
31
32
|
export { Icon, iconNames } from './icon.js';
|
|
32
33
|
export { FilterBar, FilterBarRoot, FilterBarControls, FilterBarField, FilterBarActions, FilterBarSummary, } from './filter-bar.js';
|
|
33
|
-
export { AppShell, AppShellRoot, AppShellHeader, AppShellSidebar, AppShellContent, AppShellFooter, AppShellLabel, AppShellLink, } from './app-shell.js';
|
|
34
|
+
export { AppShell, AppShellRoot, AppShellHeader, AppShellSidebar, AppShellContent, AppShellPage, AppShellFooter, AppShellLabel, AppShellLink, } from './app-shell.js';
|
|
34
35
|
export { Tree } from './tree.js';
|
|
35
36
|
export { DatePicker, DateRangePicker, TimeField, DateLocaleProvider, } from './date-picker.js';
|
|
36
37
|
export { Chart, } from './chart.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type TableSelectionOptions<Row> = {
|
|
2
|
+
/** Rows on the current page, in display order. */
|
|
3
|
+
rows: readonly Row[];
|
|
4
|
+
getId: (row: Row) => string;
|
|
5
|
+
/** Rows that fail stay unselectable, such as read-only resources. */
|
|
6
|
+
canSelect?: (row: Row) => boolean;
|
|
7
|
+
selected?: readonly string[];
|
|
8
|
+
defaultSelected?: readonly string[];
|
|
9
|
+
onSelectedChange?: (selected: string[]) => void;
|
|
10
|
+
};
|
|
11
|
+
export type TableSelectionCheckbox = {
|
|
12
|
+
checked: boolean;
|
|
13
|
+
indeterminate?: boolean;
|
|
14
|
+
disabled: boolean;
|
|
15
|
+
onCheckedChange: (checked: boolean) => void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Row selection by stable ID that survives paging, sorting and filtering.
|
|
19
|
+
* The page checkbox covers only the selectable rows on the current page;
|
|
20
|
+
* hiddenCount reports selections the reader cannot see.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useTableSelection<Row>({ rows, getId, canSelect, selected: controlled, defaultSelected, onSelectedChange, }: TableSelectionOptions<Row>): {
|
|
23
|
+
selected: readonly string[];
|
|
24
|
+
isSelected: (id: string) => boolean;
|
|
25
|
+
toggle: (id: string, checked: boolean) => void;
|
|
26
|
+
clear: () => void;
|
|
27
|
+
/** Selected rows that are not on the current page. */
|
|
28
|
+
hiddenCount: number;
|
|
29
|
+
pageCheckbox: TableSelectionCheckbox;
|
|
30
|
+
rowCheckbox: (row: Row) => TableSelectionCheckbox;
|
|
31
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* Row selection by stable ID that survives paging, sorting and filtering.
|
|
5
|
+
* The page checkbox covers only the selectable rows on the current page;
|
|
6
|
+
* hiddenCount reports selections the reader cannot see.
|
|
7
|
+
*/
|
|
8
|
+
export function useTableSelection({ rows, getId, canSelect = () => true, selected: controlled, defaultSelected = [], onSelectedChange, }) {
|
|
9
|
+
const [uncontrolled, setUncontrolled] = React.useState(defaultSelected);
|
|
10
|
+
const selected = controlled ?? uncontrolled;
|
|
11
|
+
const update = (next) => {
|
|
12
|
+
if (controlled === undefined)
|
|
13
|
+
setUncontrolled(next);
|
|
14
|
+
onSelectedChange?.(next);
|
|
15
|
+
};
|
|
16
|
+
const chosen = new Set(selected);
|
|
17
|
+
const onPage = new Set(rows.map(getId));
|
|
18
|
+
const selectable = rows.filter(canSelect).map(getId);
|
|
19
|
+
const pageChosen = selectable.filter((id) => chosen.has(id)).length;
|
|
20
|
+
const toggle = (id, checked) => update(checked
|
|
21
|
+
? chosen.has(id)
|
|
22
|
+
? [...selected]
|
|
23
|
+
: [...selected, id]
|
|
24
|
+
: selected.filter((other) => other !== id));
|
|
25
|
+
const pageCheckbox = {
|
|
26
|
+
checked: selectable.length > 0 && pageChosen === selectable.length,
|
|
27
|
+
indeterminate: pageChosen > 0 && pageChosen < selectable.length,
|
|
28
|
+
disabled: selectable.length === 0,
|
|
29
|
+
onCheckedChange: (checked) => update(checked
|
|
30
|
+
? [...new Set([...selected, ...selectable])]
|
|
31
|
+
: selected.filter((id) => !selectable.includes(id))),
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
selected: selected,
|
|
35
|
+
isSelected: (id) => chosen.has(id),
|
|
36
|
+
toggle,
|
|
37
|
+
clear: () => update([]),
|
|
38
|
+
/** Selected rows that are not on the current page. */
|
|
39
|
+
hiddenCount: selected.filter((id) => !onPage.has(id)).length,
|
|
40
|
+
pageCheckbox,
|
|
41
|
+
rowCheckbox: (row) => {
|
|
42
|
+
const id = getId(row);
|
|
43
|
+
return {
|
|
44
|
+
checked: chosen.has(id),
|
|
45
|
+
disabled: !canSelect(row),
|
|
46
|
+
onCheckedChange: (checked) => toggle(id, checked),
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@surflane/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Surflane React components built on Base UI, with data, chart, code and Markdown components.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"design-system",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"shiki": "4.5.0"
|
|
102
102
|
},
|
|
103
103
|
"peerDependencies": {
|
|
104
|
-
"@surflane/design-tokens": "^0.
|
|
104
|
+
"@surflane/design-tokens": "^0.3.0",
|
|
105
105
|
"react": "^19.0.0",
|
|
106
106
|
"react-dom": "^19.0.0"
|
|
107
107
|
},
|
package/src/styles.css
CHANGED
|
@@ -300,6 +300,14 @@
|
|
|
300
300
|
.pui-scrollbar:hover .pui-scroll-thumb {
|
|
301
301
|
opacity: 0.8;
|
|
302
302
|
}
|
|
303
|
+
/* On touch-only screens a scrollbar is a position indicator, as native mobile
|
|
304
|
+
* scrollbars are: content scrolls by swiping, so the bar overlaying its edge
|
|
305
|
+
* never takes a tap meant for the link or control beneath it. */
|
|
306
|
+
@media (hover: none) and (pointer: coarse) {
|
|
307
|
+
.pui-scrollbar {
|
|
308
|
+
pointer-events: none;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
303
311
|
@media (forced-colors: active) {
|
|
304
312
|
.pui-scrollbar {
|
|
305
313
|
opacity: 1;
|
|
@@ -2711,6 +2719,31 @@
|
|
|
2711
2719
|
background: transparent;
|
|
2712
2720
|
border-radius: 0;
|
|
2713
2721
|
}
|
|
2722
|
+
/* The page surface: concentric with the shell, inset on every side but the
|
|
2723
|
+
* sidebar's. Stretch or size it from its container: a percentage height here
|
|
2724
|
+
* would resolve against a scroll content that sizes from the page itself. */
|
|
2725
|
+
.pui-app-shell-page {
|
|
2726
|
+
box-sizing: border-box;
|
|
2727
|
+
min-inline-size: 0;
|
|
2728
|
+
margin: var(--app-shell-inset);
|
|
2729
|
+
margin-inline-start: 0;
|
|
2730
|
+
padding: var(--space-6);
|
|
2731
|
+
background: var(--canvas);
|
|
2732
|
+
border-radius: max(
|
|
2733
|
+
0px,
|
|
2734
|
+
calc(var(--app-shell-radius) - var(--app-shell-inset))
|
|
2735
|
+
);
|
|
2736
|
+
}
|
|
2737
|
+
/* Without the sidebar the page insets evenly. Below a mobile header it starts flush. */
|
|
2738
|
+
@media (max-width: 760px) {
|
|
2739
|
+
.pui-app-shell-page {
|
|
2740
|
+
margin: var(--app-shell-inset);
|
|
2741
|
+
padding: var(--space-4);
|
|
2742
|
+
}
|
|
2743
|
+
.pui-app-shell:has(> .pui-app-shell-header) .pui-app-shell-page {
|
|
2744
|
+
margin-block-start: 0;
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2714
2747
|
.pui-app-shell[data-layout='workspace'] .pui-app-shell-footer {
|
|
2715
2748
|
padding: var(--space-4);
|
|
2716
2749
|
}
|