@-reddacted-/react-ui 0.3.0 → 0.4.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/components/Accordion.d.ts +27 -0
- package/dist/components/Accordion.d.ts.map +1 -0
- package/dist/components/Accordion.js +35 -0
- package/dist/components/Badge.d.ts +15 -0
- package/dist/components/Badge.d.ts.map +1 -0
- package/dist/components/Badge.js +7 -0
- package/dist/components/Button.d.ts +15 -2
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Button.js +76 -44
- package/dist/components/Card.d.ts +21 -0
- package/dist/components/Card.d.ts.map +1 -0
- package/dist/components/Card.js +17 -0
- package/dist/components/ColorField.d.ts.map +1 -1
- package/dist/components/ColorField.js +1 -1
- package/dist/components/ConfirmDeleteButton.d.ts +4 -1
- package/dist/components/ConfirmDeleteButton.d.ts.map +1 -1
- package/dist/components/ConfirmDeleteButton.js +6 -7
- package/dist/components/Drawer.d.ts +33 -0
- package/dist/components/Drawer.d.ts.map +1 -0
- package/dist/components/Drawer.js +123 -0
- package/dist/components/DropdownMenu.d.ts +61 -0
- package/dist/components/DropdownMenu.d.ts.map +1 -0
- package/dist/components/DropdownMenu.js +302 -0
- package/dist/components/Modal.d.ts.map +1 -1
- package/dist/components/Modal.js +102 -134
- package/dist/components/NavBar.d.ts +11 -14
- package/dist/components/NavBar.d.ts.map +1 -1
- package/dist/components/NavBar.js +53 -31
- package/dist/components/PageStatus.d.ts +12 -12
- package/dist/components/PageStatus.d.ts.map +1 -1
- package/dist/components/PageStatus.js +9 -29
- package/dist/components/Pagination.d.ts +44 -0
- package/dist/components/Pagination.d.ts.map +1 -0
- package/dist/components/Pagination.js +57 -0
- package/dist/components/Skeleton.d.ts +13 -0
- package/dist/components/Skeleton.d.ts.map +1 -0
- package/dist/components/Skeleton.js +15 -0
- package/dist/components/Spinner.d.ts +14 -0
- package/dist/components/Spinner.d.ts.map +1 -0
- package/dist/components/Spinner.js +14 -0
- package/dist/components/Stack.d.ts +13 -0
- package/dist/components/Stack.d.ts.map +1 -0
- package/dist/components/Stack.js +15 -0
- package/dist/components/Table.d.ts +54 -0
- package/dist/components/Table.d.ts.map +1 -0
- package/dist/components/Table.js +101 -0
- package/dist/components/Tabs.d.ts +34 -0
- package/dist/components/Tabs.d.ts.map +1 -0
- package/dist/components/Tabs.js +82 -0
- package/dist/components/Tag.d.ts +10 -0
- package/dist/components/Tag.d.ts.map +1 -0
- package/dist/components/Tag.js +7 -0
- package/dist/components/Tooltip.d.ts +22 -0
- package/dist/components/Tooltip.d.ts.map +1 -0
- package/dist/components/Tooltip.js +76 -0
- package/dist/components/drawerStore.d.ts +11 -0
- package/dist/components/drawerStore.d.ts.map +1 -0
- package/dist/components/drawerStore.js +40 -0
- package/dist/components/paginationItems.d.ts +18 -0
- package/dist/components/paginationItems.d.ts.map +1 -0
- package/dist/components/paginationItems.js +32 -0
- package/dist/index.d.ts +23 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -2
- package/dist/popup/PopupHost.d.ts +19 -3
- package/dist/popup/PopupHost.d.ts.map +1 -1
- package/dist/popup/PopupHost.js +65 -44
- package/dist/popup/PopupProvider.d.ts +19 -2
- package/dist/popup/PopupProvider.d.ts.map +1 -1
- package/dist/popup/PopupProvider.js +69 -17
- package/dist/popup/usePopup.d.ts +11 -4
- package/dist/popup/usePopup.d.ts.map +1 -1
- package/dist/style/accordionCss.d.ts +2 -0
- package/dist/style/accordionCss.d.ts.map +1 -0
- package/dist/style/accordionCss.js +101 -0
- package/dist/style/badgeCss.d.ts +5 -0
- package/dist/style/badgeCss.d.ts.map +1 -0
- package/dist/style/badgeCss.js +68 -0
- package/dist/style/breadcrumbCss.d.ts +2 -0
- package/dist/style/breadcrumbCss.d.ts.map +1 -0
- package/dist/style/breadcrumbCss.js +53 -0
- package/dist/style/cardCss.d.ts +2 -0
- package/dist/style/cardCss.d.ts.map +1 -0
- package/dist/style/cardCss.js +49 -0
- package/dist/style/inputCss.d.ts +2 -0
- package/dist/style/inputCss.d.ts.map +1 -0
- package/dist/style/inputCss.js +107 -0
- package/dist/style/loaderCss.d.ts +2 -0
- package/dist/style/loaderCss.d.ts.map +1 -0
- package/dist/style/loaderCss.js +39 -0
- package/dist/style/menuCss.d.ts +2 -0
- package/dist/style/menuCss.d.ts.map +1 -0
- package/dist/style/menuCss.js +71 -0
- package/dist/style/paginationCss.d.ts +2 -0
- package/dist/style/paginationCss.d.ts.map +1 -0
- package/dist/style/paginationCss.js +57 -0
- package/dist/style/resolveColor.d.ts +8 -0
- package/dist/style/resolveColor.d.ts.map +1 -0
- package/dist/style/resolveColor.js +13 -0
- package/dist/style/stackCss.d.ts +2 -0
- package/dist/style/stackCss.d.ts.map +1 -0
- package/dist/style/stackCss.js +21 -0
- package/dist/style/statusCss.d.ts +2 -0
- package/dist/style/statusCss.d.ts.map +1 -0
- package/dist/style/statusCss.js +38 -0
- package/dist/style/tableCss.d.ts +2 -0
- package/dist/style/tableCss.d.ts.map +1 -0
- package/dist/style/tableCss.js +92 -0
- package/dist/style/tabsCss.d.ts +2 -0
- package/dist/style/tabsCss.d.ts.map +1 -0
- package/dist/style/tabsCss.js +72 -0
- package/dist/style/toLength.d.ts +4 -0
- package/dist/style/toLength.d.ts.map +1 -0
- package/dist/style/toLength.js +3 -0
- package/dist/style/tooltipCss.d.ts +2 -0
- package/dist/style/tooltipCss.d.ts.map +1 -0
- package/dist/style/tooltipCss.js +44 -0
- package/dist/style/useStyle.d.ts +7 -0
- package/dist/style/useStyle.d.ts.map +1 -0
- package/dist/style/useStyle.js +16 -0
- package/dist/theme/ThemeProvider.d.ts.map +1 -1
- package/dist/theme/ThemeProvider.js +32 -0
- package/dist/theme/palette.d.ts.map +1 -1
- package/dist/theme/palette.js +0 -2
- package/dist/tooltip/attributeTooltips.d.ts +7 -0
- package/dist/tooltip/attributeTooltips.d.ts.map +1 -0
- package/dist/tooltip/attributeTooltips.js +76 -0
- package/dist/tooltip/tooltipEngine.d.ts +41 -0
- package/dist/tooltip/tooltipEngine.d.ts.map +1 -0
- package/dist/tooltip/tooltipEngine.js +128 -0
- package/dist/utils/childRef.d.ts +5 -0
- package/dist/utils/childRef.d.ts.map +1 -0
- package/dist/utils/childRef.js +14 -0
- package/dist/utils/isDev.d.ts +3 -0
- package/dist/utils/isDev.d.ts.map +1 -0
- package/dist/utils/isDev.js +4 -0
- package/package.json +5 -4
|
@@ -1,31 +1,53 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
return (
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useStyle } from "../style/useStyle.js";
|
|
3
|
+
export function NavBar({ children, className, style }) {
|
|
4
|
+
useStyle("navbar", navBarCss);
|
|
5
|
+
return (_jsx("nav", { className: className ? `rui-navbar ${className}` : "rui-navbar", style: style, children: children }));
|
|
6
|
+
}
|
|
7
|
+
/** Takes the free space, pushing the following children to the right. */
|
|
8
|
+
function Spacer() {
|
|
9
|
+
return _jsx("span", { className: "rui-navbar-spacer", "aria-hidden": "true" });
|
|
10
|
+
}
|
|
11
|
+
NavBar.Spacer = Spacer;
|
|
12
|
+
// Every selector is wrapped in :where() so it has zero specificity:
|
|
13
|
+
// any class or style set by the consuming project wins without !important.
|
|
14
|
+
const navBarCss = `
|
|
15
|
+
:where(.rui-navbar) {
|
|
16
|
+
display: flex;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: 0.5rem;
|
|
19
|
+
padding: 0 1.5rem;
|
|
20
|
+
height: 56px;
|
|
21
|
+
border-bottom: 1px solid var(--color-border);
|
|
22
|
+
background-color: var(--color-surface);
|
|
23
|
+
}
|
|
24
|
+
:where(.rui-navbar-spacer) {
|
|
25
|
+
flex: 1;
|
|
26
|
+
}
|
|
27
|
+
:where(.rui-navbar img) {
|
|
28
|
+
display: block;
|
|
29
|
+
max-height: 32px;
|
|
30
|
+
}
|
|
31
|
+
:where(.rui-navbar) > :where(a, button) {
|
|
32
|
+
display: inline-flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
gap: 0.5rem;
|
|
35
|
+
padding: 0.375rem 0.75rem;
|
|
36
|
+
border: none;
|
|
37
|
+
border-radius: 6px;
|
|
38
|
+
background-color: transparent;
|
|
39
|
+
color: var(--color-text-muted);
|
|
40
|
+
font: inherit;
|
|
41
|
+
font-size: 0.875rem;
|
|
42
|
+
font-weight: 500;
|
|
43
|
+
text-decoration: none;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
}
|
|
46
|
+
:where(.rui-navbar) > :where(a, button):hover {
|
|
47
|
+
color: var(--color-text);
|
|
48
|
+
}
|
|
49
|
+
:where(.rui-navbar) > :where([aria-current="page"], [aria-pressed="true"]) {
|
|
50
|
+
background-color: var(--color-border);
|
|
51
|
+
color: var(--color-text);
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
type ErrorMessageProps = {
|
|
9
|
-
onRetry?: () => void;
|
|
10
|
-
label?: string;
|
|
11
|
-
retryLabel?: string;
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
type PageStatusProps = Omit<HTMLAttributes<HTMLDivElement>, "title"> & {
|
|
3
|
+
icon?: ReactNode;
|
|
4
|
+
title?: ReactNode;
|
|
5
|
+
description?: ReactNode;
|
|
6
|
+
/** Buttons or links, e.g. a retry. */
|
|
7
|
+
action?: ReactNode;
|
|
12
8
|
};
|
|
13
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Loading, empty, error or success state, centered horizontally. Every slot is optional and
|
|
11
|
+
* no text is provided by default. Pass `role="status"` (loading) or `role="alert"` (error).
|
|
12
|
+
*/
|
|
13
|
+
export declare function PageStatus({ icon, title, description, action, className, children, ...props }: PageStatusProps): import("react").JSX.Element;
|
|
14
14
|
export {};
|
|
15
15
|
//# sourceMappingURL=PageStatus.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageStatus.d.ts","sourceRoot":"","sources":["../../src/components/PageStatus.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"PageStatus.d.ts","sourceRoot":"","sources":["../../src/components/PageStatus.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItD,KAAK,eAAe,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,GAAG;IACrE,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,sCAAsC;IACtC,MAAM,CAAC,EAAE,SAAS,CAAA;CACnB,CAAA;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,eAAe,+BAW9G"}
|
|
@@ -1,31 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { statusCss } from "../style/statusCss.js";
|
|
3
|
+
import { useStyle } from "../style/useStyle.js";
|
|
4
|
+
/**
|
|
5
|
+
* Loading, empty, error or success state, centered horizontally. Every slot is optional and
|
|
6
|
+
* no text is provided by default. Pass `role="status"` (loading) or `role="alert"` (error).
|
|
7
|
+
*/
|
|
8
|
+
export function PageStatus({ icon, title, description, action, className, children, ...props }) {
|
|
9
|
+
useStyle("status", statusCss);
|
|
10
|
+
return (_jsxs("div", { ...props, className: className ? `rui-status ${className}` : "rui-status", children: [icon !== undefined && _jsx("div", { className: "rui-status-icon", children: icon }), title !== undefined && _jsx("p", { className: "rui-status-title", children: title }), description !== undefined && _jsx("p", { className: "rui-status-description", children: description }), action !== undefined && _jsx("div", { className: "rui-status-action", children: action }), children] }));
|
|
5
11
|
}
|
|
6
|
-
export function LoadingMessage({ label = "Loading..." }) {
|
|
7
|
-
return (_jsx(PageMessage, { children: _jsx("p", { style: mutedStyle, role: "status", children: label }) }));
|
|
8
|
-
}
|
|
9
|
-
export function ErrorMessage({ onRetry, label = "The content could not be loaded. Check your connection, then try again.", retryLabel = "Try again", }) {
|
|
10
|
-
return (_jsx(PageMessage, { children: _jsxs("div", { style: stackStyle, children: [_jsx("p", { style: mutedStyle, role: "alert", children: label }), onRetry && (_jsx(Button, { variant: "secondary", onClick: onRetry, children: retryLabel }))] }) }));
|
|
11
|
-
}
|
|
12
|
-
const containerStyle = {
|
|
13
|
-
flex: 1,
|
|
14
|
-
display: "flex",
|
|
15
|
-
alignItems: "center",
|
|
16
|
-
justifyContent: "center",
|
|
17
|
-
padding: "2rem",
|
|
18
|
-
backgroundColor: "var(--color-bg)",
|
|
19
|
-
};
|
|
20
|
-
const stackStyle = {
|
|
21
|
-
display: "flex",
|
|
22
|
-
flexDirection: "column",
|
|
23
|
-
alignItems: "center",
|
|
24
|
-
gap: "1rem",
|
|
25
|
-
textAlign: "center",
|
|
26
|
-
};
|
|
27
|
-
const mutedStyle = {
|
|
28
|
-
margin: 0,
|
|
29
|
-
fontSize: "0.9375rem",
|
|
30
|
-
color: "var(--color-text-muted)",
|
|
31
|
-
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
import type { PaginationItem } from "./paginationItems.js";
|
|
3
|
+
type PaginationLabels = {
|
|
4
|
+
nav?: string;
|
|
5
|
+
first?: string;
|
|
6
|
+
previous?: string;
|
|
7
|
+
next?: string;
|
|
8
|
+
last?: string;
|
|
9
|
+
page?: (page: number) => string;
|
|
10
|
+
jumpTo?: string;
|
|
11
|
+
};
|
|
12
|
+
type ItemProps = {
|
|
13
|
+
className: string;
|
|
14
|
+
"aria-current"?: "page";
|
|
15
|
+
"aria-label"?: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
onClick: () => void;
|
|
18
|
+
};
|
|
19
|
+
type PaginationProps = {
|
|
20
|
+
/** 1-based. */
|
|
21
|
+
page: number;
|
|
22
|
+
/** Number of pages. */
|
|
23
|
+
total: number;
|
|
24
|
+
onPageChange: (page: number) => void;
|
|
25
|
+
/** Pages shown on each side of the current one. Defaults to 1. */
|
|
26
|
+
siblings?: number;
|
|
27
|
+
/** First / last buttons. Defaults to true. */
|
|
28
|
+
showEdges?: boolean;
|
|
29
|
+
/** Adds a number field to type the page to go to. */
|
|
30
|
+
jumpTo?: boolean;
|
|
31
|
+
/** Accessible names; the buttons only show symbols. */
|
|
32
|
+
labels?: PaginationLabels;
|
|
33
|
+
/** Renders an item yourself, e.g. as a router link; ellipses are not passed here. */
|
|
34
|
+
renderItem?: (item: Exclude<PaginationItem, {
|
|
35
|
+
type: "ellipsis";
|
|
36
|
+
}>, props: ItemProps) => ReactNode;
|
|
37
|
+
/** Current page color. `"--color-x"` reads the theme variable. Defaults to `"--color-primary"`. */
|
|
38
|
+
color?: string;
|
|
39
|
+
className?: string;
|
|
40
|
+
style?: CSSProperties;
|
|
41
|
+
};
|
|
42
|
+
export declare function Pagination({ page, total, onPageChange, siblings, showEdges, jumpTo, labels, renderItem, color, className, style, }: PaginationProps): import("react").JSX.Element;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=Pagination.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../src/components/Pagination.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAMpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,KAAK,gBAAgB,GAAG;IACtB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,KAAK,SAAS,GAAG;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB,CAAA;AAED,KAAK,eAAe,GAAG;IACrB,eAAe;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACpC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,qDAAqD;IACrD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,uDAAuD;IACvD,MAAM,CAAC,EAAE,gBAAgB,CAAA;IACzB,qFAAqF;IACrF,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,cAAc,EAAE;QAAE,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,EAAE,KAAK,EAAE,SAAS,KAAK,SAAS,CAAA;IACjG,mGAAmG;IACnG,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;CACtB,CAAA;AAID,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,KAAK,EACL,YAAY,EACZ,QAAY,EACZ,SAAgB,EAChB,MAAc,EACd,MAAW,EACX,UAAU,EACV,KAAyB,EACzB,SAAS,EACT,KAAK,GACN,EAAE,eAAe,+BAiGjB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { paginationCss } from "../style/paginationCss.js";
|
|
4
|
+
import { resolveColor, resolveOnColor } from "../style/resolveColor.js";
|
|
5
|
+
import { useStyle } from "../style/useStyle.js";
|
|
6
|
+
import { isDev } from "../utils/isDev.js";
|
|
7
|
+
import { getPaginationItems } from "./paginationItems.js";
|
|
8
|
+
const SYMBOLS = { first: "«", previous: "‹", next: "›", last: "»" };
|
|
9
|
+
export function Pagination({ page, total, onPageChange, siblings = 1, showEdges = true, jumpTo = false, labels = {}, renderItem, color = "--color-primary", className, style, }) {
|
|
10
|
+
useStyle("pagination", paginationCss);
|
|
11
|
+
const last = Math.max(1, total);
|
|
12
|
+
const current = Math.min(Math.max(1, page), last);
|
|
13
|
+
const [draft, setDraft] = useState("");
|
|
14
|
+
const missingLabels = !labels.previous || !labels.next;
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (missingLabels && isDev()) {
|
|
17
|
+
console.warn("Pagination: pass labels.previous and labels.next, the buttons only show symbols.");
|
|
18
|
+
}
|
|
19
|
+
}, [missingLabels]);
|
|
20
|
+
const goTo = (target) => {
|
|
21
|
+
if (target !== current)
|
|
22
|
+
onPageChange(target);
|
|
23
|
+
};
|
|
24
|
+
const submitDraft = () => {
|
|
25
|
+
const target = Number.parseInt(draft, 10);
|
|
26
|
+
setDraft("");
|
|
27
|
+
if (Number.isNaN(target))
|
|
28
|
+
return;
|
|
29
|
+
goTo(Math.min(Math.max(1, target), last));
|
|
30
|
+
};
|
|
31
|
+
const onJumpKeyDown = (event) => {
|
|
32
|
+
if (event.key === "Enter")
|
|
33
|
+
submitDraft();
|
|
34
|
+
};
|
|
35
|
+
const items = getPaginationItems(current, last, siblings, showEdges);
|
|
36
|
+
return (_jsx("nav", { "aria-label": labels.nav, className: className ? `rui-pagination ${className}` : "rui-pagination", style: {
|
|
37
|
+
"--rui-pagination-accent": resolveColor(color),
|
|
38
|
+
"--rui-pagination-on": resolveOnColor(color),
|
|
39
|
+
...style,
|
|
40
|
+
}, children: _jsxs("ul", { children: [items.map((item, index) => {
|
|
41
|
+
if (item.type === "ellipsis") {
|
|
42
|
+
return (_jsx("li", { children: _jsx("span", { className: "rui-pagination-ellipsis", "aria-hidden": "true", children: "\u2026" }) }, `ellipsis-${index}`));
|
|
43
|
+
}
|
|
44
|
+
const isPage = item.type === "page";
|
|
45
|
+
const props = {
|
|
46
|
+
className: "rui-pagination-item",
|
|
47
|
+
"aria-current": isPage && item.current ? "page" : undefined,
|
|
48
|
+
"aria-label": isPage ? labels.page?.(item.page) : labels[item.type],
|
|
49
|
+
disabled: isPage ? undefined : item.disabled,
|
|
50
|
+
onClick: () => goTo(item.page),
|
|
51
|
+
};
|
|
52
|
+
const key = isPage ? `page-${item.page}` : item.type;
|
|
53
|
+
return (_jsx("li", { children: renderItem ? (renderItem(item, props)) : (_jsx("button", { type: "button", ...props, children: isPage ? item.page : SYMBOLS[item.type] })) }, key));
|
|
54
|
+
}), jumpTo && (_jsx("li", { children: _jsx("input", { type: "number", className: "rui-input rui-pagination-jump", min: 1, max: last, inputMode: "numeric", placeholder: String(current), "aria-label": labels.jumpTo, value: draft, onChange: event => setDraft(event.target.value), onKeyDown: onJumpKeyDown, onBlur: submitDraft,
|
|
55
|
+
// Inline because rui-input's full width may be injected after this sheet.
|
|
56
|
+
style: { width: "var(--rui-pagination-jump-width, 4.5rem)" } }) }))] }) }));
|
|
57
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { HTMLAttributes } from "react";
|
|
2
|
+
type SkeletonProps = HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
/** Numbers are pixels. Defaults to `"100%"`. */
|
|
4
|
+
width?: string | number;
|
|
5
|
+
/** Numbers are pixels. Defaults to `"1em"`. */
|
|
6
|
+
height?: string | number;
|
|
7
|
+
/** `"--color-x"` reads the theme variable; anything else is a raw CSS color. Defaults to `--color-border`. */
|
|
8
|
+
color?: string;
|
|
9
|
+
};
|
|
10
|
+
/** Decorative placeholder: its shape (size, radius) is up to the project. */
|
|
11
|
+
export declare function Skeleton({ width, height, color, className, style, ...props }: SkeletonProps): import("react").JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=Skeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skeleton.d.ts","sourceRoot":"","sources":["../../src/components/Skeleton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,OAAO,CAAA;AAM1D,KAAK,aAAa,GAAG,cAAc,CAAC,cAAc,CAAC,GAAG;IACpD,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACxB,8GAA8G;IAC9G,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,EAAE,KAAc,EAAE,MAAc,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,aAAa,+BAiB5G"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { resolveColor } from "../style/resolveColor.js";
|
|
3
|
+
import { loaderCss } from "../style/loaderCss.js";
|
|
4
|
+
import { toLength } from "../style/toLength.js";
|
|
5
|
+
import { useStyle } from "../style/useStyle.js";
|
|
6
|
+
/** Decorative placeholder: its shape (size, radius) is up to the project. */
|
|
7
|
+
export function Skeleton({ width = "100%", height = "1em", color, className, style, ...props }) {
|
|
8
|
+
useStyle("loader", loaderCss);
|
|
9
|
+
return (_jsx("div", { "aria-hidden": "true", ...props, className: className ? `rui-skeleton ${className}` : "rui-skeleton", style: {
|
|
10
|
+
width: toLength(width),
|
|
11
|
+
height: toLength(height),
|
|
12
|
+
"--rui-skeleton-color": color && resolveColor(color),
|
|
13
|
+
...style,
|
|
14
|
+
} }));
|
|
15
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { HTMLAttributes } from "react";
|
|
2
|
+
type SpinnerProps = HTMLAttributes<HTMLSpanElement> & {
|
|
3
|
+
/** Numbers are pixels. Defaults to `"1em"`. */
|
|
4
|
+
size?: string | number;
|
|
5
|
+
/** Stroke width. Numbers are pixels. Defaults to `"0.15em"`. */
|
|
6
|
+
thickness?: string | number;
|
|
7
|
+
/** `"--color-x"` reads the theme variable; anything else is a raw CSS color. Defaults to the text color. */
|
|
8
|
+
color?: string;
|
|
9
|
+
/** Accessible name. Defaults to `"Loading"`. */
|
|
10
|
+
label?: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function Spinner({ size, thickness, color, label, className, style, ...props }: SpinnerProps): import("react").JSX.Element;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=Spinner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Spinner.d.ts","sourceRoot":"","sources":["../../src/components/Spinner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,cAAc,EAAE,MAAM,OAAO,CAAA;AAM1D,KAAK,YAAY,GAAG,cAAc,CAAC,eAAe,CAAC,GAAG;IACpD,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC3B,4GAA4G;IAC5G,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAED,wBAAgB,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAiB,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,YAAY,+BAkB9G"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { resolveColor } from "../style/resolveColor.js";
|
|
3
|
+
import { loaderCss } from "../style/loaderCss.js";
|
|
4
|
+
import { toLength } from "../style/toLength.js";
|
|
5
|
+
import { useStyle } from "../style/useStyle.js";
|
|
6
|
+
export function Spinner({ size, thickness, color, label = "Loading", className, style, ...props }) {
|
|
7
|
+
useStyle("loader", loaderCss);
|
|
8
|
+
return (_jsx("span", { role: "status", "aria-label": label, ...props, className: className ? `rui-spinner ${className}` : "rui-spinner", style: {
|
|
9
|
+
"--rui-spinner-size": toLength(size),
|
|
10
|
+
"--rui-spinner-thickness": toLength(thickness),
|
|
11
|
+
"--rui-spinner-color": color && resolveColor(color),
|
|
12
|
+
...style,
|
|
13
|
+
} }));
|
|
14
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CSSProperties, HTMLAttributes } from "react";
|
|
2
|
+
type StackProps = HTMLAttributes<HTMLDivElement> & {
|
|
3
|
+
/** Defaults to `"column"`. */
|
|
4
|
+
direction?: "row" | "column" | "row-reverse" | "column-reverse";
|
|
5
|
+
/** Numbers are pixels. Defaults to `"0.75rem"`. */
|
|
6
|
+
gap?: string | number;
|
|
7
|
+
align?: CSSProperties["alignItems"];
|
|
8
|
+
justify?: CSSProperties["justifyContent"];
|
|
9
|
+
wrap?: boolean;
|
|
10
|
+
};
|
|
11
|
+
export declare function Stack({ direction, gap, align, justify, wrap, className, style, ...props }: StackProps): import("react").JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=Stack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Stack.d.ts","sourceRoot":"","sources":["../../src/components/Stack.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAK1D,KAAK,UAAU,GAAG,cAAc,CAAC,cAAc,CAAC,GAAG;IACjD,8BAA8B;IAC9B,SAAS,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,aAAa,GAAG,gBAAgB,CAAA;IAC/D,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAA;IACnC,OAAO,CAAC,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAA;IACzC,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAA;AAED,wBAAgB,KAAK,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,+BAkBrG"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { stackCss } from "../style/stackCss.js";
|
|
3
|
+
import { toLength } from "../style/toLength.js";
|
|
4
|
+
import { useStyle } from "../style/useStyle.js";
|
|
5
|
+
export function Stack({ direction, gap, align, justify, wrap, className, style, ...props }) {
|
|
6
|
+
useStyle("stack", stackCss);
|
|
7
|
+
return (_jsx("div", { ...props, className: className ? `rui-stack ${className}` : "rui-stack", style: {
|
|
8
|
+
"--rui-stack-direction": direction,
|
|
9
|
+
"--rui-stack-gap": toLength(gap),
|
|
10
|
+
"--rui-stack-align": align,
|
|
11
|
+
"--rui-stack-justify": justify,
|
|
12
|
+
"--rui-stack-wrap": wrap === undefined ? undefined : wrap ? "wrap" : "nowrap",
|
|
13
|
+
...style,
|
|
14
|
+
} }));
|
|
15
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
export type SortState = {
|
|
3
|
+
key: string;
|
|
4
|
+
direction: "asc" | "desc";
|
|
5
|
+
} | null;
|
|
6
|
+
export type TableColumn<T> = {
|
|
7
|
+
key: string;
|
|
8
|
+
header: ReactNode;
|
|
9
|
+
/** Defaults to `row[key]`. */
|
|
10
|
+
cell?: (row: T) => ReactNode;
|
|
11
|
+
sortable?: boolean;
|
|
12
|
+
/** Ascending order. Defaults to numbers, dates, then strings (locale aware), empty values last. */
|
|
13
|
+
compare?: (a: T, b: T) => number;
|
|
14
|
+
/** Numbers are pixels. */
|
|
15
|
+
width?: string | number;
|
|
16
|
+
align?: "left" | "center" | "right";
|
|
17
|
+
};
|
|
18
|
+
type TableProps<T> = {
|
|
19
|
+
columns: TableColumn<T>[];
|
|
20
|
+
data: T[];
|
|
21
|
+
rowKey: keyof T | ((row: T) => string);
|
|
22
|
+
/** Controlled sort: the project sorts `data` itself (e.g. server side). */
|
|
23
|
+
sort?: SortState;
|
|
24
|
+
/** Uncontrolled sort: the table sorts `data`, starting with this. */
|
|
25
|
+
defaultSort?: SortState;
|
|
26
|
+
onSortChange?: (sort: SortState) => void;
|
|
27
|
+
/** Row selection by click or Space / Enter. Defaults to `"none"`. */
|
|
28
|
+
selectionMode?: "none" | "single" | "multiple";
|
|
29
|
+
/** Controlled selection (row keys). */
|
|
30
|
+
selected?: string[];
|
|
31
|
+
defaultSelected?: string[];
|
|
32
|
+
onSelectedChange?: (keys: string[]) => void;
|
|
33
|
+
/** Shown instead of the rows when `data` is empty. */
|
|
34
|
+
empty?: ReactNode;
|
|
35
|
+
/** Shows `loadingRows` skeleton rows instead of the data. */
|
|
36
|
+
loading?: boolean;
|
|
37
|
+
/** Defaults to 3. */
|
|
38
|
+
loadingRows?: number;
|
|
39
|
+
/** Defaults to `"horizontal"`. */
|
|
40
|
+
borders?: "horizontal" | "grid" | "none";
|
|
41
|
+
/** Header stays visible while scrolling; give the table (or its wrapper) a limited height. */
|
|
42
|
+
stickyHeader?: boolean;
|
|
43
|
+
/** Cell padding, e.g. `"0.375rem 0.625rem"`. */
|
|
44
|
+
density?: string;
|
|
45
|
+
/** Hover and selection tint. `"--color-x"` reads the theme variable. Defaults to `"--color-primary"`. */
|
|
46
|
+
color?: string;
|
|
47
|
+
/** Row hover tint; on by default when rows are selectable. */
|
|
48
|
+
hover?: boolean;
|
|
49
|
+
className?: string;
|
|
50
|
+
style?: CSSProperties;
|
|
51
|
+
};
|
|
52
|
+
export declare function Table<T>({ columns, data, rowKey, sort: controlledSort, defaultSort, onSortChange, selectionMode, selected: controlledSelected, defaultSelected, onSelectedChange, empty, loading, loadingRows, borders, stickyHeader, density, color, hover, className, style, }: TableProps<T>): import("react").JSX.Element;
|
|
53
|
+
export {};
|
|
54
|
+
//# sourceMappingURL=Table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Table.d.ts","sourceRoot":"","sources":["../../src/components/Table.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAA6B,SAAS,EAAE,MAAM,OAAO,CAAA;AAOhF,MAAM,MAAM,SAAS,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;CAAE,GAAG,IAAI,CAAA;AAEzE,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,SAAS,CAAA;IACjB,8BAA8B;IAC9B,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,SAAS,CAAA;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,mGAAmG;IACnG,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IAChC,0BAA0B;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;CACpC,CAAA;AAED,KAAK,UAAU,CAAC,CAAC,IAAI;IACnB,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;IACzB,IAAI,EAAE,CAAC,EAAE,CAAA;IACT,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM,CAAC,CAAA;IACtC,2EAA2E;IAC3E,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,qEAAqE;IACrE,WAAW,CAAC,EAAE,SAAS,CAAA;IACvB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACxC,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAA;IAC9C,uCAAuC;IACvC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IAC3C,sDAAsD;IACtD,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qBAAqB;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kCAAkC;IAClC,OAAO,CAAC,EAAE,YAAY,GAAG,MAAM,GAAG,MAAM,CAAA;IACxC,8FAA8F;IAC9F,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yGAAyG;IACzG,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,8DAA8D;IAC9D,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;CACtB,CAAA;AAkBD,wBAAgB,KAAK,CAAC,CAAC,EAAE,EACvB,OAAO,EACP,IAAI,EACJ,MAAM,EACN,IAAI,EAAE,cAAc,EACpB,WAAkB,EAClB,YAAY,EACZ,aAAsB,EACtB,QAAQ,EAAE,kBAAkB,EAC5B,eAAoB,EACpB,gBAAgB,EAChB,KAAK,EACL,OAAe,EACf,WAAe,EACf,OAAsB,EACtB,YAAoB,EACpB,OAAO,EACP,KAAK,EACL,KAAK,EACL,SAAS,EACT,KAAK,GACN,EAAE,UAAU,CAAC,CAAC,CAAC,+BAkJf"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
|
+
import { resolveColor } from "../style/resolveColor.js";
|
|
4
|
+
import { tableCss } from "../style/tableCss.js";
|
|
5
|
+
import { toLength } from "../style/toLength.js";
|
|
6
|
+
import { useStyle } from "../style/useStyle.js";
|
|
7
|
+
import { Skeleton } from "./Skeleton.js";
|
|
8
|
+
const INTERACTIVE = "a, button, input, select, textarea, label, [role='button']";
|
|
9
|
+
function defaultCompare(a, b) {
|
|
10
|
+
const emptyA = a === null || a === undefined || a === "";
|
|
11
|
+
const emptyB = b === null || b === undefined || b === "";
|
|
12
|
+
if (emptyA || emptyB)
|
|
13
|
+
return emptyA === emptyB ? 0 : emptyA ? 1 : -1;
|
|
14
|
+
if (typeof a === "number" && typeof b === "number")
|
|
15
|
+
return a - b;
|
|
16
|
+
if (a instanceof Date && b instanceof Date)
|
|
17
|
+
return a.getTime() - b.getTime();
|
|
18
|
+
return String(a).localeCompare(String(b), undefined, { numeric: true });
|
|
19
|
+
}
|
|
20
|
+
function nextSort(current, key) {
|
|
21
|
+
if (current?.key !== key)
|
|
22
|
+
return { key, direction: "asc" };
|
|
23
|
+
return current.direction === "asc" ? { key, direction: "desc" } : null;
|
|
24
|
+
}
|
|
25
|
+
export function Table({ columns, data, rowKey, sort: controlledSort, defaultSort = null, onSortChange, selectionMode = "none", selected: controlledSelected, defaultSelected = [], onSelectedChange, empty, loading = false, loadingRows = 3, borders = "horizontal", stickyHeader = false, density, color, hover, className, style, }) {
|
|
26
|
+
useStyle("table", tableCss);
|
|
27
|
+
const [uncontrolledSort, setUncontrolledSort] = useState(defaultSort);
|
|
28
|
+
const sortControlled = controlledSort !== undefined;
|
|
29
|
+
const sort = sortControlled ? controlledSort : uncontrolledSort;
|
|
30
|
+
const [uncontrolledSelected, setUncontrolledSelected] = useState(defaultSelected);
|
|
31
|
+
const selected = controlledSelected ?? uncontrolledSelected;
|
|
32
|
+
const selectable = selectionMode !== "none";
|
|
33
|
+
const getKey = (row) => (typeof rowKey === "function" ? rowKey(row) : String(row[rowKey]));
|
|
34
|
+
// Depends on the sorted column's compare, not on `columns` (usually a new array each render).
|
|
35
|
+
const sortColumn = sort ? columns.find(c => c.key === sort.key) : undefined;
|
|
36
|
+
const sortKey = sortColumn?.key;
|
|
37
|
+
const sortCompare = sortColumn?.compare;
|
|
38
|
+
const direction = sort?.direction;
|
|
39
|
+
const rows = useMemo(() => {
|
|
40
|
+
if (sortControlled || sortKey === undefined)
|
|
41
|
+
return data;
|
|
42
|
+
const compare = sortCompare ?? ((a, b) => defaultCompare(a[sortKey], b[sortKey]));
|
|
43
|
+
const sign = direction === "asc" ? 1 : -1;
|
|
44
|
+
return [...data].sort((a, b) => sign * compare(a, b));
|
|
45
|
+
}, [data, sortKey, sortCompare, direction, sortControlled]);
|
|
46
|
+
const changeSort = (key) => {
|
|
47
|
+
const next = nextSort(sort, key);
|
|
48
|
+
if (!sortControlled)
|
|
49
|
+
setUncontrolledSort(next);
|
|
50
|
+
onSortChange?.(next);
|
|
51
|
+
};
|
|
52
|
+
const toggleRow = (key) => {
|
|
53
|
+
const isSelected = selected.includes(key);
|
|
54
|
+
const next = selectionMode === "single"
|
|
55
|
+
? isSelected
|
|
56
|
+
? []
|
|
57
|
+
: [key]
|
|
58
|
+
: isSelected
|
|
59
|
+
? selected.filter(k => k !== key)
|
|
60
|
+
: [...selected, key];
|
|
61
|
+
if (controlledSelected === undefined)
|
|
62
|
+
setUncontrolledSelected(next);
|
|
63
|
+
onSelectedChange?.(next);
|
|
64
|
+
};
|
|
65
|
+
const onRowClick = (event, key) => {
|
|
66
|
+
// A click on a button or link inside a cell is its own action, not a selection.
|
|
67
|
+
const interactive = event.target.closest(INTERACTIVE);
|
|
68
|
+
if (interactive && event.currentTarget.contains(interactive))
|
|
69
|
+
return;
|
|
70
|
+
toggleRow(key);
|
|
71
|
+
};
|
|
72
|
+
const onRowKeyDown = (event, key) => {
|
|
73
|
+
if (event.target !== event.currentTarget || (event.key !== " " && event.key !== "Enter"))
|
|
74
|
+
return;
|
|
75
|
+
event.preventDefault();
|
|
76
|
+
toggleRow(key);
|
|
77
|
+
};
|
|
78
|
+
const cellStyle = (column) => column.align || column.width !== undefined ? { textAlign: column.align, width: toLength(column.width) } : undefined;
|
|
79
|
+
let body;
|
|
80
|
+
if (loading) {
|
|
81
|
+
body = Array.from({ length: loadingRows }, (_, i) => (_jsx("tr", { children: columns.map(column => (_jsx("td", { children: _jsx(Skeleton, {}) }, column.key))) }, i)));
|
|
82
|
+
}
|
|
83
|
+
else if (rows.length === 0) {
|
|
84
|
+
body = (_jsx("tr", { children: _jsx("td", { className: "rui-table-empty", colSpan: columns.length, children: empty }) }));
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
body = rows.map(row => {
|
|
88
|
+
const key = getKey(row);
|
|
89
|
+
const isSelected = selectable && selected.includes(key);
|
|
90
|
+
return (_jsx("tr", { "aria-selected": selectable ? isSelected : undefined, tabIndex: selectable ? 0 : undefined, onClick: selectable ? event => onRowClick(event, key) : undefined, onKeyDown: selectable ? event => onRowKeyDown(event, key) : undefined, children: columns.map(column => (_jsx("td", { style: cellStyle(column), children: column.cell ? column.cell(row) : row[column.key] }, column.key))) }, key));
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return (_jsx("div", { className: "rui-table-wrap", children: _jsxs("table", { className: className ? `rui-table ${className}` : "rui-table", "data-borders": borders, "data-sticky-header": stickyHeader || undefined, "data-hover": (hover ?? selectable) || undefined, "aria-multiselectable": selectionMode === "multiple" || undefined, "aria-busy": loading || undefined, style: {
|
|
94
|
+
"--rui-table-cell-padding": density,
|
|
95
|
+
"--rui-table-accent": color && resolveColor(color),
|
|
96
|
+
...style,
|
|
97
|
+
}, children: [_jsx("thead", { children: _jsx("tr", { children: columns.map(column => {
|
|
98
|
+
const sorted = sort?.key === column.key ? sort.direction : undefined;
|
|
99
|
+
return (_jsx("th", { scope: "col", "aria-sort": sorted === "asc" ? "ascending" : sorted === "desc" ? "descending" : undefined, style: cellStyle(column), children: column.sortable ? (_jsx("button", { type: "button", className: "rui-table-sort", onClick: () => changeSort(column.key), children: column.header })) : (column.header) }, column.key));
|
|
100
|
+
}) }) }), _jsx("tbody", { children: body })] }) }));
|
|
101
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CSSProperties, HTMLAttributes, ReactNode } from "react";
|
|
2
|
+
type TabsProps = {
|
|
3
|
+
/** Controlled mode: the active tab's value. */
|
|
4
|
+
value?: string;
|
|
5
|
+
/** Uncontrolled mode: the tab active on mount. */
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
onChange?: (value: string) => void;
|
|
8
|
+
/** Defaults to `"underline"`. */
|
|
9
|
+
variant?: "underline" | "pill";
|
|
10
|
+
/** Defaults to `"horizontal"`. */
|
|
11
|
+
orientation?: "horizontal" | "vertical";
|
|
12
|
+
/** `"--color-x"` reads the theme variable; anything else is a raw CSS color. Defaults to `"--color-primary"`. */
|
|
13
|
+
color?: string;
|
|
14
|
+
/** Keeps inactive panels mounted (and hidden) instead of unmounting them. */
|
|
15
|
+
keepMounted?: boolean;
|
|
16
|
+
className?: string;
|
|
17
|
+
style?: CSSProperties;
|
|
18
|
+
children: ReactNode;
|
|
19
|
+
};
|
|
20
|
+
export declare function Tabs({ value: controlledValue, defaultValue, onChange, variant, orientation, color, keepMounted, className, style, children, }: TabsProps): import("react").JSX.Element;
|
|
21
|
+
export declare namespace Tabs {
|
|
22
|
+
var List: ({ className, style, onKeyDown, ...props }: HTMLAttributes<HTMLDivElement>) => import("react").JSX.Element;
|
|
23
|
+
var Tab: ({ value, disabled, onClick, ...props }: TabProps) => import("react").JSX.Element;
|
|
24
|
+
var Panel: ({ value, ...props }: PanelProps) => import("react").JSX.Element | null;
|
|
25
|
+
}
|
|
26
|
+
type TabProps = HTMLAttributes<HTMLButtonElement> & {
|
|
27
|
+
value: string;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
};
|
|
30
|
+
type PanelProps = HTMLAttributes<HTMLDivElement> & {
|
|
31
|
+
value: string;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=Tabs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../src/components/Tabs.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AA4BpF,KAAK,SAAS,GAAG;IACf,+CAA+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,iCAAiC;IACjC,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;IAC9B,kCAAkC;IAClC,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAA;IACvC,iHAAiH;IACjH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,aAAa,CAAA;IACrB,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED,wBAAgB,IAAI,CAAC,EACnB,KAAK,EAAE,eAAe,EACtB,YAAY,EACZ,QAAQ,EACR,OAAqB,EACrB,WAA0B,EAC1B,KAAyB,EACzB,WAAmB,EACnB,SAAS,EACT,KAAK,EACL,QAAQ,GACT,EAAE,SAAS,+BAoBX;yBA/Be,IAAI;0DAqCqC,cAAc,CAAC,cAAc,CAAC;sDA0ClC,QAAQ;qCAyBzB,UAAU;;AA9B9C,KAAK,QAAQ,GAAG,cAAc,CAAC,iBAAiB,CAAC,GAAG;IAClD,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA;AAyBD,KAAK,UAAU,GAAG,cAAc,CAAC,cAAc,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA"}
|