@proyecto-viviana/solidaria-components 0.3.2 → 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.
Files changed (398) hide show
  1. package/dist/ActionBar.js +184 -0
  2. package/dist/ActionBar.js.map +1 -0
  3. package/dist/ActionBar.jsx +128 -0
  4. package/dist/ActionBar.jsx.map +1 -0
  5. package/dist/ActionGroup.js +179 -0
  6. package/dist/ActionGroup.js.map +1 -0
  7. package/dist/ActionGroup.jsx +129 -0
  8. package/dist/ActionGroup.jsx.map +1 -0
  9. package/dist/Alert.js +111 -0
  10. package/dist/Alert.js.map +1 -0
  11. package/dist/Alert.jsx +82 -0
  12. package/dist/Alert.jsx.map +1 -0
  13. package/dist/Autocomplete.js +130 -0
  14. package/dist/Autocomplete.js.map +1 -0
  15. package/dist/Autocomplete.jsx +116 -0
  16. package/dist/Autocomplete.jsx.map +1 -0
  17. package/dist/Breadcrumbs.d.ts.map +1 -1
  18. package/dist/Breadcrumbs.js +334 -0
  19. package/dist/Breadcrumbs.js.map +1 -0
  20. package/dist/Breadcrumbs.jsx +266 -0
  21. package/dist/Breadcrumbs.jsx.map +1 -0
  22. package/dist/Button.d.ts.map +1 -1
  23. package/dist/Button.js +348 -0
  24. package/dist/Button.js.map +1 -0
  25. package/dist/Button.jsx +314 -0
  26. package/dist/Button.jsx.map +1 -0
  27. package/dist/Calendar.d.ts +4 -4
  28. package/dist/Calendar.d.ts.map +1 -1
  29. package/dist/Calendar.js +538 -0
  30. package/dist/Calendar.js.map +1 -0
  31. package/dist/Calendar.jsx +333 -0
  32. package/dist/Calendar.jsx.map +1 -0
  33. package/dist/CalendarPicker.d.ts +33 -0
  34. package/dist/CalendarPicker.d.ts.map +1 -0
  35. package/dist/CalendarPicker.js +44 -0
  36. package/dist/CalendarPicker.js.map +1 -0
  37. package/dist/CalendarPicker.jsx +44 -0
  38. package/dist/CalendarPicker.jsx.map +1 -0
  39. package/dist/Checkbox.d.ts +83 -4
  40. package/dist/Checkbox.d.ts.map +1 -1
  41. package/dist/Checkbox.js +923 -0
  42. package/dist/Checkbox.js.map +1 -0
  43. package/dist/Checkbox.jsx +707 -0
  44. package/dist/Checkbox.jsx.map +1 -0
  45. package/dist/Collection.d.ts.map +1 -1
  46. package/dist/Collection.js +202 -0
  47. package/dist/Collection.js.map +1 -0
  48. package/dist/Collection.jsx +152 -0
  49. package/dist/Collection.jsx.map +1 -0
  50. package/dist/Color.d.ts.map +1 -1
  51. package/dist/Color.js +1720 -0
  52. package/dist/Color.js.map +1 -0
  53. package/dist/Color.jsx +1344 -0
  54. package/dist/Color.jsx.map +1 -0
  55. package/dist/ColorEditor.js +208 -0
  56. package/dist/ColorEditor.js.map +1 -0
  57. package/dist/ColorEditor.jsx +120 -0
  58. package/dist/ColorEditor.jsx.map +1 -0
  59. package/dist/ComboBox.d.ts +4 -4
  60. package/dist/ComboBox.d.ts.map +1 -1
  61. package/dist/ComboBox.js +992 -0
  62. package/dist/ComboBox.js.map +1 -0
  63. package/dist/ComboBox.jsx +714 -0
  64. package/dist/ComboBox.jsx.map +1 -0
  65. package/dist/ContextualHelpTrigger.js +146 -0
  66. package/dist/ContextualHelpTrigger.js.map +1 -0
  67. package/dist/ContextualHelpTrigger.jsx +109 -0
  68. package/dist/ContextualHelpTrigger.jsx.map +1 -0
  69. package/dist/DateField.d.ts +3 -3
  70. package/dist/DateField.d.ts.map +1 -1
  71. package/dist/DateField.js +4 -0
  72. package/dist/DateField.jsx +4 -0
  73. package/dist/DateField2.js +499 -0
  74. package/dist/DateField2.js.map +1 -0
  75. package/dist/DateField2.jsx +317 -0
  76. package/dist/DateField2.jsx.map +1 -0
  77. package/dist/DatePicker.d.ts +4 -4
  78. package/dist/DatePicker.d.ts.map +1 -1
  79. package/dist/DatePicker.js +991 -0
  80. package/dist/DatePicker.js.map +1 -0
  81. package/dist/DatePicker.jsx +682 -0
  82. package/dist/DatePicker.jsx.map +1 -0
  83. package/dist/Dialog.d.ts.map +1 -1
  84. package/dist/Dialog.js +337 -0
  85. package/dist/Dialog.js.map +1 -0
  86. package/dist/Dialog.jsx +192 -0
  87. package/dist/Dialog.jsx.map +1 -0
  88. package/dist/Disclosure.d.ts.map +1 -1
  89. package/dist/Disclosure.js +328 -0
  90. package/dist/Disclosure.js.map +1 -0
  91. package/dist/Disclosure.jsx +230 -0
  92. package/dist/Disclosure.jsx.map +1 -0
  93. package/dist/DragAndDrop.d.ts.map +1 -1
  94. package/dist/DragAndDrop.js +176 -0
  95. package/dist/DragAndDrop.js.map +1 -0
  96. package/dist/DragAndDrop.jsx +160 -0
  97. package/dist/DragAndDrop.jsx.map +1 -0
  98. package/dist/DropZone.d.ts.map +1 -1
  99. package/dist/DropZone.js +189 -0
  100. package/dist/DropZone.js.map +1 -0
  101. package/dist/DropZone.jsx +144 -0
  102. package/dist/DropZone.jsx.map +1 -0
  103. package/dist/FieldError.js +66 -0
  104. package/dist/FieldError.js.map +1 -0
  105. package/dist/FieldError.jsx +47 -0
  106. package/dist/FieldError.jsx.map +1 -0
  107. package/dist/FileTrigger.js +79 -0
  108. package/dist/FileTrigger.js.map +1 -0
  109. package/dist/FileTrigger.jsx +49 -0
  110. package/dist/FileTrigger.jsx.map +1 -0
  111. package/dist/Focusable.js +70 -0
  112. package/dist/Focusable.js.map +1 -0
  113. package/dist/Focusable.jsx +69 -0
  114. package/dist/Focusable.jsx.map +1 -0
  115. package/dist/Form.js +99 -0
  116. package/dist/Form.js.map +1 -0
  117. package/dist/Form.jsx +73 -0
  118. package/dist/Form.jsx.map +1 -0
  119. package/dist/GridList.d.ts +34 -2
  120. package/dist/GridList.d.ts.map +1 -1
  121. package/dist/GridList.js +723 -0
  122. package/dist/GridList.js.map +1 -0
  123. package/dist/GridList.jsx +552 -0
  124. package/dist/GridList.jsx.map +1 -0
  125. package/dist/HiddenTimeInput.js +104 -0
  126. package/dist/HiddenTimeInput.js.map +1 -0
  127. package/dist/HiddenTimeInput.jsx +69 -0
  128. package/dist/HiddenTimeInput.jsx.map +1 -0
  129. package/dist/Icon.d.ts.map +1 -1
  130. package/dist/Icon.js +127 -0
  131. package/dist/Icon.js.map +1 -0
  132. package/dist/Icon.jsx +72 -0
  133. package/dist/Icon.jsx.map +1 -0
  134. package/dist/Keyboard.js +30 -0
  135. package/dist/Keyboard.js.map +1 -0
  136. package/dist/Keyboard.jsx +24 -0
  137. package/dist/Keyboard.jsx.map +1 -0
  138. package/dist/Landmark.js +134 -0
  139. package/dist/Landmark.js.map +1 -0
  140. package/dist/Landmark.jsx +118 -0
  141. package/dist/Landmark.jsx.map +1 -0
  142. package/dist/Link.d.ts.map +1 -1
  143. package/dist/Link.js +219 -0
  144. package/dist/Link.js.map +1 -0
  145. package/dist/Link.jsx +189 -0
  146. package/dist/Link.jsx.map +1 -0
  147. package/dist/ListBox.d.ts.map +1 -1
  148. package/dist/ListBox.js +670 -0
  149. package/dist/ListBox.js.map +1 -0
  150. package/dist/ListBox.jsx +508 -0
  151. package/dist/ListBox.jsx.map +1 -0
  152. package/dist/Menu.d.ts +27 -9
  153. package/dist/Menu.d.ts.map +1 -1
  154. package/dist/Menu.js +1254 -0
  155. package/dist/Menu.js.map +1 -0
  156. package/dist/Menu.jsx +1042 -0
  157. package/dist/Menu.jsx.map +1 -0
  158. package/dist/Meter.d.ts.map +1 -1
  159. package/dist/Meter.js +123 -0
  160. package/dist/Meter.js.map +1 -0
  161. package/dist/Meter.jsx +107 -0
  162. package/dist/Meter.jsx.map +1 -0
  163. package/dist/Modal.d.ts.map +1 -1
  164. package/dist/Modal.js +380 -0
  165. package/dist/Modal.js.map +1 -0
  166. package/dist/Modal.jsx +314 -0
  167. package/dist/Modal.jsx.map +1 -0
  168. package/dist/NumberField.d.ts +3 -3
  169. package/dist/NumberField.d.ts.map +1 -1
  170. package/dist/NumberField.js +573 -0
  171. package/dist/NumberField.js.map +1 -0
  172. package/dist/NumberField.jsx +443 -0
  173. package/dist/NumberField.jsx.map +1 -0
  174. package/dist/Popover.d.ts +10 -2
  175. package/dist/Popover.d.ts.map +1 -1
  176. package/dist/Popover.js +464 -0
  177. package/dist/Popover.js.map +1 -0
  178. package/dist/Popover.jsx +333 -0
  179. package/dist/Popover.jsx.map +1 -0
  180. package/dist/Pressable.js +69 -0
  181. package/dist/Pressable.js.map +1 -0
  182. package/dist/Pressable.jsx +68 -0
  183. package/dist/Pressable.jsx.map +1 -0
  184. package/dist/ProgressBar.d.ts.map +1 -1
  185. package/dist/ProgressBar.js +130 -0
  186. package/dist/ProgressBar.js.map +1 -0
  187. package/dist/ProgressBar.jsx +114 -0
  188. package/dist/ProgressBar.jsx.map +1 -0
  189. package/dist/RadioGroup.d.ts +82 -4
  190. package/dist/RadioGroup.d.ts.map +1 -1
  191. package/dist/RadioGroup.js +931 -0
  192. package/dist/RadioGroup.js.map +1 -0
  193. package/dist/RadioGroup.jsx +681 -0
  194. package/dist/RadioGroup.jsx.map +1 -0
  195. package/dist/RangeCalendar.d.ts.map +1 -1
  196. package/dist/RangeCalendar.js +410 -0
  197. package/dist/RangeCalendar.js.map +1 -0
  198. package/dist/RangeCalendar.jsx +253 -0
  199. package/dist/RangeCalendar.jsx.map +1 -0
  200. package/dist/RouterProvider.js +118 -0
  201. package/dist/RouterProvider.js.map +1 -0
  202. package/dist/RouterProvider.jsx +112 -0
  203. package/dist/RouterProvider.jsx.map +1 -0
  204. package/dist/SearchField.d.ts +2 -2
  205. package/dist/SearchField.d.ts.map +1 -1
  206. package/dist/SearchField.js +643 -0
  207. package/dist/SearchField.js.map +1 -0
  208. package/dist/SearchField.jsx +526 -0
  209. package/dist/SearchField.jsx.map +1 -0
  210. package/dist/Select.d.ts.map +1 -1
  211. package/dist/Select.js +1031 -0
  212. package/dist/Select.js.map +1 -0
  213. package/dist/Select.jsx +744 -0
  214. package/dist/Select.jsx.map +1 -0
  215. package/dist/SelectionIndicator.d.ts.map +1 -1
  216. package/dist/SelectionIndicator.js +86 -0
  217. package/dist/SelectionIndicator.js.map +1 -0
  218. package/dist/SelectionIndicator.jsx +50 -0
  219. package/dist/SelectionIndicator.jsx.map +1 -0
  220. package/dist/Separator.js +97 -0
  221. package/dist/Separator.js.map +1 -0
  222. package/dist/Separator.jsx +85 -0
  223. package/dist/Separator.jsx.map +1 -0
  224. package/dist/SharedElementTransition.d.ts.map +1 -1
  225. package/dist/SharedElementTransition.js +165 -0
  226. package/dist/SharedElementTransition.js.map +1 -0
  227. package/dist/SharedElementTransition.jsx +138 -0
  228. package/dist/SharedElementTransition.jsx.map +1 -0
  229. package/dist/Slider.d.ts +33 -1
  230. package/dist/Slider.d.ts.map +1 -1
  231. package/dist/Slider.js +515 -0
  232. package/dist/Slider.js.map +1 -0
  233. package/dist/Slider.jsx +403 -0
  234. package/dist/Slider.jsx.map +1 -0
  235. package/dist/StepList.js +198 -0
  236. package/dist/StepList.js.map +1 -0
  237. package/dist/StepList.jsx +141 -0
  238. package/dist/StepList.jsx.map +1 -0
  239. package/dist/Switch.d.ts +65 -2
  240. package/dist/Switch.d.ts.map +1 -1
  241. package/dist/Switch.js +534 -0
  242. package/dist/Switch.js.map +1 -0
  243. package/dist/Switch.jsx +393 -0
  244. package/dist/Switch.jsx.map +1 -0
  245. package/dist/Table.d.ts +48 -0
  246. package/dist/Table.d.ts.map +1 -1
  247. package/dist/Table.js +1759 -0
  248. package/dist/Table.js.map +1 -0
  249. package/dist/Table.jsx +1348 -0
  250. package/dist/Table.jsx.map +1 -0
  251. package/dist/Tabs.d.ts +0 -4
  252. package/dist/Tabs.d.ts.map +1 -1
  253. package/dist/Tabs.js +595 -0
  254. package/dist/Tabs.js.map +1 -0
  255. package/dist/Tabs.jsx +367 -0
  256. package/dist/Tabs.jsx.map +1 -0
  257. package/dist/TagGroup.d.ts.map +1 -1
  258. package/dist/TagGroup.js +378 -0
  259. package/dist/TagGroup.js.map +1 -0
  260. package/dist/TagGroup.jsx +270 -0
  261. package/dist/TagGroup.jsx.map +1 -0
  262. package/dist/Text.d.ts +18 -6
  263. package/dist/Text.d.ts.map +1 -1
  264. package/dist/Text.js +42 -0
  265. package/dist/Text.js.map +1 -0
  266. package/dist/Text.jsx +35 -0
  267. package/dist/Text.jsx.map +1 -0
  268. package/dist/TextField.d.ts +6 -6
  269. package/dist/TextField.d.ts.map +1 -1
  270. package/dist/TextField.js +436 -0
  271. package/dist/TextField.js.map +1 -0
  272. package/dist/TextField.jsx +403 -0
  273. package/dist/TextField.jsx.map +1 -0
  274. package/dist/TimeField.d.ts +3 -3
  275. package/dist/TimeField.d.ts.map +1 -1
  276. package/dist/TimeField.js +372 -0
  277. package/dist/TimeField.js.map +1 -0
  278. package/dist/TimeField.jsx +224 -0
  279. package/dist/TimeField.jsx.map +1 -0
  280. package/dist/Toast.d.ts +14 -0
  281. package/dist/Toast.d.ts.map +1 -1
  282. package/dist/Toast.js +551 -0
  283. package/dist/Toast.js.map +1 -0
  284. package/dist/Toast.jsx +361 -0
  285. package/dist/Toast.jsx.map +1 -0
  286. package/dist/ToggleButton.d.ts.map +1 -1
  287. package/dist/ToggleButton.js +123 -0
  288. package/dist/ToggleButton.js.map +1 -0
  289. package/dist/ToggleButton.jsx +88 -0
  290. package/dist/ToggleButton.jsx.map +1 -0
  291. package/dist/ToggleButtonGroup.d.ts.map +1 -1
  292. package/dist/ToggleButtonGroup.js +114 -0
  293. package/dist/ToggleButtonGroup.js.map +1 -0
  294. package/dist/ToggleButtonGroup.jsx +85 -0
  295. package/dist/ToggleButtonGroup.jsx.map +1 -0
  296. package/dist/Toolbar.js +112 -0
  297. package/dist/Toolbar.js.map +1 -0
  298. package/dist/Toolbar.jsx +92 -0
  299. package/dist/Toolbar.jsx.map +1 -0
  300. package/dist/Tooltip.d.ts.map +1 -1
  301. package/dist/Tooltip.js +539 -0
  302. package/dist/Tooltip.js.map +1 -0
  303. package/dist/Tooltip.jsx +465 -0
  304. package/dist/Tooltip.jsx.map +1 -0
  305. package/dist/Tree.d.ts +14 -2
  306. package/dist/Tree.d.ts.map +1 -1
  307. package/dist/Tree.js +1424 -0
  308. package/dist/Tree.js.map +1 -0
  309. package/dist/Tree.jsx +1172 -0
  310. package/dist/Tree.jsx.map +1 -0
  311. package/dist/Virtualizer.d.ts +16 -2
  312. package/dist/Virtualizer.d.ts.map +1 -1
  313. package/dist/Virtualizer.js +2 -0
  314. package/dist/Virtualizer.jsx +2 -0
  315. package/dist/Virtualizer2.js +751 -0
  316. package/dist/Virtualizer2.js.map +1 -0
  317. package/dist/Virtualizer2.jsx +730 -0
  318. package/dist/Virtualizer2.jsx.map +1 -0
  319. package/dist/VirtualizerLayouts.d.ts +18 -0
  320. package/dist/VirtualizerLayouts.d.ts.map +1 -1
  321. package/dist/VisuallyHidden.js +42 -0
  322. package/dist/VisuallyHidden.js.map +1 -0
  323. package/dist/VisuallyHidden.jsx +35 -0
  324. package/dist/VisuallyHidden.jsx.map +1 -0
  325. package/dist/contexts.js +33 -0
  326. package/dist/contexts.js.map +1 -0
  327. package/dist/contexts.jsx +33 -0
  328. package/dist/contexts.jsx.map +1 -0
  329. package/dist/index.d.ts +7 -6
  330. package/dist/index.d.ts.map +1 -1
  331. package/dist/index.js +70 -23932
  332. package/dist/index.jsx +70 -18337
  333. package/dist/useDragAndDrop.js +2 -0
  334. package/dist/useDragAndDrop.jsx +2 -0
  335. package/dist/useDragAndDrop2.js +395 -0
  336. package/dist/useDragAndDrop2.js.map +1 -0
  337. package/dist/useDragAndDrop2.jsx +395 -0
  338. package/dist/useDragAndDrop2.jsx.map +1 -0
  339. package/dist/utils.d.ts +83 -11
  340. package/dist/utils.d.ts.map +1 -1
  341. package/dist/utils.js +285 -0
  342. package/dist/utils.js.map +1 -0
  343. package/dist/utils.jsx +277 -0
  344. package/dist/utils.jsx.map +1 -0
  345. package/dist/virtualizer/Layout.js +144 -0
  346. package/dist/virtualizer/Layout.js.map +1 -0
  347. package/dist/virtualizer/Layout.jsx +144 -0
  348. package/dist/virtualizer/Layout.jsx.map +1 -0
  349. package/package.json +401 -4
  350. package/src/Breadcrumbs.tsx +3 -1
  351. package/src/Button.tsx +22 -2
  352. package/src/Calendar.tsx +27 -10
  353. package/src/CalendarPicker.tsx +73 -0
  354. package/src/Checkbox.tsx +539 -3
  355. package/src/Collection.tsx +9 -3
  356. package/src/Color.tsx +42 -14
  357. package/src/ComboBox.tsx +50 -6
  358. package/src/DateField.tsx +20 -2
  359. package/src/DatePicker.tsx +57 -5
  360. package/src/Dialog.tsx +13 -5
  361. package/src/Disclosure.tsx +3 -1
  362. package/src/DragAndDrop.tsx +3 -1
  363. package/src/DropZone.tsx +3 -1
  364. package/src/GridList.tsx +125 -24
  365. package/src/Icon.tsx +3 -1
  366. package/src/Link.tsx +3 -1
  367. package/src/ListBox.tsx +31 -4
  368. package/src/Menu.tsx +252 -128
  369. package/src/Meter.tsx +3 -1
  370. package/src/Modal.tsx +100 -52
  371. package/src/NumberField.tsx +51 -8
  372. package/src/Popover.tsx +40 -10
  373. package/src/ProgressBar.tsx +3 -1
  374. package/src/RadioGroup.tsx +468 -4
  375. package/src/RangeCalendar.tsx +3 -1
  376. package/src/SearchField.tsx +27 -3
  377. package/src/Select.tsx +22 -7
  378. package/src/SelectionIndicator.tsx +3 -1
  379. package/src/SharedElementTransition.tsx +3 -1
  380. package/src/Slider.tsx +159 -13
  381. package/src/Switch.tsx +395 -2
  382. package/src/Table.tsx +409 -95
  383. package/src/Tabs.tsx +16 -45
  384. package/src/TagGroup.tsx +3 -1
  385. package/src/Text.tsx +31 -10
  386. package/src/TextField.tsx +43 -5
  387. package/src/TimeField.tsx +20 -2
  388. package/src/Toast.tsx +79 -14
  389. package/src/ToggleButton.tsx +3 -1
  390. package/src/ToggleButtonGroup.tsx +3 -1
  391. package/src/Tooltip.tsx +3 -1
  392. package/src/Tree.tsx +77 -9
  393. package/src/Virtualizer.tsx +180 -31
  394. package/src/VirtualizerLayouts.ts +45 -10
  395. package/src/index.ts +50 -0
  396. package/src/utils.tsx +243 -27
  397. package/dist/index.js.map +0 -1
  398. package/dist/index.jsx.map +0 -1
package/src/Menu.tsx CHANGED
@@ -26,6 +26,7 @@ import {
26
26
  createHover,
27
27
  createButton,
28
28
  createInteractOutside,
29
+ createScrollIntoViewOnFocus,
29
30
  mergeProps,
30
31
  FocusScope,
31
32
  type AriaMenuProps,
@@ -86,7 +87,7 @@ export interface MenuRenderProps {
86
87
 
87
88
  export interface MenuProps<T>
88
89
  extends
89
- Omit<AriaMenuProps, "children">,
90
+ Omit<AriaMenuProps<T>, "children">,
90
91
  SlotProps,
91
92
  Pick<
92
93
  MenuStateProps<T>,
@@ -108,8 +109,10 @@ export interface MenuProps<T>
108
109
  getDisabled?: (item: T) => boolean;
109
110
  /** Keys of disabled items. */
110
111
  disabledKeys?: Iterable<Key>;
111
- /** Handler called when an item is activated. */
112
- onAction?: (key: Key) => void;
112
+ /** Whether disabled items can still receive focus. */
113
+ disabledBehavior?: "selection" | "all";
114
+ /** Handler called when an item is activated, with the activated item's value. */
115
+ onAction?: (key: Key, value: T) => void;
113
116
  /** Handler called when the menu should close. */
114
117
  onClose?: () => void;
115
118
  /** The children of the component. A function may be provided to render each item. */
@@ -125,12 +128,9 @@ export interface MenuProps<T>
125
128
  /** Whether the menu should close when an item is selected. */
126
129
  shouldCloseOnSelect?: boolean;
127
130
  /** Ref for the menu element. */
128
- ref?: RefLike<HTMLUListElement>;
131
+ ref?: RefLike<HTMLDivElement>;
129
132
  /** Custom renderer for the menu element. */
130
- render?: (
131
- props: JSX.HTMLAttributes<HTMLUListElement>,
132
- renderProps: MenuRenderProps,
133
- ) => JSX.Element;
133
+ render?: (props: JSX.HTMLAttributes<HTMLDivElement>, renderProps: MenuRenderProps) => JSX.Element;
134
134
  /** Drag and drop hooks from `useDragAndDrop`. */
135
135
  dragAndDropHooks?: DragAndDropHooks<T>;
136
136
  }
@@ -154,9 +154,22 @@ export interface MenuItemRenderProps {
154
154
  hasSubmenu: boolean;
155
155
  /** Whether the submenu is currently open. */
156
156
  isOpen: boolean;
157
+ /**
158
+ * Internal: props (carrying the slot `id` the item's `aria-describedby`
159
+ * references) for the item's description text element. Threaded to the styled
160
+ * `Text slot="description"` so it receives the id — mirrors upstream's
161
+ * `TextContext` description-slot delegation.
162
+ */
163
+ descriptionProps?: JSX.HTMLAttributes<HTMLElement>;
164
+ /**
165
+ * Internal: props (id + `aria-hidden`) for the item's keyboard-shortcut
166
+ * element, threaded to the styled `Keyboard`.
167
+ */
168
+ keyboardShortcutProps?: JSX.HTMLAttributes<HTMLElement>;
157
169
  }
158
170
 
159
- export interface MenuItemProps<T> extends Omit<AriaMenuItemProps, "children" | "key">, SlotProps {
171
+ export interface MenuItemProps<T>
172
+ extends Omit<AriaMenuItemProps, "children" | "key" | "id">, SlotProps {
160
173
  /** The unique key for the item. */
161
174
  id: Key;
162
175
  /** The item value. */
@@ -185,11 +198,11 @@ export interface MenuItemProps<T> extends Omit<AriaMenuItemProps, "children" | "
185
198
  onHoverEnd?: () => void;
186
199
  /** Handler called when hover state changes. */
187
200
  onHoverChange?: (isHovered: boolean) => void;
188
- /** Ref for the menu item element. */
189
- ref?: RefLike<HTMLLIElement>;
201
+ /** Ref for the menu item element (a `<div>`, or an `<a>` for link items). */
202
+ ref?: RefLike<HTMLElement>;
190
203
  /** Custom renderer for the menu item element. */
191
204
  render?: (
192
- props: JSX.HTMLAttributes<HTMLLIElement>,
205
+ props: JSX.HTMLAttributes<HTMLElement>,
193
206
  renderProps: MenuItemRenderProps,
194
207
  ) => JSX.Element;
195
208
  }
@@ -249,13 +262,15 @@ interface MenuTriggerContextValue {
249
262
  state: OverlayTriggerState;
250
263
  triggerProps: JSX.HTMLAttributes<HTMLElement>;
251
264
  menuProps: JSX.HTMLAttributes<HTMLElement>;
265
+ isPressed?: () => boolean;
266
+ onPressStart?: (e: { pointerType?: string }) => void;
252
267
  }
253
268
 
254
269
  interface MenuItemContextValue {
255
270
  props?: () => JSX.HTMLAttributes<HTMLElement>;
256
271
  closeOnSelect?: boolean;
257
272
  onAction?: () => void;
258
- setItemRef?: (el: HTMLLIElement | null) => void;
273
+ setItemRef?: (el: HTMLElement | null) => void;
259
274
  }
260
275
 
261
276
  interface StaticMenuCollectionItem {
@@ -283,6 +298,12 @@ interface MenuSectionSelectionRegistryContextValue {
283
298
  selectItem(key: Key, event?: MenuSelectionEvent): boolean;
284
299
  }
285
300
 
301
+ interface MenuItemCloseRegistryContextValue {
302
+ registerItem(key: Key, shouldCloseOnSelect: () => boolean | undefined): void;
303
+ unregisterItem(key: Key, shouldCloseOnSelect: () => boolean | undefined): void;
304
+ shouldCloseOnSelect(key: Key | null): boolean | undefined;
305
+ }
306
+
286
307
  export const MenuContext = createContext<MenuContextValue<unknown> | null>(null);
287
308
  export const MenuStateContext = createContext<MenuState<unknown> | null>(null);
288
309
  export const MenuTriggerContext = createContext<MenuTriggerContextValue | null>(null);
@@ -292,6 +313,7 @@ const StaticMenuCollectionContext = createContext<StaticMenuCollectionContextVal
292
313
  const MenuSectionSelectionContext = createContext<MenuSectionSelectionContextValue | null>(null);
293
314
  const MenuSectionSelectionRegistryContext =
294
315
  createContext<MenuSectionSelectionRegistryContextValue | null>(null);
316
+ const MenuItemCloseRegistryContext = createContext<MenuItemCloseRegistryContextValue | null>(null);
295
317
 
296
318
  type RefLike<T> = ((el: T) => void) | { current?: T | null } | undefined;
297
319
 
@@ -323,6 +345,22 @@ export function MenuTrigger(props: MenuTriggerProps): JSX.Element {
323
345
  },
324
346
  });
325
347
 
348
+ const [isMousePressed, setMousePressed] = createSignal(false);
349
+ const onPressStart = (e: { pointerType?: string }) => {
350
+ if (e.pointerType !== "mouse" || typeof document === "undefined") {
351
+ return;
352
+ }
353
+
354
+ setMousePressed(true);
355
+ document.addEventListener(
356
+ "pointerup",
357
+ () => {
358
+ setMousePressed(false);
359
+ },
360
+ { once: true, capture: true },
361
+ );
362
+ };
363
+
326
364
  const menuTrigger = createMenuTrigger(
327
365
  {
328
366
  get isDisabled() {
@@ -343,6 +381,8 @@ export function MenuTrigger(props: MenuTriggerProps): JSX.Element {
343
381
  get menuProps() {
344
382
  return menuTrigger.menuProps;
345
383
  },
384
+ isPressed: isMousePressed,
385
+ onPressStart,
346
386
  }}
347
387
  >
348
388
  {props.children}
@@ -369,7 +409,7 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
369
409
  },
370
410
  });
371
411
 
372
- let triggerRef: HTMLLIElement | null = null;
412
+ let triggerRef: HTMLElement | null = null;
373
413
  const triggerId = createUniqueId();
374
414
  const menuId = createUniqueId();
375
415
  let hoverTimeout: number | undefined;
@@ -448,7 +488,7 @@ export function SubmenuTrigger(props: SubmenuTriggerProps): JSX.Element {
448
488
  },
449
489
  triggerRef: () => triggerRef,
450
490
  setTriggerRef: (el: HTMLElement | null) => {
451
- triggerRef = el as HTMLLIElement | null;
491
+ triggerRef = el;
452
492
  },
453
493
  triggerId,
454
494
  trigger: "SubmenuTrigger",
@@ -550,6 +590,9 @@ export function MenuButton(props: MenuButtonProps): JSX.Element {
550
590
  get isDisabled() {
551
591
  return local.isDisabled;
552
592
  },
593
+ onPressStart(e) {
594
+ context.onPressStart?.(e);
595
+ },
553
596
  onPress() {
554
597
  state.toggle();
555
598
  },
@@ -567,14 +610,16 @@ export function MenuButton(props: MenuButtonProps): JSX.Element {
567
610
  isOpen: state.isOpen(),
568
611
  isFocused: isFocused(),
569
612
  isFocusVisible: isFocusVisible(),
570
- isPressed: buttonAria.isPressed(),
613
+ isPressed: context.isPressed?.() || buttonAria.isPressed(),
571
614
  isHovered: isHovered(),
572
615
  isDisabled: !!local.isDisabled,
573
616
  }));
574
617
 
575
618
  const renderProps = useRenderProps(
576
619
  {
577
- children: props.children,
620
+ get children() {
621
+ return props.children;
622
+ },
578
623
  class: local.class,
579
624
  style: local.style,
580
625
  defaultClassName: "solidaria-MenuButton",
@@ -624,7 +669,7 @@ export function MenuButton(props: MenuButtonProps): JSX.Element {
624
669
  data-open={state.isOpen() || undefined}
625
670
  data-focused={isFocused() || undefined}
626
671
  data-focus-visible={isFocusVisible() || undefined}
627
- data-pressed={buttonAria.isPressed() || undefined}
672
+ data-pressed={context.isPressed?.() || buttonAria.isPressed() || undefined}
628
673
  data-hovered={isHovered() || undefined}
629
674
  data-disabled={local.isDisabled || undefined}
630
675
  >
@@ -639,23 +684,14 @@ export function MenuButton(props: MenuButtonProps): JSX.Element {
639
684
  export function Menu<T>(props: MenuProps<T>): JSX.Element {
640
685
  const [local, stateProps, ariaProps] = splitProps(
641
686
  props,
642
- [
643
- "children",
644
- "class",
645
- "style",
646
- "render",
647
- "slot",
648
- "renderEmptyState",
649
- "shouldCloseOnSelect",
650
- "ref",
651
- "staticChildren",
652
- ],
687
+ ["children", "class", "style", "render", "slot", "renderEmptyState", "ref", "staticChildren"],
653
688
  [
654
689
  "items",
655
690
  "getKey",
656
691
  "getTextValue",
657
692
  "getDisabled",
658
693
  "disabledKeys",
694
+ "disabledBehavior",
659
695
  "selectionMode",
660
696
  "selectionBehavior",
661
697
  "disallowEmptySelection",
@@ -665,16 +701,18 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
665
701
  "allowDuplicateSelectionEvents",
666
702
  "onAction",
667
703
  "onClose",
704
+ "shouldCloseOnSelect",
668
705
  "dragAndDropHooks",
669
706
  ],
670
707
  );
671
708
 
672
709
  const triggerContext = useContext(MenuTriggerContext);
673
710
 
674
- const [menuRef, setMenuRef] = createSignal<HTMLUListElement | null>(null);
711
+ const [menuRef, setMenuRef] = createSignal<HTMLDivElement | null>(null);
675
712
  const [staticItems, setStaticItems] = createSignal<StaticMenuCollectionItem[]>([]);
676
713
  const staticItemMap = new Map<Key, StaticMenuCollectionItem>();
677
714
  const sectionSelectionMap = new Map<Key, MenuSectionSelectionContextValue>();
715
+ const itemCloseMap = new Map<Key, () => boolean | undefined>();
678
716
  const usesStaticChildren = () => local.staticChildren != null || stateProps.items == null;
679
717
 
680
718
  const syncStaticItems = () => {
@@ -720,9 +758,27 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
720
758
  return true;
721
759
  },
722
760
  };
723
- const handleAction = (key: Key) => {
761
+ const itemCloseRegistry: MenuItemCloseRegistryContextValue = {
762
+ registerItem(key, shouldCloseOnSelect) {
763
+ itemCloseMap.set(key, shouldCloseOnSelect);
764
+ },
765
+ unregisterItem(key, shouldCloseOnSelect) {
766
+ if (itemCloseMap.get(key) === shouldCloseOnSelect) {
767
+ itemCloseMap.delete(key);
768
+ }
769
+ },
770
+ shouldCloseOnSelect(key) {
771
+ return key == null ? undefined : itemCloseMap.get(key)?.();
772
+ },
773
+ };
774
+ const handleAction = (key: Key, value?: T) => {
724
775
  sectionSelectionRegistry.selectItem(key);
725
- stateProps.onAction?.(key);
776
+ // Forward the activated item's value, which `createMenuState` sets from the
777
+ // collection node. For dynamic collections this is the user's data item.
778
+ // Static children are modeled with an internal item descriptor that upstream
779
+ // RAC does not expose as `value` (MenuItem only carries `value` for dynamic
780
+ // collections), so it is suppressed there to match.
781
+ stateProps.onAction?.(key, (usesStaticChildren() ? undefined : value) as T);
726
782
  };
727
783
 
728
784
  const flatItems = createMemo<T[]>(() => {
@@ -757,6 +813,9 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
757
813
  get disabledKeys() {
758
814
  return stateProps.disabledKeys;
759
815
  },
816
+ get disabledBehavior() {
817
+ return stateProps.disabledBehavior;
818
+ },
760
819
  get selectionMode() {
761
820
  return stateProps.selectionMode;
762
821
  },
@@ -808,6 +867,12 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
808
867
  get onClose() {
809
868
  return stateProps.onClose ?? (() => triggerContext?.state.close());
810
869
  },
870
+ get shouldCloseOnSelect() {
871
+ return (
872
+ itemCloseRegistry.shouldCloseOnSelect(state.focusedKey()) ??
873
+ stateProps.shouldCloseOnSelect
874
+ );
875
+ },
811
876
  get "aria-label"() {
812
877
  return ariaProps["aria-label"];
813
878
  },
@@ -821,6 +886,15 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
821
886
  state,
822
887
  );
823
888
 
889
+ // Reveal the activedescendant-focused item on keyboard navigation. The menu
890
+ // keeps real DOM focus on itself, so the browser won't natively scroll an
891
+ // off-screen focused item into view the way roving tabindex would.
892
+ createScrollIntoViewOnFocus({
893
+ focusedKey: () => state.focusedKey(),
894
+ isActive: () => state.isFocused(),
895
+ ref: () => menuRef(),
896
+ });
897
+
824
898
  const { isFocused, focusProps } = createFocusRing();
825
899
 
826
900
  createInteractOutside({
@@ -870,7 +944,7 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
870
944
  const { ref: _ref4, ...rest } = labelProps as Record<string, unknown>;
871
945
  return rest;
872
946
  };
873
- const setResolvedMenuRef = (el: HTMLUListElement): void => {
947
+ const setResolvedMenuRef = (el: HTMLDivElement): void => {
874
948
  setMenuRef(el);
875
949
  assignRef(local.ref, el);
876
950
  };
@@ -1067,31 +1141,31 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
1067
1141
  parentCollectionRenderer?.renderDropIndicator?.(index, position),
1068
1142
  }));
1069
1143
  const menuItemContextValue = createMemo<MenuItemContextValue>(() =>
1070
- local.shouldCloseOnSelect !== undefined
1071
- ? { closeOnSelect: local.shouldCloseOnSelect }
1144
+ stateProps.shouldCloseOnSelect !== undefined
1145
+ ? { closeOnSelect: stateProps.shouldCloseOnSelect }
1072
1146
  : {},
1073
1147
  );
1074
1148
  const menuListChildren = () => (
1075
1149
  <SharedElementTransition>
1076
1150
  {state.collection().size === 0 && !usesStaticChildren() && local.renderEmptyState ? (
1077
- <li role="presentation" data-empty-state>
1151
+ <div role="presentation" data-empty-state>
1078
1152
  <div role="menuitem" style={{ display: "contents" }}>
1079
1153
  {local.renderEmptyState()}
1080
1154
  </div>
1081
- </li>
1155
+ </div>
1082
1156
  ) : usesStaticChildren() ? (
1083
1157
  renderStaticChildren()
1084
1158
  ) : hasSections() ? (
1085
1159
  <For each={sectionedRenderEntries()}>
1086
1160
  {(entry) =>
1087
1161
  entry.type === "section" ? (
1088
- <li role="presentation" data-section-wrapper>
1162
+ <div role="presentation" data-section-wrapper>
1089
1163
  <Section class="solidaria-Menu-section">
1090
1164
  {entry.section.title != null && (
1091
1165
  <Header class="solidaria-Menu-sectionHeader">{entry.section.title}</Header>
1092
1166
  )}
1093
1167
  <Group class="solidaria-Menu-sectionGroup">
1094
- <ul role="group" aria-label={entry.section["aria-label"]}>
1168
+ <div role="group" aria-label={entry.section["aria-label"]}>
1095
1169
  <For each={entry.items}>
1096
1170
  {(indexedItem) => (
1097
1171
  <>
@@ -1105,10 +1179,10 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
1105
1179
  </>
1106
1180
  )}
1107
1181
  </For>
1108
- </ul>
1182
+ </div>
1109
1183
  </Group>
1110
1184
  </Section>
1111
- </li>
1185
+ </div>
1112
1186
  ) : (
1113
1187
  <>
1114
1188
  {collectionRenderer().renderDropIndicator?.(entry.item.index, "before")}
@@ -1122,7 +1196,7 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
1122
1196
  ) : (
1123
1197
  <>
1124
1198
  {virtualRange()?.offsetTop ? (
1125
- <li
1199
+ <div
1126
1200
  role="presentation"
1127
1201
  aria-hidden="true"
1128
1202
  style={{ height: `${virtualRange()!.offsetTop}px` }}
@@ -1149,7 +1223,7 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
1149
1223
  }}
1150
1224
  </For>
1151
1225
  {virtualRange()?.offsetBottom ? (
1152
- <li
1226
+ <div
1153
1227
  role="presentation"
1154
1228
  aria-hidden="true"
1155
1229
  style={{ height: `${virtualRange()!.offsetBottom}px` }}
@@ -1178,7 +1252,7 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
1178
1252
  "data-empty": state.collection().size === 0 || undefined,
1179
1253
  "data-drop-target": isRootDropTarget() || undefined,
1180
1254
  children: menuListChildren(),
1181
- }) as JSX.HTMLAttributes<HTMLUListElement>;
1255
+ }) as JSX.HTMLAttributes<HTMLDivElement>;
1182
1256
 
1183
1257
  // Only use FocusScope when inside a MenuTrigger (for popover behavior)
1184
1258
  // Standalone menus don't need focus restoration
@@ -1196,44 +1270,46 @@ export function Menu<T>(props: MenuProps<T>): JSX.Element {
1196
1270
  >
1197
1271
  <MenuStateContext.Provider value={state}>
1198
1272
  <MenuSectionSelectionRegistryContext.Provider value={sectionSelectionRegistry}>
1199
- <StaticMenuCollectionContext.Provider
1200
- value={usesStaticChildren() ? staticCollectionContext : null}
1201
- >
1202
- <MenuItemContext.Provider value={menuItemContextValue()}>
1203
- <CollectionRendererContext.Provider value={collectionRenderer()}>
1204
- <>
1205
- <Show when={ariaProps.label}>
1206
- <span {...cleanLabelProps()}>{ariaProps.label as JSX.Element}</span>
1207
- </Show>
1208
- {local.render ? (
1209
- local.render(menuListProps(), renderValues())
1210
- ) : (
1211
- <ul
1212
- ref={setResolvedMenuRef}
1213
- {...mergeProps(
1214
- domProps(),
1215
- cleanMenuProps(),
1216
- cleanTriggerMenuProps(),
1217
- cleanFocusProps(),
1218
- (droppableCollection()?.collectionProps as
1219
- | Record<string, unknown>
1220
- | undefined) ?? {},
1221
- )}
1222
- class={renderProps.class()}
1223
- style={renderProps.style()}
1224
- slot={local.slot}
1225
- data-focused={state.isFocused() || undefined}
1226
- data-disabled={resolveDisabled() || undefined}
1227
- data-empty={state.collection().size === 0 || undefined}
1228
- data-drop-target={isRootDropTarget() || undefined}
1229
- >
1230
- {menuListChildren()}
1231
- </ul>
1232
- )}
1233
- </>
1234
- </CollectionRendererContext.Provider>
1235
- </MenuItemContext.Provider>
1236
- </StaticMenuCollectionContext.Provider>
1273
+ <MenuItemCloseRegistryContext.Provider value={itemCloseRegistry}>
1274
+ <StaticMenuCollectionContext.Provider
1275
+ value={usesStaticChildren() ? staticCollectionContext : null}
1276
+ >
1277
+ <MenuItemContext.Provider value={menuItemContextValue()}>
1278
+ <CollectionRendererContext.Provider value={collectionRenderer()}>
1279
+ <>
1280
+ <Show when={ariaProps.label}>
1281
+ <span {...cleanLabelProps()}>{ariaProps.label as JSX.Element}</span>
1282
+ </Show>
1283
+ {local.render ? (
1284
+ local.render(menuListProps(), renderValues())
1285
+ ) : (
1286
+ <div
1287
+ ref={setResolvedMenuRef}
1288
+ {...mergeProps(
1289
+ domProps(),
1290
+ cleanMenuProps(),
1291
+ cleanTriggerMenuProps(),
1292
+ cleanFocusProps(),
1293
+ (droppableCollection()?.collectionProps as
1294
+ | Record<string, unknown>
1295
+ | undefined) ?? {},
1296
+ )}
1297
+ class={renderProps.class()}
1298
+ style={renderProps.style()}
1299
+ slot={local.slot}
1300
+ data-focused={state.isFocused() || undefined}
1301
+ data-disabled={resolveDisabled() || undefined}
1302
+ data-empty={state.collection().size === 0 || undefined}
1303
+ data-drop-target={isRootDropTarget() || undefined}
1304
+ >
1305
+ {menuListChildren()}
1306
+ </div>
1307
+ )}
1308
+ </>
1309
+ </CollectionRendererContext.Provider>
1310
+ </MenuItemContext.Provider>
1311
+ </StaticMenuCollectionContext.Provider>
1312
+ </MenuItemCloseRegistryContext.Provider>
1237
1313
  </MenuSectionSelectionRegistryContext.Provider>
1238
1314
  </MenuStateContext.Provider>
1239
1315
  </MenuContext.Provider>
@@ -1283,17 +1359,26 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1283
1359
  const staticCollection = useContext(StaticMenuCollectionContext);
1284
1360
  const sectionSelection = useContext(MenuSectionSelectionContext);
1285
1361
  const sectionSelectionRegistry = useContext(MenuSectionSelectionRegistryContext);
1286
- const [ref, setRef] = createSignal<HTMLLIElement | null>(null);
1362
+ const itemCloseRegistry = useContext(MenuItemCloseRegistryContext);
1363
+ // Tracks the focusable menuitem element (the <div>, or the <a> for link
1364
+ // items) so roving focus can be moved onto it imperatively.
1365
+ const [ref, setRef] = createSignal<HTMLElement | null>(null);
1287
1366
  const contextProps = () => itemContext?.props?.() ?? {};
1288
1367
  const combinedOnAction = () => {
1289
1368
  local.onAction?.();
1290
1369
  itemContext?.onAction?.();
1291
1370
  };
1371
+ const itemCloseOnSelect = () =>
1372
+ ariaProps.closeOnSelect ??
1373
+ sectionSelection?.shouldCloseOnSelect() ??
1374
+ itemContext?.closeOnSelect;
1292
1375
  const activeSectionSelection = () =>
1293
1376
  sectionSelection && sectionSelection.selectionMode() !== "none" ? sectionSelection : null;
1294
1377
  let registeredStaticKey: Key | null = null;
1295
1378
  let registeredSectionSelectionKey: Key | null = null;
1296
1379
  let registeredSectionSelection: MenuSectionSelectionContextValue | null = null;
1380
+ let registeredCloseKey: Key | null = null;
1381
+ let registeredCloseAccessor: (() => boolean | undefined) | null = null;
1297
1382
 
1298
1383
  const unregisterSectionSelection = () => {
1299
1384
  if (registeredSectionSelectionKey != null && registeredSectionSelection) {
@@ -1347,9 +1432,38 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1347
1432
 
1348
1433
  onCleanup(unregisterSectionSelection);
1349
1434
 
1435
+ const unregisterItemClose = () => {
1436
+ if (registeredCloseKey != null && registeredCloseAccessor) {
1437
+ itemCloseRegistry?.unregisterItem(registeredCloseKey, registeredCloseAccessor);
1438
+ registeredCloseKey = null;
1439
+ registeredCloseAccessor = null;
1440
+ }
1441
+ };
1442
+
1443
+ createEffect(() => {
1444
+ if (!itemCloseRegistry) {
1445
+ unregisterItemClose();
1446
+ return;
1447
+ }
1448
+
1449
+ if (registeredCloseKey === local.id && registeredCloseAccessor === itemCloseOnSelect) {
1450
+ return;
1451
+ }
1452
+
1453
+ unregisterItemClose();
1454
+ registeredCloseKey = local.id;
1455
+ registeredCloseAccessor = itemCloseOnSelect;
1456
+ itemCloseRegistry.registerItem(local.id, itemCloseOnSelect);
1457
+ });
1458
+
1459
+ onCleanup(unregisterItemClose);
1460
+
1350
1461
  const itemAria = createMenuItem<T>(
1351
1462
  {
1352
1463
  key: local.id,
1464
+ get id() {
1465
+ return contextProps().id as string | undefined;
1466
+ },
1353
1467
  get isDisabled() {
1354
1468
  return Boolean(
1355
1469
  ariaProps.isDisabled ||
@@ -1360,15 +1474,20 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1360
1474
  get "aria-label"() {
1361
1475
  return ariaProps["aria-label"] ?? local.textValue;
1362
1476
  },
1477
+ get "aria-controls"() {
1478
+ return contextProps()["aria-controls"] as string | undefined;
1479
+ },
1480
+ get "aria-haspopup"() {
1481
+ return contextProps()["aria-haspopup"] as string | boolean | undefined;
1482
+ },
1483
+ get "aria-expanded"() {
1484
+ return contextProps()["aria-expanded"] as boolean | "true" | "false" | undefined;
1485
+ },
1363
1486
  get onAction() {
1364
1487
  return combinedOnAction;
1365
1488
  },
1366
1489
  get closeOnSelect() {
1367
- return (
1368
- ariaProps.closeOnSelect ??
1369
- sectionSelection?.shouldCloseOnSelect() ??
1370
- itemContext?.closeOnSelect
1371
- );
1490
+ return itemCloseOnSelect();
1372
1491
  },
1373
1492
  get href() {
1374
1493
  return local.href;
@@ -1384,6 +1503,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1384
1503
  },
1385
1504
  },
1386
1505
  state,
1506
+ () => ref(),
1387
1507
  );
1388
1508
 
1389
1509
  const { isHovered, hoverProps } = createHover({
@@ -1407,12 +1527,16 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1407
1527
  isDisabled: itemAria.isDisabled(),
1408
1528
  hasSubmenu: Boolean(contextProps()["aria-haspopup"]),
1409
1529
  isOpen: contextProps()["aria-expanded"] === true,
1530
+ descriptionProps: itemAria.descriptionProps,
1531
+ keyboardShortcutProps: itemAria.keyboardShortcutProps,
1410
1532
  };
1411
1533
  });
1412
1534
 
1413
1535
  const renderProps = useRenderProps(
1414
1536
  {
1415
- children: props.children,
1537
+ get children() {
1538
+ return props.children;
1539
+ },
1416
1540
  class: local.class,
1417
1541
  style: local.style,
1418
1542
  defaultClassName: "solidaria-Menu-item",
@@ -1424,11 +1548,13 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1424
1548
  };
1425
1549
 
1426
1550
  const cleanItemProps = () => {
1427
- const {
1428
- ref: _ref1,
1429
- "aria-describedby": _ariaDescribedby,
1430
- ...rest
1431
- } = itemAria.menuItemProps as Record<string, unknown>;
1551
+ // Keep `aria-describedby`: the headless emits it (via `createSlotId`) only
1552
+ // when a description/keyboard element is actually rendered, so it points at
1553
+ // the styled `Text slot="description"` + `Keyboard` ids threaded through
1554
+ // `renderValues` below — restoring upstream's two-context description
1555
+ // delegation. `createSlotId` clears it to `undefined` on description-less
1556
+ // items, so nothing dangles.
1557
+ const { ref: _ref1, ...rest } = itemAria.menuItemProps as Record<string, unknown>;
1432
1558
  if (!hasPrimitiveLabel() && rest["aria-label"] == null) {
1433
1559
  delete rest["aria-labelledby"];
1434
1560
  }
@@ -1519,7 +1645,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1519
1645
  ) : (
1520
1646
  renderProps.renderChildren()
1521
1647
  );
1522
- const setResolvedItemRef = (el: HTMLLIElement | null) => {
1648
+ const setResolvedItemRef = (el: HTMLElement | null) => {
1523
1649
  setRef(el);
1524
1650
  itemContext?.setItemRef?.(el);
1525
1651
  if (el) assignRef(local.ref, el);
@@ -1539,7 +1665,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1539
1665
  style: renderProps.style(),
1540
1666
  ...dataAttrs(),
1541
1667
  children: childContent(),
1542
- }) as JSX.HTMLAttributes<HTMLLIElement>;
1668
+ }) as JSX.HTMLAttributes<HTMLElement>;
1543
1669
  const linkMenuItemProps = () =>
1544
1670
  ({
1545
1671
  ...mergeProps(
@@ -1555,7 +1681,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1555
1681
  style: renderProps.style(),
1556
1682
  ...dataAttrs(),
1557
1683
  children: childContent(),
1558
- }) as JSX.HTMLAttributes<HTMLLIElement>;
1684
+ }) as JSX.HTMLAttributes<HTMLElement>;
1559
1685
 
1560
1686
  if (local.render && !isLink()) {
1561
1687
  return local.render(menuItemProps(), renderValues());
@@ -1565,7 +1691,7 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1565
1691
  <Show
1566
1692
  when={isLink()}
1567
1693
  fallback={
1568
- <li
1694
+ <div
1569
1695
  ref={(el) => {
1570
1696
  setRef(el);
1571
1697
  itemContext?.setItemRef?.(el);
@@ -1584,38 +1710,36 @@ export function MenuItem<T>(props: MenuItemProps<T>): JSX.Element {
1584
1710
  {...dataAttrs()}
1585
1711
  >
1586
1712
  {childContent()}
1587
- </li>
1713
+ </div>
1588
1714
  }
1589
1715
  >
1590
- <li
1591
- ref={(el) => {
1592
- setRef(el);
1593
- itemContext?.setItemRef?.(el);
1594
- assignRef(local.ref, el);
1595
- }}
1596
- role="presentation"
1597
- >
1598
- {local.render ? (
1599
- local.render(linkMenuItemProps(), renderValues())
1600
- ) : (
1601
- <a
1602
- {...mergeProps(
1603
- cleanItemPropsForLink(),
1604
- contextProps() as Record<string, unknown>,
1605
- domProps(),
1606
- cleanHoverProps(),
1607
- linkDomProps(),
1608
- (draggableItem()?.dragProps as Record<string, unknown> | undefined) ?? {},
1609
- (droppableItem()?.dropProps as Record<string, unknown> | undefined) ?? {},
1610
- )}
1611
- class={renderProps.class()}
1612
- style={renderProps.style()}
1613
- {...dataAttrs()}
1614
- >
1615
- {childContent()}
1616
- </a>
1617
- )}
1618
- </li>
1716
+ {local.render ? (
1717
+ local.render(linkMenuItemProps(), renderValues())
1718
+ ) : (
1719
+ // Upstream renders the link menuitem as a bare <a role="menuitem"> (no
1720
+ // presentation wrapper); the <div> root makes the wrapper unnecessary.
1721
+ <a
1722
+ ref={(el) => {
1723
+ setRef(el);
1724
+ itemContext?.setItemRef?.(el);
1725
+ assignRef(local.ref, el);
1726
+ }}
1727
+ {...mergeProps(
1728
+ cleanItemPropsForLink(),
1729
+ contextProps() as Record<string, unknown>,
1730
+ domProps(),
1731
+ cleanHoverProps(),
1732
+ linkDomProps(),
1733
+ (draggableItem()?.dragProps as Record<string, unknown> | undefined) ?? {},
1734
+ (droppableItem()?.dropProps as Record<string, unknown> | undefined) ?? {},
1735
+ )}
1736
+ class={renderProps.class()}
1737
+ style={renderProps.style()}
1738
+ {...dataAttrs()}
1739
+ >
1740
+ {childContent()}
1741
+ </a>
1742
+ )}
1619
1743
  </Show>
1620
1744
  );
1621
1745
  }