@surflane/ui 0.11.0 → 0.13.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/alert-dialog.d.ts +25 -7
- package/dist/alert-dialog.js +9 -4
- package/dist/app-shell.d.ts +10 -0
- package/dist/app-shell.js +7 -1
- package/dist/autocomplete.d.ts +2 -6
- package/dist/avatar.d.ts +7 -7
- package/dist/avatar.js +2 -2
- package/dist/bar-list.d.ts +31 -0
- package/dist/bar-list.js +31 -0
- package/dist/bottom-navigation.d.ts +6 -2
- package/dist/bottom-navigation.js +2 -2
- package/dist/button.d.ts +6 -11
- package/dist/button.js +8 -8
- package/dist/card.d.ts +15 -10
- package/dist/card.js +7 -2
- package/dist/chart.d.ts +58 -3
- package/dist/chart.js +330 -48
- package/dist/choice.d.ts +2 -2
- package/dist/class-names.d.ts +0 -4
- package/dist/class-names.js +0 -14
- package/dist/code.d.ts +19 -7
- package/dist/code.js +32 -38
- package/dist/combobox.d.ts +2 -8
- package/dist/combobox.js +2 -2
- package/dist/context-menu.d.ts +2 -8
- package/dist/context-menu.js +2 -2
- package/dist/css/bar-list.css +9 -0
- package/dist/css/chart.css +2 -0
- package/dist/css/dashboard.css +20 -0
- package/dist/css/rules/alert-dialog.css +8 -2
- package/dist/css/rules/app-shell.css +57 -10
- package/dist/css/rules/bar-list.css +101 -0
- package/dist/css/rules/bar.css +5 -12
- package/dist/css/rules/bottom-navigation.css +21 -2
- package/dist/css/rules/breadcrumbs.css +0 -6
- package/dist/css/rules/button.css +4 -12
- package/dist/css/rules/card.css +19 -0
- package/dist/css/rules/chart.css +87 -8
- package/dist/css/rules/choice.css +26 -2
- package/dist/css/rules/combobox.css +17 -16
- package/dist/css/rules/dashboard.css +118 -0
- package/dist/css/rules/date-picker.css +50 -27
- package/dist/css/rules/dialog.css +47 -7
- package/dist/css/rules/disclosure.css +17 -3
- package/dist/css/rules/field-control.css +9 -6
- package/dist/css/rules/file-upload.css +9 -5
- package/dist/css/rules/filter-bar.css +32 -2
- package/dist/css/rules/gauge.css +2 -2
- package/dist/css/rules/icon.css +0 -5
- package/dist/css/rules/input-group.css +23 -8
- package/dist/css/rules/link.css +0 -6
- package/dist/css/rules/menu.css +5 -2
- package/dist/css/rules/menubar.css +1 -1
- package/dist/css/rules/navigation-menu.css +31 -26
- package/dist/css/rules/number-field.css +8 -1
- package/dist/css/rules/otp-field.css +13 -3
- package/dist/css/rules/page-header.css +10 -0
- package/dist/css/rules/panel.css +59 -10
- package/dist/css/rules/popup.css +50 -0
- package/dist/css/rules/preview-card.css +0 -21
- package/dist/css/rules/scroll-area.css +20 -1
- package/dist/css/rules/select.css +29 -2
- package/dist/css/rules/sizing.css +25 -3
- package/dist/css/rules/skeleton.css +1 -1
- package/dist/css/rules/slider.css +16 -8
- package/dist/css/rules/spinner.css +1 -1
- package/dist/css/rules/stat.css +66 -0
- package/dist/css/rules/tabs.css +14 -6
- package/dist/css/rules/textarea.css +28 -0
- package/dist/css/rules/time-range-picker.css +14 -0
- package/dist/css/rules/toast.css +3 -1
- package/dist/css/rules/toggle.css +10 -3
- package/dist/css/rules/toolbar.css +10 -3
- package/dist/css/rules/tree.css +29 -4
- package/dist/css/styles.css +3 -0
- package/dist/css/time-range-picker.css +14 -0
- package/dist/dashboard.d.ts +58 -0
- package/dist/dashboard.js +60 -0
- package/dist/date-picker.d.ts +32 -3
- package/dist/date-picker.js +43 -4
- package/dist/dialog.d.ts +25 -7
- package/dist/dialog.js +9 -4
- package/dist/drawer.d.ts +10 -2
- package/dist/drawer.js +6 -3
- package/dist/icon.d.ts +15 -5
- package/dist/icon.js +16 -3
- package/dist/index.d.ts +9 -6
- package/dist/index.js +7 -4
- package/dist/inline-message.d.ts +2 -2
- package/dist/inline-message.js +7 -2
- package/dist/input.d.ts +2 -2
- package/dist/layout.d.ts +1 -3
- package/dist/layout.js +2 -2
- package/dist/native-select.d.ts +2 -2
- package/dist/navigation-menu.d.ts +16 -0
- package/dist/navigation-menu.js +6 -1
- package/dist/page-header.d.ts +10 -2
- package/dist/page-header.js +3 -3
- package/dist/panel.d.ts +6 -3
- package/dist/panel.js +2 -2
- package/dist/parts.d.ts +7 -3
- package/dist/parts.js +12 -4
- package/dist/popover.d.ts +6 -6
- package/dist/popover.js +3 -2
- package/dist/preview-card.d.ts +2 -8
- package/dist/preview-card.js +2 -2
- package/dist/select.d.ts +38 -8
- package/dist/select.js +110 -22
- package/dist/sheet.d.ts +10 -2
- package/dist/sheet.js +6 -3
- package/dist/size.d.ts +8 -6
- package/dist/size.js +2 -7
- package/dist/sizing.d.ts +13 -6
- package/dist/sizing.js +13 -4
- package/dist/sparkline.d.ts +2 -2
- package/dist/sparkline.js +2 -2
- package/dist/spinner.d.ts +2 -2
- package/dist/spinner.js +2 -2
- package/dist/stat.d.ts +24 -0
- package/dist/stat.js +15 -1
- package/dist/table.d.ts +12 -4
- package/dist/table.js +8 -3
- package/dist/textarea.d.ts +6 -3
- package/dist/textarea.js +2 -2
- package/dist/time-range-picker.d.ts +42 -0
- package/dist/time-range-picker.js +69 -0
- package/dist/toggle.d.ts +2 -2
- package/dist/toggle.js +2 -2
- package/dist/toolbar.d.ts +11 -10
- package/dist/toolbar.js +23 -1
- package/dist/tooltip.d.ts +1 -3
- package/dist/tooltip.js +4 -2
- package/dist/tree.d.ts +1 -3
- package/dist/tree.js +2 -2
- package/dist/typography.d.ts +10 -3
- package/dist/typography.js +4 -3
- package/package.json +18 -3
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
/* Command state uses the whole rounded surface, with no one-sided accent. */
|
|
7
7
|
.surf-toggle {
|
|
8
8
|
background: transparent;
|
|
9
|
-
border-color: var(--surf-
|
|
9
|
+
border-color: var(--surf-control-border);
|
|
10
10
|
}
|
|
11
11
|
.surf-toggle[data-pressed] {
|
|
12
|
-
background: var(--surf-selected);
|
|
12
|
+
background-color: var(--surf-selected);
|
|
13
13
|
border-color: var(--surf-control-border);
|
|
14
14
|
color: var(--surf-ink);
|
|
15
15
|
}
|
|
@@ -17,11 +17,18 @@
|
|
|
17
17
|
opacity: var(--surf-control-disabled-opacity);
|
|
18
18
|
cursor: not-allowed;
|
|
19
19
|
}
|
|
20
|
+
@media (forced-colors: active) {
|
|
21
|
+
.surf-toggle[data-pressed] {
|
|
22
|
+
background-color: Highlight;
|
|
23
|
+
color: HighlightText;
|
|
24
|
+
forced-color-adjust: none;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
20
27
|
}
|
|
21
28
|
@layer surflane.sizes {
|
|
22
29
|
:where([data-ui-size], [data-ui-size] *):is(.surf-toggle) {
|
|
23
30
|
min-block-size: var(--surf-ui-row);
|
|
24
31
|
font-size: var(--surf-ui-font);
|
|
25
|
-
line-height: var(--surf-ui-leading);
|
|
32
|
+
line-height: var(--surf-ui-label-leading);
|
|
26
33
|
}
|
|
27
34
|
}
|
|
@@ -4,10 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
@layer surflane.components {
|
|
6
6
|
.surf-toolbar-button[aria-pressed='true'] {
|
|
7
|
-
background: var(--surf-selected);
|
|
7
|
+
background-color: var(--surf-selected);
|
|
8
8
|
border-color: var(--surf-control-border);
|
|
9
9
|
color: var(--surf-ink);
|
|
10
10
|
}
|
|
11
|
+
@media (forced-colors: active) {
|
|
12
|
+
.surf-toolbar-button[aria-pressed='true'] {
|
|
13
|
+
background-color: Highlight;
|
|
14
|
+
color: HighlightText;
|
|
15
|
+
forced-color-adjust: none;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
11
18
|
.surf-toolbar-button[data-disabled],
|
|
12
19
|
.surf-toolbar-input[data-disabled] {
|
|
13
20
|
opacity: var(--surf-control-disabled-opacity);
|
|
@@ -16,7 +23,7 @@
|
|
|
16
23
|
.surf-toolbar {
|
|
17
24
|
padding: var(--surf-space-1);
|
|
18
25
|
border-radius: var(--surf-radius-md);
|
|
19
|
-
background: var(--surf-
|
|
26
|
+
background: var(--surf-recessed);
|
|
20
27
|
gap: var(--surf-space-2);
|
|
21
28
|
}
|
|
22
29
|
.surf-toolbar-group {
|
|
@@ -38,7 +45,7 @@
|
|
|
38
45
|
max-width: 100%;
|
|
39
46
|
border: 0;
|
|
40
47
|
border-radius: max(0px, calc(var(--surf-radius-md) - var(--surf-space-1)));
|
|
41
|
-
background: var(--surf-
|
|
48
|
+
background: var(--surf-plane);
|
|
42
49
|
}
|
|
43
50
|
.surf-toolbar-separator {
|
|
44
51
|
flex: none;
|
package/dist/css/rules/tree.css
CHANGED
|
@@ -25,10 +25,13 @@
|
|
|
25
25
|
transition: background-color var(--surf-duration-fast) var(--surf-ease-out);
|
|
26
26
|
}
|
|
27
27
|
.surf-tree-item:hover {
|
|
28
|
-
background:
|
|
28
|
+
background-image: linear-gradient(
|
|
29
|
+
var(--surf-interaction-hover-bg),
|
|
30
|
+
var(--surf-interaction-hover-bg)
|
|
31
|
+
);
|
|
29
32
|
}
|
|
30
33
|
.surf-tree-item[aria-selected='true'] {
|
|
31
|
-
background: var(--surf-selected);
|
|
34
|
+
background-color: var(--surf-selected);
|
|
32
35
|
}
|
|
33
36
|
.surf-tree-item:focus-visible {
|
|
34
37
|
outline: var(--surf-focus-ring-width) solid var(--surf-interaction-focus);
|
|
@@ -52,10 +55,16 @@
|
|
|
52
55
|
color: inherit;
|
|
53
56
|
}
|
|
54
57
|
.surf-tree-toggle:hover:not(:disabled) {
|
|
55
|
-
background:
|
|
58
|
+
background-image: linear-gradient(
|
|
59
|
+
var(--surf-interaction-hover-bg),
|
|
60
|
+
var(--surf-interaction-hover-bg)
|
|
61
|
+
);
|
|
56
62
|
}
|
|
57
63
|
.surf-tree-toggle:active:not(:disabled) {
|
|
58
|
-
background:
|
|
64
|
+
background-image: linear-gradient(
|
|
65
|
+
var(--surf-interaction-active-bg),
|
|
66
|
+
var(--surf-interaction-active-bg)
|
|
67
|
+
);
|
|
59
68
|
}
|
|
60
69
|
.surf-tree-toggle svg[data-expanded] {
|
|
61
70
|
rotate: 90deg;
|
|
@@ -73,6 +82,21 @@
|
|
|
73
82
|
padding: var(--surf-space-4);
|
|
74
83
|
color: var(--surf-ink-muted);
|
|
75
84
|
}
|
|
85
|
+
/* On touch the disclosure keeps its size and reaches the row's
|
|
86
|
+
--surf-control-target-size around it. */
|
|
87
|
+
@media (max-width: 760px), (pointer: coarse) {
|
|
88
|
+
.surf-tree-toggle {
|
|
89
|
+
position: relative;
|
|
90
|
+
}
|
|
91
|
+
.surf-tree-toggle::after {
|
|
92
|
+
content: '';
|
|
93
|
+
position: absolute;
|
|
94
|
+
inset: 50% auto auto 50%;
|
|
95
|
+
inline-size: var(--surf-control-target-size);
|
|
96
|
+
block-size: var(--surf-control-target-size);
|
|
97
|
+
translate: -50% -50%;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
76
100
|
@media (prefers-reduced-motion: reduce) {
|
|
77
101
|
.surf-tree-item {
|
|
78
102
|
transition: none;
|
|
@@ -82,6 +106,7 @@
|
|
|
82
106
|
.surf-tree-item[aria-selected='true'] {
|
|
83
107
|
background: Highlight;
|
|
84
108
|
color: HighlightText;
|
|
109
|
+
forced-color-adjust: none;
|
|
85
110
|
}
|
|
86
111
|
.surf-tree-item[aria-disabled='true'] {
|
|
87
112
|
color: GrayText;
|
package/dist/css/styles.css
CHANGED
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
@import './rules/app-shell.css';
|
|
63
63
|
@import './rules/tree.css';
|
|
64
64
|
@import './rules/date-picker.css';
|
|
65
|
+
@import './rules/time-range-picker.css';
|
|
65
66
|
@import './rules/chart.css';
|
|
66
67
|
@import '@surflane/css/foundations/layout.css';
|
|
67
68
|
@import './rules/layout.css';
|
|
@@ -73,8 +74,10 @@
|
|
|
73
74
|
@import './rules/list.css';
|
|
74
75
|
@import './rules/stat.css';
|
|
75
76
|
@import './rules/sparkline.css';
|
|
77
|
+
@import './rules/bar-list.css';
|
|
76
78
|
@import '@surflane/css/presentation/inline-message.css';
|
|
77
79
|
@import './rules/inline-message.css';
|
|
80
|
+
@import './rules/dashboard.css';
|
|
78
81
|
@import './rules/syntax-highlighter.css';
|
|
79
82
|
@import '@surflane/css/presentation/code.css';
|
|
80
83
|
@import './rules/code.css';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* Time range picker, with the styles of what it renders. */
|
|
2
|
+
@layer surflane.tokens, surflane.themes, surflane.base, surflane.components,
|
|
3
|
+
surflane.sizes;
|
|
4
|
+
@import '@surflane/design-tokens/tokens.css';
|
|
5
|
+
@import '@surflane/css/presentation/base.css';
|
|
6
|
+
@import './rules/base.css';
|
|
7
|
+
@import './rules/field-control.css';
|
|
8
|
+
@import './rules/sizing.css';
|
|
9
|
+
@import './rules/popup.css';
|
|
10
|
+
@import './rules/item.css';
|
|
11
|
+
@import './rules/icon.css';
|
|
12
|
+
@import './rules/select.css';
|
|
13
|
+
@import './rules/button.css';
|
|
14
|
+
@import './rules/time-range-picker.css';
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
export type DashboardRootProps = React.ComponentPropsWithoutRef<'div'> & {
|
|
3
|
+
/** Names the dashboard as a region of the page, such as "Cluster overview". */
|
|
4
|
+
label?: string;
|
|
5
|
+
/** The most columns a wide screen shows, so a row planned for that many keeps its
|
|
6
|
+
* proportions and a span keeps its meaning. Narrower screens still fit fewer. */
|
|
7
|
+
columns?: number;
|
|
8
|
+
};
|
|
9
|
+
export type DashboardPanelLabels = {
|
|
10
|
+
/** The button that shows the description, given the title. */
|
|
11
|
+
about: (title: string) => string;
|
|
12
|
+
loading: string;
|
|
13
|
+
refreshing: string;
|
|
14
|
+
error: string;
|
|
15
|
+
/** Above the last values when a refresh failed. */
|
|
16
|
+
stale: string;
|
|
17
|
+
retry: string;
|
|
18
|
+
empty: string;
|
|
19
|
+
};
|
|
20
|
+
export type DashboardPanelProps = Omit<React.ComponentPropsWithoutRef<'div'>, 'title'> & {
|
|
21
|
+
title: string;
|
|
22
|
+
/** What the panel shows and how it is measured, behind an info button by the title. */
|
|
23
|
+
description?: React.ReactNode;
|
|
24
|
+
/** The heading level of the title. */
|
|
25
|
+
level?: 2 | 3 | 4 | 5 | 6;
|
|
26
|
+
/** loading shows a placeholder until the first data arrives; error and empty
|
|
27
|
+
* replace the content with a message; stale keeps the last content under a caution
|
|
28
|
+
* that a refresh failed, with retry. */
|
|
29
|
+
state?: 'ready' | 'loading' | 'error' | 'empty' | 'stale';
|
|
30
|
+
/** The loading placeholder's height, as tall as the content will be, so the
|
|
31
|
+
* panels below don't move when the data arrives. 96px without it. */
|
|
32
|
+
placeholderHeight?: number | string;
|
|
33
|
+
/** New data is on its way: the content stays, a spinner shows by the title and the
|
|
34
|
+
* panel is busy for assistive technology. */
|
|
35
|
+
refreshing?: boolean;
|
|
36
|
+
/** Shows a retry button in the error message. */
|
|
37
|
+
onRetry?: () => void;
|
|
38
|
+
/** Why it failed or why it is empty, in place of the default text. */
|
|
39
|
+
message?: React.ReactNode;
|
|
40
|
+
/** Controls at the end of the header, such as a menu. */
|
|
41
|
+
actions?: React.ReactNode;
|
|
42
|
+
/** Columns the panel spans where they fit; a phone shows one. */
|
|
43
|
+
span?: 1 | 2 | 3 | 'full';
|
|
44
|
+
labels?: Partial<DashboardPanelLabels>;
|
|
45
|
+
};
|
|
46
|
+
export declare const Dashboard: {
|
|
47
|
+
Root: ({ label, columns, className, style, ref, ...props }: DashboardRootProps & {
|
|
48
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
49
|
+
}) => React.JSX.Element;
|
|
50
|
+
Panel: ({ title, description, level, state, refreshing, onRetry, message, actions, span, placeholderHeight, labels, className, children, ref, ...props }: DashboardPanelProps & {
|
|
51
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
52
|
+
}) => React.JSX.Element;
|
|
53
|
+
};
|
|
54
|
+
export declare const DashboardRoot: ({ label, columns, className, style, ref, ...props }: DashboardRootProps & {
|
|
55
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
56
|
+
}) => React.JSX.Element, DashboardPanel: ({ title, description, level, state, refreshing, onRetry, message, actions, span, placeholderHeight, labels, className, children, ref, ...props }: DashboardPanelProps & {
|
|
57
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
58
|
+
}) => React.JSX.Element;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Button } from './button.js';
|
|
5
|
+
import { Card } from './card.js';
|
|
6
|
+
import { Icon } from './icon.js';
|
|
7
|
+
import { InlineMessage } from './inline-message.js';
|
|
8
|
+
import { Popover } from './popover.js';
|
|
9
|
+
import { Skeleton } from './skeleton.js';
|
|
10
|
+
import { Spinner } from './spinner.js';
|
|
11
|
+
import { cx } from './class-names.js';
|
|
12
|
+
/** The panels of a dashboard on a responsive grid: as many columns as fit panels of
|
|
13
|
+
* --surf-dashboard-panel-min-width (20rem), up to columns, one column on a phone. */
|
|
14
|
+
const Root = function DashboardRoot({ label, columns, className, style, ref, ...props }) {
|
|
15
|
+
return (_jsx("div", { role: label ? 'region' : undefined, "aria-label": label, ...props, ref: ref, "data-columns": columns, style: columns
|
|
16
|
+
? {
|
|
17
|
+
...style,
|
|
18
|
+
'--surf-dashboard-columns': columns,
|
|
19
|
+
}
|
|
20
|
+
: style, className: cx('surf-dashboard', className) }));
|
|
21
|
+
};
|
|
22
|
+
const panelLabels = {
|
|
23
|
+
about: (title) => `About ${title}`,
|
|
24
|
+
loading: 'Loading',
|
|
25
|
+
refreshing: 'Refreshing',
|
|
26
|
+
error: 'This panel could not load.',
|
|
27
|
+
stale: 'These are the last values: the panel could not refresh.',
|
|
28
|
+
retry: 'Retry',
|
|
29
|
+
empty: 'No data in this range.',
|
|
30
|
+
};
|
|
31
|
+
/** One panel of a dashboard: a card with its title, an optional description, the
|
|
32
|
+
* states of its data and the content. The content takes the room the row gives it. */
|
|
33
|
+
const Panel = function DashboardPanel({ title, description, level = 3, state = 'ready', refreshing = false, onRetry, message, actions, span, placeholderHeight, labels, className, children, ref, ...props }) {
|
|
34
|
+
const text = { ...panelLabels, ...labels };
|
|
35
|
+
const id = React.useId();
|
|
36
|
+
const busy = state === 'loading' || refreshing;
|
|
37
|
+
const titleRef = React.useRef(null);
|
|
38
|
+
const retried = React.useRef(false);
|
|
39
|
+
// Retry takes its own button away when the panel leaves the error, so focus
|
|
40
|
+
// moves to the panel's title instead of falling to the page.
|
|
41
|
+
React.useEffect(() => {
|
|
42
|
+
if (!retried.current)
|
|
43
|
+
return;
|
|
44
|
+
retried.current = false;
|
|
45
|
+
const active = document.activeElement;
|
|
46
|
+
if (!active || active === document.body)
|
|
47
|
+
titleRef.current?.focus();
|
|
48
|
+
}, [state]);
|
|
49
|
+
const retry = onRetry &&
|
|
50
|
+
(() => {
|
|
51
|
+
retried.current = true;
|
|
52
|
+
onRetry();
|
|
53
|
+
});
|
|
54
|
+
return (_jsxs(Card.Root, { role: 'group', "aria-labelledby": `${id}-title`, "aria-busy": busy || undefined, ...props, ref: ref, "data-span": span, "data-state": state, className: cx('surf-dashboard-panel', className), children: [_jsxs("div", { className: 'surf-dashboard-panel-header', children: [_jsx(Card.Title, { level: level, id: `${id}-title`, title: title, ref: titleRef, tabIndex: -1, children: title }), description && (_jsxs(Popover.Root, { children: [_jsx(Popover.Trigger, { render: _jsx(Button, { variant: 'ghost', size: 'icon-small', "aria-label": text.about(title) }), children: _jsx(Icon, { name: 'info' }) }), _jsx(Popover.Content, { size: 'small', children: _jsx(Popover.Description, { children: description }) })] })), refreshing && state !== 'loading' && (_jsx(Spinner, { size: 'small', label: text.refreshing })), actions && (_jsx("div", { className: 'surf-dashboard-panel-actions', children: actions }))] }), _jsx("div", { className: 'surf-dashboard-panel-body', children: state === 'loading' ? (_jsxs(_Fragment, { children: [_jsx(Skeleton, { shape: 'block', style: placeholderHeight === undefined
|
|
55
|
+
? undefined
|
|
56
|
+
: { blockSize: placeholderHeight } }), _jsx("span", { className: 'surf-feedback-sr', children: text.loading })] })) : state === 'stale' ? (_jsxs(_Fragment, { children: [_jsxs(InlineMessage.Root, { tone: 'caution', children: [_jsx(InlineMessage.Icon, {}), _jsxs(InlineMessage.Content, { children: [_jsx(InlineMessage.Description, { children: message ?? text.stale }), onRetry && (_jsx(InlineMessage.Actions, { children: _jsx(Button, { variant: 'outline', size: 'small', onClick: retry, children: text.retry }) }))] })] }), children] })) : state === 'error' ? (_jsxs(InlineMessage.Root, { tone: 'danger', children: [_jsx(InlineMessage.Icon, {}), _jsxs(InlineMessage.Content, { children: [_jsx(InlineMessage.Description, { children: message ?? text.error }), onRetry && (_jsx(InlineMessage.Actions, { children: _jsx(Button, { variant: 'outline', size: 'small', onClick: retry, children: text.retry }) }))] })] })) : state === 'empty' ? (_jsx("p", { className: 'surf-dashboard-panel-empty', children: message ?? text.empty })) : (children) })] }));
|
|
57
|
+
};
|
|
58
|
+
export const Dashboard = { Root, Panel };
|
|
59
|
+
// Flat names for React Server Components, which cannot dot into client exports.
|
|
60
|
+
export const { Root: DashboardRoot, Panel: DashboardPanel } = Dashboard;
|
package/dist/date-picker.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
+
import { type ComponentSize } from './sizing.js';
|
|
2
3
|
import { type DatePickerProps as AriaDatePickerProps, type DateValue, type ValidationResult } from 'react-aria-components/DatePicker';
|
|
3
4
|
import { type DateRangePickerProps as AriaDateRangePickerProps } from 'react-aria-components/DateRangePicker';
|
|
4
5
|
import { type TimeFieldProps as AriaTimeFieldProps, type TimeValue } from 'react-aria-components/TimeField';
|
|
@@ -13,9 +14,37 @@ type FieldContent = {
|
|
|
13
14
|
type CalendarContent = {
|
|
14
15
|
calendarLabel?: string;
|
|
15
16
|
};
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
/** The names every other Surflane field takes. react-aria's spellings keep working. */
|
|
18
|
+
type FieldStates<Change> = {
|
|
19
|
+
/** The field's and its calendar's size; without it, the surrounding SizeProvider's. */
|
|
20
|
+
size?: ComponentSize;
|
|
21
|
+
disabled?: boolean;
|
|
22
|
+
readOnly?: boolean;
|
|
23
|
+
required?: boolean;
|
|
24
|
+
/** Marks the value invalid, as aria-invalid does on other fields. */
|
|
25
|
+
invalid?: boolean;
|
|
26
|
+
onValueChange?: Change;
|
|
27
|
+
/** @deprecated Use `disabled`. Removed in a later minor. */
|
|
28
|
+
isDisabled?: boolean;
|
|
29
|
+
/** @deprecated Use `readOnly`. Removed in a later minor. */
|
|
30
|
+
isReadOnly?: boolean;
|
|
31
|
+
/** @deprecated Use `required`. Removed in a later minor. */
|
|
32
|
+
isRequired?: boolean;
|
|
33
|
+
/** @deprecated Use `invalid`. Removed in a later minor. */
|
|
34
|
+
isInvalid?: boolean;
|
|
35
|
+
/** @deprecated Use `onValueChange`. Removed in a later minor. */
|
|
36
|
+
onChange?: Change;
|
|
37
|
+
};
|
|
38
|
+
type PopupStates = {
|
|
39
|
+
/** Whether the calendar is open, controlled. */
|
|
40
|
+
open?: boolean;
|
|
41
|
+
/** @deprecated Use `open`. Removed in a later minor. */
|
|
42
|
+
isOpen?: boolean;
|
|
43
|
+
};
|
|
44
|
+
type AriaNames = 'children' | 'isDisabled' | 'isReadOnly' | 'isRequired' | 'isInvalid' | 'isOpen' | 'onChange';
|
|
45
|
+
export type DatePickerProps<T extends DateValue> = Omit<AriaDatePickerProps<T>, AriaNames> & FieldContent & CalendarContent & FieldStates<AriaDatePickerProps<T>['onChange']> & PopupStates;
|
|
46
|
+
export type DateRangePickerProps<T extends DateValue> = Omit<AriaDateRangePickerProps<T>, AriaNames> & FieldContent & CalendarContent & FieldStates<AriaDateRangePickerProps<T>['onChange']> & PopupStates;
|
|
47
|
+
export type TimeFieldProps<T extends TimeValue> = Omit<AriaTimeFieldProps<T>, AriaNames> & FieldContent & FieldStates<AriaTimeFieldProps<T>['onChange']>;
|
|
19
48
|
/** Locale-aware segmented entry with a keyboard and touch calendar. DateValue
|
|
20
49
|
* retains calendar/time-zone semantics; conversion to an instant is caller-owned. */
|
|
21
50
|
export declare function DatePicker<T extends DateValue>({ label, description, errorMessage, calendarLabel, className, ...props }: DatePickerProps<T>): React.JSX.Element;
|
package/dist/date-picker.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Icon } from './icon.js';
|
|
4
|
-
import { useComponentSize } from './sizing.js';
|
|
4
|
+
import { ComponentSizeContext, useComponentSize, } from './sizing.js';
|
|
5
5
|
import { DatePicker as AriaDatePicker, DateInput, DateSegment, Group, Label, Text, FieldError, Calendar, CalendarGrid, CalendarGridHeader, CalendarGridBody, CalendarHeaderCell, CalendarCell, Button, Popover, } from 'react-aria-components/DatePicker';
|
|
6
6
|
import { DateRangePicker as AriaDateRangePicker, RangeCalendar, } from 'react-aria-components/DateRangePicker';
|
|
7
7
|
import { TimeField as AriaTimeField, } from 'react-aria-components/TimeField';
|
|
@@ -10,6 +10,45 @@ import { Dialog } from 'react-aria-components/Dialog';
|
|
|
10
10
|
import { skin } from './parts.js';
|
|
11
11
|
import { useLocale } from 'react-aria-components/I18nProvider';
|
|
12
12
|
export { I18nProvider as DateLocaleProvider } from 'react-aria-components/I18nProvider';
|
|
13
|
+
/** Surflane's field names to react-aria's, the new spelling first. */
|
|
14
|
+
function ariaStates({ size: _size, disabled, readOnly, required, invalid, onValueChange, isDisabled, isReadOnly, isRequired, isInvalid, onChange, open, isOpen, }) {
|
|
15
|
+
const opened = open ?? isOpen;
|
|
16
|
+
return {
|
|
17
|
+
isDisabled: disabled ?? isDisabled,
|
|
18
|
+
isReadOnly: readOnly ?? isReadOnly,
|
|
19
|
+
isRequired: required ?? isRequired,
|
|
20
|
+
isInvalid: invalid ?? isInvalid,
|
|
21
|
+
onChange: onValueChange ?? onChange,
|
|
22
|
+
...(opened === undefined ? {} : { isOpen: opened }),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const stateNames = [
|
|
26
|
+
'size',
|
|
27
|
+
'disabled',
|
|
28
|
+
'readOnly',
|
|
29
|
+
'required',
|
|
30
|
+
'invalid',
|
|
31
|
+
'onValueChange',
|
|
32
|
+
'isDisabled',
|
|
33
|
+
'isReadOnly',
|
|
34
|
+
'isRequired',
|
|
35
|
+
'isInvalid',
|
|
36
|
+
'onChange',
|
|
37
|
+
'open',
|
|
38
|
+
'isOpen',
|
|
39
|
+
];
|
|
40
|
+
/** The props a react-aria field passes on, without the names ariaStates maps. */
|
|
41
|
+
function rest(props) {
|
|
42
|
+
const copy = { ...props };
|
|
43
|
+
for (const name of stateNames)
|
|
44
|
+
delete copy[name];
|
|
45
|
+
return copy;
|
|
46
|
+
}
|
|
47
|
+
/** An explicit size scopes the field and the calendar it opens. */
|
|
48
|
+
function SizedField({ size, children, }) {
|
|
49
|
+
const scheme = useComponentSize(size);
|
|
50
|
+
return (_jsx(ComponentSizeContext.Provider, { value: scheme, children: children(size ? scheme : undefined) }));
|
|
51
|
+
}
|
|
13
52
|
function Segments({ slot }) {
|
|
14
53
|
return (_jsx(DateInput, { slot: slot, className: 'surf-date-input', children: (segment) => (_jsx(DateSegment, { segment: segment, className: 'surf-date-segment' })) }));
|
|
15
54
|
}
|
|
@@ -50,11 +89,11 @@ function CalendarPopup({ label, range }) {
|
|
|
50
89
|
/** Locale-aware segmented entry with a keyboard and touch calendar. DateValue
|
|
51
90
|
* retains calendar/time-zone semantics; conversion to an instant is caller-owned. */
|
|
52
91
|
export function DatePicker({ label, description, errorMessage, calendarLabel, className, ...props }) {
|
|
53
|
-
return (_jsxs(AriaDatePicker, { ...props, className: skin('surf-date-picker', className), children: [_jsx(Label, { className: 'surf-field-label', children: label }), _jsxs(Group, { className: 'surf-date-group', children: [_jsx(Segments, {}), _jsx(CalendarButton, {})] }), _jsx(FieldHelp, { description: description, errorMessage: errorMessage }), _jsx(CalendarPopup, { label: calendarLabel ?? label })] }));
|
|
92
|
+
return (_jsx(SizedField, { size: props.size, children: (scheme) => (_jsxs(AriaDatePicker, { ...rest(props), ...ariaStates(props), "data-ui-size": scheme, className: skin('surf-date-picker', className), children: [_jsx(Label, { className: 'surf-field-label', children: label }), _jsxs(Group, { className: 'surf-date-group', children: [_jsx(Segments, {}), _jsx(CalendarButton, {})] }), _jsx(FieldHelp, { description: description, errorMessage: errorMessage }), _jsx(CalendarPopup, { label: calendarLabel ?? label })] })) }));
|
|
54
93
|
}
|
|
55
94
|
export function DateRangePicker({ label, description, errorMessage, calendarLabel, className, ...props }) {
|
|
56
|
-
return (_jsxs(AriaDateRangePicker, { ...props, className: skin('surf-date-picker surf-date-range-picker', className), children: [_jsx(Label, { className: 'surf-field-label', children: label }), _jsxs(Group, { className: 'surf-date-group', children: [_jsxs("div", { className: 'surf-date-range-inputs', children: [_jsx(Segments, { slot: 'start' }), _jsx("span", { "aria-hidden": 'true', className: 'surf-date-range-separator', children: "\u2013" }), _jsx(Segments, { slot: 'end' })] }), _jsx(CalendarButton, {})] }), _jsx(FieldHelp, { description: description, errorMessage: errorMessage }), _jsx(CalendarPopup, { label: calendarLabel ?? label, range: true })] }));
|
|
95
|
+
return (_jsx(SizedField, { size: props.size, children: (scheme) => (_jsxs(AriaDateRangePicker, { ...rest(props), ...ariaStates(props), "data-ui-size": scheme, className: skin('surf-date-picker surf-date-range-picker', className), children: [_jsx(Label, { className: 'surf-field-label', children: label }), _jsxs(Group, { className: 'surf-date-group', children: [_jsxs("div", { className: 'surf-date-range-inputs', children: [_jsx(Segments, { slot: 'start' }), _jsx("span", { "aria-hidden": 'true', className: 'surf-date-range-separator', children: "\u2013" }), _jsx(Segments, { slot: 'end' })] }), _jsx(CalendarButton, {})] }), _jsx(FieldHelp, { description: description, errorMessage: errorMessage }), _jsx(CalendarPopup, { label: calendarLabel ?? label, range: true })] })) }));
|
|
57
96
|
}
|
|
58
97
|
export function TimeField({ label, description, errorMessage, className, ...props }) {
|
|
59
|
-
return (_jsxs(AriaTimeField, { ...props, className: skin('surf-time-field', className), children: [_jsx(Label, { className: 'surf-field-label', children: label }), _jsx("div", { className: 'surf-date-group', children: _jsx(Segments, {}) }), _jsx(FieldHelp, { description: description, errorMessage: errorMessage })] }));
|
|
98
|
+
return (_jsx(SizedField, { size: props.size, children: (scheme) => (_jsxs(AriaTimeField, { ...rest(props), ...ariaStates(props), "data-ui-size": scheme, className: skin('surf-time-field', className), children: [_jsx(Label, { className: 'surf-field-label', children: label }), _jsx("div", { className: 'surf-date-group', children: _jsx(Segments, {}) }), _jsx(FieldHelp, { description: description, errorMessage: errorMessage })] })) }));
|
|
60
99
|
}
|
package/dist/dialog.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { type
|
|
2
|
+
import { type ComponentSize } from './sizing.js';
|
|
3
3
|
import { Dialog as BaseDialog } from '@base-ui/react/dialog';
|
|
4
4
|
/** Visible icon close action; inherits Dialog focus and dismissal behavior. */
|
|
5
5
|
declare const DialogCloseButton: ({ className, "aria-label": label, ref, ...props }: Omit<React.ComponentPropsWithoutRef<typeof BaseDialog.Close>, "children"> & {
|
|
@@ -7,7 +7,7 @@ declare const DialogCloseButton: ({ className, "aria-label": label, ref, ...prop
|
|
|
7
7
|
}) => React.JSX.Element;
|
|
8
8
|
declare const DialogContent: ({ size, className, children, closeLabel, closeDisabled, focusBoundaryLabel, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseDialog.Popup> & {
|
|
9
9
|
/** Width and density: small 420px, default 640px, large 840px. */
|
|
10
|
-
size?:
|
|
10
|
+
size?: ComponentSize;
|
|
11
11
|
closeLabel?: string;
|
|
12
12
|
closeDisabled?: boolean;
|
|
13
13
|
focusBoundaryLabel?: string;
|
|
@@ -19,10 +19,20 @@ declare const DialogBody: ({ className, ref, ...props }: React.ComponentProps<"d
|
|
|
19
19
|
ref?: React.Ref<HTMLDivElement>;
|
|
20
20
|
}) => React.JSX.Element;
|
|
21
21
|
declare function DialogFooter({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
|
|
22
|
+
declare const DialogTitle: ({ ref, ...props }: Omit<Omit<Omit<import("@base-ui/react/dialog").DialogTitleProps, "ref"> & React.RefAttributes<HTMLHeadingElement>, "ref">, "size"> & {
|
|
23
|
+
size?: ComponentSize;
|
|
24
|
+
} & {
|
|
25
|
+
ref?: React.Ref<HTMLHeadingElement> | undefined;
|
|
26
|
+
}) => React.JSX.Element;
|
|
27
|
+
declare const DialogDescription: ({ ref, ...props }: Omit<Omit<Omit<import("@base-ui/react/dialog").DialogDescriptionProps, "ref"> & React.RefAttributes<HTMLParagraphElement>, "ref">, "size"> & {
|
|
28
|
+
size?: ComponentSize;
|
|
29
|
+
} & {
|
|
30
|
+
ref?: React.Ref<HTMLParagraphElement> | undefined;
|
|
31
|
+
}) => React.JSX.Element;
|
|
22
32
|
export declare const Dialog: {
|
|
23
33
|
Content: ({ size, className, children, closeLabel, closeDisabled, focusBoundaryLabel, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseDialog.Popup> & {
|
|
24
34
|
/** Width and density: small 420px, default 640px, large 840px. */
|
|
25
|
-
size?:
|
|
35
|
+
size?: ComponentSize;
|
|
26
36
|
closeLabel?: string;
|
|
27
37
|
closeDisabled?: boolean;
|
|
28
38
|
focusBoundaryLabel?: string;
|
|
@@ -37,17 +47,25 @@ export declare const Dialog: {
|
|
|
37
47
|
CloseButton: ({ className, "aria-label": label, ref, ...props }: Omit<React.ComponentPropsWithoutRef<typeof BaseDialog.Close>, "children"> & {
|
|
38
48
|
ref?: React.Ref<HTMLButtonElement>;
|
|
39
49
|
}) => React.JSX.Element;
|
|
50
|
+
Title: ({ ref, ...props }: Omit<Omit<Omit<import("@base-ui/react/dialog").DialogTitleProps, "ref"> & React.RefAttributes<HTMLHeadingElement>, "ref">, "size"> & {
|
|
51
|
+
size?: ComponentSize;
|
|
52
|
+
} & {
|
|
53
|
+
ref?: React.Ref<HTMLHeadingElement> | undefined;
|
|
54
|
+
}) => React.JSX.Element;
|
|
55
|
+
Description: ({ ref, ...props }: Omit<Omit<Omit<import("@base-ui/react/dialog").DialogDescriptionProps, "ref"> & React.RefAttributes<HTMLParagraphElement>, "ref">, "size"> & {
|
|
56
|
+
size?: ComponentSize;
|
|
57
|
+
} & {
|
|
58
|
+
ref?: React.Ref<HTMLParagraphElement> | undefined;
|
|
59
|
+
}) => React.JSX.Element;
|
|
40
60
|
Backdrop: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogBackdropProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
41
61
|
Close: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogCloseProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
42
|
-
Description: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogDescriptionProps, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
|
|
43
62
|
Popup: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogPopupProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
44
63
|
Portal: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogPortalProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
45
64
|
Root: <Payload>(props: BaseDialog.Root.Props<Payload>) => React.JSX.Element;
|
|
46
65
|
Viewport: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogViewportProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
47
|
-
Title: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogTitleProps, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
|
|
48
66
|
Trigger: BaseDialog.Trigger;
|
|
49
67
|
createHandle: typeof BaseDialog.createHandle;
|
|
50
68
|
Handle: typeof BaseDialog.Handle;
|
|
51
69
|
};
|
|
52
|
-
export { DialogContent, DialogHeader, DialogBody, DialogFooter, DialogCloseButton, };
|
|
53
|
-
export declare const DialogBackdrop: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogBackdropProps, "ref"> & React.RefAttributes<HTMLDivElement>>, DialogClose: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogCloseProps, "ref"> & React.RefAttributes<HTMLButtonElement>>,
|
|
70
|
+
export { DialogContent, DialogHeader, DialogBody, DialogFooter, DialogCloseButton, DialogTitle, DialogDescription, };
|
|
71
|
+
export declare const DialogBackdrop: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogBackdropProps, "ref"> & React.RefAttributes<HTMLDivElement>>, DialogClose: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogCloseProps, "ref"> & React.RefAttributes<HTMLButtonElement>>, DialogHandle: typeof BaseDialog.Handle, DialogPopup: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogPopupProps, "ref"> & React.RefAttributes<HTMLDivElement>>, DialogPortal: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogPortalProps, "ref"> & React.RefAttributes<HTMLDivElement>>, DialogRoot: <Payload>(props: BaseDialog.Root.Props<Payload>) => React.JSX.Element, DialogTrigger: BaseDialog.Trigger, DialogViewport: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/dialog").DialogViewportProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
package/dist/dialog.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Icon } from './icon.js';
|
|
4
|
-
import {
|
|
4
|
+
import { part, skin, cx, usePortalDirection } from './parts.js';
|
|
5
5
|
import { useDialogFocusBoundary } from './dialog-focus.js';
|
|
6
6
|
import { useComponentSize } from './sizing.js';
|
|
7
7
|
import { Dialog as BaseDialog } from '@base-ui/react/dialog';
|
|
@@ -12,7 +12,8 @@ const DialogCloseButton = function DialogCloseButton({ className, 'aria-label':
|
|
|
12
12
|
const DialogContent = function DialogContent({ size, className, children, closeLabel = 'Close dialog', closeDisabled, focusBoundaryLabel = 'Continue dialog navigation', ref, ...props }) {
|
|
13
13
|
const scheme = useComponentSize(size);
|
|
14
14
|
const portalRef = useDialogFocusBoundary(focusBoundaryLabel);
|
|
15
|
-
|
|
15
|
+
const dir = usePortalDirection();
|
|
16
|
+
return (_jsxs(BaseDialog.Portal, { ref: portalRef, children: [_jsx(BaseDialog.Backdrop, { className: 'surf-dialog-backdrop' }), _jsxs(BaseDialog.Popup, { dir: dir, "data-ui-size": scheme, "data-size": size, ...props, ref: ref, className: skin('surf-dialog-popup surf-dialog-content', className), children: [_jsx(DialogCloseButton, { "aria-label": closeLabel, disabled: closeDisabled }), children] })] }));
|
|
16
17
|
};
|
|
17
18
|
function DialogHeader({ className, ...props }) {
|
|
18
19
|
return _jsx("div", { ...props, className: cx('surf-dialog-header', className) });
|
|
@@ -23,6 +24,8 @@ const DialogBody = function DialogBody({ className, ref, ...props }) {
|
|
|
23
24
|
function DialogFooter({ className, ...props }) {
|
|
24
25
|
return _jsx("div", { ...props, className: cx('surf-dialog-footer', className) });
|
|
25
26
|
}
|
|
27
|
+
const DialogTitle = /* @__PURE__ */ part(BaseDialog.Title, 'surf-dialog-title');
|
|
28
|
+
const DialogDescription = /* @__PURE__ */ part(BaseDialog.Description, 'surf-dialog-description');
|
|
26
29
|
export const Dialog = {
|
|
27
30
|
...BaseDialog,
|
|
28
31
|
Content: DialogContent,
|
|
@@ -30,7 +33,9 @@ export const Dialog = {
|
|
|
30
33
|
Body: DialogBody,
|
|
31
34
|
Footer: DialogFooter,
|
|
32
35
|
CloseButton: DialogCloseButton,
|
|
36
|
+
Title: DialogTitle,
|
|
37
|
+
Description: DialogDescription,
|
|
33
38
|
};
|
|
34
39
|
// Flat names for React Server Components, which cannot dot into client exports.
|
|
35
|
-
export { DialogContent, DialogHeader, DialogBody, DialogFooter, DialogCloseButton, };
|
|
36
|
-
export const { Backdrop: DialogBackdrop, Close: DialogClose,
|
|
40
|
+
export { DialogContent, DialogHeader, DialogBody, DialogFooter, DialogCloseButton, DialogTitle, DialogDescription, };
|
|
41
|
+
export const { Backdrop: DialogBackdrop, Close: DialogClose, Handle: DialogHandle, Popup: DialogPopup, Portal: DialogPortal, Root: DialogRoot, Trigger: DialogTrigger, Viewport: DialogViewport, } = Dialog;
|
package/dist/drawer.d.ts
CHANGED
|
@@ -4,14 +4,22 @@ import { Footer, Header, type PanelOptions, type PanelSide } from './panel.js';
|
|
|
4
4
|
declare function DrawerRoot({ side, modal, ...props }: Omit<React.ComponentProps<typeof BaseDrawer.Root>, 'swipeDirection'> & {
|
|
5
5
|
side?: PanelSide;
|
|
6
6
|
}): React.JSX.Element;
|
|
7
|
-
declare const DrawerContent: ({ size, flush, closeLabel, className, children, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseDrawer.Popup> & PanelOptions & {
|
|
7
|
+
declare const DrawerContent: ({ size, flush, closeLabel, focusBoundaryLabel, className, children, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseDrawer.Popup> & PanelOptions & {
|
|
8
|
+
/** Names the focus guards at the panel's edges, which VoiceOver reaches past
|
|
9
|
+
* the last control, as Dialog's do. */
|
|
10
|
+
focusBoundaryLabel?: string;
|
|
11
|
+
} & {
|
|
8
12
|
ref?: React.Ref<HTMLDivElement>;
|
|
9
13
|
}) => React.JSX.Element;
|
|
10
14
|
declare function DrawerTitle({ className, ...props }: React.ComponentProps<typeof BaseDrawer.Title>): React.JSX.Element;
|
|
11
15
|
declare function DrawerDescription({ className, ...props }: React.ComponentProps<typeof BaseDrawer.Description>): React.JSX.Element;
|
|
12
16
|
export declare const Drawer: {
|
|
13
17
|
Root: typeof DrawerRoot;
|
|
14
|
-
Content: ({ size, flush, closeLabel, className, children, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseDrawer.Popup> & PanelOptions & {
|
|
18
|
+
Content: ({ size, flush, closeLabel, focusBoundaryLabel, className, children, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseDrawer.Popup> & PanelOptions & {
|
|
19
|
+
/** Names the focus guards at the panel's edges, which VoiceOver reaches past
|
|
20
|
+
* the last control, as Dialog's do. */
|
|
21
|
+
focusBoundaryLabel?: string;
|
|
22
|
+
} & {
|
|
15
23
|
ref?: React.Ref<HTMLDivElement>;
|
|
16
24
|
}) => React.JSX.Element;
|
|
17
25
|
PrimitiveContent: React.ForwardRefExoticComponent<Omit<import("@base-ui/react/drawer").DrawerContentProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
package/dist/drawer.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { Icon } from './icon.js';
|
|
5
|
-
import {
|
|
5
|
+
import { useDialogFocusBoundary } from './dialog-focus.js';
|
|
6
|
+
import { skin, usePortalDirection } from './parts.js';
|
|
6
7
|
import { useComponentSize, normalizeSize } from './sizing.js';
|
|
7
8
|
import { Drawer as BaseDrawer } from '@base-ui/react/drawer';
|
|
8
9
|
import { Body, Footer, Header, } from './panel.js';
|
|
@@ -19,11 +20,13 @@ function DrawerRoot({ side = 'bottom', modal = true, ...props }) {
|
|
|
19
20
|
};
|
|
20
21
|
return (_jsx(DrawerSide.Provider, { value: { side, modal }, children: _jsx(BaseDrawer.Root, { ...props, modal: modal, swipeDirection: direction[side] }) }));
|
|
21
22
|
}
|
|
22
|
-
const DrawerContent = function DrawerContent({ size, flush, closeLabel = 'Close panel', className, children, ref, ...props }) {
|
|
23
|
+
const DrawerContent = function DrawerContent({ size, flush, closeLabel = 'Close panel', focusBoundaryLabel = 'Continue panel navigation', className, children, ref, ...props }) {
|
|
23
24
|
const scheme = useComponentSize(size);
|
|
25
|
+
const dir = usePortalDirection();
|
|
26
|
+
const portalRef = useDialogFocusBoundary(focusBoundaryLabel);
|
|
24
27
|
const { side, modal } = React.useContext(DrawerSide);
|
|
25
28
|
const KeyboardProvider = side === 'bottom' ? BaseDrawer.VirtualKeyboardProvider : React.Fragment;
|
|
26
|
-
return (_jsx(KeyboardProvider, { children: _jsx(BaseDrawer.Portal, { children: _jsxs("div", { className: 'surf-panel-layer', "data-ui-size": scheme, children: [modal === true && (_jsx(BaseDrawer.Backdrop, { className: 'surf-panel-backdrop' })), _jsx(BaseDrawer.Viewport, { className: 'surf-panel-viewport', "data-side": side, "data-flush": flush || undefined, children: _jsxs(BaseDrawer.Popup, { ...props, ref: ref, className: skin('surf-panel surf-drawer', className), "data-side": side, "data-size": normalizeSize(size) ?? 'large', "data-flush": flush || undefined, children: [_jsx("div", { className: 'surf-drawer-handle', "aria-hidden": 'true' }), _jsx(BaseDrawer.Close, { className: 'surf-panel-close surf-icon-button', "aria-label": closeLabel, children: _jsx(Icon, { name: 'close' }) }), _jsx(BaseDrawer.Content, { className: 'surf-panel-content', children: children })] }) })] }) }) }));
|
|
29
|
+
return (_jsx(KeyboardProvider, { children: _jsx(BaseDrawer.Portal, { ref: portalRef, children: _jsxs("div", { className: 'surf-panel-layer', "data-ui-size": scheme, children: [modal === true && (_jsx(BaseDrawer.Backdrop, { className: 'surf-panel-backdrop' })), _jsx(BaseDrawer.Viewport, { className: 'surf-panel-viewport', "data-side": side, "data-flush": flush || undefined, children: _jsxs(BaseDrawer.Popup, { dir: dir, ...props, ref: ref, className: skin('surf-panel surf-drawer', className), "data-side": side, "data-size": normalizeSize(size) ?? 'large', "data-flush": flush || undefined, children: [_jsx("div", { className: 'surf-drawer-handle', "aria-hidden": 'true' }), _jsx(BaseDrawer.Close, { className: 'surf-panel-close surf-icon-button', "aria-label": closeLabel, children: _jsx(Icon, { name: 'close' }) }), _jsx(BaseDrawer.Content, { className: 'surf-panel-content', children: children })] }) })] }) }) }));
|
|
27
30
|
};
|
|
28
31
|
function DrawerTitle({ className, ...props }) {
|
|
29
32
|
return (_jsx(BaseDrawer.Title, { ...props, className: skin('surf-panel-title', className) }));
|
package/dist/icon.d.ts
CHANGED
|
@@ -23,6 +23,7 @@ declare const shapes: {
|
|
|
23
23
|
'arrow-back': React.JSX.Element;
|
|
24
24
|
'arrow-up': React.JSX.Element;
|
|
25
25
|
'arrow-down': React.JSX.Element;
|
|
26
|
+
refresh: React.JSX.Element;
|
|
26
27
|
sort: React.JSX.Element;
|
|
27
28
|
'external-link': React.JSX.Element;
|
|
28
29
|
copy: React.JSX.Element;
|
|
@@ -31,6 +32,18 @@ declare const shapes: {
|
|
|
31
32
|
calendar: React.JSX.Element;
|
|
32
33
|
user: React.JSX.Element;
|
|
33
34
|
settings: React.JSX.Element;
|
|
35
|
+
server: React.JSX.Element;
|
|
36
|
+
database: React.JSX.Element;
|
|
37
|
+
disk: React.JSX.Element;
|
|
38
|
+
chip: React.JSX.Element;
|
|
39
|
+
memory: React.JSX.Element;
|
|
40
|
+
network: React.JSX.Element;
|
|
41
|
+
bolt: React.JSX.Element;
|
|
42
|
+
token: React.JSX.Element;
|
|
43
|
+
thermometer: React.JSX.Element;
|
|
44
|
+
pin: React.JSX.Element;
|
|
45
|
+
list: React.JSX.Element;
|
|
46
|
+
grid: React.JSX.Element;
|
|
34
47
|
};
|
|
35
48
|
export type IconName = keyof typeof shapes;
|
|
36
49
|
export declare const iconNames: readonly IconName[];
|
|
@@ -43,11 +56,8 @@ type Semantics = {
|
|
|
43
56
|
};
|
|
44
57
|
export type IconProps = Omit<React.ComponentPropsWithoutRef<'svg'>, 'children' | 'name' | 'role' | 'aria-label' | 'aria-labelledby' | 'aria-hidden' | 'tabIndex' | 'focusable' | 'width' | 'height' | 'viewBox' | 'strokeWidth' | 'fill' | 'stroke' | 'title'> & Semantics & {
|
|
45
58
|
name: IconName;
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
* (16px, now default), md (20px, now large) and lg (24px, off the scale).
|
|
49
|
-
*/
|
|
50
|
-
size?: ComponentSize | 'sm' | 'md' | 'lg';
|
|
59
|
+
/** 14, 16 or 20px; 16px when omitted. */
|
|
60
|
+
size?: ComponentSize;
|
|
51
61
|
};
|
|
52
62
|
/** Static SVG only. Actions, focus, accessible button names and hit targets belong to the parent control. */
|
|
53
63
|
export declare const Icon: ({ name, size, decorative, label, className, ref, ...props }: IconProps & {
|