-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Feat: Add support for multiple adjacent collections #8553
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
Closed
Closed
Changes from 2 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
58cba2d
Feat: Add `useCollectionRef` hook to improve controlled collection cases
nwidynski 99eeadb
Fix: mergeRefs immutable tests in React 16 & 17
nwidynski be30beb
chore: update comments
nwidynski 07f7cd3
chore: add synchronization tests
nwidynski 108a757
fix: react 16 render return
nwidynski 39e9a2d
fix: react 16 render return for real this time
nwidynski File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,20 +15,37 @@ import {BaseNode, Document, ElementNode} from './Document'; | |
| import {CachedChildrenOptions, useCachedChildren} from './useCachedChildren'; | ||
| import {createPortal} from 'react-dom'; | ||
| import {FocusableContext} from '@react-aria/interactions'; | ||
| import {forwardRefType, Node} from '@react-types/shared'; | ||
| import {forwardRefType, Node, RefObject} from '@react-types/shared'; | ||
| import {Hidden} from './Hidden'; | ||
| import React, {createContext, ForwardedRef, forwardRef, JSX, ReactElement, ReactNode, useCallback, useContext, useMemo, useRef, useState} from 'react'; | ||
| import React, {createContext, ForwardedRef, forwardRef, JSX, ReactElement, ReactNode, Ref, useCallback, useContext, useMemo, useRef, useState} from 'react'; | ||
| import {useIsSSR} from '@react-aria/ssr'; | ||
| import {useLayoutEffect} from '@react-aria/utils'; | ||
| import {useLayoutEffect, useObjectRef} from '@react-aria/utils'; | ||
| import {useSyncExternalStore as useSyncExternalStoreShim} from 'use-sync-external-store/shim/index.js'; | ||
|
|
||
| const ShallowRenderContext = createContext(false); | ||
| const CollectionDocumentContext = createContext<Document<any, BaseCollection<any>> | null>(null); | ||
|
|
||
| export interface CollectionProps<T> extends CachedChildrenOptions<T> {} | ||
|
|
||
| export interface CollectionChildren<C extends BaseCollection<object>> { | ||
| (collection: C): ReactNode | ||
| } | ||
|
|
||
| export interface CollectionRenderProps<C extends BaseCollection<object>> { | ||
| /** A hook that will be called before the collection builder to build the content. */ | ||
| useCollectionContent?: (content: ReactNode) => ReactNode, | ||
| /** A hook that will be called by the collection builder to render the children. */ | ||
| useCollectionChildren?: (children: CollectionChildren<C>) => CollectionChildren<C> | ||
| // TODO: Do we also want useCollection() to wrap createCollection()? | ||
| } | ||
|
|
||
| interface CollectionRef<C extends BaseCollection<object>, E extends Element> extends RefObject<E | null>, CollectionRenderProps<C> {} | ||
|
|
||
| export interface CollectionBuilderProps<C extends BaseCollection<object>> { | ||
| content: ReactNode, | ||
| children: (collection: C) => ReactNode, | ||
| createCollection?: () => C | ||
| children: CollectionChildren<C>, | ||
| createCollection?: () => C, | ||
| collectionRef?: CollectionRef<C, Element> | ||
| } | ||
|
|
||
| /** | ||
|
|
@@ -37,13 +54,14 @@ export interface CollectionBuilderProps<C extends BaseCollection<object>> { | |
| export function CollectionBuilder<C extends BaseCollection<object>>(props: CollectionBuilderProps<C>): ReactElement { | ||
| // If a document was provided above us, we're already in a hidden tree. Just render the content. | ||
| let doc = useContext(CollectionDocumentContext); | ||
| let content = props.collectionRef?.useCollectionContent?.(props.content) ?? props.content; | ||
| if (doc) { | ||
| // The React types prior to 18 did not allow returning ReactNode from components | ||
| // even though the actual implementation since React 16 did. | ||
| // We must return ReactElement so that TS does not complain that <CollectionBuilder> | ||
| // is not a valid JSX element with React 16 and 17 types. | ||
| // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/20544 | ||
| return props.content as ReactElement; | ||
| return content as ReactElement; | ||
| } | ||
|
|
||
| // Otherwise, render a hidden copy of the children so that we can build the collection before constructing the state. | ||
|
|
@@ -52,14 +70,15 @@ export function CollectionBuilder<C extends BaseCollection<object>>(props: Colle | |
| // This is fine. CollectionDocumentContext never changes after mounting. | ||
| // eslint-disable-next-line react-hooks/rules-of-hooks | ||
| let {collection, document} = useCollectionDocument(props.createCollection); | ||
| let children = props.collectionRef?.useCollectionChildren?.(props.children) ?? props.children; | ||
| return ( | ||
| <> | ||
| <Hidden> | ||
| <CollectionDocumentContext.Provider value={document}> | ||
| {props.content} | ||
| {content} | ||
| </CollectionDocumentContext.Provider> | ||
| </Hidden> | ||
| <CollectionInner render={props.children} collection={collection} /> | ||
| <CollectionInner render={children} collection={collection} /> | ||
| </> | ||
| ); | ||
| } | ||
|
|
@@ -157,6 +176,12 @@ function useSSRCollectionNode<T extends Element>(Type: string, props: object, re | |
| return <Type ref={itemRef}>{children}</Type>; | ||
| } | ||
|
|
||
| export function useCollectionRef<C extends BaseCollection<object>, E extends Element>(props: CollectionRenderProps<C>, ref: Ref<E>): CollectionRef<C, E> { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Naming and argument order is TBD. I was also considering |
||
| let refObject = useObjectRef(ref) as CollectionRef<C, E>; | ||
|
|
||
| return Object.assign(refObject, props); | ||
| } | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| export function createLeafComponent<T extends object, P extends object, E extends Element>(type: string, render: (props: P, ref: ForwardedRef<E>) => ReactElement | null): (props: P & React.RefAttributes<E>) => ReactElement | null; | ||
| export function createLeafComponent<T extends object, P extends object, E extends Element>(type: string, render: (props: P, ref: ForwardedRef<E>, node: Node<T>) => ReactElement | null): (props: P & React.RefAttributes<E>) => ReactElement | null; | ||
|
|
@@ -206,8 +231,6 @@ function useCollectionChildren<T extends object>(options: CachedChildrenOptions< | |
| return useCachedChildren({...options, addIdAndValue: true}); | ||
| } | ||
|
|
||
| export interface CollectionProps<T> extends CachedChildrenOptions<T> {} | ||
|
|
||
| const CollectionContext = createContext<CachedChildrenOptions<unknown> | null>(null); | ||
|
|
||
| /** A Collection renders a list of items, automatically managing caching and keys. */ | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.