@tensor_1/react 2.46.0 → 2.48.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/README.md +509 -1
- package/dist/{SchedulingCalendar-B6TakO2h.d.ts → SchedulingCalendar-WWyFL3Eo.d.ts} +51 -2
- package/dist/announce.d.ts +10 -0
- package/dist/announce.js +30 -0
- package/dist/chart-analytic.cjs +33 -25
- package/dist/chart-preset.cjs +23 -15
- package/dist/chart.cjs +23 -15
- package/dist/combobox-model.d.ts +10 -1
- package/dist/combobox-model.js +15 -0
- package/dist/command-palette-model.d.ts +44 -0
- package/dist/command-palette-model.js +36 -0
- package/dist/components/AccountMenu.d.ts +44 -0
- package/dist/components/AccountMenu.js +43 -0
- package/dist/components/AppShell.d.ts +45 -2
- package/dist/components/AppShell.js +116 -5
- package/dist/components/AuditLog.d.ts +128 -0
- package/dist/components/AuditLog.js +196 -0
- package/dist/components/BrandProfiles.js +4 -3
- package/dist/components/Breadcrumbs.d.ts +9 -2
- package/dist/components/Breadcrumbs.js +3 -2
- package/dist/components/BusyBar.d.ts +13 -0
- package/dist/components/BusyBar.js +10 -0
- package/dist/components/BusyRegion.d.ts +18 -0
- package/dist/components/BusyRegion.js +12 -0
- package/dist/components/Button.d.ts +33 -5
- package/dist/components/Button.js +12 -6
- package/dist/components/ButtonFeedback.d.ts +30 -0
- package/dist/components/ButtonFeedback.js +78 -0
- package/dist/components/Card.d.ts +18 -1
- package/dist/components/Card.js +5 -1
- package/dist/components/ChangeHighlight.d.ts +30 -0
- package/dist/components/ChangeHighlight.js +21 -0
- package/dist/components/ChartCore.js +2 -1
- package/dist/components/Checkbox.d.ts +27 -1
- package/dist/components/Checkbox.js +31 -2
- package/dist/components/CodeDisplay.d.ts +65 -0
- package/dist/components/CodeDisplay.js +124 -0
- package/dist/components/Combobox.d.ts +27 -6
- package/dist/components/Combobox.js +195 -58
- package/dist/components/CommandPalette.d.ts +36 -1
- package/dist/components/CommandPalette.js +254 -2
- package/dist/components/ContactCard.d.ts +66 -0
- package/dist/components/ContactCard.js +74 -0
- package/dist/components/Count.d.ts +24 -0
- package/dist/components/Count.js +32 -0
- package/dist/components/DataWorkspace.d.ts +167 -0
- package/dist/components/DataWorkspace.js +383 -0
- package/dist/components/DateFieldParts.d.ts +2 -1
- package/dist/components/DateFieldParts.js +7 -0
- package/dist/components/DatePicker.d.ts +9 -2
- package/dist/components/DatePicker.js +67 -28
- package/dist/components/DateRangePicker.d.ts +12 -2
- package/dist/components/DateRangePicker.js +13 -12
- package/dist/components/DelayedRender.d.ts +15 -0
- package/dist/components/DelayedRender.js +10 -0
- package/dist/components/DetailPage.d.ts +7 -1
- package/dist/components/DetailPage.js +2 -1
- package/dist/components/Dialogs.d.ts +71 -10
- package/dist/components/Dialogs.js +130 -30
- package/dist/components/DiffViewer.d.ts +23 -3
- package/dist/components/DiffViewer.js +26 -12
- package/dist/components/DiscardPrompt.d.ts +1 -0
- package/dist/components/DiscardPrompt.js +16 -0
- package/dist/components/DisplayPreferences.d.ts +83 -0
- package/dist/components/DisplayPreferences.js +185 -0
- package/dist/components/Drawer.d.ts +1 -0
- package/dist/components/EditorialHome.d.ts +23 -3
- package/dist/components/EditorialHome.js +16 -11
- package/dist/components/EntityPicker.d.ts +20 -3
- package/dist/components/EntityPicker.js +32 -13
- package/dist/components/FilterEditor.d.ts +18 -4
- package/dist/components/FilterEditor.js +141 -19
- package/dist/components/InfoTip.js +11 -12
- package/dist/components/InlineEdit.d.ts +87 -20
- package/dist/components/InlineEdit.js +197 -54
- package/dist/components/Input.d.ts +12 -2
- package/dist/components/Input.js +5 -3
- package/dist/components/Kbd.d.ts +6 -1
- package/dist/components/Kbd.js +6 -6
- package/dist/components/Lightbox.d.ts +41 -5
- package/dist/components/Lightbox.js +95 -9
- package/dist/components/MatchReview.d.ts +40 -1
- package/dist/components/MatchReview.js +130 -4
- package/dist/components/MetricInput.js +3 -2
- package/dist/components/Modal.d.ts +3 -1
- package/dist/components/Modal.js +13 -4
- package/dist/components/NavFavourites.d.ts +5 -0
- package/dist/components/NavFavourites.js +7 -7
- package/dist/components/OtpInput.d.ts +33 -0
- package/dist/components/OtpInput.js +123 -0
- package/dist/components/PageHeader.d.ts +7 -1
- package/dist/components/PageHeader.js +2 -2
- package/dist/components/Pagination.js +6 -5
- package/dist/components/PasswordInput.d.ts +34 -0
- package/dist/components/PasswordInput.js +101 -0
- package/dist/components/Peek.js +3 -3
- package/dist/components/Popover.js +2 -0
- package/dist/components/PrintLayout.d.ts +63 -0
- package/dist/components/PrintLayout.js +114 -0
- package/dist/components/QrCode.d.ts +47 -0
- package/dist/components/QrCode.js +55 -0
- package/dist/components/QrScanner.d.ts +95 -0
- package/dist/components/QrScanner.js +266 -0
- package/dist/components/RelationshipGraph.d.ts +32 -1
- package/dist/components/RelationshipGraph.js +18 -5
- package/dist/components/RelationshipGraphLayered.d.ts +1 -1
- package/dist/components/RelationshipGraphLayered.js +190 -115
- package/dist/components/RelationshipGraphList.js +33 -6
- package/dist/components/RuleBuilder.js +39 -7
- package/dist/components/SaveStatus.d.ts +7 -1
- package/dist/components/SaveStatus.js +13 -4
- package/dist/components/SchedulingAgenda.d.ts +3 -1
- package/dist/components/SchedulingCalendar.d.ts +3 -1
- package/dist/components/SchedulingCalendar.js +43 -4
- package/dist/components/SchedulingResourceDay.d.ts +57 -0
- package/dist/components/SchedulingResourceDay.js +287 -0
- package/dist/components/SchedulingTimeGrid.d.ts +3 -1
- package/dist/components/SchedulingTimeline.d.ts +3 -1
- package/dist/components/SearchBar.d.ts +1 -0
- package/dist/components/SearchSuggest.d.ts +23 -3
- package/dist/components/SearchSuggest.js +48 -17
- package/dist/components/Segmented.d.ts +39 -4
- package/dist/components/Segmented.js +31 -3
- package/dist/components/Select.d.ts +3 -2
- package/dist/components/Select.js +1 -1
- package/dist/components/ShortcutHint.d.ts +11 -10
- package/dist/components/ShortcutHint.js +44 -38
- package/dist/components/Sidebar.d.ts +36 -4
- package/dist/components/Sidebar.js +37 -12
- package/dist/components/SortableList.d.ts +45 -0
- package/dist/components/SortableList.js +134 -0
- package/dist/components/Spinner.d.ts +7 -1
- package/dist/components/Spinner.js +7 -1
- package/dist/components/Stat.d.ts +28 -3
- package/dist/components/Stat.js +13 -3
- package/dist/components/States.d.ts +7 -1
- package/dist/components/States.js +7 -1
- package/dist/components/StatusPill.d.ts +14 -3
- package/dist/components/StatusPill.js +11 -3
- package/dist/components/Steps.js +2 -1
- package/dist/components/Table.d.ts +16 -2
- package/dist/components/Table.js +8 -4
- package/dist/components/TableControls.js +18 -58
- package/dist/components/TableOverflowProbe.d.ts +12 -0
- package/dist/components/TableOverflowProbe.js +27 -0
- package/dist/components/Tabs.d.ts +2 -1
- package/dist/components/Tabs.js +1 -0
- package/dist/components/TagInput.d.ts +67 -0
- package/dist/components/TagInput.js +342 -0
- package/dist/components/Textarea.d.ts +5 -0
- package/dist/components/Textarea.js +2 -2
- package/dist/components/TimePicker.d.ts +80 -0
- package/dist/components/TimePicker.js +347 -0
- package/dist/components/Toast.js +3 -2
- package/dist/components/Tooltip.d.ts +8 -4
- package/dist/components/Tooltip.js +24 -21
- package/dist/components/Tree.d.ts +8 -0
- package/dist/components/Tree.js +11 -5
- package/dist/display-preferences-model.d.ts +53 -0
- package/dist/display-preferences-model.js +64 -0
- package/dist/emoji.cjs +28 -35
- package/dist/filter-model.d.ts +59 -3
- package/dist/filter-model.js +67 -2
- package/dist/hooks/useChangeHighlight.d.ts +33 -0
- package/dist/hooks/useChangeHighlight.js +44 -0
- package/dist/hooks/useDelayedPending.d.ts +22 -0
- package/dist/hooks/useDelayedPending.js +35 -0
- package/dist/hooks/useDialog.d.ts +5 -0
- package/dist/hooks/useDialog.js +3 -2
- package/dist/hooks/useOptimisticValue.d.ts +51 -0
- package/dist/hooks/useOptimisticValue.js +61 -0
- package/dist/hooks/useReducedMotion.d.ts +4 -1
- package/dist/hooks/useReducedMotion.js +7 -1
- package/dist/hooks/useResolvedFilterLabels.d.ts +15 -0
- package/dist/hooks/useResolvedFilterLabels.js +34 -0
- package/dist/hooks/useVirtualRows.d.ts +21 -2
- package/dist/hooks/useVirtualRows.js +30 -3
- package/dist/icons/Icon.d.ts +1 -1
- package/dist/index.cjs +18977 -13378
- package/dist/index.d.cts +3065 -664
- package/dist/index.d.ts +46 -16
- package/dist/index.js +149 -7
- package/dist/labels-context.d.ts +93 -3
- package/dist/motion-timing.d.ts +8 -0
- package/dist/motion-timing.js +8 -0
- package/dist/overlay-stack.d.ts +6 -0
- package/dist/overlay-stack.js +13 -0
- package/dist/qr-model.d.ts +65 -0
- package/dist/qr-model.js +323 -0
- package/dist/relationship-graph-model.d.ts +78 -3
- package/dist/relationship-graph-model.js +112 -5
- package/dist/reorder.d.ts +30 -0
- package/dist/reorder.js +74 -0
- package/dist/rich-text.cjs +4 -2
- package/dist/scheduling-resource-model.d.ts +76 -0
- package/dist/scheduling-resource-model.js +74 -0
- package/dist/search-suggest-model.js +3 -1
- package/dist/shell-context.d.ts +11 -0
- package/dist/shell-context.js +7 -0
- package/dist/time-field-model.d.ts +46 -0
- package/dist/time-field-model.js +152 -0
- package/dist/toast-store.d.ts +17 -1
- package/dist/toast-store.js +23 -7
- package/package.json +2 -1
|
@@ -5,6 +5,7 @@ import { cx } from "../cx.js";
|
|
|
5
5
|
import { useUixLabels } from "../labels-context.js";
|
|
6
6
|
import { useAnchoredPosition } from "../hooks/useAnchoredPosition.js";
|
|
7
7
|
import { searchSegments } from "../search-suggest-model.js";
|
|
8
|
+
import { useDelayedPending } from "../hooks/useDelayedPending.js";
|
|
8
9
|
import { Spinner } from "./Spinner.js";
|
|
9
10
|
const SearchIcon = () => /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
10
11
|
/* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "7" }),
|
|
@@ -23,6 +24,7 @@ function SearchSuggest({
|
|
|
23
24
|
onValueChange,
|
|
24
25
|
options,
|
|
25
26
|
onSelect,
|
|
27
|
+
freeText = false,
|
|
26
28
|
label,
|
|
27
29
|
placeholder,
|
|
28
30
|
highlight,
|
|
@@ -47,6 +49,9 @@ function SearchSuggest({
|
|
|
47
49
|
name,
|
|
48
50
|
inputId,
|
|
49
51
|
inputDescribedBy,
|
|
52
|
+
inputLabelledBy,
|
|
53
|
+
disabled = false,
|
|
54
|
+
invalid = false,
|
|
50
55
|
className,
|
|
51
56
|
onBlur,
|
|
52
57
|
...props
|
|
@@ -67,15 +72,27 @@ function SearchSuggest({
|
|
|
67
72
|
};
|
|
68
73
|
const [focused, setFocused] = useState(false);
|
|
69
74
|
const [activeState, setActive] = useState(-1);
|
|
75
|
+
const showSpinner = useDelayedPending(loading) && !disabled;
|
|
76
|
+
const [labelled, setLabelled] = useState(false);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
setLabelled((fieldRef.current?.labels?.length ?? 0) > 0);
|
|
79
|
+
});
|
|
70
80
|
const itemCount = options.length + (footer ? 1 : 0);
|
|
71
81
|
const active = activeState < itemCount ? activeState : -1;
|
|
72
82
|
const optionKey = options.map((option) => option.id).join("|");
|
|
73
83
|
useEffect(() => setActive(-1), [optionKey]);
|
|
74
84
|
const hasText = value.trim().length > 0;
|
|
75
|
-
const
|
|
76
|
-
const
|
|
85
|
+
const showLoading = showSpinner && loading && options.length === 0;
|
|
86
|
+
const current = { empty: hasText && error == null && empty != null, error: error ?? null };
|
|
87
|
+
const settled = useRef({ empty: false, error: null });
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (!loading) settled.current = current;
|
|
90
|
+
});
|
|
91
|
+
const state = options.length > 0 || showLoading ? null : loading ? settled.current : current;
|
|
92
|
+
const shownError = state?.error ?? null;
|
|
93
|
+
const showEmpty = !!state?.empty && shownError == null;
|
|
77
94
|
const showIdle = idle != null && itemCount === 0 && !loading && error == null && !showEmpty;
|
|
78
|
-
const visible = open && (itemCount > 0 || showLoading || showEmpty || showIdle ||
|
|
95
|
+
const visible = open && !disabled && (itemCount > 0 || showLoading || showEmpty || showIdle || shownError != null);
|
|
79
96
|
const optionId = (index) => `${id}-option-${index}`;
|
|
80
97
|
useEffect(() => {
|
|
81
98
|
if (!visible || active < 0) return;
|
|
@@ -84,8 +101,10 @@ function SearchSuggest({
|
|
|
84
101
|
}, [active, visible]);
|
|
85
102
|
const choose = (index) => {
|
|
86
103
|
const option = options[index];
|
|
87
|
-
if (option)
|
|
88
|
-
|
|
104
|
+
if (option) {
|
|
105
|
+
if (freeText && option.title !== value) onValueChange(option.title);
|
|
106
|
+
onSelect?.(option.id, option);
|
|
107
|
+
} else if (footer && index === options.length) footer.onSelect();
|
|
89
108
|
else return;
|
|
90
109
|
setOpen(false);
|
|
91
110
|
setActive(-1);
|
|
@@ -107,9 +126,9 @@ function SearchSuggest({
|
|
|
107
126
|
return;
|
|
108
127
|
}
|
|
109
128
|
setActive((stored) => {
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
112
|
-
return (
|
|
129
|
+
const current2 = stored < itemCount ? stored : -1;
|
|
130
|
+
if (current2 < 0) return down ? 0 : itemCount - 1;
|
|
131
|
+
return (current2 + (down ? 1 : -1) + itemCount) % itemCount;
|
|
113
132
|
});
|
|
114
133
|
return;
|
|
115
134
|
}
|
|
@@ -121,11 +140,20 @@ function SearchSuggest({
|
|
|
121
140
|
}
|
|
122
141
|
return;
|
|
123
142
|
case "Enter":
|
|
143
|
+
if (loading && !freeText) {
|
|
144
|
+
event.preventDefault();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
124
147
|
if (visible && active >= 0) {
|
|
125
148
|
event.preventDefault();
|
|
126
149
|
choose(active);
|
|
127
150
|
return;
|
|
128
151
|
}
|
|
152
|
+
if (freeText) {
|
|
153
|
+
event.preventDefault();
|
|
154
|
+
if (open) setOpen(false);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
129
157
|
if (visible && hasText && options.length) {
|
|
130
158
|
event.preventDefault();
|
|
131
159
|
choose(0);
|
|
@@ -137,7 +165,7 @@ function SearchSuggest({
|
|
|
137
165
|
event.stopPropagation();
|
|
138
166
|
setOpen(false);
|
|
139
167
|
setActive(-1);
|
|
140
|
-
} else if (value) {
|
|
168
|
+
} else if (value && !freeText) {
|
|
141
169
|
event.preventDefault();
|
|
142
170
|
event.stopPropagation();
|
|
143
171
|
onValueChange("");
|
|
@@ -179,13 +207,13 @@ function SearchSuggest({
|
|
|
179
207
|
"div",
|
|
180
208
|
{
|
|
181
209
|
ref: rootRef,
|
|
182
|
-
className: cx("uix-search-suggest", size === "lg" && "uix-search-suggest--lg", className),
|
|
210
|
+
className: cx("uix-search-suggest", size === "lg" && "uix-search-suggest--lg", freeText && "uix-search-suggest--free-text", className),
|
|
183
211
|
"data-open": visible || void 0,
|
|
184
212
|
onBlur: handleBlur,
|
|
185
213
|
...props,
|
|
186
214
|
children: [
|
|
187
215
|
/* @__PURE__ */ jsxs("div", { ref: fieldBoxRef, className: "uix-search-suggest__field", children: [
|
|
188
|
-
/* @__PURE__ */ jsx("span", { className: "uix-search-suggest__lead", "aria-hidden": "true", children: /* @__PURE__ */ jsx(SearchIcon, {}) }),
|
|
216
|
+
!freeText && /* @__PURE__ */ jsx("span", { className: "uix-search-suggest__lead", "aria-hidden": "true", children: /* @__PURE__ */ jsx(SearchIcon, {}) }),
|
|
189
217
|
/* @__PURE__ */ jsx(
|
|
190
218
|
"input",
|
|
191
219
|
{
|
|
@@ -195,7 +223,10 @@ function SearchSuggest({
|
|
|
195
223
|
className: "uix-input uix-search-suggest__input",
|
|
196
224
|
type: "text",
|
|
197
225
|
role: "combobox",
|
|
198
|
-
"aria-label": label,
|
|
226
|
+
"aria-label": inputLabelledBy || labelled ? void 0 : label,
|
|
227
|
+
"aria-labelledby": inputLabelledBy,
|
|
228
|
+
"aria-invalid": invalid || void 0,
|
|
229
|
+
disabled,
|
|
199
230
|
"aria-autocomplete": "list",
|
|
200
231
|
"aria-expanded": visible,
|
|
201
232
|
"aria-controls": listboxId,
|
|
@@ -203,7 +234,7 @@ function SearchSuggest({
|
|
|
203
234
|
"aria-busy": loading || void 0,
|
|
204
235
|
autoComplete: "off",
|
|
205
236
|
spellCheck: false,
|
|
206
|
-
enterKeyHint: "search",
|
|
237
|
+
enterKeyHint: freeText ? "done" : "search",
|
|
207
238
|
name,
|
|
208
239
|
value,
|
|
209
240
|
placeholder,
|
|
@@ -222,9 +253,9 @@ function SearchSuggest({
|
|
|
222
253
|
}
|
|
223
254
|
),
|
|
224
255
|
/* @__PURE__ */ jsxs("span", { className: "uix-search-suggest__trail", children: [
|
|
225
|
-
|
|
226
|
-
!
|
|
227
|
-
!
|
|
256
|
+
showSpinner && /* @__PURE__ */ jsx(Spinner, { className: "uix-search-suggest__spinner", label: loadingLabel }),
|
|
257
|
+
!showSpinner && value && !disabled && /* @__PURE__ */ jsx("button", { type: "button", className: "uix-search-suggest__clear", "aria-label": clearLabel, onMouseDown: keepFocus, onClick: clear, children: /* @__PURE__ */ jsx(ClearIcon, {}) }),
|
|
258
|
+
!showSpinner && !value && !focused && shortcutHint && /* @__PURE__ */ jsx("kbd", { className: "uix-kbd", "aria-hidden": "true", children: shortcutHint })
|
|
228
259
|
] })
|
|
229
260
|
] }),
|
|
230
261
|
/* @__PURE__ */ jsxs("div", { ref: popupRef, className: "uix-search-suggest__popup", "data-strategy": floating ? "fixed" : void 0, hidden: !visible, children: [
|
|
@@ -296,7 +327,7 @@ function SearchSuggest({
|
|
|
296
327
|
/* @__PURE__ */ jsx("span", { className: "uix-spinner" }),
|
|
297
328
|
loadingLabel && /* @__PURE__ */ jsx("span", { children: loadingLabel })
|
|
298
329
|
] }),
|
|
299
|
-
|
|
330
|
+
shownError != null && /* @__PURE__ */ jsx("div", { className: "uix-search-suggest__state", children: shownError }),
|
|
300
331
|
showEmpty && /* @__PURE__ */ jsx("div", { className: "uix-search-suggest__state", children: empty }),
|
|
301
332
|
showIdle && /* @__PURE__ */ jsx("div", { className: "uix-search-suggest__state", children: idle }),
|
|
302
333
|
note != null && options.length > 0 && /* @__PURE__ */ jsx("div", { className: "uix-search-suggest__note", children: note })
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { HTMLAttributes, ReactNode, ButtonHTMLAttributes } from 'react';
|
|
3
|
+
import { UixRenderLink } from '../link.js';
|
|
3
4
|
|
|
4
5
|
interface SegmentedProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
|
|
5
6
|
/** The currently-selected option value. */
|
|
@@ -12,8 +13,15 @@ interface SegmentedProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'
|
|
|
12
13
|
* toggle bar. `'radio'`: `role="radiogroup"` of `role="radio"` with `aria-checked`, for a
|
|
13
14
|
* setting with exactly one value (theme, density, language). Name the group with
|
|
14
15
|
* `aria-label` or `aria-labelledby` in either mode. The keyboard model is the same in both.
|
|
16
|
+
*
|
|
17
|
+
* `'link'` (HAR-1380): navigation, not a choice, such as a language switcher where each
|
|
18
|
+
* option is a URL. A `<nav>` (named by your `aria-label`) around a list of links, each
|
|
19
|
+
* option needs an `href`, and the one whose `value` is `value` carries `aria-current="page"`.
|
|
20
|
+
* The same pill look; every link is its own tab stop and Enter follows it, like any nav.
|
|
15
21
|
*/
|
|
16
|
-
selection?: 'toggle' | 'radio';
|
|
22
|
+
selection?: 'toggle' | 'radio' | 'link';
|
|
23
|
+
/** `selection="link"`: renders each option's link with your router. Default: `<a>`. */
|
|
24
|
+
renderLink?: UixRenderLink;
|
|
17
25
|
children?: ReactNode;
|
|
18
26
|
}
|
|
19
27
|
/**
|
|
@@ -27,9 +35,13 @@ interface SegmentedProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'
|
|
|
27
35
|
* enabled option and select it, wrapping at the ends; Home and End jump; Left/Right swap in
|
|
28
36
|
* a right-to-left group. Before 2.32.0 every option was its own tab stop.
|
|
29
37
|
*/
|
|
30
|
-
declare function Segmented({ value, onChange, selection, children, className, onKeyDown, ...props }: SegmentedProps): react.JSX.Element;
|
|
38
|
+
declare function Segmented({ value, onChange, selection, renderLink, children, className, onKeyDown, ...props }: SegmentedProps): react.JSX.Element;
|
|
31
39
|
interface SegmentedOptionProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'onChange'> {
|
|
32
40
|
value: string;
|
|
41
|
+
/** In a `selection="link"` group: where the option goes. Required there, ignored otherwise. */
|
|
42
|
+
href?: string;
|
|
43
|
+
/** In a `selection="link"` group: the target's language, e.g. `de` on a locale switcher. */
|
|
44
|
+
hrefLang?: string;
|
|
33
45
|
children?: ReactNode;
|
|
34
46
|
}
|
|
35
47
|
/**
|
|
@@ -38,6 +50,29 @@ interface SegmentedOptionProps extends Omit<ButtonHTMLAttributes<HTMLButtonEleme
|
|
|
38
50
|
* `.uix-segmented__option[aria-pressed="true"]` (or `[aria-checked="true"]` in a
|
|
39
51
|
* `selection="radio"` group).
|
|
40
52
|
*/
|
|
41
|
-
declare function SegmentedOption({ value, children, className, onClick, ...props }: SegmentedOptionProps): react.JSX.Element;
|
|
53
|
+
declare function SegmentedOption({ value, href, hrefLang, children, className, onClick, ...props }: SegmentedOptionProps): react.JSX.Element;
|
|
54
|
+
interface LocaleSwitcherLocale {
|
|
55
|
+
/** BCP 47 code: `de`, `bs`, `en-GB`. Sets the link's `lang` and `hreflang`. */
|
|
56
|
+
code: string;
|
|
57
|
+
/** What the option shows: "Deutsch", or a short "DE". */
|
|
58
|
+
label: ReactNode;
|
|
59
|
+
/** This page in that language. */
|
|
60
|
+
href: string;
|
|
61
|
+
}
|
|
62
|
+
interface LocaleSwitcherProps extends Omit<HTMLAttributes<HTMLElement>, 'children' | 'onChange'> {
|
|
63
|
+
/** One link per language, in the order shown. */
|
|
64
|
+
locales: readonly LocaleSwitcherLocale[];
|
|
65
|
+
/** The code of the page's language; that link is `aria-current="page"`. */
|
|
66
|
+
current: string;
|
|
67
|
+
/** Names the navigation, in the page's language: "Language", "Sprache". */
|
|
68
|
+
label: string;
|
|
69
|
+
/** Renders each link with your router (locale-aware links keep client navigation). */
|
|
70
|
+
renderLink?: UixRenderLink;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A language switcher (HAR-1380; MOTUS C-12): a `Segmented selection="link"` whose links carry
|
|
74
|
+
* `lang` and `hreflang`, so each language's name is read in that language.
|
|
75
|
+
*/
|
|
76
|
+
declare function LocaleSwitcher({ locales, current, label, renderLink, ...props }: LocaleSwitcherProps): react.JSX.Element;
|
|
42
77
|
|
|
43
|
-
export { Segmented, SegmentedOption, type SegmentedOptionProps, type SegmentedProps };
|
|
78
|
+
export { LocaleSwitcher, type LocaleSwitcherLocale, type LocaleSwitcherProps, Segmented, SegmentedOption, type SegmentedOptionProps, type SegmentedProps };
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useContext, useEffect, useMemo, useRef } from "react";
|
|
4
4
|
import { cx } from "../cx.js";
|
|
5
|
+
import { renderUixLink } from "../link.js";
|
|
5
6
|
const SegmentedCtx = createContext({});
|
|
6
7
|
const OPTION = ".uix-segmented__option";
|
|
7
|
-
function Segmented({ value, onChange, selection = "toggle", children, className, onKeyDown, ...props }) {
|
|
8
|
+
function Segmented({ value, onChange, selection = "toggle", renderLink, children, className, onKeyDown, ...props }) {
|
|
8
9
|
const ref = useRef(null);
|
|
9
|
-
const contextValue = useMemo(() => ({ value, onChange, selection }), [value, onChange, selection]);
|
|
10
|
+
const contextValue = useMemo(() => ({ value, onChange, selection, renderLink }), [value, onChange, selection, renderLink]);
|
|
10
11
|
useEffect(() => {
|
|
11
12
|
const group = ref.current;
|
|
12
|
-
if (!group) return;
|
|
13
|
+
if (!group || selection === "link") return;
|
|
13
14
|
const all = Array.from(group.querySelectorAll(OPTION));
|
|
14
15
|
const enabled = all.filter((o) => !o.disabled);
|
|
15
16
|
const current = enabled.find((o) => o.getAttribute("aria-pressed") === "true" || o.getAttribute("aria-checked") === "true") ?? enabled[0];
|
|
@@ -55,10 +56,15 @@ function Segmented({ value, onChange, selection = "toggle", children, className,
|
|
|
55
56
|
target.focus();
|
|
56
57
|
target.click();
|
|
57
58
|
};
|
|
59
|
+
if (selection === "link") {
|
|
60
|
+
return /* @__PURE__ */ jsx(SegmentedCtx.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("nav", { className: cx("uix-segmented-nav", className), onKeyDown, ...props, children: /* @__PURE__ */ jsx("ul", { className: "uix-segmented", role: "list", children }) }) });
|
|
61
|
+
}
|
|
58
62
|
return /* @__PURE__ */ jsx(SegmentedCtx.Provider, { value: contextValue, children: /* @__PURE__ */ jsx("div", { ref, role: selection === "radio" ? "radiogroup" : "group", className: cx("uix-segmented", className), onKeyDown: handleKeyDown, ...props, children }) });
|
|
59
63
|
}
|
|
60
64
|
function SegmentedOption({
|
|
61
65
|
value,
|
|
66
|
+
href,
|
|
67
|
+
hrefLang,
|
|
62
68
|
children,
|
|
63
69
|
className,
|
|
64
70
|
onClick,
|
|
@@ -67,6 +73,24 @@ function SegmentedOption({
|
|
|
67
73
|
const ctx = useContext(SegmentedCtx);
|
|
68
74
|
const selected = ctx.value === value;
|
|
69
75
|
const radio = ctx.selection === "radio";
|
|
76
|
+
if (ctx.selection === "link") {
|
|
77
|
+
const { type: _type, disabled, form: _form, formAction: _formAction, name: _name, ...linkProps } = props;
|
|
78
|
+
if (disabled || !href) {
|
|
79
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("a", { ...linkProps, hrefLang, className: cx("uix-segmented__option", className), "aria-disabled": "true", "aria-current": selected ? "page" : void 0, children }) });
|
|
80
|
+
}
|
|
81
|
+
return /* @__PURE__ */ jsx("li", { children: renderUixLink(ctx.renderLink, {
|
|
82
|
+
...linkProps,
|
|
83
|
+
href,
|
|
84
|
+
hrefLang,
|
|
85
|
+
className: cx("uix-segmented__option", className),
|
|
86
|
+
"aria-current": selected ? "page" : void 0,
|
|
87
|
+
onClick: (event) => {
|
|
88
|
+
ctx.onChange?.(value);
|
|
89
|
+
onClick?.(event);
|
|
90
|
+
},
|
|
91
|
+
children
|
|
92
|
+
}) });
|
|
93
|
+
}
|
|
70
94
|
return /* @__PURE__ */ jsx(
|
|
71
95
|
"button",
|
|
72
96
|
{
|
|
@@ -85,7 +109,11 @@ function SegmentedOption({
|
|
|
85
109
|
}
|
|
86
110
|
);
|
|
87
111
|
}
|
|
112
|
+
function LocaleSwitcher({ locales, current, label, renderLink, ...props }) {
|
|
113
|
+
return /* @__PURE__ */ jsx(Segmented, { selection: "link", value: current, "aria-label": label, renderLink, ...props, children: locales.map((locale) => /* @__PURE__ */ jsx(SegmentedOption, { value: locale.code, href: locale.href, hrefLang: locale.code, lang: locale.code, children: locale.label }, locale.code)) });
|
|
114
|
+
}
|
|
88
115
|
export {
|
|
116
|
+
LocaleSwitcher,
|
|
89
117
|
Segmented,
|
|
90
118
|
SegmentedOption
|
|
91
119
|
};
|
|
@@ -27,7 +27,8 @@ interface SelectLabels {
|
|
|
27
27
|
results: string;
|
|
28
28
|
}
|
|
29
29
|
interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, 'size'> {
|
|
30
|
-
|
|
30
|
+
/** `sm` 28 px, `md` 36 px (default), `lg` 44 px, the public touch-target size (HAR-1812). */
|
|
31
|
+
size?: 'sm' | 'md' | 'lg';
|
|
31
32
|
/** The options as data, instead of `<option>` / `<optgroup>` children. */
|
|
32
33
|
options?: readonly (SelectOption | SelectGroup)[];
|
|
33
34
|
/**
|
|
@@ -64,7 +65,7 @@ interface SelectProps extends Omit<SelectHTMLAttributes<HTMLSelectElement>, 'siz
|
|
|
64
65
|
* A select that draws its own list (HAR-1572): the WAI-ARIA APG select-only combobox — focus
|
|
65
66
|
* stays on the trigger, `aria-activedescendant` marks the active option — in a top-layer popover
|
|
66
67
|
* placed with `useAnchoredPosition`, or a bottom sheet on a phone. A visually hidden native
|
|
67
|
-
*
|
|
68
|
+
* select element (the form proxy) carries `name`, `required`, `form`, `multiple` and the value, so `<option>` children,
|
|
68
69
|
* `onChange(e)` with `e.target.value`, FormData, `form.reset()`, `ref` and react-hook-form keep
|
|
69
70
|
* working; `ref` points at that select.
|
|
70
71
|
*/
|
|
@@ -706,7 +706,7 @@ const Select = forwardRef(function Select2(props, forwardedRef) {
|
|
|
706
706
|
ref: triggerRef,
|
|
707
707
|
type: "button",
|
|
708
708
|
role: "combobox",
|
|
709
|
-
className: cx("uix-select", size
|
|
709
|
+
className: cx("uix-select", size !== "md" && `uix-select--${size}`, className),
|
|
710
710
|
style,
|
|
711
711
|
disabled,
|
|
712
712
|
"aria-label": ariaLabel,
|
|
@@ -5,17 +5,18 @@ interface ShortcutHintProps {
|
|
|
5
5
|
keys: KeyShortcut;
|
|
6
6
|
/** Text before the keys, e.g. an icon button's name. */
|
|
7
7
|
label?: string;
|
|
8
|
-
/**
|
|
9
|
-
|
|
8
|
+
/** The control's own `aria-describedby`: the spoken keys are added after it, never instead. */
|
|
9
|
+
describedBy?: string;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
12
|
-
* The hover / keyboard-focus hint of a `Button` with `shortcut` (HAR-2031
|
|
13
|
-
* leaves only an empty, hidden marker, so the
|
|
14
|
-
* unchanged (no wrapper, no sibling). The bubble itself is portalled
|
|
15
|
-
* nearest `<dialog>` (outside one a modal dialog makes everything inert) or
|
|
16
|
-
* top-layer popover, `aria-hidden
|
|
17
|
-
*
|
|
18
|
-
*
|
|
12
|
+
* The hover / keyboard-focus hint of a `Button` or `ButtonLink` with `shortcut` (HAR-2031,
|
|
13
|
+
* HAR-2416). In the control it leaves only an empty, hidden marker, so the control's text, name,
|
|
14
|
+
* layout and selectors are unchanged (no wrapper, no sibling). The bubble itself is portalled
|
|
15
|
+
* after mount into the nearest `<dialog>` (outside one a modal dialog makes everything inert) or
|
|
16
|
+
* `<body>`, as a top-layer popover, `aria-hidden`. Screen readers hear the keys once, as the
|
|
17
|
+
* control's description ("Control+K"; ⌘ is "Command" on Apple), the same way a `Tooltip` with a
|
|
18
|
+
* shortcut says them: the description is the one channel every screen reader announces, and an
|
|
19
|
+
* `aria-keyshortcuts` beside it was read a second time by those that announce that too.
|
|
19
20
|
*
|
|
20
21
|
* It opens on hover and on keyboard focus (`:focus-visible`), so focus a menu or dialog sends back
|
|
21
22
|
* after a mouse choice does not open it. It closes on leave, blur, Escape and when the button is
|
|
@@ -24,6 +25,6 @@ interface ShortcutHintProps {
|
|
|
24
25
|
*
|
|
25
26
|
* It is its own client component so that `Button`, which has no hooks, still renders on a server.
|
|
26
27
|
*/
|
|
27
|
-
declare function ShortcutHint({ keys, label,
|
|
28
|
+
declare function ShortcutHint({ keys, label, describedBy }: ShortcutHintProps): react.JSX.Element;
|
|
28
29
|
|
|
29
30
|
export { ShortcutHint, type ShortcutHintProps };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
4
4
|
import { createPortal } from "react-dom";
|
|
5
5
|
import { useAnchoredPosition } from "../hooks/useAnchoredPosition.js";
|
|
6
|
-
import { KbdCombo,
|
|
6
|
+
import { KbdCombo, spokenKeys, useKbdPlatform } from "./Kbd.js";
|
|
7
7
|
const useIsomorphicLayoutEffect = typeof document !== "undefined" ? useLayoutEffect : useEffect;
|
|
8
8
|
const isShown = (el) => {
|
|
9
9
|
try {
|
|
@@ -20,26 +20,15 @@ const focusVisible = (el) => {
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
const stop = (event) => event.stopPropagation();
|
|
23
|
-
function ShortcutHint({ keys, label,
|
|
23
|
+
function ShortcutHint({ keys, label, describedBy }) {
|
|
24
24
|
const markerRef = useRef(null);
|
|
25
25
|
const bubbleRef = useRef(null);
|
|
26
26
|
const anchorRef = useRef(null);
|
|
27
27
|
const [host, setHost] = useState(null);
|
|
28
28
|
const [open, setOpen] = useState(false);
|
|
29
29
|
const platform = useKbdPlatform();
|
|
30
|
-
const
|
|
30
|
+
const spokenId = `${useId()}-keys`;
|
|
31
31
|
useAnchoredPosition(anchorRef, bubbleRef, { open, placement: "top", offset: 6 });
|
|
32
|
-
useIsomorphicLayoutEffect(() => {
|
|
33
|
-
const button = markerRef.current?.parentElement;
|
|
34
|
-
if (!button || !ownsAria) return void 0;
|
|
35
|
-
const before = button.getAttribute("aria-keyshortcuts");
|
|
36
|
-
button.setAttribute("aria-keyshortcuts", shortcuts);
|
|
37
|
-
return () => {
|
|
38
|
-
if (button.getAttribute("aria-keyshortcuts") !== shortcuts) return;
|
|
39
|
-
if (before == null) button.removeAttribute("aria-keyshortcuts");
|
|
40
|
-
else button.setAttribute("aria-keyshortcuts", before);
|
|
41
|
-
};
|
|
42
|
-
}, [shortcuts, ownsAria]);
|
|
43
32
|
useIsomorphicLayoutEffect(() => {
|
|
44
33
|
const button = markerRef.current?.parentElement ?? null;
|
|
45
34
|
anchorRef.current = button;
|
|
@@ -49,6 +38,17 @@ function ShortcutHint({ keys, label, ownsAria }) {
|
|
|
49
38
|
}
|
|
50
39
|
setHost(button.closest("dialog") ?? button.ownerDocument.body);
|
|
51
40
|
}, []);
|
|
41
|
+
useIsomorphicLayoutEffect(() => {
|
|
42
|
+
const control = anchorRef.current;
|
|
43
|
+
if (!host || !control) return void 0;
|
|
44
|
+
const value = [describedBy, spokenId].filter(Boolean).join(" ");
|
|
45
|
+
control.setAttribute("aria-describedby", value);
|
|
46
|
+
return () => {
|
|
47
|
+
if (control.getAttribute("aria-describedby") !== value) return;
|
|
48
|
+
if (describedBy) control.setAttribute("aria-describedby", describedBy);
|
|
49
|
+
else control.removeAttribute("aria-describedby");
|
|
50
|
+
};
|
|
51
|
+
}, [host, describedBy, spokenId]);
|
|
52
52
|
useEffect(() => {
|
|
53
53
|
const button = anchorRef.current;
|
|
54
54
|
const bubble = bubbleRef.current;
|
|
@@ -85,7 +85,10 @@ function ShortcutHint({ keys, label, ownsAria }) {
|
|
|
85
85
|
if (focusVisible(button)) show();
|
|
86
86
|
};
|
|
87
87
|
const onKey = (event) => {
|
|
88
|
-
if (event.key
|
|
88
|
+
if (event.key !== "Escape" || !isShown(bubble)) return;
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
event.stopPropagation();
|
|
91
|
+
hide();
|
|
89
92
|
};
|
|
90
93
|
const watch = new MutationObserver(() => {
|
|
91
94
|
if (button.hasAttribute("disabled") || button.getAttribute("aria-disabled") === "true") hide();
|
|
@@ -97,7 +100,7 @@ function ShortcutHint({ keys, label, ownsAria }) {
|
|
|
97
100
|
button.addEventListener("blur", hide);
|
|
98
101
|
bubble.addEventListener("mouseenter", show);
|
|
99
102
|
bubble.addEventListener("mouseleave", hideSoon);
|
|
100
|
-
button.ownerDocument.addEventListener("keydown", onKey);
|
|
103
|
+
button.ownerDocument.addEventListener("keydown", onKey, true);
|
|
101
104
|
return () => {
|
|
102
105
|
window.clearTimeout(timer);
|
|
103
106
|
watch.disconnect();
|
|
@@ -107,7 +110,7 @@ function ShortcutHint({ keys, label, ownsAria }) {
|
|
|
107
110
|
button.removeEventListener("blur", hide);
|
|
108
111
|
bubble.removeEventListener("mouseenter", show);
|
|
109
112
|
bubble.removeEventListener("mouseleave", hideSoon);
|
|
110
|
-
button.ownerDocument.removeEventListener("keydown", onKey);
|
|
113
|
+
button.ownerDocument.removeEventListener("keydown", onKey, true);
|
|
111
114
|
if (isShown(bubble)) {
|
|
112
115
|
try {
|
|
113
116
|
bubble.hidePopover();
|
|
@@ -120,26 +123,29 @@ function ShortcutHint({ keys, label, ownsAria }) {
|
|
|
120
123
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
121
124
|
/* @__PURE__ */ jsx("span", { ref: markerRef, hidden: true, "data-uix-shortcut-hint": "" }),
|
|
122
125
|
host && createPortal(
|
|
123
|
-
/* @__PURE__ */ jsxs(
|
|
124
|
-
"span",
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
126
|
+
/* @__PURE__ */ jsxs(Fragment, { children: [
|
|
127
|
+
/* @__PURE__ */ jsx("span", { id: spokenId, hidden: true, children: spokenKeys(keys, platform) }),
|
|
128
|
+
/* @__PURE__ */ jsxs(
|
|
129
|
+
"span",
|
|
130
|
+
{
|
|
131
|
+
ref: bubbleRef,
|
|
132
|
+
className: "uix-tooltip__bubble uix-tooltip__bubble--hint",
|
|
133
|
+
"aria-hidden": "true",
|
|
134
|
+
...bubbleAttr,
|
|
135
|
+
onClick: stop,
|
|
136
|
+
onDoubleClick: stop,
|
|
137
|
+
onContextMenu: stop,
|
|
138
|
+
onPointerDown: stop,
|
|
139
|
+
onPointerUp: stop,
|
|
140
|
+
onMouseDown: stop,
|
|
141
|
+
onMouseUp: stop,
|
|
142
|
+
children: [
|
|
143
|
+
label && /* @__PURE__ */ jsx("span", { children: label }),
|
|
144
|
+
/* @__PURE__ */ jsx("span", { className: "uix-tooltip__shortcut", children: /* @__PURE__ */ jsx(KbdCombo, { keys: [...keys], platform }) })
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
] }),
|
|
143
149
|
host
|
|
144
150
|
)
|
|
145
151
|
] });
|
|
@@ -1,17 +1,42 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, AnchorHTMLAttributes, HTMLAttributes } from 'react';
|
|
3
|
+
import { KeyShortcut } from './Kbd.js';
|
|
3
4
|
|
|
5
|
+
/** The search row under the sidebar head (HAR-1371): it opens your search or command palette. */
|
|
6
|
+
interface SidebarSearch {
|
|
7
|
+
/** The row's words, e.g. "Search". In the rail they are the button's name only. */
|
|
8
|
+
label: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* The keys that open the same search, shown at the end of the row and given to assistive
|
|
11
|
+
* technology as `aria-keyshortcuts`, e.g. `['Mod', 'K']`. Showing them does not bind them:
|
|
12
|
+
* your command palette (or app) listens for the keys.
|
|
13
|
+
*/
|
|
14
|
+
shortcut?: KeyShortcut;
|
|
15
|
+
onActivate: () => void;
|
|
16
|
+
}
|
|
4
17
|
interface SidebarProps extends HTMLAttributes<HTMLElement> {
|
|
5
18
|
collapsed?: boolean;
|
|
6
19
|
nav?: 'full' | 'rail';
|
|
7
20
|
onToggle?: () => void;
|
|
8
21
|
brand?: ReactNode;
|
|
9
22
|
toggleIcon?: ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Controls in the head beside the brand (HAR-1371): a mode toggle, a "…" utility `Menu`,
|
|
25
|
+
* collapse-all. Icon buttons (`Button icon size="sm"`) fit the row. Hidden in the rail.
|
|
26
|
+
*/
|
|
27
|
+
actions?: ReactNode;
|
|
28
|
+
/** A search row under the head that opens your search (HAR-1371). */
|
|
29
|
+
search?: SidebarSearch;
|
|
30
|
+
/**
|
|
31
|
+
* A slot pinned to the bottom of the sidebar (HAR-1371), for an `AccountMenu`. In the rail it
|
|
32
|
+
* keeps what it renders; give an `AccountMenu` `collapsed` there.
|
|
33
|
+
*/
|
|
34
|
+
footer?: ReactNode;
|
|
10
35
|
children?: ReactNode;
|
|
11
36
|
expandLabel?: string;
|
|
12
37
|
collapseLabel?: string;
|
|
13
38
|
}
|
|
14
|
-
declare function Sidebar({ collapsed, nav, onToggle, brand, toggleIcon, children, expandLabel: expandLabelProp, collapseLabel: collapseLabelProp, className, ...props }: SidebarProps): react.JSX.Element;
|
|
39
|
+
declare function Sidebar({ collapsed, nav, onToggle, brand, toggleIcon, actions, search, footer, children, expandLabel: expandLabelProp, collapseLabel: collapseLabelProp, className, ...props }: SidebarProps): react.JSX.Element;
|
|
15
40
|
interface SidebarSectionProps {
|
|
16
41
|
label?: string;
|
|
17
42
|
children?: ReactNode;
|
|
@@ -29,7 +54,13 @@ interface NavItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
|
29
54
|
description?: ReactNode;
|
|
30
55
|
children?: ReactNode;
|
|
31
56
|
}
|
|
32
|
-
|
|
57
|
+
/**
|
|
58
|
+
* One navigation row: a link (`as="a"`, default) or, for a row that acts in place (a mode toggle,
|
|
59
|
+
* an account menu), a `button`. The forwarded ref reaches the rendered `<a>` or `<button>`
|
|
60
|
+
* (HAR-1810), so a row can anchor a `Popover` (`anchor={ref}`); `popoverTarget` and other button
|
|
61
|
+
* attributes pass through with `as="button"`.
|
|
62
|
+
*/
|
|
63
|
+
declare const NavItem: react.ForwardRefExoticComponent<NavItemProps & react.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
|
|
33
64
|
interface NavGroupProps {
|
|
34
65
|
icon?: ReactNode;
|
|
35
66
|
label: ReactNode;
|
|
@@ -44,6 +75,7 @@ interface SubNavItemProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
|
44
75
|
as?: 'a' | 'button';
|
|
45
76
|
children?: ReactNode;
|
|
46
77
|
}
|
|
47
|
-
|
|
78
|
+
/** A nested navigation row. Like `NavItem`, it forwards its ref to the `<a>` or `<button>` (HAR-1810). */
|
|
79
|
+
declare const SubNavItem: react.ForwardRefExoticComponent<SubNavItemProps & react.RefAttributes<HTMLButtonElement | HTMLAnchorElement>>;
|
|
48
80
|
|
|
49
|
-
export { NavGroup, type NavGroupProps, NavItem, type NavItemProps, Sidebar, type SidebarProps, SidebarSection, type SidebarSectionProps, SubNavItem, type SubNavItemProps };
|
|
81
|
+
export { NavGroup, type NavGroupProps, NavItem, type NavItemProps, Sidebar, type SidebarProps, type SidebarSearch, SidebarSection, type SidebarSectionProps, SubNavItem, type SubNavItemProps };
|