@keboola/design 3.2.0 → 3.2.3

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.
@@ -0,0 +1,377 @@
1
+ # @keboola/design — component API reference
2
+
3
+ > **Generated file — do not edit by hand.** Regenerate with `yarn workspace @keboola/design generate:api` (extracts prop signatures from the TypeScript types via `react-docgen-typescript`).
4
+
5
+ This is the prop-signature contract for the most-used components. For _which_ component to reach for, see [`AGENTS.md`](./AGENTS.md) (the decision tree); for live worked examples, open the colocated `*.stories.tsx` in Storybook (`yarn dev --filter=@keboola/design`).
6
+
7
+ Props listed are the ones each component **declares itself**. Components built on a native element (`Button` on `<button>`, `Link` on `<a>`, `Card` on `<div>`, …) also accept that element's standard attributes — called out in each entry's note.
8
+
9
+ ## Actions
10
+
11
+ ### `Button`
12
+
13
+ Source: `src/components/Button/Button.tsx`
14
+
15
+ > Icons are composed as children, not an `icon` prop. Plus all native `<button>` attributes.
16
+
17
+ | Prop | Type | Required | Default | Description |
18
+ | ----------- | --------------------------------------------------------------------------------------------------------------------- | -------- | --------- | ------------------------------------------------------------------------------------------------------------------- |
19
+ | `argo` | `boolean` | no | `false` | @internal Transitional opt-in; removed once consumers wrap argo sections in `<ThemeProvider>`. |
20
+ | `asChild` | `boolean` | no | `false` | Render as a Radix `Slot` so the parent JSX (e.g. a `react-router` `<Link>`) becomes the button element. |
21
+ | `block` | `boolean \| null` | no | `false` | |
22
+ | `isLoading` | `boolean` | no | `false` | Replaces the leading content with a spinner and disables the button visually. The caller still controls `disabled`. |
23
+ | `size` | `"small" \| "medium" \| "large" \| "icon-lg" \| "icon" \| "icon-sm" \| "icon-xs" \| "icon-2xs" \| "icon-3xs" \| null` | no | `medium` | |
24
+ | `variant` | `"primary" \| "secondary" \| "danger" \| "invisible" \| "outline" \| "inline" \| null` | no | `primary` | |
25
+
26
+ ### `ButtonInline`
27
+
28
+ Source: `src/components/Button/ButtonInline.tsx`
29
+
30
+ > Inline text-link-style action. Plus all native `<button>` attributes.
31
+
32
+ | Prop | Type | Required | Default | Description |
33
+ | --------- | ---------------------------------------------- | -------- | ------- | ----------- |
34
+ | `asChild` | `boolean` | no | `false` | |
35
+ | `variant` | `"link" \| "custom" \| "link-reverse" \| null` | no | — | |
36
+
37
+ ### `Link`
38
+
39
+ Source: `src/components/Link.tsx`
40
+
41
+ > Defaults `target="_blank"` + `rel="noopener noreferrer"`. Accepts all native `<a>` attributes (`href`, `target`, …) — none are required props.
42
+
43
+ _No own props — see note above for passthrough attributes._
44
+
45
+ ## Status surfaces
46
+
47
+ ### `Alert`
48
+
49
+ Source: `src/components/Alert/Alert.tsx`
50
+
51
+ > Discriminated by `mode`: `"default"` renders `title`/`children`/`actions`; `"collapsible"` requires `title`+`children` and forbids `actions`. `variant` is a categorical colour contract (`info`/`success`/`warning`/`error`).
52
+
53
+ | Prop | Type | Required | Default | Description |
54
+ | ---------- | ---------------------------- | -------- | --------- | ---------------------------------------------------------------------------------------------- |
55
+ | `actions` | `ReactNode` | no | — | |
56
+ | `argo` | `boolean` | no | — | @internal Transitional opt-in; removed once consumers wrap argo sections in `<ThemeProvider>`. |
57
+ | `hideIcon` | `boolean` | no | `false` | |
58
+ | `icon` | `ReactNode` | no | — | |
59
+ | `mode` | `"collapsible" \| "default"` | no | `default` | |
60
+ | `variant` | `Variant` | no | `info` | |
61
+
62
+ ### `Toaster`
63
+
64
+ Source: `src/components/Toast/Toaster.tsx`
65
+
66
+ > Mount ONCE at app root. Wraps `sonner`'s `<Toaster>` — accepts all of sonner's props (`position`, `theme`, `richColors`, …). Fire toasts imperatively with `toast()` / `useNotification`, not by rendering children.
67
+
68
+ _No own props — see note above for passthrough attributes._
69
+
70
+ ## Inputs — bare
71
+
72
+ ### `TextInput`
73
+
74
+ Source: `src/components/Input/TextInput/TextInput.tsx`
75
+
76
+ > Bare input. Plus all native `<input>` attributes.
77
+
78
+ | Prop | Type | Required | Default | Description |
79
+ | -------------------- | --------------------------------------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------- |
80
+ | `allowClear` | `boolean` | no | — | |
81
+ | `defaultValue` | `string \| null` | no | — | |
82
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
83
+ | `leftSuffix` | `ReactNode` | no | — | |
84
+ | `onClear` | `(() => void)` | no | — | |
85
+ | `onValueBlur` | `((value: string) => void)` | no | — | Called with the unwrapped string value on blur. For the raw event use `onBlur`. |
86
+ | `onValueChange` | `((value: string) => void)` | no | — | Called with the unwrapped string value on every change. For the raw event use `onChange`. |
87
+ | `prefix` | `ReactNode` | no | — | |
88
+ | `rightSuffix` | `ReactNode` | no | — | |
89
+ | `rightSuffixVariant` | `"default" \| "addon"` | no | — | |
90
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
91
+ | `state` | `"warning" \| "error" \| "default" \| null` | no | — | |
92
+ | `testId` | `string` | no | — | |
93
+ | `type` | `"text" \| "email" \| "date" \| "datetime-local" \| "password"` | no | `text` | |
94
+ | `value` | `string \| null` | no | — | |
95
+ | `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
96
+
97
+ ### `PasswordInput`
98
+
99
+ Source: `src/blocks/PasswordInput/PasswordInput.tsx`
100
+
101
+ | Prop | Type | Required | Default | Description |
102
+ | --------------------------- | ----------------------------------------------- | -------- | -------------- | ----------- |
103
+ | `allowClear` | `boolean` | no | `false` | |
104
+ | `allowPasswordToggle` | `boolean` | no | `false` | |
105
+ | `autoComplete` | `"off" \| "current-password" \| "new-password"` | no | `new-password` | |
106
+ | `defaultPasswordVisibility` | `boolean` | no | `false` | |
107
+ | `defaultValue` | `string \| null` | no | — | |
108
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
109
+ | `onValueBlur` | `((value: string) => void)` | no | — | |
110
+ | `onValueChange` | `((value: string) => void)` | no | — | |
111
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
112
+ | `state` | `"warning" \| "error" \| "default" \| null` | no | — | |
113
+ | `value` | `string \| null` | no | — | |
114
+ | `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
115
+
116
+ ### `Textarea`
117
+
118
+ Source: `src/blocks/Textarea/Textarea.tsx`
119
+
120
+ | Prop | Type | Required | Default | Description |
121
+ | -------------------- | --------------------------------------------------------- | -------- | --------- | ----------- |
122
+ | `containerClassName` | `string` | no | — | |
123
+ | `defaultValue` | `string \| null` | no | — | |
124
+ | `disableResize` | `boolean` | no | — | |
125
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
126
+ | `maxRows` | `number \| "unlimited"` | no | — | |
127
+ | `onValueBlur` | `(((value: string) => void) & ((value: string) => void))` | no | — | |
128
+ | `onValueChange` | `(((value: string) => void) & ((value: string) => void))` | no | — | |
129
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
130
+ | `state` | `"warning" \| "error" \| "default" \| null` | no | `default` | |
131
+ | `value` | `string \| null` | no | — | |
132
+ | `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
133
+
134
+ ## Inputs — FormGroup (label + input + help, shared validation state)
135
+
136
+ ### `FormGroup`
137
+
138
+ Source: `src/components/FormGroup/FormGroup.tsx`
139
+
140
+ > `state="error"` propagates to nested `FormGroup.TextInput` / `FormGroup.Help` via context. Subcomponents: `FormGroup.TextInput`, `FormGroup.NumberInput`, `FormGroup.ColorInput`, `FormGroup.Textarea`, `FormGroup.Help`.
141
+
142
+ | Prop | Type | Required | Default | Description |
143
+ | ----------- | --------------- | -------- | ------- | ----------- |
144
+ | `className` | `string` | no | — | |
145
+ | `state` | `ValidityState` | no | — | |
146
+ | `testId` | `string` | no | — | |
147
+
148
+ ### `FormGroup.TextInput`
149
+
150
+ Source: `src/components/FormGroup/FormGroupTextInput.tsx`
151
+
152
+ > NO `error` prop — error styling comes from the parent `FormGroup state="error"` via context. `state` is omitted from the surface for the same reason. Plus native `<input>` attributes.
153
+
154
+ | Prop | Type | Required | Default | Description |
155
+ | -------------------- | --------------------------------------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------- |
156
+ | `allowClear` | `boolean` | no | — | |
157
+ | `defaultValue` | `string \| null` | no | — | |
158
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
159
+ | `leftSuffix` | `ReactNode` | no | — | |
160
+ | `onClear` | `(() => void)` | no | — | |
161
+ | `onValueBlur` | `((value: string) => void)` | no | — | Called with the unwrapped string value on blur. For the raw event use `onBlur`. |
162
+ | `onValueChange` | `((value: string) => void)` | no | — | Called with the unwrapped string value on every change. For the raw event use `onChange`. |
163
+ | `prefix` | `ReactNode` | no | — | |
164
+ | `rightSuffix` | `ReactNode` | no | — | |
165
+ | `rightSuffixVariant` | `"default" \| "addon"` | no | — | |
166
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
167
+ | `testId` | `string` | no | — | |
168
+ | `type` | `"text" \| "email" \| "date" \| "datetime-local" \| "password"` | no | — | |
169
+ | `value` | `string \| null` | no | — | |
170
+ | `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
171
+
172
+ ### `FormGroup.Help`
173
+
174
+ Source: `src/components/FormGroup/FormGroupHelp.tsx`
175
+
176
+ | Prop | Type | Required | Default | Description |
177
+ | ----------- | -------- | -------- | ------- | ----------- |
178
+ | `className` | `string` | no | — | |
179
+
180
+ ## Forms — useAppForm field connectors (accessed as `field.X` inside `form.AppField`)
181
+
182
+ ### `field.TextField`
183
+
184
+ Source: `src/blocks/Form/connectors/TextField.tsx`
185
+
186
+ > Value/onChange/onBlur/id/name are wired from the field — do not pass them. Forwards remaining `FormGroup.TextInput` props.
187
+
188
+ | Prop | Type | Required | Default | Description |
189
+ | -------------------- | --------------------------------------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------- |
190
+ | `allowClear` | `boolean` | no | — | |
191
+ | `className` | `string` | no | — | |
192
+ | `defaultValue` | `string \| null` | no | — | |
193
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
194
+ | `help` | `ReactNode` | no | — | |
195
+ | `label` | `ReactNode` | no | — | |
196
+ | `leftSuffix` | `ReactNode` | no | — | |
197
+ | `onClear` | `(() => void)` | no | — | |
198
+ | `onValueBlur` | `((value: string) => void)` | no | — | Called with the unwrapped string value on blur. For the raw event use `onBlur`. |
199
+ | `onValueChange` | `((value: string) => void)` | no | — | Called with the unwrapped string value on every change. For the raw event use `onChange`. |
200
+ | `prefix` | `ReactNode` | no | — | |
201
+ | `required` | `boolean` | no | — | |
202
+ | `rightSuffix` | `ReactNode` | no | — | |
203
+ | `rightSuffixVariant` | `"default" \| "addon"` | no | — | |
204
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
205
+ | `testId` | `string` | no | — | |
206
+ | `type` | `"text" \| "email" \| "date" \| "datetime-local" \| "password"` | no | — | |
207
+ | `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
208
+
209
+ ### `field.PasswordField`
210
+
211
+ Source: `src/blocks/Form/connectors/PasswordField.tsx`
212
+
213
+ | Prop | Type | Required | Default | Description |
214
+ | --------------------------- | ----------------------------------------------- | -------- | ------- | ----------- |
215
+ | `allowClear` | `boolean` | no | — | |
216
+ | `allowPasswordToggle` | `boolean` | no | — | |
217
+ | `autoComplete` | `"off" \| "current-password" \| "new-password"` | no | — | |
218
+ | `className` | `string` | no | — | |
219
+ | `defaultPasswordVisibility` | `boolean` | no | — | |
220
+ | `defaultValue` | `string \| null` | no | — | |
221
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
222
+ | `help` | `ReactNode` | no | — | |
223
+ | `label` | `ReactNode` | no | — | |
224
+ | `onValueBlur` | `((value: string) => void)` | no | — | |
225
+ | `required` | `boolean` | no | — | |
226
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
227
+ | `state` | `"warning" \| "error" \| "default" \| null` | no | — | |
228
+ | `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
229
+
230
+ ### `field.NumberField`
231
+
232
+ Source: `src/blocks/Form/connectors/NumberField.tsx`
233
+
234
+ | Prop | Type | Required | Default | Description |
235
+ | -------------- | -------------------------------------------- | -------- | ------- | ----------- |
236
+ | `className` | `string` | no | — | |
237
+ | `defaultValue` | `number \| null` | no | — | |
238
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
239
+ | `help` | `ReactNode` | no | — | |
240
+ | `label` | `ReactNode` | no | — | |
241
+ | `onValueBlur` | `((value: number \| null) => void)` | no | — | |
242
+ | `prefix` | `ReactNode` | no | — | |
243
+ | `required` | `boolean` | no | — | |
244
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
245
+ | `suffix` | `ReactNode` | no | — | |
246
+ | `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
247
+
248
+ ### `field.SelectField`
249
+
250
+ Source: `src/blocks/Form/connectors/SelectField.tsx`
251
+
252
+ > `options` is required. Forwards `variant === "argo"` to `Select.Content`.
253
+
254
+ | Prop | Type | Required | Default | Description |
255
+ | ------------------ | -------------------------------------------- | -------- | ------- | ----------- |
256
+ | `options` | `readonly Option[]` | yes | — | |
257
+ | `autoComplete` | `string` | no | — | |
258
+ | `className` | `string` | no | — | |
259
+ | `defaultOpen` | `boolean` | no | — | |
260
+ | `defaultValue` | `string` | no | — | |
261
+ | `dir` | `"rtl" \| "ltr"` | no | — | |
262
+ | `disabled` | `boolean` | no | — | |
263
+ | `form` | `string` | no | — | |
264
+ | `help` | `ReactNode` | no | — | |
265
+ | `label` | `ReactNode` | no | — | |
266
+ | `name` | `string` | no | — | |
267
+ | `onOpenChange` | `((open: boolean) => void)` | no | — | |
268
+ | `open` | `boolean` | no | — | |
269
+ | `placeholder` | `string` | no | — | |
270
+ | `required` | `boolean` | no | — | |
271
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
272
+ | `state` | `"warning" \| "error" \| "default" \| null` | no | — | |
273
+ | `triggerClassName` | `string` | no | — | |
274
+ | `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
275
+
276
+ ### `field.TextAreaField`
277
+
278
+ Source: `src/blocks/Form/connectors/TextAreaField.tsx`
279
+
280
+ | Prop | Type | Required | Default | Description |
281
+ | -------------------- | --------------------------------------------------------- | -------- | ------- | ----------- |
282
+ | `className` | `string` | no | — | |
283
+ | `containerClassName` | `string` | no | — | |
284
+ | `defaultValue` | `string \| null` | no | — | |
285
+ | `disableResize` | `boolean` | no | — | |
286
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
287
+ | `help` | `ReactNode` | no | — | |
288
+ | `label` | `ReactNode` | no | — | |
289
+ | `maxRows` | `number \| "unlimited"` | no | — | |
290
+ | `onValueBlur` | `(((value: string) => void) & ((value: string) => void))` | no | — | |
291
+ | `required` | `boolean` | no | — | |
292
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
293
+ | `variant` | `"primary" \| "secondary" \| "argo" \| null` | no | — | |
294
+
295
+ ### `field.CheckboxField`
296
+
297
+ Source: `src/blocks/Form/connectors/CheckboxField.tsx`
298
+
299
+ | Prop | Type | Required | Default | Description |
300
+ | ------------------ | ---------------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------- |
301
+ | `argo` | `boolean` | no | — | @internal Transitional opt-in; removed once consumers wrap argo sections in `<ThemeProvider>`. |
302
+ | `asChild` | `boolean` | no | — | |
303
+ | `className` | `string` | no | — | |
304
+ | `description` | `ReactNode` | no | — | |
305
+ | `help` | `ReactNode` | no | — | |
306
+ | `label` | `ReactNode` | no | — | |
307
+ | `position` | `"start" \| "end"` | no | — | |
308
+ | `tooltip` | `ReactNode` | no | — | |
309
+ | `tooltipPlacement` | `"top" \| "right" \| "bottom" \| "left"` | no | — | |
310
+ | `variant` | `"default" \| "boxed" \| null` | no | — | |
311
+
312
+ ### `field.SwitchField`
313
+
314
+ Source: `src/blocks/Form/connectors/SwitchField.tsx`
315
+
316
+ | Prop | Type | Required | Default | Description |
317
+ | ------------- | ---------------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------- |
318
+ | `argo` | `boolean` | no | — | @internal Transitional opt-in; removed once consumers wrap argo sections in `<ThemeProvider>`. |
319
+ | `className` | `string` | no | — | |
320
+ | `description` | `ReactNode` | no | — | |
321
+ | `help` | `ReactNode` | no | — | |
322
+ | `label` | `ReactNode` | no | — | |
323
+ | `position` | `"start" \| "end"` | no | — | |
324
+ | `size` | `"small" \| "medium" \| "large" \| null` | no | — | |
325
+ | `variant` | `"default" \| "boxed" \| null` | no | — | |
326
+
327
+ ## Data display — Card (compound)
328
+
329
+ ### `Card`
330
+
331
+ Source: `src/components/Card/Card.tsx`
332
+
333
+ > Subcomponents that EXIST: `Card.Header`, `Card.Title`, `Card.Content`. There is NO `Card.Description` and NO `Card.Footer`. Plus native `<div>` attributes.
334
+
335
+ | Prop | Type | Required | Default | Description |
336
+ | ---------- | -------------------------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------- |
337
+ | `argo` | `boolean` | no | `false` | @internal Transitional opt-in; removed once consumers wrap argo sections in `<ThemeProvider>`. |
338
+ | `bordered` | `boolean \| null` | no | `false` | |
339
+ | `padding` | `"small" \| "medium" \| "large" \| "none" \| null` | no | `small` | |
340
+
341
+ ### `Card.Header`
342
+
343
+ Source: `src/components/Card/CardHeader.tsx`
344
+
345
+ > Native `<div>` attributes only.
346
+
347
+ _No own props — see note above for passthrough attributes._
348
+
349
+ ### `Card.Title`
350
+
351
+ Source: `src/components/Card/CardTitle.tsx`
352
+
353
+ > Native `<div>` attributes only.
354
+
355
+ _No own props — see note above for passthrough attributes._
356
+
357
+ ### `Card.Content`
358
+
359
+ Source: `src/components/Card/CardContent.tsx`
360
+
361
+ > Native `<div>` attributes only.
362
+
363
+ _No own props — see note above for passthrough attributes._
364
+
365
+ ## Theming
366
+
367
+ ### `ThemeProvider`
368
+
369
+ Source: `src/components/ThemeProvider/ThemeProvider.tsx`
370
+
371
+ > Wrap the app root. `brand` defaults to the canonical `keboola` brand. Pair with `useTheme()` to read/flip the brand at runtime.
372
+
373
+ | Prop | Type | Required | Default | Description |
374
+ | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
375
+ | `brand` | `{ id: string; name: string; colors: { foreground: string; background: string; muted: string; mutedForeground: string; border: string; primary: string; primaryForeground: string; destructive: string; destructiveForeground: string; accent?: string; accentForeground?: string; }; ... 6 more ...; ...` | no | — | Brand whose tokens drive the chrome (`@keboola/design`'s semantic CSS variables) inside this provider's subtree. Defaults to the canonical `keboola` brand so existing apps that mount `<ThemeProvider>` without a `brand` prop continue to render as today. |
376
+ | `colorScheme` | `ColorScheme` | no | `light` | Light/dark mode. `'system'` follows `prefers-color-scheme` and updates reactively. Defaults to `'light'` so existing mounts don't drift. Only the ROOT provider applies this (sets `data-theme`, owns the media listener); a nested provider inherits the root's resolved mode. |
377
+ | `setBrand` | `((brand: { id: string; name: string; colors: { foreground: string; background: string; muted: string; mutedForeground: string; border: string; primary: string; primaryForeground: string; destructive: string; destructiveForeground: string; accent?: string; accentForeground?: string; }; ... 6 m...` | no | — | Optional setter exposed through `useTheme()` so consumers can flip brands at runtime (Storybook toolbar, a customer-impersonation switch). |
package/README.md CHANGED
@@ -7,9 +7,18 @@ The Keboola design system — shadcn-aligned, Radix-underneath, Lucide icons.
7
7
 
8
8
  📦 **Storybook:** https://design-keboola.vercel.app/
9
9
 
10
- 📖 **Decision tree:** [`AGENTS.md`](./AGENTS.md) — which component to use when.
11
- 🎨 **Tokens:** [`DESIGN.md`](./DESIGN.md) — canonical token surface in [google-labs-code/design.md](https://github.com/google-labs-code/design.md) format; validated by `yarn lint --filter=@keboola/design`.
12
- 🎨 **Branding:** [`../../docs/branding.md`](../../docs/branding.md) (lands with PR #5674).
10
+ 📖 **Decision tree:** [`AGENTS.md`](./AGENTS.md) — which component to use when (ships in the tarball).
11
+ 🔧 **Prop signatures:** [`COMPONENT-API.md`](./COMPONENT-API.md) — generated, version-pinned (ships in the tarball).
12
+
13
+ ## For agents and consumers: read the installed package's AGENTS.md first
14
+
15
+ Before writing UI with this design system, read the contract that ships with the version you installed:
16
+
17
+ ```
18
+ node_modules/@keboola/design/AGENTS.md
19
+ ```
20
+
21
+ It is version-pinned to your lockfile, so it always matches the components you actually have — read it rather than relying on the published Storybook or these docs, which track `main`. More generally, before building against any installed `@keboola/*` package, read that package's `node_modules/@keboola/<name>/AGENTS.md` when present.
13
22
 
14
23
  ## Install
15
24
 
package/dist/index.cjs CHANGED
@@ -10331,6 +10331,29 @@ var brandToCssVars = (brand, resolvedMode) => {
10331
10331
  vars["--color-primary-foreground"] = colors8.primaryForeground;
10332
10332
  vars["--color-destructive"] = colors8.destructive;
10333
10333
  vars["--color-destructive-foreground"] = colors8.destructiveForeground;
10334
+ if (colors8.accent !== void 0) vars["--color-accent"] = colors8.accent;
10335
+ if (colors8.accentForeground !== void 0)
10336
+ vars["--color-accent-foreground"] = colors8.accentForeground;
10337
+ }
10338
+ const sidebar = resolvedMode === "dark" ? brand.sidebarColorsDark : brand.sidebarColors;
10339
+ if (sidebar) {
10340
+ const sidebarVars = {
10341
+ "--color-sidebar": sidebar.sidebar,
10342
+ "--color-sidebar-foreground": sidebar.sidebarForeground,
10343
+ "--color-sidebar-primary": sidebar.sidebarPrimary,
10344
+ "--color-sidebar-primary-foreground": sidebar.sidebarPrimaryForeground,
10345
+ "--color-sidebar-accent": sidebar.sidebarAccent,
10346
+ "--color-sidebar-accent-foreground": sidebar.sidebarAccentForeground,
10347
+ "--color-sidebar-border": sidebar.sidebarBorder,
10348
+ "--color-sidebar-ring": sidebar.sidebarRing
10349
+ };
10350
+ for (const [name, value] of Object.entries(sidebarVars)) {
10351
+ if (value !== void 0) vars[name] = value;
10352
+ }
10353
+ }
10354
+ const fontFamily = brand.typography?.fontFamily?.trim();
10355
+ if (fontFamily) {
10356
+ vars["--font-sans"] = fontFamily;
10334
10357
  }
10335
10358
  if (brand.radii) {
10336
10359
  vars["--radius-sm"] = brand.radii.sm;
@@ -10418,7 +10441,7 @@ var useTheme = () => {
10418
10441
  const context = react.use(ThemeContext);
10419
10442
  if (context === null) {
10420
10443
  throw new Error(
10421
- "useTheme must be used within a <ThemeProvider>. Wrap your app root with <ThemeProvider brand={...}> from @keboola/design."
10444
+ "useTheme must be used within a <ThemeProvider>. Wrap your app root with <ThemeProvider> from @keboola/design."
10422
10445
  );
10423
10446
  }
10424
10447
  return context;
@@ -10427,7 +10450,7 @@ var useColorScheme = () => {
10427
10450
  const context = react.use(ThemeContext);
10428
10451
  if (context === null) {
10429
10452
  throw new Error(
10430
- "useColorScheme must be used within a <ThemeProvider>. Wrap your app root with <ThemeProvider colorScheme={...}> from @keboola/design."
10453
+ "useColorScheme must be used within a <ThemeProvider>. Wrap your app root with <ThemeProvider> from @keboola/design."
10431
10454
  );
10432
10455
  }
10433
10456
  return { colorScheme: context.colorScheme, resolvedMode: context.resolvedMode };