@uniflowed/ui 0.2.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 +22 -5
- 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 +31 -10
- package/drawer.js +47 -34
- package/field.js +24 -6
- package/hover-card.js +14 -3
- package/index.js +89 -740
- package/input-otp.js +20 -4
- package/interactions.js +0 -1
- package/internal/focus.js +13 -4
- package/internal/roving-focus.js +12 -3
- 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 +20 -2
- 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 +32 -10
- package/tabs.js +15 -9
- package/toast.js +24 -6
- package/toggle-group.js +14 -3
- package/tooltip.js +21 -5
package/combobox.js
CHANGED
|
@@ -210,7 +210,7 @@ const ComboboxGroupContext: React.Context<ComboboxGroupState | null> = createCon
|
|
|
210
210
|
* `internal/form-value.js` says why it is an `<input>` and why
|
|
211
211
|
* `@uniflowed/form` does not need it.
|
|
212
212
|
*/
|
|
213
|
-
|
|
213
|
+
component ComboboxRoot(
|
|
214
214
|
children: React.Node,
|
|
215
215
|
value?: string | null,
|
|
216
216
|
defaultValue?: string | null = null,
|
|
@@ -294,7 +294,7 @@ export component ComboboxRoot(
|
|
|
294
294
|
* because the list names it, and naming a label that is not rendered is worse
|
|
295
295
|
* than leaving the list unnamed.
|
|
296
296
|
*/
|
|
297
|
-
|
|
297
|
+
component ComboboxLabel(children: React.Node, ...rest: Rest) {
|
|
298
298
|
const combobox = useCombobox("Combobox.Label");
|
|
299
299
|
const register = combobox.registerLabel;
|
|
300
300
|
useEffect(() => {
|
|
@@ -310,7 +310,7 @@ export component ComboboxLabel(children: React.Node, ...rest: Rest) {
|
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
/** The text field, and every key the pattern defines. */
|
|
313
|
-
|
|
313
|
+
component ComboboxInput(...rest: Rest) {
|
|
314
314
|
const combobox = useCombobox("Combobox.Input");
|
|
315
315
|
// `rest` filtering is render-time props work; ref objects are only passed through later.
|
|
316
316
|
// uf-lint-disable-next-line react-compiler/refs
|
|
@@ -442,7 +442,7 @@ export component ComboboxInput(...rest: Rest) {
|
|
|
442
442
|
* the count the live region announces, and the invariant that
|
|
443
443
|
* `aria-activedescendant` never names an option that has left the list.
|
|
444
444
|
*/
|
|
445
|
-
|
|
445
|
+
component ComboboxList(
|
|
446
446
|
children: renders* (ComboboxOption | ComboboxGroup),
|
|
447
447
|
align?: Align = "start",
|
|
448
448
|
alignOffset?: number = 0,
|
|
@@ -463,19 +463,13 @@ export component ComboboxList(
|
|
|
463
463
|
// `align="start"` because a list of options belongs under the edge the text
|
|
464
464
|
// starts at, and `--uf-anchor-trigger-width` is what a stylesheet reads to
|
|
465
465
|
// make it exactly as wide as the field.
|
|
466
|
-
// useAnchor accepts ref objects and reads them from layout/effects.
|
|
467
|
-
// uf-lint-disable-next-line react-compiler/refs
|
|
468
466
|
const anchored = useAnchor({
|
|
469
467
|
align,
|
|
470
468
|
alignOffset,
|
|
471
|
-
// uf-lint-disable-next-line react-compiler/refs
|
|
472
469
|
anchorRef: inputRef,
|
|
473
470
|
avoidCollisions,
|
|
474
471
|
collisionPadding,
|
|
475
|
-
// `open` is combobox metadata; no ref value is read during render.
|
|
476
|
-
// uf-lint-disable-next-line react-compiler/refs
|
|
477
472
|
open: combobox.open,
|
|
478
|
-
// uf-lint-disable-next-line react-compiler/refs
|
|
479
473
|
overlayRef: listRef,
|
|
480
474
|
side,
|
|
481
475
|
sideOffset,
|
|
@@ -486,8 +480,6 @@ export component ComboboxList(
|
|
|
486
480
|
// `children` that no dependency list can describe. Every write below is
|
|
487
481
|
// guarded by a comparison, so the effect settles after one extra pass rather
|
|
488
482
|
// than looping.
|
|
489
|
-
// This effect measures caller-rendered options after commit.
|
|
490
|
-
// uf-lint-disable-next-line react-compiler/immutability
|
|
491
483
|
useEffect(() => {
|
|
492
484
|
const list = listRef.current;
|
|
493
485
|
if (list == null) {
|
|
@@ -505,7 +497,6 @@ export component ComboboxList(
|
|
|
505
497
|
|
|
506
498
|
const wanted = pendingActiveRef.current;
|
|
507
499
|
if (wanted != null) {
|
|
508
|
-
// uf-lint-disable-next-line react-compiler/immutability
|
|
509
500
|
pendingActiveRef.current = null;
|
|
510
501
|
setActiveId(moveTo(items, -1, wanted, false)?.id ?? null);
|
|
511
502
|
return;
|
|
@@ -562,7 +553,7 @@ export component ComboboxList(
|
|
|
562
553
|
* finds the active option in the document rather than in a registry that could
|
|
563
554
|
* disagree with it.
|
|
564
555
|
*/
|
|
565
|
-
|
|
556
|
+
component ComboboxOption(
|
|
566
557
|
value: string,
|
|
567
558
|
children: React.Node,
|
|
568
559
|
label?: string,
|
|
@@ -629,10 +620,7 @@ export component ComboboxOption(
|
|
|
629
620
|
* and nothing else. `Select.Group` says the same since ubugeeei-prod/uf#562 —
|
|
630
621
|
* it is the same listbox, and it took a second breaking change to get there.
|
|
631
622
|
*/
|
|
632
|
-
|
|
633
|
-
children: renders* (ComboboxOption | ComboboxGroupLabel),
|
|
634
|
-
...rest: Rest
|
|
635
|
-
) {
|
|
623
|
+
component ComboboxGroup(children: renders* (ComboboxOption | ComboboxGroupLabel), ...rest: Rest) {
|
|
636
624
|
const base = useId();
|
|
637
625
|
const [labelled, setLabelled] = useState(false);
|
|
638
626
|
|
|
@@ -657,7 +645,7 @@ export component ComboboxGroup(
|
|
|
657
645
|
* This is not `Combobox.Label`. That one names the field; this one names a
|
|
658
646
|
* group of options, and a combobox with groups has both.
|
|
659
647
|
*/
|
|
660
|
-
|
|
648
|
+
component ComboboxGroupLabel(children: React.Node, ...rest: Rest) {
|
|
661
649
|
const group = useContext(ComboboxGroupContext);
|
|
662
650
|
const register = group?.registerLabel;
|
|
663
651
|
|
|
@@ -683,7 +671,7 @@ export component ComboboxGroupLabel(children: React.Node, ...rest: Rest) {
|
|
|
683
671
|
* contain options: an "no matches" row inside one is announced as an option a
|
|
684
672
|
* reader can choose, and choosing it does nothing.
|
|
685
673
|
*/
|
|
686
|
-
|
|
674
|
+
component ComboboxEmpty(children: React.Node, ...rest: Rest) {
|
|
687
675
|
const combobox = useCombobox("Combobox.Empty");
|
|
688
676
|
if (!combobox.open || combobox.count > 0) {
|
|
689
677
|
return null;
|
|
@@ -702,7 +690,7 @@ export component ComboboxEmpty(children: React.Node, ...rest: Rest) {
|
|
|
702
690
|
* `children` overrides the wording — the default is English and a real
|
|
703
691
|
* application has a translation table.
|
|
704
692
|
*/
|
|
705
|
-
|
|
693
|
+
component ComboboxStatus(children?: React.Node, ...rest: Rest) {
|
|
706
694
|
const combobox = useCombobox("Combobox.Status");
|
|
707
695
|
const message = children ?? defaultAnnouncement(combobox.open, combobox.count);
|
|
708
696
|
|
|
@@ -732,3 +720,24 @@ function labelOf(element: HTMLElement): string {
|
|
|
732
720
|
function textOf(element: HTMLElement): string {
|
|
733
721
|
return (element.textContent ?? "").replace(/\s+/g, " ").trim();
|
|
734
722
|
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* The parts, under the names the `Combobox` namespace gives them.
|
|
726
|
+
*
|
|
727
|
+
* `index.js` re-exports this module whole — `export * as Combobox from "./combobox.js"` —
|
|
728
|
+
* so a caller writes `<Combobox.Root>`, and the namespace is the prefix. Each
|
|
729
|
+
* part is still *declared* as `ComboboxRoot`, so React DevTools, a component
|
|
730
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
731
|
+
* `Root`s.
|
|
732
|
+
*/
|
|
733
|
+
export {
|
|
734
|
+
ComboboxRoot as Root,
|
|
735
|
+
ComboboxLabel as Label,
|
|
736
|
+
ComboboxInput as Input,
|
|
737
|
+
ComboboxList as List,
|
|
738
|
+
ComboboxOption as Option,
|
|
739
|
+
ComboboxGroup as Group,
|
|
740
|
+
ComboboxGroupLabel as GroupLabel,
|
|
741
|
+
ComboboxEmpty as Empty,
|
|
742
|
+
ComboboxStatus as Status,
|
|
743
|
+
};
|
package/context-menu.js
CHANGED
|
@@ -91,7 +91,7 @@ function pointAt(x: number, y: number): Rect {
|
|
|
91
91
|
* Renders no element of its own, for the reason `Menu.Root` gives: the trigger
|
|
92
92
|
* and the body are siblings in whatever layout the caller wrote.
|
|
93
93
|
*/
|
|
94
|
-
|
|
94
|
+
component ContextMenuRoot(
|
|
95
95
|
children: React.Node,
|
|
96
96
|
defaultOpen?: boolean = false,
|
|
97
97
|
open?: boolean,
|
|
@@ -131,7 +131,7 @@ hook usePoint(part: string): PointState {
|
|
|
131
131
|
* region of the page. The module header says why it is in the tab order and
|
|
132
132
|
* when a caller should take it out again.
|
|
133
133
|
*/
|
|
134
|
-
|
|
134
|
+
component ContextMenuTrigger(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
135
135
|
const menu = useMenu("ContextMenu.Trigger");
|
|
136
136
|
const { openAt } = usePoint("ContextMenu.Trigger");
|
|
137
137
|
const triggerRef = useRef<HTMLElement | null>(null);
|
|
@@ -213,3 +213,32 @@ export component ContextMenuTrigger(children: React.Node, render?: RenderProp, .
|
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
export type { MenuSelect } from "./menu.js";
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* The parts, under the names the `ContextMenu` namespace gives them.
|
|
219
|
+
*
|
|
220
|
+
* `index.js` re-exports this module whole — `export * as ContextMenu from "./context-menu.js"` —
|
|
221
|
+
* so a caller writes `<ContextMenu.Root>`, and the namespace is the prefix. Each
|
|
222
|
+
* part is still *declared* as `ContextMenuRoot`, so React DevTools, a component
|
|
223
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
224
|
+
* `Root`s.
|
|
225
|
+
*/
|
|
226
|
+
export { ContextMenuRoot as Root, ContextMenuTrigger as Trigger };
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The parts `ContextMenu` shares with `Menu`, re-exported so the `ContextMenu`
|
|
230
|
+
* namespace is complete on its own: `<ContextMenu.Body>` is `Menu`'s part,
|
|
231
|
+
* not a copy of it.
|
|
232
|
+
*/
|
|
233
|
+
export {
|
|
234
|
+
Body,
|
|
235
|
+
Item,
|
|
236
|
+
CheckboxItem,
|
|
237
|
+
RadioGroup,
|
|
238
|
+
RadioItem,
|
|
239
|
+
Separator,
|
|
240
|
+
Group,
|
|
241
|
+
Label,
|
|
242
|
+
Sub,
|
|
243
|
+
SubTrigger,
|
|
244
|
+
} from "./menu.js";
|
package/date-picker.js
CHANGED
|
@@ -51,17 +51,17 @@ import type { PlainDate } from "@uniflowed/core/temporal";
|
|
|
51
51
|
import { Temporal } from "@uniflowed/core/temporal";
|
|
52
52
|
|
|
53
53
|
import type { DateValue } from "./calendar.js";
|
|
54
|
-
import { CalendarRoot } from "./calendar.js";
|
|
54
|
+
import { Root as CalendarRoot } from "./calendar.js";
|
|
55
55
|
import { useControlled } from "./internal/controlled-state.js";
|
|
56
56
|
import type { Align, LogicalSide } from "./internal/anchor.js";
|
|
57
|
-
import type { Rest } from "./internal/merge-props.js";
|
|
57
|
+
import type { PartEvent, Rest } from "./internal/merge-props.js";
|
|
58
58
|
import {
|
|
59
59
|
composeHandlers,
|
|
60
60
|
composeRefs,
|
|
61
61
|
forwarded,
|
|
62
62
|
withoutComposed,
|
|
63
63
|
} from "./internal/merge-props.js";
|
|
64
|
-
import { PopoverBody, PopoverRoot, PopoverTrigger } from "./popover.js";
|
|
64
|
+
import { Body as PopoverBody, Root as PopoverRoot, Trigger as PopoverTrigger } from "./popover.js";
|
|
65
65
|
|
|
66
66
|
type DatePickerState = {|
|
|
67
67
|
/** The text in the field, which is the draft while one is being typed. */
|
|
@@ -118,7 +118,7 @@ function isoParse(text: string): PlainDate | null {
|
|
|
118
118
|
* siblings in whatever layout the caller wrote, and a wrapper would put a
|
|
119
119
|
* `<div>` between them that they then have to style around.
|
|
120
120
|
*/
|
|
121
|
-
|
|
121
|
+
component DatePickerRoot(
|
|
122
122
|
children: React.Node,
|
|
123
123
|
defaultOpen?: boolean = false,
|
|
124
124
|
defaultValue?: DateValue | null = null,
|
|
@@ -251,7 +251,17 @@ const CalendarSettings: React.Context<CalendarSettingsValue> = createContext({
|
|
|
251
251
|
* does not open the popover, the button beside it does, and telling a reader the
|
|
252
252
|
* field expands something would be a promise the field does not keep.
|
|
253
253
|
*/
|
|
254
|
-
|
|
254
|
+
/**
|
|
255
|
+
* The text in the field an event came from.
|
|
256
|
+
*
|
|
257
|
+
* `currentTarget` is the `input` this part renders, so it is always an
|
|
258
|
+
* `HTMLInputElement`. Asked rather than cast, so that the check is the type.
|
|
259
|
+
*/
|
|
260
|
+
function typedText(target: mixed): string {
|
|
261
|
+
return target instanceof HTMLInputElement ? target.value : "";
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
component DatePickerInput(...rest: Rest) {
|
|
255
265
|
const picker = useDatePicker("DatePicker.Input");
|
|
256
266
|
// `rest` filtering is render-time props work; ref objects are only passed through later.
|
|
257
267
|
// uf-lint-disable-next-line react-compiler/refs
|
|
@@ -264,12 +274,12 @@ export component DatePickerInput(...rest: Rest) {
|
|
|
264
274
|
// Input events commit typed text while focus stays on the field ref.
|
|
265
275
|
// uf-lint-disable-next-line react-compiler/refs
|
|
266
276
|
onBlur={composeHandlers(rest.onBlur, (event) => {
|
|
267
|
-
picker.commit((event.currentTarget
|
|
277
|
+
picker.commit(typedText(event.currentTarget));
|
|
268
278
|
})}
|
|
269
279
|
// Input events commit typed text while focus stays on the field ref.
|
|
270
280
|
// uf-lint-disable-next-line react-compiler/refs
|
|
271
281
|
onChange={composeHandlers(rest.onChange, (event) => {
|
|
272
|
-
picker.setDraft((event.currentTarget
|
|
282
|
+
picker.setDraft(typedText(event.currentTarget));
|
|
273
283
|
})}
|
|
274
284
|
// Key events commit typed text while focus stays on the field ref.
|
|
275
285
|
// uf-lint-disable-next-line react-compiler/refs
|
|
@@ -280,7 +290,7 @@ export component DatePickerInput(...rest: Rest) {
|
|
|
280
290
|
// Claimed, so a date picker inside a form is not a control where
|
|
281
291
|
// pressing Enter to confirm what you typed submits the page instead.
|
|
282
292
|
event.preventDefault();
|
|
283
|
-
picker.commit((event.currentTarget
|
|
293
|
+
picker.commit(typedText(event.currentTarget));
|
|
284
294
|
})}
|
|
285
295
|
// React calls callback refs during commit; the calendar and picker read the field later.
|
|
286
296
|
// uf-lint-disable-next-line react-compiler/refs
|
|
@@ -295,7 +305,7 @@ export component DatePickerInput(...rest: Rest) {
|
|
|
295
305
|
}
|
|
296
306
|
|
|
297
307
|
/** The button that opens the calendar. */
|
|
298
|
-
|
|
308
|
+
component DatePickerTrigger(children: React.Node, ...rest: Rest) {
|
|
299
309
|
// `forwarded`, because this part renders another part rather than an
|
|
300
310
|
// intrinsic; `internal/merge-props.js` says what that costs and why.
|
|
301
311
|
return <PopoverTrigger {...forwarded(rest)}>{children}</PopoverTrigger>;
|
|
@@ -308,7 +318,7 @@ export component DatePickerTrigger(children: React.Node, ...rest: Rest) {
|
|
|
308
318
|
* `Calendar.Month` — because where those sit is a design decision and there is
|
|
309
319
|
* no arrangement of them this module could impose that would suit every one.
|
|
310
320
|
*/
|
|
311
|
-
|
|
321
|
+
component DatePickerCalendar(
|
|
312
322
|
children: React.Node,
|
|
313
323
|
align?: Align = "start",
|
|
314
324
|
side?: LogicalSide = "bottom",
|
|
@@ -327,7 +337,7 @@ export component DatePickerCalendar(
|
|
|
327
337
|
// The date, not the first button in the popover. The APG's date picker
|
|
328
338
|
// dialog puts focus on the grid for the same reason.
|
|
329
339
|
initialFocus={dayRef}
|
|
330
|
-
onKeyDown={composeHandlers(rest.onKeyDown, (event) => {
|
|
340
|
+
onKeyDown={composeHandlers(rest.onKeyDown, (event: PartEvent) => {
|
|
331
341
|
if (event.key !== "Escape") {
|
|
332
342
|
return;
|
|
333
343
|
}
|
|
@@ -355,3 +365,19 @@ export component DatePickerCalendar(
|
|
|
355
365
|
</PopoverBody>
|
|
356
366
|
);
|
|
357
367
|
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* The parts, under the names the `DatePicker` namespace gives them.
|
|
371
|
+
*
|
|
372
|
+
* `index.js` re-exports this module whole — `export * as DatePicker from "./date-picker.js"` —
|
|
373
|
+
* so a caller writes `<DatePicker.Root>`, and the namespace is the prefix. Each
|
|
374
|
+
* part is still *declared* as `DatePickerRoot`, so React DevTools, a component
|
|
375
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
376
|
+
* `Root`s.
|
|
377
|
+
*/
|
|
378
|
+
export {
|
|
379
|
+
DatePickerRoot as Root,
|
|
380
|
+
DatePickerInput as Input,
|
|
381
|
+
DatePickerTrigger as Trigger,
|
|
382
|
+
DatePickerCalendar as Calendar,
|
|
383
|
+
};
|
package/date-range-picker.js
CHANGED
|
@@ -8,10 +8,10 @@ import type { Rest } from "./internal/merge-props.js";
|
|
|
8
8
|
import { forwarded } from "./internal/merge-props.js";
|
|
9
9
|
import type { DateRange } from "./internal/date-range.js";
|
|
10
10
|
import { validateRange, unavailableInRange } from "./internal/date-range.js";
|
|
11
|
-
import { CalendarMonth } from "./calendar.js";
|
|
12
|
-
import { RangeCalendarRoot } from "./range-calendar.js";
|
|
11
|
+
import { Month as CalendarMonth } from "./calendar.js";
|
|
12
|
+
import { Root as RangeCalendarRoot } from "./range-calendar.js";
|
|
13
13
|
import { DateField } from "./date-field.js";
|
|
14
|
-
import { PopoverRoot, PopoverBody, PopoverTrigger } from "./popover.js";
|
|
14
|
+
import { Root as PopoverRoot, Body as PopoverBody, Trigger as PopoverTrigger } from "./popover.js";
|
|
15
15
|
|
|
16
16
|
type Picker = {
|
|
17
17
|
range: DateRange | null,
|
|
@@ -27,7 +27,7 @@ hook usePicker(): Picker {
|
|
|
27
27
|
if (picker == null) throw new Error("DateRangePicker parts must be inside DateRangePicker.Root");
|
|
28
28
|
return picker;
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
component DateRangePickerRoot(
|
|
31
31
|
children: React.Node,
|
|
32
32
|
value?: DateRange | null,
|
|
33
33
|
defaultValue?: DateRange | null = null,
|
|
@@ -58,7 +58,7 @@ export component DateRangePickerRoot(
|
|
|
58
58
|
</PickerContext.Provider>
|
|
59
59
|
);
|
|
60
60
|
}
|
|
61
|
-
|
|
61
|
+
component DateRangePickerStartField(...rest: Rest) {
|
|
62
62
|
const picker = usePicker();
|
|
63
63
|
return (
|
|
64
64
|
<DateField
|
|
@@ -76,7 +76,7 @@ export component DateRangePickerStartField(...rest: Rest) {
|
|
|
76
76
|
/>
|
|
77
77
|
);
|
|
78
78
|
}
|
|
79
|
-
|
|
79
|
+
component DateRangePickerEndField(...rest: Rest) {
|
|
80
80
|
const picker = usePicker();
|
|
81
81
|
return (
|
|
82
82
|
<DateField
|
|
@@ -94,10 +94,10 @@ export component DateRangePickerEndField(...rest: Rest) {
|
|
|
94
94
|
/>
|
|
95
95
|
);
|
|
96
96
|
}
|
|
97
|
-
|
|
97
|
+
component DateRangePickerTrigger(children: React.Node, ...rest: Rest) {
|
|
98
98
|
return <PopoverTrigger {...forwarded(rest)}>{children}</PopoverTrigger>;
|
|
99
99
|
}
|
|
100
|
-
|
|
100
|
+
component DateRangePickerCalendar(children?: React.Node = <CalendarMonth />, ...rest: Rest) {
|
|
101
101
|
const picker = usePicker();
|
|
102
102
|
const dayRef = useRef<HTMLElement | null>(null);
|
|
103
103
|
return (
|
|
@@ -118,3 +118,20 @@ export component DateRangePickerCalendar(children?: React.Node = <CalendarMonth
|
|
|
118
118
|
</PopoverBody>
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The parts, under the names the `DateRangePicker` namespace gives them.
|
|
124
|
+
*
|
|
125
|
+
* `index.js` re-exports this module whole — `export * as DateRangePicker from "./date-range-picker.js"` —
|
|
126
|
+
* so a caller writes `<DateRangePicker.Root>`, and the namespace is the prefix. Each
|
|
127
|
+
* part is still *declared* as `DateRangePickerRoot`, so React DevTools, a component
|
|
128
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
129
|
+
* `Root`s.
|
|
130
|
+
*/
|
|
131
|
+
export {
|
|
132
|
+
DateRangePickerRoot as Root,
|
|
133
|
+
DateRangePickerStartField as StartField,
|
|
134
|
+
DateRangePickerEndField as EndField,
|
|
135
|
+
DateRangePickerTrigger as Trigger,
|
|
136
|
+
DateRangePickerCalendar as Calendar,
|
|
137
|
+
};
|
package/dialog.js
CHANGED
|
@@ -133,7 +133,7 @@ hook useDialog(part: string): DialogState {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/** The dialog, open or closed. Uncontrolled unless `open` is given. */
|
|
136
|
-
|
|
136
|
+
component DialogRoot(
|
|
137
137
|
children: React.Node,
|
|
138
138
|
defaultOpen?: boolean = false,
|
|
139
139
|
open?: boolean,
|
|
@@ -170,7 +170,7 @@ export component DialogRoot(
|
|
|
170
170
|
* else, which is what keeps "focus comes back here" true of whatever the
|
|
171
171
|
* caller rendered.
|
|
172
172
|
*/
|
|
173
|
-
|
|
173
|
+
component DialogTrigger(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
174
174
|
const dialog = useDialog("Dialog.Trigger");
|
|
175
175
|
const props = withProps(withoutComposed(rest, ["onClick", "ref"]), {
|
|
176
176
|
// Only while it is open. An `aria-controls` naming an element that is not
|
|
@@ -203,7 +203,7 @@ export component DialogTrigger(children: React.Node, render?: RenderProp, ...res
|
|
|
203
203
|
* their own backdrop or omits one entirely must still get it. That lives on
|
|
204
204
|
* `Dialog.Body`, which is the part that knows where "outside" is.
|
|
205
205
|
*/
|
|
206
|
-
|
|
206
|
+
component DialogOverlay(render?: RenderProp, ...rest: Rest) {
|
|
207
207
|
const dialog = useDialog("Dialog.Overlay");
|
|
208
208
|
if (!dialog.open) {
|
|
209
209
|
return null;
|
|
@@ -222,7 +222,7 @@ export component DialogOverlay(render?: RenderProp, ...rest: Rest) {
|
|
|
222
222
|
* which is the half of "modal" that CSS cannot express; `inert` on everything
|
|
223
223
|
* outside is the half the browser enforces.
|
|
224
224
|
*/
|
|
225
|
-
|
|
225
|
+
component DialogBody(
|
|
226
226
|
children: React.Node,
|
|
227
227
|
dismissOnOutsidePress?: boolean = true,
|
|
228
228
|
initialFocus?: { current: HTMLElement | null },
|
|
@@ -381,7 +381,7 @@ export component DialogBody(
|
|
|
381
381
|
* rendered — a conditional title that is absent used to leave the dialog
|
|
382
382
|
* pointing at an id nothing had.
|
|
383
383
|
*/
|
|
384
|
-
|
|
384
|
+
component DialogTitle(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
385
385
|
const dialog = useDialog("Dialog.Title");
|
|
386
386
|
const register = dialog.registerTitle;
|
|
387
387
|
useEffect(() => {
|
|
@@ -407,7 +407,7 @@ export component DialogTitle(children: React.Node, render?: RenderProp, ...rest:
|
|
|
407
407
|
* the one moment the reader has to decide whether they care — so this is where
|
|
408
408
|
* "this cannot be undone" belongs, not in body text further down.
|
|
409
409
|
*/
|
|
410
|
-
|
|
410
|
+
component DialogDescription(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
411
411
|
const dialog = useDialog("Dialog.Description");
|
|
412
412
|
const register = dialog.registerDescription;
|
|
413
413
|
useEffect(() => {
|
|
@@ -431,7 +431,7 @@ export component DialogDescription(children: React.Node, render?: RenderProp, ..
|
|
|
431
431
|
* styling layer has a name to attach to, and contributes no semantics because
|
|
432
432
|
* it has none to contribute.
|
|
433
433
|
*/
|
|
434
|
-
|
|
434
|
+
component DialogHeader(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
435
435
|
const props = withProps(rest, { children });
|
|
436
436
|
if (render != null) {
|
|
437
437
|
return render(props);
|
|
@@ -440,7 +440,7 @@ export component DialogHeader(children: React.Node, render?: RenderProp, ...rest
|
|
|
440
440
|
}
|
|
441
441
|
|
|
442
442
|
/** The bottom of the dialog, where the actions go. See `Dialog.Header`. */
|
|
443
|
-
|
|
443
|
+
component DialogFooter(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
444
444
|
const props = withProps(rest, { children });
|
|
445
445
|
if (render != null) {
|
|
446
446
|
return render(props);
|
|
@@ -449,7 +449,7 @@ export component DialogFooter(children: React.Node, render?: RenderProp, ...rest
|
|
|
449
449
|
}
|
|
450
450
|
|
|
451
451
|
/** A button that closes the dialog. */
|
|
452
|
-
|
|
452
|
+
component DialogClose(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
453
453
|
const dialog = useDialog("Dialog.Close");
|
|
454
454
|
const props = withProps(withoutComposed(rest, ["onClick"]), {
|
|
455
455
|
children,
|
|
@@ -500,7 +500,7 @@ function concealOutside(element: HTMLElement): () => void {
|
|
|
500
500
|
}
|
|
501
501
|
restore.push({
|
|
502
502
|
element: sibling,
|
|
503
|
-
hidden: sibling.getAttribute("aria-hidden"),
|
|
503
|
+
hidden: sibling.getAttribute("aria-hidden") ?? null,
|
|
504
504
|
inert: sibling.hasAttribute("inert"),
|
|
505
505
|
});
|
|
506
506
|
sibling.setAttribute("aria-hidden", "true");
|
|
@@ -525,3 +525,24 @@ function concealOutside(element: HTMLElement): () => void {
|
|
|
525
525
|
}
|
|
526
526
|
};
|
|
527
527
|
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* The parts, under the names the `Dialog` namespace gives them.
|
|
531
|
+
*
|
|
532
|
+
* `index.js` re-exports this module whole — `export * as Dialog from "./dialog.js"` —
|
|
533
|
+
* so a caller writes `<Dialog.Root>`, and the namespace is the prefix. Each
|
|
534
|
+
* part is still *declared* as `DialogRoot`, so React DevTools, a component
|
|
535
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
536
|
+
* `Root`s.
|
|
537
|
+
*/
|
|
538
|
+
export {
|
|
539
|
+
DialogRoot as Root,
|
|
540
|
+
DialogTrigger as Trigger,
|
|
541
|
+
DialogOverlay as Overlay,
|
|
542
|
+
DialogBody as Body,
|
|
543
|
+
DialogHeader as Header,
|
|
544
|
+
DialogFooter as Footer,
|
|
545
|
+
DialogTitle as Title,
|
|
546
|
+
DialogDescription as Description,
|
|
547
|
+
DialogClose as Close,
|
|
548
|
+
};
|
package/drawer.js
CHANGED
|
@@ -62,15 +62,15 @@ import {
|
|
|
62
62
|
withoutComposed,
|
|
63
63
|
} from "./internal/merge-props.js";
|
|
64
64
|
import {
|
|
65
|
-
SheetBody,
|
|
66
|
-
SheetClose,
|
|
67
|
-
SheetDescription,
|
|
68
|
-
SheetFooter,
|
|
69
|
-
SheetHeader,
|
|
70
|
-
SheetOverlay,
|
|
71
|
-
SheetRoot,
|
|
72
|
-
SheetTitle,
|
|
73
|
-
SheetTrigger,
|
|
65
|
+
Body as SheetBody,
|
|
66
|
+
Close as SheetClose,
|
|
67
|
+
Description as SheetDescription,
|
|
68
|
+
Footer as SheetFooter,
|
|
69
|
+
Header as SheetHeader,
|
|
70
|
+
Overlay as SheetOverlay,
|
|
71
|
+
Root as SheetRoot,
|
|
72
|
+
Title as SheetTitle,
|
|
73
|
+
Trigger as SheetTrigger,
|
|
74
74
|
} from "./sheet.js";
|
|
75
75
|
import { useControlled } from "./internal/controlled-state.js";
|
|
76
76
|
|
|
@@ -132,7 +132,7 @@ hook useDrawer(part: string): DrawerState {
|
|
|
132
132
|
* `onOpenChange` behave exactly as they do everywhere else in this package,
|
|
133
133
|
* because `internal/controlled-state.js` is what answers here too.
|
|
134
134
|
*/
|
|
135
|
-
|
|
135
|
+
component DrawerRoot(
|
|
136
136
|
children: React.Node,
|
|
137
137
|
defaultOpen?: boolean = false,
|
|
138
138
|
defaultSnapPoint?: number = 0,
|
|
@@ -173,7 +173,7 @@ export component DrawerRoot(
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
/** What opens it, and what focus comes back to when it closes. */
|
|
176
|
-
|
|
176
|
+
component DrawerTrigger(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
177
177
|
return (
|
|
178
178
|
<SheetTrigger {...forwarded(rest)} render={render}>
|
|
179
179
|
{children}
|
|
@@ -182,7 +182,7 @@ export component DrawerTrigger(children: React.Node, render?: RenderProp, ...res
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
/** The backdrop. It carries the edge, the same as a sheet's. */
|
|
185
|
-
|
|
185
|
+
component DrawerOverlay(render?: RenderProp, ...rest: Rest) {
|
|
186
186
|
return <SheetOverlay {...forwarded(rest)} render={render} />;
|
|
187
187
|
}
|
|
188
188
|
|
|
@@ -194,7 +194,7 @@ export component DrawerOverlay(render?: RenderProp, ...rest: Rest) {
|
|
|
194
194
|
* no drag to provide an alternative to — and a drawer with a handle and no
|
|
195
195
|
* `Drawer.Close` has a gesture that is the only way out.
|
|
196
196
|
*/
|
|
197
|
-
|
|
197
|
+
component DrawerBody(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
198
198
|
const drawer = useDrawer("Drawer.Body");
|
|
199
199
|
const { bodyRef, snapIndex, snapPoints } = drawer;
|
|
200
200
|
const reducedMotion = usePrefersReducedMotion();
|
|
@@ -260,7 +260,7 @@ component RequireCloseForTheDrag() {
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
/** The top of the drawer, where the handle usually goes. */
|
|
263
|
-
|
|
263
|
+
component DrawerHeader(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
264
264
|
return (
|
|
265
265
|
<SheetHeader {...forwarded(rest)} render={render}>
|
|
266
266
|
{children}
|
|
@@ -269,7 +269,7 @@ export component DrawerHeader(children: React.Node, render?: RenderProp, ...rest
|
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
/** The bottom of the drawer, where the actions go. */
|
|
272
|
-
|
|
272
|
+
component DrawerFooter(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
273
273
|
return (
|
|
274
274
|
<SheetFooter {...forwarded(rest)} render={render}>
|
|
275
275
|
{children}
|
|
@@ -278,7 +278,7 @@ export component DrawerFooter(children: React.Node, render?: RenderProp, ...rest
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
/** The drawer's accessible name. */
|
|
281
|
-
|
|
281
|
+
component DrawerTitle(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
282
282
|
return (
|
|
283
283
|
<SheetTitle {...forwarded(rest)} render={render}>
|
|
284
284
|
{children}
|
|
@@ -287,7 +287,7 @@ export component DrawerTitle(children: React.Node, render?: RenderProp, ...rest:
|
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
/** What the drawer is for, announced after its name. */
|
|
290
|
-
|
|
290
|
+
component DrawerDescription(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
291
291
|
return (
|
|
292
292
|
<SheetDescription {...forwarded(rest)} render={render}>
|
|
293
293
|
{children}
|
|
@@ -301,7 +301,7 @@ export component DrawerDescription(children: React.Node, render?: RenderProp, ..
|
|
|
301
301
|
*
|
|
302
302
|
* It registers itself so `Drawer.Body` can tell whether the gesture has one.
|
|
303
303
|
*/
|
|
304
|
-
|
|
304
|
+
component DrawerClose(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
305
305
|
const drawer = useDrawer("Drawer.Close");
|
|
306
306
|
const closeCountRef = drawer.closeCountRef;
|
|
307
307
|
|
|
@@ -336,11 +336,7 @@ export component DrawerClose(children: React.Node, render?: RenderProp, ...rest:
|
|
|
336
336
|
* `label` because a slider with no accessible name is announced as "slider",
|
|
337
337
|
* which is the same failure `Resizable.Handle` names.
|
|
338
338
|
*/
|
|
339
|
-
|
|
340
|
-
label?: string = "Resize the drawer",
|
|
341
|
-
render?: RenderProp,
|
|
342
|
-
...rest: Rest
|
|
343
|
-
) {
|
|
339
|
+
component DrawerHandle(label?: string = "Resize the drawer", render?: RenderProp, ...rest: Rest) {
|
|
344
340
|
const drawer = useDrawer("Drawer.Handle");
|
|
345
341
|
const { bodyRef, close, handleCountRef, setSnapIndex, side, snapIndex, snapPoints } = drawer;
|
|
346
342
|
const passed = withoutComposed(rest, [
|
|
@@ -359,17 +355,12 @@ export component DrawerHandle(
|
|
|
359
355
|
// So `Drawer.Body` knows there is a drag to provide an alternative to. A
|
|
360
356
|
// drawer with no handle has no gesture, and requiring a close button of one
|
|
361
357
|
// would be this component inventing a rule WCAG did not write.
|
|
362
|
-
useEffect(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
},
|
|
369
|
-
// The context ref object is stable; the effect registers this part's mount.
|
|
370
|
-
// uf-lint-disable-next-line react-compiler/refs
|
|
371
|
-
[handleCountRef],
|
|
372
|
-
);
|
|
358
|
+
useEffect(() => {
|
|
359
|
+
handleCountRef.current += 1;
|
|
360
|
+
return () => {
|
|
361
|
+
handleCountRef.current -= 1;
|
|
362
|
+
};
|
|
363
|
+
}, [handleCountRef]);
|
|
373
364
|
|
|
374
365
|
/** Move by one snap point, or close when there is no smaller one. */
|
|
375
366
|
const step = (towardsOpen: boolean) => {
|
|
@@ -502,3 +493,25 @@ const CLOSES_WITH: { readonly [Edge]: string } = {
|
|
|
502
493
|
right: "ArrowRight",
|
|
503
494
|
top: "ArrowUp",
|
|
504
495
|
};
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* The parts, under the names the `Drawer` namespace gives them.
|
|
499
|
+
*
|
|
500
|
+
* `index.js` re-exports this module whole — `export * as Drawer from "./drawer.js"` —
|
|
501
|
+
* so a caller writes `<Drawer.Root>`, and the namespace is the prefix. Each
|
|
502
|
+
* part is still *declared* as `DrawerRoot`, so React DevTools, a component
|
|
503
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
504
|
+
* `Root`s.
|
|
505
|
+
*/
|
|
506
|
+
export {
|
|
507
|
+
DrawerRoot as Root,
|
|
508
|
+
DrawerTrigger as Trigger,
|
|
509
|
+
DrawerOverlay as Overlay,
|
|
510
|
+
DrawerBody as Body,
|
|
511
|
+
DrawerHandle as Handle,
|
|
512
|
+
DrawerHeader as Header,
|
|
513
|
+
DrawerFooter as Footer,
|
|
514
|
+
DrawerTitle as Title,
|
|
515
|
+
DrawerDescription as Description,
|
|
516
|
+
DrawerClose as Close,
|
|
517
|
+
};
|