react-aria-components 1.11.0 → 1.12.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 (108) hide show
  1. package/dist/Autocomplete.main.js +7 -20
  2. package/dist/Autocomplete.main.js.map +1 -1
  3. package/dist/Autocomplete.mjs +8 -20
  4. package/dist/Autocomplete.module.js +8 -20
  5. package/dist/Autocomplete.module.js.map +1 -1
  6. package/dist/Breadcrumbs.main.js +4 -1
  7. package/dist/Breadcrumbs.main.js.map +1 -1
  8. package/dist/Breadcrumbs.mjs +5 -2
  9. package/dist/Breadcrumbs.module.js +5 -2
  10. package/dist/Breadcrumbs.module.js.map +1 -1
  11. package/dist/GridList.main.js +96 -15
  12. package/dist/GridList.main.js.map +1 -1
  13. package/dist/GridList.mjs +98 -19
  14. package/dist/GridList.module.js +98 -19
  15. package/dist/GridList.module.js.map +1 -1
  16. package/dist/Header.main.js +1 -1
  17. package/dist/Header.main.js.map +1 -1
  18. package/dist/Header.mjs +2 -2
  19. package/dist/Header.module.js +2 -2
  20. package/dist/Header.module.js.map +1 -1
  21. package/dist/ListBox.main.js +6 -18
  22. package/dist/ListBox.main.js.map +1 -1
  23. package/dist/ListBox.mjs +8 -20
  24. package/dist/ListBox.module.js +8 -20
  25. package/dist/ListBox.module.js.map +1 -1
  26. package/dist/Menu.main.js +29 -15
  27. package/dist/Menu.main.js.map +1 -1
  28. package/dist/Menu.mjs +31 -17
  29. package/dist/Menu.module.js +31 -17
  30. package/dist/Menu.module.js.map +1 -1
  31. package/dist/Popover.main.js +7 -11
  32. package/dist/Popover.main.js.map +1 -1
  33. package/dist/Popover.mjs +8 -12
  34. package/dist/Popover.module.js +8 -12
  35. package/dist/Popover.module.js.map +1 -1
  36. package/dist/SearchField.main.js +6 -4
  37. package/dist/SearchField.main.js.map +1 -1
  38. package/dist/SearchField.mjs +7 -5
  39. package/dist/SearchField.module.js +7 -5
  40. package/dist/SearchField.module.js.map +1 -1
  41. package/dist/Separator.main.js +13 -1
  42. package/dist/Separator.main.js.map +1 -1
  43. package/dist/Separator.mjs +15 -3
  44. package/dist/Separator.module.js +15 -3
  45. package/dist/Separator.module.js.map +1 -1
  46. package/dist/Table.main.js +58 -17
  47. package/dist/Table.main.js.map +1 -1
  48. package/dist/Table.mjs +60 -19
  49. package/dist/Table.module.js +60 -19
  50. package/dist/Table.module.js.map +1 -1
  51. package/dist/Tabs.main.js +4 -1
  52. package/dist/Tabs.main.js.map +1 -1
  53. package/dist/Tabs.mjs +5 -2
  54. package/dist/Tabs.module.js +5 -2
  55. package/dist/Tabs.module.js.map +1 -1
  56. package/dist/TagGroup.main.js +13 -4
  57. package/dist/TagGroup.main.js.map +1 -1
  58. package/dist/TagGroup.mjs +15 -6
  59. package/dist/TagGroup.module.js +15 -6
  60. package/dist/TagGroup.module.js.map +1 -1
  61. package/dist/TextField.main.js +7 -5
  62. package/dist/TextField.main.js.map +1 -1
  63. package/dist/TextField.mjs +8 -6
  64. package/dist/TextField.module.js +8 -6
  65. package/dist/TextField.module.js.map +1 -1
  66. package/dist/Tooltip.main.js +4 -11
  67. package/dist/Tooltip.main.js.map +1 -1
  68. package/dist/Tooltip.mjs +6 -13
  69. package/dist/Tooltip.module.js +6 -13
  70. package/dist/Tooltip.module.js.map +1 -1
  71. package/dist/Tree.main.js +9 -3
  72. package/dist/Tree.main.js.map +1 -1
  73. package/dist/Tree.mjs +10 -4
  74. package/dist/Tree.module.js +10 -4
  75. package/dist/Tree.module.js.map +1 -1
  76. package/dist/context.main.js +25 -0
  77. package/dist/context.main.js.map +1 -0
  78. package/dist/context.mjs +19 -0
  79. package/dist/context.module.js +19 -0
  80. package/dist/context.module.js.map +1 -0
  81. package/dist/import.mjs +3 -3
  82. package/dist/main.js +3 -0
  83. package/dist/main.js.map +1 -1
  84. package/dist/module.js +3 -3
  85. package/dist/module.js.map +1 -1
  86. package/dist/types.d.ts +178 -171
  87. package/dist/types.d.ts.map +1 -1
  88. package/dist/useDragAndDrop.main.js.map +1 -1
  89. package/dist/useDragAndDrop.module.js.map +1 -1
  90. package/package.json +23 -22
  91. package/src/Autocomplete.tsx +14 -25
  92. package/src/Breadcrumbs.tsx +6 -2
  93. package/src/GridList.tsx +89 -21
  94. package/src/Header.tsx +2 -2
  95. package/src/ListBox.tsx +12 -15
  96. package/src/Menu.tsx +37 -17
  97. package/src/Popover.tsx +11 -11
  98. package/src/SearchField.tsx +5 -4
  99. package/src/Separator.tsx +17 -2
  100. package/src/Table.tsx +65 -22
  101. package/src/Tabs.tsx +6 -2
  102. package/src/TagGroup.tsx +15 -6
  103. package/src/TextField.tsx +8 -7
  104. package/src/Tooltip.tsx +10 -14
  105. package/src/Tree.tsx +13 -5
  106. package/src/context.tsx +34 -0
  107. package/src/index.ts +2 -2
  108. package/src/useDragAndDrop.tsx +9 -9
package/src/Table.tsx CHANGED
@@ -1,15 +1,16 @@
1
1
  import {AriaLabelingProps, GlobalDOMAttributes, HoverEvents, Key, LinkDOMProps, PressEvents, RefObject} from '@react-types/shared';
2
- import {BaseCollection, Collection, CollectionBuilder, CollectionNode, createBranchComponent, createLeafComponent, useCachedChildren} from '@react-aria/collections';
2
+ import {BaseCollection, Collection, CollectionBuilder, CollectionNode, createBranchComponent, createLeafComponent, FilterableNode, LoaderNode, useCachedChildren} from '@react-aria/collections';
3
3
  import {buildHeaderRows, TableColumnResizeState} from '@react-stately/table';
4
4
  import {ButtonContext} from './Button';
5
5
  import {CheckboxContext} from './RSPContexts';
6
6
  import {CollectionProps, CollectionRendererContext, DefaultCollectionRenderer, ItemRenderProps} from './Collection';
7
7
  import {ColumnSize, ColumnStaticSize, TableCollection as ITableCollection, TableProps as SharedTableProps} from '@react-types/table';
8
8
  import {ContextValue, DEFAULT_SLOT, DOMProps, Provider, RenderProps, SlotProps, StyleProps, StyleRenderProps, useContextProps, useRenderProps} from './utils';
9
- import {DisabledBehavior, DraggableCollectionState, DroppableCollectionState, MultipleSelectionState, Node, SelectionBehavior, SelectionMode, SortDirection, TableState, useMultipleSelectionState, useTableColumnResizeState, useTableState} from 'react-stately';
9
+ import {DisabledBehavior, DraggableCollectionState, DroppableCollectionState, MultipleSelectionState, Node, SelectionBehavior, SelectionMode, SortDirection, TableState, UNSTABLE_useFilteredTableState, useMultipleSelectionState, useTableColumnResizeState, useTableState} from 'react-stately';
10
10
  import {DragAndDropContext, DropIndicatorContext, DropIndicatorProps, useDndPersistedKeys, useRenderDropIndicator} from './DragAndDrop';
11
11
  import {DragAndDropHooks} from './useDragAndDrop';
12
12
  import {DraggableItemResult, DragPreviewRenderer, DropIndicatorAria, DroppableCollectionResult, FocusScope, ListKeyboardDelegate, mergeProps, useFocusRing, useHover, useLocale, useLocalizedStringFormatter, useTable, useTableCell, useTableColumnHeader, useTableColumnResize, useTableHeaderRow, useTableRow, useTableRowGroup, useTableSelectAllCheckbox, useTableSelectionCheckbox, useVisuallyHidden} from 'react-aria';
13
+ import {FieldInputContext, SelectableCollectionContext} from './context';
13
14
  import {filterDOMProps, inertValue, isScrollable, LoadMoreSentinelProps, mergeRefs, useLayoutEffect, useLoadMoreSentinel, useObjectRef, useResizeObserver} from '@react-aria/utils';
14
15
  import {GridNode} from '@react-types/grid';
15
16
  // @ts-ignore
@@ -22,8 +23,8 @@ class TableCollection<T> extends BaseCollection<T> implements ITableCollection<T
22
23
  columns: GridNode<T>[] = [];
23
24
  rows: GridNode<T>[] = [];
24
25
  rowHeaderColumnKeys: Set<Key> = new Set();
25
- head: CollectionNode<T> = new CollectionNode('tableheader', -1);
26
- body: CollectionNode<T> = new CollectionNode('tablebody', -2);
26
+ head = new TableHeaderNode<T>(-1);
27
+ body = new TableBodyNode<T>(-2);
27
28
  columnsDirty = true;
28
29
 
29
30
  addNode(node: CollectionNode<T>) {
@@ -65,7 +66,6 @@ class TableCollection<T> extends BaseCollection<T> implements ITableCollection<T
65
66
 
66
67
  this.rowHeaderColumnKeys = new Set();
67
68
  this.columns = [];
68
-
69
69
  let columnKeyMap = new Map();
70
70
  let visit = (node: Node<T>) => {
71
71
  switch (node.type) {
@@ -363,23 +363,30 @@ interface TableInnerProps {
363
363
 
364
364
 
365
365
  function TableInner({props, forwardedRef: ref, selectionState, collection}: TableInnerProps) {
366
+ let contextProps;
367
+ [contextProps] = useContextProps({}, null, SelectableCollectionContext);
368
+ let {filter, ...collectionProps} = contextProps;
369
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
370
+ let {shouldUseVirtualFocus, disallowTypeAhead, ...DOMCollectionProps} = collectionProps || {};
366
371
  let tableContainerContext = useContext(ResizableTableContainerContext);
367
372
  ref = useObjectRef(useMemo(() => mergeRefs(ref, tableContainerContext?.tableRef), [ref, tableContainerContext?.tableRef]));
368
- let state = useTableState({
373
+ let tableState = useTableState({
369
374
  ...props,
370
375
  collection,
371
376
  children: undefined,
372
377
  UNSAFE_selectionState: selectionState
373
378
  });
374
379
 
380
+ let filteredState = UNSTABLE_useFilteredTableState(tableState, filter);
375
381
  let {isVirtualized, layoutDelegate, dropTargetDelegate: ctxDropTargetDelegate, CollectionRoot} = useContext(CollectionRendererContext);
376
382
  let {dragAndDropHooks} = props;
377
383
  let {gridProps} = useTable({
378
384
  ...props,
385
+ ...DOMCollectionProps,
379
386
  layoutDelegate,
380
387
  isVirtualized
381
- }, state, ref);
382
- let selectionManager = state.selectionManager;
388
+ }, filteredState, ref);
389
+ let selectionManager = filteredState.selectionManager;
383
390
  let hasDragHooks = !!dragAndDropHooks?.useDraggableCollectionState;
384
391
  let hasDropHooks = !!dragAndDropHooks?.useDroppableCollectionState;
385
392
  let dragHooksProvided = useRef(hasDragHooks);
@@ -405,7 +412,7 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
405
412
 
406
413
  if (hasDragHooks && dragAndDropHooks) {
407
414
  dragState = dragAndDropHooks.useDraggableCollectionState!({
408
- collection,
415
+ collection: filteredState.collection,
409
416
  selectionManager,
410
417
  preview: dragAndDropHooks.renderDragPreview ? preview : undefined
411
418
  });
@@ -419,12 +426,12 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
419
426
 
420
427
  if (hasDropHooks && dragAndDropHooks) {
421
428
  dropState = dragAndDropHooks.useDroppableCollectionState!({
422
- collection,
429
+ collection: filteredState.collection,
423
430
  selectionManager
424
431
  });
425
432
 
426
433
  let keyboardDelegate = new ListKeyboardDelegate({
427
- collection,
434
+ collection: filteredState.collection,
428
435
  disabledKeys: selectionManager.disabledKeys,
429
436
  disabledBehavior: selectionManager.disabledBehavior,
430
437
  ref,
@@ -448,7 +455,7 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
448
455
  isDropTarget: isRootDropTarget,
449
456
  isFocused,
450
457
  isFocusVisible,
451
- state
458
+ state: filteredState
452
459
  }
453
460
  });
454
461
 
@@ -459,7 +466,7 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
459
466
  if (tableContainerContext) {
460
467
  layoutState = tableContainerContext.useTableColumnResizeState({
461
468
  tableWidth: tableContainerContext.tableWidth
462
- }, state);
469
+ }, filteredState);
463
470
  if (!isVirtualized) {
464
471
  style = {
465
472
  ...style,
@@ -475,10 +482,12 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
475
482
  return (
476
483
  <Provider
477
484
  values={[
478
- [TableStateContext, state],
485
+ [TableStateContext, filteredState],
479
486
  [TableColumnResizeStateContext, layoutState],
480
487
  [DragAndDropContext, {dragAndDropHooks, dragState, dropState}],
481
- [DropIndicatorContext, {render: TableDropIndicatorWrapper}]
488
+ [DropIndicatorContext, {render: TableDropIndicatorWrapper}],
489
+ [SelectableCollectionContext, null],
490
+ [FieldInputContext, null]
482
491
  ]}>
483
492
  <FocusScope>
484
493
  <ElementType
@@ -492,7 +501,7 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
492
501
  data-focused={isFocused || undefined}
493
502
  data-focus-visible={isFocusVisible || undefined}>
494
503
  <CollectionRoot
495
- collection={collection}
504
+ collection={filteredState.collection}
496
505
  scrollRef={tableContainerContext?.scrollRef ?? ref}
497
506
  persistedKeys={useDndPersistedKeys(selectionManager, dragAndDropHooks, dropState)} />
498
507
  </ElementType>
@@ -544,11 +553,15 @@ export interface TableHeaderProps<T> extends StyleRenderProps<TableHeaderRenderP
544
553
  dependencies?: ReadonlyArray<any>
545
554
  }
546
555
 
556
+ class TableHeaderNode<T> extends CollectionNode<T> {
557
+ static readonly type = 'tableheader';
558
+ }
559
+
547
560
  /**
548
561
  * A header within a `<Table>`, containing the table columns.
549
562
  */
550
563
  export const TableHeader = /*#__PURE__*/ createBranchComponent(
551
- 'tableheader',
564
+ TableHeaderNode,
552
565
  <T extends object>(props: TableHeaderProps<T>, ref: ForwardedRef<HTMLTableSectionElement | HTMLDivElement>) => {
553
566
  let collection = useContext(TableStateContext)!.collection as TableCollection<unknown>;
554
567
  let headerRows = useCachedChildren({
@@ -681,10 +694,14 @@ export interface ColumnProps extends RenderProps<ColumnRenderProps>, GlobalDOMAt
681
694
  maxWidth?: ColumnStaticSize | null
682
695
  }
683
696
 
697
+ class TableColumnNode extends CollectionNode<unknown> {
698
+ static readonly type = 'column';
699
+ }
700
+
684
701
  /**
685
702
  * A column within a `<Table>`.
686
703
  */
687
- export const Column = /*#__PURE__*/ createLeafComponent('column', (props: ColumnProps, forwardedRef: ForwardedRef<HTMLTableCellElement | HTMLDivElement>, column: GridNode<unknown>) => {
704
+ export const Column = /*#__PURE__*/ createLeafComponent(TableColumnNode, (props: ColumnProps, forwardedRef: ForwardedRef<HTMLTableCellElement | HTMLDivElement>, column: GridNode<unknown>) => {
688
705
  let ref = useObjectRef<HTMLTableCellElement | HTMLDivElement>(forwardedRef);
689
706
  let state = useContext(TableStateContext)!;
690
707
  let {isVirtualized} = useContext(CollectionRendererContext);
@@ -916,10 +933,15 @@ export interface TableBodyProps<T> extends Omit<CollectionProps<T>, 'disabledKey
916
933
  /** Provides content to display when there are no rows in the table. */
917
934
  renderEmptyState?: (props: TableBodyRenderProps) => ReactNode
918
935
  }
936
+
937
+ class TableBodyNode<T> extends FilterableNode<T> {
938
+ static readonly type = 'tablebody';
939
+ }
940
+
919
941
  /**
920
942
  * The body of a `<Table>`, containing the table rows.
921
943
  */
922
- export const TableBody = /*#__PURE__*/ createBranchComponent('tablebody', <T extends object>(props: TableBodyProps<T>, ref: ForwardedRef<HTMLTableSectionElement | HTMLDivElement>) => {
944
+ export const TableBody = /*#__PURE__*/ createBranchComponent(TableBodyNode, <T extends object>(props: TableBodyProps<T>, ref: ForwardedRef<HTMLTableSectionElement | HTMLDivElement>) => {
923
945
  let state = useContext(TableStateContext)!;
924
946
  let {isVirtualized} = useContext(CollectionRendererContext);
925
947
  let collection = state.collection;
@@ -1017,11 +1039,28 @@ export interface RowProps<T> extends StyleRenderProps<RowRenderProps>, LinkDOMPr
1017
1039
  id?: Key
1018
1040
  }
1019
1041
 
1042
+ class TableRowNode<T> extends CollectionNode<T> {
1043
+ static readonly type = 'item';
1044
+
1045
+ filter(collection: BaseCollection<T>, newCollection: BaseCollection<T>, filterFn: (textValue: string, node: Node<T>) => boolean): TableRowNode<T> | null {
1046
+ let cells = collection.getChildren(this.key);
1047
+ for (let cell of cells) {
1048
+ if (filterFn(cell.textValue, cell)) {
1049
+ let clone = this.clone();
1050
+ newCollection.addDescendants(clone, collection);
1051
+ return clone;
1052
+ }
1053
+ }
1054
+
1055
+ return null;
1056
+ }
1057
+ }
1058
+
1020
1059
  /**
1021
1060
  * A row within a `<Table>`.
1022
1061
  */
1023
1062
  export const Row = /*#__PURE__*/ createBranchComponent(
1024
- 'item',
1063
+ TableRowNode,
1025
1064
  <T extends object>(props: RowProps<T>, forwardedRef: ForwardedRef<HTMLTableRowElement | HTMLDivElement>, item: GridNode<T>) => {
1026
1065
  let ref = useObjectRef<HTMLTableRowElement | HTMLDivElement>(forwardedRef);
1027
1066
  let state = useContext(TableStateContext)!;
@@ -1201,10 +1240,14 @@ export interface CellProps extends RenderProps<CellRenderProps>, GlobalDOMAttrib
1201
1240
  colSpan?: number
1202
1241
  }
1203
1242
 
1243
+ class TableCellNode extends CollectionNode<unknown> {
1244
+ static readonly type = 'cell';
1245
+ }
1246
+
1204
1247
  /**
1205
1248
  * A cell within a table row.
1206
1249
  */
1207
- export const Cell = /*#__PURE__*/ createLeafComponent('cell', (props: CellProps, forwardedRef: ForwardedRef<HTMLTableCellElement | HTMLDivElement>, cell: GridNode<unknown>) => {
1250
+ export const Cell = /*#__PURE__*/ createLeafComponent(TableCellNode, (props: CellProps, forwardedRef: ForwardedRef<HTMLTableCellElement | HTMLDivElement>, cell: GridNode<unknown>) => {
1208
1251
  let ref = useObjectRef<HTMLTableCellElement | HTMLDivElement>(forwardedRef);
1209
1252
  let state = useContext(TableStateContext)!;
1210
1253
  let {dragState} = useContext(DragAndDropContext);
@@ -1359,7 +1402,7 @@ export interface TableLoadMoreItemProps extends Omit<LoadMoreSentinelProps, 'col
1359
1402
  isLoading?: boolean
1360
1403
  }
1361
1404
 
1362
- export const TableLoadMoreItem = createLeafComponent('loader', function TableLoadingIndicator(props: TableLoadMoreItemProps, ref: ForwardedRef<HTMLTableRowElement>, item: Node<object>) {
1405
+ export const TableLoadMoreItem = createLeafComponent(LoaderNode, function TableLoadingIndicator(props: TableLoadMoreItemProps, ref: ForwardedRef<HTMLTableRowElement>, item: Node<object>) {
1363
1406
  let state = useContext(TableStateContext)!;
1364
1407
  let {isVirtualized} = useContext(CollectionRendererContext);
1365
1408
  let {isLoading, onLoadMore, scrollOffset, ...otherProps} = props;
package/src/Tabs.tsx CHANGED
@@ -12,7 +12,7 @@
12
12
 
13
13
  import {AriaLabelingProps, forwardRefType, GlobalDOMAttributes, HoverEvents, Key, LinkDOMProps, PressEvents, RefObject} from '@react-types/shared';
14
14
  import {AriaTabListProps, AriaTabPanelProps, mergeProps, Orientation, useFocusRing, useHover, useTab, useTabList, useTabPanel} from 'react-aria';
15
- import {Collection, CollectionBuilder, createHideableComponent, createLeafComponent} from '@react-aria/collections';
15
+ import {Collection, CollectionBuilder, CollectionNode, 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
18
  import {filterDOMProps, inertValue, useObjectRef} from '@react-aria/utils';
@@ -235,10 +235,14 @@ function TabListInner<T extends object>({props, forwardedRef: ref}: TabListInner
235
235
  );
236
236
  }
237
237
 
238
+ class TabItemNode extends CollectionNode<unknown> {
239
+ static readonly type = 'item';
240
+ }
241
+
238
242
  /**
239
243
  * A Tab provides a title for an individual item within a TabList.
240
244
  */
241
- export const Tab = /*#__PURE__*/ createLeafComponent('item', (props: TabProps, forwardedRef: ForwardedRef<HTMLDivElement>, item: Node<unknown>) => {
245
+ export const Tab = /*#__PURE__*/ createLeafComponent(TabItemNode, (props: TabProps, forwardedRef: ForwardedRef<HTMLDivElement>, item: Node<unknown>) => {
242
246
  let state = useContext(TabListStateContext)!;
243
247
  let ref = useObjectRef<any>(forwardedRef);
244
248
  let {tabProps, isSelected, isDisabled, isPressed} = useTab({key: item.key, ...props}, state, ref);
package/src/TagGroup.tsx CHANGED
@@ -12,15 +12,16 @@
12
12
 
13
13
  import {AriaTagGroupProps, useFocusRing, useHover, useTag, useTagGroup} from 'react-aria';
14
14
  import {ButtonContext} from './Button';
15
- import {Collection, CollectionBuilder, createLeafComponent} from '@react-aria/collections';
15
+ import {Collection, CollectionBuilder, createLeafComponent, ItemNode} from '@react-aria/collections';
16
16
  import {CollectionProps, CollectionRendererContext, DefaultCollectionRenderer, ItemRenderProps, usePersistedKeys} from './Collection';
17
17
  import {ContextValue, DOMProps, Provider, RenderProps, SlotProps, StyleRenderProps, useContextProps, useRenderProps, useSlot} from './utils';
18
18
  import {filterDOMProps, mergeProps, useObjectRef} from '@react-aria/utils';
19
19
  import {forwardRefType, GlobalDOMAttributes, HoverEvents, Key, LinkDOMProps, PressEvents} from '@react-types/shared';
20
20
  import {LabelContext} from './Label';
21
- import {ListState, Node, useListState} from 'react-stately';
21
+ import {ListState, Node, UNSTABLE_useFilteredListState, useListState} from 'react-stately';
22
22
  import {ListStateContext} from './ListBox';
23
23
  import React, {createContext, ForwardedRef, forwardRef, JSX, ReactNode, useContext, useEffect, useRef} from 'react';
24
+ import {SelectableCollectionContext} from './context';
24
25
  import {TextContext} from './Text';
25
26
 
26
27
  export interface TagGroupProps extends Omit<AriaTagGroupProps<unknown>, 'children' | 'items' | 'label' | 'description' | 'errorMessage' | 'keyboardDelegate'>, DOMProps, SlotProps, GlobalDOMAttributes<HTMLDivElement> {}
@@ -74,16 +75,23 @@ interface TagGroupInnerProps {
74
75
  }
75
76
 
76
77
  function TagGroupInner({props, forwardedRef: ref, collection}: TagGroupInnerProps) {
78
+ let contextProps;
79
+ [contextProps] = useContextProps({}, null, SelectableCollectionContext);
80
+ let {filter, ...collectionProps} = contextProps;
81
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
82
+ let {shouldUseVirtualFocus, disallowTypeAhead, ...DOMCollectionProps} = collectionProps || {};
77
83
  let tagListRef = useRef<HTMLDivElement>(null);
78
84
  let [labelRef, label] = useSlot(
79
85
  !props['aria-label'] && !props['aria-labelledby']
80
86
  );
81
- let state = useListState({
87
+ let tagGroupState = useListState({
82
88
  ...props,
83
89
  children: undefined,
84
90
  collection
85
91
  });
86
92
 
93
+ let filteredState = UNSTABLE_useFilteredListState(tagGroupState, filter);
94
+
87
95
  // Prevent DOM props from going to two places.
88
96
  let domProps = filterDOMProps(props, {global: true});
89
97
  let domPropOverrides = Object.fromEntries(Object.entries(domProps).map(([k]) => [k, undefined]));
@@ -95,8 +103,9 @@ function TagGroupInner({props, forwardedRef: ref, collection}: TagGroupInnerProp
95
103
  } = useTagGroup({
96
104
  ...props,
97
105
  ...domPropOverrides,
106
+ ...DOMCollectionProps,
98
107
  label
99
- }, state, tagListRef);
108
+ }, filteredState, tagListRef);
100
109
 
101
110
  return (
102
111
  <div
@@ -109,7 +118,7 @@ function TagGroupInner({props, forwardedRef: ref, collection}: TagGroupInnerProp
109
118
  values={[
110
119
  [LabelContext, {...labelProps, elementType: 'span', ref: labelRef}],
111
120
  [TagListContext, {...gridProps, ref: tagListRef}],
112
- [ListStateContext, state],
121
+ [ListStateContext, filteredState],
113
122
  [TextContext, {
114
123
  slots: {
115
124
  description: descriptionProps,
@@ -197,7 +206,7 @@ export interface TagProps extends RenderProps<TagRenderProps>, LinkDOMProps, Hov
197
206
  /**
198
207
  * A Tag is an individual item within a TagList.
199
208
  */
200
- export const Tag = /*#__PURE__*/ createLeafComponent('item', (props: TagProps, forwardedRef: ForwardedRef<HTMLDivElement>, item: Node<unknown>) => {
209
+ export const Tag = /*#__PURE__*/ createLeafComponent(ItemNode, (props: TagProps, forwardedRef: ForwardedRef<HTMLDivElement>, item: Node<unknown>) => {
201
210
  let state = useContext(ListStateContext)!;
202
211
  let ref = useObjectRef<HTMLDivElement>(forwardedRef);
203
212
  let {focusProps, isFocusVisible} = useFocusRing({within: false});
package/src/TextField.tsx CHANGED
@@ -14,7 +14,8 @@ import {AriaTextFieldProps, useTextField} from 'react-aria';
14
14
  import {ContextValue, DOMProps, Provider, RACValidation, removeDataAttributes, RenderProps, SlotProps, useContextProps, useRenderProps, useSlot, useSlottedContext} from './utils';
15
15
  import {createHideableComponent} from '@react-aria/collections';
16
16
  import {FieldErrorContext} from './FieldError';
17
- import {filterDOMProps, mergeProps} from '@react-aria/utils';
17
+ import {FieldInputContext} from './context';
18
+ import {filterDOMProps} from '@react-aria/utils';
18
19
  import {FormContext} from './Form';
19
20
  import {GlobalDOMAttributes} from '@react-types/shared';
20
21
  import {GroupContext} from './Group';
@@ -61,8 +62,8 @@ export const TextField = /*#__PURE__*/ createHideableComponent(function TextFiel
61
62
  [props, ref] = useContextProps(props, ref, TextFieldContext);
62
63
  let {validationBehavior: formValidationBehavior} = useSlottedContext(FormContext) || {};
63
64
  let validationBehavior = props.validationBehavior ?? formValidationBehavior ?? 'native';
64
- let inputRef = useRef(null);
65
- let [inputContextProps, mergedInputRef] = useContextProps({}, inputRef, InputContext);
65
+ let inputRef = useRef<HTMLInputElement>(null);
66
+ [props, inputRef as unknown] = useContextProps(props, inputRef, FieldInputContext);
66
67
  let [labelRef, label] = useSlot(
67
68
  !props['aria-label'] && !props['aria-labelledby']
68
69
  );
@@ -72,16 +73,16 @@ export const TextField = /*#__PURE__*/ createHideableComponent(function TextFiel
72
73
  inputElementType,
73
74
  label,
74
75
  validationBehavior
75
- }, mergedInputRef);
76
+ }, inputRef);
76
77
 
77
78
  // Intercept setting the input ref so we can determine what kind of element we have.
78
79
  // useTextField uses this to determine what props to include.
79
80
  let inputOrTextAreaRef = useCallback((el) => {
80
- mergedInputRef.current = el;
81
+ inputRef.current = el;
81
82
  if (el) {
82
83
  setInputElementType(el instanceof HTMLTextAreaElement ? 'textarea' : 'input');
83
84
  }
84
- }, [mergedInputRef]);
85
+ }, [inputRef]);
85
86
 
86
87
  let renderProps = useRenderProps({
87
88
  ...props,
@@ -110,7 +111,7 @@ export const TextField = /*#__PURE__*/ createHideableComponent(function TextFiel
110
111
  <Provider
111
112
  values={[
112
113
  [LabelContext, {...labelProps, ref: labelRef}],
113
- [InputContext, {...mergeProps(inputProps, inputContextProps), ref: inputOrTextAreaRef}],
114
+ [InputContext, {...inputProps, ref: inputOrTextAreaRef}],
114
115
  [TextAreaContext, {...inputProps, ref: inputOrTextAreaRef}],
115
116
  [GroupContext, {role: 'presentation', isInvalid: validation.isInvalid, isDisabled: props.isDisabled || false}],
116
117
  [TextContext, {
package/src/Tooltip.tsx CHANGED
@@ -13,11 +13,11 @@
13
13
  import {AriaLabelingProps, FocusableElement, forwardRefType, GlobalDOMAttributes, RefObject} from '@react-types/shared';
14
14
  import {AriaPositionProps, mergeProps, OverlayContainer, Placement, PlacementAxis, PositionProps, useOverlayPosition, useTooltip, useTooltipTrigger} from 'react-aria';
15
15
  import {ContextValue, Provider, RenderProps, useContextProps, useRenderProps} from './utils';
16
- import {filterDOMProps, useEnterAnimation, useExitAnimation, useLayoutEffect} from '@react-aria/utils';
16
+ import {filterDOMProps, useEnterAnimation, useExitAnimation} from '@react-aria/utils';
17
17
  import {FocusableProvider} from '@react-aria/focus';
18
18
  import {OverlayArrowContext} from './OverlayArrow';
19
19
  import {OverlayTriggerProps, TooltipTriggerProps, TooltipTriggerState, useTooltipTriggerState} from 'react-stately';
20
- import React, {createContext, ForwardedRef, forwardRef, JSX, ReactNode, useContext, useRef, useState} from 'react';
20
+ import React, {createContext, CSSProperties, ForwardedRef, forwardRef, JSX, ReactNode, useContext, useRef} from 'react';
21
21
 
22
22
  export interface TooltipTriggerComponentProps extends TooltipTriggerProps {
23
23
  children: ReactNode
@@ -121,27 +121,19 @@ export const Tooltip = /*#__PURE__*/ (forwardRef as forwardRefType)(function Too
121
121
 
122
122
  function TooltipInner(props: TooltipProps & {isExiting: boolean, tooltipRef: RefObject<HTMLDivElement | null>}) {
123
123
  let state = useContext(TooltipTriggerStateContext)!;
124
-
125
- // Calculate the arrow size internally
126
- // Referenced from: packages/@react-spectrum/tooltip/src/TooltipTrigger.tsx
127
124
  let arrowRef = useRef<HTMLDivElement>(null);
128
- let [arrowWidth, setArrowWidth] = useState(0);
129
- useLayoutEffect(() => {
130
- if (arrowRef.current && state.isOpen) {
131
- setArrowWidth(arrowRef.current.getBoundingClientRect().width);
132
- }
133
- }, [state.isOpen, arrowRef]);
134
125
 
135
- let {overlayProps, arrowProps, placement} = useOverlayPosition({
126
+ let {overlayProps, arrowProps, placement, triggerAnchorPoint} = useOverlayPosition({
136
127
  placement: props.placement || 'top',
137
128
  targetRef: props.triggerRef!,
138
129
  overlayRef: props.tooltipRef,
130
+ arrowRef,
139
131
  offset: props.offset,
140
132
  crossOffset: props.crossOffset,
141
133
  isOpen: state.isOpen,
142
- arrowSize: arrowWidth,
143
134
  arrowBoundaryOffset: props.arrowBoundaryOffset,
144
135
  shouldFlip: props.shouldFlip,
136
+ containerPadding: props.containerPadding,
145
137
  onClose: () => state.close(true)
146
138
  });
147
139
 
@@ -166,7 +158,11 @@ function TooltipInner(props: TooltipProps & {isExiting: boolean, tooltipRef: Ref
166
158
  <div
167
159
  {...mergeProps(DOMProps, renderProps, tooltipProps)}
168
160
  ref={props.tooltipRef}
169
- style={{...overlayProps.style, ...renderProps.style}}
161
+ style={{
162
+ ...overlayProps.style,
163
+ '--trigger-anchor-point': triggerAnchorPoint ? `${triggerAnchorPoint.x}px ${triggerAnchorPoint.y}px` : undefined,
164
+ ...renderProps.style
165
+ } as CSSProperties}
170
166
  data-placement={placement ?? undefined}
171
167
  data-entering={isEntering || undefined}
172
168
  data-exiting={props.isExiting || undefined}>
package/src/Tree.tsx CHANGED
@@ -13,7 +13,7 @@
13
13
  import {AriaTreeItemOptions, AriaTreeProps, DraggableItemResult, DropIndicatorAria, DropIndicatorProps, DroppableCollectionResult, FocusScope, ListKeyboardDelegate, mergeProps, useCollator, useFocusRing, useGridListSelectionCheckbox, useHover, useId, useLocale, useTree, useTreeItem, useVisuallyHidden} from 'react-aria';
14
14
  import {ButtonContext} from './Button';
15
15
  import {CheckboxContext} from './RSPContexts';
16
- import {Collection, CollectionBuilder, CollectionNode, createBranchComponent, createLeafComponent, useCachedChildren} from '@react-aria/collections';
16
+ import {Collection, CollectionBuilder, CollectionNode, createBranchComponent, createLeafComponent, LoaderNode, useCachedChildren} from '@react-aria/collections';
17
17
  import {CollectionProps, CollectionRendererContext, DefaultCollectionRenderer, ItemRenderProps} from './Collection';
18
18
  import {ContextValue, DEFAULT_SLOT, Provider, RenderProps, SlotProps, StyleRenderProps, useContextProps, useRenderProps} from './utils';
19
19
  import {DisabledBehavior, DragPreviewRenderer, Expandable, forwardRefType, GlobalDOMAttributes, HoverEvents, Key, LinkDOMProps, MultipleSelection, PressEvents, RefObject, SelectionMode} from '@react-types/shared';
@@ -148,7 +148,7 @@ export interface TreeProps<T> extends Omit<AriaTreeProps<T>, 'children'>, Multip
148
148
  */
149
149
  disabledBehavior?: DisabledBehavior,
150
150
  /** The drag and drop hooks returned by `useDragAndDrop` used to enable drag and drop behavior for the Tree. */
151
- dragAndDropHooks?: DragAndDropHooks
151
+ dragAndDropHooks?: DragAndDropHooks<NoInfer<T>>
152
152
  }
153
153
 
154
154
 
@@ -448,7 +448,11 @@ export interface TreeItemContentRenderProps extends TreeItemRenderProps {}
448
448
  // 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
449
449
  export interface TreeItemContentProps extends Pick<RenderProps<TreeItemContentRenderProps>, 'children'> {}
450
450
 
451
- export const TreeItemContent = /*#__PURE__*/ createLeafComponent('content', function TreeItemContent(props: TreeItemContentProps) {
451
+ class TreeContentNode extends CollectionNode<any> {
452
+ static readonly type = 'content';
453
+ }
454
+
455
+ export const TreeItemContent = /*#__PURE__*/ createLeafComponent(TreeContentNode, function TreeItemContent(props: TreeItemContentProps) {
452
456
  let values = useContext(TreeItemContentContext)!;
453
457
  let renderProps = useRenderProps({
454
458
  children: props.children,
@@ -483,10 +487,14 @@ export interface TreeItemProps<T = object> extends StyleRenderProps<TreeItemRend
483
487
  onAction?: () => void
484
488
  }
485
489
 
490
+ class TreeItemNode extends CollectionNode<any> {
491
+ static readonly type = 'item';
492
+ }
493
+
486
494
  /**
487
495
  * A TreeItem represents an individual item in a Tree.
488
496
  */
489
- export const TreeItem = /*#__PURE__*/ createBranchComponent('item', <T extends object>(props: TreeItemProps<T>, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) => {
497
+ export const TreeItem = /*#__PURE__*/ createBranchComponent(TreeItemNode, <T extends object>(props: TreeItemProps<T>, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) => {
490
498
  let state = useContext(TreeStateContext)!;
491
499
  ref = useObjectRef<HTMLDivElement>(ref);
492
500
  let {dragAndDropHooks, dragState, dropState} = useContext(DragAndDropContext)!;
@@ -719,7 +727,7 @@ export interface TreeLoadMoreItemProps extends Omit<LoadMoreSentinelProps, 'coll
719
727
  isLoading?: boolean
720
728
  }
721
729
 
722
- export const TreeLoadMoreItem = createLeafComponent('loader', function TreeLoadingSentinel<T extends object>(props: TreeLoadMoreItemProps, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) {
730
+ export const TreeLoadMoreItem = createLeafComponent(LoaderNode, function TreeLoadingSentinel<T extends object>(props: TreeLoadMoreItemProps, ref: ForwardedRef<HTMLDivElement>, item: Node<T>) {
723
731
  let {isVirtualized} = useContext(CollectionRendererContext);
724
732
  let state = useContext(TreeStateContext)!;
725
733
  let {isLoading, onLoadMore, scrollOffset, ...otherProps} = props;
@@ -0,0 +1,34 @@
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 {AriaLabelingProps, DOMProps, FocusableElement, FocusEvents, KeyboardEvents, Node, ValueBase} from '@react-types/shared';
14
+ import {AriaTextFieldProps} from '@react-aria/textfield';
15
+ import {ContextValue} from './utils';
16
+ import {createContext} from 'react';
17
+
18
+ export interface SelectableCollectionContextValue<T> extends DOMProps, AriaLabelingProps {
19
+ filter?: (nodeTextValue: string, node: Node<T>) => boolean,
20
+ /** Whether the collection items should use virtual focus instead of being focused directly. */
21
+ shouldUseVirtualFocus?: boolean,
22
+ /** Whether typeahead is disabled. */
23
+ disallowTypeAhead?: boolean
24
+ }
25
+
26
+ interface FieldInputContextValue<T = FocusableElement> extends
27
+ DOMProps,
28
+ FocusEvents<T>,
29
+ KeyboardEvents,
30
+ Pick<ValueBase<string>, 'onChange' | 'value'>,
31
+ Pick<AriaTextFieldProps, 'enterKeyHint' | 'aria-controls' | 'aria-autocomplete' | 'aria-activedescendant' | 'spellCheck' | 'autoCorrect' | 'autoComplete'> {}
32
+
33
+ export const SelectableCollectionContext = createContext<ContextValue<SelectableCollectionContextValue<any>, HTMLElement>>(null);
34
+ export const FieldInputContext = createContext<ContextValue<FieldInputContextValue, FocusableElement>>(null);
package/src/index.ts CHANGED
@@ -39,7 +39,7 @@ export {DropZone, DropZoneContext} from './DropZone';
39
39
  export {FieldError, FieldErrorContext} from './FieldError';
40
40
  export {FileTrigger} from './FileTrigger';
41
41
  export {Form, FormContext} from './Form';
42
- export {GridListLoadMoreItem, GridList, GridListItem, GridListContext} from './GridList';
42
+ export {GridListLoadMoreItem, GridList, GridListItem, GridListContext, GridListHeader, GridListSection} from './GridList';
43
43
  export {Group, GroupContext} from './Group';
44
44
  export {Header, HeaderContext} from './Header';
45
45
  export {Heading} from './Heading';
@@ -79,7 +79,7 @@ export {TreeLoadMoreItem, Tree, TreeItem, TreeContext, TreeItemContent, TreeStat
79
79
  export {useDragAndDrop} from './useDragAndDrop';
80
80
  export {DropIndicator, DropIndicatorContext, DragAndDropContext} from './DragAndDrop';
81
81
  export {Virtualizer} from './Virtualizer';
82
- export {DIRECTORY_DRAG_TYPE, isDirectoryDropItem, isFileDropItem, isTextDropItem, SSRProvider, RouterProvider, I18nProvider, useLocale, useFilter, Pressable, Focusable} from 'react-aria';
82
+ export {DIRECTORY_DRAG_TYPE, isDirectoryDropItem, isFileDropItem, isTextDropItem, SSRProvider, RouterProvider, I18nProvider, useLocale, useFilter, Pressable, Focusable, VisuallyHidden} from 'react-aria';
83
83
  export {FormValidationContext, parseColor, getColorChannels, ToastQueue as UNSTABLE_ToastQueue} from 'react-stately';
84
84
  export {ListLayout, GridLayout, WaterfallLayout} from '@react-stately/layout';
85
85
  export {Layout, LayoutInfo, Size, Rect, Point} from '@react-stately/virtualizer';
@@ -43,10 +43,10 @@ import {
43
43
  import {isVirtualDragging} from '@react-aria/dnd';
44
44
  import {JSX, useMemo} from 'react';
45
45
 
46
- interface DraggableCollectionStateOpts extends Omit<DraggableCollectionStateOptions, 'getItems'> {}
46
+ interface DraggableCollectionStateOpts<T = object> extends Omit<DraggableCollectionStateOptions<T>, 'getItems'> {}
47
47
 
48
- interface DragHooks {
49
- useDraggableCollectionState?: (props: DraggableCollectionStateOpts) => DraggableCollectionState,
48
+ interface DragHooks<T = object> {
49
+ useDraggableCollectionState?: (props: DraggableCollectionStateOpts<T>) => DraggableCollectionState,
50
50
  useDraggableCollection?: (props: DraggableCollectionOptions, state: DraggableCollectionState, ref: RefObject<HTMLElement | null>) => void,
51
51
  useDraggableItem?: (props: DraggableItemProps, state: DraggableCollectionState) => DraggableItemResult,
52
52
  DragPreview?: typeof DragPreview,
@@ -64,19 +64,19 @@ interface DropHooks {
64
64
  ListDropTargetDelegate: typeof ListDropTargetDelegate
65
65
  }
66
66
 
67
- export type DragAndDropHooks = DragHooks & DropHooks
67
+ export type DragAndDropHooks<T = object> = DragHooks<T> & DropHooks
68
68
 
69
- export interface DragAndDrop {
69
+ export interface DragAndDrop<T = object> {
70
70
  /** Drag and drop hooks for the collection element. */
71
- dragAndDropHooks: DragAndDropHooks
71
+ dragAndDropHooks: DragAndDropHooks<T>
72
72
  }
73
73
 
74
- export interface DragAndDropOptions extends Omit<DraggableCollectionProps, 'preview' | 'getItems'>, DroppableCollectionProps {
74
+ export interface DragAndDropOptions<T = object> extends Omit<DraggableCollectionProps, 'preview' | 'getItems'>, DroppableCollectionProps {
75
75
  /**
76
76
  * A function that returns the items being dragged. If not specified, we assume that the collection is not draggable.
77
77
  * @default () => []
78
78
  */
79
- getItems?: (keys: Set<Key>) => DragItem[],
79
+ getItems?: (keys: Set<Key>, items: T[]) => DragItem[],
80
80
  /**
81
81
  * A function that renders a drag preview, which is shown under the user's cursor while dragging.
82
82
  * By default, a copy of the dragged element is rendered.
@@ -97,7 +97,7 @@ export interface DragAndDropOptions extends Omit<DraggableCollectionProps, 'prev
97
97
  /**
98
98
  * Provides the hooks required to enable drag and drop behavior for a drag and drop compatible collection component.
99
99
  */
100
- export function useDragAndDrop(options: DragAndDropOptions): DragAndDrop {
100
+ export function useDragAndDrop<T = object>(options: DragAndDropOptions<T>): DragAndDrop<T> {
101
101
  let dragAndDropHooks = useMemo(() => {
102
102
  let {
103
103
  onDrop,