@arun-dev/headless 4.6.0 → 4.7.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/chunk-2S4XG4VD.js +33 -0
- package/dist/menu/index.cjs +438 -0
- package/dist/menu/index.d.cts +115 -0
- package/dist/menu/index.d.ts +115 -0
- package/dist/menu/index.js +255 -0
- package/dist/tabs/index.cjs +62 -43
- package/dist/tabs/index.d.cts +15 -4
- package/dist/tabs/index.d.ts +15 -4
- package/dist/tabs/index.js +37 -43
- package/package.json +11 -1
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import {
|
|
2
|
+
byDocumentOrder,
|
|
3
|
+
rovingIndex
|
|
4
|
+
} from "../chunk-2S4XG4VD.js";
|
|
5
|
+
import {
|
|
6
|
+
anchorNameFor,
|
|
7
|
+
anchoredDataAttributes,
|
|
8
|
+
anchoredPopupStyle
|
|
9
|
+
} from "../chunk-HCOCPQXS.js";
|
|
10
|
+
import {
|
|
11
|
+
useControlled
|
|
12
|
+
} from "../chunk-UEIB3I3T.js";
|
|
13
|
+
import {
|
|
14
|
+
__export,
|
|
15
|
+
useRender
|
|
16
|
+
} from "../chunk-OQTWWZ4B.js";
|
|
17
|
+
|
|
18
|
+
// src/menu/index.parts.ts
|
|
19
|
+
var index_parts_exports = {};
|
|
20
|
+
__export(index_parts_exports, {
|
|
21
|
+
Item: () => MenuItem,
|
|
22
|
+
Popup: () => MenuPopup,
|
|
23
|
+
Root: () => MenuRoot,
|
|
24
|
+
Trigger: () => MenuTrigger
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// src/menu/MenuRoot.tsx
|
|
28
|
+
import { useCallback, useId, useMemo, useRef, useState } from "react";
|
|
29
|
+
|
|
30
|
+
// src/menu/MenuRootContext.ts
|
|
31
|
+
import { createContext, useContext } from "react";
|
|
32
|
+
var MenuRootContext = createContext(null);
|
|
33
|
+
function useMenuRootContext(part) {
|
|
34
|
+
const context = useContext(MenuRootContext);
|
|
35
|
+
if (context === null) {
|
|
36
|
+
throw new Error(`<Menu.${part}> must be rendered inside <Menu.Root>.`);
|
|
37
|
+
}
|
|
38
|
+
return context;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/menu/MenuRoot.tsx
|
|
42
|
+
import { jsx } from "react/jsx-runtime";
|
|
43
|
+
function MenuRoot({
|
|
44
|
+
open: openProp,
|
|
45
|
+
defaultOpen,
|
|
46
|
+
onOpenChange,
|
|
47
|
+
focusableWhenDisabled = false,
|
|
48
|
+
children
|
|
49
|
+
}) {
|
|
50
|
+
const [open, setOpenState] = useControlled({
|
|
51
|
+
controlled: openProp,
|
|
52
|
+
default: defaultOpen ?? false,
|
|
53
|
+
name: "Menu.Root",
|
|
54
|
+
state: "open"
|
|
55
|
+
});
|
|
56
|
+
const setOpen = useCallback(
|
|
57
|
+
(next) => {
|
|
58
|
+
if (next === open) return;
|
|
59
|
+
setOpenState(next);
|
|
60
|
+
onOpenChange?.(next);
|
|
61
|
+
},
|
|
62
|
+
[open, setOpenState, onOpenChange]
|
|
63
|
+
);
|
|
64
|
+
const [items, setItems] = useState([]);
|
|
65
|
+
const register = useCallback((entry) => {
|
|
66
|
+
setItems((current) => [...current, entry].sort(byDocumentOrder));
|
|
67
|
+
return () => setItems((current) => current.filter((i) => i !== entry));
|
|
68
|
+
}, []);
|
|
69
|
+
const navigableItems = useMemo(
|
|
70
|
+
() => focusableWhenDisabled ? items : items.filter((i) => !i.disabled),
|
|
71
|
+
[items, focusableWhenDisabled]
|
|
72
|
+
);
|
|
73
|
+
const id = useId();
|
|
74
|
+
const triggerRef = useRef(null);
|
|
75
|
+
const focusOnOpenRef = useRef("first");
|
|
76
|
+
const context = useMemo(
|
|
77
|
+
() => ({
|
|
78
|
+
open,
|
|
79
|
+
setOpen,
|
|
80
|
+
navigableItems,
|
|
81
|
+
focusableWhenDisabled,
|
|
82
|
+
register,
|
|
83
|
+
focusOnOpenRef,
|
|
84
|
+
triggerId: `${id}-trigger`,
|
|
85
|
+
popupId: `${id}-popup`,
|
|
86
|
+
anchorName: anchorNameFor(id),
|
|
87
|
+
triggerRef
|
|
88
|
+
}),
|
|
89
|
+
[open, setOpen, navigableItems, focusableWhenDisabled, register, id]
|
|
90
|
+
);
|
|
91
|
+
return /* @__PURE__ */ jsx(MenuRootContext.Provider, { value: context, children });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/menu/menuDataAttributes.ts
|
|
95
|
+
function menuDataAttributes({ open }) {
|
|
96
|
+
return {
|
|
97
|
+
"data-open": open ? "" : void 0,
|
|
98
|
+
"data-closed": open ? void 0 : ""
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
function menuItemDataAttributes(disabled) {
|
|
102
|
+
return { "data-disabled": disabled ? "" : void 0 };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// src/menu/MenuTrigger.tsx
|
|
106
|
+
function MenuTrigger({ className, children, render, ...rest }) {
|
|
107
|
+
const { open, setOpen, focusOnOpenRef, triggerId, popupId, anchorName, triggerRef } = useMenuRootContext("Trigger");
|
|
108
|
+
return useRender({
|
|
109
|
+
render,
|
|
110
|
+
defaultTagName: "button",
|
|
111
|
+
props: {
|
|
112
|
+
type: "button",
|
|
113
|
+
id: triggerId,
|
|
114
|
+
"aria-haspopup": "menu",
|
|
115
|
+
"aria-expanded": open,
|
|
116
|
+
"aria-controls": popupId,
|
|
117
|
+
...menuDataAttributes({ open }),
|
|
118
|
+
style: { anchorName },
|
|
119
|
+
className,
|
|
120
|
+
children,
|
|
121
|
+
ref: triggerRef,
|
|
122
|
+
onClick() {
|
|
123
|
+
focusOnOpenRef.current = "first";
|
|
124
|
+
setOpen(!open);
|
|
125
|
+
},
|
|
126
|
+
onKeyDown(event) {
|
|
127
|
+
if (event.key !== "ArrowDown" && event.key !== "ArrowUp") return;
|
|
128
|
+
event.preventDefault();
|
|
129
|
+
focusOnOpenRef.current = event.key === "ArrowUp" ? "last" : "first";
|
|
130
|
+
setOpen(true);
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
consumerProps: rest
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/menu/MenuPopup.tsx
|
|
138
|
+
import { useEffect, useReducer, useRef as useRef2 } from "react";
|
|
139
|
+
function MenuPopup({
|
|
140
|
+
side = "bottom",
|
|
141
|
+
align = "start",
|
|
142
|
+
className,
|
|
143
|
+
children,
|
|
144
|
+
render,
|
|
145
|
+
...rest
|
|
146
|
+
}) {
|
|
147
|
+
const {
|
|
148
|
+
open,
|
|
149
|
+
setOpen,
|
|
150
|
+
navigableItems,
|
|
151
|
+
focusOnOpenRef,
|
|
152
|
+
triggerId,
|
|
153
|
+
popupId,
|
|
154
|
+
anchorName,
|
|
155
|
+
triggerRef
|
|
156
|
+
} = useMenuRootContext("Popup");
|
|
157
|
+
const elementRef = useRef2(null);
|
|
158
|
+
const focusPendingRef = useRef2(false);
|
|
159
|
+
const [, resync] = useReducer((n) => n + 1, 0);
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
const popup = elementRef.current;
|
|
162
|
+
if (!popup || typeof popup.showPopover !== "function") return;
|
|
163
|
+
const shown = popup.matches(":popover-open");
|
|
164
|
+
if (open && !shown) {
|
|
165
|
+
popup.showPopover({ source: triggerRef.current ?? void 0 });
|
|
166
|
+
if (!popup.matches(":popover-open")) setOpen(false);
|
|
167
|
+
else focusPendingRef.current = true;
|
|
168
|
+
} else if (!open && shown) {
|
|
169
|
+
focusPendingRef.current = false;
|
|
170
|
+
popup.hidePopover();
|
|
171
|
+
}
|
|
172
|
+
if (focusPendingRef.current && navigableItems.length > 0) {
|
|
173
|
+
focusPendingRef.current = false;
|
|
174
|
+
const target = focusOnOpenRef.current === "last" ? navigableItems.at(-1) : navigableItems[0];
|
|
175
|
+
target?.ref.current?.focus();
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
return useRender({
|
|
179
|
+
render,
|
|
180
|
+
defaultTagName: "div",
|
|
181
|
+
props: {
|
|
182
|
+
id: popupId,
|
|
183
|
+
popover: "auto",
|
|
184
|
+
role: "menu",
|
|
185
|
+
"aria-labelledby": triggerId,
|
|
186
|
+
...anchoredDataAttributes(side, align),
|
|
187
|
+
...menuDataAttributes({ open }),
|
|
188
|
+
style: anchoredPopupStyle(anchorName, side, align),
|
|
189
|
+
className,
|
|
190
|
+
children,
|
|
191
|
+
ref: elementRef,
|
|
192
|
+
onKeyDown(event) {
|
|
193
|
+
if (event.key === "Tab") {
|
|
194
|
+
setOpen(false);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
const current = navigableItems.findIndex((i) => i.ref.current === event.target);
|
|
198
|
+
if (current < 0 && event.target !== event.currentTarget) return;
|
|
199
|
+
const next = rovingIndex(event.key, {
|
|
200
|
+
count: navigableItems.length,
|
|
201
|
+
current,
|
|
202
|
+
orientation: "vertical",
|
|
203
|
+
rtl: false
|
|
204
|
+
});
|
|
205
|
+
if (next === null) return;
|
|
206
|
+
event.preventDefault();
|
|
207
|
+
navigableItems[next]?.ref.current?.focus();
|
|
208
|
+
},
|
|
209
|
+
onToggle(event) {
|
|
210
|
+
if (event.target !== event.currentTarget) return;
|
|
211
|
+
if (event.nativeEvent.newState !== "closed") return;
|
|
212
|
+
setOpen(false);
|
|
213
|
+
resync();
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
consumerProps: rest
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// src/menu/MenuItem.tsx
|
|
221
|
+
import { useLayoutEffect, useRef as useRef3 } from "react";
|
|
222
|
+
function MenuItem({
|
|
223
|
+
disabled = false,
|
|
224
|
+
onClick,
|
|
225
|
+
className,
|
|
226
|
+
children,
|
|
227
|
+
render,
|
|
228
|
+
...rest
|
|
229
|
+
}) {
|
|
230
|
+
const { setOpen, focusableWhenDisabled, register } = useMenuRootContext("Item");
|
|
231
|
+
const elementRef = useRef3(null);
|
|
232
|
+
useLayoutEffect(() => register({ disabled, ref: elementRef }), [register, disabled]);
|
|
233
|
+
return useRender({
|
|
234
|
+
render,
|
|
235
|
+
defaultTagName: "button",
|
|
236
|
+
props: {
|
|
237
|
+
type: "button",
|
|
238
|
+
role: "menuitem",
|
|
239
|
+
tabIndex: -1,
|
|
240
|
+
disabled: disabled && !focusableWhenDisabled || void 0,
|
|
241
|
+
"aria-disabled": disabled && focusableWhenDisabled || void 0,
|
|
242
|
+
...menuItemDataAttributes(disabled),
|
|
243
|
+
className,
|
|
244
|
+
children,
|
|
245
|
+
ref: elementRef,
|
|
246
|
+
onClick() {
|
|
247
|
+
if (!disabled) setOpen(false);
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
consumerProps: disabled ? rest : { ...rest, onClick }
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
export {
|
|
254
|
+
index_parts_exports as Menu
|
|
255
|
+
};
|
package/dist/tabs/index.cjs
CHANGED
|
@@ -36,6 +36,35 @@ __export(index_parts_exports, {
|
|
|
36
36
|
// src/tabs/TabsRoot.tsx
|
|
37
37
|
var import_react4 = require("react");
|
|
38
38
|
|
|
39
|
+
// src/core/rovingFocus.ts
|
|
40
|
+
function byDocumentOrder(a, b) {
|
|
41
|
+
const x = a.ref.current;
|
|
42
|
+
const y = b.ref.current;
|
|
43
|
+
if (!x || !y) return 0;
|
|
44
|
+
return x.compareDocumentPosition(y) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
|
|
45
|
+
}
|
|
46
|
+
function rovingIndex(key, {
|
|
47
|
+
count,
|
|
48
|
+
current,
|
|
49
|
+
orientation,
|
|
50
|
+
rtl
|
|
51
|
+
}) {
|
|
52
|
+
if (count === 0) return null;
|
|
53
|
+
const [prevKey, nextKey] = orientation === "vertical" ? ["ArrowUp", "ArrowDown"] : rtl ? ["ArrowRight", "ArrowLeft"] : ["ArrowLeft", "ArrowRight"];
|
|
54
|
+
switch (key) {
|
|
55
|
+
case nextKey:
|
|
56
|
+
return current < 0 ? 0 : (current + 1) % count;
|
|
57
|
+
case prevKey:
|
|
58
|
+
return current < 0 ? count - 1 : (current - 1 + count) % count;
|
|
59
|
+
case "Home":
|
|
60
|
+
return 0;
|
|
61
|
+
case "End":
|
|
62
|
+
return count - 1;
|
|
63
|
+
default:
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
39
68
|
// src/core/useControlled.ts
|
|
40
69
|
var import_react = require("react");
|
|
41
70
|
function useControlled({
|
|
@@ -186,18 +215,13 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
186
215
|
function idPart(value) {
|
|
187
216
|
return value.replace(/\s+/g, "_");
|
|
188
217
|
}
|
|
189
|
-
function documentOrder(a, b) {
|
|
190
|
-
const x = a.ref.current;
|
|
191
|
-
const y = b.ref.current;
|
|
192
|
-
if (!x || !y) return 0;
|
|
193
|
-
return x.compareDocumentPosition(y) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
|
|
194
|
-
}
|
|
195
218
|
function TabsRoot({
|
|
196
219
|
value: valueProp,
|
|
197
220
|
defaultValue,
|
|
198
221
|
onValueChange,
|
|
199
222
|
orientation = "horizontal",
|
|
200
223
|
activationMode = "automatic",
|
|
224
|
+
focusableWhenDisabled: focusableWhenDisabledProp = false,
|
|
201
225
|
className,
|
|
202
226
|
children,
|
|
203
227
|
render,
|
|
@@ -220,12 +244,16 @@ function TabsRoot({
|
|
|
220
244
|
const [tabs, setTabs] = (0, import_react4.useState)([]);
|
|
221
245
|
const register = (0, import_react4.useCallback)((entry) => {
|
|
222
246
|
setTabs(
|
|
223
|
-
(current) => [...current.filter((t) => t.value !== entry.value), entry].sort(
|
|
247
|
+
(current) => [...current.filter((t) => t.value !== entry.value), entry].sort(byDocumentOrder)
|
|
224
248
|
);
|
|
225
249
|
return () => setTabs((current) => current.filter((t) => t !== entry));
|
|
226
250
|
}, []);
|
|
227
|
-
const
|
|
228
|
-
const
|
|
251
|
+
const focusableWhenDisabled = focusableWhenDisabledProp && activationMode === "manual";
|
|
252
|
+
const navigableTabs = (0, import_react4.useMemo)(
|
|
253
|
+
() => focusableWhenDisabled ? tabs : tabs.filter((t) => !t.disabled),
|
|
254
|
+
[tabs, focusableWhenDisabled]
|
|
255
|
+
);
|
|
256
|
+
const tabStopValue = tabs.length === 0 ? value : (navigableTabs.find((t) => t.value === value) ?? navigableTabs[0])?.value;
|
|
229
257
|
const baseId = (0, import_react4.useId)();
|
|
230
258
|
const context = (0, import_react4.useMemo)(
|
|
231
259
|
() => ({
|
|
@@ -233,13 +261,24 @@ function TabsRoot({
|
|
|
233
261
|
setValue,
|
|
234
262
|
orientation,
|
|
235
263
|
activationMode,
|
|
236
|
-
|
|
264
|
+
navigableTabs,
|
|
265
|
+
focusableWhenDisabled,
|
|
237
266
|
tabStopValue,
|
|
238
267
|
register,
|
|
239
268
|
tabId: (v) => `${baseId}-tab-${idPart(v)}`,
|
|
240
269
|
panelId: (v) => `${baseId}-panel-${idPart(v)}`
|
|
241
270
|
}),
|
|
242
|
-
[
|
|
271
|
+
[
|
|
272
|
+
value,
|
|
273
|
+
setValue,
|
|
274
|
+
orientation,
|
|
275
|
+
activationMode,
|
|
276
|
+
navigableTabs,
|
|
277
|
+
focusableWhenDisabled,
|
|
278
|
+
tabStopValue,
|
|
279
|
+
register,
|
|
280
|
+
baseId
|
|
281
|
+
]
|
|
243
282
|
);
|
|
244
283
|
const element = useRender({
|
|
245
284
|
render,
|
|
@@ -252,33 +291,8 @@ function TabsRoot({
|
|
|
252
291
|
|
|
253
292
|
// src/tabs/TabsList.tsx
|
|
254
293
|
var import_react5 = require("react");
|
|
255
|
-
|
|
256
|
-
// src/core/rovingFocus.ts
|
|
257
|
-
function rovingIndex(key, {
|
|
258
|
-
count,
|
|
259
|
-
current,
|
|
260
|
-
orientation,
|
|
261
|
-
rtl
|
|
262
|
-
}) {
|
|
263
|
-
if (count === 0) return null;
|
|
264
|
-
const [prevKey, nextKey] = orientation === "vertical" ? ["ArrowUp", "ArrowDown"] : rtl ? ["ArrowRight", "ArrowLeft"] : ["ArrowLeft", "ArrowRight"];
|
|
265
|
-
switch (key) {
|
|
266
|
-
case nextKey:
|
|
267
|
-
return current < 0 ? 0 : (current + 1) % count;
|
|
268
|
-
case prevKey:
|
|
269
|
-
return current < 0 ? count - 1 : (current - 1 + count) % count;
|
|
270
|
-
case "Home":
|
|
271
|
-
return 0;
|
|
272
|
-
case "End":
|
|
273
|
-
return count - 1;
|
|
274
|
-
default:
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// src/tabs/TabsList.tsx
|
|
280
294
|
function TabsList({ className, children, render, ...rest }) {
|
|
281
|
-
const { orientation,
|
|
295
|
+
const { orientation, navigableTabs } = useTabsRootContext("List");
|
|
282
296
|
const elementRef = (0, import_react5.useRef)(null);
|
|
283
297
|
return useRender({
|
|
284
298
|
render,
|
|
@@ -292,19 +306,19 @@ function TabsList({ className, children, render, ...rest }) {
|
|
|
292
306
|
children,
|
|
293
307
|
ref: elementRef,
|
|
294
308
|
onKeyDown(event) {
|
|
295
|
-
const current =
|
|
309
|
+
const current = navigableTabs.findIndex((t) => t.ref.current === event.target);
|
|
296
310
|
if (current < 0) return;
|
|
297
311
|
const list = elementRef.current;
|
|
298
312
|
const rtl = list ? getComputedStyle(list).direction === "rtl" : false;
|
|
299
313
|
const next = rovingIndex(event.key, {
|
|
300
|
-
count:
|
|
314
|
+
count: navigableTabs.length,
|
|
301
315
|
current,
|
|
302
316
|
orientation,
|
|
303
317
|
rtl
|
|
304
318
|
});
|
|
305
319
|
if (next === null) return;
|
|
306
320
|
event.preventDefault();
|
|
307
|
-
|
|
321
|
+
navigableTabs[next]?.ref.current?.focus();
|
|
308
322
|
}
|
|
309
323
|
},
|
|
310
324
|
consumerProps: rest
|
|
@@ -316,6 +330,7 @@ var import_react6 = require("react");
|
|
|
316
330
|
function TabsTab({
|
|
317
331
|
value,
|
|
318
332
|
disabled = false,
|
|
333
|
+
onClick,
|
|
319
334
|
className,
|
|
320
335
|
children,
|
|
321
336
|
render,
|
|
@@ -325,6 +340,7 @@ function TabsTab({
|
|
|
325
340
|
value: selectedValue,
|
|
326
341
|
setValue,
|
|
327
342
|
activationMode,
|
|
343
|
+
focusableWhenDisabled,
|
|
328
344
|
tabStopValue,
|
|
329
345
|
register,
|
|
330
346
|
tabId,
|
|
@@ -346,8 +362,10 @@ function TabsTab({
|
|
|
346
362
|
"aria-selected": selected,
|
|
347
363
|
"aria-controls": panelId(value),
|
|
348
364
|
tabIndex: value === tabStopValue ? 0 : -1,
|
|
349
|
-
// The platform keeps a disabled button out of focus and activation.
|
|
350
|
-
disabled
|
|
365
|
+
// The platform keeps a disabled button out of focus and activation. Focusable when
|
|
366
|
+
// disabled, it is aria-disabled instead, and activation is blocked here.
|
|
367
|
+
disabled: disabled && !focusableWhenDisabled || void 0,
|
|
368
|
+
"aria-disabled": disabled && focusableWhenDisabled || void 0,
|
|
351
369
|
...selectedDataAttributes(selected, disabled),
|
|
352
370
|
className,
|
|
353
371
|
children,
|
|
@@ -359,7 +377,8 @@ function TabsTab({
|
|
|
359
377
|
if (activationMode === "automatic" && !disabled) setValue(value);
|
|
360
378
|
}
|
|
361
379
|
},
|
|
362
|
-
|
|
380
|
+
// A native `disabled` would block your onClick; aria-disabled does not, so it is left off.
|
|
381
|
+
consumerProps: disabled ? rest : { ...rest, onClick }
|
|
363
382
|
});
|
|
364
383
|
}
|
|
365
384
|
|
package/dist/tabs/index.d.cts
CHANGED
|
@@ -36,6 +36,13 @@ type TabsRootOwnProps = {
|
|
|
36
36
|
* click. Manual suits panels that are slow to show.
|
|
37
37
|
*/
|
|
38
38
|
activationMode?: TabsActivationMode;
|
|
39
|
+
/**
|
|
40
|
+
* Keeps disabled tabs in the arrow-key sequence, so a screen reader announces them as
|
|
41
|
+
* unavailable. They still cannot be selected. Only with `activationMode="manual"`: under
|
|
42
|
+
* `"automatic"` moving focus to a tab selects it, so disabled tabs are always skipped and
|
|
43
|
+
* this has no effect.
|
|
44
|
+
*/
|
|
45
|
+
focusableWhenDisabled?: boolean;
|
|
39
46
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
40
47
|
render?: ReactElement;
|
|
41
48
|
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
@@ -52,7 +59,7 @@ type TabsRootProps = TabsRootOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof
|
|
|
52
59
|
* Each Tab registers its own `value` and `disabled` from its props; the Root never reads
|
|
53
60
|
* them back from the DOM (decision 10). Elements are kept only to move focus to.
|
|
54
61
|
*/
|
|
55
|
-
declare function TabsRoot({ value: valueProp, defaultValue, onValueChange, orientation, activationMode, className, children, render, ...rest }: TabsRootProps): react.JSX.Element;
|
|
62
|
+
declare function TabsRoot({ value: valueProp, defaultValue, onValueChange, orientation, activationMode, focusableWhenDisabled: focusableWhenDisabledProp, className, children, render, ...rest }: TabsRootProps): react.JSX.Element;
|
|
56
63
|
|
|
57
64
|
type TabsListOwnProps = {
|
|
58
65
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
@@ -63,7 +70,8 @@ type TabsListOwnProps = {
|
|
|
63
70
|
type TabsListProps = TabsListOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof TabsListOwnProps>;
|
|
64
71
|
/**
|
|
65
72
|
* The tablist. Holds the keyboard: arrows along the orientation, wrapping at the ends,
|
|
66
|
-
* Home and End — moving focus among the enabled tabs
|
|
73
|
+
* Home and End — moving focus among the enabled tabs, and the disabled ones too with
|
|
74
|
+
* `focusableWhenDisabled`. Whether focusing a tab also
|
|
67
75
|
* selects it is the Tab's to decide, by `activationMode`.
|
|
68
76
|
*
|
|
69
77
|
* Name it with `aria-label` or `aria-labelledby` when the page has more than one.
|
|
@@ -73,7 +81,10 @@ declare function TabsList({ className, children, render, ...rest }: TabsListProp
|
|
|
73
81
|
type TabsTabOwnProps = {
|
|
74
82
|
/** Identifies this tab, and the Panel with the same `value`. */
|
|
75
83
|
value: string;
|
|
76
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* Cannot be selected. Skipped by the arrow keys, unless the Root sets
|
|
86
|
+
* `focusableWhenDisabled` with `activationMode="manual"`.
|
|
87
|
+
*/
|
|
77
88
|
disabled?: boolean;
|
|
78
89
|
/** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
|
|
79
90
|
render?: ReactElement;
|
|
@@ -89,7 +100,7 @@ type TabsTabProps = TabsTabOwnProps & Omit<ComponentPropsWithRef<'button'>, keyo
|
|
|
89
100
|
* With `activationMode="automatic"` (the default) focus selects: the arrow keys change the
|
|
90
101
|
* panel as they move. With `"manual"` they only move focus.
|
|
91
102
|
*/
|
|
92
|
-
declare function TabsTab({ value, disabled, className, children, render, ...rest }: TabsTabProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
103
|
+
declare function TabsTab({ value, disabled, onClick, className, children, render, ...rest }: TabsTabProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
93
104
|
|
|
94
105
|
type TabsPanelOwnProps = {
|
|
95
106
|
/** The `value` of the Tab this panel belongs to. */
|
package/dist/tabs/index.d.ts
CHANGED
|
@@ -36,6 +36,13 @@ type TabsRootOwnProps = {
|
|
|
36
36
|
* click. Manual suits panels that are slow to show.
|
|
37
37
|
*/
|
|
38
38
|
activationMode?: TabsActivationMode;
|
|
39
|
+
/**
|
|
40
|
+
* Keeps disabled tabs in the arrow-key sequence, so a screen reader announces them as
|
|
41
|
+
* unavailable. They still cannot be selected. Only with `activationMode="manual"`: under
|
|
42
|
+
* `"automatic"` moving focus to a tab selects it, so disabled tabs are always skipped and
|
|
43
|
+
* this has no effect.
|
|
44
|
+
*/
|
|
45
|
+
focusableWhenDisabled?: boolean;
|
|
39
46
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
40
47
|
render?: ReactElement;
|
|
41
48
|
/** Ref to the rendered element. Merged with any ref on the `render` element. */
|
|
@@ -52,7 +59,7 @@ type TabsRootProps = TabsRootOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof
|
|
|
52
59
|
* Each Tab registers its own `value` and `disabled` from its props; the Root never reads
|
|
53
60
|
* them back from the DOM (decision 10). Elements are kept only to move focus to.
|
|
54
61
|
*/
|
|
55
|
-
declare function TabsRoot({ value: valueProp, defaultValue, onValueChange, orientation, activationMode, className, children, render, ...rest }: TabsRootProps): react.JSX.Element;
|
|
62
|
+
declare function TabsRoot({ value: valueProp, defaultValue, onValueChange, orientation, activationMode, focusableWhenDisabled: focusableWhenDisabledProp, className, children, render, ...rest }: TabsRootProps): react.JSX.Element;
|
|
56
63
|
|
|
57
64
|
type TabsListOwnProps = {
|
|
58
65
|
/** Element to render instead of the default `<div>`. Props and ref are merged onto it. */
|
|
@@ -63,7 +70,8 @@ type TabsListOwnProps = {
|
|
|
63
70
|
type TabsListProps = TabsListOwnProps & Omit<ComponentPropsWithRef<'div'>, keyof TabsListOwnProps>;
|
|
64
71
|
/**
|
|
65
72
|
* The tablist. Holds the keyboard: arrows along the orientation, wrapping at the ends,
|
|
66
|
-
* Home and End — moving focus among the enabled tabs
|
|
73
|
+
* Home and End — moving focus among the enabled tabs, and the disabled ones too with
|
|
74
|
+
* `focusableWhenDisabled`. Whether focusing a tab also
|
|
67
75
|
* selects it is the Tab's to decide, by `activationMode`.
|
|
68
76
|
*
|
|
69
77
|
* Name it with `aria-label` or `aria-labelledby` when the page has more than one.
|
|
@@ -73,7 +81,10 @@ declare function TabsList({ className, children, render, ...rest }: TabsListProp
|
|
|
73
81
|
type TabsTabOwnProps = {
|
|
74
82
|
/** Identifies this tab, and the Panel with the same `value`. */
|
|
75
83
|
value: string;
|
|
76
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* Cannot be selected. Skipped by the arrow keys, unless the Root sets
|
|
86
|
+
* `focusableWhenDisabled` with `activationMode="manual"`.
|
|
87
|
+
*/
|
|
77
88
|
disabled?: boolean;
|
|
78
89
|
/** Element to render instead of the default `<button>`. Props and ref are merged onto it. */
|
|
79
90
|
render?: ReactElement;
|
|
@@ -89,7 +100,7 @@ type TabsTabProps = TabsTabOwnProps & Omit<ComponentPropsWithRef<'button'>, keyo
|
|
|
89
100
|
* With `activationMode="automatic"` (the default) focus selects: the arrow keys change the
|
|
90
101
|
* panel as they move. With `"manual"` they only move focus.
|
|
91
102
|
*/
|
|
92
|
-
declare function TabsTab({ value, disabled, className, children, render, ...rest }: TabsTabProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
103
|
+
declare function TabsTab({ value, disabled, onClick, className, children, render, ...rest }: TabsTabProps): ReactElement<unknown, string | react.JSXElementConstructor<any>>;
|
|
93
104
|
|
|
94
105
|
type TabsPanelOwnProps = {
|
|
95
106
|
/** The `value` of the Tab this panel belongs to. */
|