@uniflowed/ui 0.1.0 → 0.3.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/accordion.js +22 -9
- package/alert-dialog.js +41 -19
- package/alert.js +14 -8
- package/avatar.js +14 -8
- package/breadcrumb.js +24 -6
- package/calendar.js +54 -10
- package/carousel.js +24 -6
- package/collapsible.js +14 -3
- package/color-picker.js +22 -5
- package/combobox.js +30 -21
- package/context-menu.js +31 -2
- package/date-picker.js +37 -11
- package/date-range-picker.js +25 -8
- package/dialog.js +39 -11
- package/drawer.js +47 -34
- package/field.js +24 -6
- package/hover-card.js +14 -3
- package/index.js +107 -740
- package/input-otp.js +20 -4
- package/interactions.js +0 -1
- package/internal/collection.js +262 -95
- package/internal/focus.js +13 -4
- package/internal/roving-focus.js +12 -3
- package/internal/segmented-field.js +2 -1
- package/internal/selection.js +171 -0
- package/internal/visually-hidden-style.js +41 -0
- package/menu.js +36 -13
- package/menubar.js +32 -5
- package/navigation-menu.js +24 -6
- package/number-field.js +20 -12
- package/package.json +5 -5
- package/pagination.js +22 -5
- package/popover.js +14 -4
- package/radio-group.js +15 -4
- package/range-calendar.js +22 -3
- package/resizable.js +14 -3
- package/scroll-area.js +14 -3
- package/select.js +30 -13
- package/sheet.js +39 -18
- package/sidebar.js +31 -16
- package/skeleton.js +13 -3
- package/slider.js +15 -4
- package/table.js +34 -24
- package/tabs.js +15 -9
- package/toast.js +24 -6
- package/toggle-group.js +14 -3
- package/tooltip.js +21 -5
- package/visually-hidden.js +259 -0
package/accordion.js
CHANGED
|
@@ -173,7 +173,7 @@ hook useAccordionItem(part: string): AccordionItemState {
|
|
|
173
173
|
* one, and keeping that invariant is the component's job rather than the
|
|
174
174
|
* caller's to remember.
|
|
175
175
|
*/
|
|
176
|
-
|
|
176
|
+
component AccordionRoot(
|
|
177
177
|
children: renders* AccordionItem,
|
|
178
178
|
type?: AccordionType = "single",
|
|
179
179
|
collapsible?: boolean = true,
|
|
@@ -235,7 +235,7 @@ export component AccordionRoot(
|
|
|
235
235
|
* a panel inside its own heading would be part of the heading's accessible
|
|
236
236
|
* name.
|
|
237
237
|
*/
|
|
238
|
-
|
|
238
|
+
component AccordionItem(
|
|
239
239
|
value: string,
|
|
240
240
|
children: renders* (AccordionHeader | AccordionContent),
|
|
241
241
|
disabled?: boolean = false,
|
|
@@ -280,11 +280,7 @@ export component AccordionItem(
|
|
|
280
280
|
* a level outside that range is clamped rather than rendered — a tag nobody
|
|
281
281
|
* recognises is announced as nothing at all, which loses the heading entirely.
|
|
282
282
|
*/
|
|
283
|
-
|
|
284
|
-
children: renders AccordionTrigger,
|
|
285
|
-
level?: number = 3,
|
|
286
|
-
...rest: Rest
|
|
287
|
-
) {
|
|
283
|
+
component AccordionHeader(children: renders AccordionTrigger, level?: number = 3, ...rest: Rest) {
|
|
288
284
|
const clamped = Math.min(6, Math.max(1, Math.trunc(level)));
|
|
289
285
|
const Heading = `h${String(clamped)}`;
|
|
290
286
|
|
|
@@ -297,7 +293,7 @@ export component AccordionHeader(
|
|
|
297
293
|
* It carries no `tabIndex` of its own on purpose: every header stays in the
|
|
298
294
|
* page's tab order, which is what makes this an accordion and not a tab list.
|
|
299
295
|
*/
|
|
300
|
-
|
|
296
|
+
component AccordionTrigger(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
301
297
|
const item = useAccordionItem("Accordion.Trigger");
|
|
302
298
|
// Locked and disabled are two different sentences a reader hears the same
|
|
303
299
|
// way, and both are `aria-disabled` rather than `disabled` so the header
|
|
@@ -333,7 +329,7 @@ export component AccordionTrigger(children: React.Node, render?: RenderProp, ...
|
|
|
333
329
|
* `internal/disclosure.js` explains what "stays in the document" is worth and
|
|
334
330
|
* what `hidden` is upgraded to for it.
|
|
335
331
|
*/
|
|
336
|
-
|
|
332
|
+
component AccordionContent(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
337
333
|
const accordion = useAccordion("Accordion.Content");
|
|
338
334
|
const item = useAccordionItem("Accordion.Content");
|
|
339
335
|
const contentRef = useRef<HTMLElement | null>(null);
|
|
@@ -360,3 +356,20 @@ export component AccordionContent(children: React.Node, render?: RenderProp, ...
|
|
|
360
356
|
}
|
|
361
357
|
return <div {...props} />;
|
|
362
358
|
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* The parts, under the names the `Accordion` namespace gives them.
|
|
362
|
+
*
|
|
363
|
+
* `index.js` re-exports this module whole — `export * as Accordion from "./accordion.js"` —
|
|
364
|
+
* so a caller writes `<Accordion.Root>`, and the namespace is the prefix. Each
|
|
365
|
+
* part is still *declared* as `AccordionRoot`, so React DevTools, a component
|
|
366
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
367
|
+
* `Root`s.
|
|
368
|
+
*/
|
|
369
|
+
export {
|
|
370
|
+
AccordionRoot as Root,
|
|
371
|
+
AccordionItem as Item,
|
|
372
|
+
AccordionHeader as Header,
|
|
373
|
+
AccordionTrigger as Trigger,
|
|
374
|
+
AccordionContent as Content,
|
|
375
|
+
};
|
package/alert-dialog.js
CHANGED
|
@@ -49,15 +49,15 @@ import { createContext, useContext, useEffect, useMemo, useRef } from "@uniflowe
|
|
|
49
49
|
import type { RenderProp, Rest } from "./internal/merge-props.js";
|
|
50
50
|
import { composeRefs, forwarded, withoutComposed } from "./internal/merge-props.js";
|
|
51
51
|
import {
|
|
52
|
-
DialogBody,
|
|
53
|
-
DialogClose,
|
|
54
|
-
DialogDescription,
|
|
55
|
-
DialogFooter,
|
|
56
|
-
DialogHeader,
|
|
57
|
-
DialogOverlay,
|
|
58
|
-
DialogRoot,
|
|
59
|
-
DialogTitle,
|
|
60
|
-
DialogTrigger,
|
|
52
|
+
Body as DialogBody,
|
|
53
|
+
Close as DialogClose,
|
|
54
|
+
Description as DialogDescription,
|
|
55
|
+
Footer as DialogFooter,
|
|
56
|
+
Header as DialogHeader,
|
|
57
|
+
Overlay as DialogOverlay,
|
|
58
|
+
Root as DialogRoot,
|
|
59
|
+
Title as DialogTitle,
|
|
60
|
+
Trigger as DialogTrigger,
|
|
61
61
|
} from "./dialog.js";
|
|
62
62
|
|
|
63
63
|
type AlertDialogState = {|
|
|
@@ -98,7 +98,7 @@ hook useAlertDialog(part: string): AlertDialogState {
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/** The alert dialog, open or closed. Uncontrolled unless `open` is given. */
|
|
101
|
-
|
|
101
|
+
component AlertDialogRoot(
|
|
102
102
|
children: React.Node,
|
|
103
103
|
defaultOpen?: boolean = false,
|
|
104
104
|
open?: boolean,
|
|
@@ -118,7 +118,7 @@ export component AlertDialogRoot(
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
/** What opens it, and what focus comes back to when it closes. */
|
|
121
|
-
|
|
121
|
+
component AlertDialogTrigger(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
122
122
|
return (
|
|
123
123
|
<DialogTrigger {...forwarded(rest)} render={render}>
|
|
124
124
|
{children}
|
|
@@ -127,7 +127,7 @@ export component AlertDialogTrigger(children: React.Node, render?: RenderProp, .
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
/** The backdrop. See `Dialog.Overlay`: it is decoration and says so. */
|
|
130
|
-
|
|
130
|
+
component AlertDialogOverlay(render?: RenderProp, ...rest: Rest) {
|
|
131
131
|
return <DialogOverlay {...forwarded(rest)} render={render} />;
|
|
132
132
|
}
|
|
133
133
|
|
|
@@ -140,7 +140,7 @@ export component AlertDialogOverlay(render?: RenderProp, ...rest: Rest) {
|
|
|
140
140
|
* who set two of them would have an alert dialog that is wrong in the third
|
|
141
141
|
* without anything saying so.
|
|
142
142
|
*/
|
|
143
|
-
|
|
143
|
+
component AlertDialogBody(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
144
144
|
const alert = useAlertDialog("AlertDialog.Body");
|
|
145
145
|
|
|
146
146
|
return (
|
|
@@ -189,7 +189,7 @@ component RequireDescription() {
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
/** The top of the alert dialog. See `Dialog.Header` for why it is a `div`. */
|
|
192
|
-
|
|
192
|
+
component AlertDialogHeader(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
193
193
|
return (
|
|
194
194
|
<DialogHeader {...forwarded(rest)} render={render}>
|
|
195
195
|
{children}
|
|
@@ -198,7 +198,7 @@ export component AlertDialogHeader(children: React.Node, render?: RenderProp, ..
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
/** The bottom, where `Action` and `Cancel` go. */
|
|
201
|
-
|
|
201
|
+
component AlertDialogFooter(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
202
202
|
return (
|
|
203
203
|
<DialogFooter {...forwarded(rest)} render={render}>
|
|
204
204
|
{children}
|
|
@@ -207,7 +207,7 @@ export component AlertDialogFooter(children: React.Node, render?: RenderProp, ..
|
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
/** The question, which is the alert dialog's accessible name. */
|
|
210
|
-
|
|
210
|
+
component AlertDialogTitle(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
211
211
|
return (
|
|
212
212
|
<DialogTitle {...forwarded(rest)} render={render}>
|
|
213
213
|
{children}
|
|
@@ -222,7 +222,7 @@ export component AlertDialogTitle(children: React.Node, render?: RenderProp, ...
|
|
|
222
222
|
* exists to deliver, and the only moment the reader has to decide whether they
|
|
223
223
|
* care is before they have pressed anything.
|
|
224
224
|
*/
|
|
225
|
-
|
|
225
|
+
component AlertDialogDescription(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
226
226
|
const alert = useAlertDialog("AlertDialog.Description");
|
|
227
227
|
const describedBy = alert.describedBy;
|
|
228
228
|
|
|
@@ -250,7 +250,7 @@ export component AlertDialogDescription(children: React.Node, render?: RenderPro
|
|
|
250
250
|
* are made of, so the composition rule about a caller's `onClick` has one
|
|
251
251
|
* implementation rather than a second copy here.
|
|
252
252
|
*/
|
|
253
|
-
|
|
253
|
+
component AlertDialogAction(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
254
254
|
return (
|
|
255
255
|
<DialogClose {...forwarded(rest)} render={render}>
|
|
256
256
|
{children}
|
|
@@ -265,7 +265,7 @@ export component AlertDialogAction(children: React.Node, render?: RenderProp, ..
|
|
|
265
265
|
* without the caller wiring a ref: the least destructive action is a fact about
|
|
266
266
|
* which part this is, not a decision to be repeated at every call.
|
|
267
267
|
*/
|
|
268
|
-
|
|
268
|
+
component AlertDialogCancel(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
269
269
|
const alert = useAlertDialog("AlertDialog.Cancel");
|
|
270
270
|
const cancelRef = alert.cancelRef;
|
|
271
271
|
const passed = withoutComposed(rest, ["ref"]);
|
|
@@ -282,3 +282,25 @@ export component AlertDialogCancel(children: React.Node, render?: RenderProp, ..
|
|
|
282
282
|
</DialogClose>
|
|
283
283
|
);
|
|
284
284
|
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* The parts, under the names the `AlertDialog` namespace gives them.
|
|
288
|
+
*
|
|
289
|
+
* `index.js` re-exports this module whole — `export * as AlertDialog from "./alert-dialog.js"` —
|
|
290
|
+
* so a caller writes `<AlertDialog.Root>`, and the namespace is the prefix. Each
|
|
291
|
+
* part is still *declared* as `AlertDialogRoot`, so React DevTools, a component
|
|
292
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
293
|
+
* `Root`s.
|
|
294
|
+
*/
|
|
295
|
+
export {
|
|
296
|
+
AlertDialogRoot as Root,
|
|
297
|
+
AlertDialogTrigger as Trigger,
|
|
298
|
+
AlertDialogOverlay as Overlay,
|
|
299
|
+
AlertDialogBody as Body,
|
|
300
|
+
AlertDialogHeader as Header,
|
|
301
|
+
AlertDialogFooter as Footer,
|
|
302
|
+
AlertDialogTitle as Title,
|
|
303
|
+
AlertDialogDescription as Description,
|
|
304
|
+
AlertDialogAction as Action,
|
|
305
|
+
AlertDialogCancel as Cancel,
|
|
306
|
+
};
|
package/alert.js
CHANGED
|
@@ -88,7 +88,7 @@ import { withProps } from "./internal/merge-props.js";
|
|
|
88
88
|
* header is about: the role is a promise about a change, and a box that was
|
|
89
89
|
* always there has no change to report.
|
|
90
90
|
*/
|
|
91
|
-
|
|
91
|
+
component AlertRoot(
|
|
92
92
|
children: React.Node,
|
|
93
93
|
live?: boolean = false,
|
|
94
94
|
render?: RenderProp,
|
|
@@ -116,12 +116,7 @@ export component AlertRoot(
|
|
|
116
116
|
* the six HTML has is clamped, because `<h7>` is not an element and is
|
|
117
117
|
* announced as nothing at all.
|
|
118
118
|
*/
|
|
119
|
-
|
|
120
|
-
children: React.Node,
|
|
121
|
-
level?: number = 3,
|
|
122
|
-
render?: RenderProp,
|
|
123
|
-
...rest: Rest
|
|
124
|
-
) {
|
|
119
|
+
component AlertTitle(children: React.Node, level?: number = 3, render?: RenderProp, ...rest: Rest) {
|
|
125
120
|
const clamped = Math.min(6, Math.max(1, Math.trunc(level)));
|
|
126
121
|
const Heading = `h${String(clamped)}`;
|
|
127
122
|
const props = withProps(rest, { children });
|
|
@@ -133,10 +128,21 @@ export component AlertTitle(
|
|
|
133
128
|
}
|
|
134
129
|
|
|
135
130
|
/** What the callout says, under its heading. */
|
|
136
|
-
|
|
131
|
+
component AlertDescription(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
137
132
|
const props = withProps(rest, { children });
|
|
138
133
|
if (render != null) {
|
|
139
134
|
return render(props);
|
|
140
135
|
}
|
|
141
136
|
return <p {...props} />;
|
|
142
137
|
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The parts, under the names the `Alert` namespace gives them.
|
|
141
|
+
*
|
|
142
|
+
* `index.js` re-exports this module whole — `export * as Alert from "./alert.js"` —
|
|
143
|
+
* so a caller writes `<Alert.Root>`, and the namespace is the prefix. Each
|
|
144
|
+
* part is still *declared* as `AlertRoot`, so React DevTools, a component
|
|
145
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
146
|
+
* `Root`s.
|
|
147
|
+
*/
|
|
148
|
+
export { AlertRoot as Root, AlertTitle as Title, AlertDescription as Description };
|
package/avatar.js
CHANGED
|
@@ -127,7 +127,7 @@ hook useAvatar(part: string): AvatarState {
|
|
|
127
127
|
* in a table cell, in a paragraph, inside a button's label — and a block
|
|
128
128
|
* element is invalid in half of those.
|
|
129
129
|
*/
|
|
130
|
-
|
|
130
|
+
component AvatarRoot(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
131
131
|
const [seen, setSeen] = useState<Seen>(START);
|
|
132
132
|
const [hasImage, setHasImage] = useState(false);
|
|
133
133
|
|
|
@@ -181,12 +181,7 @@ export component AvatarRoot(children: React.Node, render?: RenderProp, ...rest:
|
|
|
181
181
|
* stylesheet: `hidden` loses to any `display` the caller sets, and a caller who
|
|
182
182
|
* has not written that rule yet would see both.
|
|
183
183
|
*/
|
|
184
|
-
|
|
185
|
-
alt?: string = "",
|
|
186
|
-
src?: string | null,
|
|
187
|
-
render?: RenderProp,
|
|
188
|
-
...rest: Rest
|
|
189
|
-
) {
|
|
184
|
+
component AvatarImage(alt?: string = "", src?: string | null, render?: RenderProp, ...rest: Rest) {
|
|
190
185
|
const avatar = useAvatar("Avatar.Image");
|
|
191
186
|
const element = useRef<HTMLImageElement | null>(null);
|
|
192
187
|
const report = avatar.report;
|
|
@@ -249,7 +244,7 @@ export component AvatarImage(
|
|
|
249
244
|
* avatar with no `Avatar.Image` at all are both answers rather than waits, and
|
|
250
245
|
* the fallback for either is immediate.
|
|
251
246
|
*/
|
|
252
|
-
|
|
247
|
+
component AvatarFallback(
|
|
253
248
|
children: React.Node,
|
|
254
249
|
delay?: number = 300,
|
|
255
250
|
render?: RenderProp,
|
|
@@ -278,3 +273,14 @@ export component AvatarFallback(
|
|
|
278
273
|
}
|
|
279
274
|
return <span {...props} />;
|
|
280
275
|
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* The parts, under the names the `Avatar` namespace gives them.
|
|
279
|
+
*
|
|
280
|
+
* `index.js` re-exports this module whole — `export * as Avatar from "./avatar.js"` —
|
|
281
|
+
* so a caller writes `<Avatar.Root>`, and the namespace is the prefix. Each
|
|
282
|
+
* part is still *declared* as `AvatarRoot`, so React DevTools, a component
|
|
283
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
284
|
+
* `Root`s.
|
|
285
|
+
*/
|
|
286
|
+
export { AvatarRoot as Root, AvatarImage as Image, AvatarFallback as Fallback };
|
package/breadcrumb.js
CHANGED
|
@@ -56,7 +56,7 @@ import { withProps } from "./internal/merge-props.js";
|
|
|
56
56
|
* to translate; there is no case for leaving it off, which is why it is not
|
|
57
57
|
* optional in the sense of being absent.
|
|
58
58
|
*/
|
|
59
|
-
|
|
59
|
+
component BreadcrumbRoot(
|
|
60
60
|
children: React.Node,
|
|
61
61
|
label?: string = "Breadcrumb",
|
|
62
62
|
render?: RenderProp,
|
|
@@ -76,7 +76,7 @@ export component BreadcrumbRoot(
|
|
|
76
76
|
* information: a reader is told how many levels there are before walking them,
|
|
77
77
|
* and can skip the lot in one keystroke.
|
|
78
78
|
*/
|
|
79
|
-
|
|
79
|
+
component BreadcrumbList(
|
|
80
80
|
children: renders* (BreadcrumbItem | BreadcrumbSeparator),
|
|
81
81
|
render?: RenderProp,
|
|
82
82
|
...rest: Rest
|
|
@@ -89,7 +89,7 @@ export component BreadcrumbList(
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
/** One level of the trail. Holds a `Breadcrumb.Link` or a `Breadcrumb.Page`. */
|
|
92
|
-
|
|
92
|
+
component BreadcrumbItem(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
93
93
|
const props = withProps(rest, { children });
|
|
94
94
|
if (render != null) {
|
|
95
95
|
return render(withProps(props, { role: "listitem" }));
|
|
@@ -98,7 +98,7 @@ export component BreadcrumbItem(children: React.Node, render?: RenderProp, ...re
|
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/** A level you can go back to. */
|
|
101
|
-
|
|
101
|
+
component BreadcrumbLink(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
102
102
|
const props = withProps(rest, { children });
|
|
103
103
|
if (render != null) {
|
|
104
104
|
return render(withProps(props, { role: "link" }));
|
|
@@ -114,7 +114,7 @@ export component BreadcrumbLink(children: React.Node, render?: RenderProp, ...re
|
|
|
114
114
|
* a link by accident. See the module header for why announcing it as a disabled
|
|
115
115
|
* link is worse than announcing it as text.
|
|
116
116
|
*/
|
|
117
|
-
|
|
117
|
+
component BreadcrumbPage(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
118
118
|
const props = withProps(rest, { "aria-current": "page", children });
|
|
119
119
|
if (render != null) {
|
|
120
120
|
return render(props);
|
|
@@ -129,10 +129,28 @@ export component BreadcrumbPage(children: React.Node, render?: RenderProp, ...re
|
|
|
129
129
|
* design decision and this package makes none. What is not the caller's is that
|
|
130
130
|
* it is announced to nobody.
|
|
131
131
|
*/
|
|
132
|
-
|
|
132
|
+
component BreadcrumbSeparator(children?: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
133
133
|
const props = withProps(rest, { "aria-hidden": "true", children, role: "presentation" });
|
|
134
134
|
if (render != null) {
|
|
135
135
|
return render(props);
|
|
136
136
|
}
|
|
137
137
|
return <li {...props} />;
|
|
138
138
|
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* The parts, under the names the `Breadcrumb` namespace gives them.
|
|
142
|
+
*
|
|
143
|
+
* `index.js` re-exports this module whole — `export * as Breadcrumb from "./breadcrumb.js"` —
|
|
144
|
+
* so a caller writes `<Breadcrumb.Root>`, and the namespace is the prefix. Each
|
|
145
|
+
* part is still *declared* as `BreadcrumbRoot`, so React DevTools, a component
|
|
146
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
147
|
+
* `Root`s.
|
|
148
|
+
*/
|
|
149
|
+
export {
|
|
150
|
+
BreadcrumbRoot as Root,
|
|
151
|
+
BreadcrumbList as List,
|
|
152
|
+
BreadcrumbItem as Item,
|
|
153
|
+
BreadcrumbLink as Link,
|
|
154
|
+
BreadcrumbPage as Page,
|
|
155
|
+
BreadcrumbSeparator as Separator,
|
|
156
|
+
};
|
package/calendar.js
CHANGED
|
@@ -77,6 +77,7 @@ import {
|
|
|
77
77
|
withoutComposed,
|
|
78
78
|
} from "./internal/merge-props.js";
|
|
79
79
|
import { directionOf } from "./internal/roving-focus.js";
|
|
80
|
+
import { visuallyHiddenStyle } from "./internal/visually-hidden-style.js";
|
|
80
81
|
import {
|
|
81
82
|
firstDayOfWeekFor,
|
|
82
83
|
moveDate,
|
|
@@ -174,7 +175,7 @@ function toDate(value: DateValue): PlainDate {
|
|
|
174
175
|
* place it — so `Calendar.Root` renders it and keeps it empty until the month
|
|
175
176
|
* actually changes.
|
|
176
177
|
*/
|
|
177
|
-
|
|
178
|
+
component CalendarRoot(
|
|
178
179
|
children: React.Node,
|
|
179
180
|
defaultFocused?: DateValue,
|
|
180
181
|
defaultValue?: DateValue | null = null,
|
|
@@ -321,7 +322,16 @@ export component CalendarRoot(
|
|
|
321
322
|
<CalendarContext.Provider value={state}>
|
|
322
323
|
<div {...rest}>
|
|
323
324
|
{children}
|
|
324
|
-
|
|
325
|
+
{/* Heard and not drawn: the caption above the grid already shows the
|
|
326
|
+
month, and a second copy under it is what a sighted reader would
|
|
327
|
+
otherwise see after the first page. */}
|
|
328
|
+
<div
|
|
329
|
+
aria-atomic="true"
|
|
330
|
+
aria-live="polite"
|
|
331
|
+
id={`${base}-status`}
|
|
332
|
+
role="status"
|
|
333
|
+
style={visuallyHiddenStyle}
|
|
334
|
+
>
|
|
325
335
|
{announcement}
|
|
326
336
|
</div>
|
|
327
337
|
</div>
|
|
@@ -343,7 +353,14 @@ export component CalendarRoot(
|
|
|
343
353
|
* with a dot under it for an appointment is a `Calendar.Day` with a child, not a
|
|
344
354
|
* fork of this component. Omitted, every day renders its own number.
|
|
345
355
|
*/
|
|
346
|
-
|
|
356
|
+
component CalendarMonth(
|
|
357
|
+
/** A class for the `<caption>`, which this part renders itself. */
|
|
358
|
+
captionClassName?: string,
|
|
359
|
+
children?: (date: PlainDate) => renders CalendarDay,
|
|
360
|
+
/** A class for each weekday heading, which this part renders itself. */
|
|
361
|
+
columnHeaderClassName?: string,
|
|
362
|
+
...rest: Rest
|
|
363
|
+
) {
|
|
347
364
|
const calendar = useCalendar("Calendar.Month");
|
|
348
365
|
const gridRef = useRef<HTMLElement | null>(null);
|
|
349
366
|
const { focused, focusedDayRef, moveFocus, pendingFocusRef, weekStartsOn } = calendar;
|
|
@@ -406,7 +423,9 @@ export component CalendarMonth(children?: (date: PlainDate) => renders CalendarD
|
|
|
406
423
|
})}
|
|
407
424
|
role="grid"
|
|
408
425
|
>
|
|
409
|
-
<caption id={`${calendar.base}-caption`}>
|
|
426
|
+
<caption className={captionClassName} id={`${calendar.base}-caption`}>
|
|
427
|
+
{calendar.caption}
|
|
428
|
+
</caption>
|
|
410
429
|
<thead>
|
|
411
430
|
<tr>
|
|
412
431
|
{columns.map((day) => (
|
|
@@ -416,6 +435,7 @@ export component CalendarMonth(children?: (date: PlainDate) => renders CalendarD
|
|
|
416
435
|
// header. `aria-label` wins over the contents for the announced
|
|
417
436
|
// name, so a reader still hears "Wednesday" rather than "Wed".
|
|
418
437
|
aria-label={day.toLocaleString(calendar.locale, COLUMN_FORMAT)}
|
|
438
|
+
className={columnHeaderClassName}
|
|
419
439
|
key={day.dayOfWeek}
|
|
420
440
|
scope="col"
|
|
421
441
|
>
|
|
@@ -460,12 +480,17 @@ export component CalendarMonth(children?: (date: PlainDate) => renders CalendarD
|
|
|
460
480
|
* inventing a second wording that a translation table would then have to own. A
|
|
461
481
|
* caller who wants one passes it; it is not overridden here.
|
|
462
482
|
*/
|
|
463
|
-
|
|
483
|
+
component CalendarDay(date: PlainDate, children?: React.Node, ...rest: Rest) {
|
|
464
484
|
const calendar = useCalendar("Calendar.Day");
|
|
465
485
|
const disabled = calendar.isDisabled(date);
|
|
466
|
-
const
|
|
467
|
-
calendar.isDateSelected?.(
|
|
468
|
-
|
|
486
|
+
const isChosen = (day: PlainDate) =>
|
|
487
|
+
calendar.isDateSelected?.(day) ?? (calendar.selected != null && calendar.selected.equals(day));
|
|
488
|
+
const chosen = isChosen(date);
|
|
489
|
+
// Where a run of chosen days opens and closes, for a stylesheet to round the
|
|
490
|
+
// ends of a range and join its middle. Markup only: nothing reads it, and a
|
|
491
|
+
// single chosen day is a run that opens and closes on itself.
|
|
492
|
+
const opensRun = chosen && !isChosen(date.subtract({ days: 1 }));
|
|
493
|
+
const closesRun = chosen && !isChosen(date.add({ days: 1 }));
|
|
469
494
|
const passed = withoutComposed(rest, ["onClick", "onFocus", "onKeyDown"]);
|
|
470
495
|
|
|
471
496
|
return (
|
|
@@ -481,6 +506,8 @@ export component CalendarDay(date: PlainDate, children?: React.Node, ...rest: Re
|
|
|
481
506
|
// makes a screen reader announce "not selected" on all thirty-one.
|
|
482
507
|
aria-selected={chosen ? "true" : undefined}
|
|
483
508
|
data-date={date.toString()}
|
|
509
|
+
data-selection-end={closesRun ? "true" : undefined}
|
|
510
|
+
data-selection-start={opensRun ? "true" : undefined}
|
|
484
511
|
onClick={composeHandlers(rest.onClick, () => calendar.select(date))}
|
|
485
512
|
// The tab stop follows real focus, which is the half of a roving set that
|
|
486
513
|
// is easy to leave out and impossible to see. A press on an *unavailable*
|
|
@@ -516,7 +543,7 @@ export component CalendarDay(date: PlainDate, children?: React.Node, ...rest: Re
|
|
|
516
543
|
* and not onto a sibling part, because `Rest` names `key` out of its indexer and
|
|
517
544
|
* the receiving component's own indexer answers `mixed` for it.
|
|
518
545
|
*/
|
|
519
|
-
|
|
546
|
+
component CalendarPrevious(children: React.Node, ...rest: Rest) {
|
|
520
547
|
return (
|
|
521
548
|
<MonthStep {...forwarded(rest)} by={-1}>
|
|
522
549
|
{children}
|
|
@@ -525,7 +552,7 @@ export component CalendarPrevious(children: React.Node, ...rest: Rest) {
|
|
|
525
552
|
}
|
|
526
553
|
|
|
527
554
|
/** The button that shows the month after this one. */
|
|
528
|
-
|
|
555
|
+
component CalendarNext(children: React.Node, ...rest: Rest) {
|
|
529
556
|
return (
|
|
530
557
|
<MonthStep {...forwarded(rest)} by={1}>
|
|
531
558
|
{children}
|
|
@@ -558,3 +585,20 @@ component MonthStep(children: React.Node, by: number, ...rest: Rest) {
|
|
|
558
585
|
</button>
|
|
559
586
|
);
|
|
560
587
|
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* The parts, under the names the `Calendar` namespace gives them.
|
|
591
|
+
*
|
|
592
|
+
* `index.js` re-exports this module whole — `export * as Calendar from "./calendar.js"` —
|
|
593
|
+
* so a caller writes `<Calendar.Root>`, and the namespace is the prefix. Each
|
|
594
|
+
* part is still *declared* as `CalendarRoot`, so React DevTools, a component
|
|
595
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
596
|
+
* `Root`s.
|
|
597
|
+
*/
|
|
598
|
+
export {
|
|
599
|
+
CalendarRoot as Root,
|
|
600
|
+
CalendarPrevious as Previous,
|
|
601
|
+
CalendarNext as Next,
|
|
602
|
+
CalendarMonth as Month,
|
|
603
|
+
CalendarDay as Day,
|
|
604
|
+
};
|
package/carousel.js
CHANGED
|
@@ -128,7 +128,7 @@ hook useCarousel(part: string): CarouselState {
|
|
|
128
128
|
* hold a `Carousel.Pause`, and that one must be the first thing `Tab` reaches
|
|
129
129
|
* inside it; both are checked.
|
|
130
130
|
*/
|
|
131
|
-
|
|
131
|
+
component CarouselRoot(
|
|
132
132
|
children: React.Node,
|
|
133
133
|
autoplay?: number | null = null,
|
|
134
134
|
count: number,
|
|
@@ -264,7 +264,7 @@ export component CarouselRoot(
|
|
|
264
264
|
* four seconds is a page a screen reader cannot be used on. `"polite"` the rest
|
|
265
265
|
* of the time, so pressing Next says something.
|
|
266
266
|
*/
|
|
267
|
-
|
|
267
|
+
component CarouselContent(children: React.Node, ...rest: Rest) {
|
|
268
268
|
const carousel = useCarousel("Carousel.Content");
|
|
269
269
|
|
|
270
270
|
return (
|
|
@@ -288,7 +288,7 @@ export component CarouselContent(children: React.Node, ...rest: Rest) {
|
|
|
288
288
|
* takes the subtree out of the accessibility tree, which is what stops a reader
|
|
289
289
|
* being read six slides in a row.
|
|
290
290
|
*/
|
|
291
|
-
|
|
291
|
+
component CarouselItem(children: React.Node, index: number, ...rest: Rest) {
|
|
292
292
|
const carousel = useCarousel("Carousel.Item");
|
|
293
293
|
const current = index === carousel.index;
|
|
294
294
|
|
|
@@ -320,7 +320,7 @@ export component CarouselItem(children: React.Node, index: number, ...rest: Rest
|
|
|
320
320
|
* for: `aria-pressed` on a pause button is the announcement "pause, pressed",
|
|
321
321
|
* and a reader who has stopped a carousel wants to be told it is stopped.
|
|
322
322
|
*/
|
|
323
|
-
|
|
323
|
+
component CarouselPause(
|
|
324
324
|
children?: React.Node,
|
|
325
325
|
pauseLabel?: string = "Stop the carousel",
|
|
326
326
|
playLabel?: string = "Start the carousel",
|
|
@@ -354,7 +354,7 @@ export component CarouselPause(
|
|
|
354
354
|
}
|
|
355
355
|
|
|
356
356
|
/** The button that goes back one slide. */
|
|
357
|
-
|
|
357
|
+
component CarouselPrevious(
|
|
358
358
|
children?: React.Node,
|
|
359
359
|
label?: string = "Previous slide",
|
|
360
360
|
...rest: Rest
|
|
@@ -367,7 +367,7 @@ export component CarouselPrevious(
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
/** The button that goes forward one slide. */
|
|
370
|
-
|
|
370
|
+
component CarouselNext(children?: React.Node, label?: string = "Next slide", ...rest: Rest) {
|
|
371
371
|
return (
|
|
372
372
|
<CarouselStep {...forwarded(rest)} label={label} step={1}>
|
|
373
373
|
{children}
|
|
@@ -408,3 +408,21 @@ component CarouselStep(children?: React.Node, label: string, step: number, ...re
|
|
|
408
408
|
</button>
|
|
409
409
|
);
|
|
410
410
|
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* The parts, under the names the `Carousel` namespace gives them.
|
|
414
|
+
*
|
|
415
|
+
* `index.js` re-exports this module whole — `export * as Carousel from "./carousel.js"` —
|
|
416
|
+
* so a caller writes `<Carousel.Root>`, and the namespace is the prefix. Each
|
|
417
|
+
* part is still *declared* as `CarouselRoot`, so React DevTools, a component
|
|
418
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
419
|
+
* `Root`s.
|
|
420
|
+
*/
|
|
421
|
+
export {
|
|
422
|
+
CarouselRoot as Root,
|
|
423
|
+
CarouselContent as Content,
|
|
424
|
+
CarouselItem as Item,
|
|
425
|
+
CarouselPause as Pause,
|
|
426
|
+
CarouselPrevious as Previous,
|
|
427
|
+
CarouselNext as Next,
|
|
428
|
+
};
|
package/collapsible.js
CHANGED
|
@@ -91,7 +91,7 @@ hook useCollapsible(part: string): CollapsibleState {
|
|
|
91
91
|
* them that the caller then has to style around. `Menu.Root` makes the same
|
|
92
92
|
* choice for the same reason.
|
|
93
93
|
*/
|
|
94
|
-
|
|
94
|
+
component CollapsibleRoot(
|
|
95
95
|
children: React.Node,
|
|
96
96
|
defaultOpen?: boolean = false,
|
|
97
97
|
open?: boolean,
|
|
@@ -111,7 +111,7 @@ export component CollapsibleRoot(
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
/** The control that shows and hides the content. */
|
|
114
|
-
|
|
114
|
+
component CollapsibleTrigger(
|
|
115
115
|
children: React.Node,
|
|
116
116
|
disabled?: boolean = false,
|
|
117
117
|
render?: RenderProp,
|
|
@@ -146,7 +146,7 @@ export component CollapsibleTrigger(
|
|
|
146
146
|
* the module header, and `internal/disclosure.js` for what `hidden` is upgraded
|
|
147
147
|
* to and why that takes an effect.
|
|
148
148
|
*/
|
|
149
|
-
|
|
149
|
+
component CollapsibleContent(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
150
150
|
const collapsible = useCollapsible("Collapsible.Content");
|
|
151
151
|
const contentRef = useRef<HTMLElement | null>(null);
|
|
152
152
|
usePresence(collapsible.registerContent);
|
|
@@ -169,3 +169,14 @@ export component CollapsibleContent(children: React.Node, render?: RenderProp, .
|
|
|
169
169
|
}
|
|
170
170
|
return <div {...props} />;
|
|
171
171
|
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* The parts, under the names the `Collapsible` namespace gives them.
|
|
175
|
+
*
|
|
176
|
+
* `index.js` re-exports this module whole — `export * as Collapsible from "./collapsible.js"` —
|
|
177
|
+
* so a caller writes `<Collapsible.Root>`, and the namespace is the prefix. Each
|
|
178
|
+
* part is still *declared* as `CollapsibleRoot`, so React DevTools, a component
|
|
179
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
180
|
+
* `Root`s.
|
|
181
|
+
*/
|
|
182
|
+
export { CollapsibleRoot as Root, CollapsibleTrigger as Trigger, CollapsibleContent as Content };
|