react-aria-components 1.10.1 → 1.11.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 (302) hide show
  1. package/dist/Breadcrumbs.main.js +9 -2
  2. package/dist/Breadcrumbs.main.js.map +1 -1
  3. package/dist/Breadcrumbs.mjs +10 -3
  4. package/dist/Breadcrumbs.module.js +10 -3
  5. package/dist/Breadcrumbs.module.js.map +1 -1
  6. package/dist/Button.main.js +7 -17
  7. package/dist/Button.main.js.map +1 -1
  8. package/dist/Button.mjs +7 -17
  9. package/dist/Button.module.js +7 -17
  10. package/dist/Button.module.js.map +1 -1
  11. package/dist/Calendar.main.js +36 -14
  12. package/dist/Calendar.main.js.map +1 -1
  13. package/dist/Calendar.mjs +38 -16
  14. package/dist/Calendar.module.js +38 -16
  15. package/dist/Calendar.module.js.map +1 -1
  16. package/dist/Checkbox.main.js +8 -3
  17. package/dist/Checkbox.main.js.map +1 -1
  18. package/dist/Checkbox.mjs +10 -5
  19. package/dist/Checkbox.module.js +10 -5
  20. package/dist/Checkbox.module.js.map +1 -1
  21. package/dist/Collection.main.js.map +1 -1
  22. package/dist/Collection.module.js.map +1 -1
  23. package/dist/ColorArea.main.js +4 -4
  24. package/dist/ColorArea.main.js.map +1 -1
  25. package/dist/ColorArea.mjs +5 -5
  26. package/dist/ColorArea.module.js +5 -5
  27. package/dist/ColorArea.module.js.map +1 -1
  28. package/dist/ColorField.main.js +14 -1
  29. package/dist/ColorField.main.js.map +1 -1
  30. package/dist/ColorField.mjs +14 -1
  31. package/dist/ColorField.module.js +14 -1
  32. package/dist/ColorField.module.js.map +1 -1
  33. package/dist/ColorSlider.main.js +3 -1
  34. package/dist/ColorSlider.main.js.map +1 -1
  35. package/dist/ColorSlider.mjs +3 -1
  36. package/dist/ColorSlider.module.js +3 -1
  37. package/dist/ColorSlider.module.js.map +1 -1
  38. package/dist/ColorSwatch.main.js +6 -2
  39. package/dist/ColorSwatch.main.js.map +1 -1
  40. package/dist/ColorSwatch.mjs +6 -2
  41. package/dist/ColorSwatch.module.js +6 -2
  42. package/dist/ColorSwatch.module.js.map +1 -1
  43. package/dist/ColorSwatchPicker.main.js.map +1 -1
  44. package/dist/ColorSwatchPicker.module.js.map +1 -1
  45. package/dist/ColorThumb.main.js +3 -1
  46. package/dist/ColorThumb.main.js.map +1 -1
  47. package/dist/ColorThumb.mjs +3 -1
  48. package/dist/ColorThumb.module.js +3 -1
  49. package/dist/ColorThumb.module.js.map +1 -1
  50. package/dist/ColorWheel.main.js +3 -1
  51. package/dist/ColorWheel.main.js.map +1 -1
  52. package/dist/ColorWheel.mjs +3 -1
  53. package/dist/ColorWheel.module.js +3 -1
  54. package/dist/ColorWheel.module.js.map +1 -1
  55. package/dist/ComboBox.main.js +4 -1
  56. package/dist/ComboBox.main.js.map +1 -1
  57. package/dist/ComboBox.mjs +4 -1
  58. package/dist/ComboBox.module.js +4 -1
  59. package/dist/ComboBox.module.js.map +1 -1
  60. package/dist/DateField.main.js +16 -3
  61. package/dist/DateField.main.js.map +1 -1
  62. package/dist/DateField.mjs +16 -3
  63. package/dist/DateField.module.js +16 -3
  64. package/dist/DateField.module.js.map +1 -1
  65. package/dist/DatePicker.main.js +15 -8
  66. package/dist/DatePicker.main.js.map +1 -1
  67. package/dist/DatePicker.mjs +16 -9
  68. package/dist/DatePicker.module.js +16 -9
  69. package/dist/DatePicker.module.js.map +1 -1
  70. package/dist/Dialog.main.js +4 -3
  71. package/dist/Dialog.main.js.map +1 -1
  72. package/dist/Dialog.mjs +5 -4
  73. package/dist/Dialog.module.js +5 -4
  74. package/dist/Dialog.module.js.map +1 -1
  75. package/dist/Disclosure.main.js +12 -10
  76. package/dist/Disclosure.main.js.map +1 -1
  77. package/dist/Disclosure.mjs +13 -11
  78. package/dist/Disclosure.module.js +13 -11
  79. package/dist/Disclosure.module.js.map +1 -1
  80. package/dist/DragAndDrop.main.js +31 -3
  81. package/dist/DragAndDrop.main.js.map +1 -1
  82. package/dist/DragAndDrop.mjs +31 -3
  83. package/dist/DragAndDrop.module.js +31 -3
  84. package/dist/DragAndDrop.module.js.map +1 -1
  85. package/dist/DropZone.main.js +4 -3
  86. package/dist/DropZone.main.js.map +1 -1
  87. package/dist/DropZone.mjs +4 -3
  88. package/dist/DropZone.module.js +4 -3
  89. package/dist/DropZone.module.js.map +1 -1
  90. package/dist/FieldError.main.js +3 -1
  91. package/dist/FieldError.main.js.map +1 -1
  92. package/dist/FieldError.mjs +3 -1
  93. package/dist/FieldError.module.js +3 -1
  94. package/dist/FieldError.module.js.map +1 -1
  95. package/dist/FileTrigger.main.js +3 -1
  96. package/dist/FileTrigger.main.js.map +1 -1
  97. package/dist/FileTrigger.mjs +3 -1
  98. package/dist/FileTrigger.module.js +3 -1
  99. package/dist/FileTrigger.module.js.map +1 -1
  100. package/dist/Form.main.js.map +1 -1
  101. package/dist/Form.module.js.map +1 -1
  102. package/dist/GridList.main.js +20 -13
  103. package/dist/GridList.main.js.map +1 -1
  104. package/dist/GridList.mjs +21 -14
  105. package/dist/GridList.module.js +21 -14
  106. package/dist/GridList.module.js.map +1 -1
  107. package/dist/HiddenDateInput.main.js +118 -0
  108. package/dist/HiddenDateInput.main.js.map +1 -0
  109. package/dist/HiddenDateInput.mjs +109 -0
  110. package/dist/HiddenDateInput.module.js +109 -0
  111. package/dist/HiddenDateInput.module.js.map +1 -0
  112. package/dist/Link.main.js +7 -1
  113. package/dist/Link.main.js.map +1 -1
  114. package/dist/Link.mjs +7 -1
  115. package/dist/Link.module.js +7 -1
  116. package/dist/Link.module.js.map +1 -1
  117. package/dist/ListBox.main.js +22 -19
  118. package/dist/ListBox.main.js.map +1 -1
  119. package/dist/ListBox.mjs +23 -20
  120. package/dist/ListBox.module.js +23 -20
  121. package/dist/ListBox.module.js.map +1 -1
  122. package/dist/Menu.main.js +15 -8
  123. package/dist/Menu.main.js.map +1 -1
  124. package/dist/Menu.mjs +16 -9
  125. package/dist/Menu.module.js +16 -9
  126. package/dist/Menu.module.js.map +1 -1
  127. package/dist/Meter.main.js +6 -2
  128. package/dist/Meter.main.js.map +1 -1
  129. package/dist/Meter.mjs +6 -2
  130. package/dist/Meter.module.js +6 -2
  131. package/dist/Meter.module.js.map +1 -1
  132. package/dist/Modal.main.js +31 -6
  133. package/dist/Modal.main.js.map +1 -1
  134. package/dist/Modal.mjs +31 -6
  135. package/dist/Modal.module.js +31 -6
  136. package/dist/Modal.module.js.map +1 -1
  137. package/dist/NumberField.main.js +4 -1
  138. package/dist/NumberField.main.js.map +1 -1
  139. package/dist/NumberField.mjs +4 -1
  140. package/dist/NumberField.module.js +4 -1
  141. package/dist/NumberField.module.js.map +1 -1
  142. package/dist/Popover.main.js +3 -1
  143. package/dist/Popover.main.js.map +1 -1
  144. package/dist/Popover.mjs +3 -1
  145. package/dist/Popover.module.js +3 -1
  146. package/dist/Popover.module.js.map +1 -1
  147. package/dist/ProgressBar.main.js +6 -2
  148. package/dist/ProgressBar.main.js.map +1 -1
  149. package/dist/ProgressBar.mjs +6 -2
  150. package/dist/ProgressBar.module.js +6 -2
  151. package/dist/ProgressBar.module.js.map +1 -1
  152. package/dist/RadioGroup.main.js +8 -3
  153. package/dist/RadioGroup.main.js.map +1 -1
  154. package/dist/RadioGroup.mjs +9 -4
  155. package/dist/RadioGroup.module.js +9 -4
  156. package/dist/RadioGroup.module.js.map +1 -1
  157. package/dist/SearchField.main.js +3 -1
  158. package/dist/SearchField.main.js.map +1 -1
  159. package/dist/SearchField.mjs +3 -1
  160. package/dist/SearchField.module.js +3 -1
  161. package/dist/SearchField.module.js.map +1 -1
  162. package/dist/Select.main.js +12 -14
  163. package/dist/Select.main.js.map +1 -1
  164. package/dist/Select.mjs +13 -15
  165. package/dist/Select.module.js +13 -15
  166. package/dist/Select.module.js.map +1 -1
  167. package/dist/Separator.main.js +4 -2
  168. package/dist/Separator.main.js.map +1 -1
  169. package/dist/Separator.mjs +5 -3
  170. package/dist/Separator.module.js +5 -3
  171. package/dist/Separator.module.js.map +1 -1
  172. package/dist/Slider.main.js +7 -5
  173. package/dist/Slider.main.js.map +1 -1
  174. package/dist/Slider.mjs +8 -6
  175. package/dist/Slider.module.js +8 -6
  176. package/dist/Slider.module.js.map +1 -1
  177. package/dist/Switch.main.js +4 -1
  178. package/dist/Switch.main.js.map +1 -1
  179. package/dist/Switch.mjs +4 -1
  180. package/dist/Switch.module.js +4 -1
  181. package/dist/Switch.module.js.map +1 -1
  182. package/dist/Table.main.js +47 -26
  183. package/dist/Table.main.js.map +1 -1
  184. package/dist/Table.mjs +48 -27
  185. package/dist/Table.module.js +48 -27
  186. package/dist/Table.module.js.map +1 -1
  187. package/dist/Tabs.main.js +20 -10
  188. package/dist/Tabs.main.js.map +1 -1
  189. package/dist/Tabs.mjs +21 -11
  190. package/dist/Tabs.module.js +21 -11
  191. package/dist/Tabs.module.js.map +1 -1
  192. package/dist/TagGroup.main.js +14 -8
  193. package/dist/TagGroup.main.js.map +1 -1
  194. package/dist/TagGroup.mjs +14 -8
  195. package/dist/TagGroup.module.js +14 -8
  196. package/dist/TagGroup.module.js.map +1 -1
  197. package/dist/TextField.main.js +13 -1
  198. package/dist/TextField.main.js.map +1 -1
  199. package/dist/TextField.mjs +13 -1
  200. package/dist/TextField.module.js +13 -1
  201. package/dist/TextField.module.js.map +1 -1
  202. package/dist/Toast.main.js +9 -5
  203. package/dist/Toast.main.js.map +1 -1
  204. package/dist/Toast.mjs +9 -5
  205. package/dist/Toast.module.js +9 -5
  206. package/dist/Toast.module.js.map +1 -1
  207. package/dist/ToggleButton.main.js +8 -2
  208. package/dist/ToggleButton.main.js.map +1 -1
  209. package/dist/ToggleButton.mjs +8 -2
  210. package/dist/ToggleButton.module.js +8 -2
  211. package/dist/ToggleButton.module.js.map +1 -1
  212. package/dist/ToggleButtonGroup.main.js +6 -2
  213. package/dist/ToggleButtonGroup.main.js.map +1 -1
  214. package/dist/ToggleButtonGroup.mjs +6 -2
  215. package/dist/ToggleButtonGroup.module.js +6 -2
  216. package/dist/ToggleButtonGroup.module.js.map +1 -1
  217. package/dist/Toolbar.main.js +4 -3
  218. package/dist/Toolbar.main.js.map +1 -1
  219. package/dist/Toolbar.mjs +4 -3
  220. package/dist/Toolbar.module.js +4 -3
  221. package/dist/Toolbar.module.js.map +1 -1
  222. package/dist/Tooltip.main.js +5 -3
  223. package/dist/Tooltip.main.js.map +1 -1
  224. package/dist/Tooltip.mjs +5 -3
  225. package/dist/Tooltip.module.js +5 -3
  226. package/dist/Tooltip.module.js.map +1 -1
  227. package/dist/Tree.main.js +73 -26
  228. package/dist/Tree.main.js.map +1 -1
  229. package/dist/Tree.mjs +74 -27
  230. package/dist/Tree.module.js +74 -27
  231. package/dist/Tree.module.js.map +1 -1
  232. package/dist/TreeDropTargetDelegate.main.js +8 -5
  233. package/dist/TreeDropTargetDelegate.main.js.map +1 -1
  234. package/dist/TreeDropTargetDelegate.mjs +8 -5
  235. package/dist/TreeDropTargetDelegate.module.js +8 -5
  236. package/dist/TreeDropTargetDelegate.module.js.map +1 -1
  237. package/dist/import.mjs +5 -5
  238. package/dist/main.js +4 -4
  239. package/dist/main.js.map +1 -1
  240. package/dist/module.js +5 -5
  241. package/dist/module.js.map +1 -1
  242. package/dist/types.d.ts +212 -203
  243. package/dist/types.d.ts.map +1 -1
  244. package/dist/useDragAndDrop.main.js.map +1 -1
  245. package/dist/useDragAndDrop.module.js.map +1 -1
  246. package/dist/utils.main.js.map +1 -1
  247. package/dist/utils.module.js.map +1 -1
  248. package/i18n/de-DE.js +1 -1
  249. package/i18n/de-DE.mjs +1 -1
  250. package/package.json +25 -25
  251. package/src/Breadcrumbs.tsx +10 -6
  252. package/src/Button.tsx +8 -30
  253. package/src/Calendar.tsx +41 -24
  254. package/src/Checkbox.tsx +8 -6
  255. package/src/Collection.tsx +2 -2
  256. package/src/ColorArea.tsx +5 -6
  257. package/src/ColorField.tsx +6 -4
  258. package/src/ColorSlider.tsx +3 -2
  259. package/src/ColorSwatch.tsx +6 -3
  260. package/src/ColorSwatchPicker.tsx +3 -3
  261. package/src/ColorThumb.tsx +3 -3
  262. package/src/ColorWheel.tsx +6 -5
  263. package/src/ComboBox.tsx +4 -4
  264. package/src/DateField.tsx +15 -10
  265. package/src/DatePicker.tsx +14 -12
  266. package/src/Dialog.tsx +6 -6
  267. package/src/Disclosure.tsx +10 -14
  268. package/src/DragAndDrop.tsx +31 -1
  269. package/src/DropZone.tsx +4 -5
  270. package/src/FieldError.tsx +3 -3
  271. package/src/FileTrigger.tsx +4 -3
  272. package/src/Form.tsx +2 -1
  273. package/src/GridList.tsx +25 -18
  274. package/src/HiddenDateInput.tsx +142 -0
  275. package/src/Link.tsx +7 -3
  276. package/src/ListBox.tsx +30 -26
  277. package/src/Menu.tsx +15 -12
  278. package/src/Meter.tsx +6 -3
  279. package/src/Modal.tsx +16 -5
  280. package/src/NumberField.tsx +4 -4
  281. package/src/Popover.tsx +3 -3
  282. package/src/ProgressBar.tsx +6 -2
  283. package/src/RadioGroup.tsx +8 -6
  284. package/src/SearchField.tsx +3 -2
  285. package/src/Select.tsx +13 -16
  286. package/src/Separator.tsx +6 -4
  287. package/src/Slider.tsx +9 -11
  288. package/src/Switch.tsx +4 -3
  289. package/src/Table.tsx +58 -56
  290. package/src/Tabs.tsx +18 -15
  291. package/src/TagGroup.tsx +13 -12
  292. package/src/TextField.tsx +5 -2
  293. package/src/Toast.tsx +10 -8
  294. package/src/ToggleButton.tsx +8 -4
  295. package/src/ToggleButtonGroup.tsx +6 -4
  296. package/src/Toolbar.tsx +4 -5
  297. package/src/Tooltip.tsx +6 -5
  298. package/src/Tree.tsx +90 -42
  299. package/src/TreeDropTargetDelegate.ts +5 -1
  300. package/src/index.ts +8 -8
  301. package/src/useDragAndDrop.tsx +2 -2
  302. package/src/utils.tsx +9 -9
package/src/GridList.tsx CHANGED
@@ -14,12 +14,12 @@ import {ButtonContext} from './Button';
14
14
  import {CheckboxContext} from './RSPContexts';
15
15
  import {Collection, CollectionBuilder, createLeafComponent} from '@react-aria/collections';
16
16
  import {CollectionProps, CollectionRendererContext, DefaultCollectionRenderer, ItemRenderProps} from './Collection';
17
- import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, ScrollableProps, SlotProps, StyleProps, StyleRenderProps, useContextProps, useRenderProps} from './utils';
17
+ import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, SlotProps, StyleProps, StyleRenderProps, useContextProps, useRenderProps} from './utils';
18
18
  import {DragAndDropContext, DropIndicatorContext, DropIndicatorProps, useDndPersistedKeys, useRenderDropIndicator} from './DragAndDrop';
19
19
  import {DragAndDropHooks} from './useDragAndDrop';
20
20
  import {DraggableCollectionState, DroppableCollectionState, Collection as ICollection, ListState, Node, SelectionBehavior, useListState} from 'react-stately';
21
- import {filterDOMProps, inertValue, LoadMoreSentinelProps, UNSTABLE_useLoadMoreSentinel, useObjectRef} from '@react-aria/utils';
22
- import {forwardRefType, HoverEvents, Key, LinkDOMProps, RefObject} from '@react-types/shared';
21
+ import {filterDOMProps, inertValue, LoadMoreSentinelProps, useLoadMoreSentinel, useObjectRef} from '@react-aria/utils';
22
+ import {forwardRefType, GlobalDOMAttributes, HoverEvents, Key, LinkDOMProps, PressEvents, RefObject} from '@react-types/shared';
23
23
  import {ListStateContext} from './ListBox';
24
24
  import React, {createContext, ForwardedRef, forwardRef, HTMLAttributes, JSX, ReactNode, useContext, useEffect, useMemo, useRef} from 'react';
25
25
  import {TextContext} from './Text';
@@ -56,13 +56,16 @@ export interface GridListRenderProps {
56
56
  state: ListState<unknown>
57
57
  }
58
58
 
59
- export interface GridListProps<T> extends Omit<AriaGridListProps<T>, 'children'>, CollectionProps<T>, StyleRenderProps<GridListRenderProps>, SlotProps, ScrollableProps<HTMLDivElement> {
59
+ export interface GridListProps<T> extends Omit<AriaGridListProps<T>, 'children'>, CollectionProps<T>, StyleRenderProps<GridListRenderProps>, SlotProps, GlobalDOMAttributes<HTMLDivElement> {
60
60
  /**
61
61
  * Whether typeahead navigation is disabled.
62
62
  * @default false
63
63
  */
64
64
  disallowTypeAhead?: boolean,
65
- /** How multiple selection should behave in the collection. */
65
+ /**
66
+ * How multiple selection should behave in the collection.
67
+ * @default "toggle"
68
+ */
66
69
  selectionBehavior?: SelectionBehavior,
67
70
  /** The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the GridList. */
68
71
  dragAndDropHooks?: DragAndDropHooks,
@@ -194,8 +197,7 @@ function GridListInner<T extends object>({props, collection, gridListRef: ref}:
194
197
  }
195
198
 
196
199
  let {focusProps, isFocused, isFocusVisible} = useFocusRing();
197
- // TODO: What do we think about this check? Ideally we could just query the collection and see if ALL node are loaders and thus have it return that it is empty
198
- let isEmpty = state.collection.size === 0 || (state.collection.size === 1 && state.collection.getItem(state.collection.getFirstKey()!)?.type === 'loader');
200
+ let isEmpty = state.collection.size === 0;
199
201
  let renderValues = {
200
202
  isDropTarget: isRootDropTarget,
201
203
  isEmpty,
@@ -225,12 +227,12 @@ function GridListInner<T extends object>({props, collection, gridListRef: ref}:
225
227
  );
226
228
  }
227
229
 
230
+ let DOMProps = filterDOMProps(props, {global: true});
231
+
228
232
  return (
229
233
  <FocusScope>
230
234
  <div
231
- {...filterDOMProps(props)}
232
- {...renderProps}
233
- {...mergeProps(gridProps, focusProps, droppableCollection?.collectionProps, emptyStatePropOverrides)}
235
+ {...mergeProps(DOMProps, renderProps, gridProps, focusProps, droppableCollection?.collectionProps, emptyStatePropOverrides)}
234
236
  ref={ref}
235
237
  slot={props.slot || undefined}
236
238
  onScroll={props.onScroll}
@@ -261,7 +263,7 @@ function GridListInner<T extends object>({props, collection, gridListRef: ref}:
261
263
 
262
264
  export interface GridListItemRenderProps extends ItemRenderProps {}
263
265
 
264
- export interface GridListItemProps<T = object> extends RenderProps<GridListItemRenderProps>, LinkDOMProps, HoverEvents {
266
+ export interface GridListItemProps<T = object> extends RenderProps<GridListItemRenderProps>, LinkDOMProps, HoverEvents, PressEvents, Omit<GlobalDOMAttributes<HTMLDivElement>, 'onClick'> {
265
267
  /** The unique id of the item. */
266
268
  id?: Key,
267
269
  /** The object value that this item represents. When using dynamic collections, this is set automatically. */
@@ -356,6 +358,10 @@ export const GridListItem = /*#__PURE__*/ createLeafComponent('item', function G
356
358
  }
357
359
  }, [item.textValue]);
358
360
 
361
+ let DOMProps = filterDOMProps(props as any, {global: true});
362
+ delete DOMProps.id;
363
+ delete DOMProps.onClick;
364
+
359
365
  return (
360
366
  <>
361
367
  {dropIndicator && !dropIndicator.isHidden &&
@@ -366,8 +372,7 @@ export const GridListItem = /*#__PURE__*/ createLeafComponent('item', function G
366
372
  </div>
367
373
  }
368
374
  <div
369
- {...mergeProps(filterDOMProps(props as any), rowProps, focusProps, hoverProps, draggableItem?.dragProps)}
370
- {...renderProps}
375
+ {...mergeProps(DOMProps, renderProps, rowProps, focusProps, hoverProps, draggableItem?.dragProps)}
371
376
  ref={ref}
372
377
  data-selected={states.isSelected || undefined}
373
378
  data-disabled={states.isDisabled || undefined}
@@ -497,7 +502,7 @@ function RootDropIndicator() {
497
502
  );
498
503
  }
499
504
 
500
- export interface GridListLoadingSentinelProps extends Omit<LoadMoreSentinelProps, 'collection'>, StyleProps {
505
+ export interface GridListLoadMoreItemProps extends Omit<LoadMoreSentinelProps, 'collection'>, StyleProps, GlobalDOMAttributes<HTMLDivElement> {
501
506
  /**
502
507
  * The load more spinner to render when loading additional items.
503
508
  */
@@ -508,7 +513,7 @@ export interface GridListLoadingSentinelProps extends Omit<LoadMoreSentinelProps
508
513
  isLoading?: boolean
509
514
  }
510
515
 
511
- export const UNSTABLE_GridListLoadingSentinel = createLeafComponent('loader', function GridListLoadingIndicator<T extends object>(props: GridListLoadingSentinelProps, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) {
516
+ export const GridListLoadMoreItem = createLeafComponent('loader', function GridListLoadingIndicator(props: GridListLoadMoreItemProps, ref: ForwardedRef<HTMLDivElement>, item: Node<object>) {
512
517
  let state = useContext(ListStateContext)!;
513
518
  let {isVirtualized} = useContext(CollectionRendererContext);
514
519
  let {isLoading, onLoadMore, scrollOffset, ...otherProps} = props;
@@ -520,7 +525,7 @@ export const UNSTABLE_GridListLoadingSentinel = createLeafComponent('loader', fu
520
525
  sentinelRef,
521
526
  scrollOffset
522
527
  }), [onLoadMore, scrollOffset, state?.collection]);
523
- UNSTABLE_useLoadMoreSentinel(memoedLoadMoreProps, sentinelRef);
528
+ useLoadMoreSentinel(memoedLoadMoreProps, sentinelRef);
524
529
 
525
530
  let renderProps = useRenderProps({
526
531
  ...otherProps,
@@ -529,6 +534,9 @@ export const UNSTABLE_GridListLoadingSentinel = createLeafComponent('loader', fu
529
534
  defaultClassName: 'react-aria-GridListLoadingIndicator',
530
535
  values: null
531
536
  });
537
+ // For now don't include aria-posinset and aria-setsize on loader since they aren't keyboard focusable
538
+ // Arguably shouldn't include them ever since it might be confusing to the user to include the loaders as part of the
539
+ // item count
532
540
 
533
541
  return (
534
542
  <>
@@ -540,9 +548,8 @@ export const UNSTABLE_GridListLoadingSentinel = createLeafComponent('loader', fu
540
548
  {isLoading && renderProps.children && (
541
549
  <div
542
550
  {...renderProps}
543
- {...mergeProps(filterDOMProps(props as any))}
551
+ {...filterDOMProps(props, {global: true})}
544
552
  role="row"
545
- aria-rowindex={isVirtualized ? item.index + 1 : undefined}
546
553
  ref={ref}>
547
554
  <div
548
555
  aria-colindex={isVirtualized ? 1 : undefined}
@@ -0,0 +1,142 @@
1
+ /*
2
+ * Copyright 2025 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+
14
+ import {CalendarDate, CalendarDateTime, parseDate, parseDateTime} from '@internationalized/date';
15
+ import {DateFieldState, DatePickerState, DateSegmentType} from 'react-stately';
16
+ import React, {ReactNode} from 'react';
17
+ import {useVisuallyHidden} from 'react-aria';
18
+
19
+ interface AriaHiddenDateInputProps {
20
+ /**
21
+ * Describes the type of autocomplete functionality the input should provide if any. See [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#htmlattrdefautocomplete).
22
+ */
23
+ autoComplete?: string,
24
+ /** HTML form input name. */
25
+ name?: string,
26
+ /** Sets the disabled state of the input. */
27
+ isDisabled?: boolean
28
+ }
29
+
30
+ interface HiddenDateInputProps extends AriaHiddenDateInputProps {
31
+ /**
32
+ * State for the input.
33
+ */
34
+ state: DateFieldState | DatePickerState
35
+ }
36
+
37
+ export interface HiddenDateAria {
38
+ /** Props for the container element. */
39
+ containerProps: React.HTMLAttributes<HTMLDivElement>,
40
+ /** Props for the hidden input element. */
41
+ inputProps: React.InputHTMLAttributes<HTMLInputElement>
42
+ }
43
+
44
+ const dateSegments = ['day', 'month', 'year'];
45
+ const granularityMap = {'hour': 1, 'minute': 2, 'second': 3};
46
+
47
+ export function useHiddenDateInput(props: HiddenDateInputProps, state: DateFieldState | DatePickerState) : HiddenDateAria {
48
+ let {
49
+ autoComplete,
50
+ isDisabled,
51
+ name
52
+ } = props;
53
+ let {visuallyHiddenProps} = useVisuallyHidden({
54
+ style: {
55
+ // Prevent page scrolling.
56
+ position: 'fixed',
57
+ top: 0,
58
+ left: 0
59
+ }
60
+ });
61
+
62
+ let inputStep = 60;
63
+ if (state.granularity === 'second') {
64
+ inputStep = 1;
65
+ } else if (state.granularity === 'hour') {
66
+ inputStep = 3600;
67
+ }
68
+
69
+ let dateValue = state.value == null ? '' : state.value.toString();
70
+
71
+ let inputType = state.granularity === 'day' ? 'date' : 'datetime-local';
72
+
73
+ let timeSegments = ['hour', 'minute', 'second'];
74
+ // Depending on the granularity, we only want to validate certain time segments
75
+ let end = 0;
76
+ if (timeSegments.includes(state.granularity)) {
77
+ end = granularityMap[state.granularity];
78
+ timeSegments = timeSegments.slice(0, end);
79
+ }
80
+
81
+ return {
82
+ containerProps: {
83
+ ...visuallyHiddenProps,
84
+ 'aria-hidden': true,
85
+ // @ts-ignore
86
+ ['data-react-aria-prevent-focus']: true,
87
+ // @ts-ignore
88
+ ['data-a11y-ignore']: 'aria-hidden-focus'
89
+ },
90
+ inputProps: {
91
+ tabIndex: -1,
92
+ autoComplete,
93
+ disabled: isDisabled,
94
+ type: inputType,
95
+ // We set the form prop to an empty string to prevent the hidden date input's value from being submitted
96
+ form: '',
97
+ name,
98
+ step: inputStep,
99
+ value: dateValue,
100
+ onChange: (e) => {
101
+ let targetString = e.target.value.toString();
102
+ if (targetString) {
103
+ try {
104
+ let targetValue: CalendarDateTime | CalendarDate = parseDateTime(targetString);
105
+ if (state.granularity === 'day') {
106
+ targetValue = parseDate(targetString);
107
+ }
108
+ // We check to to see if setSegment exists in the state since it only exists in DateFieldState and not DatePickerState.
109
+ // The setValue method has different behavior depending on if it's coming from DateFieldState or DatePickerState.
110
+ // In DateFieldState, setValue firsts checks to make sure that each segment is filled before committing the newValue
111
+ // which is why in the code below we first set each segment to validate it before committing the new value.
112
+ // However, in DatePickerState, since we have to be able to commit values from the Calendar popover, we are also able to
113
+ // set a new value when the field itself is empty.
114
+ if ('setSegment' in state) {
115
+ for (let type in targetValue) {
116
+ if (dateSegments.includes(type)) {
117
+ state.setSegment(type as DateSegmentType, targetValue[type]);
118
+ }
119
+ if (timeSegments.includes(type)) {
120
+ state.setSegment(type as DateSegmentType, targetValue[type]);
121
+ }
122
+ }
123
+ }
124
+ state.setValue(targetValue);
125
+ } catch {
126
+ // ignore
127
+ }
128
+ }
129
+ }
130
+ }
131
+ };
132
+ }
133
+
134
+ export function HiddenDateInput(props: HiddenDateInputProps): ReactNode | null {
135
+ let {state} = props;
136
+ let {containerProps, inputProps} = useHiddenDateInput({...props}, state);
137
+ return (
138
+ <div {...containerProps} data-testid="hidden-dateinput-container">
139
+ <input {...inputProps} />
140
+ </div>
141
+ );
142
+ }
package/src/Link.tsx CHANGED
@@ -12,10 +12,11 @@
12
12
 
13
13
  import {AriaLinkOptions, HoverEvents, mergeProps, useFocusRing, useHover, useLink} from 'react-aria';
14
14
  import {ContextValue, RenderProps, SlotProps, useContextProps, useRenderProps} from './utils';
15
- import {forwardRefType} from '@react-types/shared';
15
+ import {filterDOMProps} from '@react-aria/utils';
16
+ import {forwardRefType, GlobalDOMAttributes} from '@react-types/shared';
16
17
  import React, {createContext, ElementType, ForwardedRef, forwardRef} from 'react';
17
18
 
18
- export interface LinkProps extends Omit<AriaLinkOptions, 'elementType'>, HoverEvents, RenderProps<LinkRenderProps>, SlotProps {}
19
+ export interface LinkProps extends Omit<AriaLinkOptions, 'elementType'>, HoverEvents, RenderProps<LinkRenderProps>, SlotProps, Omit<GlobalDOMAttributes<HTMLDivElement>, 'onClick'> {}
19
20
 
20
21
  export interface LinkRenderProps {
21
22
  /**
@@ -78,11 +79,14 @@ export const Link = /*#__PURE__*/ (forwardRef as forwardRefType)(function Link(p
78
79
  }
79
80
  });
80
81
 
82
+ let DOMProps = filterDOMProps(props, {global: true});
83
+ delete DOMProps.onClick;
84
+
81
85
  return (
82
86
  <ElementType
83
87
  ref={ref}
84
88
  slot={props.slot || undefined}
85
- {...mergeProps(renderProps, linkProps, hoverProps, focusProps)}
89
+ {...mergeProps(DOMProps, renderProps, linkProps, hoverProps, focusProps)}
86
90
  data-focused={isFocused || undefined}
87
91
  data-hovered={isHovered || undefined}
88
92
  data-pressed={isPressed || undefined}
package/src/ListBox.tsx CHANGED
@@ -13,12 +13,12 @@
13
13
  import {AriaListBoxOptions, AriaListBoxProps, DraggableItemResult, DragPreviewRenderer, DroppableCollectionResult, DroppableItemResult, FocusScope, ListKeyboardDelegate, mergeProps, useCollator, useFocusRing, useHover, useListBox, useListBoxSection, useLocale, useOption} from 'react-aria';
14
14
  import {Collection, CollectionBuilder, createBranchComponent, createLeafComponent} from '@react-aria/collections';
15
15
  import {CollectionProps, CollectionRendererContext, ItemRenderProps, SectionContext, SectionProps} from './Collection';
16
- import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, ScrollableProps, SlotProps, StyleProps, StyleRenderProps, useContextProps, useRenderProps, useSlot} from './utils';
16
+ import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, SlotProps, StyleProps, StyleRenderProps, useContextProps, useRenderProps, useSlot} from './utils';
17
17
  import {DragAndDropContext, DropIndicatorContext, DropIndicatorProps, useDndPersistedKeys, useRenderDropIndicator} from './DragAndDrop';
18
18
  import {DragAndDropHooks} from './useDragAndDrop';
19
19
  import {DraggableCollectionState, DroppableCollectionState, ListState, Node, Orientation, SelectionBehavior, UNSTABLE_useFilteredListState, useListState} from 'react-stately';
20
- import {filterDOMProps, inertValue, LoadMoreSentinelProps, mergeRefs, UNSTABLE_useLoadMoreSentinel, useObjectRef} from '@react-aria/utils';
21
- import {forwardRefType, HoverEvents, Key, LinkDOMProps, RefObject} from '@react-types/shared';
20
+ import {filterDOMProps, inertValue, LoadMoreSentinelProps, mergeRefs, useLoadMoreSentinel, useObjectRef} from '@react-aria/utils';
21
+ import {forwardRefType, GlobalDOMAttributes, HoverEvents, Key, LinkDOMProps, PressEvents, RefObject} from '@react-types/shared';
22
22
  import {HeaderContext} from './Header';
23
23
  import React, {createContext, ForwardedRef, forwardRef, JSX, ReactNode, useContext, useEffect, useMemo, useRef} from 'react';
24
24
  import {SeparatorContext} from './Separator';
@@ -57,8 +57,11 @@ export interface ListBoxRenderProps {
57
57
  state: ListState<unknown>
58
58
  }
59
59
 
60
- export interface ListBoxProps<T> extends Omit<AriaListBoxProps<T>, 'children' | 'label'>, CollectionProps<T>, StyleRenderProps<ListBoxRenderProps>, SlotProps, ScrollableProps<HTMLDivElement> {
61
- /** How multiple selection should behave in the collection. */
60
+ export interface ListBoxProps<T> extends Omit<AriaListBoxProps<T>, 'children' | 'label'>, CollectionProps<T>, StyleRenderProps<ListBoxRenderProps>, SlotProps, GlobalDOMAttributes<HTMLDivElement> {
61
+ /**
62
+ * How multiple selection should behave in the collection.
63
+ * @default "toggle"
64
+ */
62
65
  selectionBehavior?: SelectionBehavior,
63
66
  /** The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the ListBox. */
64
67
  dragAndDropHooks?: DragAndDropHooks,
@@ -202,7 +205,7 @@ function ListBoxInner<T extends object>({state: inputState, props, listBoxRef}:
202
205
  }
203
206
 
204
207
  let {focusProps, isFocused, isFocusVisible} = useFocusRing();
205
- let isEmpty = state.collection.size === 0 || (state.collection.size === 1 && state.collection.getItem(state.collection.getFirstKey()!)?.type === 'loader');
208
+ let isEmpty = state.collection.size === 0;
206
209
  let renderValues = {
207
210
  isDropTarget: isRootDropTarget,
208
211
  isEmpty,
@@ -230,12 +233,12 @@ function ListBoxInner<T extends object>({state: inputState, props, listBoxRef}:
230
233
  );
231
234
  }
232
235
 
236
+ let DOMProps = filterDOMProps(props, {global: true});
237
+
233
238
  return (
234
239
  <FocusScope>
235
240
  <div
236
- {...filterDOMProps(props)}
237
- {...mergeProps(listBoxProps, focusProps, droppableCollection?.collectionProps)}
238
- {...renderProps}
241
+ {...mergeProps(DOMProps, renderProps, listBoxProps, focusProps, droppableCollection?.collectionProps)}
239
242
  ref={listBoxRef}
240
243
  slot={props.slot || undefined}
241
244
  onScroll={props.onScroll}
@@ -285,11 +288,12 @@ function ListBoxSectionInner<T extends object>(props: ListBoxSectionProps<T>, re
285
288
  values: {}
286
289
  });
287
290
 
291
+ let DOMProps = filterDOMProps(props as any, {global: true});
292
+ delete DOMProps.id;
293
+
288
294
  return (
289
295
  <section
290
- {...filterDOMProps(props as any)}
291
- {...groupProps}
292
- {...renderProps}
296
+ {...mergeProps(DOMProps, renderProps, groupProps)}
293
297
  ref={ref}>
294
298
  <HeaderContext.Provider value={{...headingProps, ref: headingRef}}>
295
299
  <CollectionBranch
@@ -308,7 +312,7 @@ export const ListBoxSection = /*#__PURE__*/ createBranchComponent('section', Lis
308
312
 
309
313
  export interface ListBoxItemRenderProps extends ItemRenderProps {}
310
314
 
311
- export interface ListBoxItemProps<T = object> extends RenderProps<ListBoxItemRenderProps>, LinkDOMProps, HoverEvents {
315
+ export interface ListBoxItemProps<T = object> extends RenderProps<ListBoxItemRenderProps>, LinkDOMProps, HoverEvents, PressEvents, Omit<GlobalDOMAttributes<HTMLDivElement>, 'onClick'> {
312
316
  /** The unique id of the item. */
313
317
  id?: Key,
314
318
  /** The object value that this item represents. When using dynamic collections, this is set automatically. */
@@ -383,10 +387,13 @@ export const ListBoxItem = /*#__PURE__*/ createLeafComponent('item', function Li
383
387
 
384
388
  let ElementType: React.ElementType = props.href ? 'a' : 'div';
385
389
 
390
+ let DOMProps = filterDOMProps(props as any, {global: true});
391
+ delete DOMProps.id;
392
+ delete DOMProps.onClick;
393
+
386
394
  return (
387
395
  <ElementType
388
- {...mergeProps(optionProps, hoverProps, draggableItem?.dragProps, droppableItem?.dropProps)}
389
- {...renderProps}
396
+ {...mergeProps(DOMProps, renderProps, optionProps, hoverProps, draggableItem?.dragProps, droppableItem?.dropProps)}
390
397
  ref={ref}
391
398
  data-allows-dragging={!!dragState || undefined}
392
399
  data-selected={states.isSelected || undefined}
@@ -465,7 +472,7 @@ function ListBoxDropIndicator(props: ListBoxDropIndicatorProps, ref: ForwardedRe
465
472
 
466
473
  const ListBoxDropIndicatorForwardRef = forwardRef(ListBoxDropIndicator);
467
474
 
468
- export interface ListBoxLoadingSentinelProps extends Omit<LoadMoreSentinelProps, 'collection'>, StyleProps {
475
+ export interface ListBoxLoadMoreItemProps extends Omit<LoadMoreSentinelProps, 'collection'>, StyleProps, GlobalDOMAttributes<HTMLDivElement> {
469
476
  /**
470
477
  * The load more spinner to render when loading additional items.
471
478
  */
@@ -476,9 +483,8 @@ export interface ListBoxLoadingSentinelProps extends Omit<LoadMoreSentinelProps,
476
483
  isLoading?: boolean
477
484
  }
478
485
 
479
- export const UNSTABLE_ListBoxLoadingSentinel = createLeafComponent('loader', function ListBoxLoadingIndicator<T extends object>(props: ListBoxLoadingSentinelProps, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) {
486
+ export const ListBoxLoadMoreItem = createLeafComponent('loader', function ListBoxLoadingIndicator(props: ListBoxLoadMoreItemProps, ref: ForwardedRef<HTMLDivElement>, item: Node<object>) {
480
487
  let state = useContext(ListStateContext)!;
481
- let {isVirtualized} = useContext(CollectionRendererContext);
482
488
  let {isLoading, onLoadMore, scrollOffset, ...otherProps} = props;
483
489
 
484
490
  let sentinelRef = useRef<HTMLDivElement>(null);
@@ -488,7 +494,7 @@ export const UNSTABLE_ListBoxLoadingSentinel = createLeafComponent('loader', fun
488
494
  sentinelRef,
489
495
  scrollOffset
490
496
  }), [onLoadMore, scrollOffset, state?.collection]);
491
- UNSTABLE_useLoadMoreSentinel(memoedLoadMoreProps, sentinelRef);
497
+ useLoadMoreSentinel(memoedLoadMoreProps, sentinelRef);
492
498
  let renderProps = useRenderProps({
493
499
  ...otherProps,
494
500
  id: undefined,
@@ -500,13 +506,11 @@ export const UNSTABLE_ListBoxLoadingSentinel = createLeafComponent('loader', fun
500
506
  let optionProps = {
501
507
  // For Android talkback
502
508
  tabIndex: -1
509
+ // For now don't include aria-posinset and aria-setsize on loader since they aren't keyboard focusable
510
+ // Arguably shouldn't include them ever since it might be confusing to the user to include the loaders as part of the
511
+ // item count
503
512
  };
504
513
 
505
- if (isVirtualized) {
506
- optionProps['aria-posinset'] = item.index + 1;
507
- optionProps['aria-setsize'] = state.collection.size;
508
- }
509
-
510
514
  return (
511
515
  <>
512
516
  {/* Alway render the sentinel. For now onus is on the user for styling when using flex + gap (this would introduce a gap even though it doesn't take room) */}
@@ -516,12 +520,12 @@ export const UNSTABLE_ListBoxLoadingSentinel = createLeafComponent('loader', fun
516
520
  </div>
517
521
  {isLoading && renderProps.children && (
518
522
  <div
519
- {...mergeProps(filterDOMProps(props as any), optionProps)}
523
+ {...mergeProps(filterDOMProps(props, {global: true}), optionProps)}
520
524
  {...renderProps}
521
525
  // aria-selected isn't needed here since this option is not selectable.
522
526
  // eslint-disable-next-line jsx-a11y/role-has-required-aria-props
523
527
  role="option"
524
- ref={ref}>
528
+ ref={ref as ForwardedRef<HTMLDivElement>}>
525
529
  {renderProps.children}
526
530
  </div>
527
531
  )}
package/src/Menu.tsx CHANGED
@@ -14,9 +14,9 @@ import {AriaMenuProps, FocusScope, mergeProps, useHover, useMenu, useMenuItem, u
14
14
  import {BaseCollection, Collection, CollectionBuilder, createBranchComponent, createLeafComponent} from '@react-aria/collections';
15
15
  import {MenuTriggerProps as BaseMenuTriggerProps, Collection as ICollection, Node, RootMenuTriggerState, TreeState, useMenuTriggerState, useSubmenuTriggerState, useTreeState} from 'react-stately';
16
16
  import {CollectionProps, CollectionRendererContext, ItemRenderProps, SectionContext, SectionProps, usePersistedKeys} from './Collection';
17
- import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, ScrollableProps, SlotProps, StyleRenderProps, useContextProps, useRenderProps, useSlot, useSlottedContext} from './utils';
17
+ import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, SlotProps, StyleRenderProps, useContextProps, useRenderProps, useSlot, useSlottedContext} from './utils';
18
18
  import {filterDOMProps, mergeRefs, useObjectRef, useResizeObserver} from '@react-aria/utils';
19
- import {FocusStrategy, forwardRefType, HoverEvents, Key, LinkDOMProps, MultipleSelection} from '@react-types/shared';
19
+ import {FocusStrategy, forwardRefType, GlobalDOMAttributes, HoverEvents, Key, LinkDOMProps, MultipleSelection, PressEvents} from '@react-types/shared';
20
20
  import {HeaderContext} from './Header';
21
21
  import {KeyboardContext} from './Keyboard';
22
22
  import {MultipleSelectionState, SelectionManager, useMultipleSelectionState} from '@react-stately/selection';
@@ -156,7 +156,7 @@ export interface MenuRenderProps {
156
156
  isEmpty: boolean
157
157
  }
158
158
 
159
- export interface MenuProps<T> extends Omit<AriaMenuProps<T>, 'children'>, CollectionProps<T>, StyleRenderProps<MenuRenderProps>, SlotProps, ScrollableProps<HTMLDivElement> {
159
+ export interface MenuProps<T> extends Omit<AriaMenuProps<T>, 'children'>, CollectionProps<T>, StyleRenderProps<MenuRenderProps>, SlotProps, GlobalDOMAttributes<HTMLDivElement> {
160
160
  /** Provides content to display when there are no items in the list. */
161
161
  renderEmptyState?: () => ReactNode
162
162
  }
@@ -214,12 +214,12 @@ function MenuInner<T extends object>({props, collection, menuRef: ref}: MenuInne
214
214
  );
215
215
  }
216
216
 
217
+ let DOMProps = filterDOMProps(props, {global: true});
218
+
217
219
  return (
218
220
  <FocusScope>
219
221
  <div
220
- {...filterDOMProps(props)}
221
- {...menuProps}
222
- {...renderProps}
222
+ {...mergeProps(DOMProps, renderProps, menuProps)}
223
223
  ref={ref}
224
224
  slot={props.slot || undefined}
225
225
  data-empty={state.collection.size === 0 || undefined}
@@ -301,11 +301,12 @@ function MenuSectionInner<T extends object>(props: MenuSectionProps<T>, ref: For
301
301
  let selectionState = useMultipleSelectionState(props);
302
302
  let manager = props.selectionMode != null ? new GroupSelectionManager(parent, selectionState) : parent;
303
303
 
304
+ let DOMProps = filterDOMProps(props as any, {global: true});
305
+ delete DOMProps.id;
306
+
304
307
  return (
305
308
  <section
306
- {...filterDOMProps(props as any)}
307
- {...groupProps}
308
- {...renderProps}
309
+ {...mergeProps(DOMProps, renderProps, groupProps)}
309
310
  ref={ref}>
310
311
  <Provider
311
312
  values={[
@@ -338,7 +339,7 @@ export interface MenuItemRenderProps extends ItemRenderProps {
338
339
  isOpen: boolean
339
340
  }
340
341
 
341
- export interface MenuItemProps<T = object> extends RenderProps<MenuItemRenderProps>, LinkDOMProps, HoverEvents {
342
+ export interface MenuItemProps<T = object> extends RenderProps<MenuItemRenderProps>, LinkDOMProps, HoverEvents, PressEvents, Omit<GlobalDOMAttributes<HTMLDivElement>, 'onClick'> {
342
343
  /** The unique id of the item. */
343
344
  id?: Key,
344
345
  /** The object value that this item represents. When using dynamic collections, this is set automatically. */
@@ -392,11 +393,13 @@ export const MenuItem = /*#__PURE__*/ createLeafComponent('item', function MenuI
392
393
  });
393
394
 
394
395
  let ElementType: React.ElementType = props.href ? 'a' : 'div';
396
+ let DOMProps = filterDOMProps(props as any, {global: true});
397
+ delete DOMProps.id;
398
+ delete DOMProps.onClick;
395
399
 
396
400
  return (
397
401
  <ElementType
398
- {...mergeProps(menuItemProps, hoverProps)}
399
- {...renderProps}
402
+ {...mergeProps(DOMProps, renderProps, menuItemProps, hoverProps)}
400
403
  ref={ref}
401
404
  data-disabled={states.isDisabled || undefined}
402
405
  data-hovered={isHovered || undefined}
package/src/Meter.tsx CHANGED
@@ -13,11 +13,12 @@
13
13
  import {AriaMeterProps, useMeter} from 'react-aria';
14
14
  import {clamp} from '@react-stately/utils';
15
15
  import {ContextValue, RenderProps, SlotProps, useContextProps, useRenderProps, useSlot} from './utils';
16
- import {forwardRefType} from '@react-types/shared';
16
+ import {filterDOMProps, mergeProps} from '@react-aria/utils';
17
+ import {forwardRefType, GlobalDOMAttributes} from '@react-types/shared';
17
18
  import {LabelContext} from './Label';
18
19
  import React, {createContext, ForwardedRef, forwardRef} from 'react';
19
20
 
20
- export interface MeterProps extends Omit<AriaMeterProps, 'label'>, RenderProps<MeterRenderProps>, SlotProps {}
21
+ export interface MeterProps extends Omit<AriaMeterProps, 'label'>, RenderProps<MeterRenderProps>, SlotProps, GlobalDOMAttributes<HTMLDivElement> {}
21
22
 
22
23
  export interface MeterRenderProps {
23
24
  /**
@@ -65,8 +66,10 @@ export const Meter = /*#__PURE__*/ (forwardRef as forwardRefType)(function Meter
65
66
  }
66
67
  });
67
68
 
69
+ let DOMProps = filterDOMProps(props, {global: true});
70
+
68
71
  return (
69
- <div {...meterProps} {...renderProps} ref={ref} slot={props.slot || undefined}>
72
+ <div {...mergeProps(DOMProps, renderProps, meterProps)} ref={ref} slot={props.slot || undefined}>
70
73
  <LabelContext.Provider value={{...labelProps, ref: labelRef, elementType: 'span'}}>
71
74
  {renderProps.children}
72
75
  </LabelContext.Provider>
package/src/Modal.tsx CHANGED
@@ -12,13 +12,13 @@
12
12
 
13
13
  import {AriaModalOverlayProps, DismissButton, Overlay, useIsSSR, useModalOverlay} from 'react-aria';
14
14
  import {ContextValue, Provider, RenderProps, SlotProps, useContextProps, useRenderProps} from './utils';
15
- import {DOMAttributes, forwardRefType, RefObject} from '@react-types/shared';
15
+ import {DOMAttributes, forwardRefType, GlobalDOMAttributes, RefObject} from '@react-types/shared';
16
16
  import {filterDOMProps, mergeProps, mergeRefs, useEnterAnimation, useExitAnimation, useObjectRef, useViewportSize} from '@react-aria/utils';
17
17
  import {OverlayTriggerProps, OverlayTriggerState, useOverlayTriggerState} from 'react-stately';
18
18
  import {OverlayTriggerStateContext} from './Dialog';
19
19
  import React, {createContext, ForwardedRef, forwardRef, useContext, useMemo, useRef} from 'react';
20
20
 
21
- export interface ModalOverlayProps extends AriaModalOverlayProps, OverlayTriggerProps, RenderProps<ModalRenderProps>, SlotProps {
21
+ export interface ModalOverlayProps extends AriaModalOverlayProps, OverlayTriggerProps, RenderProps<ModalRenderProps>, SlotProps, GlobalDOMAttributes<HTMLDivElement> {
22
22
  /**
23
23
  * Whether the modal is currently performing an entry animation.
24
24
  */
@@ -69,6 +69,12 @@ export const Modal = /*#__PURE__*/ (forwardRef as forwardRefType)(function Modal
69
69
  let ctx = useContext(InternalModalContext);
70
70
 
71
71
  if (ctx) {
72
+ if (process.env.NODE_ENV !== 'production' && (props.onOpenChange || props.defaultOpen !== undefined || props.isOpen !== undefined)) {
73
+ // create a list of props that are passed in but not allowed when using an external ModalOverlay
74
+ const invalidSet = new Set(['isDismissable', 'isKeyboardDismissDisabled', 'isOpen', 'defaultOpen', 'onOpenChange', 'isEntering', 'isExiting', 'UNSTABLE_portalContainer', 'shouldCloseOnInteractOutside']);
75
+ const invalidProps = Object.keys(props).filter(key => invalidSet.has(key));
76
+ console.warn(`This modal is already wrapped in a ModalOverlay, props [${invalidProps.join(', ')}] should be placed on the ModalOverlay instead.`);
77
+ }
72
78
  return <ModalContent {...props} modalRef={ref}>{props.children}</ModalContent>;
73
79
  }
74
80
 
@@ -116,6 +122,11 @@ function ModalOverlayWithForwardRef(props: ModalOverlayProps, ref: ForwardedRef<
116
122
  let contextState = useContext(OverlayTriggerStateContext);
117
123
  let localState = useOverlayTriggerState(props);
118
124
  let state = props.isOpen != null || props.defaultOpen != null || !contextState ? localState : contextState;
125
+ if (state === contextState) {
126
+ if (process.env.NODE_ENV !== 'production' && (props.onOpenChange || props.defaultOpen !== undefined || props.isOpen !== undefined)) {
127
+ console.warn('This modals state is controlled by a trigger, place onOpenChange on the trigger instead.');
128
+ }
129
+ }
119
130
 
120
131
  let objectRef = useObjectRef(ref);
121
132
  let modalRef = useRef<HTMLDivElement>(null);
@@ -168,7 +179,7 @@ function ModalOverlayInner({UNSTABLE_portalContainer, ...props}: ModalOverlayInn
168
179
  return (
169
180
  <Overlay isExiting={props.isExiting} portalContainer={UNSTABLE_portalContainer}>
170
181
  <div
171
- {...mergeProps(filterDOMProps(props as any), underlayProps)}
182
+ {...mergeProps(filterDOMProps(props, {global: true}), underlayProps)}
172
183
  {...renderProps}
173
184
  style={style}
174
185
  ref={props.overlayRef}
@@ -186,7 +197,7 @@ function ModalOverlayInner({UNSTABLE_portalContainer, ...props}: ModalOverlayInn
186
197
  );
187
198
  }
188
199
 
189
- interface ModalContentProps extends RenderProps<ModalRenderProps> {
200
+ interface ModalContentProps extends RenderProps<ModalRenderProps>, GlobalDOMAttributes<HTMLDivElement> {
190
201
  modalRef: ForwardedRef<HTMLDivElement>
191
202
  }
192
203
 
@@ -209,7 +220,7 @@ function ModalContent(props: ModalContentProps) {
209
220
 
210
221
  return (
211
222
  <div
212
- {...mergeProps(filterDOMProps(props as any), modalProps)}
223
+ {...mergeProps(filterDOMProps(props, {global: true}), modalProps)}
213
224
  {...renderProps}
214
225
  ref={ref}
215
226
  data-entering={entering || undefined}