@k8ordo/ui 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -12
- package/dist/components/ai/conversation/conversation.d.mts +8 -10
- package/dist/components/ai/conversation/conversation.mjs +1 -6
- package/dist/components/ai/conversation/index.d.mts +15 -1
- package/dist/components/ai/conversation/index.mjs +8 -1
- package/dist/components/ai/index.d.mts +5 -9
- package/dist/components/ai/index.mjs +4 -4
- package/dist/components/ai/message/index.d.mts +12 -1
- package/dist/components/ai/message/index.mjs +7 -1
- package/dist/components/ai/message/message.d.mts +3 -5
- package/dist/components/ai/message/message.mjs +1 -5
- package/dist/components/ai/prompt-input/index.d.mts +23 -1
- package/dist/components/ai/prompt-input/index.mjs +8 -1
- package/dist/components/ai/prompt-input/prompt-input.d.mts +4 -6
- package/dist/components/ai/prompt-input/prompt-input.mjs +1 -6
- package/dist/components/ai/suggestion/index.d.mts +13 -1
- package/dist/components/ai/suggestion/index.mjs +7 -1
- package/dist/components/ai/suggestion/suggestion.d.mts +3 -5
- package/dist/components/ai/suggestion/suggestion.mjs +1 -5
- package/dist/components/buttons/icon-button/icon-button.mjs +1 -1
- package/dist/components/form/checkbox/checkbox.d.mts +1 -0
- package/dist/components/form/checkbox/checkbox.mjs +3 -2
- package/dist/components/form/checkbox-group/index.d.mts +1 -0
- package/dist/components/form/file-field/file-field.d.mts +12 -15
- package/dist/components/form/file-field/file-field.mjs +1 -6
- package/dist/components/form/file-field/index.d.mts +17 -1
- package/dist/components/form/file-field/index.mjs +8 -1
- package/dist/components/form/radio/radio.d.mts +1 -0
- package/dist/components/form/radio/radio.mjs +3 -2
- package/dist/components/index.d.mts +15 -21
- package/dist/components/index.mjs +7 -7
- package/dist/components/navigation/anchor/anchor.mjs +1 -1
- package/dist/components/navigation/tabs/index.d.mts +19 -1
- package/dist/components/navigation/tabs/index.mjs +9 -1
- package/dist/components/navigation/tabs/tabs.d.mts +16 -18
- package/dist/components/navigation/tabs/tabs.mjs +1 -7
- package/dist/components/overlays/dialog/dialog.d.mts +12 -16
- package/dist/components/overlays/dialog/dialog.mjs +1 -6
- package/dist/components/overlays/dialog/index.d.mts +17 -1
- package/dist/components/overlays/dialog/index.mjs +8 -1
- package/dist/components/overlays/dropdown-menu/dropdown-menu.d.mts +20 -24
- package/dist/components/overlays/dropdown-menu/dropdown-menu.mjs +2 -11
- package/dist/components/overlays/dropdown-menu/index.d.mts +31 -1
- package/dist/components/overlays/dropdown-menu/index.mjs +12 -1
- package/dist/components/overlays/dropdown-menu/sub-menu.mjs +1 -1
- package/dist/components/overlays/list-box/index.d.mts +27 -1
- package/dist/components/overlays/list-box/index.mjs +9 -1
- package/dist/components/overlays/list-box/list-box.d.mts +20 -22
- package/dist/components/overlays/list-box/list-box.mjs +2 -8
- package/dist/components/overlays/popover/index.d.mts +24 -1
- package/dist/components/overlays/popover/index.mjs +8 -1
- package/dist/components/overlays/popover/popover.d.mts +18 -20
- package/dist/components/overlays/popover/popover.mjs +2 -7
- package/dist/components/overlays/tooltip/index.d.mts +21 -1
- package/dist/components/overlays/tooltip/index.mjs +8 -1
- package/dist/components/overlays/tooltip/tooltip.d.mts +18 -22
- package/dist/components/overlays/tooltip/tooltip.mjs +2 -7
- package/dist/hooks/index.d.mts +1 -4
- package/dist/hooks/index.mjs +2 -5
- package/dist/index.d.mts +13 -15
- package/dist/index.mjs +9 -12
- package/dist/integrations/_shared/renderers.mjs +7 -7
- package/dist/integrations/_shared/schemas.d.mts +1 -1
- package/dist/{hooks/focus-trap/index.d.mts → internal/focus-trap.d.mts} +1 -1
- package/dist/{hooks/focus-trap/index.mjs → internal/focus-trap.mjs} +1 -1
- package/dist/styles/index.css +0 -8
- package/docs/GUIDE.md +148 -133
- package/docs/llms.txt +11 -7
- package/docs/props.generated.json +18 -0
- package/docs/references/ai-chat.md +67 -67
- package/docs/references/color.md +108 -107
- package/docs/references/components.md +318 -310
- package/docs/references/generative-ui.md +51 -30
- package/docs/references/helpers.md +155 -52
- package/docs/references/hooks.md +61 -74
- package/docs/references/interaction-design.md +47 -47
- package/docs/references/spatial-design.md +83 -81
- package/docs/references/typography.md +68 -67
- package/package.json +32 -33
- package/dist/hooks/hash/index.d.mts +0 -4
- package/dist/hooks/hash/index.mjs +0 -25
- package/dist/hooks/local-storage/index.d.mts +0 -4
- package/dist/hooks/local-storage/index.mjs +0 -46
- package/dist/hooks/session-storage/index.d.mts +0 -4
- package/dist/hooks/session-storage/index.mjs +0 -46
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
# k8ordo
|
|
1
|
+
# @k8ordo/ui component catalog
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## Importing
|
|
4
4
|
|
|
5
5
|
```tsx
|
|
6
|
-
//
|
|
7
|
-
//
|
|
6
|
+
// The stylesheet (required). In a Tailwind CSS 4 project,
|
|
7
|
+
// import '@k8ordo/ui/tailwind.css' instead
|
|
8
8
|
import '@k8ordo/ui/styles.css';
|
|
9
9
|
|
|
10
|
-
//
|
|
10
|
+
// The provider (once, at the app root)
|
|
11
11
|
import { UIProvider } from '@k8ordo/ui';
|
|
12
12
|
|
|
13
|
-
//
|
|
13
|
+
// Components (all from the root entry)
|
|
14
14
|
import { Button, Card, TextField } from '@k8ordo/ui';
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Every component can be rendered from a Server Component, compound ones
|
|
18
|
+
included: `Dialog.Root`, `Tabs.Root`, `Popover.Trigger`, and the rest are
|
|
19
|
+
composed outside the client modules, so the parts resolve on the server. Only
|
|
20
|
+
the interactive parts carry `'use client'`.
|
|
21
|
+
|
|
22
|
+
## Buttons and links
|
|
18
23
|
|
|
19
24
|
### Button
|
|
20
25
|
|
|
@@ -31,25 +36,25 @@ import { Button } from '@k8ordo/ui';
|
|
|
31
36
|
disabled={false}
|
|
32
37
|
isActive={false}
|
|
33
38
|
>
|
|
34
|
-
|
|
39
|
+
Button
|
|
35
40
|
</Button>
|
|
36
41
|
```
|
|
37
42
|
|
|
38
43
|
Props:
|
|
39
44
|
|
|
40
45
|
- `children`: `ReactNode`
|
|
41
|
-
- `color`: `'primary'` | `'secondary'` | `'base'
|
|
46
|
+
- `color`: `'primary'` | `'secondary'` | `'base'` (default: `'primary'`)
|
|
42
47
|
- `endIcon`: `ReactNode`
|
|
43
|
-
- `fullWidth`: `boolean
|
|
44
|
-
- `isActive`: `boolean
|
|
48
|
+
- `fullWidth`: `boolean` (default: `false`)
|
|
49
|
+
- `isActive`: `boolean` (default: `false`)
|
|
45
50
|
- `onAction`: `() => void | Promise<void>`
|
|
46
51
|
- `renderItem`: `(props: { className: string; children: ReactNode }) => ReactNode`
|
|
47
|
-
- `size`: `'sm'` | `'md'` | `'lg'
|
|
52
|
+
- `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
|
|
48
53
|
- `startIcon`: `ReactNode`
|
|
49
|
-
- `type`: `'button'` | `'submit'
|
|
50
|
-
- `variant`: `'solid'` | `'outline'` | `'skeleton'
|
|
54
|
+
- `type`: `'button'` | `'submit'` (default: `'button'`)
|
|
55
|
+
- `variant`: `'solid'` | `'outline'` | `'skeleton'` (default: `'solid'`)
|
|
51
56
|
|
|
52
|
-
|
|
57
|
+
Use the `renderItem` prop to render it as a link. The same applies to things like Next.js's `<Link>`.
|
|
53
58
|
|
|
54
59
|
```tsx
|
|
55
60
|
<Button
|
|
@@ -61,39 +66,39 @@ Props:
|
|
|
61
66
|
</a>
|
|
62
67
|
)}
|
|
63
68
|
>
|
|
64
|
-
|
|
69
|
+
Link
|
|
65
70
|
</Button>
|
|
66
71
|
```
|
|
67
72
|
|
|
68
73
|
### IconButton
|
|
69
74
|
|
|
70
|
-
|
|
75
|
+
An icon-only button. Styling is controlled by the `color` prop.
|
|
71
76
|
|
|
72
77
|
```tsx
|
|
73
78
|
import { IconButton } from '@k8ordo/ui';
|
|
74
79
|
|
|
75
|
-
<IconButton label="
|
|
80
|
+
<IconButton label="Close" color="transparent" size="md">
|
|
76
81
|
<CloseIcon />
|
|
77
82
|
</IconButton>;
|
|
78
83
|
```
|
|
79
84
|
|
|
80
85
|
Props:
|
|
81
86
|
|
|
82
|
-
- `label`: `string
|
|
87
|
+
- `label`: `string` (required)
|
|
83
88
|
- `children`: `ReactNode`
|
|
84
|
-
- `color`: `'transparent'` | `'base'` | `'primary'` | `'secondary'
|
|
89
|
+
- `color`: `'transparent'` | `'base'` | `'primary'` | `'secondary'` (default: `'transparent'`)
|
|
85
90
|
- `onAction`: `() => void | Promise<void>`
|
|
86
91
|
- `renderItem`: `(props: { className: string; children: ReactNode; 'aria-label': string; triggerProps: IconButtonTriggerProps; }) => ReactNode`
|
|
87
|
-
- `size`: `'sm'` | `'md'` | `'lg'
|
|
88
|
-
- `tooltipDisabled`: `boolean
|
|
89
|
-
- `tooltipPlacement`: `Placement
|
|
92
|
+
- `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
|
|
93
|
+
- `tooltipDisabled`: `boolean` (default: `false`)
|
|
94
|
+
- `tooltipPlacement`: `Placement` (default: `'top'`)
|
|
90
95
|
|
|
91
|
-
|
|
96
|
+
Use the `renderItem` prop to render it as a link. Spreading `triggerProps` onto the `<a>` shows `label` as a tooltip on hover and focus.
|
|
92
97
|
|
|
93
98
|
```tsx
|
|
94
99
|
<IconButton
|
|
95
100
|
color="base"
|
|
96
|
-
label="
|
|
101
|
+
label="Mail"
|
|
97
102
|
renderItem={({
|
|
98
103
|
className,
|
|
99
104
|
children,
|
|
@@ -116,36 +121,36 @@ Props:
|
|
|
116
121
|
|
|
117
122
|
### Anchor
|
|
118
123
|
|
|
119
|
-
|
|
124
|
+
A text link. External links automatically get a new-tab icon.
|
|
120
125
|
|
|
121
126
|
```tsx
|
|
122
127
|
import { Anchor } from '@k8ordo/ui';
|
|
123
128
|
|
|
124
|
-
<Anchor href="https://example.com"
|
|
125
|
-
<Anchor href="/about"
|
|
126
|
-
<Anchor href="/docs" openInNewTab
|
|
129
|
+
<Anchor href="https://example.com">External link</Anchor>
|
|
130
|
+
<Anchor href="/about">Internal link</Anchor>
|
|
131
|
+
<Anchor href="/docs" openInNewTab>Open in a new tab</Anchor>
|
|
127
132
|
```
|
|
128
133
|
|
|
129
134
|
Props:
|
|
130
135
|
|
|
131
|
-
- `children`: `ReactNode
|
|
132
|
-
- `href`: `T
|
|
133
|
-
- `openInNewTab`: `boolean
|
|
134
|
-
- `renderAnchor`: `(props: RenderAnchorProps<T>) => ReactNode
|
|
136
|
+
- `children`: `ReactNode` (required)
|
|
137
|
+
- `href`: `T` (required)
|
|
138
|
+
- `openInNewTab`: `boolean` (default: `false`)
|
|
139
|
+
- `renderAnchor`: `(props: RenderAnchorProps<T>) => ReactNode` (default: `defaultRenderAnchor`)
|
|
135
140
|
|
|
136
|
-
##
|
|
141
|
+
## Layout and navigation
|
|
137
142
|
|
|
138
143
|
### Accordion
|
|
139
144
|
|
|
140
|
-
|
|
145
|
+
A collapsible section, as a compound component.
|
|
141
146
|
|
|
142
147
|
```tsx
|
|
143
148
|
import { Accordion } from '@k8ordo/ui';
|
|
144
149
|
|
|
145
150
|
<Accordion.Root>
|
|
146
151
|
<Accordion.Item>
|
|
147
|
-
<Accordion.Button
|
|
148
|
-
<Accordion.Panel
|
|
152
|
+
<Accordion.Button>Section 1</Accordion.Button>
|
|
153
|
+
<Accordion.Panel>Content</Accordion.Panel>
|
|
149
154
|
</Accordion.Item>
|
|
150
155
|
</Accordion.Root>;
|
|
151
156
|
```
|
|
@@ -157,7 +162,7 @@ Props (Accordion.Button):
|
|
|
157
162
|
Props (Accordion.Item):
|
|
158
163
|
|
|
159
164
|
- `children`: `ReactNode`
|
|
160
|
-
- `defaultOpen`: `boolean
|
|
165
|
+
- `defaultOpen`: `boolean` (default: `false`)
|
|
161
166
|
- `isOpen`: `boolean`
|
|
162
167
|
- `onChange`: `(isOpen: boolean) => void`
|
|
163
168
|
|
|
@@ -171,23 +176,23 @@ Props (Accordion.Root):
|
|
|
171
176
|
|
|
172
177
|
### Breadcrumb
|
|
173
178
|
|
|
174
|
-
|
|
179
|
+
A breadcrumb trail, as a compound component.
|
|
175
180
|
|
|
176
181
|
```tsx
|
|
177
182
|
import { Breadcrumb } from '@k8ordo/ui';
|
|
178
183
|
|
|
179
184
|
<Breadcrumb.List>
|
|
180
185
|
<Breadcrumb.Item>
|
|
181
|
-
<Breadcrumb.Link href="/"
|
|
186
|
+
<Breadcrumb.Link href="/">Home</Breadcrumb.Link>
|
|
182
187
|
</Breadcrumb.Item>
|
|
183
188
|
<Breadcrumb.Separator />
|
|
184
189
|
<Breadcrumb.Item>
|
|
185
|
-
<Breadcrumb.Link href="/products"
|
|
190
|
+
<Breadcrumb.Link href="/products">Products</Breadcrumb.Link>
|
|
186
191
|
</Breadcrumb.Item>
|
|
187
192
|
<Breadcrumb.Separator />
|
|
188
193
|
<Breadcrumb.Item>
|
|
189
194
|
<Breadcrumb.Link href="/products/1" current>
|
|
190
|
-
|
|
195
|
+
Details
|
|
191
196
|
</Breadcrumb.Link>
|
|
192
197
|
</Breadcrumb.Item>
|
|
193
198
|
</Breadcrumb.List>;
|
|
@@ -196,14 +201,14 @@ import { Breadcrumb } from '@k8ordo/ui';
|
|
|
196
201
|
Props (Breadcrumb.List):
|
|
197
202
|
|
|
198
203
|
- `children`: `ReactNode`
|
|
199
|
-
- `size`: `'sm'` | `'md'` | `'lg'
|
|
204
|
+
- `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
|
|
200
205
|
|
|
201
206
|
Props (Breadcrumb.Link):
|
|
202
207
|
|
|
203
|
-
- `href`: `T
|
|
208
|
+
- `href`: `T` (required)
|
|
204
209
|
- `children`: `ReactNode`
|
|
205
|
-
- `current`: `boolean
|
|
206
|
-
- `renderAnchor`: `(props: RenderBreadcrumbAnchorProps<T>) => ReactNode
|
|
210
|
+
- `current`: `boolean` (default: `false`)
|
|
211
|
+
- `renderAnchor`: `(props: RenderBreadcrumbAnchorProps<T>) => ReactNode` (default: `defaultRenderBreadcrumbAnchor`)
|
|
207
212
|
|
|
208
213
|
Props (Breadcrumb.Item):
|
|
209
214
|
|
|
@@ -211,7 +216,7 @@ Props (Breadcrumb.Item):
|
|
|
211
216
|
|
|
212
217
|
### Pagination
|
|
213
218
|
|
|
214
|
-
|
|
219
|
+
Pagination. It shows previous/next buttons and the current page only — there is no list of page numbers.
|
|
215
220
|
|
|
216
221
|
```tsx
|
|
217
222
|
import { Pagination } from '@k8ordo/ui';
|
|
@@ -221,83 +226,83 @@ import { Pagination } from '@k8ordo/ui';
|
|
|
221
226
|
|
|
222
227
|
Props:
|
|
223
228
|
|
|
224
|
-
- `currentPage`: `number
|
|
225
|
-
- `onChange`: `(page: number) => void
|
|
226
|
-
- `totalPages`: `number
|
|
229
|
+
- `currentPage`: `number` (required)
|
|
230
|
+
- `onChange`: `(page: number) => void` (required)
|
|
231
|
+
- `totalPages`: `number` (required)
|
|
227
232
|
- `aria-label`: `string`
|
|
228
|
-
- `disabled`: `boolean
|
|
233
|
+
- `disabled`: `boolean` (default: `false`)
|
|
229
234
|
- `nextLabel`: `string`
|
|
230
235
|
- `prevLabel`: `string`
|
|
231
236
|
- `ref`: `Ref<HTMLElement>`
|
|
232
237
|
|
|
233
238
|
### Tabs
|
|
234
239
|
|
|
235
|
-
|
|
240
|
+
Tab switching, as a compound component.
|
|
236
241
|
|
|
237
242
|
```tsx
|
|
238
243
|
import { Tabs } from '@k8ordo/ui';
|
|
239
244
|
|
|
240
245
|
<Tabs.Root ids={['tab1', 'tab2']}>
|
|
241
|
-
<Tabs.List label="
|
|
242
|
-
<Tabs.Tab id="tab1"
|
|
243
|
-
<Tabs.Tab id="tab2"
|
|
246
|
+
<Tabs.List label="Tabs">
|
|
247
|
+
<Tabs.Tab id="tab1">Tab 1</Tabs.Tab>
|
|
248
|
+
<Tabs.Tab id="tab2">Tab 2</Tabs.Tab>
|
|
244
249
|
</Tabs.List>
|
|
245
|
-
<Tabs.Panel id="tab1"
|
|
246
|
-
<Tabs.Panel id="tab2"
|
|
250
|
+
<Tabs.Panel id="tab1">Panel 1</Tabs.Panel>
|
|
251
|
+
<Tabs.Panel id="tab2">Panel 2</Tabs.Panel>
|
|
247
252
|
</Tabs.Root>;
|
|
248
253
|
```
|
|
249
254
|
|
|
250
255
|
Props (Tabs.Root):
|
|
251
256
|
|
|
252
|
-
- `ids`: `[string, ...string[]]
|
|
257
|
+
- `ids`: `[string, ...string[]]` (required)
|
|
253
258
|
- `children`: `ReactNode`
|
|
254
|
-
- `defaultSelectedId`: `string` | `null
|
|
259
|
+
- `defaultSelectedId`: `string` | `null` (default: `null`)
|
|
255
260
|
- `onChange`: `(id: string) => void`
|
|
256
261
|
- `selectedId`: `string`
|
|
257
262
|
|
|
258
263
|
Props (Tabs.List):
|
|
259
264
|
|
|
260
|
-
- `label`: `string
|
|
265
|
+
- `label`: `string` (required)
|
|
261
266
|
- `children`: `ReactNode`
|
|
262
267
|
|
|
263
268
|
Props (Tabs.Panel):
|
|
264
269
|
|
|
265
|
-
- `id`: `string
|
|
270
|
+
- `id`: `string` (required)
|
|
266
271
|
- `children`: `ReactNode`
|
|
267
272
|
|
|
268
273
|
Props (Tabs.Tab):
|
|
269
274
|
|
|
270
|
-
- `id`: `string
|
|
275
|
+
- `id`: `string` (required)
|
|
271
276
|
- `children`: `ReactNode`
|
|
272
277
|
|
|
273
278
|
### Card
|
|
274
279
|
|
|
275
|
-
|
|
280
|
+
A card that groups content.
|
|
276
281
|
|
|
277
282
|
```tsx
|
|
278
283
|
import { Card } from '@k8ordo/ui';
|
|
279
284
|
|
|
280
|
-
//
|
|
285
|
+
// Static card
|
|
281
286
|
<Card width="full" variant="shadow">
|
|
282
|
-
<div className="p-6"
|
|
287
|
+
<div className="p-6">Content</div>
|
|
283
288
|
</Card>
|
|
284
289
|
|
|
285
|
-
//
|
|
290
|
+
// Clickable card (hover:scale-[1.02], active:scale-[0.98])
|
|
286
291
|
<Card variant="outline" interactive>
|
|
287
|
-
<div className="p-6"
|
|
292
|
+
<div className="p-6">Content</div>
|
|
288
293
|
</Card>
|
|
289
294
|
```
|
|
290
295
|
|
|
291
296
|
Props:
|
|
292
297
|
|
|
293
298
|
- `children`: `ReactNode`
|
|
294
|
-
- `interactive`: `boolean
|
|
295
|
-
- `variant`: `'shadow'` | `'outline'
|
|
296
|
-
- `width`: `'full'` | `'fit'
|
|
299
|
+
- `interactive`: `boolean` (default: `false`)
|
|
300
|
+
- `variant`: `'shadow'` | `'outline'` (default: `'shadow'`)
|
|
301
|
+
- `width`: `'full'` | `'fit'` (default: `'full'`)
|
|
297
302
|
|
|
298
303
|
### Separator
|
|
299
304
|
|
|
300
|
-
|
|
305
|
+
A dividing rule.
|
|
301
306
|
|
|
302
307
|
```tsx
|
|
303
308
|
import { Separator } from '@k8ordo/ui';
|
|
@@ -310,12 +315,12 @@ import { Separator } from '@k8ordo/ui';
|
|
|
310
315
|
|
|
311
316
|
Props:
|
|
312
317
|
|
|
313
|
-
- `color`: `'base'` | `'mute'` | `'subtle'
|
|
314
|
-
- `orientation`: `'horizontal'` | `'vertical'
|
|
318
|
+
- `color`: `'base'` | `'mute'` | `'subtle'` (default: `'base'`)
|
|
319
|
+
- `orientation`: `'horizontal'` | `'vertical'` (default: `'horizontal'`)
|
|
315
320
|
|
|
316
321
|
### ScrollLinked
|
|
317
322
|
|
|
318
|
-
|
|
323
|
+
Shows scroll progress as a progress bar.
|
|
319
324
|
|
|
320
325
|
```tsx
|
|
321
326
|
import { ScrollLinked } from '@k8ordo/ui';
|
|
@@ -330,7 +335,7 @@ Props:
|
|
|
330
335
|
|
|
331
336
|
### Stack
|
|
332
337
|
|
|
333
|
-
|
|
338
|
+
Lays children out along one axis. Pick `gap` from the spacing tokens.
|
|
334
339
|
|
|
335
340
|
```tsx
|
|
336
341
|
import { Stack } from '@k8ordo/ui';
|
|
@@ -341,8 +346,8 @@ import { Stack } from '@k8ordo/ui';
|
|
|
341
346
|
</Stack>
|
|
342
347
|
|
|
343
348
|
<Stack direction="row" justify="between" align="center">
|
|
344
|
-
<Heading level="h2"
|
|
345
|
-
<Button
|
|
349
|
+
<Heading level="h2">Title</Heading>
|
|
350
|
+
<Button>Action</Button>
|
|
346
351
|
</Stack>
|
|
347
352
|
```
|
|
348
353
|
|
|
@@ -350,14 +355,14 @@ Props:
|
|
|
350
355
|
|
|
351
356
|
- `align`: `'start'` | `'center'` | `'end'` | `'stretch'`
|
|
352
357
|
- `children`: `ReactNode`
|
|
353
|
-
- `direction`: `'row'` | `'column'
|
|
354
|
-
- `gap`: `GapSize
|
|
358
|
+
- `direction`: `'row'` | `'column'` (default: `'column'`)
|
|
359
|
+
- `gap`: `GapSize` (default: `'md'`)
|
|
355
360
|
- `justify`: `'start'` | `'center'` | `'end'` | `'between'`
|
|
356
361
|
- `padding`: `PaddingSize`
|
|
357
362
|
|
|
358
363
|
### Grid
|
|
359
364
|
|
|
360
|
-
|
|
365
|
+
A grid layout. Passing `'auto-fill'` or `'auto-fit'` to `cols` wraps with `minItemSize` as the lower bound.
|
|
361
366
|
|
|
362
367
|
```tsx
|
|
363
368
|
import { Grid } from '@k8ordo/ui';
|
|
@@ -378,49 +383,49 @@ import { Grid } from '@k8ordo/ui';
|
|
|
378
383
|
Props:
|
|
379
384
|
|
|
380
385
|
- `children`: `ReactNode`
|
|
381
|
-
- `cols`: `1` | `2` | `3` | `4` | `5` | `6` | `'auto-fill'` | `'auto-fit'
|
|
382
|
-
- `gap`: `GapSize
|
|
383
|
-
- `minItemSize`: `24` | `32` | `40` | `48` | `64` | `80
|
|
386
|
+
- `cols`: `1` | `2` | `3` | `4` | `5` | `6` | `'auto-fill'` | `'auto-fit'` (default: `'auto-fill'`)
|
|
387
|
+
- `gap`: `GapSize` (default: `'md'`)
|
|
388
|
+
- `minItemSize`: `24` | `32` | `40` | `48` | `64` | `80` (default: `48`)
|
|
384
389
|
|
|
385
|
-
##
|
|
390
|
+
## Forms
|
|
386
391
|
|
|
387
|
-
|
|
392
|
+
Form components are used together with `FormControl`'s `renderInput` pattern. Every form component supports both controlled and uncontrolled use.
|
|
388
393
|
|
|
389
|
-
`ref`
|
|
394
|
+
`ref` reaches the real element (`input` / `textarea` / `select` / `fieldset`). `Textarea` and `FileField` use a ref internally but compose it with yours, so `react-hook-form`'s `register()` and the like can be passed straight through. `Radio` (a group that renders several inputs) and `FormControl` (a wrapper) do not take a `ref`.
|
|
390
395
|
|
|
391
396
|
### Form
|
|
392
397
|
|
|
393
|
-
`<form
|
|
398
|
+
A wrapper for `<form>`. `action` accepts a Server Action (`(formData) => …`) or a URL string.
|
|
394
399
|
|
|
395
400
|
```tsx
|
|
396
401
|
import { Button, Form, FormControl, TextField } from '@k8ordo/ui';
|
|
397
402
|
|
|
398
403
|
<Form action={submitAction}>
|
|
399
404
|
<FormControl
|
|
400
|
-
label="
|
|
405
|
+
label="Email"
|
|
401
406
|
required
|
|
402
407
|
renderInput={(props) => <TextField {...props} name="email" />}
|
|
403
408
|
/>
|
|
404
|
-
<Button type="submit"
|
|
409
|
+
<Button type="submit">Submit</Button>
|
|
405
410
|
</Form>;
|
|
406
411
|
```
|
|
407
412
|
|
|
408
413
|
Props:
|
|
409
414
|
|
|
410
|
-
- `children`: `ReactNode
|
|
415
|
+
- `children`: `ReactNode` (required)
|
|
411
416
|
- `action`: `((formData: FormData) => void | Promise<void>)` | `string`
|
|
412
417
|
|
|
413
418
|
### FormControl
|
|
414
419
|
|
|
415
|
-
|
|
420
|
+
A wrapper for a form field. It unifies the label, help text, and error display.
|
|
416
421
|
|
|
417
422
|
```tsx
|
|
418
423
|
import { FormControl, TextField } from '@k8ordo/ui';
|
|
419
424
|
|
|
420
425
|
<FormControl
|
|
421
|
-
label="
|
|
422
|
-
errorText="
|
|
423
|
-
helpText="
|
|
426
|
+
label="Email address"
|
|
427
|
+
errorText="This field is required"
|
|
428
|
+
helpText="Enter your work email address"
|
|
424
429
|
required
|
|
425
430
|
renderInput={(props) => (
|
|
426
431
|
<TextField {...props} placeholder="example@mail.com" />
|
|
@@ -430,19 +435,19 @@ import { FormControl, TextField } from '@k8ordo/ui';
|
|
|
430
435
|
|
|
431
436
|
Props:
|
|
432
437
|
|
|
433
|
-
- `label`: `string
|
|
434
|
-
- `renderInput`: `(props: { id: string; 'aria-describedby': string | undefined; 'aria-labelledby': string; disabled: boolean; invalid: boolean; required: boolean; }) => ReactElement
|
|
435
|
-
- `disabled`: `boolean
|
|
438
|
+
- `label`: `string` (required)
|
|
439
|
+
- `renderInput`: `(props: { id: string; 'aria-describedby': string | undefined; 'aria-labelledby': string; disabled: boolean; invalid: boolean; required: boolean; }) => ReactElement` (required)
|
|
440
|
+
- `disabled`: `boolean` (default: `false`)
|
|
436
441
|
- `errorText`: `string`
|
|
437
442
|
- `helpText`: `string`
|
|
438
|
-
- `invalid`: `boolean
|
|
439
|
-
- `labelAs`: `'label'` | `'legend'
|
|
443
|
+
- `invalid`: `boolean` (default: `false`)
|
|
444
|
+
- `labelAs`: `'label'` | `'legend'` (default: `'label'`)
|
|
440
445
|
- `ref`: `Ref<HTMLElement>`
|
|
441
|
-
- `required`: `boolean
|
|
446
|
+
- `required`: `boolean` (default: `false`)
|
|
442
447
|
|
|
443
|
-
`renderInput`
|
|
448
|
+
`renderInput` receives `{ id, 'aria-describedby', 'aria-labelledby', disabled, invalid, required }`.
|
|
444
449
|
|
|
445
|
-
|
|
450
|
+
The wrapper element depends on `labelAs`. `'label'` (the default) gives `<div>` + `<label htmlFor>`; `'legend'` gives `<fieldset>` + `<legend>`. `<fieldset>` is used only for `legend`, so that a single field never becomes an unnamed group. Pass `labelAs="legend"` when wrapping a group input such as `Radio` or `CheckboxGroup`.
|
|
446
451
|
|
|
447
452
|
### TextField
|
|
448
453
|
|
|
@@ -457,16 +462,16 @@ import { TextField } from '@k8ordo/ui';
|
|
|
457
462
|
<TextField id="email" value={value} onChange={onChange}
|
|
458
463
|
invalid={false} disabled={false} required={false} />
|
|
459
464
|
|
|
460
|
-
// type
|
|
465
|
+
// type can be passed too (default: "text")
|
|
461
466
|
<TextField id="tel" type="tel" inputMode="numeric" />
|
|
462
467
|
```
|
|
463
468
|
|
|
464
469
|
Props:
|
|
465
470
|
|
|
466
471
|
- `children`: `ReactNode`
|
|
467
|
-
- `invalid`: `boolean
|
|
472
|
+
- `invalid`: `boolean` (default: `false`)
|
|
468
473
|
- `ref`: `Ref<HTMLInputElement>`
|
|
469
|
-
- `type`: `TextInputType
|
|
474
|
+
- `type`: `TextInputType` (default: `'text'`)
|
|
470
475
|
|
|
471
476
|
### Textarea
|
|
472
477
|
|
|
@@ -485,10 +490,10 @@ import { Textarea } from '@k8ordo/ui';
|
|
|
485
490
|
|
|
486
491
|
Props:
|
|
487
492
|
|
|
488
|
-
- `autoResize`: `boolean
|
|
493
|
+
- `autoResize`: `boolean` (default: `false`)
|
|
489
494
|
- `children`: `ReactNode`
|
|
490
|
-
- `fullHeight`: `boolean
|
|
491
|
-
- `invalid`: `boolean
|
|
495
|
+
- `fullHeight`: `boolean` (default: `false`)
|
|
496
|
+
- `invalid`: `boolean` (default: `false`)
|
|
492
497
|
- `ref`: `Ref<HTMLTextAreaElement>`
|
|
493
498
|
|
|
494
499
|
### NumberField
|
|
@@ -511,18 +516,18 @@ import { NumberField } from '@k8ordo/ui';
|
|
|
511
516
|
Props:
|
|
512
517
|
|
|
513
518
|
- `defaultValue`: `never`
|
|
514
|
-
- `invalid`: `boolean
|
|
515
|
-
- `max`: `number
|
|
516
|
-
- `min`: `number
|
|
519
|
+
- `invalid`: `boolean` (default: `false`)
|
|
520
|
+
- `max`: `number` (default: `9_007_199_254_740_991`)
|
|
521
|
+
- `min`: `number` (default: `-9_007_199_254_740_991`)
|
|
517
522
|
- `onChange`: `(value: number) => void`
|
|
518
|
-
- `precision`: `number
|
|
523
|
+
- `precision`: `number` (default: `0`)
|
|
519
524
|
- `ref`: `Ref<HTMLInputElement>`
|
|
520
|
-
- `step`: `number
|
|
525
|
+
- `step`: `number` (default: `1`)
|
|
521
526
|
- `value`: `number`
|
|
522
527
|
|
|
523
528
|
### PasswordInput
|
|
524
529
|
|
|
525
|
-
|
|
530
|
+
A password input, with a show/hide toggle.
|
|
526
531
|
|
|
527
532
|
```tsx
|
|
528
533
|
import { PasswordInput } from '@k8ordo/ui';
|
|
@@ -534,8 +539,8 @@ import { PasswordInput } from '@k8ordo/ui';
|
|
|
534
539
|
invalid={false}
|
|
535
540
|
disabled={false}
|
|
536
541
|
required={false}
|
|
537
|
-
showLabel="
|
|
538
|
-
hideLabel="
|
|
542
|
+
showLabel="Show"
|
|
543
|
+
hideLabel="Hide"
|
|
539
544
|
/>;
|
|
540
545
|
```
|
|
541
546
|
|
|
@@ -543,7 +548,7 @@ Props:
|
|
|
543
548
|
|
|
544
549
|
- `children`: `ReactNode`
|
|
545
550
|
- `hideLabel`: `string`
|
|
546
|
-
- `invalid`: `boolean
|
|
551
|
+
- `invalid`: `boolean` (default: `false`)
|
|
547
552
|
- `ref`: `Ref<HTMLInputElement>`
|
|
548
553
|
- `showLabel`: `string`
|
|
549
554
|
|
|
@@ -555,8 +560,8 @@ import { Select } from '@k8ordo/ui';
|
|
|
555
560
|
<Select
|
|
556
561
|
id="category"
|
|
557
562
|
options={[
|
|
558
|
-
{ value: '1', label: '
|
|
559
|
-
{ value: '2', label: '
|
|
563
|
+
{ value: '1', label: 'Option 1' },
|
|
564
|
+
{ value: '2', label: 'Option 2' },
|
|
560
565
|
]}
|
|
561
566
|
value={value}
|
|
562
567
|
onChange={onChange}
|
|
@@ -568,14 +573,14 @@ import { Select } from '@k8ordo/ui';
|
|
|
568
573
|
|
|
569
574
|
Props:
|
|
570
575
|
|
|
571
|
-
- `options`: `readonly Option[]
|
|
576
|
+
- `options`: `readonly Option[]` (required)
|
|
572
577
|
- `children`: `ReactNode`
|
|
573
|
-
- `invalid`: `boolean
|
|
578
|
+
- `invalid`: `boolean` (default: `false`)
|
|
574
579
|
- `ref`: `Ref<HTMLSelectElement>`
|
|
575
580
|
|
|
576
581
|
### Autocomplete
|
|
577
582
|
|
|
578
|
-
|
|
583
|
+
A multi-select autocomplete. `value` and `onChange` are `string[]`.
|
|
579
584
|
|
|
580
585
|
```tsx
|
|
581
586
|
import { Autocomplete } from '@k8ordo/ui';
|
|
@@ -593,83 +598,85 @@ import { Autocomplete } from '@k8ordo/ui';
|
|
|
593
598
|
|
|
594
599
|
Props:
|
|
595
600
|
|
|
596
|
-
- `id`: `string
|
|
597
|
-
- `options`: `readonly Option[]
|
|
601
|
+
- `id`: `string` (required)
|
|
602
|
+
- `options`: `readonly Option[]` (required)
|
|
598
603
|
- `defaultValue`: `never`
|
|
599
|
-
- `invalid`: `boolean
|
|
604
|
+
- `invalid`: `boolean` (default: `false`)
|
|
600
605
|
- `onChange`: `(value: string[]) => void`
|
|
601
606
|
- `ref`: `Ref<HTMLInputElement>`
|
|
602
607
|
- `value`: `string[]`
|
|
603
608
|
|
|
604
609
|
### Checkbox
|
|
605
610
|
|
|
606
|
-
|
|
611
|
+
The label is passed as the `label` prop, not as children. `onChange` is `(checked, event)`.
|
|
607
612
|
|
|
608
613
|
```tsx
|
|
609
614
|
import { Checkbox } from '@k8ordo/ui';
|
|
610
615
|
|
|
611
616
|
// Controlled
|
|
612
|
-
<Checkbox checked={checked} label="
|
|
617
|
+
<Checkbox checked={checked} label="I agree" onChange={onChange} />
|
|
613
618
|
|
|
614
619
|
// Uncontrolled
|
|
615
|
-
<Checkbox defaultChecked label="
|
|
620
|
+
<Checkbox defaultChecked label="I agree" />
|
|
616
621
|
```
|
|
617
622
|
|
|
618
623
|
Props:
|
|
619
624
|
|
|
620
|
-
- `label`: `string
|
|
625
|
+
- `label`: `string` (required)
|
|
621
626
|
- `checked`: `boolean`
|
|
622
627
|
- `defaultChecked`: `never`
|
|
628
|
+
- `invalid`: `boolean` (default: `false`)
|
|
623
629
|
- `itemValue`: `string`
|
|
624
630
|
- `onChange`: `(checked: boolean, event: ChangeEvent<HTMLInputElement>) => void`
|
|
625
631
|
- `ref`: `Ref<HTMLInputElement>`
|
|
626
632
|
|
|
627
633
|
### CheckboxGroup
|
|
628
634
|
|
|
629
|
-
|
|
635
|
+
A group of checkboxes. The children are `CheckboxGroup.Item` (= `Checkbox`), and `itemValue` is required.
|
|
630
636
|
|
|
631
|
-
|
|
637
|
+
The group's selection lives in `value` / `onChange` (`string[]`). That is a different thing from a lone `Checkbox` holding a boolean in `checked` — do not conflate them.
|
|
632
638
|
|
|
633
|
-
`fieldset[role="group"]
|
|
639
|
+
It renders a `fieldset[role="group"]`, so `aria-labelledby` is required. Convey that the group is required through the referenced label element (for example `FormControl`'s required marker). `role="group"` does not allow `aria-required`, so do not put it on the group.
|
|
634
640
|
|
|
635
641
|
```tsx
|
|
636
642
|
import { CheckboxGroup } from '@k8ordo/ui';
|
|
637
643
|
|
|
638
|
-
<p id="interests-label"
|
|
644
|
+
<p id="interests-label">Areas of interest</p>
|
|
639
645
|
<CheckboxGroup.Root
|
|
640
646
|
aria-labelledby="interests-label"
|
|
641
647
|
name="interests"
|
|
642
648
|
value={values}
|
|
643
649
|
onChange={setValues}
|
|
644
650
|
>
|
|
645
|
-
<CheckboxGroup.Item itemValue="music" label="
|
|
646
|
-
<CheckboxGroup.Item itemValue="movie" label="
|
|
651
|
+
<CheckboxGroup.Item itemValue="music" label="Music" />
|
|
652
|
+
<CheckboxGroup.Item itemValue="movie" label="Film" />
|
|
647
653
|
</CheckboxGroup.Root>;
|
|
648
654
|
```
|
|
649
655
|
|
|
650
656
|
Props (CheckboxGroup.Item):
|
|
651
657
|
|
|
652
|
-
- `label`: `string
|
|
658
|
+
- `label`: `string` (required)
|
|
653
659
|
- `checked`: `boolean`
|
|
654
660
|
- `defaultChecked`: `never`
|
|
661
|
+
- `invalid`: `boolean` (default: `false`)
|
|
655
662
|
- `itemValue`: `string`
|
|
656
663
|
- `onChange`: `(checked: boolean, event: ChangeEvent<HTMLInputElement>) => void`
|
|
657
664
|
- `ref`: `Ref<HTMLInputElement>`
|
|
658
665
|
|
|
659
666
|
Props (CheckboxGroup.Root):
|
|
660
667
|
|
|
661
|
-
- `aria-labelledby`: `string
|
|
662
|
-
- `name`: `string
|
|
668
|
+
- `aria-labelledby`: `string` (required)
|
|
669
|
+
- `name`: `string` (required)
|
|
663
670
|
- `children`: `ReactNode`
|
|
664
671
|
- `defaultValue`: `never`
|
|
665
|
-
- `invalid`: `boolean
|
|
672
|
+
- `invalid`: `boolean` (default: `false`)
|
|
666
673
|
- `onChange`: `(value: string[]) => void`
|
|
667
674
|
- `ref`: `Ref<HTMLFieldSetElement>`
|
|
668
675
|
- `value`: `string[]`
|
|
669
676
|
|
|
670
677
|
### CheckboxCard
|
|
671
678
|
|
|
672
|
-
|
|
679
|
+
A card-styled checkbox.
|
|
673
680
|
|
|
674
681
|
```tsx
|
|
675
682
|
import { CheckboxCard } from '@k8ordo/ui';
|
|
@@ -678,11 +685,11 @@ import { CheckboxCard } from '@k8ordo/ui';
|
|
|
678
685
|
name="plan"
|
|
679
686
|
disabled={false}
|
|
680
687
|
options={[
|
|
681
|
-
{ value: 'basic', label: '
|
|
688
|
+
{ value: 'basic', label: 'Basic', description: '$9 / month' },
|
|
682
689
|
{
|
|
683
690
|
value: 'pro',
|
|
684
|
-
label: '
|
|
685
|
-
description: '
|
|
691
|
+
label: 'Pro',
|
|
692
|
+
description: '$19 / month',
|
|
686
693
|
visual: <Icon />,
|
|
687
694
|
},
|
|
688
695
|
]}
|
|
@@ -693,10 +700,10 @@ import { CheckboxCard } from '@k8ordo/ui';
|
|
|
693
700
|
|
|
694
701
|
Props:
|
|
695
702
|
|
|
696
|
-
- `aria-labelledby`: `string
|
|
697
|
-
- `options`: `readonly CheckboxCardOption[]
|
|
703
|
+
- `aria-labelledby`: `string` (required)
|
|
704
|
+
- `options`: `readonly CheckboxCardOption[]` (required)
|
|
698
705
|
- `defaultValue`: `never`
|
|
699
|
-
- `invalid`: `boolean
|
|
706
|
+
- `invalid`: `boolean` (default: `false`)
|
|
700
707
|
- `onChange`: `(value: string[]) => void`
|
|
701
708
|
- `ref`: `Ref<HTMLFieldSetElement>`
|
|
702
709
|
- `value`: `string[]`
|
|
@@ -711,8 +718,8 @@ import { Radio } from '@k8ordo/ui';
|
|
|
711
718
|
name="example"
|
|
712
719
|
onChange={onChange}
|
|
713
720
|
options={[
|
|
714
|
-
{ value: 'a', label: '
|
|
715
|
-
{ value: 'b', label: '
|
|
721
|
+
{ value: 'a', label: 'Choice A' },
|
|
722
|
+
{ value: 'b', label: 'Choice B' },
|
|
716
723
|
]}
|
|
717
724
|
value={value}
|
|
718
725
|
/>;
|
|
@@ -720,9 +727,10 @@ import { Radio } from '@k8ordo/ui';
|
|
|
720
727
|
|
|
721
728
|
Props:
|
|
722
729
|
|
|
723
|
-
- `aria-labelledby`: `string
|
|
724
|
-
- `options`: `readonly Option[]
|
|
725
|
-
- `disabled`: `boolean
|
|
730
|
+
- `aria-labelledby`: `string` (required)
|
|
731
|
+
- `options`: `readonly Option[]` (required)
|
|
732
|
+
- `disabled`: `boolean` (default: `false`)
|
|
733
|
+
- `invalid`: `boolean` (default: `false`)
|
|
726
734
|
- `name`: `string`
|
|
727
735
|
- `onChange`: `(value: string, event: ChangeEvent<HTMLInputElement>) => void`
|
|
728
736
|
- `ref`: `Ref<HTMLDivElement>`
|
|
@@ -730,7 +738,7 @@ Props:
|
|
|
730
738
|
|
|
731
739
|
### RadioCard
|
|
732
740
|
|
|
733
|
-
|
|
741
|
+
A card-styled radio button. Real `input[type="radio"]` elements sit inside a `fieldset[role="radiogroup"]`, so arrow-key roving and single selection are left to the browser. Reach them from tests with `getByRole('radio', { checked })`.
|
|
734
742
|
|
|
735
743
|
```tsx
|
|
736
744
|
import { RadioCard } from '@k8ordo/ui';
|
|
@@ -740,11 +748,11 @@ import { RadioCard } from '@k8ordo/ui';
|
|
|
740
748
|
name="plan"
|
|
741
749
|
disabled={false}
|
|
742
750
|
options={[
|
|
743
|
-
{ value: 'basic', label: '
|
|
751
|
+
{ value: 'basic', label: 'Basic', description: '$9 / month' },
|
|
744
752
|
{
|
|
745
753
|
value: 'pro',
|
|
746
|
-
label: '
|
|
747
|
-
description: '
|
|
754
|
+
label: 'Pro',
|
|
755
|
+
description: '$19 / month',
|
|
748
756
|
visual: <Icon />,
|
|
749
757
|
},
|
|
750
758
|
]}
|
|
@@ -755,17 +763,17 @@ import { RadioCard } from '@k8ordo/ui';
|
|
|
755
763
|
|
|
756
764
|
Props:
|
|
757
765
|
|
|
758
|
-
- `aria-labelledby`: `string
|
|
759
|
-
- `options`: `readonly RadioCardOption[]
|
|
766
|
+
- `aria-labelledby`: `string` (required)
|
|
767
|
+
- `options`: `readonly RadioCardOption[]` (required)
|
|
760
768
|
- `defaultValue`: `never`
|
|
761
|
-
- `invalid`: `boolean
|
|
769
|
+
- `invalid`: `boolean` (default: `false`)
|
|
762
770
|
- `onChange`: `(value: string) => void`
|
|
763
771
|
- `ref`: `Ref<HTMLFieldSetElement>`
|
|
764
772
|
- `value`: `string`
|
|
765
773
|
|
|
766
774
|
### Slider
|
|
767
775
|
|
|
768
|
-
|
|
776
|
+
A range slider.
|
|
769
777
|
|
|
770
778
|
```tsx
|
|
771
779
|
import { Slider } from '@k8ordo/ui';
|
|
@@ -785,17 +793,17 @@ import { Slider } from '@k8ordo/ui';
|
|
|
785
793
|
Props:
|
|
786
794
|
|
|
787
795
|
- `defaultValue`: `never`
|
|
788
|
-
- `invalid`: `boolean
|
|
789
|
-
- `max`: `number
|
|
790
|
-
- `min`: `number
|
|
796
|
+
- `invalid`: `boolean` (default: `false`)
|
|
797
|
+
- `max`: `number` (default: `100`)
|
|
798
|
+
- `min`: `number` (default: `0`)
|
|
791
799
|
- `onChange`: `(value: number) => void`
|
|
792
800
|
- `ref`: `Ref<HTMLInputElement>`
|
|
793
|
-
- `step`: `number
|
|
801
|
+
- `step`: `number` (default: `1`)
|
|
794
802
|
- `value`: `number`
|
|
795
803
|
|
|
796
804
|
### Switch
|
|
797
805
|
|
|
798
|
-
|
|
806
|
+
A toggle switch.
|
|
799
807
|
|
|
800
808
|
```tsx
|
|
801
809
|
import { Switch } from '@k8ordo/ui';
|
|
@@ -804,7 +812,7 @@ import { Switch } from '@k8ordo/ui';
|
|
|
804
812
|
checked={checked}
|
|
805
813
|
disabled={false}
|
|
806
814
|
invalid={false}
|
|
807
|
-
label="
|
|
815
|
+
label="Enable notifications"
|
|
808
816
|
onChange={onChange}
|
|
809
817
|
required={false}
|
|
810
818
|
/>;
|
|
@@ -812,16 +820,16 @@ import { Switch } from '@k8ordo/ui';
|
|
|
812
820
|
|
|
813
821
|
Props:
|
|
814
822
|
|
|
815
|
-
- `label`: `string
|
|
823
|
+
- `label`: `string` (required)
|
|
816
824
|
- `checked`: `boolean`
|
|
817
825
|
- `defaultChecked`: `never`
|
|
818
|
-
- `invalid`: `boolean
|
|
826
|
+
- `invalid`: `boolean` (default: `false`)
|
|
819
827
|
- `onChange`: `(checked: boolean, event: ChangeEvent<HTMLInputElement>) => void`
|
|
820
828
|
- `ref`: `Ref<HTMLInputElement>`
|
|
821
829
|
|
|
822
830
|
### FileField
|
|
823
831
|
|
|
824
|
-
|
|
832
|
+
File upload, as a composite pattern.
|
|
825
833
|
|
|
826
834
|
```tsx
|
|
827
835
|
import { FileField } from '@k8ordo/ui';
|
|
@@ -830,7 +838,7 @@ import { FileField } from '@k8ordo/ui';
|
|
|
830
838
|
<FileField.Trigger
|
|
831
839
|
renderItem={({ onClick, disabled }) => (
|
|
832
840
|
<Button onClick={onClick} disabled={disabled}>
|
|
833
|
-
|
|
841
|
+
Choose files
|
|
834
842
|
</Button>
|
|
835
843
|
)}
|
|
836
844
|
/>
|
|
@@ -842,11 +850,11 @@ Props (Root):
|
|
|
842
850
|
|
|
843
851
|
- `children`: `ReactNode`
|
|
844
852
|
- `defaultValue`: `File[]`
|
|
845
|
-
- `invalid`: `boolean
|
|
853
|
+
- `invalid`: `boolean` (default: `false`)
|
|
846
854
|
- `maxFiles`: `number`
|
|
847
855
|
- `onChange`: `(files: FileList | null, event?: ChangeEvent<HTMLInputElement>) => void`
|
|
848
856
|
- `ref`: `Ref<HTMLInputElement>`
|
|
849
|
-
- `webkitDirectory`: `boolean
|
|
857
|
+
- `webkitDirectory`: `boolean` (default: `false`)
|
|
850
858
|
|
|
851
859
|
Props (FileField.ItemList):
|
|
852
860
|
|
|
@@ -855,37 +863,37 @@ Props (FileField.ItemList):
|
|
|
855
863
|
|
|
856
864
|
Props (FileField.Trigger):
|
|
857
865
|
|
|
858
|
-
- `renderItem`: `(props: { onClick: () => void; disabled: boolean; invalid: boolean; }) => ReactElement
|
|
866
|
+
- `renderItem`: `(props: { onClick: () => void; disabled: boolean; invalid: boolean; }) => ReactElement` (required)
|
|
859
867
|
|
|
860
|
-
##
|
|
868
|
+
## Data display
|
|
861
869
|
|
|
862
870
|
### Heading
|
|
863
871
|
|
|
864
|
-
|
|
872
|
+
A semantic heading. The `type` prop selects the HTML element.
|
|
865
873
|
|
|
866
874
|
```tsx
|
|
867
875
|
import { Heading } from '@k8ordo/ui';
|
|
868
876
|
|
|
869
|
-
<Heading level="h1"
|
|
870
|
-
<Heading level="h2"
|
|
871
|
-
<Heading level="h3"
|
|
877
|
+
<Heading level="h1">Page title</Heading>
|
|
878
|
+
<Heading level="h2">Section heading</Heading>
|
|
879
|
+
<Heading level="h3">Subsection</Heading>
|
|
872
880
|
```
|
|
873
881
|
|
|
874
882
|
Props:
|
|
875
883
|
|
|
876
|
-
- `level`: `'h1'` | `'h2'` | `'h3'` | `'h4'` | `'h5'` | `'h6'
|
|
884
|
+
- `level`: `'h1'` | `'h2'` | `'h3'` | `'h4'` | `'h5'` | `'h6'` (required)
|
|
877
885
|
- `children`: `ReactNode`
|
|
878
886
|
- `lineClamp`: `1` | `2` | `3` | `4` | `5` | `6`
|
|
879
887
|
|
|
880
888
|
### Avatar
|
|
881
889
|
|
|
882
|
-
|
|
890
|
+
A user avatar.
|
|
883
891
|
|
|
884
892
|
```tsx
|
|
885
893
|
import { Avatar } from '@k8ordo/ui';
|
|
886
894
|
|
|
887
|
-
<Avatar src="/avatar.jpg" alt="
|
|
888
|
-
<Avatar name="
|
|
895
|
+
<Avatar src="/avatar.jpg" alt="User name" size="md" />
|
|
896
|
+
<Avatar name="Ada Lovelace" fallback="A" size="lg" />
|
|
889
897
|
<Avatar color="primary" icon={<AssistantIcon />} name="AI" size="sm" />
|
|
890
898
|
```
|
|
891
899
|
|
|
@@ -893,28 +901,28 @@ Props:
|
|
|
893
901
|
|
|
894
902
|
- `alt`: `string`
|
|
895
903
|
- `children`: `ReactNode`
|
|
896
|
-
- `color`: `'base'` | `'primary'` | `'secondary'
|
|
904
|
+
- `color`: `'base'` | `'primary'` | `'secondary'` (default: `'base'`)
|
|
897
905
|
- `fallback`: `string`
|
|
898
906
|
- `icon`: `ReactNode`
|
|
899
907
|
- `name`: `string`
|
|
900
|
-
- `size`: `'sm'` | `'md'` | `'lg'
|
|
908
|
+
- `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
|
|
901
909
|
- `src`: `string`
|
|
902
910
|
|
|
903
911
|
### Badge
|
|
904
912
|
|
|
905
|
-
|
|
913
|
+
A status badge.
|
|
906
914
|
|
|
907
915
|
```tsx
|
|
908
916
|
import { Badge } from '@k8ordo/ui';
|
|
909
917
|
|
|
910
|
-
<Badge label="
|
|
911
|
-
<Badge label="
|
|
912
|
-
<Badge label="
|
|
918
|
+
<Badge label="New" tone="info" variant="solid" />
|
|
919
|
+
<Badge label="Done" tone="success" variant="outline" />
|
|
920
|
+
<Badge label="Filter" interactive />
|
|
913
921
|
```
|
|
914
922
|
|
|
915
923
|
Props:
|
|
916
924
|
|
|
917
|
-
- `label`: `string
|
|
925
|
+
- `label`: `string` (required)
|
|
918
926
|
- `interactive`: `true`
|
|
919
927
|
- `size`: `Size`
|
|
920
928
|
- `tone`: `Tone`
|
|
@@ -922,7 +930,7 @@ Props:
|
|
|
922
930
|
|
|
923
931
|
### Code
|
|
924
932
|
|
|
925
|
-
|
|
933
|
+
Inline code.
|
|
926
934
|
|
|
927
935
|
```tsx
|
|
928
936
|
import { Code } from '@k8ordo/ui';
|
|
@@ -932,11 +940,11 @@ import { Code } from '@k8ordo/ui';
|
|
|
932
940
|
|
|
933
941
|
Props:
|
|
934
942
|
|
|
935
|
-
- `children`: `string
|
|
943
|
+
- `children`: `string` (required)
|
|
936
944
|
|
|
937
945
|
### Table
|
|
938
946
|
|
|
939
|
-
|
|
947
|
+
A data table, as a compound component.
|
|
940
948
|
|
|
941
949
|
```tsx
|
|
942
950
|
import { Table } from '@k8ordo/ui';
|
|
@@ -944,13 +952,13 @@ import { Table } from '@k8ordo/ui';
|
|
|
944
952
|
<Table.Root>
|
|
945
953
|
<Table.Head>
|
|
946
954
|
<Table.Row>
|
|
947
|
-
<Table.HeaderCell
|
|
948
|
-
<Table.HeaderCell align="right"
|
|
955
|
+
<Table.HeaderCell>Name</Table.HeaderCell>
|
|
956
|
+
<Table.HeaderCell align="right">Amount</Table.HeaderCell>
|
|
949
957
|
</Table.Row>
|
|
950
958
|
</Table.Head>
|
|
951
959
|
<Table.Body>
|
|
952
960
|
<Table.Row interactive>
|
|
953
|
-
<Table.Cell
|
|
961
|
+
<Table.Cell>Product A</Table.Cell>
|
|
954
962
|
<Table.Cell align="right">¥1,000</Table.Cell>
|
|
955
963
|
</Table.Row>
|
|
956
964
|
</Table.Body>
|
|
@@ -967,14 +975,14 @@ Props (Table.Caption):
|
|
|
967
975
|
|
|
968
976
|
Props (Table.Cell):
|
|
969
977
|
|
|
970
|
-
- `align`: `CellAlign
|
|
978
|
+
- `align`: `CellAlign` (default: `'left'`)
|
|
971
979
|
- `children`: `ReactNode`
|
|
972
|
-
- `color`: `'base'` | `'mute'
|
|
980
|
+
- `color`: `'base'` | `'mute'` (default: `'base'`)
|
|
973
981
|
|
|
974
982
|
Props (Table.EmptyState):
|
|
975
983
|
|
|
976
|
-
- `children`: `ReactNode
|
|
977
|
-
- `colSpan`: `number
|
|
984
|
+
- `children`: `ReactNode` (required)
|
|
985
|
+
- `colSpan`: `number` (required)
|
|
978
986
|
|
|
979
987
|
Props (Table.Head):
|
|
980
988
|
|
|
@@ -982,9 +990,9 @@ Props (Table.Head):
|
|
|
982
990
|
|
|
983
991
|
Props (Table.HeaderCell):
|
|
984
992
|
|
|
985
|
-
- `align`: `CellAlign
|
|
993
|
+
- `align`: `CellAlign` (default: `'left'`)
|
|
986
994
|
- `children`: `ReactNode`
|
|
987
|
-
- `scope`: `'col'` | `'row'` | `'colgroup'` | `'rowgroup'
|
|
995
|
+
- `scope`: `'col'` | `'row'` | `'colgroup'` | `'rowgroup'` (default: `'col'`)
|
|
988
996
|
|
|
989
997
|
Props (Table.Root):
|
|
990
998
|
|
|
@@ -993,23 +1001,23 @@ Props (Table.Root):
|
|
|
993
1001
|
Props (Table.Row):
|
|
994
1002
|
|
|
995
1003
|
- `children`: `ReactNode`
|
|
996
|
-
- `interactive`: `boolean
|
|
1004
|
+
- `interactive`: `boolean` (default: `false`)
|
|
997
1005
|
|
|
998
|
-
##
|
|
1006
|
+
## Feedback
|
|
999
1007
|
|
|
1000
1008
|
### Alert
|
|
1001
1009
|
|
|
1002
1010
|
```tsx
|
|
1003
1011
|
import { Alert } from '@k8ordo/ui';
|
|
1004
1012
|
|
|
1005
|
-
<Alert tone="info" message="
|
|
1006
|
-
<Alert tone="error" message={['
|
|
1013
|
+
<Alert tone="info" message="An informational message" />
|
|
1014
|
+
<Alert tone="error" message={['Error 1', 'Error 2']} />
|
|
1007
1015
|
```
|
|
1008
1016
|
|
|
1009
1017
|
Props:
|
|
1010
1018
|
|
|
1011
|
-
- `message`: `string` | `string[]
|
|
1012
|
-
- `tone`: `Status
|
|
1019
|
+
- `message`: `string` | `string[]` (required)
|
|
1020
|
+
- `tone`: `Status` (required)
|
|
1013
1021
|
- `action`: `AlertAction`
|
|
1014
1022
|
- `closeLabel`: `string`
|
|
1015
1023
|
- `onClose`: `() => void`
|
|
@@ -1021,21 +1029,21 @@ import { useToast } from '@k8ordo/ui';
|
|
|
1021
1029
|
|
|
1022
1030
|
const { open, close, closeAll } = useToast();
|
|
1023
1031
|
|
|
1024
|
-
open('success', '
|
|
1025
|
-
open('error', '
|
|
1032
|
+
open('success', 'Saved');
|
|
1033
|
+
open('error', 'Something went wrong');
|
|
1026
1034
|
```
|
|
1027
1035
|
|
|
1028
|
-
`ToastProvider`
|
|
1036
|
+
`ToastProvider` is already inside `UIProvider`, so no extra wrapper is needed.
|
|
1029
1037
|
|
|
1030
|
-
`useToast()`
|
|
1038
|
+
What `useToast()` returns:
|
|
1031
1039
|
|
|
1032
|
-
- `open`: `(tone: Status, message: string, options?: ToastOptions) => void
|
|
1040
|
+
- `open`: `(tone: Status, message: string, options?: ToastOptions) => void` (`ToastOptions` is `{ duration?: number; action?: ToastAction }`)
|
|
1033
1041
|
- `close`: `(id: string) => void`
|
|
1034
1042
|
- `closeAll`: `() => void`
|
|
1035
1043
|
|
|
1036
1044
|
### ToastProvider
|
|
1037
1045
|
|
|
1038
|
-
|
|
1046
|
+
Wrap explicitly inside `UIProvider` only when you want to change where toasts appear or which Portal root they use.
|
|
1039
1047
|
|
|
1040
1048
|
```tsx
|
|
1041
1049
|
import { ToastProvider } from '@k8ordo/ui';
|
|
@@ -1048,8 +1056,8 @@ import { ToastProvider } from '@k8ordo/ui';
|
|
|
1048
1056
|
Props:
|
|
1049
1057
|
|
|
1050
1058
|
- `children`: `ReactNode`
|
|
1051
|
-
- `portalRef`: `RefObject<HTMLElement | null
|
|
1052
|
-
- `position`: `'fixed'` | `'absolute'
|
|
1059
|
+
- `portalRef`: `RefObject<HTMLElement | null>` (default: `null`)
|
|
1060
|
+
- `position`: `'fixed'` | `'absolute'` (default: `'fixed'`)
|
|
1053
1061
|
|
|
1054
1062
|
### Progress
|
|
1055
1063
|
|
|
@@ -1057,34 +1065,34 @@ Props:
|
|
|
1057
1065
|
import { Progress } from '@k8ordo/ui';
|
|
1058
1066
|
|
|
1059
1067
|
<Progress value={50} max={100} />
|
|
1060
|
-
<Progress value={50} max={100} min={0} label="
|
|
1068
|
+
<Progress value={50} max={100} min={0} label="Progress" />
|
|
1061
1069
|
```
|
|
1062
1070
|
|
|
1063
1071
|
Props:
|
|
1064
1072
|
|
|
1065
|
-
- `max`: `number
|
|
1066
|
-
- `value`: `number
|
|
1073
|
+
- `max`: `number` (required)
|
|
1074
|
+
- `value`: `number` (required)
|
|
1067
1075
|
- `label`: `string`
|
|
1068
|
-
- `min`: `number
|
|
1076
|
+
- `min`: `number` (default: `0`)
|
|
1069
1077
|
|
|
1070
1078
|
### Spinner
|
|
1071
1079
|
|
|
1072
|
-
|
|
1080
|
+
A loading spinner.
|
|
1073
1081
|
|
|
1074
1082
|
```tsx
|
|
1075
1083
|
import { Spinner } from '@k8ordo/ui';
|
|
1076
1084
|
|
|
1077
|
-
<Spinner size="md" label="
|
|
1085
|
+
<Spinner size="md" label="Loading" />;
|
|
1078
1086
|
```
|
|
1079
1087
|
|
|
1080
1088
|
Props:
|
|
1081
1089
|
|
|
1082
1090
|
- `label`: `string`
|
|
1083
|
-
- `size`: `'sm'` | `'md'` | `'lg'
|
|
1091
|
+
- `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
|
|
1084
1092
|
|
|
1085
1093
|
### Skeleton
|
|
1086
1094
|
|
|
1087
|
-
|
|
1095
|
+
A content placeholder.
|
|
1088
1096
|
|
|
1089
1097
|
```tsx
|
|
1090
1098
|
import { Skeleton } from '@k8ordo/ui';
|
|
@@ -1096,21 +1104,21 @@ import { Skeleton } from '@k8ordo/ui';
|
|
|
1096
1104
|
|
|
1097
1105
|
Props:
|
|
1098
1106
|
|
|
1099
|
-
- `animate`: `boolean
|
|
1100
|
-
- `shape`: `'rect'` | `'circle'
|
|
1101
|
-
- `size`: `'sm'` | `'md'` | `'lg'
|
|
1107
|
+
- `animate`: `boolean` (default: `true`)
|
|
1108
|
+
- `shape`: `'rect'` | `'circle'` (default: `'rect'`)
|
|
1109
|
+
- `size`: `'sm'` | `'md'` | `'lg'` (default: `'md'`)
|
|
1102
1110
|
|
|
1103
|
-
##
|
|
1111
|
+
## Overlays
|
|
1104
1112
|
|
|
1105
1113
|
### Modal
|
|
1106
1114
|
|
|
1107
|
-
|
|
1115
|
+
The base overlay component. It uses the `<dialog>` element.
|
|
1108
1116
|
|
|
1109
1117
|
```tsx
|
|
1110
1118
|
import { Modal } from '@k8ordo/ui';
|
|
1111
1119
|
|
|
1112
1120
|
<Modal isOpen={open} onClose={onClose} side="center">
|
|
1113
|
-
|
|
1121
|
+
Content
|
|
1114
1122
|
</Modal>;
|
|
1115
1123
|
```
|
|
1116
1124
|
|
|
@@ -1124,27 +1132,27 @@ Props:
|
|
|
1124
1132
|
- `isOpen`: `boolean`
|
|
1125
1133
|
- `onClose`: `() => void`
|
|
1126
1134
|
- `ref`: `Ref<HTMLDialogElement>`
|
|
1127
|
-
- `side`: `ModalSide
|
|
1135
|
+
- `side`: `ModalSide` (default: `'center'`)
|
|
1128
1136
|
|
|
1129
|
-
|
|
1137
|
+
Name resolution goes `aria-label` / `aria-labelledby` first, then the heading registered by a `Dialog.Root` inside. With neither, the dialog is unnamed — so pass `aria-label` when you place content directly without a `Dialog`.
|
|
1130
1138
|
|
|
1131
1139
|
```tsx
|
|
1132
|
-
<Modal aria-label="
|
|
1140
|
+
<Modal aria-label="Image preview" isOpen={open} onClose={onClose}>
|
|
1133
1141
|
<img alt="" src={src} />
|
|
1134
1142
|
</Modal>
|
|
1135
1143
|
```
|
|
1136
1144
|
|
|
1137
1145
|
### Dialog
|
|
1138
1146
|
|
|
1139
|
-
|
|
1147
|
+
A compound component, used together with Modal.
|
|
1140
1148
|
|
|
1141
1149
|
```tsx
|
|
1142
1150
|
import { Modal, Dialog } from '@k8ordo/ui';
|
|
1143
1151
|
|
|
1144
1152
|
<Modal isOpen={open} onClose={onClose}>
|
|
1145
1153
|
<Dialog.Root>
|
|
1146
|
-
<Dialog.Header title="
|
|
1147
|
-
<Dialog.Content
|
|
1154
|
+
<Dialog.Header title="Confirm" onClose={onClose} />
|
|
1155
|
+
<Dialog.Content>Content</Dialog.Content>
|
|
1148
1156
|
</Dialog.Root>
|
|
1149
1157
|
</Modal>;
|
|
1150
1158
|
```
|
|
@@ -1155,8 +1163,8 @@ Props (Dialog.Content):
|
|
|
1155
1163
|
|
|
1156
1164
|
Props (Dialog.Header):
|
|
1157
1165
|
|
|
1158
|
-
- `onClose`: `() => void
|
|
1159
|
-
- `title`: `ReactNode
|
|
1166
|
+
- `onClose`: `() => void` (required)
|
|
1167
|
+
- `title`: `ReactNode` (required)
|
|
1160
1168
|
|
|
1161
1169
|
Props (Dialog.Root):
|
|
1162
1170
|
|
|
@@ -1168,36 +1176,36 @@ Props (Dialog.Root):
|
|
|
1168
1176
|
|
|
1169
1177
|
### Drawer
|
|
1170
1178
|
|
|
1171
|
-
|
|
1179
|
+
A side panel. It uses Modal internally.
|
|
1172
1180
|
|
|
1173
1181
|
```tsx
|
|
1174
1182
|
import { Drawer } from '@k8ordo/ui';
|
|
1175
1183
|
|
|
1176
|
-
<Drawer title="
|
|
1177
|
-
|
|
1184
|
+
<Drawer title="Menu" isOpen={open} onClose={onClose} side="right">
|
|
1185
|
+
Content
|
|
1178
1186
|
</Drawer>;
|
|
1179
1187
|
```
|
|
1180
1188
|
|
|
1181
1189
|
Props:
|
|
1182
1190
|
|
|
1183
|
-
- `title`: `ReactNode
|
|
1191
|
+
- `title`: `ReactNode` (required)
|
|
1184
1192
|
- `children`: `ReactNode`
|
|
1185
1193
|
- `defaultOpen`: `boolean`
|
|
1186
1194
|
- `isOpen`: `boolean`
|
|
1187
1195
|
- `onClose`: `() => void`
|
|
1188
|
-
- `side`: `DrawerSide
|
|
1196
|
+
- `side`: `DrawerSide` (default: `'right'`)
|
|
1189
1197
|
|
|
1190
1198
|
### Popover
|
|
1191
1199
|
|
|
1192
|
-
CSS Anchor Positioning
|
|
1200
|
+
A popover built on CSS Anchor Positioning, as a compound component.
|
|
1193
1201
|
|
|
1194
1202
|
```tsx
|
|
1195
1203
|
import { Popover } from '@k8ordo/ui';
|
|
1196
1204
|
|
|
1197
1205
|
<Popover.Root placement="bottom">
|
|
1198
|
-
<Popover.Trigger renderItem={(props) => <Button {...props}
|
|
1206
|
+
<Popover.Trigger renderItem={(props) => <Button {...props}>Open</Button>} />
|
|
1199
1207
|
<Popover.Content
|
|
1200
|
-
renderItem={(props) => <div {...props}
|
|
1208
|
+
renderItem={(props) => <div {...props}>Popover content</div>}
|
|
1201
1209
|
/>
|
|
1202
1210
|
</Popover.Root>;
|
|
1203
1211
|
```
|
|
@@ -1205,48 +1213,48 @@ import { Popover } from '@k8ordo/ui';
|
|
|
1205
1213
|
Props (Root):
|
|
1206
1214
|
|
|
1207
1215
|
- `children`: `ReactNode`
|
|
1208
|
-
- `closeOnClickAway`: `boolean
|
|
1209
|
-
- `defaultOpen`: `boolean
|
|
1210
|
-
- `flipDisabled`: `boolean
|
|
1216
|
+
- `closeOnClickAway`: `boolean` (default: `true`)
|
|
1217
|
+
- `defaultOpen`: `boolean` (default: `false`)
|
|
1218
|
+
- `flipDisabled`: `boolean` (default: `false`)
|
|
1211
1219
|
- `isOpen`: `boolean`
|
|
1212
1220
|
- `onChange`: `(isOpen: boolean) => void`
|
|
1213
|
-
- `placement`: `Placement
|
|
1214
|
-
- `role`: `'dialog'` | `'menu'` | `'listbox'
|
|
1215
|
-
- `trapFocus`: `boolean
|
|
1221
|
+
- `placement`: `Placement` (default: `'bottom-start'`)
|
|
1222
|
+
- `role`: `'dialog'` | `'menu'` | `'listbox'` (default: `'menu'`)
|
|
1223
|
+
- `trapFocus`: `boolean` (default: `true`)
|
|
1216
1224
|
|
|
1217
|
-
Escape
|
|
1225
|
+
Escape closes **only the innermost one** when they are nested.
|
|
1218
1226
|
|
|
1219
1227
|
Props (Popover.Content):
|
|
1220
1228
|
|
|
1221
|
-
- `renderItem`: `(props: PopoverContentProps) => ReactElement
|
|
1222
|
-
- `animation`: `'scale'` | `'fade'
|
|
1229
|
+
- `renderItem`: `(props: PopoverContentProps) => ReactElement` (required)
|
|
1230
|
+
- `animation`: `'scale'` | `'fade'` (default: `'scale'`)
|
|
1223
1231
|
|
|
1224
1232
|
Props (Popover.Trigger):
|
|
1225
1233
|
|
|
1226
|
-
- `renderItem`: `(props: PopoverTriggerProps) => ReactElement
|
|
1234
|
+
- `renderItem`: `(props: PopoverTriggerProps) => ReactElement` (required)
|
|
1227
1235
|
|
|
1228
1236
|
### Tooltip
|
|
1229
1237
|
|
|
1230
|
-
|
|
1238
|
+
A tooltip, as a compound component.
|
|
1231
1239
|
|
|
1232
1240
|
```tsx
|
|
1233
1241
|
import { Tooltip } from '@k8ordo/ui';
|
|
1234
1242
|
|
|
1235
1243
|
<Tooltip.Root placement="top">
|
|
1236
|
-
<Tooltip.Trigger renderItem={(props) => <Button {...props}
|
|
1237
|
-
<Tooltip.Content
|
|
1244
|
+
<Tooltip.Trigger renderItem={(props) => <Button {...props}>Hover</Button>} />
|
|
1245
|
+
<Tooltip.Content>A hint</Tooltip.Content>
|
|
1238
1246
|
</Tooltip.Root>;
|
|
1239
1247
|
```
|
|
1240
1248
|
|
|
1241
1249
|
Props (Root):
|
|
1242
1250
|
|
|
1243
1251
|
- `children`: `ReactNode`
|
|
1244
|
-
- `closeDelay`: `number
|
|
1252
|
+
- `closeDelay`: `number` (default: `150`)
|
|
1245
1253
|
- `defaultOpen`: `boolean`
|
|
1246
1254
|
- `isOpen`: `boolean`
|
|
1247
1255
|
- `onChange`: `(isOpen: boolean) => void`
|
|
1248
|
-
- `openDelay`: `number
|
|
1249
|
-
- `placement`: `Placement
|
|
1256
|
+
- `openDelay`: `number` (default: `0`)
|
|
1257
|
+
- `placement`: `Placement` (default: `'bottom'`)
|
|
1250
1258
|
|
|
1251
1259
|
Props (Tooltip.Content):
|
|
1252
1260
|
|
|
@@ -1254,20 +1262,20 @@ Props (Tooltip.Content):
|
|
|
1254
1262
|
|
|
1255
1263
|
Props (Tooltip.Trigger):
|
|
1256
1264
|
|
|
1257
|
-
- `renderItem`: `(props: TooltipTriggerProps) => ReactElement
|
|
1265
|
+
- `renderItem`: `(props: TooltipTriggerProps) => ReactElement` (required)
|
|
1258
1266
|
|
|
1259
1267
|
### DropdownMenu
|
|
1260
1268
|
|
|
1261
|
-
|
|
1269
|
+
A dropdown menu, as a compound component.
|
|
1262
1270
|
|
|
1263
1271
|
```tsx
|
|
1264
1272
|
import { DropdownMenu } from '@k8ordo/ui';
|
|
1265
1273
|
|
|
1266
1274
|
<DropdownMenu.Root>
|
|
1267
|
-
<DropdownMenu.Trigger label="
|
|
1275
|
+
<DropdownMenu.Trigger label="Menu" />
|
|
1268
1276
|
<DropdownMenu.Content>
|
|
1269
|
-
<DropdownMenu.Item label="
|
|
1270
|
-
<DropdownMenu.Item label="
|
|
1277
|
+
<DropdownMenu.Item label="Item 1" onAction={handleClick} />
|
|
1278
|
+
<DropdownMenu.Item label="Item 2" onAction={handleClick} />
|
|
1271
1279
|
</DropdownMenu.Content>
|
|
1272
1280
|
</DropdownMenu.Root>;
|
|
1273
1281
|
```
|
|
@@ -1278,12 +1286,12 @@ Props (Root):
|
|
|
1278
1286
|
- `defaultOpen`: `boolean`
|
|
1279
1287
|
- `isOpen`: `boolean`
|
|
1280
1288
|
- `onChange`: `(isOpen: boolean) => void`
|
|
1281
|
-
- `placement`: `Placement
|
|
1289
|
+
- `placement`: `Placement` (default: `'bottom-start'`)
|
|
1282
1290
|
|
|
1283
|
-
Trigger
|
|
1291
|
+
Trigger variants:
|
|
1284
1292
|
|
|
1285
|
-
- `DropdownMenu.Trigger`:
|
|
1286
|
-
- `DropdownMenu.IconTrigger`:
|
|
1293
|
+
- `DropdownMenu.Trigger`: text-based (`label`, `size`, `variant`)
|
|
1294
|
+
- `DropdownMenu.IconTrigger`: icon-based (`icon`, `label`)
|
|
1287
1295
|
|
|
1288
1296
|
Props (DropdownMenu.Content):
|
|
1289
1297
|
|
|
@@ -1291,30 +1299,30 @@ Props (DropdownMenu.Content):
|
|
|
1291
1299
|
|
|
1292
1300
|
Props (DropdownMenu.IconTrigger):
|
|
1293
1301
|
|
|
1294
|
-
- `icon`: `ReactNode
|
|
1295
|
-
- `label`: `string
|
|
1302
|
+
- `icon`: `ReactNode` (required)
|
|
1303
|
+
- `label`: `string` (required)
|
|
1296
1304
|
|
|
1297
1305
|
Props (DropdownMenu.Item):
|
|
1298
1306
|
|
|
1299
|
-
- `label`: `string
|
|
1300
|
-
- `onAction`: `() => void
|
|
1307
|
+
- `label`: `string` (required)
|
|
1308
|
+
- `onAction`: `() => void` (required)
|
|
1301
1309
|
|
|
1302
|
-
`DropdownMenu.SubMenu`
|
|
1310
|
+
`DropdownMenu.SubMenu` is a nested menu. Hovering the `label` row, or opening it from the keyboard, opens the child menu to the right.
|
|
1303
1311
|
|
|
1304
1312
|
Props (DropdownMenu.SubMenu):
|
|
1305
1313
|
|
|
1306
|
-
- `label`: `string
|
|
1314
|
+
- `label`: `string` (required)
|
|
1307
1315
|
- `children`: `ReactNode`
|
|
1308
1316
|
|
|
1309
1317
|
Props (DropdownMenu.Trigger):
|
|
1310
1318
|
|
|
1311
|
-
- `label`: `string
|
|
1312
|
-
- `size`: `ComponentProps<typeof Button>['size']
|
|
1313
|
-
- `variant`: `ComponentProps<typeof Button>['variant']
|
|
1319
|
+
- `label`: `string` (required)
|
|
1320
|
+
- `size`: `ComponentProps<typeof Button>['size']` (default: `'md'`)
|
|
1321
|
+
- `variant`: `ComponentProps<typeof Button>['variant']` (default: `'solid'`)
|
|
1314
1322
|
|
|
1315
1323
|
### ListBox
|
|
1316
1324
|
|
|
1317
|
-
|
|
1325
|
+
List selection, as a compound component. The choices use the same `Option` (`{ value, label }`) as `Select`.
|
|
1318
1326
|
|
|
1319
1327
|
```tsx
|
|
1320
1328
|
import { ListBox } from '@k8ordo/ui';
|
|
@@ -1322,31 +1330,31 @@ import { ListBox } from '@k8ordo/ui';
|
|
|
1322
1330
|
<ListBox.Root
|
|
1323
1331
|
onChange={onChange}
|
|
1324
1332
|
options={[
|
|
1325
|
-
{ value: '1', label: '
|
|
1326
|
-
{ value: '2', label: '
|
|
1333
|
+
{ value: '1', label: 'Option 1' },
|
|
1334
|
+
{ value: '2', label: 'Option 2' },
|
|
1327
1335
|
]}
|
|
1328
1336
|
value={value}
|
|
1329
1337
|
>
|
|
1330
|
-
<ListBox.Trigger label="
|
|
1338
|
+
<ListBox.Trigger label="Items per page" size="md" />
|
|
1331
1339
|
<ListBox.Content />
|
|
1332
1340
|
</ListBox.Root>;
|
|
1333
1341
|
```
|
|
1334
1342
|
|
|
1335
1343
|
Props (Root):
|
|
1336
1344
|
|
|
1337
|
-
- `options`: `readonly Option[]
|
|
1345
|
+
- `options`: `readonly Option[]` (required)
|
|
1338
1346
|
- `children`: `ReactNode`
|
|
1339
1347
|
- `defaultValue`: `Option['value']`
|
|
1340
1348
|
- `onChange`: `(value: Option['value']) => void`
|
|
1341
|
-
- `placement`: `Placement
|
|
1349
|
+
- `placement`: `Placement` (default: `'bottom'`)
|
|
1342
1350
|
- `value`: `Option['value']`
|
|
1343
1351
|
|
|
1344
|
-
Trigger
|
|
1352
|
+
Trigger variants:
|
|
1345
1353
|
|
|
1346
|
-
- `ListBox.Trigger`:
|
|
1347
|
-
- `ListBox.IconTrigger`:
|
|
1354
|
+
- `ListBox.Trigger`: text-based (`size`, `label`)
|
|
1355
|
+
- `ListBox.IconTrigger`: icon-based (`size`, `icon`, `label`)
|
|
1348
1356
|
|
|
1349
|
-
`label`
|
|
1357
|
+
Passing `label` makes the trigger's accessible name "label + current value". Omit it and only the current value is used, so pass it when there is no heading nearby.
|
|
1350
1358
|
|
|
1351
1359
|
Props (Content):
|
|
1352
1360
|
|
|
@@ -1354,20 +1362,20 @@ Props (Content):
|
|
|
1354
1362
|
|
|
1355
1363
|
Props (ListBox.IconTrigger):
|
|
1356
1364
|
|
|
1357
|
-
- `icon`: `ReactElement
|
|
1365
|
+
- `icon`: `ReactElement` (required)
|
|
1358
1366
|
- `label`: `string`
|
|
1359
|
-
- `size`: `ComponentProps<typeof Button>['size']
|
|
1367
|
+
- `size`: `ComponentProps<typeof Button>['size']` (default: `'md'`)
|
|
1360
1368
|
|
|
1361
1369
|
Props (ListBox.Trigger):
|
|
1362
1370
|
|
|
1363
1371
|
- `label`: `string`
|
|
1364
|
-
- `size`: `ComponentProps<typeof Button>['size']
|
|
1372
|
+
- `size`: `ComponentProps<typeof Button>['size']` (default: `'md'`)
|
|
1365
1373
|
|
|
1366
|
-
##
|
|
1374
|
+
## Providers
|
|
1367
1375
|
|
|
1368
1376
|
### UIProvider
|
|
1369
1377
|
|
|
1370
|
-
|
|
1378
|
+
Wrap the app root once. It includes ToastProvider and the message dictionary (i18n, below).
|
|
1371
1379
|
|
|
1372
1380
|
```tsx
|
|
1373
1381
|
import { UIProvider } from '@k8ordo/ui';
|
|
@@ -1384,7 +1392,7 @@ Props:
|
|
|
1384
1392
|
|
|
1385
1393
|
### PortalRootProvider
|
|
1386
1394
|
|
|
1387
|
-
|
|
1395
|
+
Sets the root element for portals.
|
|
1388
1396
|
|
|
1389
1397
|
```tsx
|
|
1390
1398
|
import { PortalRootProvider, usePortalRoot } from '@k8ordo/ui';
|
|
@@ -1397,11 +1405,11 @@ Props:
|
|
|
1397
1405
|
- `children`: `ReactNode`
|
|
1398
1406
|
- `value`: `RefObject<HTMLElement | null>`
|
|
1399
1407
|
|
|
1400
|
-
## i18n
|
|
1408
|
+
## i18n (message dictionary)
|
|
1401
1409
|
|
|
1402
|
-
|
|
1410
|
+
The wording components own internally (close, required, loading, …) comes from a dictionary. **It defaults to Japanese**, and works without a provider and without passing `messages`.
|
|
1403
1411
|
|
|
1404
|
-
|
|
1412
|
+
To switch to English, pass `en` from `@k8ordo/ui/i18n`.
|
|
1405
1413
|
|
|
1406
1414
|
```tsx
|
|
1407
1415
|
import { UIProvider } from '@k8ordo/ui';
|
|
@@ -1412,7 +1420,7 @@ import { en } from '@k8ordo/ui/i18n';
|
|
|
1412
1420
|
</UIProvider>;
|
|
1413
1421
|
```
|
|
1414
1422
|
|
|
1415
|
-
|
|
1423
|
+
To replace only part of it, spread the dictionary and override those keys (`Partial<Messages>`, so you need not fill in every key).
|
|
1416
1424
|
|
|
1417
1425
|
```tsx
|
|
1418
1426
|
<UIProvider messages={{ ...en, close: 'Dismiss' }}>
|
|
@@ -1420,7 +1428,7 @@ import { en } from '@k8ordo/ui/i18n';
|
|
|
1420
1428
|
</UIProvider>
|
|
1421
1429
|
```
|
|
1422
1430
|
|
|
1423
|
-
|
|
1431
|
+
To stay in Japanese and change only one string, pass just that key.
|
|
1424
1432
|
|
|
1425
1433
|
```tsx
|
|
1426
1434
|
<UIProvider messages={{ close: '閉じる(Esc)' }}>
|
|
@@ -1428,32 +1436,32 @@ import { en } from '@k8ordo/ui/i18n';
|
|
|
1428
1436
|
</UIProvider>
|
|
1429
1437
|
```
|
|
1430
1438
|
|
|
1431
|
-
###
|
|
1439
|
+
### Resolution order
|
|
1432
1440
|
|
|
1433
|
-
|
|
1441
|
+
**Component prop > the dictionary passed to the provider > the built-in default (Japanese)**.
|
|
1434
1442
|
|
|
1435
|
-
`Spinner`
|
|
1443
|
+
A component with a wording prop of its own — `Spinner`'s `label`, `Alert`'s `closeLabel`, `PasswordInput`'s `showLabel` / `hideLabel`, `Pagination`'s `prevLabel` / `nextLabel` — takes that prop over the dictionary.
|
|
1436
1444
|
|
|
1437
1445
|
```tsx
|
|
1438
|
-
//
|
|
1446
|
+
// Even with the en dictionary, this one Spinner reads 「保存中」
|
|
1439
1447
|
<Spinner label="保存中" />
|
|
1440
1448
|
```
|
|
1441
1449
|
|
|
1442
|
-
###
|
|
1450
|
+
### Exports
|
|
1443
1451
|
|
|
1444
1452
|
```tsx
|
|
1445
1453
|
import { en, ja, type Messages } from '@k8ordo/ui/i18n';
|
|
1446
1454
|
```
|
|
1447
1455
|
|
|
1448
|
-
`ja`
|
|
1456
|
+
`ja` and `en` are exported only from the `@k8ordo/ui/i18n` subpath, not the root, so the dictionaries stay out of the main bundle.
|
|
1449
1457
|
|
|
1450
|
-
###
|
|
1458
|
+
### Key list
|
|
1451
1459
|
|
|
1452
|
-
`Messages`
|
|
1460
|
+
Every key in the `Messages` type. All values are `string`.
|
|
1453
1461
|
|
|
1454
|
-
|
|
|
1462
|
+
| Category | Keys |
|
|
1455
1463
|
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
1456
|
-
|
|
|
1464
|
+
| Common | `close`, `required`, `loading`, `avatar`, `color` |
|
|
1457
1465
|
| Alert | `alertSuccess`, `alertInfo`, `alertWarning`, `alertError` |
|
|
1458
1466
|
| Toast | `toastRegion` |
|
|
1459
1467
|
| Autocomplete | `autocompletePlaceholder`, `autocompleteRemoveTag`, `autocompleteClear`, `autocompleteEmpty` |
|
|
@@ -1463,4 +1471,4 @@ import { en, ja, type Messages } from '@k8ordo/ui/i18n';
|
|
|
1463
1471
|
| ListBox | `listBoxPlaceholder` |
|
|
1464
1472
|
| Breadcrumb | `breadcrumb` |
|
|
1465
1473
|
| Pagination | `paginationLabel`, `paginationPrevious`, `paginationNext` |
|
|
1466
|
-
| AI
|
|
1474
|
+
| AI chat | `chat`, `scrollToLatest`, `reasoning`, `reasoningStreaming`, `suggestions`, `send`, `stop`, `toolInput`, `toolOutput`, `toolError` |
|