Skip to content

feat: TextFields in GridList and Grid #8691

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

Conversation

snowystinger
Copy link
Member

@snowystinger snowystinger commented Aug 8, 2025

Closes RSP Component Milestones (view)

This uses the approach of only handling events on grid/row/cells and not on their contents.
Note: this does not address the event leaking brought up in another issue. That work is still to come and may make this unnecessary, however, that touches a much wider set of components and hooks with much more testing needed.
The approach in this PR allows us to more quickly get TextFields working in our grids, and we'll be able to write tests against it which can further inform our other work.

Adding more tests monday

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

Added two stories, one for RAC GridList and one for S2 TableView which shows a textfield inside an item. You must use tab keyboard navigation on the grids in order to get to the field.
Notes: If typing in the inputs, selection should not occur, nor should type ahead.

I did not apply any logic in the TableView to remember the textfield contents, so when reused, they may display the contents of a previous cell.

🧢 Your Project:

Comment on lines +66 to +68
if (keyboardNavigationBehavior === 'tab') {
focusMode = 'cell';
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a hard override? IIRC, my impl had

focusMode ??= keyboardNavigation === 'tab' ? 'cell' : 'child';

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a good point, hadn't thought this through yet

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to think of the mixed use case, I was thinking maybe for the selection column in a table. But it's a little weird to mix the navigation styles, feels a little inconsistent even if i don't like the way the selection column ends up looking in React Spectrum. What was your reason for doing it not as a hard override?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imagine a cell with a text field and "save" button. When pressing on the cell, wouldn't you want to have the textfield focused for convenience?

if (keyboardNavigationBehavior === 'tab' && e.target !== ref.current) {
return;
}

let walker = getFocusableTreeWalker(ref.current);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should only walk tabbable, right? Same in L78.

We need to add tests for disabled interactive content 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for cell level navigation, not inside the cell. In keyboardNavigationBehavior = tab, we've already exited if we were inside the cell, skipping this code. I think it is correct as it is, but maybe an example would be helpful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a test for disabled interactive content

Copy link
Contributor

@nwidynski nwidynski Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this isn't related to edit, IIRC they were bugs I fixed while working on it. L78 is basically the focus strategy of the cell, which should honor whether a child is tabbable. L123 is for keyboardNavigationBehavior=arrow movement inside the cell, which also does not respect tabbable at the moment.

@@ -90,7 +96,8 @@ export function useGrid<T>(props: GridProps, state: GridState<T, GridCollection<
onRowAction,
onCellAction,
escapeKeyBehavior = 'clearSelection',
shouldSelectOnPressUp
shouldSelectOnPressUp,
keyboardNavigationBehavior = 'arrow'
Copy link
Contributor

@nwidynski nwidynski Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the insights while working on this was that "edit mode", when handling events in the scroll container, was pretty much just keyboardNavigationBehavior="tab" applied conditionally.

Raising here because I think it could make sense to lift this prop into grid state instead of forwarding via props, which could replace state.isKeyboardNavigationDisabled of table and grid.

For impl, see useGridEditState & useGridState

Copy link
Member Author

@snowystinger snowystinger Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: started playing around with resizable table columns, I'm definitely going to need to think more about this

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify in your changes how this decided a cell was editable? I don't think I'm following that right.

I implemented an extended SelectionManager for the editable grid, called a GridManager. You can checkout the impl here. TLDR; isEditable was set as a node prop on either column or cell.

@@ -113,6 +116,10 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
return;
}

if (keyboardNavigationBehavior === 'tab' && e.target !== ref.current) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L115: I think state.isKeyboardNavigationBehaviorDisabled shouldn't interfere with editing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, I don't follow your concern here, both are possible conditions for leaving this event handler early?

Copy link
Contributor

@nwidynski nwidynski Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, you are correct. I had removed this condition for the W3C focus wrapping feature.

See here for impl.

Comment on lines +285 to +287
if (!isFocusVisible()) {
state.selectionManager.setFocusedKey(node.key);
}
Copy link
Contributor

@nwidynski nwidynski Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just flagging that this is still missing a fix to maintain a consistent tab sequence. Re-entering the collection from the bottom after exiting may cause focus to land on the item instead of the field. Same goes for the cell.onFocus().

For impl, see here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I suspect this is related to #8686 as well
Thanks for the extra info, really appreciated. I'll make it much easier to determine if we tackle it in this PR as well.

@rspbot
Copy link

rspbot commented Aug 12, 2025

@rspbot
Copy link

rspbot commented Aug 12, 2025

@rspbot
Copy link

rspbot commented Aug 12, 2025

@rspbot
Copy link

rspbot commented Aug 12, 2025

@rspbot
Copy link

rspbot commented Aug 12, 2025

@@ -123,8 +130,45 @@ export function useGrid<T>(props: GridProps, state: GridState<T, GridCollection<
escapeKeyBehavior
});


let originalOnKeyDown = collectionProps.onKeyDown;
let onKeyDown = useCallback((e: BaseEvent<KeyboardEvent<any>>) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow what these event handlers are doing. Why the special cases? Seems quite specific to our implementation

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to avoid passing keyboardNavigationBehavior to useSelectableCollection
I couldn't necessarily pass it to the GridKeyboardDelegate either since that can be passed in, but that was another thought I had.

I know this won't be the final logic for the PR, but it serves as a starting point since I'm unsure what we want to do here. So this shows where there are problematic event handlers.

@nwidynski had this suggestion #8691 (comment)

But there are a few ways we could approach this.

The problematic behaviours that this is blocking are:
useSelectableCollection encompasses type select, which is capturing, and moving focus out of the collection on bubble phase tab.

@@ -171,7 +178,7 @@ export function useGridCell<T, C extends GridCollection<T>>(props: GridCellProps
? walker.previousNode() as FocusableElement
: walker.nextNode() as FocusableElement;

if (focusMode === 'child' && focusable === ref.current) {
if ((focusMode === 'child' && focusable === ref.current) || (keyboardNavigationBehavior === 'tab')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will never happen because of the early return above right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It happens if you are focused on the cell, the early return above is only for events inside the cell

@@ -135,6 +135,10 @@ export function useGridListItem<T>(props: AriaGridListItemOptions, state: ListSt
return;
}

if (keyboardNavigationBehavior === 'tab' && e.target !== ref.current) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's some logic below that previously ran on arrowup/arrowdown with keyboardNavigationBehavior = tab. Noticed in CardView you can no longer press up/down to move to the next card when focused on an action menu.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I allow those through, it'll conflict with cursor positioning in textfields. I think we'll have to solve event leaks to have that not collide. We'll also need to make it non-capturing.

originalOnKeyDown?.(e);
};

// Prevent clicking on a focusable element from selecting the row.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one and the one above seem like they should be handled by the event leaks - i.e. stopping propagation within the component that handles the press.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, these would go away, but this pr isn't fixing event leaks, see description

Note: this does not address the event leaking brought up in another issue. That work is still to come and may make this unnecessary, however, that touches a much wider set of components and hooks with much more testing needed.

I'm working on event leaks in another local branch at the moment, but it has some interesting issues to solve still.

@@ -144,6 +146,38 @@ export function useGridList<T>(props: AriaGridListOptions<T>, state: ListState<T
escapeKeyBehavior
});

let originalOnKeyDown = listProps.onKeyDown;
let onKeyDown = useCallback((e: BaseEvent<KeyboardEvent<any>>) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

</TableHeader>
<TableBody items={manyRows}>
{item => (
<Row id={item.id} columns={manyColumns}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why so many rows and columns? We should try to make a realistic example

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's funny, I've actually seen a screenshot of one which looked much like this (though only one textfield to a cell, but i wanted more for testing)
But I'm happy to change it to something a little more real life looking.

* via the left/right arrow keys or the tab key.
* @default 'arrow'
*/
keyboardNavigationBehavior?: 'arrow' | 'tab'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this API should be at the cell level instead of (or in addition to?) the whole grid. I could imagine a UI where only certain columns have textfields in them, and it would be nice if the other columns still automatically focused the content of the cell. For example, in the Reddit Table story in S2 with keyboardNavigationBehavior="tab", now you have to tab to the links instead of just arrowing to them, but there are no inputs in that cell.

Ideally we'd even automatically set a cell to tab behavior if we detected inputs in them. But I guess there will be cases with custom components where we'll need a prop too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linking related discussion #8691 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I don't love it either, I have to tab to the column header menu trigger now as well for resizing table, and the focus ring on selection checkbox cells looks funny.

@rspbot
Copy link

rspbot commented Aug 13, 2025

@rspbot
Copy link

rspbot commented Aug 13, 2025

## API Changes

react-aria-components

/react-aria-components:Popover

 Popover {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   arrowBoundaryOffset?: number = 0
-  arrowRef?: RefObject<Element | null>
   boundaryElement?: Element = document.body
   children?: ChildrenOrFunction<PopoverRenderProps>
   className?: ClassNameOrFunction<PopoverRenderProps>
   containerPadding?: number = 12
   defaultOpen?: boolean
   isEntering?: boolean
   isExiting?: boolean
   isKeyboardDismissDisabled?: boolean = false
   isNonModal?: boolean
   isOpen?: boolean
   maxHeight?: number
   offset?: number = 8
   onOpenChange?: (boolean) => void
   placement?: Placement = 'bottom'
   scrollRef?: RefObject<Element | null> = overlayRef
   shouldCloseOnInteractOutside?: (Element) => boolean
   shouldFlip?: boolean = true
   shouldUpdatePosition?: boolean = true
   slot?: string | null
   style?: StyleOrFunction<PopoverRenderProps>
   trigger?: string
   triggerRef?: RefObject<Element | null>
 }

/react-aria-components:Table

 Table {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   children?: ReactNode
   className?: ClassNameOrFunction<TableRenderProps>
   defaultSelectedKeys?: 'all' | Iterable<Key>
   disabledBehavior?: DisabledBehavior = "selection"
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   dragAndDropHooks?: DragAndDropHooks
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
+  keyboardNavigationBehavior?: 'arrow' | 'tab' = 'arrow'
   onRowAction?: (Key) => void
   onSelectionChange?: (Selection) => void
   onSortChange?: (SortDescriptor) => any
   selectedKeys?: 'all' | Iterable<Key>
   selectionMode?: SelectionMode
   shouldSelectOnPressUp?: boolean
   slot?: string | null
   sortDescriptor?: SortDescriptor
   style?: StyleOrFunction<TableRenderProps>
 }

/react-aria-components:VisuallyHidden

-VisuallyHidden {
-  children?: ReactNode
-  className?: string | undefined
-  elementType?: string | JSXElementConstructor<any> = 'div'
-  id?: string | undefined
-  isFocusable?: boolean
-  role?: AriaRole | undefined
-  style?: CSSProperties | undefined
-  tabIndex?: number | undefined
-}

/react-aria-components:PopoverProps

 PopoverProps {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   arrowBoundaryOffset?: number = 0
-  arrowRef?: RefObject<Element | null>
   boundaryElement?: Element = document.body
   children?: ChildrenOrFunction<PopoverRenderProps>
   className?: ClassNameOrFunction<PopoverRenderProps>
   containerPadding?: number = 12
   defaultOpen?: boolean
   isEntering?: boolean
   isExiting?: boolean
   isKeyboardDismissDisabled?: boolean = false
   isNonModal?: boolean
   isOpen?: boolean
   maxHeight?: number
   offset?: number = 8
   onOpenChange?: (boolean) => void
   placement?: Placement = 'bottom'
   scrollRef?: RefObject<Element | null> = overlayRef
   shouldCloseOnInteractOutside?: (Element) => boolean
   shouldFlip?: boolean = true
   shouldUpdatePosition?: boolean = true
   slot?: string | null
   style?: StyleOrFunction<PopoverRenderProps>
   trigger?: string
   triggerRef?: RefObject<Element | null>
 }

/react-aria-components:TableProps

 TableProps {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   children?: ReactNode
   className?: ClassNameOrFunction<TableRenderProps>
   defaultSelectedKeys?: 'all' | Iterable<Key>
   disabledBehavior?: DisabledBehavior = "selection"
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   dragAndDropHooks?: DragAndDropHooks
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
+  keyboardNavigationBehavior?: 'arrow' | 'tab' = 'arrow'
   onRowAction?: (Key) => void
   onSelectionChange?: (Selection) => void
   onSortChange?: (SortDescriptor) => any
   selectedKeys?: 'all' | Iterable<Key>
   selectionMode?: SelectionMode
   shouldSelectOnPressUp?: boolean
   slot?: string | null
   sortDescriptor?: SortDescriptor
   style?: StyleOrFunction<TableRenderProps>
 }

/react-aria-components:GridLayoutOptions

 GridLayoutOptions {
   dropIndicatorThickness?: number = 2
   maxColumns?: number = Infinity
-  maxHorizontalSpace?: number = Infinity
   maxItemSize?: Size = Infinity
   minItemSize?: Size = 200 x 200
   minSpace?: Size = 18 x 18
   preserveAspectRatio?: boolean = false

@internationalized/date

/@internationalized/date:setLocalTimeZone

-setLocalTimeZone {
-  timeZone: string
-  returnVal: undefined
-}

/@internationalized/date:resetLocalTimeZone

-resetLocalTimeZone {
-  returnVal: undefined
-}

@react-aria/grid

/@react-aria/grid:GridProps

 GridProps {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   disallowTypeAhead?: boolean = false
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
   focusMode?: 'row' | 'cell' = 'row'
   getRowText?: (Key) => string = (key) => state.collection.getItem(key)?.textValue
   id?: string
   isVirtualized?: boolean
   keyboardDelegate?: KeyboardDelegate
+  keyboardNavigationBehavior?: 'arrow' | 'tab' = 'arrow'
   onCellAction?: (Key) => void
   onRowAction?: (Key) => void
   scrollRef?: RefObject<HTMLElement | null>
   shouldSelectOnPressUp?: boolean

@react-aria/overlays

/@react-aria/overlays:AriaPositionProps

 AriaPositionProps {
   arrowBoundaryOffset?: number = 0
-  arrowRef?: RefObject<Element | null>
   arrowSize?: number = 0
   boundaryElement?: Element = document.body
   containerPadding?: number = 12
   crossOffset?: number = 0
   maxHeight?: number
   offset?: number = 0
   onClose?: () => void | null
   overlayRef: RefObject<Element | null>
   placement?: Placement = 'bottom'
   scrollRef?: RefObject<Element | null> = overlayRef
   shouldFlip?: boolean = true
   shouldUpdatePosition?: boolean = true
   targetRef: RefObject<Element | null>
 }

/@react-aria/overlays:PositionAria

 PositionAria {
   arrowProps: DOMAttributes
   overlayProps: DOMAttributes
   placement: PlacementAxis | null
-  triggerOrigin: {
-    x: number
-  y: number
-} | null
   updatePosition: () => void
 }

/@react-aria/overlays:AriaPopoverProps

 AriaPopoverProps {
   arrowBoundaryOffset?: number = 0
-  arrowRef?: RefObject<Element | null>
   arrowSize?: number = 0
   boundaryElement?: Element = document.body
   containerPadding?: number = 12
   crossOffset?: number = 0
   isKeyboardDismissDisabled?: boolean = false
   isNonModal?: boolean
   maxHeight?: number
   offset?: number = 0
   placement?: Placement = 'bottom'
   popoverRef: RefObject<Element | null>
   scrollRef?: RefObject<Element | null> = overlayRef
   shouldCloseOnInteractOutside?: (Element) => boolean
   shouldFlip?: boolean = true
   shouldUpdatePosition?: boolean = true
   triggerRef: RefObject<Element | null>
 }

/@react-aria/overlays:PopoverAria

 PopoverAria {
   arrowProps: DOMAttributes
   placement: PlacementAxis | null
   popoverProps: DOMAttributes
-  triggerOrigin: {
-    x: number
-  y: number
-} | null
   underlayProps: DOMAttributes
 }

@react-aria/table

/@react-aria/table:AriaTableProps

 AriaTableProps {
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   disallowTypeAhead?: boolean = false
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
   focusMode?: 'row' | 'cell' = 'row'
   getRowText?: (Key) => string = (key) => state.collection.getItem(key)?.textValue
   id?: string
   isVirtualized?: boolean
   keyboardDelegate?: KeyboardDelegate
+  keyboardNavigationBehavior?: 'arrow' | 'tab' = 'arrow'
   layoutDelegate?: LayoutDelegate
   onCellAction?: (Key) => void
   onRowAction?: (Key) => void
   scrollRef?: RefObject<HTMLElement | null>
 }

@react-spectrum/overlays

/@react-spectrum/overlays:Popover

 Popover {
   UNSAFE_className?: string
   UNSAFE_style?: CSSProperties
   alignSelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'center' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'stretch'>
   arrowBoundaryOffset?: number = 0
-  arrowRef?: RefObject<Element | null>
   arrowSize?: number = 0
   bottom?: Responsive<DimensionValue>
   boundaryElement?: Element = document.body
   children: ReactNode
   containerPadding?: number = 12
   crossOffset?: number = 0
   disableFocusManagement?: boolean
   enableBothDismissButtons?: boolean
   end?: Responsive<DimensionValue>
   flex?: Responsive<string | number | boolean>
   flexBasis?: Responsive<number | string>
   flexGrow?: Responsive<number>
   flexShrink?: Responsive<number>
   gridArea?: Responsive<string>
   gridColumn?: Responsive<string>
   gridColumnEnd?: Responsive<string>
   gridColumnStart?: Responsive<string>
   gridRow?: Responsive<string>
   gridRowEnd?: Responsive<string>
   gridRowStart?: Responsive<string>
   groupRef?: RefObject<Element | null>
   height?: Responsive<DimensionValue>
   hideArrow?: boolean
   isDisabled?: boolean
   isHidden?: Responsive<boolean>
   isKeyboardDismissDisabled?: boolean = false
   isNonModal?: boolean
   justifySelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'center' | 'left' | 'right' | 'stretch'>
   left?: Responsive<DimensionValue>
   margin?: Responsive<DimensionValue>
   marginBottom?: Responsive<DimensionValue>
   marginEnd?: Responsive<DimensionValue>
   marginStart?: Responsive<DimensionValue>
   marginTop?: Responsive<DimensionValue>
   marginX?: Responsive<DimensionValue>
   marginY?: Responsive<DimensionValue>
   maxHeight?: Responsive<DimensionValue>
   maxWidth?: Responsive<DimensionValue>
   minHeight?: Responsive<DimensionValue>
   minWidth?: Responsive<DimensionValue>
   offset?: number = 0
   onBlurWithin?: (FocusEvent) => void
   onDismissButtonPress?: () => void
   onEnter?: () => void
   onEntered?: () => void
   onEntering?: () => void
   onExit?: () => void
   onExited?: () => void
   onExiting?: () => void
   onFocusWithin?: (FocusEvent) => void
   onFocusWithinChange?: (boolean) => void
   order?: Responsive<number>
   placement?: Placement = 'bottom'
   position?: Responsive<'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'>
   right?: Responsive<DimensionValue>
   scrollRef?: RefObject<Element | null> = overlayRef
   shouldCloseOnInteractOutside?: (Element) => boolean
   shouldContainFocus?: boolean
   shouldFlip?: boolean = true
   shouldUpdatePosition?: boolean = true
   start?: Responsive<DimensionValue>
   state: OverlayTriggerState
   top?: Responsive<DimensionValue>
   triggerRef: RefObject<Element | null>
   width?: Responsive<DimensionValue>
   zIndex?: Responsive<number>
 }

@react-spectrum/s2

/@react-spectrum/s2:TableView

 TableView {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   children?: ReactNode
   defaultSelectedKeys?: 'all' | Iterable<Key>
   density?: 'compact' | 'spacious' | 'regular' = 'regular'
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
   isQuiet?: boolean
+  keyboardNavigationBehavior?: 'arrow' | 'tab' = 'arrow'
   loadingState?: LoadingState
   onAction?: (Key) => void
   onLoadMore?: () => any
   onResize?: (Map<Key, ColumnSize>) => void
   onResizeStart?: (Map<Key, ColumnSize>) => void
   onSelectionChange?: (Selection) => void
   onSortChange?: (SortDescriptor) => any
   overflowMode?: 'wrap' | 'truncate' = 'truncate'
   renderActionBar?: ('all' | Set<Key>) => ReactElement
   selectedKeys?: 'all' | Iterable<Key>
   selectionMode?: SelectionMode
   shouldSelectOnPressUp?: boolean
   slot?: string | null
   sortDescriptor?: SortDescriptor
   styles?: StylesPropWithHeight
 }

/@react-spectrum/s2:PopoverProps

 PopoverProps {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
-  arrowRef?: RefObject<Element | null>
   boundaryElement?: Element = document.body
   children?: ChildrenOrFunction<PopoverRenderProps>
   className?: ClassNameOrFunction<PopoverRenderProps>
   containerPadding?: number = 12
   defaultOpen?: boolean
   hideArrow?: boolean = false
   isEntering?: boolean
   isExiting?: boolean
   isOpen?: boolean
   maxHeight?: number
   offset?: number = 8
   onOpenChange?: (boolean) => void
   placement?: Placement = 'bottom'
   scrollRef?: RefObject<Element | null> = overlayRef
   shouldFlip?: boolean = true
   size?: 'S' | 'M' | 'L'
   slot?: string | null
   style?: StyleOrFunction<PopoverRenderProps>
   styles?: StyleString
   trigger?: string
   triggerRef?: RefObject<Element | null>
 }

/@react-spectrum/s2:TableViewProps

 TableViewProps {
   UNSAFE_className?: UnsafeClassName
   UNSAFE_style?: CSSProperties
   aria-describedby?: string
   aria-details?: string
   aria-label?: string
   aria-labelledby?: string
   children?: ReactNode
   defaultSelectedKeys?: 'all' | Iterable<Key>
   density?: 'compact' | 'spacious' | 'regular' = 'regular'
   disabledKeys?: Iterable<Key>
   disallowEmptySelection?: boolean
   escapeKeyBehavior?: 'clearSelection' | 'none' = 'clearSelection'
   isQuiet?: boolean
+  keyboardNavigationBehavior?: 'arrow' | 'tab' = 'arrow'
   loadingState?: LoadingState
   onAction?: (Key) => void
   onLoadMore?: () => any
   onResize?: (Map<Key, ColumnSize>) => void
   onResizeStart?: (Map<Key, ColumnSize>) => void
   onSelectionChange?: (Selection) => void
   onSortChange?: (SortDescriptor) => any
   overflowMode?: 'wrap' | 'truncate' = 'truncate'
   renderActionBar?: ('all' | Set<Key>) => ReactElement
   selectedKeys?: 'all' | Iterable<Key>
   selectionMode?: SelectionMode
   shouldSelectOnPressUp?: boolean
   slot?: string | null
   sortDescriptor?: SortDescriptor
   styles?: StylesPropWithHeight
 }

@react-stately/data

/@react-stately/data:ListData

 ListData <T> {
-  addKeysToSelection: (Selection) => void
   append: (Array<T>) => void
   filterText: string
   getItem: (Key) => T | undefined
   insert: (number, Array<T>) => void
   insertAfter: (Key, Array<T>) => void
   insertBefore: (Key, Array<T>) => void
   items: Array<T>
   move: (Key, number) => void
   moveAfter: (Key, Iterable<Key>) => void
   moveBefore: (Key, Iterable<Key>) => void
   prepend: (Array<T>) => void
   remove: (Array<Key>) => void
-  removeKeysFromSelection: (Selection) => void
   removeSelectedItems: () => void
   selectedKeys: Selection
   setFilterText: (string) => void
   setSelectedKeys: (Selection) => void
 }

/@react-stately/data:AsyncListData

 AsyncListData <T> {
-  addKeysToSelection: (Selection) => void
   append: (Array<T>) => void
   error?: Error
   filterText: string
   getItem: (Key) => T | undefined
   insert: (number, Array<T>) => void
   insertAfter: (Key, Array<T>) => void
   insertBefore: (Key, Array<T>) => void
   isLoading: boolean
   items: Array<T>
   loadMore: () => void
   loadingState: LoadingState
   move: (Key, number) => void
   moveAfter: (Key, Iterable<Key>) => void
   moveBefore: (Key, Iterable<Key>) => void
   prepend: (Array<T>) => void
   reload: () => void
   remove: (Array<Key>) => void
-  removeKeysFromSelection: (Selection) => void
   removeSelectedItems: () => void
   selectedKeys: Selection
   setFilterText: (string) => void
   setSelectedKeys: (Selection) => void
   sortDescriptor?: SortDescriptor
   update: (Key, T) => void
 }

@react-stately/layout

/@react-stately/layout:GridLayoutOptions

 GridLayoutOptions {
   dropIndicatorThickness?: number = 2
   maxColumns?: number = Infinity
-  maxHorizontalSpace?: number = Infinity
   maxItemSize?: Size = Infinity
   minItemSize?: Size = 200 x 200
   minSpace?: Size = 18 x 18
   preserveAspectRatio?: boolean = false

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants