@keboola/design 5.1.0 → 6.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/AGENTS.md CHANGED
@@ -84,7 +84,7 @@ This file answers **which** component to use; [`COMPONENT-API.md`](./COMPONENT-A
84
84
  | `FormGroup.TextInput` | Text field with help text + error state from `FormGroup state` |
85
85
  | `useAppForm` | Full form layouts with validation (see Forms below) |
86
86
  | `useAppForm` connectors | Picking between `TextField` / `NumberField` / `SelectField` / … |
87
- | `InputOtp` | Fixed-length verification code (MFA, email confirm, sudo step-up) |
87
+ | `OtpInput` | Fixed-length verification code (MFA, email confirm, sudo step-up) |
88
88
  | `FileUpload` | Argo-only drag-and-drop file picker; caller owns the file array |
89
89
 
90
90
  **Never** build custom label + input combinations — compose `Label` + `FormGroup.TextInput` + `FormGroup.Help` inside `FormGroup`.
package/COMPONENT-API.md CHANGED
@@ -135,13 +135,11 @@ Source: `src/blocks/Textarea/Textarea.tsx`
135
135
 
136
136
  Source: `src/components/FormGroup/FormGroup.tsx`
137
137
 
138
- > `state="error"` propagates to nested `FormGroup.TextInput` / `FormGroup.Help` via context. Subcomponents: `FormGroup.TextInput`, `FormGroup.NumberInput`, `FormGroup.ColorInput`, `FormGroup.Textarea`, `FormGroup.Help`.
138
+ > `state` ("error" | "warning") propagates to nested inputs (e.g. `FormGroup.TextInput`) via context; `FormGroup.Help` stays advisory (reacts only to "warning"). Validation errors render via `FormGroup.Error` (`role="alert"`), not the input `state`. Subcomponents: `FormGroup.TextInput`, `FormGroup.NumberInput`, `FormGroup.ColorInput`, `FormGroup.Textarea`, `FormGroup.Help`, `FormGroup.Error`. Plus native `<div>` attributes (`className`, `data-testid`, …).
139
139
 
140
- | Prop | Type | Required | Default | Description |
141
- | ----------- | --------------- | -------- | ------- | ----------- |
142
- | `className` | `string` | no | — | |
143
- | `state` | `ValidityState` | no | — | |
144
- | `testId` | `string` | no | — | |
140
+ | Prop | Type | Required | Default | Description |
141
+ | ------- | --------------- | -------- | ------- | ----------- |
142
+ | `state` | `ValidityState` | no | — | |
145
143
 
146
144
  ### `FormGroup.TextInput`
147
145
 
@@ -171,9 +169,17 @@ Source: `src/components/FormGroup/FormGroupTextInput.tsx`
171
169
 
172
170
  Source: `src/components/FormGroup/FormGroupHelp.tsx`
173
171
 
174
- | Prop | Type | Required | Default | Description |
175
- | ----------- | -------- | -------- | ------- | ----------- |
176
- | `className` | `string` | no | — | |
172
+ _No own props — see note above for passthrough attributes._
173
+
174
+ ### `FormGroup.Error`
175
+
176
+ Source: `src/components/FormGroup/FormGroupError.tsx`
177
+
178
+ > Field validation error — carries `role="alert"` (announced on appearance). Pass `children` or an `errors` array (TanStack `string` / `{ message }` entries); a single message renders inline, several as a `<ul>`. Plus native `<div>` attributes.
179
+
180
+ | Prop | Type | Required | Default | Description |
181
+ | -------- | ----------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
182
+ | `errors` | `readonly (string \| { message?: string; })[] \| undefined` | no | — | Field validation errors. TanStack Form errors are strings (function validators) or `{ message }` objects (Standard Schema / zod). A single message renders inline; several render as a list. Ignored when `children` is provided. |
177
183
 
178
184
  ## Forms — useAppForm field connectors (accessed as `field.X` inside `form.AppField`)
179
185
 
@@ -183,65 +189,74 @@ Source: `src/blocks/Form/connectors/TextField.tsx`
183
189
 
184
190
  > Value/onChange/onBlur/id/name are wired from the field — do not pass them. Forwards remaining `FormGroup.TextInput` props.
185
191
 
186
- | Prop | Type | Required | Default | Description |
187
- | -------------------- | --------------------------------------------------------------- | -------- | ------- | ----------------------------------------------------------------------------------------- |
188
- | `allowClear` | `boolean` | no | — | |
189
- | `className` | `string` | no | — | |
190
- | `defaultValue` | `string \| null` | no | — | |
191
- | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
192
- | `help` | `ReactNode` | no | — | |
193
- | `label` | `ReactNode` | no | — | |
194
- | `leftSuffix` | `ReactNode` | no | — | |
195
- | `onClear` | `(() => void)` | no | — | |
196
- | `onValueBlur` | `((value: string) => void)` | no | — | Called with the unwrapped string value on blur. For the raw event use `onBlur`. |
197
- | `onValueChange` | `((value: string) => void)` | no | — | Called with the unwrapped string value on every change. For the raw event use `onChange`. |
198
- | `prefix` | `ReactNode` | no | — | |
199
- | `required` | `boolean` | no | — | |
200
- | `rightSuffix` | `ReactNode` | no | — | |
201
- | `rightSuffixVariant` | `"default" \| "addon"` | no | — | |
202
- | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
203
- | `testId` | `string` | no | — | |
204
- | `type` | `"text" \| "email" \| "date" \| "datetime-local" \| "password"` | no | — | |
205
- | `variant` | `"primary" \| "secondary" \| null` | no | — | |
192
+ | Prop | Type | Required | Default | Description |
193
+ | -------------------- | --------------------------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
194
+ | `allowClear` | `boolean` | no | — | |
195
+ | `aria-describedby` | `string` | no | — | Identifies the element (or elements) that describes the object. @see aria-labelledby |
196
+ | `className` | `string` | no | — | |
197
+ | `defaultValue` | `string \| null` | no | — | |
198
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
199
+ | `help` | `ReactNode` | no | — | |
200
+ | `label` | `ReactNode` | no | — | |
201
+ | `leftSuffix` | `ReactNode` | no | — | |
202
+ | `onClear` | `(() => void)` | no | — | |
203
+ | `onValueBlur` | `((value: string) => void)` | no | — | Called with the unwrapped string value on blur. For the raw event use `onBlur`. |
204
+ | `onValueChange` | `((value: string) => void)` | no | — | Called with the unwrapped string value on every change. For the raw event use `onChange`. |
205
+ | `prefix` | `ReactNode` | no | — | |
206
+ | `required` | `boolean` | no | — | |
207
+ | `requiredMark` | `RequiredMark` | no | — | Which marker to show beside the label — gated by `required` so it never lies: `'required'` renders `*` only when the field is `required`; `'optional'` renders `(optional)` only when it is not; `'hidden'` renders neither. Defaults to `'required'`. |
208
+ | `rightSuffix` | `ReactNode` | no | — | |
209
+ | `rightSuffixVariant` | `"default" \| "addon"` | no | — | |
210
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
211
+ | `testId` | `string` | no | — | |
212
+ | `tooltip` | `ReactNode` | no | — | |
213
+ | `type` | `"text" \| "email" \| "date" \| "datetime-local" \| "password"` | no | — | |
214
+ | `variant` | `"primary" \| "secondary" \| null` | no | — | |
206
215
 
207
216
  ### `field.PasswordField`
208
217
 
209
218
  Source: `src/blocks/Form/connectors/PasswordField.tsx`
210
219
 
211
- | Prop | Type | Required | Default | Description |
212
- | --------------------------- | ----------------------------------------------- | -------- | ------- | ----------- |
213
- | `allowClear` | `boolean` | no | — | |
214
- | `allowPasswordToggle` | `boolean` | no | — | |
215
- | `autoComplete` | `"off" \| "current-password" \| "new-password"` | no | — | |
216
- | `className` | `string` | no | — | |
217
- | `defaultPasswordVisibility` | `boolean` | no | — | |
218
- | `defaultValue` | `string \| null` | no | — | |
219
- | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
220
- | `help` | `ReactNode` | no | — | |
221
- | `label` | `ReactNode` | no | — | |
222
- | `onValueBlur` | `((value: string) => void)` | no | — | |
223
- | `required` | `boolean` | no | — | |
224
- | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
225
- | `state` | `"warning" \| "error" \| "default" \| null` | no | — | |
226
- | `variant` | `"primary" \| "secondary" \| null` | no | — | |
220
+ | Prop | Type | Required | Default | Description |
221
+ | --------------------------- | ----------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
222
+ | `allowClear` | `boolean` | no | — | |
223
+ | `allowPasswordToggle` | `boolean` | no | — | |
224
+ | `aria-describedby` | `string` | no | — | Identifies the element (or elements) that describes the object. @see aria-labelledby |
225
+ | `autoComplete` | `"off" \| "current-password" \| "new-password"` | no | — | |
226
+ | `className` | `string` | no | — | |
227
+ | `defaultPasswordVisibility` | `boolean` | no | — | |
228
+ | `defaultValue` | `string \| null` | no | — | |
229
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
230
+ | `help` | `ReactNode` | no | — | |
231
+ | `label` | `ReactNode` | no | — | |
232
+ | `onValueBlur` | `((value: string) => void)` | no | — | |
233
+ | `required` | `boolean` | no | — | |
234
+ | `requiredMark` | `RequiredMark` | no | — | Which marker to show beside the label — gated by `required` so it never lies: `'required'` renders `*` only when the field is `required`; `'optional'` renders `(optional)` only when it is not; `'hidden'` renders neither. Defaults to `'required'`. |
235
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
236
+ | `state` | `"warning" \| "error" \| "default" \| null` | no | — | |
237
+ | `tooltip` | `ReactNode` | no | — | |
238
+ | `variant` | `"primary" \| "secondary" \| null` | no | — | |
227
239
 
228
240
  ### `field.NumberField`
229
241
 
230
242
  Source: `src/blocks/Form/connectors/NumberField.tsx`
231
243
 
232
- | Prop | Type | Required | Default | Description |
233
- | -------------- | ------------------------------------------ | -------- | ------- | ----------- |
234
- | `className` | `string` | no | — | |
235
- | `defaultValue` | `number \| null` | no | — | |
236
- | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
237
- | `help` | `ReactNode` | no | — | |
238
- | `label` | `ReactNode` | no | — | |
239
- | `onValueBlur` | `((value: number \| null) => void)` | no | — | |
240
- | `prefix` | `ReactNode` | no | — | |
241
- | `required` | `boolean` | no | — | |
242
- | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
243
- | `suffix` | `ReactNode` | no | — | |
244
- | `variant` | `"primary" \| "secondary" \| null` | no | — | |
244
+ | Prop | Type | Required | Default | Description |
245
+ | ------------------ | ------------------------------------------ | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
246
+ | `aria-describedby` | `string` | no | — | Identifies the element (or elements) that describes the object. @see aria-labelledby |
247
+ | `className` | `string` | no | — | |
248
+ | `defaultValue` | `number \| null` | no | — | |
249
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
250
+ | `help` | `ReactNode` | no | — | |
251
+ | `label` | `ReactNode` | no | — | |
252
+ | `onValueBlur` | `((value: number \| null) => void)` | no | — | |
253
+ | `prefix` | `ReactNode` | no | — | |
254
+ | `required` | `boolean` | no | — | |
255
+ | `requiredMark` | `RequiredMark` | no | — | Which marker to show beside the label — gated by `required` so it never lies: `'required'` renders `*` only when the field is `required`; `'optional'` renders `(optional)` only when it is not; `'hidden'` renders neither. Defaults to `'required'`. |
256
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
257
+ | `suffix` | `ReactNode` | no | — | |
258
+ | `tooltip` | `ReactNode` | no | — | |
259
+ | `variant` | `"primary" \| "secondary" \| null` | no | — | |
245
260
 
246
261
  ### `field.SelectField`
247
262
 
@@ -249,47 +264,53 @@ Source: `src/blocks/Form/connectors/SelectField.tsx`
249
264
 
250
265
  > Pass `items` (canonical, matches the base `Select`) or the deprecated `options` alias — one is required.
251
266
 
252
- | Prop | Type | Required | Default | Description |
253
- | ------------------ | ------------------------------------------- | -------- | ------- | ----------------------- |
254
- | `autoComplete` | `string` | no | — | |
255
- | `className` | `string` | no | — | |
256
- | `defaultOpen` | `boolean` | no | — | |
257
- | `defaultValue` | `string` | no | — | |
258
- | `dir` | `"rtl" \| "ltr"` | no | — | |
259
- | `disabled` | `boolean` | no | — | |
260
- | `form` | `string` | no | — | |
261
- | `help` | `ReactNode` | no | — | |
262
- | `items` | `readonly Option[]` | no | — | |
263
- | `label` | `ReactNode` | no | — | |
264
- | `name` | `string` | no | — | |
265
- | `onOpenChange` | `((open: boolean) => void)` | no | — | |
266
- | `open` | `boolean` | no | — | |
267
- | `options` | `readonly Option[]` | no | — | @deprecated use `items` |
268
- | `placeholder` | `string` | no | — | |
269
- | `required` | `boolean` | no | — | |
270
- | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
271
- | `state` | `"warning" \| "error" \| "default" \| null` | no | — | |
272
- | `triggerClassName` | `string` | no | — | |
273
- | `variant` | `"primary" \| "secondary" \| null` | no | — | |
274
-
275
- ### `field.TextAreaField`
276
-
277
- Source: `src/blocks/Form/connectors/TextAreaField.tsx`
278
-
279
- | Prop | Type | Required | Default | Description |
280
- | -------------------- | --------------------------------------------------------- | -------- | ------- | ----------- |
281
- | `className` | `string` | no | — | |
282
- | `containerClassName` | `string` | no | — | |
283
- | `defaultValue` | `string \| null` | no | — | |
284
- | `disableResize` | `boolean` | no | — | |
285
- | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
286
- | `help` | `ReactNode` | no | — | |
287
- | `label` | `ReactNode` | no | — | |
288
- | `maxRows` | `number \| "unlimited"` | no | — | |
289
- | `onValueBlur` | `(((value: string) => void) & ((value: string) => void))` | no | — | |
290
- | `required` | `boolean` | no | — | |
291
- | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
292
- | `variant` | `"primary" \| "secondary" \| null` | no | — | |
267
+ | Prop | Type | Required | Default | Description |
268
+ | ------------------ | ------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
269
+ | `aria-describedby` | `string` | no | — | |
270
+ | `autoComplete` | `string` | no | — | |
271
+ | `className` | `string` | no | — | |
272
+ | `defaultOpen` | `boolean` | no | — | |
273
+ | `defaultValue` | `string` | no | — | |
274
+ | `dir` | `"rtl" \| "ltr"` | no | — | |
275
+ | `disabled` | `boolean` | no | — | |
276
+ | `form` | `string` | no | — | |
277
+ | `help` | `ReactNode` | no | — | |
278
+ | `items` | `readonly Option[]` | no | — | |
279
+ | `label` | `ReactNode` | no | — | |
280
+ | `name` | `string` | no | — | |
281
+ | `onOpenChange` | `((open: boolean) => void)` | no | — | |
282
+ | `open` | `boolean` | no | — | |
283
+ | `options` | `readonly Option[]` | no | — | @deprecated use `items` |
284
+ | `placeholder` | `string` | no | — | |
285
+ | `required` | `boolean` | no | — | |
286
+ | `requiredMark` | `RequiredMark` | no | — | Which marker to show beside the label — gated by `required` so it never lies: `'required'` renders `*` only when the field is `required`; `'optional'` renders `(optional)` only when it is not; `'hidden'` renders neither. Defaults to `'required'`. |
287
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
288
+ | `state` | `"warning" \| "error" \| "default" \| null` | no | — | |
289
+ | `tooltip` | `ReactNode` | no | — | |
290
+ | `triggerClassName` | `string` | no | — | |
291
+ | `variant` | `"primary" \| "secondary" \| null` | no | — | |
292
+
293
+ ### `field.TextareaField`
294
+
295
+ Source: `src/blocks/Form/connectors/TextareaField.tsx`
296
+
297
+ | Prop | Type | Required | Default | Description |
298
+ | -------------------- | --------------------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
299
+ | `aria-describedby` | `string` | no | — | Identifies the element (or elements) that describes the object. @see aria-labelledby |
300
+ | `className` | `string` | no | — | |
301
+ | `containerClassName` | `string` | no | — | |
302
+ | `defaultValue` | `string \| null` | no | — | |
303
+ | `disableResize` | `boolean` | no | — | |
304
+ | `focusVariant` | `"off" \| "on" \| "default" \| null` | no | — | |
305
+ | `help` | `ReactNode` | no | — | |
306
+ | `label` | `ReactNode` | no | — | |
307
+ | `maxRows` | `number \| "unlimited"` | no | — | |
308
+ | `onValueBlur` | `(((value: string) => void) & ((value: string) => void))` | no | — | |
309
+ | `required` | `boolean` | no | — | |
310
+ | `requiredMark` | `RequiredMark` | no | — | Which marker to show beside the label — gated by `required` so it never lies: `'required'` renders `*` only when the field is `required`; `'optional'` renders `(optional)` only when it is not; `'hidden'` renders neither. Defaults to `'required'`. |
311
+ | `sizing` | `"small" \| "medium" \| "default" \| null` | no | — | |
312
+ | `tooltip` | `ReactNode` | no | — | |
313
+ | `variant` | `"primary" \| "secondary" \| null` | no | — | |
293
314
 
294
315
  ### `field.CheckboxField`
295
316
 
@@ -300,8 +321,6 @@ Source: `src/blocks/Form/connectors/CheckboxField.tsx`
300
321
  | `asChild` | `boolean` | no | — | |
301
322
  | `className` | `string` | no | — | |
302
323
  | `description` | `ReactNode` | no | — | |
303
- | `help` | `ReactNode` | no | — | |
304
- | `label` | `ReactNode` | no | — | |
305
324
  | `position` | `"start" \| "end"` | no | — | |
306
325
  | `tooltip` | `ReactNode` | no | — | |
307
326
  | `tooltipPlacement` | `"top" \| "right" \| "bottom" \| "left"` | no | — | |
@@ -315,12 +334,35 @@ Source: `src/blocks/Form/connectors/SwitchField.tsx`
315
334
  | ------------- | ---------------------------------------- | -------- | ------- | ----------- |
316
335
  | `className` | `string` | no | — | |
317
336
  | `description` | `ReactNode` | no | — | |
318
- | `help` | `ReactNode` | no | — | |
319
- | `label` | `ReactNode` | no | — | |
320
337
  | `position` | `"start" \| "end"` | no | — | |
321
338
  | `size` | `"small" \| "medium" \| "large" \| null` | no | — | |
322
339
  | `variant` | `"default" \| "boxed" \| null` | no | — | |
323
340
 
341
+ ### `field.OtpInputField`
342
+
343
+ Source: `src/blocks/Form/connectors/OtpInputField.tsx`
344
+
345
+ > Fixed-length code; string value. Pass `maxLength` — slots are rendered for you.
346
+
347
+ | Prop | Type | Required | Default | Description |
348
+ | ----------------------------- | ------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
349
+ | `maxLength` | `number` | yes | — | |
350
+ | `aria-describedby` | `string` | no | — | |
351
+ | `className` | `string` | no | — | |
352
+ | `containerClassName` | `string` | no | — | |
353
+ | `help` | `ReactNode` | no | — | |
354
+ | `label` | `ReactNode` | no | — | |
355
+ | `noScriptCSSFallback` | `string \| null` | no | — | |
356
+ | `onComplete` | `((...args: any[]) => unknown)` | no | — | |
357
+ | `pasteTransformer` | `((pasted: string) => string)` | no | — | |
358
+ | `pushPasswordManagerStrategy` | `"none" \| "increase-width"` | no | — | |
359
+ | `render` | `undefined` | no | — | |
360
+ | `required` | `boolean` | no | — | |
361
+ | `requiredMark` | `RequiredMark` | no | — | Which marker to show beside the label — gated by `required` so it never lies: `'required'` renders `*` only when the field is `required`; `'optional'` renders `(optional)` only when it is not; `'hidden'` renders neither. Defaults to `'required'`. |
362
+ | `sizing` | `OtpInputSizing` | no | — | |
363
+ | `textAlign` | `"center" \| "right" \| "left"` | no | — | |
364
+ | `tooltip` | `ReactNode` | no | — | |
365
+
324
366
  ## Data display — Card (compound)
325
367
 
326
368
  ### `Card`
package/dist/editors.cjs CHANGED
@@ -324,14 +324,13 @@ var helpVariants = classVarianceAuthority.cva(["tw-m-0", "tw-text-xs"], {
324
324
  variants: {
325
325
  state: {
326
326
  default: ["tw-text-muted-foreground"],
327
- error: ["tw-text-destructive"],
328
327
  warning: ["tw-text-warning"]
329
328
  }
330
329
  }
331
330
  });
332
- var HelpBlock = ({ children, className, state = "default", testId }) => {
331
+ var HelpBlock = ({ children, className, state = "default", ...rest }) => {
333
332
  if (!children) return null;
334
- return /* @__PURE__ */ jsxRuntime.jsx("p", { "data-testid": testId, className: helpVariants({ state, className }), children });
333
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { ...rest, className: helpVariants({ state, className }), children });
335
334
  };
336
335
 
337
336
  // src/icons/index.ts
@@ -371,11 +370,12 @@ var variants = classVarianceAuthority.cva(
371
370
  "tw-items-center",
372
371
  "tw-justify-center",
373
372
  "tw-gap-2",
374
- // text
373
+ // text — chrome weight/tracking are brand-overridable tokens
374
+ // (`--font-weight-medium` / `--letter-spacing-chrome`); casing stays `tw-uppercase`.
375
375
  "tw-text-xs",
376
376
  "tw-leading-5",
377
377
  "tw-font-medium",
378
- "tw-tracking-[1px]",
378
+ "tw-tracking-chrome",
379
379
  "tw-uppercase",
380
380
  // border — legacy (non-argo) chrome uses a fixed radius, not the brand token.
381
381
  "tw-rounded",