@godxjp/ui 22.0.0 → 23.0.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.
Files changed (83) hide show
  1. package/README.md +4 -4
  2. package/dist/components/data-display/scroll-area.d.ts +24 -4
  3. package/dist/components/data-display/scroll-area.js +34 -72
  4. package/dist/components/data-entry/cascader.js +8 -6
  5. package/dist/components/data-entry/checkbox.js +2 -0
  6. package/dist/components/data-entry/choice-hit-target.d.ts +24 -0
  7. package/dist/components/data-entry/choice-hit-target.js +12 -0
  8. package/dist/components/data-entry/control-surface.d.ts +8 -0
  9. package/dist/components/data-entry/control-surface.js +10 -1
  10. package/dist/components/data-entry/form-field.js +3 -2
  11. package/dist/components/data-entry/radio.js +3 -2
  12. package/dist/components/data-entry/search-select.js +225 -95
  13. package/dist/components/data-entry/select.d.ts +76 -14
  14. package/dist/components/data-entry/select.js +495 -163
  15. package/dist/components/data-entry/slider.d.ts +3 -11
  16. package/dist/components/data-entry/slider.js +582 -93
  17. package/dist/components/data-entry/switch.js +2 -0
  18. package/dist/components/navigation/dropdown-menu.d.ts +11 -3
  19. package/dist/components/navigation/dropdown-menu.js +190 -15
  20. package/dist/components/navigation/index.d.ts +0 -3
  21. package/dist/components/navigation/index.js +0 -78
  22. package/dist/components/ui/index.d.ts +0 -3
  23. package/dist/components/ui/index.js +0 -3
  24. package/dist/components/ui/input-otp.d.ts +1 -1
  25. package/dist/components/ui/segmented.js +3 -1
  26. package/dist/components/ui/tag-input.js +3 -5
  27. package/dist/lib/select-options.d.ts +21 -0
  28. package/dist/lib/select-options.js +46 -0
  29. package/dist/props/components/data-display.prop.d.ts +9 -6
  30. package/dist/props/components/data-entry.prop.d.ts +323 -30
  31. package/dist/props/components/index.d.ts +1 -1
  32. package/dist/props/components/navigation.prop.d.ts +17 -0
  33. package/dist/props/registry.d.ts +63 -0
  34. package/dist/props/registry.js +69 -0
  35. package/dist/styles/control.css +205 -23
  36. package/dist/styles/data-display-layout.css +18 -10
  37. package/dist/styles/focus-ring.css +2 -2
  38. package/dist/styles/fonts.css +88 -4
  39. package/dist/styles/navigation-layout.css +11 -236
  40. package/dist/styles/shell-layout.css +144 -139
  41. package/dist/styles/table-layout.css +7 -3
  42. package/dist/tokens/components/control.css +4 -0
  43. package/dist/tokens/components/data-display.css +0 -5
  44. package/dist/tokens/components/navigation.css +3 -5
  45. package/dist/tokens/components/scroll-area.css +7 -0
  46. package/docs/CUSTOMER-THEMING.md +7 -1
  47. package/docs/FRAME-COVERAGE-REPORT.md +4 -7
  48. package/docs/data-display/data-table/index.tsx +27 -1
  49. package/docs/data-display/popover.tsx +4 -6
  50. package/docs/data-display/scroll-area.tsx +51 -45
  51. package/docs/data-entry/date-picker.tsx +2 -3
  52. package/docs/data-entry/input-otp.tsx +5 -2
  53. package/docs/data-entry/segmented.tsx +40 -1
  54. package/docs/data-entry/select-matrix.tsx +1 -2
  55. package/docs/data-entry/select.tsx +108 -3
  56. package/docs/data-entry/slider.tsx +125 -47
  57. package/docs/feedback/dialog.tsx +1 -2
  58. package/docs/feedback/sheet.tsx +1 -2
  59. package/docs/layout/app-shell-states.tsx +143 -0
  60. package/docs/navigation/dropdown-menu.tsx +75 -4
  61. package/docs/roadmap/parity-audit-data-entry.md +44 -33
  62. package/docs/roadmap/parity-audit-layout-navigation-general.md +304 -310
  63. package/docs/roadmap/parity-backlog.md +2 -3
  64. package/package.json +20 -44
  65. package/scripts/ui-audit.mjs +1 -1
  66. package/scripts/visual-audit-rules.mjs +0 -7
  67. package/scripts/visual-audit.mjs +6 -27
  68. package/dist/components/navigation/context-menu.d.ts +0 -21
  69. package/dist/components/navigation/context-menu.js +0 -149
  70. package/dist/components/navigation/menubar.d.ts +0 -28
  71. package/dist/components/navigation/menubar.js +0 -136
  72. package/dist/components/navigation/navigation-menu.d.ts +0 -10
  73. package/dist/components/navigation/navigation-menu.js +0 -91
  74. package/dist/components/ui/context-menu.d.ts +0 -1
  75. package/dist/components/ui/context-menu.js +0 -2
  76. package/dist/components/ui/menubar.d.ts +0 -1
  77. package/dist/components/ui/menubar.js +0 -2
  78. package/dist/components/ui/navigation-menu.d.ts +0 -1
  79. package/dist/components/ui/navigation-menu.js +0 -2
  80. package/docs/FRAME-A11Y-CI.md +0 -349
  81. package/docs/navigation/context-menu.tsx +0 -128
  82. package/docs/navigation/menubar.tsx +0 -141
  83. package/docs/navigation/navigation-menu.tsx +0 -158
@@ -5,6 +5,7 @@ import { Switch as AriaSwitch } from "react-aria-components";
5
5
  import { Loader2 } from "lucide-react";
6
6
  import { cn } from "../../lib/utils.js";
7
7
  import { useFieldIdentity, useMirroredInputAttributes } from "../../lib/field-a11y.js";
8
+ import { withOwnHitTarget } from "./choice-hit-target.js";
8
9
  const Switch = React.forwardRef(
9
10
  ({
10
11
  className,
@@ -72,6 +73,7 @@ const Switch = React.forwardRef(
72
73
  event.preventDefault();
73
74
  handleCheckedChange(!isChecked);
74
75
  },
76
+ render: (domProps) => /* @__PURE__ */ jsx("label", { ...domProps, children: withOwnHitTarget(domProps.children) }),
75
77
  className: cn(
76
78
  // `.ui-switch:disabled, .ui-switch[data-disabled]` in styles/control.css already
77
79
  // declares both and reads --disabled-opacity. The utility was layered after
@@ -1,7 +1,7 @@
1
1
  import * as React from "react";
2
2
  import { type MenuItemRenderProps, type PopoverProps, type PopoverRenderProps } from "react-aria-components";
3
- import type { DropdownMenuPlacementProp } from "../../props/components/navigation.prop.js";
4
- export type { DropdownMenuPlacementProp } from "../../props/components/navigation.prop.js";
3
+ import type { DropdownMenuPlacementProp, DropdownMenuTriggerActionProp } from "../../props/components/navigation.prop.js";
4
+ export type { DropdownMenuPlacementProp, DropdownMenuTriggerActionProp, } from "../../props/components/navigation.prop.js";
5
5
  /**
6
6
  * Dịch trạng thái item của RAC sang bộ `data-*` mà Radix phát ra và CSS của kho đang bám.
7
7
  *
@@ -47,9 +47,17 @@ interface DropdownMenuPropsOwn {
47
47
  * `useLocale`), nên prop này còn trong API vì hợp đồng, nhưng không tự đảo hướng.
48
48
  */
49
49
  dir?: "ltr" | "rtl";
50
+ /** Ant Design `trigger`. @see DropdownMenuTriggerActionProp. Default `['click']`. */
51
+ trigger?: readonly DropdownMenuTriggerActionProp[];
52
+ /** Ant Design `disabled` — no gesture opens the menu (antd empties the trigger list). */
53
+ disabled?: boolean;
54
+ /** Ant Design `mouseEnterDelay`, in SECONDS, for `trigger={['hover']}`. Default 0.15. */
55
+ mouseEnterDelay?: number;
56
+ /** Ant Design `mouseLeaveDelay`, in SECONDS. Default 0.1 — long enough to cross the gap. */
57
+ mouseLeaveDelay?: number;
50
58
  }
51
59
  type DropdownMenuProps = React.PropsWithChildren<DropdownMenuPropsOwn>;
52
- export declare function DropdownMenu({ children, open, defaultOpen, onOpenChange, modal, dir, }: DropdownMenuProps): React.JSX.Element;
60
+ export declare function DropdownMenu({ children, open, defaultOpen, onOpenChange, modal, dir, trigger, disabled, mouseEnterDelay, mouseLeaveDelay, }: DropdownMenuProps): React.JSX.Element;
53
61
  interface DropdownMenuTriggerProps extends React.ComponentPropsWithoutRef<"button"> {
54
62
  /** Giao hành vi mở cho phần tử con thay vì `<button>` mặc định — như Radix. */
55
63
  asChild?: boolean;
@@ -12,9 +12,11 @@ import {
12
12
  OverlayTriggerStateContext,
13
13
  Popover,
14
14
  Pressable,
15
+ RootMenuTriggerStateContext,
15
16
  Separator,
16
17
  OverlayArrow,
17
- SubmenuTrigger
18
+ SubmenuTrigger,
19
+ useLocale
18
20
  } from "react-aria-components";
19
21
  import { Check, ChevronRight } from "lucide-react";
20
22
  import { cn } from "../../lib/utils.js";
@@ -58,39 +60,201 @@ function selectEvent(name) {
58
60
  return typeof CustomEvent === "function" ? new CustomEvent(name, { bubbles: false, cancelable: true }) : { defaultPrevented: false, preventDefault() {
59
61
  } };
60
62
  }
61
- const DropdownMenuModalContext = React.createContext({ modal: true });
63
+ const DROPDOWN_MENU_DEFAULT_TRIGGER = ["click"];
64
+ const DROPDOWN_MENU_MOUSE_ENTER_DELAY = 0.15;
65
+ const DROPDOWN_MENU_MOUSE_LEAVE_DELAY = 0.1;
66
+ const SECOND_IN_MS = 1e3;
67
+ const DropdownMenuModalContext = React.createContext({
68
+ modal: true,
69
+ contextMenuGesture: false,
70
+ disabled: false,
71
+ hover: null,
72
+ racOwnsContextMenu: false,
73
+ openedByHover: { current: false }
74
+ });
75
+ function clearContextMenuPoint(state) {
76
+ state?.setPoint(null);
77
+ }
78
+ function chainGestureProps(own, incoming) {
79
+ const merged = { ...own };
80
+ for (const [key, handler] of Object.entries(incoming)) {
81
+ const existing = own[key];
82
+ merged[key] = typeof existing === "function" && typeof handler === "function" ? (event) => {
83
+ existing(event);
84
+ if (!event.defaultPrevented) handler(event);
85
+ } : handler;
86
+ }
87
+ return merged;
88
+ }
89
+ function isContextMenuKey(event) {
90
+ return event.key === "ContextMenu" || event.key === "F10" && event.shiftKey;
91
+ }
62
92
  function DropdownMenu({
63
93
  children,
64
94
  open,
65
95
  defaultOpen,
66
96
  onOpenChange,
67
97
  modal = true,
68
- dir
98
+ dir,
99
+ trigger = DROPDOWN_MENU_DEFAULT_TRIGGER,
100
+ disabled = false,
101
+ mouseEnterDelay = DROPDOWN_MENU_MOUSE_ENTER_DELAY,
102
+ mouseLeaveDelay = DROPDOWN_MENU_MOUSE_LEAVE_DELAY
69
103
  }) {
70
104
  void dir;
71
- const options = React.useMemo(() => ({ modal }), [modal]);
72
- return /* @__PURE__ */ jsx(DropdownMenuModalContext.Provider, { value: options, children: /* @__PURE__ */ jsx(MenuTrigger, { isOpen: open, defaultOpen, onOpenChange, children }) });
105
+ const wantsHover = !disabled && trigger.includes("hover");
106
+ const wantsClick = !disabled && trigger.includes("click");
107
+ const wantsContextMenu = !disabled && trigger.includes("contextMenu");
108
+ const racOwnsContextMenu = wantsContextMenu && !wantsClick && !wantsHover;
109
+ const [uncontrolled, setUncontrolled] = React.useState(defaultOpen ?? false);
110
+ const isOpen = open ?? uncontrolled;
111
+ const isOpenRef = React.useRef(isOpen);
112
+ isOpenRef.current = isOpen;
113
+ const openedByHover = React.useRef(false);
114
+ const setOpen = React.useCallback(
115
+ (next) => {
116
+ if (next === isOpenRef.current) return;
117
+ if (next && disabled) return;
118
+ if (!next) openedByHover.current = false;
119
+ if (open === void 0) setUncontrolled(next);
120
+ onOpenChange?.(next);
121
+ },
122
+ [disabled, open, onOpenChange]
123
+ );
124
+ const enterTimer = React.useRef(null);
125
+ const leaveTimer = React.useRef(null);
126
+ React.useEffect(
127
+ () => () => {
128
+ if (enterTimer.current) clearTimeout(enterTimer.current);
129
+ if (leaveTimer.current) clearTimeout(leaveTimer.current);
130
+ },
131
+ []
132
+ );
133
+ const hover = React.useMemo(() => {
134
+ if (!wantsHover) return null;
135
+ return {
136
+ enter: () => {
137
+ if (leaveTimer.current) clearTimeout(leaveTimer.current);
138
+ if (isOpenRef.current) return;
139
+ enterTimer.current = setTimeout(() => {
140
+ openedByHover.current = true;
141
+ setOpen(true);
142
+ }, mouseEnterDelay * SECOND_IN_MS);
143
+ },
144
+ leave: () => {
145
+ if (enterTimer.current) clearTimeout(enterTimer.current);
146
+ leaveTimer.current = setTimeout(() => setOpen(false), mouseLeaveDelay * SECOND_IN_MS);
147
+ }
148
+ };
149
+ }, [wantsHover, mouseEnterDelay, mouseLeaveDelay, setOpen]);
150
+ const options = React.useMemo(
151
+ () => ({
152
+ // A HOVER MENU CANNOT BE MODAL. A modal RAC popover paints a full-bleed underlay the instant
153
+ // it opens; that underlay lands under the pointer, the trigger gets `pointerleave`, and the
154
+ // menu closes before the reader can move onto it. antd's hover dropdown is non-modal for the
155
+ // same reason. Every other mode keeps the caller's `modal`.
156
+ modal: wantsHover ? false : modal,
157
+ contextMenuGesture: wantsContextMenu,
158
+ disabled,
159
+ hover,
160
+ racOwnsContextMenu,
161
+ openedByHover
162
+ }),
163
+ [modal, wantsContextMenu, disabled, hover, racOwnsContextMenu, wantsHover]
164
+ );
165
+ return /* @__PURE__ */ jsx(DropdownMenuModalContext.Provider, { value: options, children: /* @__PURE__ */ jsx(
166
+ MenuTrigger,
167
+ {
168
+ isOpen,
169
+ onOpenChange: setOpen,
170
+ trigger: racOwnsContextMenu ? "contextMenu" : "press",
171
+ children
172
+ }
173
+ ) });
73
174
  }
74
175
  function DropdownMenuTrigger({ asChild, children, ...props }) {
75
176
  const state = React.useContext(OverlayTriggerStateContext);
177
+ const menuState = React.useContext(
178
+ RootMenuTriggerStateContext
179
+ );
180
+ const { contextMenuGesture, disabled, hover, racOwnsContextMenu } = React.useContext(DropdownMenuModalContext);
76
181
  const dataState = state?.isOpen ? "open" : "closed";
182
+ const wantsContextMenu = contextMenuGesture;
183
+ const isDisabled = disabled || props.disabled;
184
+ const { direction } = useLocale();
185
+ const openAtTriggerBox = (element) => {
186
+ const rect = element.getBoundingClientRect();
187
+ menuState?.setPoint({ x: direction === "rtl" ? rect.right : rect.left, y: rect.bottom });
188
+ menuState?.open("first");
189
+ };
190
+ const gestureProps = {};
191
+ if (wantsContextMenu && !isDisabled) {
192
+ gestureProps.onKeyDown = (event) => {
193
+ if (!isContextMenuKey(event)) return;
194
+ event.preventDefault();
195
+ openAtTriggerBox(event.currentTarget);
196
+ };
197
+ if (!racOwnsContextMenu) {
198
+ gestureProps.onContextMenu = (event) => {
199
+ event.preventDefault();
200
+ menuState?.setPoint({ x: event.clientX, y: event.clientY });
201
+ menuState?.open(null);
202
+ };
203
+ }
204
+ }
205
+ if (!racOwnsContextMenu) {
206
+ gestureProps.onPointerDownCapture = () => clearContextMenuPoint(menuState);
207
+ gestureProps.onKeyDownCapture = (event) => {
208
+ if (!isContextMenuKey(event)) clearContextMenuPoint(menuState);
209
+ };
210
+ }
211
+ if (hover && !isDisabled) {
212
+ gestureProps.onPointerEnter = (event) => {
213
+ if (event.pointerType === "mouse") hover.enter();
214
+ };
215
+ gestureProps.onPointerLeave = (event) => {
216
+ if (event.pointerType === "mouse") hover.leave();
217
+ };
218
+ }
77
219
  if (asChild && React.isValidElement(children)) {
78
- return /* @__PURE__ */ jsx(Pressable, { children: React.cloneElement(children, {
220
+ return /* @__PURE__ */ jsx(Pressable, { isDisabled, children: React.cloneElement(children, {
79
221
  "data-slot": "dropdown-menu-trigger",
80
- "data-state": dataState
222
+ "data-state": dataState,
223
+ // A right click target is usually a region rather than a button, and Shift+F10 needs it
224
+ // focusable — so it is given a tab stop unless the consumer already placed one.
225
+ ...wantsContextMenu && children.props.tabIndex === void 0 ? { tabIndex: 0 } : {},
226
+ ...chainGestureProps(
227
+ children.props,
228
+ gestureProps
229
+ )
81
230
  }) });
82
231
  }
83
232
  return /* @__PURE__ */ jsx(
84
233
  AriaButton,
85
234
  {
86
- ...props,
87
- isDisabled: props.disabled,
235
+ ...chainGestureProps(
236
+ props,
237
+ gestureProps
238
+ ),
239
+ isDisabled,
88
240
  "data-slot": "dropdown-menu-trigger",
89
241
  "data-state": dataState,
90
242
  children
91
243
  }
92
244
  );
93
245
  }
246
+ function useHoverSurfaceProps() {
247
+ const { hover } = React.useContext(DropdownMenuModalContext);
248
+ if (!hover) return {};
249
+ return {
250
+ onPointerEnter: (event) => {
251
+ if (event.pointerType === "mouse") hover.enter();
252
+ },
253
+ onPointerLeave: (event) => {
254
+ if (event.pointerType === "mouse") hover.leave();
255
+ }
256
+ };
257
+ }
94
258
  function DropdownMenuPortal({ children }) {
95
259
  return /* @__PURE__ */ jsx(Fragment, { children });
96
260
  }
@@ -129,7 +293,7 @@ function DropdownMenuContent({
129
293
  className,
130
294
  side,
131
295
  align,
132
- sideOffset = 4,
296
+ sideOffset,
133
297
  placement,
134
298
  arrow,
135
299
  width,
@@ -144,17 +308,25 @@ function DropdownMenuContent({
144
308
  void hideWhenDetached;
145
309
  void sticky;
146
310
  void forceMount;
147
- const { modal } = React.useContext(DropdownMenuModalContext);
311
+ const { modal, openedByHover } = React.useContext(DropdownMenuModalContext);
312
+ const hoverSurfaceProps = useHoverSurfaceProps();
313
+ const menuState = React.useContext(
314
+ RootMenuTriggerStateContext
315
+ );
148
316
  const anchor = placement ? DROPDOWN_MENU_PLACEMENT[placement] : void 0;
149
317
  const overlayPortalContainer = useOverlayPortalContainer();
318
+ const pointAnchored = menuState?.point != null;
319
+ const hasExplicitAnchor = placement !== void 0 || side !== void 0 || align !== void 0;
320
+ const resolvedPlacement = hasExplicitAnchor || !pointAnchored ? toPlacement(side ?? anchor?.side, align ?? anchor?.align) : "bottom start";
321
+ const resolvedOffset = sideOffset ?? (pointAnchored && !hasExplicitAnchor ? 0 : 4);
150
322
  return /* @__PURE__ */ jsx(DropdownMenuPortal, { children: /* @__PURE__ */ jsxs(
151
323
  Popover,
152
324
  {
153
325
  UNSTABLE_portalContainer: overlayPortalContainer,
154
326
  "data-slot": "dropdown-menu-content",
155
327
  isNonModal: !modal,
156
- placement: toPlacement(side ?? anchor?.side, align ?? anchor?.align),
157
- offset: sideOffset,
328
+ placement: resolvedPlacement,
329
+ offset: resolvedOffset,
158
330
  crossOffset: alignOffset,
159
331
  shouldFlip: avoidCollisions,
160
332
  containerPadding: collisionPadding,
@@ -168,15 +340,16 @@ function DropdownMenuContent({
168
340
  "div",
169
341
  {
170
342
  ...props,
343
+ ...hoverSurfaceProps,
171
344
  role: void 0,
172
345
  ...radixSurfaceState(state),
173
- "data-align": align ?? anchor?.align ?? "center",
346
+ "data-align": align ?? anchor?.align ?? (pointAnchored && !hasExplicitAnchor ? "start" : "center"),
174
347
  "data-width": width
175
348
  }
176
349
  )
177
350
  ),
178
351
  children: [
179
- /* @__PURE__ */ jsx(Menu, { shouldFocusWrap: loop, children }),
352
+ /* @__PURE__ */ jsx(Menu, { shouldFocusWrap: loop, autoFocus: openedByHover.current ? false : void 0, children }),
180
353
  arrow ? /* @__PURE__ */ jsx(OverlayArrow, { children: /* @__PURE__ */ jsx(
181
354
  "svg",
182
355
  {
@@ -388,6 +561,7 @@ function DropdownMenuSubContent({
388
561
  void hideWhenDetached;
389
562
  void sticky;
390
563
  const overlayPortalContainer = useOverlayPortalContainer();
564
+ const hoverSurfaceProps = useHoverSurfaceProps();
391
565
  return /* @__PURE__ */ jsx(
392
566
  Popover,
393
567
  {
@@ -408,6 +582,7 @@ function DropdownMenuSubContent({
408
582
  "div",
409
583
  {
410
584
  ...props,
585
+ ...hoverSurfaceProps,
411
586
  role: void 0,
412
587
  ...radixSurfaceState(state),
413
588
  "data-align": align ?? "center"
@@ -1,8 +1,5 @@
1
1
  export { Tabs, TabsContent, TabsList, TabsTrigger } from "./tabs.js";
2
- export { ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, } from "./context-menu.js";
3
2
  export { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationEllipsis, PaginationPrevious, PaginationNext, } from "./pagination.js";
4
- export { Menubar, MenubarCheckboxItem, MenubarContent, MenubarItem, MenubarLabel, MenubarMenu, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, } from "./menubar.js";
5
- export { NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, } from "./navigation-menu.js";
6
3
  export { Steps } from "./steps.js";
7
4
  export { FilterBar, FilterBarGroup, Toolbar, ToolbarGroup } from "./filter-bar.js";
8
5
  export type { FilterBarChipProp, FilterBarChipProps, FilterBarFilterProp, FilterBarFilterProps, FilterBarGroupProp, FilterBarGroupProps, FilterBarOverflowProp, FilterBarProp, FilterBarProps, FilterBarSearchProp, FilterBarSearchProps, ToolbarGroupProps, ToolbarProps, } from "./filter-bar.js";
@@ -1,20 +1,4 @@
1
1
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "./tabs.js";
2
- import {
3
- ContextMenu,
4
- ContextMenuCheckboxItem,
5
- ContextMenuContent,
6
- ContextMenuItem,
7
- ContextMenuLabel,
8
- ContextMenuPortal,
9
- ContextMenuRadioGroup,
10
- ContextMenuRadioItem,
11
- ContextMenuSeparator,
12
- ContextMenuShortcut,
13
- ContextMenuSub,
14
- ContextMenuSubContent,
15
- ContextMenuSubTrigger,
16
- ContextMenuTrigger
17
- } from "./context-menu.js";
18
2
  import {
19
3
  Pagination,
20
4
  PaginationContent,
@@ -24,32 +8,6 @@ import {
24
8
  PaginationPrevious,
25
9
  PaginationNext
26
10
  } from "./pagination.js";
27
- import {
28
- Menubar,
29
- MenubarCheckboxItem,
30
- MenubarContent,
31
- MenubarItem,
32
- MenubarLabel,
33
- MenubarMenu,
34
- MenubarRadioGroup,
35
- MenubarRadioItem,
36
- MenubarSeparator,
37
- MenubarShortcut,
38
- MenubarSub,
39
- MenubarSubContent,
40
- MenubarSubTrigger,
41
- MenubarTrigger
42
- } from "./menubar.js";
43
- import {
44
- NavigationMenu,
45
- NavigationMenuContent,
46
- NavigationMenuIndicator,
47
- NavigationMenuItem,
48
- NavigationMenuLink,
49
- NavigationMenuList,
50
- NavigationMenuTrigger,
51
- NavigationMenuViewport
52
- } from "./navigation-menu.js";
53
11
  import { Steps } from "./steps.js";
54
12
  import { FilterBar, FilterBarGroup, Toolbar, ToolbarGroup } from "./filter-bar.js";
55
13
  import { AppSettingPicker } from "./app-setting-picker.js";
@@ -74,20 +32,6 @@ import {
74
32
  export {
75
33
  AppSettingPicker,
76
34
  AppSettingToggle,
77
- ContextMenu,
78
- ContextMenuCheckboxItem,
79
- ContextMenuContent,
80
- ContextMenuItem,
81
- ContextMenuLabel,
82
- ContextMenuPortal,
83
- ContextMenuRadioGroup,
84
- ContextMenuRadioItem,
85
- ContextMenuSeparator,
86
- ContextMenuShortcut,
87
- ContextMenuSub,
88
- ContextMenuSubContent,
89
- ContextMenuSubTrigger,
90
- ContextMenuTrigger,
91
35
  DropdownMenu,
92
36
  DropdownMenuCheckboxItem,
93
37
  DropdownMenuContent,
@@ -105,28 +49,6 @@ export {
105
49
  DropdownMenuTrigger,
106
50
  FilterBar,
107
51
  FilterBarGroup,
108
- Menubar,
109
- MenubarCheckboxItem,
110
- MenubarContent,
111
- MenubarItem,
112
- MenubarLabel,
113
- MenubarMenu,
114
- MenubarRadioGroup,
115
- MenubarRadioItem,
116
- MenubarSeparator,
117
- MenubarShortcut,
118
- MenubarSub,
119
- MenubarSubContent,
120
- MenubarSubTrigger,
121
- MenubarTrigger,
122
- NavigationMenu,
123
- NavigationMenuContent,
124
- NavigationMenuIndicator,
125
- NavigationMenuItem,
126
- NavigationMenuLink,
127
- NavigationMenuList,
128
- NavigationMenuTrigger,
129
- NavigationMenuViewport,
130
52
  Pagination,
131
53
  PaginationContent,
132
54
  PaginationEllipsis,
@@ -10,9 +10,6 @@ export * from "./card.js";
10
10
  export * from "./checkbox.js";
11
11
  export * from "./color-picker.js";
12
12
  export * from "./command.js";
13
- export * from "./context-menu.js";
14
- export * from "./menubar.js";
15
- export * from "./navigation-menu.js";
16
13
  export * from "./resizable.js";
17
14
  export * from "./date-picker.js";
18
15
  export * from "./dialog.js";
@@ -11,9 +11,6 @@ export * from "./card.js";
11
11
  export * from "./checkbox.js";
12
12
  export * from "./color-picker.js";
13
13
  export * from "./command.js";
14
- export * from "./context-menu.js";
15
- export * from "./menubar.js";
16
- export * from "./navigation-menu.js";
17
14
  export * from "./resizable.js";
18
15
  export * from "./date-picker.js";
19
16
  export * from "./dialog.js";
@@ -16,7 +16,7 @@ import * as React from "react";
16
16
  * too, and `input-otp` writes its own internal state inside its paste handler, which a wrapper
17
17
  * that only intercepted `onChange` could not undo.
18
18
  */
19
- export declare const InputOTP: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "children" | "defaultValue" | "onChange" | "size" | "value"> & {
19
+ export declare const InputOTP: React.ForwardRefExoticComponent<Omit<React.InputHTMLAttributes<HTMLInputElement>, "children" | "defaultValue" | "onChange" | "size" | "style" | "value"> & {
20
20
  maxLength: number;
21
21
  value?: string;
22
22
  defaultValue?: string;
@@ -2,6 +2,7 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { Radio as AriaRadio, RadioGroup as AriaRadioGroup } from "react-aria-components";
5
+ import { withOwnHitTarget } from "../data-entry/choice-hit-target.js";
5
6
  import { cn } from "../../lib/utils.js";
6
7
  const Segmented = React.forwardRef(function Segmented2({
7
8
  options,
@@ -44,7 +45,8 @@ const Segmented = React.forwardRef(function Segmented2({
44
45
  "label",
45
46
  {
46
47
  ...domProps,
47
- "data-state": state.isSelected ? "checked" : "unchecked"
48
+ "data-state": state.isSelected ? "checked" : "unchecked",
49
+ children: withOwnHitTarget(domProps.children)
48
50
  }
49
51
  ),
50
52
  children: [
@@ -7,11 +7,9 @@ import { cn } from "../../lib/utils.js";
7
7
  import {
8
8
  applyMaxTagCount,
9
9
  controlSurfaceAttrs,
10
- resolveAllowClear
10
+ resolveAllowClear,
11
+ splitByTokenSeparators
11
12
  } from "../data-entry/control-surface.js";
12
- function escapeForCharClass(character) {
13
- return character.replace(/[\\\]^-]/g, "\\$&");
14
- }
15
13
  const TagInput = React.forwardRef(
16
14
  ({
17
15
  value,
@@ -51,7 +49,7 @@ const TagInput = React.forwardRef(
51
49
  };
52
50
  const addAll = (raw) => {
53
51
  let next = [...tags];
54
- const pieces = tokenSeparators.length ? raw.split(new RegExp(`[${tokenSeparators.map(escapeForCharClass).join("")}]`)) : [raw];
52
+ const pieces = splitByTokenSeparators(raw, tokenSeparators);
55
53
  for (const piece of pieces) {
56
54
  const tag = piece.trim();
57
55
  if (!tag || next.includes(tag)) continue;
@@ -0,0 +1,21 @@
1
+ import type { SearchSelectOptionProp, SelectFieldNamesProp, SelectOptionGroupProp } from "../props/components/data-entry.prop.js";
2
+ /**
3
+ * One list of rows, whatever shape the call site had.
4
+ *
5
+ * `Select` accepts three spellings of the same thing and they all have to arrive at the engine as
6
+ * ONE flat array, or every feature downstream (filtering, `maxCount`, the hidden `<option>` list)
7
+ * would need to know about all three:
8
+ *
9
+ * • this library's flat rows, `{ value, label, group? }`
10
+ * • antd's nested groups, `{ label, options: [...] }`
11
+ * • a foreign row read through `fieldNames`, `{ id, name, children }`
12
+ *
13
+ * Written once, here, rather than in both `select.tsx` and `search-select.tsx` — the two branches
14
+ * of one component must not disagree about what an option is. Group headings survive as the flat
15
+ * `group` string the rows already carried, so a grouped list renders identically whichever
16
+ * spelling produced it.
17
+ */
18
+ /** A row whose keys are not known ahead of time — what `fieldNames` exists to read. */
19
+ type RawOption = Record<string, unknown>;
20
+ export declare function normalizeSelectOptions(options: readonly (SearchSelectOptionProp | SelectOptionGroupProp | RawOption)[] | undefined, fieldNames?: SelectFieldNamesProp): SearchSelectOptionProp[];
21
+ export {};
@@ -0,0 +1,46 @@
1
+ function text(value) {
2
+ if (typeof value === "string" || typeof value === "number" || typeof value === "bigint") {
3
+ return String(value);
4
+ }
5
+ return "";
6
+ }
7
+ function groupChildren(option, optionsKey) {
8
+ const children = option[optionsKey];
9
+ return Array.isArray(children) ? children : void 0;
10
+ }
11
+ function normalizeSelectOptions(options, fieldNames) {
12
+ if (!options?.length) return [];
13
+ const labelKey = fieldNames?.label ?? "label";
14
+ const valueKey = fieldNames?.value ?? "value";
15
+ const optionsKey = fieldNames?.options ?? "options";
16
+ const groupLabelKey = fieldNames?.groupLabel ?? labelKey;
17
+ const disabledKey = fieldNames?.disabled ?? "disabled";
18
+ const flat = [];
19
+ const push = (raw, group) => {
20
+ const value = text(raw[valueKey]);
21
+ const label = text(raw[labelKey]);
22
+ flat.push({
23
+ ...raw,
24
+ value,
25
+ // A row with no label reads as its own value — the id is at least identifiable, where an
26
+ // empty row is not selectable by sight or by type-to-select.
27
+ label: label || value,
28
+ disabled: raw[disabledKey] === true || void 0,
29
+ // A row inside a group takes the group's heading; a flat row keeps the `group` it declared.
30
+ group: group ?? (typeof raw.group === "string" ? raw.group : void 0)
31
+ });
32
+ };
33
+ for (const entry of options) {
34
+ const children = groupChildren(entry, optionsKey);
35
+ if (children) {
36
+ const heading = text(entry[groupLabelKey]) || void 0;
37
+ for (const child of children) push(child, heading);
38
+ continue;
39
+ }
40
+ push(entry, void 0);
41
+ }
42
+ return flat;
43
+ }
44
+ export {
45
+ normalizeSelectOptions
46
+ };
@@ -403,9 +403,10 @@ export type PermissionMatrixProp = {
403
403
  export type ScrollAreaAnchorProp = "none" | "bottom";
404
404
  /** @see ScrollArea */
405
405
  /**
406
- * @see ScrollArea — which AXES scroll. This is not decoration: Radix sets the viewport's
407
- * `overflowX`/`overflowY` inline from which scrollbars are mounted, so an axis with no `ScrollBar`
408
- * is `overflow: hidden` and its content is CLIPPED, not merely un-barred.
406
+ * @see ScrollArea — which AXES scroll. This is not decoration: it IS the `overflow` the element
407
+ * carries, so an axis this does not name is `hidden` and its content is CLIPPED, not merely
408
+ * un-barred. It is also the whole replacement for mounting a `<ScrollBar>`, which was how the
409
+ * Radix-era component was told to open a second axis.
409
410
  *
410
411
  * `both` is a third value rather than an array or a pair of booleans because the axes are one
411
412
  * decision — a pane scrolls down, across, or freely — and a closed union is what `check:prop-vocabulary`
@@ -419,12 +420,14 @@ export type ScrollAreaProp = {
419
420
  *
420
421
  * Reach for `horizontal` for a strip of non-shrinking columns (a board, a lane of cards): the
421
422
  * viewport keeps its tab stop, so the strip is scrollable from the keyboard, and the consumer
422
- * writes no overflow styling of its own.
423
+ * writes no overflow styling of its own. `both` is what replaces a vertical area that also
424
+ * mounted `<ScrollBar orientation="horizontal" />`.
423
425
  */
424
426
  orientation?: ScrollAreaOrientationProp;
425
427
  /**
426
- * Ref to the element that actually SCROLLS the Radix viewport — not the root. The root is
427
- * `overflow: hidden` and never scrolls, so the component's own `ref` cannot serve.
428
+ * Ref to the element that actually SCROLLS. Since v23 that is the component's own element, so
429
+ * this and `ref` hand back the SAME node it is kept because it names the thing precisely, and
430
+ * because the Radix-era shape (a root wrapping a separate viewport) made `ref` the wrong handle.
428
431
  */
429
432
  viewportRef?: React.Ref<HTMLDivElement>;
430
433
  /** Edge the viewport sticks to as content grows. Default `none` (inert). */