Skip to content

Commit 56797c0

Browse files
committed
add nested slottable support
1 parent 36d954d commit 56797c0

File tree

6 files changed

+562
-91
lines changed

6 files changed

+562
-91
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
'use client';
2+
3+
import * as React from 'react';
4+
import { Slot } from 'radix-ui';
5+
6+
export const Link = React.forwardRef<
7+
React.ComponentRef<'a'>,
8+
React.ComponentProps<'a'> & { asChild?: boolean }
9+
>(({ asChild = false, ...props }, forwardedRef) => {
10+
const Comp = asChild ? Slot.Root : 'a';
11+
return <Comp {...props} ref={forwardedRef} />;
12+
});
13+
14+
export const LinkSlottable = React.forwardRef<
15+
React.ComponentRef<'a'>,
16+
React.ComponentProps<'a'> & { asChild?: boolean }
17+
>(({ asChild = false, ...props }, forwardedRef) => {
18+
const Comp = asChild ? Slot.Root : 'a';
19+
return (
20+
<Comp {...props} ref={forwardedRef}>
21+
<span>left</span>
22+
<Slot.Slottable>{props.children}</Slot.Slottable>
23+
<span>right</span>
24+
</Comp>
25+
);
26+
});
27+
28+
export const LinkButton = React.forwardRef<
29+
React.ComponentRef<typeof Link>,
30+
React.ComponentProps<typeof Link>
31+
>((props, forwardedRef) => (
32+
<Button asChild>
33+
<Link {...props} ref={forwardedRef}>
34+
{props.children}
35+
</Link>
36+
</Button>
37+
));
38+
39+
export const Button = React.forwardRef<
40+
React.ComponentRef<'button'>,
41+
React.ComponentProps<'button'> & { asChild?: boolean }
42+
>(({ asChild = false, ...props }, forwardedRef) => {
43+
const Comp = asChild ? Slot.Root : 'button';
44+
return <Comp {...props} ref={forwardedRef} style={{ display: 'flex', gap: '3rem' }} />;
45+
});
46+
47+
export const ButtonSlottable = React.forwardRef<
48+
React.ComponentRef<'button'>,
49+
React.ComponentProps<'button'> & { asChild?: boolean }
50+
>(({ children, asChild = false, ...props }, forwardedRef) => {
51+
const Comp = asChild ? Slot.Root : 'button';
52+
return (
53+
<Comp {...props} ref={forwardedRef} style={{ display: 'flex', gap: '3rem' }}>
54+
<span>left</span>
55+
<Slot.Slottable>{children}</Slot.Slottable>
56+
<span>right</span>
57+
</Comp>
58+
);
59+
});
60+
61+
export const ButtonNestedSlottable = React.forwardRef<
62+
React.ComponentRef<typeof Button>,
63+
React.ComponentProps<typeof Button>
64+
>(({ children, asChild = false, ...props }, forwardedRef) => {
65+
const Comp = asChild ? Slot.Root : 'button';
66+
return (
67+
<Comp {...props} ref={forwardedRef} style={{ display: 'flex', gap: '3rem' }}>
68+
<Slot.Slottable child={children}>
69+
{(slottable) => (
70+
<>
71+
<span>left</span>
72+
<b>bold {slottable}</b>
73+
<span>right</span>
74+
</>
75+
)}
76+
</Slot.Slottable>
77+
</Comp>
78+
);
79+
});
80+
81+
export const IconButtonNestedSlottable = React.forwardRef<
82+
React.ComponentRef<typeof Button>,
83+
React.ComponentProps<typeof Button>
84+
>(({ children, ...props }, forwardedRef) => {
85+
return (
86+
<Button {...props} ref={forwardedRef} style={{ display: 'flex', gap: '3rem' }}>
87+
<Slot.Root>
88+
<Slot.Slottable child={children}>
89+
{(slottable) => (
90+
<>
91+
<span>ICON</span>
92+
<b>bold {slottable}</b>
93+
</>
94+
)}
95+
</Slot.Slottable>
96+
</Slot.Root>
97+
</Button>
98+
);
99+
});

apps/ssr-testing/app/slot/page.tsx

Lines changed: 135 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,141 @@
11
import * as React from 'react';
2-
import { Slot } from 'radix-ui';
2+
import * as Client from './client';
3+
import * as Server from './server';
34

45
export default function Page() {
56
return (
6-
<Slot.Root>
7-
<span>I'm in a </span>
8-
<Slot.Slottable>
9-
<em>Slot!?</em>
10-
</Slot.Slottable>
11-
</Slot.Root>
7+
<>
8+
<p>All components should be rendered as links</p>
9+
10+
<h2>Client.LinkButton</h2>
11+
12+
<Client.LinkButton href="/">children</Client.LinkButton>
13+
14+
<h2>Client.Button as Client.Link</h2>
15+
16+
<Client.Button asChild>
17+
<Client.Link href="/">children</Client.Link>
18+
</Client.Button>
19+
20+
<h2>Client.Button as Server.Link</h2>
21+
22+
<Client.Button asChild>
23+
<Server.Link href="/">children</Server.Link>
24+
</Client.Button>
25+
26+
<h2>Client.Button as Client.LinkSlottable</h2>
27+
28+
<Client.Button asChild>
29+
<Client.LinkSlottable href="/">children</Client.LinkSlottable>
30+
</Client.Button>
31+
32+
<h2>Client.Button as Server.LinkSlottable</h2>
33+
34+
<Client.Button asChild>
35+
<Server.LinkSlottable href="/">children</Server.LinkSlottable>
36+
</Client.Button>
37+
38+
<h2>Client.ButtonSlottable as Server.Link</h2>
39+
40+
<Client.ButtonSlottable asChild>
41+
<Server.Link href="/">children</Server.Link>
42+
</Client.ButtonSlottable>
43+
44+
<h2>Client.ButtonSlottable as Client.Link</h2>
45+
46+
<Client.ButtonSlottable asChild>
47+
<Client.Link href="/">children</Client.Link>
48+
</Client.ButtonSlottable>
49+
50+
<h2>Client.ButtonNestedSlottable as Server.Link</h2>
51+
52+
<Client.ButtonNestedSlottable asChild>
53+
<Server.Link href="/">children</Server.Link>
54+
</Client.ButtonNestedSlottable>
55+
56+
<h2>Client.ButtonNestedSlottable as Client.Link</h2>
57+
58+
<Client.ButtonNestedSlottable asChild>
59+
<Client.Link href="/">children</Client.Link>
60+
</Client.ButtonNestedSlottable>
61+
62+
<h2>Client.IconButtonNestedSlottable as Server.Link</h2>
63+
64+
<Client.IconButtonNestedSlottable asChild>
65+
<Server.Link href="/">children</Server.Link>
66+
</Client.IconButtonNestedSlottable>
67+
68+
<h2>Client.IconButtonNestedSlottable as Client.Link</h2>
69+
70+
<Client.IconButtonNestedSlottable asChild>
71+
<Client.Link href="/">children</Client.Link>
72+
</Client.IconButtonNestedSlottable>
73+
74+
<hr />
75+
76+
<h2>Server.LinkButton</h2>
77+
78+
<Server.LinkButton href="/">children</Server.LinkButton>
79+
80+
<h2>Server.Button as Server.Link</h2>
81+
82+
<Server.Button asChild>
83+
<Server.Link href="/">children</Server.Link>
84+
</Server.Button>
85+
86+
<h2>Server.Button as Client.Link</h2>
87+
88+
<Server.Button asChild>
89+
<Client.Link href="/">children</Client.Link>
90+
</Server.Button>
91+
92+
<h2>Server.Button as Server.LinkSlottable</h2>
93+
94+
<Server.Button asChild>
95+
<Server.LinkSlottable href="/">children</Server.LinkSlottable>
96+
</Server.Button>
97+
98+
<h2>Server.Button as Client.LinkSlottable</h2>
99+
100+
<Server.Button asChild>
101+
<Client.LinkSlottable href="/">children</Client.LinkSlottable>
102+
</Server.Button>
103+
104+
<h2>Server.ButtonSlottable as Client.Link</h2>
105+
106+
<Server.ButtonSlottable asChild>
107+
<Client.Link href="/">children</Client.Link>
108+
</Server.ButtonSlottable>
109+
110+
<h2>Server.ButtonSlottable as Server.Link</h2>
111+
112+
<Server.ButtonSlottable asChild>
113+
<Server.Link href="/">children</Server.Link>
114+
</Server.ButtonSlottable>
115+
116+
<h2>Server.ButtonNestedSlottable as Client.Link</h2>
117+
118+
<Server.ButtonNestedSlottable asChild>
119+
<Client.Link href="/">children</Client.Link>
120+
</Server.ButtonNestedSlottable>
121+
122+
<h2>Server.ButtonNestedSlottable as Server.Link</h2>
123+
124+
<Server.ButtonNestedSlottable asChild>
125+
<Server.Link href="/">children</Server.Link>
126+
</Server.ButtonNestedSlottable>
127+
128+
<h2>Server.IconButtonNestedSlottable as Server.Link</h2>
129+
130+
<Server.IconButtonNestedSlottable asChild>
131+
<Server.Link href="/">children</Server.Link>
132+
</Server.IconButtonNestedSlottable>
133+
134+
<h2>Server.IconButtonNestedSlottable as Client.Link</h2>
135+
136+
<Server.IconButtonNestedSlottable asChild>
137+
<Client.Link href="/">children</Client.Link>
138+
</Server.IconButtonNestedSlottable>
139+
</>
12140
);
13141
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import * as React from 'react';
2+
import { Slot } from 'radix-ui';
3+
import * as Client from './client';
4+
5+
export const Link = React.forwardRef<
6+
React.ComponentRef<'a'>,
7+
React.ComponentProps<'a'> & { asChild?: boolean }
8+
>(({ asChild = false, ...props }, forwardedRef) => {
9+
const Comp = asChild ? Slot.Root : 'a';
10+
return <Comp {...props} ref={forwardedRef} />;
11+
});
12+
13+
export const LinkSlottable = React.forwardRef<
14+
React.ComponentRef<'a'>,
15+
React.ComponentProps<'a'> & { asChild?: boolean }
16+
>(({ asChild = false, ...props }, forwardedRef) => {
17+
const Comp = asChild ? Slot.Root : 'a';
18+
return (
19+
<Comp {...props} ref={forwardedRef}>
20+
<span>left</span>
21+
<Slot.Slottable>{props.children}</Slot.Slottable>
22+
<span>right</span>
23+
</Comp>
24+
);
25+
});
26+
27+
export const LinkButton = React.forwardRef<
28+
React.ComponentRef<typeof Link>,
29+
React.ComponentProps<typeof Link>
30+
>((props, forwardedRef) => (
31+
<Button asChild>
32+
<Link {...props} ref={forwardedRef}>
33+
{props.children}
34+
</Link>
35+
</Button>
36+
));
37+
38+
export const Button = React.forwardRef<
39+
React.ComponentRef<'button'>,
40+
React.ComponentProps<'button'> & { asChild?: boolean }
41+
>(({ asChild = false, ...props }, forwardedRef) => {
42+
const Comp = asChild ? Slot.Root : 'button';
43+
return <Comp {...props} ref={forwardedRef} style={{ display: 'flex', gap: '3rem' }} />;
44+
});
45+
46+
export const ButtonSlottable = React.forwardRef<
47+
React.ComponentRef<'button'>,
48+
React.ComponentProps<'button'> & { asChild?: boolean }
49+
>(({ children, asChild = false, ...props }, forwardedRef) => {
50+
const Comp = asChild ? Slot.Root : 'button';
51+
return (
52+
<Comp {...props} ref={forwardedRef} style={{ display: 'flex', gap: '3rem' }}>
53+
<span>left</span>
54+
<Slot.Slottable>{children}</Slot.Slottable>
55+
<span>right</span>
56+
</Comp>
57+
);
58+
});
59+
60+
export const ButtonNestedSlottable = React.forwardRef<
61+
React.ComponentRef<typeof Button>,
62+
React.ComponentProps<typeof Button>
63+
>(({ children, asChild = false, ...props }, forwardedRef) => {
64+
const Comp = asChild ? Slot.Root : 'button';
65+
return (
66+
<Comp {...props} ref={forwardedRef} style={{ display: 'flex', gap: '3rem' }}>
67+
<Slot.Slottable child={children}>
68+
{(slottable) => (
69+
<>
70+
<span>left</span>
71+
<b>bold {slottable}</b>
72+
<span>right</span>
73+
</>
74+
)}
75+
</Slot.Slottable>
76+
</Comp>
77+
);
78+
});
79+
80+
export const IconButtonNestedSlottable = React.forwardRef<
81+
React.ComponentRef<typeof Button>,
82+
React.ComponentProps<typeof Button>
83+
>(({ children, ...props }, forwardedRef) => {
84+
return (
85+
<Client.Button {...props} ref={forwardedRef} style={{ display: 'flex', gap: '3rem' }}>
86+
<Slot.Root>
87+
<Slot.Slottable child={children}>
88+
{(slottable) => (
89+
<>
90+
<span>ICON</span>
91+
<b>bold {slottable}</b>
92+
</>
93+
)}
94+
</Slot.Slottable>
95+
</Slot.Root>
96+
</Client.Button>
97+
);
98+
});

0 commit comments

Comments
 (0)