@@ -262,6 +262,7 @@ export class ElementNode<T> extends BaseNode<T> {
262
262
nodeType = 8 ; // COMMENT_NODE (we'd use ELEMENT_NODE but React DevTools will fail to get its dimensions)
263
263
node : NodeValue < T > ;
264
264
private _index : number = 0 ;
265
+ private hasSetProps = false ;
265
266
266
267
constructor ( type : string , ownerDocument : Document < T , any > ) {
267
268
super ( ownerDocument ) ;
@@ -297,21 +298,20 @@ export class ElementNode<T> extends BaseNode<T> {
297
298
node . lastChildKey = this . lastChild ?. node . key ?? null ;
298
299
}
299
300
300
- // Special property that React passes through as an object rather than a string via setAttribute.
301
- // See below for details.
302
- set multiple ( obj : any ) {
301
+ setProps ( obj : any , rendered ?: ReactNode ) {
303
302
let node = this . ownerDocument . getMutableNode ( this ) ;
304
- let { rendered , value, textValue, id, ...props } = obj ;
303
+ let { value, textValue, id, ...props } = obj ;
305
304
node . props = props ;
306
305
node . rendered = rendered ;
307
306
node . value = value ;
308
307
node . textValue = textValue || ( typeof rendered === 'string' ? rendered : '' ) || obj [ 'aria-label' ] || '' ;
309
308
if ( id != null && id !== node . key ) {
310
- if ( this . parentNode ) {
309
+ if ( this . hasSetProps ) {
311
310
throw new Error ( 'Cannot change the id of an item' ) ;
312
311
}
313
312
node . key = id ;
314
313
}
314
+ this . hasSetProps = true ;
315
315
}
316
316
317
317
get style ( ) {
@@ -672,11 +672,13 @@ export function useCollection<T extends object, C extends BaseCollection<T>>(pro
672
672
}
673
673
674
674
/** Renders a DOM element (e.g. separator or header) shallowly when inside a collection. */
675
- export function useShallowRender < T extends Element > ( Element : string , props : React . HTMLAttributes < T > , ref : React . RefObject < T > ) : ReactElement | null {
675
+ export function useShallowRender < T extends Element > ( Element : string , props : React . HTMLAttributes < T > , ref : React . Ref < T > ) : ReactElement | null {
676
676
let isShallow = useContext ( ShallowRenderContext ) ;
677
+ props = useMemo ( ( ) => ( { ...props , ref} ) , [ props , ref ] ) ;
678
+ ref = useCollectionItemRef ( props , props . children ) ;
677
679
if ( isShallow ) {
678
680
// @ts -ignore
679
- return < Element multiple = { { ... props , ref, rendered : props . children } } /> ;
681
+ return < Element ref = { ref } /> ;
680
682
}
681
683
682
684
return null ;
@@ -738,6 +740,13 @@ export interface ItemRenderProps {
738
740
isDropTarget ?: boolean
739
741
}
740
742
743
+ export function useCollectionItemRef ( props : any , rendered ?: ReactNode ) {
744
+ // Return a callback ref that sets the props object on the fake DOM node.
745
+ return useCallback ( ( element ) => {
746
+ element ?. setProps ( props , rendered ) ;
747
+ } , [ props , rendered ] ) ;
748
+ }
749
+
741
750
export interface ItemProps < T = object > extends Omit < SharedItemProps < T > , 'children' > , RenderProps < ItemRenderProps > {
742
751
/** The unique id of the item. */
743
752
id ?: Key ,
@@ -746,13 +755,8 @@ export interface ItemProps<T = object> extends Omit<SharedItemProps<T>, 'childre
746
755
}
747
756
748
757
export function Item < T extends object > ( props : ItemProps < T > ) : JSX . Element {
749
- // HACK: the `multiple` prop is special in that React will pass it through as a property rather
750
- // than converting to a string and using setAttribute. This allows our custom fake DOM to receive
751
- // the props as an object. Once React supports custom elements, we can switch to that instead.
752
- // https://github.com/facebook/react/issues/11347
753
- // https://github.com/facebook/react/blob/82c64e1a49239158c0daa7f0d603d2ad2ee667a9/packages/react-dom/src/shared/DOMProperty.js#L386
754
758
// @ts -ignore
755
- return < item multiple = { { ... props , rendered : props . children } } /> ;
759
+ return < item ref = { useCollectionItemRef ( props , props . children ) } /> ;
756
760
}
757
761
758
762
export interface SectionProps < T > extends Omit < SharedSectionProps < T > , 'children' | 'title' > , DOMProps {
@@ -768,7 +772,7 @@ export function Section<T extends object>(props: SectionProps<T>): JSX.Element {
768
772
let children = useCollectionChildren ( props ) ;
769
773
770
774
// @ts -ignore
771
- return < section multiple = { { ... props , rendered : props . title } } > { children } </ section > ;
775
+ return < section ref = { useCollectionItemRef ( props ) } > { children } </ section > ;
772
776
}
773
777
774
778
export const CollectionContext = createContext < CachedChildrenOptions < unknown > | null > ( null ) ;
0 commit comments