react-aria-components 1.9.0 → 1.10.1

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 (81) hide show
  1. package/dist/Checkbox.main.js +4 -1
  2. package/dist/Checkbox.main.js.map +1 -1
  3. package/dist/Checkbox.mjs +5 -2
  4. package/dist/Checkbox.module.js +5 -2
  5. package/dist/Checkbox.module.js.map +1 -1
  6. package/dist/Collection.main.js +31 -7
  7. package/dist/Collection.main.js.map +1 -1
  8. package/dist/Collection.mjs +32 -9
  9. package/dist/Collection.module.js +32 -9
  10. package/dist/Collection.module.js.map +1 -1
  11. package/dist/ComboBox.main.js +10 -1
  12. package/dist/ComboBox.main.js.map +1 -1
  13. package/dist/ComboBox.mjs +10 -1
  14. package/dist/ComboBox.module.js +10 -1
  15. package/dist/ComboBox.module.js.map +1 -1
  16. package/dist/DatePicker.main.js +11 -2
  17. package/dist/DatePicker.main.js.map +1 -1
  18. package/dist/DatePicker.mjs +11 -2
  19. package/dist/DatePicker.module.js +11 -2
  20. package/dist/DatePicker.module.js.map +1 -1
  21. package/dist/DragAndDrop.main.js.map +1 -1
  22. package/dist/DragAndDrop.module.js.map +1 -1
  23. package/dist/Popover.main.js +12 -2
  24. package/dist/Popover.main.js.map +1 -1
  25. package/dist/Popover.mjs +13 -3
  26. package/dist/Popover.module.js +13 -3
  27. package/dist/Popover.module.js.map +1 -1
  28. package/dist/RadioGroup.main.js +4 -1
  29. package/dist/RadioGroup.main.js.map +1 -1
  30. package/dist/RadioGroup.mjs +5 -2
  31. package/dist/RadioGroup.module.js +5 -2
  32. package/dist/RadioGroup.module.js.map +1 -1
  33. package/dist/Select.main.js +10 -2
  34. package/dist/Select.main.js.map +1 -1
  35. package/dist/Select.mjs +10 -2
  36. package/dist/Select.module.js +10 -2
  37. package/dist/Select.module.js.map +1 -1
  38. package/dist/Tabs.main.js +2 -1
  39. package/dist/Tabs.main.js.map +1 -1
  40. package/dist/Tabs.mjs +2 -1
  41. package/dist/Tabs.module.js +2 -1
  42. package/dist/Tabs.module.js.map +1 -1
  43. package/dist/Tree.main.js +296 -18
  44. package/dist/Tree.main.js.map +1 -1
  45. package/dist/Tree.mjs +299 -21
  46. package/dist/Tree.module.js +299 -21
  47. package/dist/Tree.module.js.map +1 -1
  48. package/dist/TreeDropTargetDelegate.main.js +213 -0
  49. package/dist/TreeDropTargetDelegate.main.js.map +1 -0
  50. package/dist/TreeDropTargetDelegate.mjs +208 -0
  51. package/dist/TreeDropTargetDelegate.module.js +208 -0
  52. package/dist/TreeDropTargetDelegate.module.js.map +1 -0
  53. package/dist/Virtualizer.main.js +8 -9
  54. package/dist/Virtualizer.main.js.map +1 -1
  55. package/dist/Virtualizer.mjs +9 -10
  56. package/dist/Virtualizer.module.js +9 -10
  57. package/dist/Virtualizer.module.js.map +1 -1
  58. package/dist/main.js.map +1 -1
  59. package/dist/module.js.map +1 -1
  60. package/dist/types.d.ts +23 -6
  61. package/dist/types.d.ts.map +1 -1
  62. package/dist/useDragAndDrop.main.js +2 -2
  63. package/dist/useDragAndDrop.main.js.map +1 -1
  64. package/dist/useDragAndDrop.mjs +2 -2
  65. package/dist/useDragAndDrop.module.js +2 -2
  66. package/dist/useDragAndDrop.module.js.map +1 -1
  67. package/package.json +32 -28
  68. package/src/Checkbox.tsx +2 -2
  69. package/src/Collection.tsx +39 -5
  70. package/src/ComboBox.tsx +5 -1
  71. package/src/DatePicker.tsx +7 -2
  72. package/src/DragAndDrop.tsx +1 -1
  73. package/src/Popover.tsx +21 -5
  74. package/src/RadioGroup.tsx +2 -2
  75. package/src/Select.tsx +6 -2
  76. package/src/Tabs.tsx +2 -1
  77. package/src/Tree.tsx +364 -38
  78. package/src/TreeDropTargetDelegate.ts +304 -0
  79. package/src/Virtualizer.tsx +7 -8
  80. package/src/index.ts +3 -2
  81. package/src/useDragAndDrop.tsx +2 -1
@@ -12,7 +12,7 @@
12
12
  import {CollectionBase, DropTargetDelegate, ItemDropTarget, Key, LayoutDelegate, RefObject} from '@react-types/shared';
13
13
  import {createBranchComponent, useCachedChildren} from '@react-aria/collections';
14
14
  import {Collection as ICollection, Node, SelectionBehavior, SelectionMode, SectionProps as SharedSectionProps} from 'react-stately';
15
- import React, {createContext, ForwardedRef, HTMLAttributes, JSX, ReactElement, ReactNode, useContext, useMemo} from 'react';
15
+ import React, {cloneElement, createContext, ForwardedRef, HTMLAttributes, isValidElement, JSX, ReactElement, ReactNode, useContext, useMemo} from 'react';
16
16
  import {StyleProps} from './utils';
17
17
 
18
18
  export interface CollectionProps<T> extends Omit<CollectionBase<T>, 'children'> {
@@ -164,19 +164,53 @@ function useCollectionRender(
164
164
  return rendered;
165
165
  }
166
166
 
167
- let key = node.key;
168
- let keyAfter = collection.getKeyAfter(key);
169
167
  return (
170
168
  <>
171
- {renderDropIndicator({type: 'item', key, dropPosition: 'before'})}
169
+ {renderDropIndicator({type: 'item', key: node.key, dropPosition: 'before'})}
172
170
  {rendered}
173
- {((keyAfter == null || collection.getItem(keyAfter)?.type !== 'item')) && renderDropIndicator({type: 'item', key, dropPosition: 'after'})}
171
+ {renderAfterDropIndicators(collection, node, renderDropIndicator)}
174
172
  </>
175
173
  );
176
174
  }
177
175
  });
178
176
  }
179
177
 
178
+ export function renderAfterDropIndicators(collection: ICollection<Node<unknown>>, node: Node<unknown>, renderDropIndicator: (target: ItemDropTarget) => ReactNode): ReactNode {
179
+ let key = node.key;
180
+ let keyAfter = collection.getKeyAfter(key);
181
+ let nextItemInFlattenedCollection = keyAfter != null ? collection.getItem(keyAfter) : null;
182
+ while (nextItemInFlattenedCollection != null && nextItemInFlattenedCollection.type !== 'item') {
183
+ keyAfter = collection.getKeyAfter(nextItemInFlattenedCollection.key);
184
+ nextItemInFlattenedCollection = keyAfter != null ? collection.getItem(keyAfter) : null;
185
+ }
186
+
187
+ let nextItemInSameLevel = node.nextKey != null ? collection.getItem(node.nextKey) : null;
188
+ while (nextItemInSameLevel != null && nextItemInSameLevel.type !== 'item') {
189
+ nextItemInSameLevel = nextItemInSameLevel.nextKey != null ? collection.getItem(nextItemInSameLevel.nextKey) : null;
190
+ }
191
+
192
+ // Render one or more "after" drop indicators when the next item in the flattened collection
193
+ // has a smaller level, is not an item, or there are no more items in the collection.
194
+ // Otherwise, the "after" position is equivalent to the next item's "before" position.
195
+ let afterIndicators: ReactNode[] = [];
196
+ if (nextItemInSameLevel == null) {
197
+ let current: Node<unknown> | null = node;
198
+ while (current && (!nextItemInFlattenedCollection || (current.parentKey !== nextItemInFlattenedCollection.parentKey && nextItemInFlattenedCollection.level < current.level))) {
199
+ let indicator = renderDropIndicator({
200
+ type: 'item',
201
+ key: current.key,
202
+ dropPosition: 'after'
203
+ });
204
+ if (isValidElement(indicator)) {
205
+ afterIndicators.push(cloneElement(indicator, {key: `${current.key}-after`}));
206
+ }
207
+ current = current.parentKey != null ? collection.getItem(current.parentKey) : null;
208
+ }
209
+ }
210
+
211
+ return afterIndicators;
212
+ }
213
+
180
214
  export const CollectionRendererContext = createContext<CollectionRenderer>(DefaultCollectionRenderer);
181
215
 
182
216
  type PersistedKeysReturnValue = Set<Key> | null;
package/src/ComboBox.tsx CHANGED
@@ -93,6 +93,9 @@ export const ComboBox = /*#__PURE__*/ (forwardRef as forwardRefType)(function Co
93
93
  );
94
94
  });
95
95
 
96
+ // Contexts to clear inside the popover.
97
+ const CLEAR_CONTEXTS = [LabelContext, ButtonContext, InputContext, GroupContext, TextContext];
98
+
96
99
  interface ComboBoxInnerProps<T extends object> {
97
100
  props: ComboBoxProps<T>,
98
101
  collection: Collection<Node<T>>,
@@ -197,7 +200,8 @@ function ComboBoxInner<T extends object>({props, collection, comboBoxRef: ref}:
197
200
  placement: 'bottom start',
198
201
  isNonModal: true,
199
202
  trigger: 'ComboBox',
200
- style: {'--trigger-width': menuWidth} as React.CSSProperties
203
+ style: {'--trigger-width': menuWidth} as React.CSSProperties,
204
+ clearContexts: CLEAR_CONTEXTS
201
205
  }],
202
206
  [ListBoxContext, {...listBoxProps, ref: listBoxRef}],
203
207
  [ListStateContext, state],
@@ -72,6 +72,9 @@ export const DateRangePickerContext = createContext<ContextValue<DateRangePicker
72
72
  export const DatePickerStateContext = createContext<DatePickerState | null>(null);
73
73
  export const DateRangePickerStateContext = createContext<DateRangePickerState | null>(null);
74
74
 
75
+ // Contexts to clear inside the popover.
76
+ const CLEAR_CONTEXTS = [GroupContext, ButtonContext, LabelContext, TextContext];
77
+
75
78
  /**
76
79
  * A date picker combines a DateField and a Calendar popover to allow users to enter or select a date and time value.
77
80
  */
@@ -148,7 +151,8 @@ export const DatePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(function
148
151
  trigger: 'DatePicker',
149
152
  triggerRef: groupRef,
150
153
  placement: 'bottom start',
151
- style: {'--trigger-width': groupWidth} as React.CSSProperties
154
+ style: {'--trigger-width': groupWidth} as React.CSSProperties,
155
+ clearContexts: CLEAR_CONTEXTS
152
156
  }],
153
157
  [DialogContext, dialogProps],
154
158
  [TextContext, {
@@ -251,7 +255,8 @@ export const DateRangePicker = /*#__PURE__*/ (forwardRef as forwardRefType)(func
251
255
  trigger: 'DateRangePicker',
252
256
  triggerRef: groupRef,
253
257
  placement: 'bottom start',
254
- style: {'--trigger-width': groupWidth} as React.CSSProperties
258
+ style: {'--trigger-width': groupWidth} as React.CSSProperties,
259
+ clearContexts: CLEAR_CONTEXTS
255
260
  }],
256
261
  [DialogContext, dialogProps],
257
262
  [DateFieldContext, {
@@ -32,7 +32,7 @@ export interface DropIndicatorRenderProps {
32
32
  isDropTarget: boolean
33
33
  }
34
34
 
35
- export interface DropIndicatorProps extends AriaDropIndicatorProps, RenderProps<DropIndicatorRenderProps> { }
35
+ export interface DropIndicatorProps extends Omit<AriaDropIndicatorProps, 'activateButtonRef'>, RenderProps<DropIndicatorRenderProps> { }
36
36
  interface DropIndicatorContextValue {
37
37
  render: (props: DropIndicatorProps, ref: ForwardedRef<HTMLElement>) => ReactNode
38
38
  }
package/src/Popover.tsx CHANGED
@@ -18,7 +18,7 @@ import {focusSafely} from '@react-aria/interactions';
18
18
  import {OverlayArrowContext} from './OverlayArrow';
19
19
  import {OverlayTriggerProps, OverlayTriggerState, useOverlayTriggerState} from 'react-stately';
20
20
  import {OverlayTriggerStateContext} from './Dialog';
21
- import React, {createContext, ForwardedRef, forwardRef, useContext, useEffect, useRef, useState} from 'react';
21
+ import React, {Context, createContext, ForwardedRef, forwardRef, useContext, useEffect, useMemo, useRef, useState} from 'react';
22
22
  import {useIsHidden} from '@react-aria/collections';
23
23
 
24
24
  export interface PopoverProps extends Omit<PositionProps, 'isOpen'>, Omit<AriaPopoverProps, 'popoverRef' | 'triggerRef' | 'groupRef' | 'offset' | 'arrowSize'>, OverlayTriggerProps, RenderProps<PopoverRenderProps>, SlotProps, AriaLabelingProps {
@@ -80,7 +80,12 @@ export interface PopoverRenderProps {
80
80
  isExiting: boolean
81
81
  }
82
82
 
83
- export const PopoverContext = createContext<ContextValue<PopoverProps, HTMLElement>>(null);
83
+ interface PopoverContextValue extends PopoverProps {
84
+ /** Contexts to clear. */
85
+ clearContexts?: Context<any>[]
86
+ }
87
+
88
+ export const PopoverContext = createContext<ContextValue<PopoverContextValue, HTMLElement>>(null);
84
89
 
85
90
  // Stores a ref for the portal container for a group of popovers (e.g. submenus).
86
91
  const PopoverGroupContext = createContext<RefObject<Element | null> | null>(null);
@@ -134,10 +139,11 @@ interface PopoverInnerProps extends AriaPopoverProps, RenderProps<PopoverRenderP
134
139
  isExiting: boolean,
135
140
  UNSTABLE_portalContainer?: Element,
136
141
  trigger?: string,
137
- dir?: 'ltr' | 'rtl'
142
+ dir?: 'ltr' | 'rtl',
143
+ clearContexts?: Context<any>[]
138
144
  }
139
145
 
140
- function PopoverInner({state, isExiting, UNSTABLE_portalContainer, ...props}: PopoverInnerProps) {
146
+ function PopoverInner({state, isExiting, UNSTABLE_portalContainer, clearContexts, ...props}: PopoverInnerProps) {
141
147
  // Calculate the arrow size internally (and remove props.arrowSize from PopoverProps)
142
148
  // Referenced from: packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx
143
149
  let arrowRef = useRef<HTMLDivElement>(null);
@@ -190,6 +196,16 @@ function PopoverInner({state, isExiting, UNSTABLE_portalContainer, ...props}: Po
190
196
  }
191
197
  }, [isDialog, ref]);
192
198
 
199
+ let children = useMemo(() => {
200
+ let children = renderProps.children;
201
+ if (clearContexts) {
202
+ for (let Context of clearContexts) {
203
+ children = <Context.Provider value={null}>{children}</Context.Provider>;
204
+ }
205
+ }
206
+ return children;
207
+ }, [renderProps.children, clearContexts]);
208
+
193
209
  let style = {...popoverProps.style, ...renderProps.style};
194
210
  let overlay = (
195
211
  <div
@@ -209,7 +225,7 @@ function PopoverInner({state, isExiting, UNSTABLE_portalContainer, ...props}: Po
209
225
  data-exiting={isExiting || undefined}>
210
226
  {!props.isNonModal && <DismissButton onDismiss={state.close} />}
211
227
  <OverlayArrowContext.Provider value={{...arrowProps, placement, ref: arrowRef}}>
212
- {renderProps.children}
228
+ {children}
213
229
  </OverlayArrowContext.Provider>
214
230
  <DismissButton onDismiss={state.close} />
215
231
  </div>
@@ -18,7 +18,7 @@ import {FormContext} from './Form';
18
18
  import {forwardRefType, RefObject} from '@react-types/shared';
19
19
  import {LabelContext} from './Label';
20
20
  import {RadioGroupState, useRadioGroupState} from 'react-stately';
21
- import React, {createContext, ForwardedRef, forwardRef} from 'react';
21
+ import React, {createContext, ForwardedRef, forwardRef, useMemo} from 'react';
22
22
  import {TextContext} from './Text';
23
23
 
24
24
  export interface RadioGroupProps extends Omit<AriaRadioGroupProps, 'children' | 'label' | 'description' | 'errorMessage' | 'validationState' | 'validationBehavior'>, RACValidation, RenderProps<RadioGroupRenderProps>, SlotProps {}
@@ -186,7 +186,7 @@ export const Radio = /*#__PURE__*/ (forwardRef as forwardRefType)(function Radio
186
186
  } = props;
187
187
  [props, ref] = useContextProps(otherProps, ref, RadioContext);
188
188
  let state = React.useContext(RadioGroupStateContext)!;
189
- let inputRef = useObjectRef(mergeRefs(userProvidedInputRef, props.inputRef !== undefined ? props.inputRef : null));
189
+ let inputRef = useObjectRef(useMemo(() => mergeRefs(userProvidedInputRef, props.inputRef !== undefined ? props.inputRef : null), [userProvidedInputRef, props.inputRef]));
190
190
  let {labelProps, inputProps, isSelected, isDisabled, isPressed} = useRadio({
191
191
  ...removeDataAttributes<RadioProps>(props),
192
192
  // ReactNode type doesn't allow function children.
package/src/Select.tsx CHANGED
@@ -100,6 +100,9 @@ export const Select = /*#__PURE__*/ (forwardRef as forwardRefType)(function Sele
100
100
  );
101
101
  });
102
102
 
103
+ // Contexts to clear inside the popover.
104
+ const CLEAR_CONTEXTS = [LabelContext, ButtonContext, TextContext];
105
+
103
106
  interface SelectInnerProps<T extends object> {
104
107
  props: SelectProps<T>,
105
108
  selectRef: ForwardedRef<HTMLDivElement>,
@@ -178,7 +181,7 @@ function SelectInner<T extends object>({props, selectRef: ref, collection}: Sele
178
181
  [SelectStateContext, state],
179
182
  [SelectValueContext, valueProps],
180
183
  [LabelContext, {...labelProps, ref: labelRef, elementType: 'span'}],
181
- [ButtonContext, {...triggerProps, ref: buttonRef, isPressed: state.isOpen}],
184
+ [ButtonContext, {...triggerProps, ref: buttonRef, isPressed: state.isOpen, autoFocus: props.autoFocus}],
182
185
  [OverlayTriggerStateContext, state],
183
186
  [PopoverContext, {
184
187
  trigger: 'Select',
@@ -186,7 +189,8 @@ function SelectInner<T extends object>({props, selectRef: ref, collection}: Sele
186
189
  scrollRef,
187
190
  placement: 'bottom start',
188
191
  style: {'--trigger-width': buttonWidth} as React.CSSProperties,
189
- 'aria-labelledby': menuProps['aria-labelledby']
192
+ 'aria-labelledby': menuProps['aria-labelledby'],
193
+ clearContexts: CLEAR_CONTEXTS
190
194
  }],
191
195
  [ListBoxContext, {...menuProps, ref: scrollRef}],
192
196
  [ListStateContext, state],
package/src/Tabs.tsx CHANGED
@@ -300,7 +300,8 @@ export const TabPanel = /*#__PURE__*/ createHideableComponent(function TabPanel(
300
300
  values: {
301
301
  isFocused,
302
302
  isFocusVisible,
303
- isInert: !isSelected,
303
+ // @ts-ignore - compatibility with React < 19
304
+ isInert: inertValue(!isSelected),
304
305
  state
305
306
  }
306
307
  });