Skip to content

Commit b92f602

Browse files
authored
fix(#4369): Fix children renderProps for react-aria-components (#4385)
* fix(#4369): Fix children renderProps for react-aria-components
1 parent 76932d3 commit b92f602

34 files changed

+664
-32
lines changed

packages/react-aria-components/src/ComboBox.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,7 @@ function ComboBox<T extends object>(props: ComboBoxProps<T>, ref: ForwardedRef<H
114114
}
115115
}]
116116
]}>
117-
<div {...renderProps} ref={ref} slot={props.slot}>
118-
{props.children}
119-
</div>
117+
<div {...renderProps} ref={ref} slot={props.slot} />
120118
{portal}
121119
</Provider>
122120
);

packages/react-aria-components/src/DateField.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ function DateField<T extends DateValue>(props: DateFieldProps<T>, ref: Forwarded
6161
}
6262
}]
6363
]}>
64-
<div {...renderProps} ref={ref} slot={props.slot}>
65-
{props.children}
66-
</div>
64+
<div {...renderProps} ref={ref} slot={props.slot} />
6765
</Provider>
6866
);
6967
}
@@ -105,9 +103,7 @@ function TimeField<T extends TimeValue>(props: TimeFieldProps<T>, ref: Forwarded
105103
}
106104
}]
107105
]}>
108-
<div {...renderProps} ref={ref} slot={props.slot}>
109-
{props.children}
110-
</div>
106+
<div {...renderProps} ref={ref} slot={props.slot} />
111107
</Provider>
112108
);
113109
}

packages/react-aria-components/src/DatePicker.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,7 @@ function DatePicker<T extends DateValue>(props: DatePickerProps<T>, ref: Forward
7878
}
7979
}]
8080
]}>
81-
<div {...renderProps} ref={ref} slot={props.slot}>
82-
{props.children}
83-
</div>
81+
<div {...renderProps} ref={ref} slot={props.slot} />
8482
</Provider>
8583
);
8684
}
@@ -163,9 +161,7 @@ function DateRangePicker<T extends DateValue>(props: DateRangePickerProps<T>, re
163161
}
164162
}]
165163
]}>
166-
<div {...renderProps} ref={ref} slot={props.slot}>
167-
{props.children}
168-
</div>
164+
<div {...renderProps} ref={ref} slot={props.slot} />
169165
</Provider>
170166
);
171167
}

packages/react-aria-components/src/Link.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export const LinkContext = createContext<ContextValue<LinkProps, HTMLAnchorEleme
5555
function Link(props: LinkProps, ref: ForwardedRef<HTMLAnchorElement>) {
5656
[props, ref] = useContextProps(props, ref, LinkContext);
5757

58-
let elementType = typeof props.children === 'string' ? 'span' : 'a';
58+
let elementType = typeof props.children === 'string' || typeof props.children === 'function' ? 'span' : 'a';
5959
let {linkProps, isPressed} = useLink({...props, elementType}, ref);
6060

6161
let {hoverProps, isHovered} = useHover(props);

packages/react-aria-components/src/NumberField.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,7 @@ function NumberField(props: NumberFieldProps, ref: ForwardedRef<HTMLDivElement>)
6565
}
6666
}]
6767
]}>
68-
<div {...renderProps} ref={ref} slot={props.slot}>
69-
{props.children}
70-
</div>
68+
<div {...renderProps} ref={ref} slot={props.slot} />
7169
</Provider>
7270
);
7371
}

packages/react-aria-components/src/Popover.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ interface PopoverInnerProps extends AriaPopoverProps, RenderProps<PopoverRenderP
8282
isExiting: boolean
8383
}
8484

85-
function PopoverInner({children, state, isExiting, ...props}: PopoverInnerProps) {
85+
function PopoverInner({state, isExiting, ...props}: PopoverInnerProps) {
8686
let {popoverProps, underlayProps, arrowProps, placement} = usePopover({
8787
...props,
8888
offset: props.offset ?? 8
@@ -116,7 +116,7 @@ function PopoverInner({children, state, isExiting, ...props}: PopoverInnerProps)
116116
data-exiting={isExiting || undefined}>
117117
{!props.isNonModal && <DismissButton onDismiss={state.close} />}
118118
<OverlayArrowContext.Provider value={{arrowProps, placement}}>
119-
{children}
119+
{renderProps.children}
120120
</OverlayArrowContext.Provider>
121121
<DismissButton onDismiss={state.close} />
122122
</div>

packages/react-aria-components/src/Select.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,7 @@ function Select<T extends object>(props: SelectProps<T>, ref: ForwardedRef<HTMLD
9999
}
100100
}]
101101
]}>
102-
<div {...renderProps} ref={ref} slot={props.slot}>
103-
{props.children}
104-
</div>
102+
<div {...renderProps} ref={ref} slot={props.slot} />
105103
{portal}
106104
<HiddenSelect
107105
state={state}

packages/react-aria-components/src/Tabs.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ function Tabs(props: TabsProps, ref: ForwardedRef<HTMLDivElement>) {
124124
slot={props.slot}
125125
data-orientation={orientation}>
126126
<InternalTabsContext.Provider value={{state, setState, orientation}}>
127-
{props.children}
127+
{renderProps.children}
128128
</InternalTabsContext.Provider>
129129
</div>
130130
);

packages/react-aria-components/stories/index.stories.tsx

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {Button, Calendar, CalendarCell, CalendarGrid, Cell, Column, ComboBox, DateField, DateInput, DatePicker, DateRangePicker, DateSegment, Dialog, DialogTrigger, Group, Header, Heading, Input, Item, Keyboard, Label, ListBox, Menu, MenuTrigger, Modal, ModalOverlay, NumberField, OverlayArrow, Popover, RangeCalendar, Row, Section, Select, SelectValue, Separator, Slider, SliderOutput, SliderThumb, SliderTrack, Tab, Table, TableBody, TableHeader, TabList, TabPanel, TabPanels, Tabs, Text, TimeField, Tooltip, TooltipTrigger} from 'react-aria-components';
13+
import {Button, Calendar, CalendarCell, CalendarGrid, Cell, Column, ComboBox, DateField, DateInput, DatePicker, DateRangePicker, DateSegment, Dialog, DialogTrigger, Group, Header, Heading, Input, Item, Keyboard, Label, ListBox, Menu, MenuTrigger, Modal, ModalOverlay, NumberField, OverlayArrow, Popover, RangeCalendar, Row, Section, Select, SelectValue, Separator, Slider, SliderOutput, SliderThumb, SliderTrack, Tab, Table, TableBody, TableHeader, TabList, TabPanel, TabPanels, Tabs, TabsProps, Text, TimeField, Tooltip, TooltipTrigger} from 'react-aria-components';
1414
import {classNames} from '@react-spectrum/utils';
1515
import clsx from 'clsx';
16-
import React from 'react';
16+
import React, {useState} from 'react';
1717
import styles from '../example/index.css';
1818
import {useListData} from 'react-stately';
1919

@@ -40,6 +40,29 @@ export const ComboBoxExample = () => (
4040
</ComboBox>
4141
);
4242

43+
export const ComboBoxRenderProps = () => (
44+
<ComboBox>
45+
{({isOpen}) => (
46+
<>
47+
<Label style={{display: 'block'}}>Test</Label>
48+
<div style={{display: 'flex'}}>
49+
<Input />
50+
<Button>
51+
<span aria-hidden="true" style={{padding: '0 2px'}}>{isOpen ? '▲' : '▼'}</span>
52+
</Button>
53+
</div>
54+
<Popover placement="bottom end">
55+
<ListBox className={styles.menu}>
56+
<MyItem>Foo</MyItem>
57+
<MyItem>Bar</MyItem>
58+
<MyItem>Baz</MyItem>
59+
</ListBox>
60+
</Popover>
61+
</>
62+
)}
63+
</ComboBox>
64+
);
65+
4366
export const ListBoxExample = () => (
4467
<ListBox className={styles.menu} selectionMode="multiple" selectionBehavior="replace">
4568
<MyItem>Foo</MyItem>
@@ -100,6 +123,27 @@ export const SelectExample = () => (
100123
</Select>
101124
);
102125

126+
export const SelectRenderProps = () => (
127+
<Select>
128+
{({isOpen}) => (
129+
<>
130+
<Label style={{display: 'block'}}>Test</Label>
131+
<Button>
132+
<SelectValue />
133+
<span aria-hidden="true" style={{paddingLeft: 5}}>{isOpen ? '▲' : '▼'}</span>
134+
</Button>
135+
<Popover>
136+
<ListBox className={styles.menu}>
137+
<MyItem>Foo</MyItem>
138+
<MyItem>Bar</MyItem>
139+
<MyItem>Baz</MyItem>
140+
</ListBox>
141+
</Popover>
142+
</>
143+
)}
144+
</Select>
145+
);
146+
103147
export const MenuExample = () => (
104148
<MenuTrigger>
105149
<Button aria-label="Menu"></Button>
@@ -479,6 +523,44 @@ export const TabsExample = () => (
479523
</Tabs>
480524
);
481525

526+
export const TabsRenderProps = () => {
527+
const [tabOrientation, setTabOrientation] = useState<TabsProps['orientation']>('vertical');
528+
529+
return (
530+
<div style={{display: 'flex', flexDirection: 'row', gap: 8}}>
531+
<Button onPress={() => setTabOrientation((current) => current === 'vertical' ? 'horizontal' : 'vertical')}>
532+
Change Orientation
533+
</Button>
534+
<Tabs orientation={tabOrientation}>
535+
{({orientation}) => (
536+
<div>
537+
<div style={{display: 'flex', flexDirection: orientation === 'vertical' ? 'row' : 'column', gap: 8}}>
538+
<TabList
539+
aria-label="History of Ancient Rome"
540+
style={{display: 'flex', flexDirection: orientation === 'vertical' ? 'column' : 'row', gap: 8}}>
541+
<CustomTab id="FoR">Founding of Rome</CustomTab>
542+
<CustomTab id="MaR">Monarchy and Republic</CustomTab>
543+
<CustomTab id="Emp">Empire</CustomTab>
544+
</TabList>
545+
<TabPanels>
546+
<TabPanel id="FoR">
547+
Arma virumque cano, Troiae qui primus ab oris.
548+
</TabPanel>
549+
<TabPanel id="MaR">
550+
Senatus Populusque Romanus.
551+
</TabPanel>
552+
<TabPanel id="Emp">
553+
Alea jacta est.
554+
</TabPanel>
555+
</TabPanels>
556+
</div>
557+
</div>
558+
)}
559+
</Tabs>
560+
</div>
561+
);
562+
};
563+
482564
export const TableExample = () => {
483565
let list = useListData({
484566
initialItems: [

packages/react-aria-components/test/Breadcrumbs.test.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,20 @@ describe('Breadcrumbs', () => {
7171
expect(breadcrumbs).toHaveAttribute('slot', 'test');
7272
expect(breadcrumbs).toHaveAttribute('aria-label', 'test');
7373
});
74+
75+
it('should support dynamic collections', () => {
76+
let items = [
77+
{id: 1, name: 'Item 1'},
78+
{id: 2, name: 'Item 2'},
79+
{id: 3, name: 'Item 3'}
80+
];
81+
82+
let {getAllByRole} = render(
83+
<Breadcrumbs items={items}>
84+
{(item) => <Item>{item.name}</Item>}
85+
</Breadcrumbs>
86+
);
87+
88+
expect(getAllByRole('listitem').map((it) => it.textContent)).toEqual(['Item 1', 'Item 2', 'Item 3']);
89+
});
7490
});

0 commit comments

Comments
 (0)