-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Fix virtualizer persisted keys with drag and drop #6644
base: move-collections
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that within the 'Drag within table many items' story, if you mouse drag an item from the top of the list to the bottom, then try to keyboard drag an item back up, the list doesn't scroll as you move the drop indicator up the list.
Hmm yeah that seems to be an issue with persisted keys in TableLayout... |
Ok fixed 3 issues:
|
## API Changes
unknown top level export { type: 'any' } @react-aria/virtualizerVirtualizer Virtualizer<O, T extends {}, V extends ReactNode> {
children: (string, {}) => ReactNode
collection: Collection<{}>
- focusedKey?: Key
isLoading?: boolean
layout: Layout<{}, O>
layoutOptions?: O
onLoadMore?: () => void
+ persistedKeys?: Set<Key> | null
renderWrapper?: RenderWrapper<{}, ReactNode>
scrollDirection?: 'horizontal' | 'vertical' | 'both'
sizeToFit?: 'width' | 'height'
} @react-stately/layoutGridLayout GridLayout<O = any, T> {
constructor: (GridLayoutOptions) => void
getContentSize: () => Size
getDropTargetFromPoint: (number, number, (DropTarget) => boolean) => DropTarget
getDropTargetLayoutInfo: (ItemDropTarget) => LayoutInfo
getLayoutInfo: (Key) => LayoutInfo | null
getVisibleLayoutInfos: (Rect) => Array<LayoutInfo>
- validate: () => void
+ update: () => void
} ListLayout ListLayout<O = any, T> {
constructor: (ListLayoutOptions) => void
getContentSize: () => void
getDropTargetFromPoint: (number, number, (DropTarget) => boolean) => DropTarget
getDropTargetLayoutInfo: (ItemDropTarget) => LayoutInfo
getLayoutInfo: (Key) => void
getVisibleLayoutInfos: (Rect) => void
+ update: (InvalidationContext<O>) => void
updateItemSize: (Key, Size) => void
- validate: (InvalidationContext<O>) => void
} TableLayout TableLayout<O extends TableLayoutProps = TableLayoutProps, T> {
constructor: (ListLayoutOptions) => void
getDropTargetFromPoint: (number, number, (DropTarget) => boolean) => DropTarget
getDropTargetLayoutInfo: (ItemDropTarget) => LayoutInfo
getVisibleLayoutInfos: (Rect) => void
- validate: (InvalidationContext<TableLayoutProps>) => void
+ update: (InvalidationContext<TableLayoutProps>) => void
} @react-stately/virtualizerLayout Layout<O = any, T extends {}> {
getContentSize: () => Size
getDropTargetLayoutInfo: (ItemDropTarget) => LayoutInfo
getItemRect: (Key) => Rect
getLayoutInfo: (Key) => LayoutInfo | null
getVisibleLayoutInfos: (Rect) => Array<LayoutInfo>
getVisibleRect: () => Rect
shouldInvalidate: (Rect, Rect) => boolean
+ update: (InvalidationContext<O>) => void
updateItemSize: (Key, Size) => boolean
- validate: (InvalidationContext<O>) => void
virtualizer: Virtualizer<{}, any>
} @react-aria/collectionsCollectionBuilder-
+CollectionBuilder<C extends BaseCollection<{}>> {
+ children: (BaseCollection<{}>) => ReactNode
+ content: ReactNode
+ createCollection?: () => BaseCollection<{}>
+} Collection+Collection<T extends {}> {
+} createLeafComponent-
+createLeafComponent<E extends Element, P extends {}> {
+ type: string
+ render: (P, ForwardedRef<E>, any) => ReactNode
+ returnVal: undefined
+} createBranchComponent-
+createBranchComponent<E extends Element, P extends {
+ children?: any
+}, T extends {}> {
+ type: string
+ render: (P, ForwardedRef<E>, Node<T>) => ReactNode
+ useChildren: (P) => ReactNode
+ returnVal: undefined
+} createHideableComponent-
+createHideableComponent<P = {
+
+}, T> {
+ fn: (P, React.Ref<T>) => ReactNode | null
+ returnVal: undefined
+} useIsHidden-
+useIsHidden {
+ returnVal: undefined
+} useCachedChildrenchanged by:
-
+useCachedChildren<T extends {}> {
+ props: CachedChildrenOptions<T>
+ returnVal: undefined
+} BaseCollectionchanged by:
-
+BaseCollection<T> {
+ addNode: (NodeValue<T>) => void
+ at: () => Node<T>
+ clone: () => this
+ commit: (Key | null, Key | null, any) => void
+ getChildren: (Key) => Iterable<Node<T>>
+ getFirstKey: () => void
+ getItem: (Key) => Node<T> | null
+ getKeyAfter: (Key) => void
+ getKeyBefore: (Key) => void
+ getKeys: () => void
+ getLastKey: () => void
+ removeNode: (Key) => void
+ size: any
+ undefined: () => void
+} NodeValuechanged by:
-
+NodeValue<T> {
+ aria-label?: string
+ childNodes: Iterable<Node<T>>
+ clone: () => NodeValue<T>
+ constructor: (string, Key) => void
+ firstChildKey: Key | null
+ hasChildNodes: boolean
+ index: number
+ key: Key
+ lastChildKey: Key | null
+ level: number
+ nextKey: Key | null
+ parentKey: Key | null
+ prevKey: Key | null
+ props: any
+ render?: (Node<any>) => ReactElement
+ rendered: ReactNode
+ textValue: string
+ type: string
+ value: T | null
+} it changed:
CollectionBuilderProps-
+CollectionBuilderProps<C extends BaseCollection<{}>> {
+ children: (BaseCollection<{}>) => ReactNode
+ content: ReactNode
+ createCollection?: () => BaseCollection<{}>
+} CollectionProps+CollectionProps<T> {
+} CachedChildrenOptions-
+CachedChildrenOptions<T> {
+ addIdAndValue?: boolean
+ children?: ReactNode | (T) => ReactNode
+ dependencies?: Array<any>
+ idScope?: Key
+ items?: Iterable<T>
+} it changed:
|
Brain dump before break: Actually I did manage to reproduce (2) in RSP as well, so we should persist the drag target as well as the drop target. It only occurs when the drag target element is removed from the dom and not reused by another view, most commonly with variable row heights. The other issue with scrolling to the top on drop also only seems to occur in the non-util handlers stories, I think because the |
Depends on #6640
This fixes the virtualizer
persistedKeys
during drag and drop so that keyboard navigation works correctly and focus isn't lost. Since we only render one of the drop positions (before or after), we need to normalize the key we persist accordingly so the correct one is in the DOM and able to get focus.I've also changed the API on Virtualizer and collection renderers in general to accept
persistedKeys
as a prop rather than a singlefocusedKey
. This enables multiple keys to be persisted and is more extensible for future use cases.Finally, based on feedback in #6631 (comment), I've renamed the Layout
validate
method toupdate
to make it easier to understand. This was originally pulled from v2 CollectionView but since we are doing a breaking change we can rename it now.