|
1 | | -# beqa/react-slots - Responsible React Parenting |
| 1 | +### Vite, Rollup, esbuild plugin for @beqa/react-slots |
2 | 2 |
|
3 | | -`react-slots` empowers you to prioritize composability in your component APIs. |
4 | | - |
5 | | -## Featuring |
6 | | - |
7 | | -- Composability with ease |
8 | | -- Type-safety |
9 | | -- Server Components support |
10 | | -- Not implemented with context |
11 | | -- Intuitive API |
12 | | -- Self-documenting with typescript |
13 | | -- Elegant solution to a11y attributes |
14 | | -- Inversion of control |
15 | | - |
16 | | -## Docs |
17 | | - |
18 | | -You can find the docs on the |
19 | | -[docs website](https://react-slots-docs.vercel.app/) |
20 | | - |
21 | | -## Simple Example: Implementing |
22 | | - |
23 | | -```jsx |
24 | | -import { useSlot, SlotChildren, Slot } from "@beqa/react-slots"; |
25 | | - |
26 | | -type ListItemProps = { |
27 | | - children: SlotChildren< |
28 | | - | Slot<"title"> // Shorthand of Slot<"title", {}> |
29 | | - | Slot<"thumbnail"> // Shorthand of Slot<"thumbnail", {}> |
30 | | - | Slot<{ isExpanded: boolean }> // Shorthand of Slot<"default", {isExpanded: boolean}> |
31 | | - >; |
32 | | -} |
33 | | - |
34 | | -function ListItem({ children }: ListItemProps) { |
35 | | - const { slot } = useSlot(children); |
36 | | - const [isExpanded, setIsExpanded] = useState(); |
37 | | - |
38 | | - return ( |
39 | | - <li |
40 | | - className={`${isExpanded ? "expanded" : "collapsed"}`} |
41 | | - onClick={() => setIsExpanded(!isExpanded)} |
42 | | - > |
43 | | - {/* Render thumbnail if provided, otherwise nothing*/} |
44 | | - <slot.thumbnail /> |
45 | | - <div> |
46 | | - {/* Render a fallback if title is not provided*/} |
47 | | - <slot.title>Expand for more</slot.title> |
48 | | - {/* Render the description and pass the prop up to the parent */} |
49 | | - <slot.default isExpanded={isExpanded} /> |
50 | | - </div> |
51 | | - </li> |
52 | | - ); |
53 | | -} |
54 | | -``` |
55 | | - |
56 | | -## Simple Example: Specifying Slot Content From the Parent |
57 | | - |
58 | | -### With `slot-name` Attribute |
59 | | - |
60 | | -```jsx |
61 | | -<ListItem> |
62 | | - <img slot-name="thumbnail" src="..." /> |
63 | | - <div slot-name="title">A title</div> |
64 | | - this is a description |
65 | | -</ListItem> |
66 | | -``` |
67 | | - |
68 | | -### With Templates |
69 | | - |
70 | | -```jsx |
71 | | -import { template } from "beqa/react-slots"; |
72 | | - |
73 | | -<ListItem> |
74 | | - <template.thumbnail> |
75 | | - <img src=".." /> |
76 | | - </template.thumbnail> |
77 | | - <template.title>A title</template.title> |
78 | | - <template.description> |
79 | | - {({ isExpanded }) => |
80 | | - isExpanded ? <strong>A description</strong> : "A description" |
81 | | - } |
82 | | - </template.description> |
83 | | - <template.description>doesn't have to be a function</template.description> |
84 | | -</ListItem>; |
85 | | -``` |
86 | | -
|
87 | | -### With Type-safe Templates |
88 | | -
|
89 | | -```tsx |
90 | | -// Option #1 |
91 | | -import { createTemplate } from "@beqa/react-slots"; |
92 | | -const template = createTemplate<ListItemProps["children"]>(); |
93 | | -
|
94 | | -// Option #2 |
95 | | -import { template, CreateTemplate } from "@beqa/react-slots"; |
96 | | -const template = template as CreateTemplate<ListItemProps["children"]>; |
97 | | -
|
98 | | -// Typo-free and auto-complete for props! |
99 | | -<ListItem> |
100 | | - <template.thumbnail> |
101 | | - <img src="..." /> |
102 | | - </template.thumbnail> |
103 | | - <template.title>A title</template.title> |
104 | | - <template.description> |
105 | | - {({ isExpanded }) => |
106 | | - isExpanded ? <strong>A description</strong> : "A description" |
107 | | - } |
108 | | - </template.description> |
109 | | - <template.description>doesn't have to be a function</template.description> |
110 | | -</ListItem>; |
111 | | -``` |
112 | | - |
113 | | -## Advanced Examples |
114 | | - |
115 | | -| The code samples below represent actual implementations. No need to define external state or event handlers for these components to function. | |
116 | | -| --------------------------------------------------------------------------------------------------------------------------------------------- | |
117 | | - |
118 | | -#### Creating highly composable `Accordion` and `AccordionList` components using react-slots |
119 | | - |
120 | | -Checkout |
121 | | -[live example](https://stackblitz.com/edit/stackblitz-starters-tq32ef?file=pages%2Findex.tsx) |
122 | | - |
123 | | -```jsx |
124 | | -<AccordionList> |
125 | | - <Accordion key={1}> |
126 | | - <span slot-name="summary">First Accordion</span> |
127 | | - This part of Accordion is hidden |
128 | | - </Accordion> |
129 | | - <Accordion key={2}> |
130 | | - <span slot-name="summary">Second Accordion</span> |
131 | | - AccordionList makes it so that only one Accordion is open at a time |
132 | | - </Accordion> |
133 | | - <Accordion key={3}> |
134 | | - <span slot-name="summary">Third Accordion</span> |
135 | | - No external state required |
136 | | - </Accordion> |
137 | | -</AccordionList> |
138 | | -``` |
139 | | - |
140 | | -#### Creating highly composable `Dialog` and `DialogTrigger` components using react-slots |
141 | | - |
142 | | -Checkout |
143 | | -[live example](https://stackblitz.com/edit/stackblitz-starters-fa5wbe?file=pages%2Findex.tsx) |
144 | | - |
145 | | -```jsx |
146 | | -<DialogTrigger> |
147 | | - <Button>Trigger Dialog</Button> |
148 | | - <Dialog slot-name="dialog"> |
149 | | - <span slot-name="title">Look Ma, No External State</span> |
150 | | - <p slot-name="content">... And no event handlers.</p> |
151 | | - <p slot-name="content">Closes automatically on button click.</p> |
152 | | - <p slot-name="content">Can work with external state if desired.</p> |
153 | | - <Button |
154 | | - slot-name="secondary" |
155 | | - onClick={() => alert("But how are the button variants different?")} |
156 | | - > |
157 | | - Close?? |
158 | | - </Button> |
159 | | - <Button slot-name="primary">Close!</Button> |
160 | | - </Dialog> |
161 | | -</DialogTrigger> |
162 | | -``` |
163 | | - |
164 | | -If you like this project please show support by starring it on |
165 | | -[Github](https://github.com/Flammae/react-slots) |
| 3 | +Read the [@beqa/react-slots docs](https://github.com/Flammae/react-slots) |
0 commit comments