@idyeah/diya 0.0.0-stage → 1.0.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/CHANGELOG.md +317 -0
- package/LICENSE +21 -0
- package/NOTICE +29 -0
- package/README.md +599 -2
- package/dist/DiyaProvider.d.ts +79 -0
- package/dist/DiyaProvider.js +77 -0
- package/dist/Icon.d.ts +10 -0
- package/dist/Icon.js +27 -0
- package/dist/accordion/Accordion.d.ts +34 -0
- package/dist/accordion/Accordion.js +15 -0
- package/dist/alert/Alert.d.ts +49 -0
- package/dist/alert/Alert.js +11 -0
- package/dist/alert/messages.d.ts +9 -0
- package/dist/alert/messages.js +2 -0
- package/dist/api.json +7277 -0
- package/dist/api.schema.json +214 -0
- package/dist/application-patterns/Chatbot.d.ts +114 -0
- package/dist/application-patterns/Chatbot.js +110 -0
- package/dist/application-patterns/SideNavigation.d.ts +74 -0
- package/dist/application-patterns/SideNavigation.js +31 -0
- package/dist/application-patterns/chatbot-messages.d.ts +20 -0
- package/dist/application-patterns/chatbot-messages.js +2 -0
- package/dist/application-patterns/side-navigation-messages.d.ts +5 -0
- package/dist/application-patterns/side-navigation-messages.js +2 -0
- package/dist/avatar/Avatar.d.ts +32 -0
- package/dist/avatar/Avatar.js +19 -0
- package/dist/avatar/messages.d.ts +7 -0
- package/dist/avatar/messages.js +2 -0
- package/dist/badge/Badge.d.ts +42 -0
- package/dist/badge/Badge.js +16 -0
- package/dist/badge/badge-utils.d.ts +6 -0
- package/dist/badge/badge-utils.js +24 -0
- package/dist/badge/messages.d.ts +4 -0
- package/dist/badge/messages.js +2 -0
- package/dist/breadcrumbs/Breadcrumbs.d.ts +34 -0
- package/dist/breadcrumbs/Breadcrumbs.js +19 -0
- package/dist/breadcrumbs/messages.d.ts +5 -0
- package/dist/breadcrumbs/messages.js +2 -0
- package/dist/button/Button.d.ts +46 -0
- package/dist/button/Button.js +44 -0
- package/dist/calendar/Calendar.d.ts +55 -0
- package/dist/calendar/Calendar.js +61 -0
- package/dist/calendar/messages.d.ts +8 -0
- package/dist/calendar/messages.js +2 -0
- package/dist/calendar/month.d.ts +61 -0
- package/dist/calendar/month.js +134 -0
- package/dist/card/Card.d.ts +46 -0
- package/dist/card/Card.js +8 -0
- package/dist/choice/Choice.d.ts +72 -0
- package/dist/choice/Choice.js +68 -0
- package/dist/choice/messages.d.ts +4 -0
- package/dist/choice/messages.js +2 -0
- package/dist/code-block/CodeBlock.d.ts +20 -0
- package/dist/code-block/CodeBlock.js +49 -0
- package/dist/code-block/messages.d.ts +8 -0
- package/dist/code-block/messages.js +2 -0
- package/dist/combobox/Combobox.d.ts +60 -0
- package/dist/combobox/Combobox.js +160 -0
- package/dist/combobox/messages.d.ts +9 -0
- package/dist/combobox/messages.js +2 -0
- package/dist/combobox/useAnchoredPopover.d.ts +5 -0
- package/dist/combobox/useAnchoredPopover.js +100 -0
- package/dist/data-viz/DataViz.d.ts +140 -0
- package/dist/data-viz/DataViz.js +469 -0
- package/dist/data-viz/index.d.ts +2 -0
- package/dist/data-viz/index.js +1 -0
- package/dist/data-viz/messages.d.ts +11 -0
- package/dist/data-viz/messages.js +2 -0
- package/dist/date-picker/DatePicker.d.ts +57 -0
- package/dist/date-picker/DatePicker.js +146 -0
- package/dist/date-picker/messages.d.ts +13 -0
- package/dist/date-picker/messages.js +2 -0
- package/dist/dialog/Dialog.d.ts +84 -0
- package/dist/dialog/Dialog.js +107 -0
- package/dist/dialog/messages.d.ts +9 -0
- package/dist/dialog/messages.js +2 -0
- package/dist/fonts/DIYASans-Italic.woff2 +0 -0
- package/dist/fonts/DIYASans.woff2 +0 -0
- package/dist/fonts/OFL.txt +94 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +46 -0
- package/dist/internal/brand.d.ts +33 -0
- package/dist/internal/brand.js +57 -0
- package/dist/internal/cx.d.ts +2 -0
- package/dist/internal/cx.js +4 -0
- package/dist/internal/link.d.ts +14 -0
- package/dist/internal/link.js +7 -0
- package/dist/internal/slot.d.ts +15 -0
- package/dist/internal/slot.js +67 -0
- package/dist/layout/Inline.d.ts +4 -0
- package/dist/layout/Inline.js +7 -0
- package/dist/layout/Stack.d.ts +4 -0
- package/dist/layout/Stack.js +7 -0
- package/dist/layout/layout.d.ts +32 -0
- package/dist/layout/layout.js +12 -0
- package/dist/link/TextLink.d.ts +23 -0
- package/dist/link/TextLink.js +17 -0
- package/dist/list/List.d.ts +48 -0
- package/dist/list/List.js +17 -0
- package/dist/list/messages.d.ts +4 -0
- package/dist/list/messages.js +2 -0
- package/dist/menu/Menu.d.ts +49 -0
- package/dist/menu/Menu.js +54 -0
- package/dist/messages-defaults.d.ts +201 -0
- package/dist/messages-defaults.js +61 -0
- package/dist/messages.d.ts +12 -0
- package/dist/messages.js +1 -0
- package/dist/metric/Metric.d.ts +42 -0
- package/dist/metric/Metric.js +11 -0
- package/dist/metric/messages.d.ts +9 -0
- package/dist/metric/messages.js +2 -0
- package/dist/overlay/FloatingSurface.d.ts +29 -0
- package/dist/overlay/FloatingSurface.js +254 -0
- package/dist/page-header/PageHeader.d.ts +38 -0
- package/dist/page-header/PageHeader.js +10 -0
- package/dist/pagination/Pagination.d.ts +44 -0
- package/dist/pagination/Pagination.js +26 -0
- package/dist/pagination/messages.d.ts +11 -0
- package/dist/pagination/messages.js +2 -0
- package/dist/popover/Popover.d.ts +23 -0
- package/dist/popover/Popover.js +8 -0
- package/dist/progress/Progress.d.ts +33 -0
- package/dist/progress/Progress.js +14 -0
- package/dist/progress/messages.d.ts +4 -0
- package/dist/progress/messages.js +2 -0
- package/dist/prose/Prose.d.ts +14 -0
- package/dist/prose/Prose.js +7 -0
- package/dist/rating/Rating.d.ts +32 -0
- package/dist/rating/Rating.js +27 -0
- package/dist/rating/messages.d.ts +6 -0
- package/dist/rating/messages.js +2 -0
- package/dist/search/Search.d.ts +11 -0
- package/dist/search/Search.js +9 -0
- package/dist/select/Select.d.ts +65 -0
- package/dist/select/Select.js +19 -0
- package/dist/select/messages.d.ts +4 -0
- package/dist/select/messages.js +2 -0
- package/dist/site-header/SiteHeader.d.ts +88 -0
- package/dist/site-header/SiteHeader.js +211 -0
- package/dist/site-header/messages.d.ts +8 -0
- package/dist/site-header/messages.js +2 -0
- package/dist/slider/Slider.d.ts +54 -0
- package/dist/slider/Slider.js +89 -0
- package/dist/slider/messages.d.ts +5 -0
- package/dist/slider/messages.js +2 -0
- package/dist/styles.css +3379 -0
- package/dist/switch/Switch.d.ts +47 -0
- package/dist/switch/Switch.js +18 -0
- package/dist/table/Table.d.ts +99 -0
- package/dist/table/Table.js +158 -0
- package/dist/table/messages.d.ts +23 -0
- package/dist/table/messages.js +2 -0
- package/dist/tabs/Tabs.d.ts +49 -0
- package/dist/tabs/Tabs.js +26 -0
- package/dist/tag/Tag.d.ts +37 -0
- package/dist/tag/Tag.js +20 -0
- package/dist/tag/messages.d.ts +4 -0
- package/dist/tag/messages.js +2 -0
- package/dist/text-area/TextArea.d.ts +47 -0
- package/dist/text-area/TextArea.js +19 -0
- package/dist/text-input/TextInput.d.ts +53 -0
- package/dist/text-input/TextInput.js +35 -0
- package/dist/text-input/messages.d.ts +4 -0
- package/dist/text-input/messages.js +3 -0
- package/dist/text-input/native-field.d.ts +15 -0
- package/dist/text-input/native-field.js +56 -0
- package/dist/toast/Toast.d.ts +24 -0
- package/dist/toast/Toast.js +79 -0
- package/dist/toast/messages.d.ts +4 -0
- package/dist/toast/messages.js +2 -0
- package/dist/tooltip/Tooltip.d.ts +22 -0
- package/dist/tooltip/Tooltip.js +92 -0
- package/dist/workflow/ContentState.d.ts +44 -0
- package/dist/workflow/ContentState.js +11 -0
- package/dist/workflow/Drawer.d.ts +48 -0
- package/dist/workflow/Drawer.js +51 -0
- package/dist/workflow/FileUpload.d.ts +67 -0
- package/dist/workflow/FileUpload.js +47 -0
- package/dist/workflow/Form.d.ts +52 -0
- package/dist/workflow/Form.js +16 -0
- package/dist/workflow/Wizard.d.ts +76 -0
- package/dist/workflow/Wizard.js +31 -0
- package/dist/workflow/drawer-messages.d.ts +4 -0
- package/dist/workflow/drawer-messages.js +2 -0
- package/dist/workflow/file-upload-messages.d.ts +11 -0
- package/dist/workflow/file-upload-messages.js +2 -0
- package/dist/workflow/form-messages.d.ts +5 -0
- package/dist/workflow/form-messages.js +2 -0
- package/dist/workflow/wizard-messages.d.ts +9 -0
- package/dist/workflow/wizard-messages.js +2 -0
- package/package.json +84 -4
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/** Every built-in English string in the full library, for reference and translation. */
|
|
2
|
+
export declare const defaultMessages: {
|
|
3
|
+
alert: {
|
|
4
|
+
dismiss: string;
|
|
5
|
+
brand: string;
|
|
6
|
+
success: string;
|
|
7
|
+
warning: string;
|
|
8
|
+
error: string;
|
|
9
|
+
info: string;
|
|
10
|
+
};
|
|
11
|
+
avatar: {
|
|
12
|
+
user: string;
|
|
13
|
+
online: string;
|
|
14
|
+
away: string;
|
|
15
|
+
busy: string;
|
|
16
|
+
};
|
|
17
|
+
badge: {
|
|
18
|
+
count: (count: number, label: string) => string;
|
|
19
|
+
};
|
|
20
|
+
breadcrumbs: {
|
|
21
|
+
label: string;
|
|
22
|
+
morePages: string;
|
|
23
|
+
};
|
|
24
|
+
calendar: {
|
|
25
|
+
previousMonth: string;
|
|
26
|
+
nextMonth: string;
|
|
27
|
+
chooseStart: string;
|
|
28
|
+
chooseEnd: string;
|
|
29
|
+
unavailableDay: (date: string) => string;
|
|
30
|
+
};
|
|
31
|
+
chart: {
|
|
32
|
+
total: string;
|
|
33
|
+
empty: string;
|
|
34
|
+
showData: string;
|
|
35
|
+
hideData: string;
|
|
36
|
+
dataTable: (title: string) => string;
|
|
37
|
+
dataCaption: (title: string) => string;
|
|
38
|
+
category: string;
|
|
39
|
+
value: string;
|
|
40
|
+
};
|
|
41
|
+
chatbot: {
|
|
42
|
+
you: string;
|
|
43
|
+
assistant: string;
|
|
44
|
+
message: string;
|
|
45
|
+
placeholder: string;
|
|
46
|
+
send: string;
|
|
47
|
+
stop: string;
|
|
48
|
+
retry: string;
|
|
49
|
+
copy: string;
|
|
50
|
+
copied: string;
|
|
51
|
+
copyUnavailable: string;
|
|
52
|
+
attach: string;
|
|
53
|
+
attachFiles: string;
|
|
54
|
+
remove: string;
|
|
55
|
+
preparing: string;
|
|
56
|
+
openChat: string;
|
|
57
|
+
closeChat: string;
|
|
58
|
+
messages: (title: string) => string;
|
|
59
|
+
};
|
|
60
|
+
choice: {
|
|
61
|
+
selectAll: string;
|
|
62
|
+
};
|
|
63
|
+
codeBlock: {
|
|
64
|
+
code: string;
|
|
65
|
+
namedCode: (label: string) => string;
|
|
66
|
+
copy: string;
|
|
67
|
+
copied: string;
|
|
68
|
+
copyFailed: string;
|
|
69
|
+
};
|
|
70
|
+
combobox: {
|
|
71
|
+
placeholder: string;
|
|
72
|
+
addAnother: string;
|
|
73
|
+
noResults: string;
|
|
74
|
+
openOptions: string;
|
|
75
|
+
closeOptions: string;
|
|
76
|
+
remove: (label: string) => string;
|
|
77
|
+
};
|
|
78
|
+
datePicker: {
|
|
79
|
+
chooseDate: string;
|
|
80
|
+
chooseRange: string;
|
|
81
|
+
chooseStart: string;
|
|
82
|
+
chooseEnd: string;
|
|
83
|
+
endDate: string;
|
|
84
|
+
previousMonth: string;
|
|
85
|
+
nextMonth: string;
|
|
86
|
+
today: string;
|
|
87
|
+
clear: string;
|
|
88
|
+
unavailableDay: (date: string) => string;
|
|
89
|
+
};
|
|
90
|
+
dialog: {
|
|
91
|
+
open: string;
|
|
92
|
+
confirm: string;
|
|
93
|
+
dismiss: string;
|
|
94
|
+
closeAction: string;
|
|
95
|
+
close: string;
|
|
96
|
+
error: string;
|
|
97
|
+
};
|
|
98
|
+
drawer: {
|
|
99
|
+
close: string;
|
|
100
|
+
};
|
|
101
|
+
fileUpload: {
|
|
102
|
+
title: string;
|
|
103
|
+
description: string;
|
|
104
|
+
choose: string;
|
|
105
|
+
remove: (name: string) => string;
|
|
106
|
+
rejected: (count: number) => string;
|
|
107
|
+
selected: (count: number) => string;
|
|
108
|
+
kilobytes: (size: string) => string;
|
|
109
|
+
megabytes: (size: string) => string;
|
|
110
|
+
};
|
|
111
|
+
form: {
|
|
112
|
+
submit: string;
|
|
113
|
+
cancel: string;
|
|
114
|
+
};
|
|
115
|
+
list: {
|
|
116
|
+
unread: string;
|
|
117
|
+
};
|
|
118
|
+
metric: {
|
|
119
|
+
increased: string;
|
|
120
|
+
decreased: string;
|
|
121
|
+
unchanged: string;
|
|
122
|
+
positive: string;
|
|
123
|
+
negative: string;
|
|
124
|
+
neutral: string;
|
|
125
|
+
};
|
|
126
|
+
pagination: {
|
|
127
|
+
label: string;
|
|
128
|
+
previous: string;
|
|
129
|
+
next: string;
|
|
130
|
+
perPage: string;
|
|
131
|
+
resultsPerPage: string;
|
|
132
|
+
page: (page: number) => string;
|
|
133
|
+
range: (start: number, end: number, total: number) => string;
|
|
134
|
+
noResults: string;
|
|
135
|
+
};
|
|
136
|
+
progress: {
|
|
137
|
+
inProgress: string;
|
|
138
|
+
};
|
|
139
|
+
rating: {
|
|
140
|
+
rated: (value: string, max: string) => string;
|
|
141
|
+
reviews: (count: number, formatted: string) => string;
|
|
142
|
+
count: (formatted: string) => string;
|
|
143
|
+
};
|
|
144
|
+
select: {
|
|
145
|
+
placeholder: string;
|
|
146
|
+
};
|
|
147
|
+
sideNavigation: {
|
|
148
|
+
label: string;
|
|
149
|
+
count: (label: string, count: number) => string;
|
|
150
|
+
};
|
|
151
|
+
siteHeader: {
|
|
152
|
+
home: string;
|
|
153
|
+
navigation: string;
|
|
154
|
+
openNavigation: string;
|
|
155
|
+
closeNavigation: string;
|
|
156
|
+
search: string;
|
|
157
|
+
};
|
|
158
|
+
slider: {
|
|
159
|
+
minimum: (label: string) => string;
|
|
160
|
+
maximum: (label: string) => string;
|
|
161
|
+
};
|
|
162
|
+
table: {
|
|
163
|
+
loading: string;
|
|
164
|
+
emptyTitle: string;
|
|
165
|
+
emptyDescription: string;
|
|
166
|
+
noMatches: string;
|
|
167
|
+
noMatchesDescription: string;
|
|
168
|
+
clearAll: string;
|
|
169
|
+
clearFilters: string;
|
|
170
|
+
clearSelection: string;
|
|
171
|
+
selected: (count: number) => string;
|
|
172
|
+
search: string;
|
|
173
|
+
searchLabel: (label: string) => string;
|
|
174
|
+
filterValue: (filter: string, value: string) => string;
|
|
175
|
+
noValue: string;
|
|
176
|
+
all: string;
|
|
177
|
+
open: string;
|
|
178
|
+
actions: string;
|
|
179
|
+
rowActions: (row: string) => string;
|
|
180
|
+
selectPage: string;
|
|
181
|
+
selectRow: (row: string) => string;
|
|
182
|
+
scrollHint: (label: string) => string;
|
|
183
|
+
};
|
|
184
|
+
tag: {
|
|
185
|
+
remove: (label: string) => string;
|
|
186
|
+
};
|
|
187
|
+
textInput: {
|
|
188
|
+
clear: (label: string) => string;
|
|
189
|
+
};
|
|
190
|
+
toast: {
|
|
191
|
+
label: string;
|
|
192
|
+
};
|
|
193
|
+
wizard: {
|
|
194
|
+
label: string;
|
|
195
|
+
progress: string;
|
|
196
|
+
back: string;
|
|
197
|
+
next: string;
|
|
198
|
+
complete: string;
|
|
199
|
+
step: (step: number, total: number) => string;
|
|
200
|
+
};
|
|
201
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { alertMessages } from './alert/messages.js';
|
|
2
|
+
import { avatarMessages } from './avatar/messages.js';
|
|
3
|
+
import { badgeMessages } from './badge/messages.js';
|
|
4
|
+
import { breadcrumbsMessages } from './breadcrumbs/messages.js';
|
|
5
|
+
import { calendarMessages } from './calendar/messages.js';
|
|
6
|
+
import { chartMessages } from './data-viz/messages.js';
|
|
7
|
+
import { chatbotMessages } from './application-patterns/chatbot-messages.js';
|
|
8
|
+
import { choiceMessages } from './choice/messages.js';
|
|
9
|
+
import { codeBlockMessages } from './code-block/messages.js';
|
|
10
|
+
import { comboboxMessages } from './combobox/messages.js';
|
|
11
|
+
import { datePickerMessages } from './date-picker/messages.js';
|
|
12
|
+
import { dialogMessages } from './dialog/messages.js';
|
|
13
|
+
import { drawerMessages } from './workflow/drawer-messages.js';
|
|
14
|
+
import { fileUploadMessages } from './workflow/file-upload-messages.js';
|
|
15
|
+
import { formMessages } from './workflow/form-messages.js';
|
|
16
|
+
import { listMessages } from './list/messages.js';
|
|
17
|
+
import { metricMessages } from './metric/messages.js';
|
|
18
|
+
import { paginationMessages } from './pagination/messages.js';
|
|
19
|
+
import { progressMessages } from './progress/messages.js';
|
|
20
|
+
import { ratingMessages } from './rating/messages.js';
|
|
21
|
+
import { selectMessages } from './select/messages.js';
|
|
22
|
+
import { sideNavigationMessages } from './application-patterns/side-navigation-messages.js';
|
|
23
|
+
import { siteHeaderMessages } from './site-header/messages.js';
|
|
24
|
+
import { sliderMessages } from './slider/messages.js';
|
|
25
|
+
import { tableMessages } from './table/messages.js';
|
|
26
|
+
import { tagMessages } from './tag/messages.js';
|
|
27
|
+
import { textInputMessages } from './text-input/messages.js';
|
|
28
|
+
import { toastMessages } from './toast/messages.js';
|
|
29
|
+
import { wizardMessages } from './workflow/wizard-messages.js';
|
|
30
|
+
/** Every built-in English string in the full library, for reference and translation. */
|
|
31
|
+
export const defaultMessages = {
|
|
32
|
+
alert: alertMessages,
|
|
33
|
+
avatar: avatarMessages,
|
|
34
|
+
badge: badgeMessages,
|
|
35
|
+
breadcrumbs: breadcrumbsMessages,
|
|
36
|
+
calendar: calendarMessages,
|
|
37
|
+
chart: chartMessages,
|
|
38
|
+
chatbot: chatbotMessages,
|
|
39
|
+
choice: choiceMessages,
|
|
40
|
+
codeBlock: codeBlockMessages,
|
|
41
|
+
combobox: comboboxMessages,
|
|
42
|
+
datePicker: datePickerMessages,
|
|
43
|
+
dialog: dialogMessages,
|
|
44
|
+
drawer: drawerMessages,
|
|
45
|
+
fileUpload: fileUploadMessages,
|
|
46
|
+
form: formMessages,
|
|
47
|
+
list: listMessages,
|
|
48
|
+
metric: metricMessages,
|
|
49
|
+
pagination: paginationMessages,
|
|
50
|
+
progress: progressMessages,
|
|
51
|
+
rating: ratingMessages,
|
|
52
|
+
select: selectMessages,
|
|
53
|
+
sideNavigation: sideNavigationMessages,
|
|
54
|
+
siteHeader: siteHeaderMessages,
|
|
55
|
+
slider: sliderMessages,
|
|
56
|
+
table: tableMessages,
|
|
57
|
+
tag: tagMessages,
|
|
58
|
+
textInput: textInputMessages,
|
|
59
|
+
toast: toastMessages,
|
|
60
|
+
wizard: wizardMessages,
|
|
61
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in strings, by component. Each component that has strings adds its
|
|
3
|
+
* own entry (see its messages module), so a bundle types exactly the
|
|
4
|
+
* components it contains. Values are strings, or functions for strings that
|
|
5
|
+
* interpolate values.
|
|
6
|
+
*/
|
|
7
|
+
export interface DiyaMessages {
|
|
8
|
+
}
|
|
9
|
+
/** Override any subset: `{ table: { emptyTitle: 'Nothing here' } }`. */
|
|
10
|
+
export type DiyaMessagesInput = {
|
|
11
|
+
[K in keyof DiyaMessages]?: Partial<DiyaMessages[K]>;
|
|
12
|
+
};
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
import { metricMessages } from './messages.js';
|
|
3
|
+
declare module '../messages.js' {
|
|
4
|
+
interface DiyaMessages {
|
|
5
|
+
metric: typeof metricMessages;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export type MetricChange = {
|
|
9
|
+
/** Visible change text, already formatted, such as '+12%'. */
|
|
10
|
+
value: string;
|
|
11
|
+
/** Draws an up, down or flat arrow and is announced as increased, decreased or unchanged. */
|
|
12
|
+
direction: 'up' | 'down' | 'flat';
|
|
13
|
+
/** Whether the change is good ('positive', green), bad ('negative', red) or neither; independent of direction, and announced. */
|
|
14
|
+
meaning: 'positive' | 'negative' | 'neutral';
|
|
15
|
+
/** Visible context after the change, such as 'vs last month'. */
|
|
16
|
+
comparison?: string;
|
|
17
|
+
};
|
|
18
|
+
export type MetricProps = Omit<HTMLAttributes<HTMLDivElement>, 'children'> & {
|
|
19
|
+
/** The headline figure as visible text, already formatted, such as '2,481'. */
|
|
20
|
+
value: string;
|
|
21
|
+
/** Visible caption above the figure. */
|
|
22
|
+
label?: string;
|
|
23
|
+
/** Visible unit after the figure, such as 'ms' or '%'. */
|
|
24
|
+
unit?: string;
|
|
25
|
+
/** Figure size. Defaults to 'medium'. */
|
|
26
|
+
size?: 'small' | 'medium' | 'large';
|
|
27
|
+
/** A change against an earlier value, shown under the figure. */
|
|
28
|
+
change?: MetricChange;
|
|
29
|
+
};
|
|
30
|
+
/** One headline number with an optional caption, unit and change. */
|
|
31
|
+
export declare const Metric: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
|
|
32
|
+
/** The headline figure as visible text, already formatted, such as '2,481'. */
|
|
33
|
+
value: string;
|
|
34
|
+
/** Visible caption above the figure. */
|
|
35
|
+
label?: string;
|
|
36
|
+
/** Visible unit after the figure, such as 'ms' or '%'. */
|
|
37
|
+
unit?: string;
|
|
38
|
+
/** Figure size. Defaults to 'medium'. */
|
|
39
|
+
size?: "small" | "medium" | "large";
|
|
40
|
+
/** A change against an earlier value, shown under the figure. */
|
|
41
|
+
change?: MetricChange;
|
|
42
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { useDiyaMessages } from '../DiyaProvider.js';
|
|
5
|
+
import { cx } from '../internal/cx.js';
|
|
6
|
+
import { metricMessages } from './messages.js';
|
|
7
|
+
/** One headline number with an optional caption, unit and change. */
|
|
8
|
+
export const Metric = forwardRef(function Metric({ value, label, unit, change, size = 'medium', className, ...props }, ref) {
|
|
9
|
+
const t = useDiyaMessages('metric', metricMessages);
|
|
10
|
+
return _jsxs("div", { ...props, ref: ref, className: cx('diya-metric', className), "data-size": size, children: [label && _jsx("span", { className: "diya-metric-label", children: label }), _jsxs("div", { className: "diya-metric-number", children: [value, unit && _jsx("span", { className: "diya-metric-unit", children: unit })] }), change && _jsxs("div", { className: "diya-metric-comparison", children: [_jsxs("span", { className: "diya-metric-change", "data-meaning": change.meaning, children: [_jsx("span", { "aria-hidden": "true", children: change.direction === 'flat' ? '→' : change.direction === 'up' ? '↑' : '↓' }), _jsxs("span", { className: "diya-metric-sr", children: [change.direction === 'flat' ? t.unchanged : change.direction === 'up' ? t.increased : t.decreased, ": "] }), change.value, _jsxs("span", { className: "diya-metric-sr", children: [" (", t[change.meaning], ")"] })] }), change.comparison && _jsx("span", { children: change.comparison })] })] });
|
|
11
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type ButtonHTMLAttributes, type ReactElement, type ReactNode, type KeyboardEvent } from 'react';
|
|
2
|
+
/** Root props shared by Menu and Popover: everything except `children` lands on the trigger. An interface, so declaration files keep these docs. */
|
|
3
|
+
export interface FloatingTriggerProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children' | 'disabled' | 'type' | 'role'> {
|
|
4
|
+
/** Your own trigger element, such as `<Button iconOnly aria-label="More">…</Button>`; DIYA wires its click, keys and ARIA. Defaults to a DIYA Button showing `label`. */
|
|
5
|
+
trigger?: ReactElement;
|
|
6
|
+
/** Whether the panel is open; leave it out to let the trigger manage it. */
|
|
7
|
+
open?: boolean;
|
|
8
|
+
/** Called with the next open state whenever the panel opens or closes. */
|
|
9
|
+
onOpenChange?: (open: boolean) => void;
|
|
10
|
+
}
|
|
11
|
+
/** The shared trigger button and floating panel behind Menu and Popover. */
|
|
12
|
+
export declare const FloatingSurface: import("react").ForwardRefExoticComponent<FloatingTriggerProps & {
|
|
13
|
+
/** Shows this icon as an icon-only trigger; `label` then becomes its accessible name. */
|
|
14
|
+
triggerIcon?: ReactNode;
|
|
15
|
+
/** The trigger's visible text (or accessible name with `triggerIcon`) and the panel's accessible name. */
|
|
16
|
+
label: string;
|
|
17
|
+
/** 'menu' for a list of menu items, 'dialog' for free content with its own tab order. Defaults to 'dialog'. */
|
|
18
|
+
role?: "menu" | "dialog";
|
|
19
|
+
/** Preferred side for the panel; it moves to stay on screen. Defaults to 'bottom'. */
|
|
20
|
+
placement?: "top" | "bottom";
|
|
21
|
+
/** Disables the trigger and closes an open panel. */
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
/** The panel's content, or a function that renders it; call `close` to shut it and return focus to the trigger. */
|
|
24
|
+
children: ReactNode | ((close: () => void) => ReactNode);
|
|
25
|
+
/** Handles keys other than Tab inside the panel, such as menu arrow keys. */
|
|
26
|
+
onPanelKeyDown?: (event: KeyboardEvent<HTMLDivElement>) => void;
|
|
27
|
+
/** Focuses the last control instead of the first when the panel opens. */
|
|
28
|
+
focusLast?: boolean;
|
|
29
|
+
} & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, } from 'react';
|
|
4
|
+
import { createPortal } from 'react-dom';
|
|
5
|
+
import { Button } from '../button/Button.js';
|
|
6
|
+
import { useDiyaPortal } from '../DiyaProvider.js';
|
|
7
|
+
import { composeRefs, mergeSlotProps, renderSlot } from '../internal/slot.js';
|
|
8
|
+
const useClientLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
|
|
9
|
+
// Scrolls this soon after opening only reposition, even if the trigger is briefly out of view:
|
|
10
|
+
// the browser may still be bringing it in after focus moved to it.
|
|
11
|
+
const OPEN_SETTLE_MS = 300;
|
|
12
|
+
/** Whether a trigger rectangle still shows any part inside the viewport. */
|
|
13
|
+
function inViewport(rect, view) {
|
|
14
|
+
return rect.bottom > 0 && rect.right > 0 && rect.top < view.innerHeight && rect.left < view.innerWidth;
|
|
15
|
+
}
|
|
16
|
+
const tabbableSelector = 'a[href], area[href], button, input:not([type="hidden"]), select, textarea, iframe, object, embed, audio[controls], video[controls], summary, [contenteditable], [tabindex]';
|
|
17
|
+
function tabStops(scope, surface) {
|
|
18
|
+
const document = scope.ownerDocument ?? scope;
|
|
19
|
+
const view = document.defaultView;
|
|
20
|
+
const stops = Array.from(scope.querySelectorAll(tabbableSelector)).filter((element) => {
|
|
21
|
+
if (surface?.contains(element) || element.matches(':disabled'))
|
|
22
|
+
return false;
|
|
23
|
+
const editable = element.hasAttribute('contenteditable') &&
|
|
24
|
+
element.contentEditable !== 'false' &&
|
|
25
|
+
!element.parentElement?.isContentEditable;
|
|
26
|
+
if (element.tabIndex < 0 && (element.hasAttribute('tabindex') || !editable))
|
|
27
|
+
return false;
|
|
28
|
+
for (let ancestor = element; ancestor; ancestor = ancestor.parentElement) {
|
|
29
|
+
if (ancestor.hidden || ancestor.hasAttribute('inert'))
|
|
30
|
+
return false;
|
|
31
|
+
const style = view?.getComputedStyle(ancestor);
|
|
32
|
+
if (style?.display === 'none' ||
|
|
33
|
+
style?.visibility === 'hidden' ||
|
|
34
|
+
style?.visibility === 'collapse' ||
|
|
35
|
+
style?.contentVisibility === 'hidden')
|
|
36
|
+
return false;
|
|
37
|
+
if (ancestor !== element &&
|
|
38
|
+
ancestor.tagName === 'DETAILS' &&
|
|
39
|
+
!ancestor.hasAttribute('open')) {
|
|
40
|
+
const summary = Array.from(ancestor.children).find((child) => child.tagName === 'SUMMARY');
|
|
41
|
+
if (!summary?.contains(element))
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return true;
|
|
46
|
+
});
|
|
47
|
+
const ordered = stops
|
|
48
|
+
.filter((element) => {
|
|
49
|
+
if (element.tagName !== 'INPUT')
|
|
50
|
+
return true;
|
|
51
|
+
const radio = element;
|
|
52
|
+
return (radio.type !== 'radio' ||
|
|
53
|
+
!radio.name ||
|
|
54
|
+
radio.checked ||
|
|
55
|
+
!stops.some((candidate) => {
|
|
56
|
+
if (candidate.tagName !== 'INPUT')
|
|
57
|
+
return false;
|
|
58
|
+
const other = candidate;
|
|
59
|
+
return (other.type === 'radio' &&
|
|
60
|
+
other.name === radio.name &&
|
|
61
|
+
other.form === radio.form &&
|
|
62
|
+
other.checked);
|
|
63
|
+
}));
|
|
64
|
+
})
|
|
65
|
+
.map((element, index) => ({ element, index, order: Math.max(0, element.tabIndex) }))
|
|
66
|
+
.sort((a, b) => {
|
|
67
|
+
if (a.order === b.order)
|
|
68
|
+
return a.index - b.index;
|
|
69
|
+
if (a.order === 0)
|
|
70
|
+
return 1;
|
|
71
|
+
if (b.order === 0)
|
|
72
|
+
return -1;
|
|
73
|
+
return a.order - b.order;
|
|
74
|
+
});
|
|
75
|
+
return ordered.map(({ element }) => element);
|
|
76
|
+
}
|
|
77
|
+
function adjacentTabStop(anchor, surface, backwards) {
|
|
78
|
+
const modal = anchor.closest('dialog[open]');
|
|
79
|
+
const ordered = tabStops(modal ?? anchor.ownerDocument, surface);
|
|
80
|
+
const index = ordered.indexOf(anchor);
|
|
81
|
+
if (index < 0)
|
|
82
|
+
return undefined;
|
|
83
|
+
const next = index + (backwards ? -1 : 1);
|
|
84
|
+
return ordered[modal ? (next + ordered.length) % ordered.length : next];
|
|
85
|
+
}
|
|
86
|
+
/** The shared trigger button and floating panel behind Menu and Popover. */
|
|
87
|
+
export const FloatingSurface = forwardRef(function FloatingSurface({ label, role = 'dialog', placement = 'bottom', disabled, children, onPanelKeyDown, focusLast = false, triggerIcon, trigger: triggerElement, open: controlledOpen, onOpenChange, ...rest }, ref) {
|
|
88
|
+
const providerPortal = useDiyaPortal();
|
|
89
|
+
const id = useId();
|
|
90
|
+
const trigger = useRef(null);
|
|
91
|
+
const setTrigger = useMemo(() => composeRefs(trigger, ref), [ref]);
|
|
92
|
+
const panel = useRef(null);
|
|
93
|
+
const [localOpen, setLocalOpen] = useState(false);
|
|
94
|
+
const open = controlledOpen ?? localOpen;
|
|
95
|
+
// Document listeners outlive a render, so they read the latest state and callback from here.
|
|
96
|
+
const current = useRef(open);
|
|
97
|
+
current.current = open;
|
|
98
|
+
const latest = useRef({ controlled: controlledOpen !== undefined, onOpenChange });
|
|
99
|
+
latest.current = { controlled: controlledOpen !== undefined, onOpenChange };
|
|
100
|
+
const openedAt = useRef(0);
|
|
101
|
+
const last = useRef(focusLast);
|
|
102
|
+
const modal = open ? trigger.current?.closest('dialog[open]') : null;
|
|
103
|
+
const portal = modal && !modal.contains(providerPortal) ? modal : providerPortal;
|
|
104
|
+
function setOpen(next) {
|
|
105
|
+
if (next === current.current)
|
|
106
|
+
return;
|
|
107
|
+
current.current = next;
|
|
108
|
+
if (!latest.current.controlled)
|
|
109
|
+
setLocalOpen(next);
|
|
110
|
+
latest.current.onOpenChange?.(next);
|
|
111
|
+
}
|
|
112
|
+
function close(restore = true) {
|
|
113
|
+
setOpen(false);
|
|
114
|
+
if (restore)
|
|
115
|
+
trigger.current?.focus({ preventScroll: true });
|
|
116
|
+
}
|
|
117
|
+
// Anchors the panel to the trigger, flipping above it or clamping so it stays on screen.
|
|
118
|
+
// Written straight to the panel's style, so following a scroll doesn't re-render the content.
|
|
119
|
+
function place() {
|
|
120
|
+
const node = panel.current;
|
|
121
|
+
const anchor = trigger.current?.getBoundingClientRect();
|
|
122
|
+
if (!node || !anchor)
|
|
123
|
+
return;
|
|
124
|
+
const box = node.getBoundingClientRect();
|
|
125
|
+
let top = placement === 'top' ? anchor.top - box.height - 10 : anchor.bottom + 10;
|
|
126
|
+
if (top + box.height > window.innerHeight - 12)
|
|
127
|
+
top = anchor.top - box.height - 10;
|
|
128
|
+
if (top < 12)
|
|
129
|
+
top = 12;
|
|
130
|
+
const left = Math.max(12, Math.min(anchor.left + (anchor.width - box.width) / 2, window.innerWidth - box.width - 12));
|
|
131
|
+
node.style.left = `${left}px`;
|
|
132
|
+
node.style.top = `${top}px`;
|
|
133
|
+
}
|
|
134
|
+
function handleKeyDown(event) {
|
|
135
|
+
if (event.defaultPrevented)
|
|
136
|
+
return;
|
|
137
|
+
if (event.key !== 'Tab') {
|
|
138
|
+
onPanelKeyDown?.(event);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const anchor = trigger.current;
|
|
142
|
+
if (role === 'dialog' && panel.current) {
|
|
143
|
+
const controls = tabStops(panel.current);
|
|
144
|
+
const current = controls.indexOf(panel.current.ownerDocument.activeElement);
|
|
145
|
+
if (current >= 0 && (event.shiftKey ? current > 0 : current < controls.length - 1))
|
|
146
|
+
return;
|
|
147
|
+
if (event.shiftKey) {
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
close();
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
const destination = anchor && adjacentTabStop(anchor, panel.current, event.shiftKey);
|
|
154
|
+
close(false);
|
|
155
|
+
if (destination) {
|
|
156
|
+
destination.focus();
|
|
157
|
+
if (destination.ownerDocument.activeElement === destination)
|
|
158
|
+
event.preventDefault();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
useClientLayoutEffect(() => {
|
|
162
|
+
if (!open || !trigger.current || !panel.current)
|
|
163
|
+
return;
|
|
164
|
+
openedAt.current = performance.now();
|
|
165
|
+
place();
|
|
166
|
+
const targets = role === 'dialog' && panel.current ? tabStops(panel.current)
|
|
167
|
+
: panel.current?.querySelectorAll('[role^="menuitem"]:not(:disabled), input:not(:disabled), [tabindex="0"]');
|
|
168
|
+
const target = last.current ? targets?.[targets.length - 1] : targets?.[0];
|
|
169
|
+
(target ?? panel.current)?.focus({ preventScroll: true });
|
|
170
|
+
}, [open, placement]);
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
if (!open)
|
|
173
|
+
return;
|
|
174
|
+
function outside(event) {
|
|
175
|
+
if (!panel.current?.contains(event.target) &&
|
|
176
|
+
!trigger.current?.contains(event.target))
|
|
177
|
+
setOpen(false);
|
|
178
|
+
}
|
|
179
|
+
function escape(event) {
|
|
180
|
+
if (event.key === 'Escape' && !event.isComposing && !event.defaultPrevented) {
|
|
181
|
+
event.preventDefault();
|
|
182
|
+
setOpen(false);
|
|
183
|
+
trigger.current?.focus();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// A scroll or resize outside the panel moves it with its trigger, once per frame. It closes only
|
|
187
|
+
// when the trigger has left the viewport, and never in the first moments after opening.
|
|
188
|
+
let frame = 0;
|
|
189
|
+
const follow = () => {
|
|
190
|
+
frame = 0;
|
|
191
|
+
const anchor = trigger.current?.getBoundingClientRect();
|
|
192
|
+
if (anchor && !inViewport(anchor, window) && performance.now() - openedAt.current > OPEN_SETTLE_MS) {
|
|
193
|
+
close(!!panel.current?.contains(document.activeElement));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
place();
|
|
197
|
+
};
|
|
198
|
+
const schedule = (event) => {
|
|
199
|
+
if (event.type === 'scroll' && panel.current?.contains(event.target))
|
|
200
|
+
return;
|
|
201
|
+
if (!frame)
|
|
202
|
+
frame = requestAnimationFrame(follow);
|
|
203
|
+
};
|
|
204
|
+
// The panel's own size changes too, such as switching Tabs inside it.
|
|
205
|
+
const observer = typeof ResizeObserver === 'function' ? new ResizeObserver(() => schedule(new Event('resize'))) : null;
|
|
206
|
+
if (panel.current)
|
|
207
|
+
observer?.observe(panel.current);
|
|
208
|
+
if (trigger.current)
|
|
209
|
+
observer?.observe(trigger.current);
|
|
210
|
+
document.addEventListener('pointerdown', outside);
|
|
211
|
+
document.addEventListener('keydown', escape);
|
|
212
|
+
window.addEventListener('resize', schedule);
|
|
213
|
+
window.addEventListener('scroll', schedule, true);
|
|
214
|
+
return () => {
|
|
215
|
+
cancelAnimationFrame(frame);
|
|
216
|
+
observer?.disconnect();
|
|
217
|
+
document.removeEventListener('pointerdown', outside);
|
|
218
|
+
document.removeEventListener('keydown', escape);
|
|
219
|
+
window.removeEventListener('resize', schedule);
|
|
220
|
+
window.removeEventListener('scroll', schedule, true);
|
|
221
|
+
};
|
|
222
|
+
}, [open, placement]);
|
|
223
|
+
useEffect(() => {
|
|
224
|
+
if (disabled && open)
|
|
225
|
+
close(false);
|
|
226
|
+
}, [disabled, open]);
|
|
227
|
+
const triggerProps = {
|
|
228
|
+
...(triggerElement ? rest : {}),
|
|
229
|
+
disabled: disabled || undefined,
|
|
230
|
+
'aria-haspopup': role,
|
|
231
|
+
'aria-expanded': open,
|
|
232
|
+
'aria-controls': open ? id : undefined,
|
|
233
|
+
onClick: () => {
|
|
234
|
+
last.current = false;
|
|
235
|
+
setOpen(!current.current);
|
|
236
|
+
},
|
|
237
|
+
onKeyDown: (event) => {
|
|
238
|
+
if (role === 'menu' && ['ArrowDown', 'ArrowUp'].includes(event.key)) {
|
|
239
|
+
event.preventDefault();
|
|
240
|
+
last.current = event.key === 'ArrowUp';
|
|
241
|
+
setOpen(true);
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
};
|
|
245
|
+
return (_jsxs(_Fragment, { children: [_jsx("span", { children: triggerElement
|
|
246
|
+
? renderSlot(triggerElement, triggerProps, setTrigger)
|
|
247
|
+
: _jsx(Button, { ref: setTrigger, variant: triggerIcon ? 'quiet' : 'outline', iconOnly: !!triggerIcon, "aria-label": triggerIcon ? label : undefined, disabled: disabled, ...mergeSlotProps(triggerProps, rest), children: triggerIcon ?? label }) }), open &&
|
|
248
|
+
portal &&
|
|
249
|
+
createPortal(_jsx("div", { ref: panel, id: id, role: role, "aria-label": label, tabIndex: -1, className: `diya-floating-surface diya-floating-${role}`, onKeyDown: handleKeyDown, onBlur: (event) => {
|
|
250
|
+
if (!event.currentTarget.contains(event.relatedTarget) &&
|
|
251
|
+
event.relatedTarget !== trigger.current)
|
|
252
|
+
close(false);
|
|
253
|
+
}, children: typeof children === 'function' ? children(() => close()) : children }), portal)] }));
|
|
254
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type HTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
export type PageHeaderProps = Omit<HTMLAttributes<HTMLElement>, 'title'> & {
|
|
3
|
+
/** The page heading; it also names the section for assistive technology. */
|
|
4
|
+
title: ReactNode;
|
|
5
|
+
/** Heading element level, h1 to h6; defaults to 2. Use 1 for the page's only top heading. */
|
|
6
|
+
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
7
|
+
/** Slot above the heading, usually a Breadcrumbs element. */
|
|
8
|
+
breadcrumbs?: ReactNode;
|
|
9
|
+
/** Supporting text under the heading. */
|
|
10
|
+
description?: ReactNode;
|
|
11
|
+
/** Slot under the description for Tag or Badge elements. */
|
|
12
|
+
tags?: ReactNode;
|
|
13
|
+
/** Slot beside the heading for page-level buttons. */
|
|
14
|
+
actions?: ReactNode;
|
|
15
|
+
/** Slot along the bottom edge, usually Tabs for sub-pages. */
|
|
16
|
+
navigation?: ReactNode;
|
|
17
|
+
/** Draws the header on its own panel; defaults to true. Pass false to set it straight on the page, as an app screen's title. */
|
|
18
|
+
surface?: boolean;
|
|
19
|
+
};
|
|
20
|
+
/** A page's heading block with optional breadcrumbs, description, tags, actions and tabs. Data and actions belong to the host app. Optional slots reserve no empty space. */
|
|
21
|
+
export declare const PageHeader: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLElement>, "title"> & {
|
|
22
|
+
/** The page heading; it also names the section for assistive technology. */
|
|
23
|
+
title: ReactNode;
|
|
24
|
+
/** Heading element level, h1 to h6; defaults to 2. Use 1 for the page's only top heading. */
|
|
25
|
+
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
26
|
+
/** Slot above the heading, usually a Breadcrumbs element. */
|
|
27
|
+
breadcrumbs?: ReactNode;
|
|
28
|
+
/** Supporting text under the heading. */
|
|
29
|
+
description?: ReactNode;
|
|
30
|
+
/** Slot under the description for Tag or Badge elements. */
|
|
31
|
+
tags?: ReactNode;
|
|
32
|
+
/** Slot beside the heading for page-level buttons. */
|
|
33
|
+
actions?: ReactNode;
|
|
34
|
+
/** Slot along the bottom edge, usually Tabs for sub-pages. */
|
|
35
|
+
navigation?: ReactNode;
|
|
36
|
+
/** Draws the header on its own panel; defaults to true. Pass false to set it straight on the page, as an app screen's title. */
|
|
37
|
+
surface?: boolean;
|
|
38
|
+
} & import("react").RefAttributes<HTMLElement>>;
|