@uniflowed/ui 0.2.0 → 0.4.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/input-otp.js
CHANGED
|
@@ -112,7 +112,7 @@ function clean(raw: string, kind: InputOtpKind, length: number): string {
|
|
|
112
112
|
* Renders no element of its own beyond the input — see the module header. The
|
|
113
113
|
* caller's props go on the input, because the input is the field.
|
|
114
114
|
*/
|
|
115
|
-
|
|
115
|
+
component InputOtpRoot(
|
|
116
116
|
children: React.Node,
|
|
117
117
|
defaultValue?: string = "",
|
|
118
118
|
disabled?: boolean = false,
|
|
@@ -173,7 +173,7 @@ export component InputOtpRoot(
|
|
|
173
173
|
* already been announced, and a reader told "group, 3, group, 4" is being read
|
|
174
174
|
* a picture.
|
|
175
175
|
*/
|
|
176
|
-
|
|
176
|
+
component InputOtpGroup(children: React.Node, ...rest: Rest) {
|
|
177
177
|
return (
|
|
178
178
|
<div {...rest} aria-hidden="true">
|
|
179
179
|
{children}
|
|
@@ -188,7 +188,7 @@ export component InputOtpGroup(children: React.Node, ...rest: Rest) {
|
|
|
188
188
|
* whether there is one in it already, so a stylesheet can draw a cursor and a
|
|
189
189
|
* border without this module having an opinion about either.
|
|
190
190
|
*/
|
|
191
|
-
|
|
191
|
+
component InputOtpSlot(children?: React.Node, index: number, ...rest: Rest) {
|
|
192
192
|
const otp = useInputOtp("InputOtp.Slot");
|
|
193
193
|
const character = otp.value[index] ?? "";
|
|
194
194
|
// The box the next character goes in, clamped so a full code lights its last
|
|
@@ -209,10 +209,26 @@ export component InputOtpSlot(children?: React.Node, index: number, ...rest: Res
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
/** The dash between two groups. Decoration, and it says so. */
|
|
212
|
-
|
|
212
|
+
component InputOtpSeparator(children?: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
213
213
|
const props = withProps(rest, { "aria-hidden": "true", children });
|
|
214
214
|
if (render != null) {
|
|
215
215
|
return render(props);
|
|
216
216
|
}
|
|
217
217
|
return <div {...props} />;
|
|
218
218
|
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* The parts, under the names the `InputOtp` namespace gives them.
|
|
222
|
+
*
|
|
223
|
+
* `index.js` re-exports this module whole — `export * as InputOtp from "./input-otp.js"` —
|
|
224
|
+
* so a caller writes `<InputOtp.Root>`, and the namespace is the prefix. Each
|
|
225
|
+
* part is still *declared* as `InputOtpRoot`, so React DevTools, a component
|
|
226
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
227
|
+
* `Root`s.
|
|
228
|
+
*/
|
|
229
|
+
export {
|
|
230
|
+
InputOtpRoot as Root,
|
|
231
|
+
InputOtpGroup as Group,
|
|
232
|
+
InputOtpSlot as Slot,
|
|
233
|
+
InputOtpSeparator as Separator,
|
|
234
|
+
};
|
package/interactions.js
CHANGED
|
@@ -1798,7 +1798,6 @@ hook useDescription(text: string | void): string | void {
|
|
|
1798
1798
|
const entry: SharedDescription = shared;
|
|
1799
1799
|
entry.users += 1;
|
|
1800
1800
|
// The id is state because it must render only after the shared DOM node exists.
|
|
1801
|
-
// uf-lint-disable-next-line react-compiler/set-state-in-effect
|
|
1802
1801
|
setId(entry.node.id);
|
|
1803
1802
|
return () => {
|
|
1804
1803
|
entry.users -= 1;
|
package/internal/focus.js
CHANGED
|
@@ -52,13 +52,22 @@ export const FOCUS_STOPS: string =
|
|
|
52
52
|
* document.
|
|
53
53
|
*/
|
|
54
54
|
export function focusable(root: HTMLElement): Array<HTMLElement> {
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
const found: Array<HTMLElement> = [];
|
|
56
|
+
for (const element of root.querySelectorAll(FOCUS_STOPS)) {
|
|
57
|
+
if (
|
|
58
|
+
// Asked rather than annotated: `querySelectorAll` answers `Element`, and
|
|
59
|
+
// what focus lands on is an HTML or SVG element, both `HTMLElement` to
|
|
60
|
+
// Flow.
|
|
61
|
+
(element instanceof HTMLElement || element instanceof SVGElement) &&
|
|
57
62
|
// All three hide a whole subtree, so all three are asked of the
|
|
58
63
|
// ancestors; see the module header for what reading them off the element
|
|
59
64
|
// alone let through.
|
|
60
65
|
element.closest("[hidden]") == null &&
|
|
61
66
|
element.closest("[inert]") == null &&
|
|
62
|
-
element.closest('[aria-hidden="true"]') == null
|
|
63
|
-
|
|
67
|
+
element.closest('[aria-hidden="true"]') == null
|
|
68
|
+
) {
|
|
69
|
+
found.push(element);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return found;
|
|
64
73
|
}
|
package/internal/roving-focus.js
CHANGED
|
@@ -69,9 +69,18 @@ const TYPEAHEAD_WINDOW = 500;
|
|
|
69
69
|
* cannot see.
|
|
70
70
|
*/
|
|
71
71
|
export function itemsOf(container: HTMLElement, item: string, owner: string): Array<HTMLElement> {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
const found: Array<HTMLElement> = [];
|
|
73
|
+
for (const element of container.querySelectorAll(item)) {
|
|
74
|
+
// An item is an HTML or SVG element, both `HTMLElement` to Flow; asked
|
|
75
|
+
// rather than annotated, because `querySelectorAll` answers `Element`.
|
|
76
|
+
if (
|
|
77
|
+
(element instanceof HTMLElement || element instanceof SVGElement) &&
|
|
78
|
+
element.closest(owner) === container
|
|
79
|
+
) {
|
|
80
|
+
found.push(element);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return found;
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
/**
|
package/menu.js
CHANGED
|
@@ -180,7 +180,7 @@ const MenuRadioContext: React.Context<MenuRadioState | null> = createContext(nul
|
|
|
180
180
|
* whatever layout the caller wrote, and a wrapper would put a `<div>` between
|
|
181
181
|
* them that the caller then has to style around.
|
|
182
182
|
*/
|
|
183
|
-
|
|
183
|
+
component MenuRoot(
|
|
184
184
|
children: React.Node,
|
|
185
185
|
defaultOpen?: boolean = false,
|
|
186
186
|
open?: boolean,
|
|
@@ -200,7 +200,7 @@ export component MenuRoot(
|
|
|
200
200
|
* parent — and that difference is what `ArrowLeft`, `Escape` and "choosing an
|
|
201
201
|
* item closes everything" are all defined in terms of.
|
|
202
202
|
*/
|
|
203
|
-
|
|
203
|
+
component MenuSub(
|
|
204
204
|
children: React.Node,
|
|
205
205
|
defaultOpen?: boolean = false,
|
|
206
206
|
open?: boolean,
|
|
@@ -218,7 +218,7 @@ export component MenuSub(
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
/** The button that opens the menu. */
|
|
221
|
-
|
|
221
|
+
component MenuTrigger(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
222
222
|
const menu = useMenu("Menu.Trigger");
|
|
223
223
|
useTriggerRegistration(menu);
|
|
224
224
|
const props = withProps(withoutComposed(rest, ["onClick", "onKeyDown", "ref"]), {
|
|
@@ -269,7 +269,7 @@ export component MenuTrigger(children: React.Node, render?: RenderProp, ...rest:
|
|
|
269
269
|
* and only the container can answer it. Items still get their own `Enter` and
|
|
270
270
|
* `Space` from being buttons.
|
|
271
271
|
*/
|
|
272
|
-
|
|
272
|
+
component MenuBody(
|
|
273
273
|
children: renders* (
|
|
274
274
|
| MenuItem
|
|
275
275
|
| MenuCheckboxItem
|
|
@@ -323,7 +323,6 @@ export component MenuBody(
|
|
|
323
323
|
// `open` is menu-tree metadata; no ref value is read during render.
|
|
324
324
|
// uf-lint-disable-next-line react-compiler/refs
|
|
325
325
|
open: menu.open,
|
|
326
|
-
// uf-lint-disable-next-line react-compiler/refs
|
|
327
326
|
overlayRef: bodyRef,
|
|
328
327
|
side: placement,
|
|
329
328
|
sideOffset,
|
|
@@ -551,7 +550,7 @@ hook useMenuItem(
|
|
|
551
550
|
* tree. That combination is what shadcn's copy step is usually reached for, and
|
|
552
551
|
* what this package offers instead of it.
|
|
553
552
|
*/
|
|
554
|
-
|
|
553
|
+
component MenuItem(
|
|
555
554
|
children: React.Node,
|
|
556
555
|
disabled?: boolean = false,
|
|
557
556
|
closeOnSelect?: boolean = true,
|
|
@@ -593,7 +592,7 @@ export component MenuItem(
|
|
|
593
592
|
* summarises other checkboxes — `checkbox.js` has it, and a menu item is a
|
|
594
593
|
* command rather than a summary of a table's rows.
|
|
595
594
|
*/
|
|
596
|
-
|
|
595
|
+
component MenuCheckboxItem(
|
|
597
596
|
children: React.Node,
|
|
598
597
|
checked?: boolean,
|
|
599
598
|
defaultChecked?: boolean = false,
|
|
@@ -640,7 +639,7 @@ export component MenuCheckboxItem(
|
|
|
640
639
|
* a state the group starts in and never an event it reports, because no gesture
|
|
641
640
|
* inside it unchooses an answer.
|
|
642
641
|
*/
|
|
643
|
-
|
|
642
|
+
component MenuRadioGroup(
|
|
644
643
|
children: renders* (MenuRadioItem | MenuLabel | MenuSeparator),
|
|
645
644
|
defaultValue?: string | null = null,
|
|
646
645
|
value?: string | null,
|
|
@@ -688,7 +687,7 @@ export component MenuRadioGroup(
|
|
|
688
687
|
* what a sort order or a zoom level in a native menu does; `closeOnSelect` is
|
|
689
688
|
* the way to say otherwise for a choice that ends the visit.
|
|
690
689
|
*/
|
|
691
|
-
|
|
690
|
+
component MenuRadioItem(
|
|
692
691
|
children: React.Node,
|
|
693
692
|
value: string,
|
|
694
693
|
disabled?: boolean = false,
|
|
@@ -728,7 +727,7 @@ export component MenuRadioItem(
|
|
|
728
727
|
* is why it reads the list context of the menu around it and the menu context
|
|
729
728
|
* of the one below it.
|
|
730
729
|
*/
|
|
731
|
-
|
|
730
|
+
component MenuSubTrigger(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
732
731
|
const menu = useMenu("Menu.SubTrigger");
|
|
733
732
|
const list = useContext(MenuListContext);
|
|
734
733
|
const setActiveId = list?.setActiveId;
|
|
@@ -785,7 +784,7 @@ export component MenuSubTrigger(children: React.Node, render?: RenderProp, ...re
|
|
|
785
784
|
* moving through the menu is told the group changed. It is not focusable and
|
|
786
785
|
* the arrow keys pass straight over it.
|
|
787
786
|
*/
|
|
788
|
-
|
|
787
|
+
component MenuSeparator(render?: RenderProp, ...rest: Rest) {
|
|
789
788
|
const props = withProps(rest, { "aria-orientation": "horizontal", role: "separator" });
|
|
790
789
|
if (render != null) {
|
|
791
790
|
return render(props);
|
|
@@ -801,7 +800,7 @@ export component MenuSeparator(render?: RenderProp, ...rest: Rest) {
|
|
|
801
800
|
* that is not in the document makes a screen reader announce *nothing*, which
|
|
802
801
|
* is worse than an unnamed group.
|
|
803
802
|
*/
|
|
804
|
-
|
|
803
|
+
component MenuGroup(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
805
804
|
const base = useId();
|
|
806
805
|
const [labelled, setLabelled] = useState(false);
|
|
807
806
|
|
|
@@ -826,7 +825,7 @@ export component MenuGroup(children: React.Node, render?: RenderProp, ...rest: R
|
|
|
826
825
|
* as ordinary content would have a reader hear the heading once as the group's
|
|
827
826
|
* name and again as a stray line of text between the items.
|
|
828
827
|
*/
|
|
829
|
-
|
|
828
|
+
component MenuLabel(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
830
829
|
const group = useContext(MenuGroupContext);
|
|
831
830
|
const register = group?.registerLabel;
|
|
832
831
|
|
|
@@ -844,3 +843,27 @@ export component MenuLabel(children: React.Node, render?: RenderProp, ...rest: R
|
|
|
844
843
|
}
|
|
845
844
|
return <div {...props} />;
|
|
846
845
|
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* The parts, under the names the `Menu` namespace gives them.
|
|
849
|
+
*
|
|
850
|
+
* `index.js` re-exports this module whole — `export * as Menu from "./menu.js"` —
|
|
851
|
+
* so a caller writes `<Menu.Root>`, and the namespace is the prefix. Each
|
|
852
|
+
* part is still *declared* as `MenuRoot`, so React DevTools, a component
|
|
853
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
854
|
+
* `Root`s.
|
|
855
|
+
*/
|
|
856
|
+
export {
|
|
857
|
+
MenuRoot as Root,
|
|
858
|
+
MenuTrigger as Trigger,
|
|
859
|
+
MenuBody as Body,
|
|
860
|
+
MenuItem as Item,
|
|
861
|
+
MenuCheckboxItem as CheckboxItem,
|
|
862
|
+
MenuRadioGroup as RadioGroup,
|
|
863
|
+
MenuRadioItem as RadioItem,
|
|
864
|
+
MenuSeparator as Separator,
|
|
865
|
+
MenuGroup as Group,
|
|
866
|
+
MenuLabel as Label,
|
|
867
|
+
MenuSub as Sub,
|
|
868
|
+
MenuSubTrigger as SubTrigger,
|
|
869
|
+
};
|
package/menubar.js
CHANGED
|
@@ -128,7 +128,7 @@ hook useMenubar(part: string): MenubarState {
|
|
|
128
128
|
* a page with an application menubar and a formatting toolbar has two, and
|
|
129
129
|
* "menu bar" twice tells a reader nothing about which is which.
|
|
130
130
|
*/
|
|
131
|
-
|
|
131
|
+
component MenubarRoot(children: renders* MenubarMenu, render?: RenderProp, ...rest: Rest) {
|
|
132
132
|
const barRef = useRef<HTMLElement | null>(null);
|
|
133
133
|
const [open, setOpenValue] = useState<string | null>(null);
|
|
134
134
|
const [active, setActive] = useState<string | null>(null);
|
|
@@ -208,7 +208,7 @@ export component MenubarRoot(children: renders* MenubarMenu, render?: RenderProp
|
|
|
208
208
|
* Renders no element of its own, for the reason `Menu.Root` gives: a trigger and
|
|
209
209
|
* its body are siblings in whatever layout the caller wrote.
|
|
210
210
|
*/
|
|
211
|
-
|
|
211
|
+
component MenubarMenu(children: React.Node, value: string) {
|
|
212
212
|
const bar = useMenubar("Menubar.Menu");
|
|
213
213
|
const setOpen = bar.setOpen;
|
|
214
214
|
const onOpenChange = useCallback(
|
|
@@ -237,7 +237,7 @@ export component MenubarMenu(children: React.Node, value: string) {
|
|
|
237
237
|
* menubar — a reader is told "File, menu item, has popup, 1 of 3" — and it is
|
|
238
238
|
* what makes the bar's arrow keys agree with what they were told is in it.
|
|
239
239
|
*/
|
|
240
|
-
|
|
240
|
+
component MenubarTrigger(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
241
241
|
const bar = useMenubar("Menubar.Trigger");
|
|
242
242
|
const menu = useMenu("Menubar.Trigger");
|
|
243
243
|
const value = useContext(MenubarMenuContext);
|
|
@@ -278,8 +278,6 @@ export component MenubarTrigger(children: React.Node, render?: RenderProp, ...re
|
|
|
278
278
|
menu.pendingFocusRef.current = end;
|
|
279
279
|
bar.setOpen(value);
|
|
280
280
|
}),
|
|
281
|
-
// React calls callback refs during commit; menu focus restoration reads it later.
|
|
282
|
-
// uf-lint-disable-next-line react-compiler/refs
|
|
283
281
|
ref: composeRefs(rest.ref, (element: HTMLElement | null) => {
|
|
284
282
|
// uf-lint-disable-next-line react-compiler/immutability
|
|
285
283
|
menu.triggerRef.current = element;
|
|
@@ -293,3 +291,32 @@ export component MenubarTrigger(children: React.Node, render?: RenderProp, ...re
|
|
|
293
291
|
}
|
|
294
292
|
return <button {...props} type="button" />;
|
|
295
293
|
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* The parts, under the names the `Menubar` namespace gives them.
|
|
297
|
+
*
|
|
298
|
+
* `index.js` re-exports this module whole — `export * as Menubar from "./menubar.js"` —
|
|
299
|
+
* so a caller writes `<Menubar.Root>`, and the namespace is the prefix. Each
|
|
300
|
+
* part is still *declared* as `MenubarRoot`, so React DevTools, a component
|
|
301
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
302
|
+
* `Root`s.
|
|
303
|
+
*/
|
|
304
|
+
export { MenubarRoot as Root, MenubarMenu as Menu, MenubarTrigger as Trigger };
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* The parts `Menubar` shares with `Menu`, re-exported so the `Menubar`
|
|
308
|
+
* namespace is complete on its own: `<Menubar.Body>` is `Menu`'s part,
|
|
309
|
+
* not a copy of it.
|
|
310
|
+
*/
|
|
311
|
+
export {
|
|
312
|
+
Body,
|
|
313
|
+
Item,
|
|
314
|
+
CheckboxItem,
|
|
315
|
+
RadioGroup,
|
|
316
|
+
RadioItem,
|
|
317
|
+
Separator,
|
|
318
|
+
Group,
|
|
319
|
+
Label,
|
|
320
|
+
Sub,
|
|
321
|
+
SubTrigger,
|
|
322
|
+
} from "./menu.js";
|
package/navigation-menu.js
CHANGED
|
@@ -106,7 +106,7 @@ hook useNavigationMenuItem(part: string): NavigationMenuItemState {
|
|
|
106
106
|
* trigger writing itself into a ref — is a registry that has to be kept in step
|
|
107
107
|
* with a document that already knows the answer.
|
|
108
108
|
*/
|
|
109
|
-
|
|
109
|
+
component NavigationMenuRoot(
|
|
110
110
|
children: renders* NavigationMenuList,
|
|
111
111
|
defaultValue?: string | null = null,
|
|
112
112
|
value?: string | null,
|
|
@@ -145,13 +145,13 @@ export component NavigationMenuRoot(
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
/** The list of entries. A `<ul>`, because a reader is told how many there are. */
|
|
148
|
-
|
|
148
|
+
component NavigationMenuList(children: renders* NavigationMenuItem, ...rest: Rest) {
|
|
149
149
|
useNavigationMenu("NavigationMenu.List");
|
|
150
150
|
return <ul {...rest}>{children}</ul>;
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/** One entry: a link on its own, or a button and the group it opens. */
|
|
154
|
-
|
|
154
|
+
component NavigationMenuItem(value: string, children: React.Node, ...rest: Rest) {
|
|
155
155
|
const menu = useNavigationMenu("NavigationMenu.Item");
|
|
156
156
|
const base = useId();
|
|
157
157
|
const [present, setPresent] = useState(false);
|
|
@@ -179,7 +179,7 @@ export component NavigationMenuItem(value: string, children: React.Node, ...rest
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
/** The button that opens an entry's group. Not a `menuitem`; see the header. */
|
|
182
|
-
|
|
182
|
+
component NavigationMenuTrigger(children: React.Node, ...rest: Rest) {
|
|
183
183
|
const item = useNavigationMenuItem("NavigationMenu.Trigger");
|
|
184
184
|
const passed = withoutComposed(rest, ["onClick"]);
|
|
185
185
|
|
|
@@ -203,7 +203,7 @@ export component NavigationMenuTrigger(children: React.Node, ...rest: Rest) {
|
|
|
203
203
|
* Named after its trigger, so a reader who lands in it by `Tab` is told which
|
|
204
204
|
* entry they are inside rather than hearing an unnamed list of four links.
|
|
205
205
|
*/
|
|
206
|
-
|
|
206
|
+
component NavigationMenuBody(children: renders* NavigationMenuLink, ...rest: Rest) {
|
|
207
207
|
const item = useNavigationMenuItem("NavigationMenu.Body");
|
|
208
208
|
// Registered only while the group is actually in the document, which for this
|
|
209
209
|
// component means only while it is open — see the module header for why a
|
|
@@ -237,7 +237,7 @@ export component NavigationMenuBody(children: renders* NavigationMenuLink, ...re
|
|
|
237
237
|
* behind them so that coming back — or a router that never unmounted the page —
|
|
238
238
|
* does not leave it hanging open.
|
|
239
239
|
*/
|
|
240
|
-
|
|
240
|
+
component NavigationMenuLink(children: React.Node, ...rest: Rest) {
|
|
241
241
|
const item = useNavigationMenuItem("NavigationMenu.Link");
|
|
242
242
|
const passed = withoutComposed(rest, ["onClick"]);
|
|
243
243
|
|
|
@@ -249,3 +249,21 @@ export component NavigationMenuLink(children: React.Node, ...rest: Rest) {
|
|
|
249
249
|
</li>
|
|
250
250
|
);
|
|
251
251
|
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* The parts, under the names the `NavigationMenu` namespace gives them.
|
|
255
|
+
*
|
|
256
|
+
* `index.js` re-exports this module whole — `export * as NavigationMenu from "./navigation-menu.js"` —
|
|
257
|
+
* so a caller writes `<NavigationMenu.Root>`, and the namespace is the prefix. Each
|
|
258
|
+
* part is still *declared* as `NavigationMenuRoot`, so React DevTools, a component
|
|
259
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
260
|
+
* `Root`s.
|
|
261
|
+
*/
|
|
262
|
+
export {
|
|
263
|
+
NavigationMenuRoot as Root,
|
|
264
|
+
NavigationMenuList as List,
|
|
265
|
+
NavigationMenuItem as Item,
|
|
266
|
+
NavigationMenuTrigger as Trigger,
|
|
267
|
+
NavigationMenuBody as Body,
|
|
268
|
+
NavigationMenuLink as Link,
|
|
269
|
+
};
|
package/number-field.js
CHANGED
|
@@ -82,7 +82,7 @@ hook useNumber(): NumberState {
|
|
|
82
82
|
return state;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
component NumberFieldRoot(
|
|
86
86
|
children: React.Node,
|
|
87
87
|
value?: number | null,
|
|
88
88
|
defaultValue?: number | null = null,
|
|
@@ -189,7 +189,7 @@ export component NumberFieldRoot(
|
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
/** Field.Control may render this input to supply the label, description and error ids. */
|
|
192
|
-
|
|
192
|
+
component NumberFieldInput(render?: RenderProp, ...rest: Rest) {
|
|
193
193
|
const state = useNumber();
|
|
194
194
|
const props = withProps(rest, {
|
|
195
195
|
type: "text",
|
|
@@ -225,11 +225,7 @@ export component NumberFieldInput(render?: RenderProp, ...rest: Rest) {
|
|
|
225
225
|
return render != null ? render(props) : <input {...props} />;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
|
|
229
|
-
children?: React.Node = "+",
|
|
230
|
-
render?: RenderProp,
|
|
231
|
-
...rest: Rest
|
|
232
|
-
) {
|
|
228
|
+
component NumberFieldIncrement(children?: React.Node = "+", render?: RenderProp, ...rest: Rest) {
|
|
233
229
|
const state = useNumber();
|
|
234
230
|
const props = withProps(rest, {
|
|
235
231
|
children,
|
|
@@ -243,11 +239,7 @@ export component NumberFieldIncrement(
|
|
|
243
239
|
});
|
|
244
240
|
return render != null ? render(props) : <button {...props} />;
|
|
245
241
|
}
|
|
246
|
-
|
|
247
|
-
children?: React.Node = "−",
|
|
248
|
-
render?: RenderProp,
|
|
249
|
-
...rest: Rest
|
|
250
|
-
) {
|
|
242
|
+
component NumberFieldDecrement(children?: React.Node = "−", render?: RenderProp, ...rest: Rest) {
|
|
251
243
|
const state = useNumber();
|
|
252
244
|
const props = withProps(rest, {
|
|
253
245
|
children,
|
|
@@ -261,3 +253,19 @@ export component NumberFieldDecrement(
|
|
|
261
253
|
});
|
|
262
254
|
return render != null ? render(props) : <button {...props} />;
|
|
263
255
|
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* The parts, under the names the `NumberField` namespace gives them.
|
|
259
|
+
*
|
|
260
|
+
* `index.js` re-exports this module whole — `export * as NumberField from "./number-field.js"` —
|
|
261
|
+
* so a caller writes `<NumberField.Root>`, and the namespace is the prefix. Each
|
|
262
|
+
* part is still *declared* as `NumberFieldRoot`, so React DevTools, a component
|
|
263
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
264
|
+
* `Root`s.
|
|
265
|
+
*/
|
|
266
|
+
export {
|
|
267
|
+
NumberFieldRoot as Root,
|
|
268
|
+
NumberFieldInput as Input,
|
|
269
|
+
NumberFieldIncrement as Increment,
|
|
270
|
+
NumberFieldDecrement as Decrement,
|
|
271
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniflowed/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Headless, accessible React components whose composition Flow checks, part of the Unified Toolchain for Flow.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"!*.test.js"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@uniflowed/core": "0.
|
|
23
|
-
"@uniflowed/hooks": "0.
|
|
24
|
-
"@uniflowed/react": "0.
|
|
25
|
-
"@uniflowed/state": "0.
|
|
22
|
+
"@uniflowed/core": "0.4.0",
|
|
23
|
+
"@uniflowed/hooks": "0.4.0",
|
|
24
|
+
"@uniflowed/react": "0.4.0",
|
|
25
|
+
"@uniflowed/state": "0.4.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": ">=19"
|
package/pagination.js
CHANGED
|
@@ -56,7 +56,7 @@ import { withProps, withoutComposed } from "./internal/merge-props.js";
|
|
|
56
56
|
* links are on screen, and a component that showed five links out of
|
|
57
57
|
* twenty-five would otherwise announce "page 4 of 5".
|
|
58
58
|
*/
|
|
59
|
-
|
|
59
|
+
component PaginationRoot(
|
|
60
60
|
children: React.Node,
|
|
61
61
|
label?: string = "Pagination",
|
|
62
62
|
page?: number | null = null,
|
|
@@ -91,7 +91,7 @@ export component PaginationRoot(
|
|
|
91
91
|
* A real list, so a reader is told how many there are before walking them and
|
|
92
92
|
* can skip the whole thing in one keystroke.
|
|
93
93
|
*/
|
|
94
|
-
|
|
94
|
+
component PaginationContent(
|
|
95
95
|
children: renders* (PaginationItem | PaginationPrevious | PaginationNext),
|
|
96
96
|
render?: RenderProp,
|
|
97
97
|
...rest: Rest
|
|
@@ -109,7 +109,7 @@ export component PaginationContent(
|
|
|
109
109
|
* The `<li>` is structural and takes nothing; everything a caller passes goes
|
|
110
110
|
* on the `<a>`, which is what they style and what a reader activates.
|
|
111
111
|
*/
|
|
112
|
-
|
|
112
|
+
component PaginationItem(
|
|
113
113
|
children: React.Node,
|
|
114
114
|
current?: boolean = false,
|
|
115
115
|
disabled?: boolean = false,
|
|
@@ -131,7 +131,7 @@ export component PaginationItem(
|
|
|
131
131
|
* is not something a reader can act on. Pass `label` to translate it; the
|
|
132
132
|
* glyph stays whatever the caller rendered.
|
|
133
133
|
*/
|
|
134
|
-
|
|
134
|
+
component PaginationPrevious(
|
|
135
135
|
children?: React.Node,
|
|
136
136
|
label?: string = "Previous page",
|
|
137
137
|
disabled?: boolean = false,
|
|
@@ -146,7 +146,7 @@ export component PaginationPrevious(
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
/** The link to the page after this one. See `Pagination.Previous`. */
|
|
149
|
-
|
|
149
|
+
component PaginationNext(
|
|
150
150
|
children?: React.Node,
|
|
151
151
|
label?: string = "Next page",
|
|
152
152
|
disabled?: boolean = false,
|
|
@@ -207,3 +207,20 @@ component PageLink(
|
|
|
207
207
|
function defaultAnnouncement(page: number, pageCount: number): string {
|
|
208
208
|
return `Page ${String(page)} of ${String(pageCount)}.`;
|
|
209
209
|
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* The parts, under the names the `Pagination` namespace gives them.
|
|
213
|
+
*
|
|
214
|
+
* `index.js` re-exports this module whole — `export * as Pagination from "./pagination.js"` —
|
|
215
|
+
* so a caller writes `<Pagination.Root>`, and the namespace is the prefix. Each
|
|
216
|
+
* part is still *declared* as `PaginationRoot`, so React DevTools, a component
|
|
217
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
218
|
+
* `Root`s.
|
|
219
|
+
*/
|
|
220
|
+
export {
|
|
221
|
+
PaginationRoot as Root,
|
|
222
|
+
PaginationContent as Content,
|
|
223
|
+
PaginationItem as Item,
|
|
224
|
+
PaginationPrevious as Previous,
|
|
225
|
+
PaginationNext as Next,
|
|
226
|
+
};
|
package/popover.js
CHANGED
|
@@ -117,7 +117,7 @@ hook usePopover(part: string): PopoverState {
|
|
|
117
117
|
* whatever layout the caller wrote, and a wrapper would put a `<div>` between
|
|
118
118
|
* them for the caller to style around.
|
|
119
119
|
*/
|
|
120
|
-
|
|
120
|
+
component PopoverRoot(
|
|
121
121
|
children: React.Node,
|
|
122
122
|
defaultOpen?: boolean = false,
|
|
123
123
|
open?: boolean,
|
|
@@ -152,7 +152,7 @@ export component PopoverRoot(
|
|
|
152
152
|
* trigger is not "outside" for exactly this reason — closing there and letting
|
|
153
153
|
* this click reopen made the press a no-op that flickered.
|
|
154
154
|
*/
|
|
155
|
-
|
|
155
|
+
component PopoverTrigger(children: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
156
156
|
const popover = usePopover("Popover.Trigger");
|
|
157
157
|
const passed = withoutComposed(rest, ["onClick", "ref"]);
|
|
158
158
|
usePresence(popover.registerTrigger);
|
|
@@ -190,7 +190,7 @@ export component PopoverTrigger(children: React.Node, render?: RenderProp, ...re
|
|
|
190
190
|
* separates this from a dialog, and the one a copy of `dialog.js` with the
|
|
191
191
|
* `aria-modal` deleted would get wrong.
|
|
192
192
|
*/
|
|
193
|
-
|
|
193
|
+
component PopoverBody(
|
|
194
194
|
children: React.Node,
|
|
195
195
|
align?: Align = "center",
|
|
196
196
|
alignOffset?: number = 0,
|
|
@@ -234,7 +234,6 @@ export component PopoverBody(
|
|
|
234
234
|
// `open` is popover metadata; no ref value is read during render.
|
|
235
235
|
// uf-lint-disable-next-line react-compiler/refs
|
|
236
236
|
open: popover.open,
|
|
237
|
-
// uf-lint-disable-next-line react-compiler/refs
|
|
238
237
|
overlayRef: bodyRef,
|
|
239
238
|
side,
|
|
240
239
|
sideOffset,
|
|
@@ -365,3 +364,14 @@ export component PopoverBody(
|
|
|
365
364
|
}
|
|
366
365
|
return <div {...props} />;
|
|
367
366
|
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* The parts, under the names the `Popover` namespace gives them.
|
|
370
|
+
*
|
|
371
|
+
* `index.js` re-exports this module whole — `export * as Popover from "./popover.js"` —
|
|
372
|
+
* so a caller writes `<Popover.Root>`, and the namespace is the prefix. Each
|
|
373
|
+
* part is still *declared* as `PopoverRoot`, so React DevTools, a component
|
|
374
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
375
|
+
* `Root`s.
|
|
376
|
+
*/
|
|
377
|
+
export { PopoverRoot as Root, PopoverTrigger as Trigger, PopoverBody as Body };
|
package/radio-group.js
CHANGED
|
@@ -96,7 +96,7 @@ import { useControlled } from "./internal/controlled-state.js";
|
|
|
96
96
|
* have to reach it. `ToggleGroup type="single"` renders through here and is the
|
|
97
97
|
* reason that matters in practice rather than in principle.
|
|
98
98
|
*/
|
|
99
|
-
|
|
99
|
+
function radioSet(orientation: Orientation): RovingSet {
|
|
100
100
|
return {
|
|
101
101
|
item: '[role="radio"]',
|
|
102
102
|
owner: '[role="radiogroup"]',
|
|
@@ -144,7 +144,7 @@ hook useRadioGroup(part: string): RadioGroupState {
|
|
|
144
144
|
* `name` puts the answer where a form can submit it; see the hidden input
|
|
145
145
|
* below.
|
|
146
146
|
*/
|
|
147
|
-
|
|
147
|
+
component RadioGroupRoot(
|
|
148
148
|
children: React.Node,
|
|
149
149
|
defaultValue?: string | null = null,
|
|
150
150
|
value?: string | null,
|
|
@@ -232,7 +232,7 @@ export component RadioGroupRoot(
|
|
|
232
232
|
* `disabled` leaves a gap they cannot ask about. The arrow keys step over it
|
|
233
233
|
* either way, and so does the search for the item that holds the tab stop.
|
|
234
234
|
*/
|
|
235
|
-
|
|
235
|
+
component RadioGroupItem(
|
|
236
236
|
value: string,
|
|
237
237
|
children?: React.Node,
|
|
238
238
|
disabled?: boolean = false,
|
|
@@ -291,7 +291,7 @@ export component RadioGroupItem(
|
|
|
291
291
|
* `[aria-checked="true"] > *`, and so the "only while chosen" part is not
|
|
292
292
|
* something each caller reimplements.
|
|
293
293
|
*/
|
|
294
|
-
|
|
294
|
+
component RadioGroupIndicator(children?: React.Node, render?: RenderProp, ...rest: Rest) {
|
|
295
295
|
const item = useContext(RadioItemContext);
|
|
296
296
|
if (item == null) {
|
|
297
297
|
throw new Error("RadioGroup.Indicator must be rendered inside a RadioGroup.Item");
|
|
@@ -302,3 +302,14 @@ export component RadioGroupIndicator(children?: React.Node, render?: RenderProp,
|
|
|
302
302
|
const props = withProps(rest, { "aria-hidden": "true", children });
|
|
303
303
|
return render == null ? <span {...props} /> : render(props);
|
|
304
304
|
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* The parts, under the names the `RadioGroup` namespace gives them.
|
|
308
|
+
*
|
|
309
|
+
* `index.js` re-exports this module whole — `export * as RadioGroup from "./radio-group.js"` —
|
|
310
|
+
* so a caller writes `<RadioGroup.Root>`, and the namespace is the prefix. Each
|
|
311
|
+
* part is still *declared* as `RadioGroupRoot`, so React DevTools, a component
|
|
312
|
+
* stack and an error name the part a reader can find rather than one of forty
|
|
313
|
+
* `Root`s.
|
|
314
|
+
*/
|
|
315
|
+
export { RadioGroupRoot as Root, RadioGroupItem as Item, RadioGroupIndicator as Indicator };
|