react-aria-components 1.6.0 → 1.7.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 (228) hide show
  1. package/README.md +1 -1
  2. package/dist/Autocomplete.main.js +23 -12
  3. package/dist/Autocomplete.main.js.map +1 -1
  4. package/dist/Autocomplete.mjs +23 -12
  5. package/dist/Autocomplete.module.js +23 -12
  6. package/dist/Autocomplete.module.js.map +1 -1
  7. package/dist/Checkbox.main.js +1 -1
  8. package/dist/Checkbox.main.js.map +1 -1
  9. package/dist/Checkbox.mjs +1 -1
  10. package/dist/Checkbox.module.js +1 -1
  11. package/dist/Checkbox.module.js.map +1 -1
  12. package/dist/Collection.main.js.map +1 -1
  13. package/dist/Collection.module.js.map +1 -1
  14. package/dist/ColorArea.main.js +4 -4
  15. package/dist/ColorArea.main.js.map +1 -1
  16. package/dist/ColorArea.mjs +2 -2
  17. package/dist/ColorArea.module.js +2 -2
  18. package/dist/ColorArea.module.js.map +1 -1
  19. package/dist/ColorField.main.js +8 -10
  20. package/dist/ColorField.main.js.map +1 -1
  21. package/dist/ColorField.mjs +4 -6
  22. package/dist/ColorField.module.js +4 -6
  23. package/dist/ColorField.module.js.map +1 -1
  24. package/dist/ColorPicker.main.js +2 -2
  25. package/dist/ColorPicker.main.js.map +1 -1
  26. package/dist/ColorPicker.mjs +1 -1
  27. package/dist/ColorPicker.module.js +1 -1
  28. package/dist/ColorPicker.module.js.map +1 -1
  29. package/dist/ColorSlider.main.js +5 -7
  30. package/dist/ColorSlider.main.js.map +1 -1
  31. package/dist/ColorSlider.mjs +3 -5
  32. package/dist/ColorSlider.module.js +3 -5
  33. package/dist/ColorSlider.module.js.map +1 -1
  34. package/dist/ColorSwatch.main.js +2 -2
  35. package/dist/ColorSwatch.main.js.map +1 -1
  36. package/dist/ColorSwatch.mjs +1 -1
  37. package/dist/ColorSwatch.module.js +1 -1
  38. package/dist/ColorSwatch.module.js.map +1 -1
  39. package/dist/ColorSwatchPicker.main.js +3 -3
  40. package/dist/ColorSwatchPicker.main.js.map +1 -1
  41. package/dist/ColorSwatchPicker.mjs +1 -1
  42. package/dist/ColorSwatchPicker.module.js +1 -1
  43. package/dist/ColorSwatchPicker.module.js.map +1 -1
  44. package/dist/ColorThumb.main.js +2 -6
  45. package/dist/ColorThumb.main.js.map +1 -1
  46. package/dist/ColorThumb.mjs +1 -5
  47. package/dist/ColorThumb.module.js +1 -5
  48. package/dist/ColorThumb.module.js.map +1 -1
  49. package/dist/ColorWheel.main.js +4 -4
  50. package/dist/ColorWheel.main.js.map +1 -1
  51. package/dist/ColorWheel.mjs +2 -2
  52. package/dist/ColorWheel.module.js +2 -2
  53. package/dist/ColorWheel.module.js.map +1 -1
  54. package/dist/ComboBox.main.js +1 -1
  55. package/dist/ComboBox.main.js.map +1 -1
  56. package/dist/ComboBox.mjs +1 -1
  57. package/dist/ComboBox.module.js +1 -1
  58. package/dist/ComboBox.module.js.map +1 -1
  59. package/dist/DateField.main.js +4 -3
  60. package/dist/DateField.main.js.map +1 -1
  61. package/dist/DateField.mjs +4 -3
  62. package/dist/DateField.module.js +4 -3
  63. package/dist/DateField.module.js.map +1 -1
  64. package/dist/DatePicker.main.js +2 -2
  65. package/dist/DatePicker.main.js.map +1 -1
  66. package/dist/DatePicker.mjs +2 -2
  67. package/dist/DatePicker.module.js +2 -2
  68. package/dist/DatePicker.module.js.map +1 -1
  69. package/dist/Dialog.main.js +2 -1
  70. package/dist/Dialog.main.js.map +1 -1
  71. package/dist/Dialog.mjs +2 -1
  72. package/dist/Dialog.module.js +2 -1
  73. package/dist/Dialog.module.js.map +1 -1
  74. package/dist/Disclosure.main.js +5 -7
  75. package/dist/Disclosure.main.js.map +1 -1
  76. package/dist/Disclosure.mjs +2 -4
  77. package/dist/Disclosure.module.js +2 -4
  78. package/dist/Disclosure.module.js.map +1 -1
  79. package/dist/DropZone.main.js +1 -3
  80. package/dist/DropZone.main.js.map +1 -1
  81. package/dist/DropZone.mjs +1 -3
  82. package/dist/DropZone.module.js +1 -3
  83. package/dist/DropZone.module.js.map +1 -1
  84. package/dist/GridList.main.js.map +1 -1
  85. package/dist/GridList.module.js.map +1 -1
  86. package/dist/Group.main.js.map +1 -1
  87. package/dist/Group.module.js.map +1 -1
  88. package/dist/ListBox.main.js +17 -16
  89. package/dist/ListBox.main.js.map +1 -1
  90. package/dist/ListBox.mjs +19 -18
  91. package/dist/ListBox.module.js +19 -18
  92. package/dist/ListBox.module.js.map +1 -1
  93. package/dist/Menu.main.js +39 -24
  94. package/dist/Menu.main.js.map +1 -1
  95. package/dist/Menu.mjs +40 -25
  96. package/dist/Menu.module.js +40 -25
  97. package/dist/Menu.module.js.map +1 -1
  98. package/dist/Meter.main.js +1 -1
  99. package/dist/Meter.main.js.map +1 -1
  100. package/dist/Meter.mjs +1 -1
  101. package/dist/Meter.module.js +1 -1
  102. package/dist/Meter.module.js.map +1 -1
  103. package/dist/NumberField.main.js +4 -2
  104. package/dist/NumberField.main.js.map +1 -1
  105. package/dist/NumberField.mjs +4 -2
  106. package/dist/NumberField.module.js +4 -2
  107. package/dist/NumberField.module.js.map +1 -1
  108. package/dist/Popover.main.js +67 -15
  109. package/dist/Popover.main.js.map +1 -1
  110. package/dist/Popover.mjs +69 -17
  111. package/dist/Popover.module.js +69 -17
  112. package/dist/Popover.module.js.map +1 -1
  113. package/dist/ProgressBar.main.js +1 -1
  114. package/dist/ProgressBar.main.js.map +1 -1
  115. package/dist/ProgressBar.mjs +1 -1
  116. package/dist/ProgressBar.module.js +1 -1
  117. package/dist/ProgressBar.module.js.map +1 -1
  118. package/dist/RadioGroup.main.js +1 -1
  119. package/dist/RadioGroup.main.js.map +1 -1
  120. package/dist/RadioGroup.mjs +1 -1
  121. package/dist/RadioGroup.module.js +1 -1
  122. package/dist/RadioGroup.module.js.map +1 -1
  123. package/dist/SearchField.main.js +4 -2
  124. package/dist/SearchField.main.js.map +1 -1
  125. package/dist/SearchField.mjs +5 -3
  126. package/dist/SearchField.module.js +5 -3
  127. package/dist/SearchField.module.js.map +1 -1
  128. package/dist/Select.main.js +3 -2
  129. package/dist/Select.main.js.map +1 -1
  130. package/dist/Select.mjs +3 -2
  131. package/dist/Select.module.js +3 -2
  132. package/dist/Select.module.js.map +1 -1
  133. package/dist/Slider.main.js +2 -2
  134. package/dist/Slider.main.js.map +1 -1
  135. package/dist/Slider.mjs +2 -2
  136. package/dist/Slider.module.js +2 -2
  137. package/dist/Slider.module.js.map +1 -1
  138. package/dist/Table.main.js +15 -6
  139. package/dist/Table.main.js.map +1 -1
  140. package/dist/Table.mjs +15 -6
  141. package/dist/Table.module.js +15 -6
  142. package/dist/Table.module.js.map +1 -1
  143. package/dist/TableLayout.main.js.map +1 -1
  144. package/dist/TableLayout.module.js.map +1 -1
  145. package/dist/Tabs.main.js +3 -2
  146. package/dist/Tabs.main.js.map +1 -1
  147. package/dist/Tabs.mjs +4 -3
  148. package/dist/Tabs.module.js +4 -3
  149. package/dist/Tabs.module.js.map +1 -1
  150. package/dist/TagGroup.main.js +1 -1
  151. package/dist/TagGroup.main.js.map +1 -1
  152. package/dist/TagGroup.mjs +1 -1
  153. package/dist/TagGroup.module.js +1 -1
  154. package/dist/TagGroup.module.js.map +1 -1
  155. package/dist/TextField.main.js +4 -2
  156. package/dist/TextField.main.js.map +1 -1
  157. package/dist/TextField.mjs +5 -3
  158. package/dist/TextField.module.js +5 -3
  159. package/dist/TextField.module.js.map +1 -1
  160. package/dist/Toast.main.js +148 -0
  161. package/dist/Toast.main.js.map +1 -0
  162. package/dist/Toast.mjs +137 -0
  163. package/dist/Toast.module.js +137 -0
  164. package/dist/Toast.module.js.map +1 -0
  165. package/dist/Tree.main.js +38 -34
  166. package/dist/Tree.main.js.map +1 -1
  167. package/dist/Tree.mjs +34 -30
  168. package/dist/Tree.module.js +34 -30
  169. package/dist/Tree.module.js.map +1 -1
  170. package/dist/Virtualizer.main.js +4 -1
  171. package/dist/Virtualizer.main.js.map +1 -1
  172. package/dist/Virtualizer.mjs +4 -1
  173. package/dist/Virtualizer.module.js +4 -1
  174. package/dist/Virtualizer.module.js.map +1 -1
  175. package/dist/import.mjs +9 -7
  176. package/dist/main.js +31 -17
  177. package/dist/main.js.map +1 -1
  178. package/dist/module.js +9 -7
  179. package/dist/module.js.map +1 -1
  180. package/dist/types.d.ts +159 -59
  181. package/dist/types.d.ts.map +1 -1
  182. package/dist/utils.main.js +9 -7
  183. package/dist/utils.main.js.map +1 -1
  184. package/dist/utils.mjs +9 -7
  185. package/dist/utils.module.js +9 -7
  186. package/dist/utils.module.js.map +1 -1
  187. package/i18n/index.js +1 -1
  188. package/i18n/index.mjs +1 -1
  189. package/package.json +25 -30
  190. package/src/Autocomplete.tsx +19 -15
  191. package/src/Checkbox.tsx +3 -1
  192. package/src/Collection.tsx +2 -2
  193. package/src/ColorArea.tsx +2 -3
  194. package/src/ColorField.tsx +8 -6
  195. package/src/ColorPicker.tsx +1 -2
  196. package/src/ColorSlider.tsx +5 -5
  197. package/src/ColorSwatch.tsx +2 -2
  198. package/src/ColorSwatchPicker.tsx +1 -1
  199. package/src/ColorThumb.tsx +2 -4
  200. package/src/ColorWheel.tsx +2 -2
  201. package/src/ComboBox.tsx +3 -1
  202. package/src/DateField.tsx +8 -3
  203. package/src/DatePicker.tsx +6 -2
  204. package/src/Dialog.tsx +6 -2
  205. package/src/Disclosure.tsx +2 -3
  206. package/src/DropZone.tsx +1 -2
  207. package/src/GridList.tsx +5 -0
  208. package/src/Group.tsx +1 -0
  209. package/src/ListBox.tsx +11 -9
  210. package/src/Menu.tsx +53 -25
  211. package/src/Meter.tsx +3 -1
  212. package/src/NumberField.tsx +11 -2
  213. package/src/Popover.tsx +77 -25
  214. package/src/ProgressBar.tsx +3 -1
  215. package/src/RadioGroup.tsx +3 -1
  216. package/src/SearchField.tsx +6 -4
  217. package/src/Select.tsx +5 -2
  218. package/src/Slider.tsx +6 -2
  219. package/src/Table.tsx +35 -15
  220. package/src/TableLayout.ts +1 -1
  221. package/src/Tabs.tsx +6 -3
  222. package/src/TagGroup.tsx +3 -1
  223. package/src/TextField.tsx +6 -4
  224. package/src/Toast.tsx +184 -0
  225. package/src/Tree.tsx +67 -49
  226. package/src/Virtualizer.tsx +18 -3
  227. package/src/index.ts +16 -16
  228. package/src/utils.tsx +8 -10
@@ -15,7 +15,7 @@ import {LayoutOptionsDelegate} from './Virtualizer';
15
15
  import {TableColumnResizeStateContext} from './Table';
16
16
  import {useContext, useMemo} from 'react';
17
17
 
18
- export class TableLayout<T> extends BaseTableLayout<T> implements LayoutOptionsDelegate<TableLayoutProps> {
18
+ export class TableLayout<T, O extends TableLayoutProps = TableLayoutProps> extends BaseTableLayout<T, O> implements LayoutOptionsDelegate<TableLayoutProps> {
19
19
  // Invalidate the layout whenever the column widths change.
20
20
  useLayoutOptions() {
21
21
  // This is not a React class component, just a regular class.
package/src/Tabs.tsx CHANGED
@@ -15,7 +15,7 @@ import {AriaTabListProps, AriaTabPanelProps, mergeProps, Orientation, useFocusRi
15
15
  import {Collection, CollectionBuilder, createHideableComponent, createLeafComponent} from '@react-aria/collections';
16
16
  import {CollectionProps, CollectionRendererContext, DefaultCollectionRenderer, usePersistedKeys} from './Collection';
17
17
  import {ContextValue, Provider, RenderProps, SlotProps, StyleRenderProps, useContextProps, useRenderProps, useSlottedContext} from './utils';
18
- import {filterDOMProps, useObjectRef} from '@react-aria/utils';
18
+ import {filterDOMProps, inertValue, useObjectRef} from '@react-aria/utils';
19
19
  import {Collection as ICollection, Node, TabListState, useTabListState} from 'react-stately';
20
20
  import React, {createContext, ForwardedRef, forwardRef, JSX, useContext, useMemo} from 'react';
21
21
 
@@ -255,6 +255,7 @@ export const Tab = /*#__PURE__*/ createLeafComponent('item', (props: TabProps, f
255
255
  let renderProps = useRenderProps({
256
256
  ...props,
257
257
  id: undefined,
258
+ children: item.rendered,
258
259
  defaultClassName: 'react-aria-Tab',
259
260
  values: {
260
261
  isSelected,
@@ -277,7 +278,9 @@ export const Tab = /*#__PURE__*/ createLeafComponent('item', (props: TabProps, f
277
278
  data-focused={isFocused || undefined}
278
279
  data-focus-visible={isFocusVisible || undefined}
279
280
  data-pressed={isPressed || undefined}
280
- data-hovered={isHovered || undefined} />
281
+ data-hovered={isHovered || undefined}>
282
+ {renderProps.children}
283
+ </ElementType>
281
284
  );
282
285
  });
283
286
 
@@ -320,7 +323,7 @@ export const TabPanel = /*#__PURE__*/ createHideableComponent(function TabPanel(
320
323
  data-focused={isFocused || undefined}
321
324
  data-focus-visible={isFocusVisible || undefined}
322
325
  // @ts-ignore
323
- inert={!isSelected ? 'true' : undefined}
326
+ inert={inertValue(!isSelected)}
324
327
  data-inert={!isSelected ? 'true' : undefined}>
325
328
  <Provider
326
329
  values={[
package/src/TagGroup.tsx CHANGED
@@ -75,7 +75,9 @@ interface TagGroupInnerProps {
75
75
 
76
76
  function TagGroupInner({props, forwardedRef: ref, collection}: TagGroupInnerProps) {
77
77
  let tagListRef = useRef<HTMLDivElement>(null);
78
- let [labelRef, label] = useSlot();
78
+ let [labelRef, label] = useSlot(
79
+ !props['aria-label'] && !props['aria-labelledby']
80
+ );
79
81
  let state = useListState({
80
82
  ...props,
81
83
  children: undefined,
package/src/TextField.tsx CHANGED
@@ -12,13 +12,13 @@
12
12
 
13
13
  import {AriaTextFieldProps, useTextField} from 'react-aria';
14
14
  import {ContextValue, DOMProps, Provider, RACValidation, removeDataAttributes, RenderProps, SlotProps, useContextProps, useRenderProps, useSlot, useSlottedContext} from './utils';
15
+ import {createHideableComponent} from '@react-aria/collections';
15
16
  import {FieldErrorContext} from './FieldError';
16
17
  import {filterDOMProps, mergeProps} from '@react-aria/utils';
17
18
  import {FormContext} from './Form';
18
- import {forwardRefType} from '@react-types/shared';
19
19
  import {InputContext} from './Input';
20
20
  import {LabelContext} from './Label';
21
- import React, {createContext, ForwardedRef, forwardRef, useCallback, useRef, useState} from 'react';
21
+ import React, {createContext, ForwardedRef, useCallback, useRef, useState} from 'react';
22
22
  import {TextAreaContext} from './TextArea';
23
23
  import {TextContext} from './Text';
24
24
 
@@ -55,13 +55,15 @@ export const TextFieldContext = createContext<ContextValue<TextFieldProps, HTMLD
55
55
  /**
56
56
  * A text field allows a user to enter a plain text value with a keyboard.
57
57
  */
58
- export const TextField = /*#__PURE__*/ (forwardRef as forwardRefType)(function TextField(props: TextFieldProps, ref: ForwardedRef<HTMLDivElement>) {
58
+ export const TextField = /*#__PURE__*/ createHideableComponent(function TextField(props: TextFieldProps, ref: ForwardedRef<HTMLDivElement>) {
59
59
  [props, ref] = useContextProps(props, ref, TextFieldContext);
60
60
  let {validationBehavior: formValidationBehavior} = useSlottedContext(FormContext) || {};
61
61
  let validationBehavior = props.validationBehavior ?? formValidationBehavior ?? 'native';
62
62
  let inputRef = useRef(null);
63
63
  let [inputContextProps, mergedInputRef] = useContextProps({}, inputRef, InputContext);
64
- let [labelRef, label] = useSlot();
64
+ let [labelRef, label] = useSlot(
65
+ !props['aria-label'] && !props['aria-labelledby']
66
+ );
65
67
  let [inputElementType, setInputElementType] = useState('input');
66
68
  let {labelProps, inputProps, descriptionProps, errorMessageProps, ...validation} = useTextField<any>({
67
69
  ...removeDataAttributes(props),
package/src/Toast.tsx ADDED
@@ -0,0 +1,184 @@
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
+ import {AriaToastProps, AriaToastRegionProps, mergeProps, useFocusRing, useToast, useToastRegion} from 'react-aria';
14
+ import {ButtonContext} from './Button';
15
+ import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, StyleRenderProps, useContextProps, useRenderProps} from './utils';
16
+ import {createPortal} from 'react-dom';
17
+ import {forwardRefType} from '@react-types/shared';
18
+ import {QueuedToast, ToastQueue, ToastState, useToastQueue} from 'react-stately';
19
+ import React, {createContext, ForwardedRef, forwardRef, HTMLAttributes, JSX, ReactElement, useContext} from 'react';
20
+ import {TextContext} from './Text';
21
+ import {useObjectRef} from '@react-aria/utils';
22
+
23
+ const ToastStateContext = createContext<ToastState<any> | null>(null);
24
+
25
+ export interface ToastRegionRenderProps<T> {
26
+ /** A list of all currently visible toasts. */
27
+ visibleToasts: QueuedToast<T>[],
28
+ /**
29
+ * Whether the toast region is currently focused.
30
+ * @selector [data-focused]
31
+ */
32
+ isFocused: boolean,
33
+ /**
34
+ * Whether the toast region is keyboard focused.
35
+ * @selector [data-focus-visible]
36
+ */
37
+ isFocusVisible: boolean
38
+ }
39
+
40
+ export interface ToastRegionProps<T> extends AriaToastRegionProps, StyleRenderProps<ToastRegionRenderProps<T>> {
41
+ /** The queue of toasts to display. */
42
+ queue: ToastQueue<T>,
43
+ /** A function to render each toast. */
44
+ children: (renderProps: {toast: QueuedToast<T>}) => ReactElement
45
+ }
46
+
47
+ /**
48
+ * A ToastRegion displays one or more toast notifications.
49
+ */
50
+ export const ToastRegion = /*#__PURE__*/ (forwardRef as forwardRefType)(function ToastRegion<T>(props: ToastRegionProps<T>, ref: ForwardedRef<HTMLDivElement>): JSX.Element | null {
51
+ let state = useToastQueue(props.queue);
52
+ let objectRef = useObjectRef(ref);
53
+ let {regionProps} = useToastRegion(props, state, objectRef);
54
+
55
+ let {focusProps, isFocused, isFocusVisible} = useFocusRing();
56
+ let renderProps = useRenderProps({
57
+ ...props,
58
+ children: undefined,
59
+ defaultClassName: 'react-aria-ToastRegion',
60
+ values: {
61
+ visibleToasts: state.visibleToasts,
62
+ isFocused,
63
+ isFocusVisible
64
+ }
65
+ });
66
+
67
+ let region = (
68
+ <ToastStateContext.Provider value={state}>
69
+ <div
70
+ {...renderProps}
71
+ {...mergeProps(regionProps, focusProps)}
72
+ ref={objectRef}
73
+ data-focused={isFocused || undefined}
74
+ data-focus-visible={isFocusVisible || undefined}>
75
+ {typeof props.children === 'function' ? <ToastList {...props} style={{display: 'contents'}} /> : props.children}
76
+ </div>
77
+ </ToastStateContext.Provider>
78
+ );
79
+
80
+ return state.visibleToasts.length > 0 && typeof document !== 'undefined'
81
+ ? createPortal(region, document.body)
82
+ : null;
83
+ });
84
+
85
+ // TODO: possibly export this so additional children can be added to the region, outside the list.
86
+ const ToastList = /*#__PURE__*/ (forwardRef as forwardRefType)(function ToastList<T>(props: ToastRegionProps<T>, ref: ForwardedRef<HTMLOListElement>) {
87
+ let state = useContext(ToastStateContext)!;
88
+ return (
89
+ // @ts-ignore
90
+ <ol ref={ref} style={props.style} className={props.className}>
91
+ {state.visibleToasts.map((toast) => (
92
+ <li key={toast.key} style={{display: 'contents'}}>
93
+ {props.children({toast})}
94
+ </li>
95
+ ))}
96
+ </ol>
97
+ );
98
+ });
99
+
100
+ export interface ToastRenderProps<T> {
101
+ /**
102
+ * The toast object to display.
103
+ */
104
+ toast: QueuedToast<T>,
105
+ /**
106
+ * Whether the toast is currently focused.
107
+ * @selector [data-focused]
108
+ */
109
+ isFocused: boolean,
110
+ /**
111
+ * Whether the toast is keyboard focused.
112
+ * @selector [data-focus-visible]
113
+ */
114
+ isFocusVisible: boolean
115
+ }
116
+
117
+ export interface ToastProps<T> extends AriaToastProps<T>, RenderProps<ToastRenderProps<T>> {}
118
+
119
+ /**
120
+ * A Toast displays a brief, temporary notification of actions, errors, or other events in an application.
121
+ */
122
+ export const Toast = /*#__PURE__*/ (forwardRef as forwardRefType)(function Toast<T>(props: ToastProps<T>, ref: ForwardedRef<HTMLDivElement>) {
123
+ let state = useContext(ToastStateContext)!;
124
+ let objectRef = useObjectRef(ref);
125
+ let {toastProps, contentProps, titleProps, descriptionProps, closeButtonProps} = useToast(
126
+ props,
127
+ state,
128
+ objectRef
129
+ );
130
+
131
+ let {focusProps, isFocused, isFocusVisible} = useFocusRing();
132
+ let renderProps = useRenderProps({
133
+ ...props,
134
+ defaultClassName: 'react-aria-Toast',
135
+ values: {
136
+ toast: props.toast,
137
+ isFocused,
138
+ isFocusVisible
139
+ }
140
+ });
141
+
142
+ return (
143
+ <div
144
+ {...renderProps}
145
+ {...mergeProps(toastProps, focusProps)}
146
+ ref={objectRef}
147
+ data-focused={isFocused || undefined}
148
+ data-focus-visible={isFocusVisible || undefined}>
149
+ <Provider
150
+ values={[
151
+ [ToastContentContext, contentProps],
152
+ [TextContext, {
153
+ slots: {
154
+ [DEFAULT_SLOT]: {},
155
+ title: titleProps,
156
+ description: descriptionProps
157
+ }
158
+ }],
159
+ [ButtonContext, {
160
+ slots: {
161
+ [DEFAULT_SLOT]: {},
162
+ close: closeButtonProps
163
+ }
164
+ }]
165
+ ]}>
166
+ {renderProps.children}
167
+ </Provider>
168
+ </div>
169
+ );
170
+ });
171
+
172
+ export const ToastContentContext = createContext<ContextValue<HTMLAttributes<HTMLElement>, HTMLDivElement>>({});
173
+
174
+ /**
175
+ * ToastContent wraps the main content of a toast notification.
176
+ */
177
+ export const ToastContent = /*#__PURE__*/ forwardRef(function ToastContent(props: HTMLAttributes<HTMLElement>, ref: ForwardedRef<HTMLDivElement>) {
178
+ [props, ref] = useContextProps(props, ref, ToastContentContext);
179
+ return (
180
+ <div className="react-aria-ToastContent" {...props} ref={ref}>
181
+ {props.children}
182
+ </div>
183
+ );
184
+ });
package/src/Tree.tsx CHANGED
@@ -10,17 +10,16 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import {AriaTreeGridListProps, useTreeGridList, useTreeGridListItem} from '@react-aria/tree';
13
+ import {AriaTreeItemOptions, AriaTreeProps, FocusScope, mergeProps, useFocusRing, useGridListSelectionCheckbox, useHover, useTree, useTreeItem} from 'react-aria';
14
14
  import {ButtonContext} from './Button';
15
15
  import {CheckboxContext} from './RSPContexts';
16
16
  import {Collection, CollectionBuilder, CollectionNode, createBranchComponent, createLeafComponent, useCachedChildren} from '@react-aria/collections';
17
17
  import {CollectionProps, CollectionRendererContext, DefaultCollectionRenderer, ItemRenderProps, usePersistedKeys} from './Collection';
18
18
  import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, ScrollableProps, SlotProps, StyleRenderProps, useContextProps, useRenderProps} from './utils';
19
- import {DisabledBehavior, Expandable, forwardRefType, HoverEvents, Key, LinkDOMProps, RefObject} from '@react-types/shared';
19
+ import {DisabledBehavior, Expandable, forwardRefType, HoverEvents, Key, LinkDOMProps, MultipleSelection, RefObject} from '@react-types/shared';
20
20
  import {filterDOMProps, useObjectRef} from '@react-aria/utils';
21
- import {FocusScope, mergeProps, useFocusRing, useGridListSelectionCheckbox, useHover} from 'react-aria';
22
21
  import {Collection as ICollection, Node, SelectionBehavior, TreeState, useTreeState} from 'react-stately';
23
- import React, {createContext, ForwardedRef, forwardRef, HTMLAttributes, ReactNode, useContext, useEffect, useMemo, useRef} from 'react';
22
+ import React, {createContext, ForwardedRef, forwardRef, ReactNode, useContext, useEffect, useMemo, useRef} from 'react';
24
23
  import {useControlledState} from '@react-stately/utils';
25
24
 
26
25
  class TreeCollection<T> implements ICollection<Node<T>> {
@@ -120,29 +119,29 @@ export interface TreeRenderProps {
120
119
 
121
120
  export interface TreeEmptyStateRenderProps extends Omit<TreeRenderProps, 'isEmpty'> {}
122
121
 
123
- export interface TreeProps<T> extends Omit<AriaTreeGridListProps<T>, 'children'>, CollectionProps<T>, StyleRenderProps<TreeRenderProps>, SlotProps, ScrollableProps<HTMLDivElement>, Expandable {
122
+ export interface TreeProps<T> extends Omit<AriaTreeProps<T>, 'children'>, MultipleSelection, CollectionProps<T>, StyleRenderProps<TreeRenderProps>, SlotProps, ScrollableProps<HTMLDivElement>, Expandable {
124
123
  /** How multiple selection should behave in the tree. */
125
124
  selectionBehavior?: SelectionBehavior,
126
125
  /** Provides content to display when there are no items in the list. */
127
126
  renderEmptyState?: (props: TreeEmptyStateRenderProps) => ReactNode,
128
127
  /**
129
128
  * Whether `disabledKeys` applies to all interactions, or only selection.
130
- * @default 'selection'
129
+ * @default 'all'
131
130
  */
132
131
  disabledBehavior?: DisabledBehavior
133
132
  }
134
133
 
135
134
 
136
- export const UNSTABLE_TreeContext = createContext<ContextValue<TreeProps<any>, HTMLDivElement>>(null);
137
- export const UNSTABLE_TreeStateContext = createContext<TreeState<any> | null>(null);
135
+ export const TreeContext = createContext<ContextValue<TreeProps<any>, HTMLDivElement>>(null);
136
+ export const TreeStateContext = createContext<TreeState<any> | null>(null);
138
137
 
139
138
  /**
140
139
  * A tree provides users with a way to navigate nested hierarchical information, with support for keyboard navigation
141
140
  * and selection.
142
141
  */
143
- export const UNSTABLE_Tree = /*#__PURE__*/ (forwardRef as forwardRefType)(function Tree<T extends object>(props: TreeProps<T>, ref: ForwardedRef<HTMLDivElement>) {
142
+ export const Tree = /*#__PURE__*/ (forwardRef as forwardRefType)(function Tree<T extends object>(props: TreeProps<T>, ref: ForwardedRef<HTMLDivElement>) {
144
143
  // Render the portal first so that we have the collection by the time we render the DOM in SSR.
145
- [props, ref] = useContextProps(props, ref, UNSTABLE_TreeContext);
144
+ [props, ref] = useContextProps(props, ref, TreeContext);
146
145
 
147
146
  return (
148
147
  <CollectionBuilder content={<Collection {...props} />}>
@@ -163,7 +162,7 @@ function TreeInner<T extends object>({props, collection, treeRef: ref}: TreeInne
163
162
  expandedKeys: propExpandedKeys,
164
163
  defaultExpandedKeys: propDefaultExpandedKeys,
165
164
  onExpandedChange,
166
- disabledBehavior = 'selection'
165
+ disabledBehavior = 'all'
167
166
  } = props;
168
167
  let {CollectionRoot, isVirtualized, layoutDelegate} = useContext(CollectionRendererContext);
169
168
 
@@ -189,7 +188,7 @@ function TreeInner<T extends object>({props, collection, treeRef: ref}: TreeInne
189
188
  disabledBehavior
190
189
  });
191
190
 
192
- let {gridProps} = useTreeGridList({
191
+ let {gridProps} = useTree({
193
192
  ...props,
194
193
  isVirtualized,
195
194
  layoutDelegate
@@ -211,7 +210,6 @@ function TreeInner<T extends object>({props, collection, treeRef: ref}: TreeInne
211
210
  });
212
211
 
213
212
  let emptyState: ReactNode = null;
214
- let emptyStatePropOverrides: HTMLAttributes<HTMLElement> | null = null;
215
213
  if (state.collection.size === 0 && props.renderEmptyState) {
216
214
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
217
215
  let {isEmpty, ...values} = renderValues;
@@ -236,7 +234,7 @@ function TreeInner<T extends object>({props, collection, treeRef: ref}: TreeInne
236
234
  <div
237
235
  {...filterDOMProps(props)}
238
236
  {...renderProps}
239
- {...mergeProps(gridProps, focusProps, emptyStatePropOverrides)}
237
+ {...mergeProps(gridProps, focusProps)}
240
238
  ref={ref}
241
239
  slot={props.slot || undefined}
242
240
  onScroll={props.onScroll}
@@ -245,7 +243,7 @@ function TreeInner<T extends object>({props, collection, treeRef: ref}: TreeInne
245
243
  data-focus-visible={isFocusVisible || undefined}>
246
244
  <Provider
247
245
  values={[
248
- [UNSTABLE_TreeStateContext, state]
246
+ [TreeStateContext, state]
249
247
  ]}>
250
248
  <CollectionRoot
251
249
  collection={state.collection}
@@ -260,30 +258,39 @@ function TreeInner<T extends object>({props, collection, treeRef: ref}: TreeInne
260
258
 
261
259
  // TODO: readd the rest of the render props when tree supports them
262
260
  export interface TreeItemRenderProps extends Omit<ItemRenderProps, 'allowsDragging' | 'isDragging' | 'isDropTarget'> {
263
- /** Whether the tree item is expanded. */
264
- isExpanded: boolean,
265
- // TODO: api discussion, how do we feel about the below? This is so we can still style the row as grey when a child element within is focused
266
- // Maybe should have this for the other collection item render props
267
- /** Whether the tree item's children have keyboard focus. */
268
- isFocusVisibleWithin: boolean
269
- }
270
-
271
- export interface TreeItemContentRenderProps extends ItemRenderProps {
272
- // Whether the tree item is expanded.
261
+ /**
262
+ * Whether the tree item is expanded.
263
+ * @selector [data-expanded]
264
+ */
273
265
  isExpanded: boolean,
274
- // Whether the tree item has child rows.
275
- hasChildRows: boolean,
276
- // What level the tree item has within the tree.
266
+ /**
267
+ * Whether the tree item has child tree items.
268
+ * @selector [data-has-child-items]
269
+ */
270
+ hasChildItems: boolean,
271
+ /**
272
+ * What level the tree item has within the tree.
273
+ * @selector [data-level="number"]
274
+ */
277
275
  level: number,
278
- // Whether the tree item's children have keyboard focus.
279
- isFocusVisibleWithin: boolean
276
+ /**
277
+ * Whether the tree item's children have keyboard focus.
278
+ * @selector [data-focus-visible-within]
279
+ */
280
+ isFocusVisibleWithin: boolean,
281
+ /** The state of the tree. */
282
+ state: TreeState<unknown>,
283
+ /** The unique id of the tree row. */
284
+ id: Key
280
285
  }
281
286
 
287
+ export interface TreeItemContentRenderProps extends TreeItemRenderProps {}
288
+
282
289
  // The TreeItemContent is the one that accepts RenderProps because we would get much more complicated logic in TreeItem otherwise since we'd
283
290
  // need to do a bunch of check to figure out what is the Content and what are the actual collection elements (aka child rows) of the TreeItem
284
291
  export interface TreeItemContentProps extends Pick<RenderProps<TreeItemContentRenderProps>, 'children'> {}
285
292
 
286
- export const UNSTABLE_TreeItemContent = /*#__PURE__*/ createLeafComponent('content', function TreeItemContent(props: TreeItemContentProps) {
293
+ export const TreeItemContent = /*#__PURE__*/ createLeafComponent('content', function TreeItemContent(props: TreeItemContentProps) {
287
294
  let values = useContext(TreeItemContentContext)!;
288
295
  let renderProps = useRenderProps({
289
296
  children: props.children,
@@ -298,7 +305,7 @@ export const UNSTABLE_TreeItemContent = /*#__PURE__*/ createLeafComponent('conte
298
305
 
299
306
  export const TreeItemContentContext = createContext<TreeItemContentRenderProps | null>(null);
300
307
 
301
- export interface TreeItemProps<T = object> extends StyleRenderProps<TreeItemRenderProps>, LinkDOMProps, HoverEvents {
308
+ export interface TreeItemProps<T = object> extends StyleRenderProps<TreeItemRenderProps>, LinkDOMProps, HoverEvents, Pick<AriaTreeItemOptions, 'hasChildItems'> {
302
309
  /** The unique id of the tree row. */
303
310
  id?: Key,
304
311
  /** The object value that this tree item represents. When using dynamic collections, this is set automatically. */
@@ -308,20 +315,27 @@ export interface TreeItemProps<T = object> extends StyleRenderProps<TreeItemRend
308
315
  /** An accessibility label for this tree item. */
309
316
  'aria-label'?: string,
310
317
  /** The content of the tree item along with any nested children. Supports static nested tree items or use of a Collection to dynamically render nested tree items. */
311
- children: ReactNode
318
+ children: ReactNode,
319
+ /** Whether the item is disabled. */
320
+ isDisabled?: boolean,
321
+ /**
322
+ * Handler that is called when a user performs an action on this tree item. The exact user event depends on
323
+ * the collection's `selectionBehavior` prop and the interaction modality.
324
+ */
325
+ onAction?: () => void
312
326
  }
313
327
 
314
328
  /**
315
329
  * A TreeItem represents an individual item in a Tree.
316
330
  */
317
- export const UNSTABLE_TreeItem = /*#__PURE__*/ createBranchComponent('item', <T extends object>(props: TreeItemProps<T>, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) => {
318
- let state = useContext(UNSTABLE_TreeStateContext)!;
331
+ export const TreeItem = /*#__PURE__*/ createBranchComponent('item', <T extends object>(props: TreeItemProps<T>, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) => {
332
+ let state = useContext(TreeStateContext)!;
319
333
  ref = useObjectRef<HTMLDivElement>(ref);
320
334
  // TODO: remove this when we support description in tree row
321
335
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
322
- let {rowProps, gridCellProps, expandButtonProps, descriptionProps, ...states} = useTreeGridListItem({node: item}, state, ref);
336
+ let {rowProps, gridCellProps, expandButtonProps, descriptionProps, ...states} = useTreeItem({node: item}, state, ref);
323
337
  let isExpanded = rowProps['aria-expanded'] === true;
324
- let hasChildRows = [...state.collection.getChildren!(item.key)]?.length > 1;
338
+ let hasChildItems = props.hasChildItems || [...state.collection.getChildren!(item.key)]?.length > 1;;
325
339
  let level = rowProps['aria-level'] || 1;
326
340
 
327
341
  let {hoverProps, isHovered} = useHover({
@@ -341,17 +355,21 @@ export const UNSTABLE_TreeItem = /*#__PURE__*/ createBranchComponent('item', <T
341
355
  state
342
356
  );
343
357
 
358
+ let selectionMode = state.selectionManager.selectionMode;
359
+ let selectionBehavior = state.selectionManager.selectionBehavior;
344
360
  let renderPropValues = React.useMemo<TreeItemContentRenderProps>(() => ({
345
361
  ...states,
346
362
  isHovered,
347
363
  isFocusVisible,
348
364
  isExpanded,
349
- hasChildRows,
365
+ hasChildItems,
350
366
  level,
351
- selectionMode: state.selectionManager.selectionMode,
352
- selectionBehavior: state.selectionManager.selectionBehavior,
353
- isFocusVisibleWithin
354
- }), [states, isHovered, isFocusVisible, state.selectionManager, isExpanded, hasChildRows, level, isFocusVisibleWithin]);
367
+ selectionMode,
368
+ selectionBehavior,
369
+ isFocusVisibleWithin,
370
+ state,
371
+ id: item.key
372
+ }), [states, isHovered, isFocusVisible, selectionMode, selectionBehavior, isExpanded, hasChildItems, level, isFocusVisibleWithin, state, item.key]);
355
373
 
356
374
  let renderProps = useRenderProps({
357
375
  ...props,
@@ -373,7 +391,7 @@ export const UNSTABLE_TreeItem = /*#__PURE__*/ createBranchComponent('item', <T
373
391
 
374
392
  let expandButtonRef = useRef<HTMLButtonElement>(null);
375
393
  useEffect(() => {
376
- if (hasChildRows && !expandButtonRef.current) {
394
+ if (hasChildItems && !expandButtonRef.current) {
377
395
  console.warn('Expandable tree items must contain a expand button so screen reader users can expand/collapse the item.');
378
396
  }
379
397
  // eslint-disable-next-line
@@ -404,8 +422,8 @@ export const UNSTABLE_TreeItem = /*#__PURE__*/ createBranchComponent('item', <T
404
422
  {...renderProps}
405
423
  ref={ref}
406
424
  // TODO: missing selectionBehavior, hasAction and allowsSelection data attribute equivalents (available in renderProps). Do we want those?
407
- data-expanded={(hasChildRows && isExpanded) || undefined}
408
- data-has-child-rows={hasChildRows || undefined}
425
+ data-expanded={(hasChildItems && isExpanded) || undefined}
426
+ data-has-child-items={hasChildItems || undefined}
409
427
  data-level={level}
410
428
  data-selected={states.isSelected || undefined}
411
429
  data-disabled={states.isDisabled || undefined}
@@ -445,7 +463,7 @@ export const UNSTABLE_TreeItem = /*#__PURE__*/ createBranchComponent('item', <T
445
463
  );
446
464
  });
447
465
 
448
- export interface TreeLoadingIndicatorRenderProps {
466
+ export interface UNSTABLE_TreeLoadingIndicatorRenderProps {
449
467
  /**
450
468
  * What level the tree item has within the tree.
451
469
  * @selector [data-level]
@@ -453,13 +471,13 @@ export interface TreeLoadingIndicatorRenderProps {
453
471
  level: number
454
472
  }
455
473
 
456
- export interface TreeLoaderProps extends RenderProps<TreeLoadingIndicatorRenderProps>, StyleRenderProps<TreeLoadingIndicatorRenderProps> {}
474
+ export interface TreeLoaderProps extends RenderProps<UNSTABLE_TreeLoadingIndicatorRenderProps>, StyleRenderProps<UNSTABLE_TreeLoadingIndicatorRenderProps> {}
457
475
 
458
476
  export const UNSTABLE_TreeLoadingIndicator = createLeafComponent('loader', function TreeLoader<T extends object>(props: TreeLoaderProps, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) {
459
- let state = useContext(UNSTABLE_TreeStateContext);
477
+ let state = useContext(TreeStateContext);
460
478
  // This loader row is is non-interactable, but we want the same aria props calculated as a typical row
461
479
  // @ts-ignore
462
- let {rowProps} = useTreeGridListItem({node: item}, state, ref);
480
+ let {rowProps} = useTreeItem({node: item}, state, ref);
463
481
  let level = rowProps['aria-level'] || 1;
464
482
 
465
483
  let ariaProps = {
@@ -24,20 +24,35 @@ export interface LayoutOptionsDelegate<O> {
24
24
 
25
25
  interface ILayout<O> extends Layout<Node<unknown>, O>, Partial<DropTargetDelegate>, LayoutOptionsDelegate<O> {}
26
26
 
27
+ interface LayoutClass<O> {
28
+ new(): ILayout<O>
29
+ }
30
+
27
31
  export interface VirtualizerProps<O> {
28
32
  /** The child collection to virtualize (e.g. ListBox, GridList, or Table). */
29
33
  children: ReactNode,
30
34
  /** The layout object that determines the position and size of the visible elements. */
31
- layout: ILayout<O>,
35
+ layout: LayoutClass<O> | ILayout<O>,
32
36
  /** Options for the layout. */
33
37
  layoutOptions?: O
34
38
  }
35
39
 
40
+ interface LayoutContextValue {
41
+ layout: ILayout<any>,
42
+ layoutOptions?: any
43
+ }
44
+
36
45
  const VirtualizerContext = createContext<VirtualizerState<any, any> | null>(null);
37
- const LayoutContext = createContext<Pick<VirtualizerProps<any>, 'layout' | 'layoutOptions'> | null>(null);
46
+ const LayoutContext = createContext<LayoutContextValue | null>(null);
38
47
 
48
+ /**
49
+ * A Virtualizer renders a scrollable collection of data using customizable layouts.
50
+ * It supports very large collections by only rendering visible items to the DOM, reusing
51
+ * them as the user scrolls.
52
+ */
39
53
  export function Virtualizer<O>(props: VirtualizerProps<O>) {
40
- let {children, layout, layoutOptions} = props;
54
+ let {children, layout: layoutProp, layoutOptions} = props;
55
+ let layout = useMemo(() => typeof layoutProp === 'function' ? new layoutProp() : layoutProp, [layoutProp]);
41
56
  let renderer: CollectionRenderer = useMemo(() => ({
42
57
  isVirtualized: true,
43
58
  layoutDelegate: layout,