@keboola/design 9.1.0 → 10.1.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.
Files changed (84) hide show
  1. package/AGENTS.md +117 -40
  2. package/COMPONENT-API.md +31 -9
  3. package/README.md +3 -3
  4. package/dist/MermaidDiagram-EOKJHQQV.js +10 -0
  5. package/dist/MermaidDiagram-EOKJHQQV.js.map +1 -0
  6. package/dist/charts.d.ts +31 -2
  7. package/dist/charts.js +6 -9
  8. package/dist/charts.js.map +1 -1
  9. package/dist/chunk-63NSN2VL.js +274 -0
  10. package/dist/chunk-63NSN2VL.js.map +1 -0
  11. package/dist/{rjsf.cjs → chunk-6FPEI4EM.js} +1491 -5701
  12. package/dist/chunk-6FPEI4EM.js.map +1 -0
  13. package/dist/chunk-7PUUHEJQ.js +1313 -0
  14. package/dist/chunk-7PUUHEJQ.js.map +1 -0
  15. package/dist/chunk-BOHNXTMM.js +606 -0
  16. package/dist/chunk-BOHNXTMM.js.map +1 -0
  17. package/dist/{testing.cjs → chunk-C3L3TBBT.js} +33 -164
  18. package/dist/chunk-C3L3TBBT.js.map +1 -0
  19. package/dist/chunk-CTCFYWJC.js +407 -0
  20. package/dist/chunk-CTCFYWJC.js.map +1 -0
  21. package/dist/chunk-ESBL3IPF.js +23 -0
  22. package/dist/chunk-ESBL3IPF.js.map +1 -0
  23. package/dist/chunk-IJTHFNNJ.js +261 -0
  24. package/dist/chunk-IJTHFNNJ.js.map +1 -0
  25. package/dist/chunk-JP7PNHLH.js +40 -0
  26. package/dist/chunk-JP7PNHLH.js.map +1 -0
  27. package/dist/chunk-KPNAW5MU.js +229 -0
  28. package/dist/chunk-KPNAW5MU.js.map +1 -0
  29. package/dist/chunk-L37JJ6MR.js +152 -0
  30. package/dist/chunk-L37JJ6MR.js.map +1 -0
  31. package/dist/chunk-Q7NWXLCT.js +90 -0
  32. package/dist/chunk-Q7NWXLCT.js.map +1 -0
  33. package/dist/chunk-SYIEF644.js +1016 -0
  34. package/dist/chunk-SYIEF644.js.map +1 -0
  35. package/dist/chunk-VMFSRV5H.js +16 -0
  36. package/dist/chunk-VMFSRV5H.js.map +1 -0
  37. package/dist/chunk-VPPM7UUQ.js +47 -0
  38. package/dist/chunk-VPPM7UUQ.js.map +1 -0
  39. package/dist/chunk-XV3UUOYF.js +845 -0
  40. package/dist/chunk-XV3UUOYF.js.map +1 -0
  41. package/dist/editors.d.ts +27 -3
  42. package/dist/editors.js +85 -2081
  43. package/dist/editors.js.map +1 -1
  44. package/dist/icons.d.ts +29 -8
  45. package/dist/icons.js +2 -361
  46. package/dist/icons.js.map +1 -1
  47. package/dist/index.d.ts +709 -425
  48. package/dist/index.js +5042 -13885
  49. package/dist/index.js.map +1 -1
  50. package/dist/markdown-editor.js +41 -3426
  51. package/dist/markdown-editor.js.map +1 -1
  52. package/dist/mermaid.js +8 -1129
  53. package/dist/mermaid.js.map +1 -1
  54. package/dist/rjsf.js +180 -9381
  55. package/dist/rjsf.js.map +1 -1
  56. package/dist/styles.css +1 -1
  57. package/dist/testing.js +5 -357
  58. package/dist/testing.js.map +1 -1
  59. package/package.json +28 -73
  60. package/src/styles.css +60 -3
  61. package/src/theme.css +1 -0
  62. package/dist/charts.cjs +0 -268
  63. package/dist/charts.cjs.map +0 -1
  64. package/dist/charts.d.cts +0 -181
  65. package/dist/constants-D3gaMY-W.d.cts +0 -39
  66. package/dist/editors.cjs +0 -2440
  67. package/dist/editors.cjs.map +0 -1
  68. package/dist/editors.d.cts +0 -165
  69. package/dist/icons.cjs +0 -23888
  70. package/dist/icons.cjs.map +0 -1
  71. package/dist/icons.d.cts +0 -20
  72. package/dist/index.cjs +0 -24894
  73. package/dist/index.cjs.map +0 -1
  74. package/dist/index.d.cts +0 -10438
  75. package/dist/markdown-editor.cjs +0 -4636
  76. package/dist/markdown-editor.cjs.map +0 -1
  77. package/dist/markdown-editor.d.cts +0 -75
  78. package/dist/mermaid.cjs +0 -1138
  79. package/dist/mermaid.cjs.map +0 -1
  80. package/dist/mermaid.d.cts +0 -15
  81. package/dist/rjsf.cjs.map +0 -1
  82. package/dist/rjsf.d.cts +0 -55
  83. package/dist/testing.cjs.map +0 -1
  84. package/dist/testing.d.cts +0 -25
@@ -0,0 +1,1016 @@
1
+ import { HelpBlock } from './chunk-ESBL3IPF.js';
2
+ import { Button } from './chunk-CTCFYWJC.js';
3
+ import { X, Pipette } from './chunk-BOHNXTMM.js';
4
+ import { useArgoDesign } from './chunk-63NSN2VL.js';
5
+ import { cn } from './chunk-JP7PNHLH.js';
6
+ import * as ScrollAreaPrimitive2 from '@radix-ui/react-scroll-area';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
+ import * as RLabel from '@radix-ui/react-label';
9
+ import { cva } from 'class-variance-authority';
10
+ import TextareaAutosize from 'react-textarea-autosize';
11
+ import { createContext, useState, useRef, useCallback, useMemo, use } from 'react';
12
+
13
+ // src/utils/mergeRefs.ts
14
+ function setRef(ref, value) {
15
+ if (typeof ref === "function") {
16
+ ref(value);
17
+ } else if (ref != null) {
18
+ ref.current = value;
19
+ }
20
+ }
21
+ var mergeRefs = (...refs) => {
22
+ return (node) => refs.forEach((ref) => setRef(ref, node));
23
+ };
24
+
25
+ // src/utils/createChangeInputEvent.ts
26
+ var createChangeInputEvent = (input) => {
27
+ const changeEvent = {
28
+ target: input,
29
+ currentTarget: input,
30
+ type: "change",
31
+ nativeEvent: new Event("change", { bubbles: true }),
32
+ bubbles: true,
33
+ cancelable: false,
34
+ defaultPrevented: false,
35
+ eventPhase: 2,
36
+ // AT_TARGET
37
+ isTrusted: false,
38
+ // Synthetic events are not trusted
39
+ preventDefault: () => {
40
+ },
41
+ // Provide dummy functions if not needed
42
+ isDefaultPrevented: () => false,
43
+ stopPropagation: () => {
44
+ },
45
+ isPropagationStopped: () => false,
46
+ persist: () => {
47
+ },
48
+ timeStamp: Date.now()
49
+ };
50
+ Object.defineProperty(changeEvent, "target", {
51
+ value: input,
52
+ writable: false
53
+ });
54
+ return changeEvent;
55
+ };
56
+
57
+ // src/utils/createPrefixedString.ts
58
+ var createPrefixedString = (prefix) => (literals) => literals.reduce((acc, literal) => acc + literal, `${prefix}-`);
59
+ var ScrollBar = ({ className, orientation = "vertical", ...props }) => /* @__PURE__ */ jsx(
60
+ ScrollAreaPrimitive2.ScrollAreaScrollbar,
61
+ {
62
+ orientation,
63
+ className: cn(
64
+ "tw:flex tw:touch-none tw:select-none tw:transition-color",
65
+ {
66
+ "tw:h-full tw:w-2.5 tw:p-px": orientation === "vertical",
67
+ "tw:h-2.5 tw:flex-col tw:p-px": orientation === "horizontal"
68
+ },
69
+ className
70
+ ),
71
+ ...props,
72
+ children: /* @__PURE__ */ jsx(
73
+ ScrollAreaPrimitive2.ScrollAreaThumb,
74
+ {
75
+ className: cn(
76
+ "tw:relative",
77
+ "tw:flex-1",
78
+ "tw:rounded-full",
79
+ "tw:bg-border",
80
+ "tw:hover:bg-muted-foreground"
81
+ )
82
+ }
83
+ )
84
+ }
85
+ );
86
+ var ScrollArea = ({
87
+ ref,
88
+ className,
89
+ children,
90
+ viewPortClassName,
91
+ orientation,
92
+ scrollBarClassName,
93
+ ...props
94
+ }) => /* @__PURE__ */ jsxs(
95
+ ScrollAreaPrimitive2.Root,
96
+ {
97
+ "data-slot": "scroll-area",
98
+ className: cn(
99
+ "tw:peer/scroll-area tw:relative tw:overflow-hidden tw:focus-visible:outline-hidden",
100
+ className
101
+ ),
102
+ ...props,
103
+ children: [
104
+ /* @__PURE__ */ jsx(
105
+ ScrollAreaPrimitive2.Viewport,
106
+ {
107
+ ref,
108
+ className: cn(
109
+ "tw:h-full tw:w-full tw:rounded-[inherit] tw:focus-visible:outline-hidden",
110
+ viewPortClassName
111
+ ),
112
+ children
113
+ }
114
+ ),
115
+ orientation ? /* @__PURE__ */ jsx(ScrollBar, { className: scrollBarClassName, orientation }) : /* @__PURE__ */ jsxs(Fragment, { children: [
116
+ /* @__PURE__ */ jsx(ScrollBar, { className: scrollBarClassName, orientation: "vertical" }),
117
+ /* @__PURE__ */ jsx(ScrollBar, { className: scrollBarClassName, orientation: "horizontal" })
118
+ ] }),
119
+ /* @__PURE__ */ jsx(ScrollAreaPrimitive2.Corner, {})
120
+ ]
121
+ }
122
+ );
123
+ var Optional = ({ className, ...props }) => /* @__PURE__ */ jsx("span", { ...props, "aria-hidden": true, className: cn("tw:ml-0.5", "tw:text-muted-foreground", className), children: "(optional)" });
124
+ var Required = ({ className, ...props }) => /* @__PURE__ */ jsx("span", { ...props, "aria-hidden": true, className: cn("tw:ml-0.5", "tw:text-primary", className), children: "*" });
125
+ var Label = ({ className, children, id, htmlFor, ...rest }) => /* @__PURE__ */ jsx(
126
+ RLabel.Root,
127
+ {
128
+ ...rest,
129
+ id: id?.toString(),
130
+ htmlFor: htmlFor?.toString(),
131
+ className: cn(
132
+ "tw:m-0 tw:text-foreground tw:font-normal tw:peer-disabled:opacity-50",
133
+ className
134
+ ),
135
+ children
136
+ }
137
+ );
138
+ Label.Optional = Optional;
139
+ Label.Required = Required;
140
+ var addonVariants = cva(
141
+ [
142
+ "tw:flex",
143
+ "tw:items-center",
144
+ "tw:gap-1",
145
+ // Default size for nested Lucide icons in prefix/suffix slots; callers can override on the icon.
146
+ "tw:[&_svg.lucide:not([class*='tw:size-'])]:size-4",
147
+ "tw:[&_svg]:shrink-0"
148
+ ],
149
+ {
150
+ defaultVariants: {
151
+ align: "inline-start"
152
+ },
153
+ variants: {
154
+ align: {
155
+ "inline-start": ["tw:order-first", "tw:[&:not(:empty)]:pl-4"],
156
+ "inline-end": ["tw:order-last", "tw:[&:not(:empty)]:pr-4"],
157
+ "block-start": [
158
+ "tw:order-first",
159
+ // `tw:w-full` needs to be empty-conditional too — when the addon
160
+ // has no content the root stays in flex-row, and a 100%-wide
161
+ // empty addon would claim half of the input row beside the input.
162
+ "tw:[&:not(:empty)]:w-full",
163
+ "tw:[&:not(:empty)]:px-4",
164
+ "tw:[&:not(:empty)]:py-1.5"
165
+ ],
166
+ "block-end": [
167
+ "tw:order-last",
168
+ "tw:[&:not(:empty)]:w-full",
169
+ "tw:[&:not(:empty)]:px-4",
170
+ "tw:[&:not(:empty)]:py-1.5"
171
+ ]
172
+ }
173
+ }
174
+ }
175
+ );
176
+ var InputGroupAddon = ({
177
+ children,
178
+ align = "inline-start",
179
+ className,
180
+ ...props
181
+ }) => /* @__PURE__ */ jsx("div", { ...props, "data-align": align, className: cn(addonVariants({ align, className })), children });
182
+ var InputGroupButton = ({ ref, className, tabIndex = -1, ...props }) => /* @__PURE__ */ jsx(
183
+ Button,
184
+ {
185
+ ...props,
186
+ tabIndex,
187
+ ref,
188
+ variant: "invisible",
189
+ size: "icon-sm",
190
+ className: cn("tw:size-5", "tw:[&_svg]:text-muted-foreground", className)
191
+ }
192
+ );
193
+ var InputGroupInput = ({ ref, className, ...inputProps }) => /* @__PURE__ */ jsx(
194
+ "input",
195
+ {
196
+ ...inputProps,
197
+ ref,
198
+ className: cn(
199
+ "tw:w-full",
200
+ "tw:bg-transparent",
201
+ "tw:outline-hidden",
202
+ // font
203
+ "tw:font-sans",
204
+ "tw:text-sm",
205
+ // placeholder
206
+ "tw:placeholder:text-neutral-400",
207
+ "tw:placeholder:font-normal",
208
+ // disabled
209
+ "tw:disabled:cursor-not-allowed",
210
+ className
211
+ )
212
+ }
213
+ );
214
+ var InputGroupText = ({ className, ...props }) => /* @__PURE__ */ jsx(
215
+ "span",
216
+ {
217
+ className: cn(
218
+ "tw:flex",
219
+ "tw:items-center",
220
+ "tw:gap-2",
221
+ "tw:text-sm",
222
+ "tw:text-muted-foreground",
223
+ "tw:[&_svg]:pointer-events-none",
224
+ 'tw:[&_svg:not([class*="tw:size-"])]:size-4',
225
+ className
226
+ ),
227
+ ...props
228
+ }
229
+ );
230
+ var InputGroupTextArea = ({
231
+ ref,
232
+ className,
233
+ onChange,
234
+ onValueChange,
235
+ value,
236
+ defaultValue,
237
+ onBlur,
238
+ onValueBlur,
239
+ disableResize = false,
240
+ minRows = 1,
241
+ maxRows = 4,
242
+ ...props
243
+ }) => {
244
+ const handleChange = (event) => {
245
+ onValueChange?.(event.target.value);
246
+ onChange?.(event);
247
+ };
248
+ const handleBlur = (event) => {
249
+ onValueBlur?.(event.target.value);
250
+ onBlur?.(event);
251
+ };
252
+ return /* @__PURE__ */ jsx(
253
+ TextareaAutosize,
254
+ {
255
+ ...props,
256
+ ref,
257
+ value: value ?? void 0,
258
+ defaultValue: defaultValue ?? void 0,
259
+ onChange: handleChange,
260
+ onBlur: handleBlur,
261
+ minRows,
262
+ maxRows: maxRows === "unlimited" ? void 0 : maxRows,
263
+ className: cn(
264
+ "tw:w-full",
265
+ "tw:bg-transparent",
266
+ "tw:outline-hidden",
267
+ "tw:px-4",
268
+ // font
269
+ "tw:font-sans",
270
+ "tw:text-sm",
271
+ // placeholder
272
+ "tw:placeholder:text-neutral-400",
273
+ "tw:placeholder:font-normal",
274
+ // disabled
275
+ "tw:disabled:cursor-not-allowed",
276
+ {
277
+ "tw:resize-none": disableResize
278
+ },
279
+ className
280
+ )
281
+ }
282
+ );
283
+ };
284
+ var inputGroupVariants = cva(
285
+ [
286
+ "tailwindcss-preflight",
287
+ "tw:group",
288
+ "tw:overflow-hidden",
289
+ "tw:box-border",
290
+ // positioning
291
+ "tw:flex",
292
+ "tw:items-center",
293
+ // base — legacy (non-argo) chrome uses a fixed radius; argo overrides it with
294
+ // the brand radius token in the `argo` variant below.
295
+ "tw:rounded",
296
+ "tw:border",
297
+ "tw:border-solid",
298
+ // `border-input` rather than the fixed `neutral-200` — same light-scheme
299
+ // grey, but it follows the dark scheme too. The base text stays pinned:
300
+ // `secondary` and the readonly state below both fill with a fixed light
301
+ // grey, so a scheme-following text colour would go light-on-light there.
302
+ // `primary` opts into the token itself (and re-pins its readonly fill).
303
+ "tw:border-input",
304
+ "tw:text-neutral-800",
305
+ "tw:transition",
306
+ // focus
307
+ "tw:has-[:is(input,textarea):focus]:ring-4",
308
+ // readonly
309
+ "tw:has-[:is(input,textarea)[readonly]]:bg-neutral-150",
310
+ "tw:has-[:is(input,textarea)[readonly]]:focus-within:ring-0",
311
+ "tw:has-[:is(input,textarea)[readonly]]:border-neutral-150",
312
+ // disabled cursor (opacity owned by variant)
313
+ "tw:has-[:is(input,textarea):disabled]:cursor-not-allowed",
314
+ // textarea: top-align addons, allow vertical expansion, own its y-padding
315
+ "tw:has-[textarea]:items-start",
316
+ "tw:has-[[data-align=block-start]:not(:empty)]:flex-wrap",
317
+ "tw:has-[[data-align=block-end]:not(:empty)]:flex-wrap",
318
+ "tw:[&>input]:has-[[data-align=block-start]:not(:empty)]:w-auto",
319
+ "tw:[&>input]:has-[[data-align=block-start]:not(:empty)]:flex-1",
320
+ "tw:[&>input]:has-[[data-align=block-end]:not(:empty)]:w-auto",
321
+ "tw:[&>input]:has-[[data-align=block-end]:not(:empty)]:flex-1",
322
+ "tw:[&>input]:px-4",
323
+ "tw:[&>input]:has-[[data-align=inline-start]:not(:empty)]:pl-2",
324
+ "tw:[&>input]:has-[[data-align=inline-end]:not(:empty)]:pr-2"
325
+ ],
326
+ {
327
+ defaultVariants: {
328
+ variant: "primary",
329
+ state: "default",
330
+ sizing: "medium",
331
+ focusVariant: "default"
332
+ },
333
+ compoundVariants: [
334
+ {
335
+ variant: "secondary",
336
+ state: "error",
337
+ className: ["tw:bg-error-100"]
338
+ },
339
+ {
340
+ variant: "secondary",
341
+ state: "warning",
342
+ className: ["tw:bg-warning-100"]
343
+ },
344
+ {
345
+ variant: "primary",
346
+ state: "default",
347
+ focusVariant: "off",
348
+ className: ["tw:has-[:is(input,textarea):focus]:border-neutral-200"]
349
+ },
350
+ {
351
+ variant: "secondary",
352
+ state: "default",
353
+ focusVariant: "off",
354
+ className: ["tw:has-[:is(input,textarea):focus]:border-neutral-100"]
355
+ },
356
+ {
357
+ variant: ["primary", "secondary"],
358
+ state: "error",
359
+ focusVariant: "on",
360
+ className: ["tw:!border-error-500", "tw:!ring-error-200"]
361
+ },
362
+ {
363
+ variant: ["primary", "secondary"],
364
+ state: "warning",
365
+ focusVariant: "on",
366
+ className: ["tw:!border-warning-500", "tw:!ring-warning-200"]
367
+ },
368
+ // --- argo ---
369
+ {
370
+ variant: "argo",
371
+ state: "default",
372
+ className: [
373
+ "tw:has-[:is(input,textarea):focus]:border-primary",
374
+ "tw:has-[:is(input,textarea):focus]:ring-ring/50"
375
+ ]
376
+ },
377
+ {
378
+ variant: "argo",
379
+ state: "error",
380
+ className: [
381
+ "tw:border-destructive",
382
+ "tw:has-[:is(input,textarea):focus]:border-destructive",
383
+ "tw:has-[:is(input,textarea):focus]:ring-destructive/20"
384
+ ]
385
+ },
386
+ {
387
+ variant: "argo",
388
+ focusVariant: "on",
389
+ className: ["tw:!border-primary", "tw:!ring-ring/50"]
390
+ },
391
+ {
392
+ variant: "argo",
393
+ state: "error",
394
+ focusVariant: "on",
395
+ className: ["tw:!border-destructive", "tw:!ring-destructive/20"]
396
+ },
397
+ {
398
+ variant: "argo",
399
+ state: "default",
400
+ focusVariant: "off",
401
+ className: ["tw:has-[:is(input,textarea):focus]:border-input"]
402
+ }
403
+ ],
404
+ variants: {
405
+ focusVariant: {
406
+ default: [],
407
+ on: ["tw:!border-ring", "tw:!ring-ring/30", "tw:!ring-4"],
408
+ off: ["tw:has-[:is(input,textarea):focus]:!ring-0"]
409
+ },
410
+ variant: {
411
+ primary: [
412
+ // The field-surface token — white in the light scheme, so this is a
413
+ // no-op there; the dark scheme gets a field fill, not a white slab.
414
+ "tw:bg-input-background",
415
+ "tw:text-foreground",
416
+ // The base readonly fill is a fixed light grey, which the scheme-following
417
+ // text above would sit on invisibly in dark. Re-pin to the same
418
+ // `muted`/`input` pair argo uses for exactly this reason.
419
+ "tw:has-[:is(input,textarea)[readonly]]:bg-muted",
420
+ "tw:has-[:is(input,textarea)[readonly]]:border-input",
421
+ "tw:has-[:is(input,textarea):disabled]:opacity-40",
422
+ // aria-invalid on the control surfaces the error chrome without a `state` prop — the
423
+ // accessible path (mirrors the `state="error"` legacy tokens). Higher specificity than
424
+ // the default focus selector, so it wins without `!important`.
425
+ "tw:has-[:is(input,textarea)[aria-invalid=true]]:border-error-500",
426
+ "tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:border-error-500",
427
+ "tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:ring-error-200"
428
+ ],
429
+ secondary: [
430
+ "tw:bg-neutral-100",
431
+ "tw:border-neutral-100",
432
+ "tw:has-[:is(input,textarea):disabled]:opacity-40",
433
+ "tw:has-[:is(input,textarea)[aria-invalid=true]]:border-error-500",
434
+ "tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:border-error-500",
435
+ "tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:ring-error-200"
436
+ ],
437
+ argo: [
438
+ // argo follows the brand radius token (overrides the static base)
439
+ "tw:rounded-[var(--radius-lg,0.25rem)]",
440
+ // muted filled input surface — gray, distinct from white containers; not the app-background token.
441
+ // Deliberately `muted`, not the `input-background` field token legacy uses: argo's field is a
442
+ // grey inset by design. Converging the two is a brand-value decision, not a component one.
443
+ "tw:bg-muted",
444
+ "tw:border-input",
445
+ "tw:text-foreground",
446
+ "tw:has-[:is(input,textarea):disabled]:opacity-50",
447
+ // readonly: keep the themed input surface/border. The base layer's fixed
448
+ // `neutral-150` (a light grey) is correct for the legacy light chrome but
449
+ // collides with argo's themed `foreground` text — light-on-light, invisible
450
+ // in dark mode. Re-pin to the same `muted`/`input` tokens the editable argo
451
+ // input uses (validated AA), so readonly stays legible in every scheme.
452
+ "tw:has-[:is(input,textarea)[readonly]]:bg-muted",
453
+ "tw:has-[:is(input,textarea)[readonly]]:border-input",
454
+ // higher specificity than has-[:is(input,textarea):focus] — prevents focus border on readonly
455
+ "tw:has-[:is(input,textarea)[readonly]:focus]:border-input",
456
+ // aria-invalid on the control surfaces the error chrome without a `state` prop — the
457
+ // accessible path (uses the themeable `destructive` status token).
458
+ "tw:has-[:is(input,textarea)[aria-invalid=true]]:border-destructive",
459
+ "tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:border-destructive",
460
+ "tw:has-[:is(input,textarea)[aria-invalid=true]:focus]:ring-destructive/20"
461
+ ]
462
+ },
463
+ sizing: {
464
+ default: [
465
+ "tw:[&>:is(input,textarea)]:py-2.5",
466
+ "tw:[&>:is(input,textarea)]:leading-[18px]",
467
+ "tw:[&>textarea]:!min-h-[calc(2.5rem-2px)]"
468
+ ],
469
+ small: [
470
+ "tw:[&>:is(input,textarea)]:py-2",
471
+ "tw:[&>:is(input,textarea)]:leading-[16px]",
472
+ "tw:[&>textarea]:!min-h-[calc(2rem-2px)]"
473
+ ],
474
+ medium: [
475
+ "tw:[&>:is(input,textarea)]:py-2",
476
+ "tw:[&>:is(input,textarea)]:leading-[18px]",
477
+ "tw:[&>textarea]:!min-h-[calc(2.25rem-2px)]"
478
+ ]
479
+ },
480
+ state: {
481
+ default: [
482
+ "tw:has-[:is(input,textarea):focus]:border-ring",
483
+ "tw:has-[:is(input,textarea):focus]:ring-ring/30"
484
+ ],
485
+ error: [
486
+ "tw:border-error-500",
487
+ "tw:has-[:is(input,textarea):focus]:border-error-500",
488
+ "tw:has-[:is(input,textarea):focus]:ring-error-200"
489
+ ],
490
+ warning: [
491
+ "tw:border-warning-500",
492
+ "tw:has-[:is(input,textarea):focus]:border-warning-500",
493
+ "tw:has-[:is(input,textarea):focus]:ring-warning-200"
494
+ ]
495
+ }
496
+ }
497
+ }
498
+ );
499
+ var InputGroupRoot = ({
500
+ ref,
501
+ children,
502
+ state,
503
+ variant,
504
+ sizing,
505
+ focusVariant,
506
+ className,
507
+ ...props
508
+ }) => {
509
+ const isArgo = useArgoDesign();
510
+ const effectiveVariant = isArgo ? "argo" : variant;
511
+ const effectiveSizing = effectiveVariant === "argo" ? "medium" : sizing;
512
+ return /* @__PURE__ */ jsx(
513
+ "div",
514
+ {
515
+ ...props,
516
+ ref,
517
+ className: cn(
518
+ inputGroupVariants({
519
+ state,
520
+ variant: effectiveVariant,
521
+ sizing: effectiveSizing,
522
+ focusVariant,
523
+ className
524
+ })
525
+ ),
526
+ children
527
+ }
528
+ );
529
+ };
530
+ var InputGroup = InputGroupRoot;
531
+ InputGroup.Input = InputGroupInput;
532
+ InputGroup.Addon = InputGroupAddon;
533
+ InputGroup.Button = InputGroupButton;
534
+ InputGroup.TextArea = InputGroupTextArea;
535
+ InputGroup.Text = InputGroupText;
536
+ var useControllableState = ({
537
+ prop,
538
+ defaultProp,
539
+ onChange
540
+ }) => {
541
+ const [uncontrolled, setUncontrolled] = useState(defaultProp);
542
+ const isControlled = prop !== void 0;
543
+ const value = prop !== void 0 ? prop : uncontrolled;
544
+ const valueRef = useRef(value);
545
+ valueRef.current = value;
546
+ const onChangeRef = useRef(onChange);
547
+ onChangeRef.current = onChange;
548
+ const setValue = useCallback(
549
+ (next) => {
550
+ const nextValue = typeof next === "function" ? next(valueRef.current) : next;
551
+ valueRef.current = nextValue;
552
+ if (!isControlled) setUncontrolled(nextValue);
553
+ onChangeRef.current?.(nextValue);
554
+ },
555
+ [isControlled]
556
+ );
557
+ return [value, setValue];
558
+ };
559
+
560
+ // src/blocks/TextInput/utils.ts
561
+ var genInputTestId = (prefix = "") => {
562
+ const ps = createPrefixedString(prefix);
563
+ return {
564
+ toString: () => prefix,
565
+ inputWrapper: ps`input-wrapper`,
566
+ input: ps`input`,
567
+ clearButton: ps`clear-button`
568
+ };
569
+ };
570
+ var sanitizeTextInputValue = (value) => {
571
+ if (typeof value === "string" && value.trim() === "") return "";
572
+ return value;
573
+ };
574
+ var TextInput = ({
575
+ ref: forwardedRef,
576
+ state = "default",
577
+ sizing = "default",
578
+ className,
579
+ prefix = null,
580
+ rightSuffix = null,
581
+ rightSuffixVariant = "default",
582
+ leftSuffix = null,
583
+ allowClear = false,
584
+ onClear,
585
+ disabled = false,
586
+ testId: prefixTestId = "",
587
+ autoFocus = false,
588
+ id,
589
+ name,
590
+ variant,
591
+ readOnly,
592
+ type = "text",
593
+ focusVariant = "default",
594
+ onChange,
595
+ onBlur,
596
+ onValueChange,
597
+ onValueBlur,
598
+ value: valueProp,
599
+ defaultValue,
600
+ ...inputProps
601
+ }) => {
602
+ const inputRef = useRef(null);
603
+ const [value, setValue] = useControllableState({
604
+ // `undefined` stays uncontrolled; any provided value (incl. `null`) is controlled and coerced
605
+ // to a string. Whitespace-only input collapses to '' via `sanitizeTextInputValue`.
606
+ prop: valueProp === void 0 ? void 0 : sanitizeTextInputValue(valueProp) ?? "",
607
+ defaultProp: sanitizeTextInputValue(defaultValue) ?? "",
608
+ onChange: onValueChange
609
+ });
610
+ const testId = genInputTestId(prefixTestId);
611
+ const isClearButtonVisible = !!value && !disabled && !readOnly || !!onClear;
612
+ const handleChange = (event) => {
613
+ setValue(event.target.value);
614
+ onChange?.(event);
615
+ };
616
+ const handleBlur = (event) => {
617
+ onValueBlur?.(event.target.value);
618
+ onBlur?.(event);
619
+ };
620
+ const handleClear = () => {
621
+ if (inputRef.current === null) return;
622
+ inputRef.current.value = "";
623
+ inputRef.current.focus();
624
+ onClear?.();
625
+ handleChange(createChangeInputEvent(inputRef.current));
626
+ };
627
+ return /* @__PURE__ */ jsxs(
628
+ InputGroup,
629
+ {
630
+ state,
631
+ variant,
632
+ sizing,
633
+ focusVariant,
634
+ className,
635
+ "data-testid": testId.inputWrapper,
636
+ children: [
637
+ prefix && /* @__PURE__ */ jsx(InputGroup.Addon, { align: "inline-start", children: prefix }),
638
+ /* @__PURE__ */ jsx(
639
+ InputGroup.Input,
640
+ {
641
+ ...inputProps,
642
+ value,
643
+ autoFocus,
644
+ type,
645
+ onChange: handleChange,
646
+ onBlur: handleBlur,
647
+ ref: mergeRefs(forwardedRef ?? null, inputRef),
648
+ disabled,
649
+ id,
650
+ name,
651
+ readOnly,
652
+ "data-testid": testId.input
653
+ }
654
+ ),
655
+ (leftSuffix || allowClear || rightSuffix) && /* @__PURE__ */ jsxs(InputGroup.Addon, { align: "inline-end", children: [
656
+ leftSuffix,
657
+ allowClear && isClearButtonVisible && /* @__PURE__ */ jsx(
658
+ InputGroup.Button,
659
+ {
660
+ "aria-label": "Clear",
661
+ onMouseDown: (e) => e.preventDefault(),
662
+ onClick: handleClear,
663
+ "data-testid": testId.clearButton,
664
+ children: /* @__PURE__ */ jsx(X, { className: "tw:size-4" })
665
+ }
666
+ ),
667
+ rightSuffix && /* @__PURE__ */ jsx(
668
+ "div",
669
+ {
670
+ className: cn({
671
+ "tw:whitespace-nowrap tw:bg-muted tw:px-4 tw:-mr-4 tw:py-2.5": rightSuffixVariant === "addon"
672
+ }),
673
+ children: rightSuffix
674
+ }
675
+ )
676
+ ] })
677
+ ]
678
+ }
679
+ );
680
+ };
681
+ var Textarea = ({
682
+ ref,
683
+ containerClassName,
684
+ // group props
685
+ state = "default",
686
+ variant,
687
+ sizing,
688
+ focusVariant,
689
+ // value handling
690
+ value: valueProp,
691
+ defaultValue,
692
+ onValueChange,
693
+ ...rest
694
+ }) => {
695
+ const [value, setValue] = useControllableState({
696
+ // `undefined` stays uncontrolled; any provided value (incl. `null`) is controlled, coerced to ''.
697
+ prop: valueProp === void 0 ? void 0 : valueProp ?? "",
698
+ defaultProp: defaultValue ?? "",
699
+ onChange: onValueChange
700
+ });
701
+ return /* @__PURE__ */ jsx(
702
+ InputGroup,
703
+ {
704
+ state,
705
+ sizing,
706
+ focusVariant,
707
+ variant,
708
+ className: containerClassName,
709
+ children: /* @__PURE__ */ jsx(InputGroup.TextArea, { ...rest, ref, value, onValueChange: setValue })
710
+ }
711
+ );
712
+ };
713
+
714
+ // src/blocks/ColorInput/utils.ts
715
+ var HEX_CHARSET = /^[0-9a-fA-F]+$/;
716
+ var COMPLETE_HEX_PATTERN = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
717
+ var MAX_HEX_BODY_LENGTH = 8;
718
+ var PICKER_FALLBACK = "#000000";
719
+ var extractHexBody = (value) => {
720
+ if (typeof value !== "string") return null;
721
+ const trimmed = value.trim();
722
+ if (trimmed === "") return null;
723
+ return trimmed.startsWith("#") ? trimmed.slice(1) : trimmed;
724
+ };
725
+ var isCompleteHexColor = (value) => COMPLETE_HEX_PATTERN.test(value);
726
+ var showPicker = (input) => {
727
+ const isShowPickerSupported = "showPicker" in HTMLInputElement.prototype;
728
+ isShowPickerSupported ? input.showPicker() : input.click();
729
+ };
730
+ var coerceHexInputValue = (value) => {
731
+ const body = extractHexBody(value);
732
+ if (body === null) return "";
733
+ const [validBody] = body.match(/^[0-9a-fA-F]+/) ?? [];
734
+ if (!validBody) return "";
735
+ return `#${validBody.slice(0, MAX_HEX_BODY_LENGTH)}`;
736
+ };
737
+ var coerceColorPickerValue = (value) => {
738
+ const body = extractHexBody(value);
739
+ if (body === null || !HEX_CHARSET.test(body)) return PICKER_FALLBACK;
740
+ if (body.length === 3 || body.length === 4) {
741
+ const [r, g, b] = body;
742
+ return `#${r}${r}${g}${g}${b}${b}`.toLowerCase();
743
+ }
744
+ if (body.length === 6 || body.length === 8) {
745
+ return `#${body.slice(0, 6).toLowerCase()}`;
746
+ }
747
+ return PICKER_FALLBACK;
748
+ };
749
+ var ColorPicker = ({ value, disabled, readOnly, ...props }) => {
750
+ const pickerRef = useRef(null);
751
+ const handleOpenPicker = () => {
752
+ if (!pickerRef.current) return;
753
+ showPicker(pickerRef.current);
754
+ };
755
+ return /* @__PURE__ */ jsxs("div", { className: "tw:relative", children: [
756
+ /* @__PURE__ */ jsx(
757
+ "input",
758
+ {
759
+ ...props,
760
+ ref: pickerRef,
761
+ type: "color",
762
+ value: coerceColorPickerValue(value),
763
+ tabIndex: -1,
764
+ "aria-hidden": true,
765
+ className: "tw:pointer-events-none tw:absolute tw:left-0 tw:top-full tw:size-0 tw:opacity-0",
766
+ disabled,
767
+ readOnly
768
+ }
769
+ ),
770
+ /* @__PURE__ */ jsx(
771
+ InputGroup.Button,
772
+ {
773
+ onMouseDown: (event) => event.preventDefault(),
774
+ disabled: disabled || readOnly,
775
+ onClick: handleOpenPicker,
776
+ "aria-label": "Pick color",
777
+ children: /* @__PURE__ */ jsx(Pipette, { className: "tw:size-4" })
778
+ }
779
+ )
780
+ ] });
781
+ };
782
+ var ColorInput = ({
783
+ ref,
784
+ // group props
785
+ state,
786
+ variant,
787
+ focusVariant,
788
+ sizing,
789
+ className,
790
+ // own props
791
+ value: valueProp,
792
+ onValueChange,
793
+ onValueBlur,
794
+ onChange,
795
+ onBlur,
796
+ defaultValue,
797
+ allowClear = false,
798
+ // input props
799
+ disabled,
800
+ readOnly,
801
+ ...restInputProps
802
+ }) => {
803
+ const inputRef = useRef(null);
804
+ const [value, setValue] = useControllableState({
805
+ // A `null` controlled value stays controlled (coerced to ''); `undefined` is uncontrolled.
806
+ prop: valueProp === null ? "" : valueProp,
807
+ defaultProp: defaultValue ?? "",
808
+ onChange: onValueChange
809
+ });
810
+ const isControlled = valueProp !== void 0;
811
+ const canClear = allowClear && !!value && !disabled && !readOnly;
812
+ const swatchColor = coerceHexInputValue(value);
813
+ const isValidSwatch = isCompleteHexColor(swatchColor);
814
+ const handleChange = (event) => {
815
+ setValue(event.target.value);
816
+ onChange?.(event);
817
+ };
818
+ const handleBlur = (event) => {
819
+ const newValue = event.target.value;
820
+ const sanitizedNewValue = coerceHexInputValue(newValue);
821
+ if (sanitizedNewValue !== newValue) {
822
+ if (!isControlled) event.target.value = sanitizedNewValue;
823
+ setValue(sanitizedNewValue);
824
+ }
825
+ onValueBlur?.(sanitizedNewValue);
826
+ onBlur?.(event);
827
+ };
828
+ const handlePickerChange = (event) => {
829
+ setValue(coerceHexInputValue(event.target.value));
830
+ onChange?.(event);
831
+ };
832
+ const handleClear = () => {
833
+ if (!inputRef.current) return;
834
+ inputRef.current.value = "";
835
+ setValue("");
836
+ onChange?.(createChangeInputEvent(inputRef.current));
837
+ };
838
+ return /* @__PURE__ */ jsxs(
839
+ InputGroup,
840
+ {
841
+ state,
842
+ variant,
843
+ sizing,
844
+ focusVariant,
845
+ className,
846
+ children: [
847
+ /* @__PURE__ */ jsx(
848
+ InputGroup.Addon,
849
+ {
850
+ align: "inline-start",
851
+ className: cn(
852
+ { "tw:-ml-7 tw:opacity-0": !value },
853
+ "tw:transition-[opacity,margin]",
854
+ "tw:ease-linear",
855
+ "tw:duration-200"
856
+ ),
857
+ children: /* @__PURE__ */ jsx(
858
+ "div",
859
+ {
860
+ style: isValidSwatch ? { background: swatchColor } : void 0,
861
+ className: cn(
862
+ "tw:size-5",
863
+ "tw:shrink-0",
864
+ "tw:rounded-sm",
865
+ "tw:border",
866
+ "tw:border-solid",
867
+ "tw:border-neutral-300",
868
+ {
869
+ "tw:bg-[linear-gradient(to_top_right,transparent_calc(50%_-_1px),theme(colors.red.300)_calc(50%_-_1px),theme(colors.red.300)_calc(50%_+_1px),transparent_calc(50%_+_1px))]": !isValidSwatch
870
+ }
871
+ )
872
+ }
873
+ )
874
+ }
875
+ ),
876
+ /* @__PURE__ */ jsx(
877
+ InputGroup.Input,
878
+ {
879
+ ...restInputProps,
880
+ type: "text",
881
+ ref: mergeRefs(ref ?? null, inputRef),
882
+ value,
883
+ onChange: handleChange,
884
+ onBlur: handleBlur,
885
+ disabled,
886
+ readOnly
887
+ }
888
+ ),
889
+ /* @__PURE__ */ jsxs(InputGroup.Addon, { align: "inline-end", children: [
890
+ canClear && /* @__PURE__ */ jsx(
891
+ InputGroup.Button,
892
+ {
893
+ onMouseDown: (event) => event.preventDefault(),
894
+ onClick: handleClear,
895
+ "aria-label": "Clear color",
896
+ children: /* @__PURE__ */ jsx(X, { className: "tw:size-4" })
897
+ }
898
+ ),
899
+ /* @__PURE__ */ jsx(
900
+ ColorPicker,
901
+ {
902
+ disabled,
903
+ readOnly,
904
+ value,
905
+ onChange: handlePickerChange
906
+ }
907
+ )
908
+ ] })
909
+ ]
910
+ }
911
+ );
912
+ };
913
+ var toNumberOrNull = (event) => Number.isNaN(event.target.valueAsNumber) ? null : event.target.valueAsNumber;
914
+ var NumberInput = ({
915
+ ref,
916
+ state,
917
+ variant,
918
+ focusVariant,
919
+ sizing,
920
+ className,
921
+ value,
922
+ defaultValue,
923
+ onValueChange,
924
+ onValueBlur,
925
+ onChange,
926
+ onBlur,
927
+ prefix,
928
+ suffix,
929
+ ...inputProps
930
+ }) => {
931
+ const handleChange = (event) => {
932
+ onValueChange?.(toNumberOrNull(event));
933
+ onChange?.(event);
934
+ };
935
+ const handleBlur = (event) => {
936
+ onValueBlur?.(toNumberOrNull(event));
937
+ onBlur?.(event);
938
+ };
939
+ const isControlled = value !== void 0;
940
+ const valueProp = isControlled ? { value: value ?? "" } : { defaultValue: defaultValue ?? "" };
941
+ return /* @__PURE__ */ jsxs(
942
+ InputGroup,
943
+ {
944
+ state,
945
+ variant,
946
+ sizing,
947
+ focusVariant,
948
+ className,
949
+ children: [
950
+ prefix && /* @__PURE__ */ jsx(InputGroup.Addon, { align: "inline-start", children: prefix }),
951
+ /* @__PURE__ */ jsx(
952
+ InputGroup.Input,
953
+ {
954
+ ...inputProps,
955
+ ...valueProp,
956
+ ref,
957
+ type: "number",
958
+ onChange: handleChange,
959
+ onBlur: handleBlur
960
+ }
961
+ ),
962
+ suffix && /* @__PURE__ */ jsx(InputGroup.Addon, { align: "inline-end", children: suffix })
963
+ ]
964
+ }
965
+ );
966
+ };
967
+ var FormGroupContext = createContext({
968
+ state: "default"
969
+ });
970
+ var FormGroupProvider = FormGroupContext;
971
+ var useFormGroupContext = () => use(FormGroupContext);
972
+ var FormGroupColorInput = ({ ref, ...props }) => {
973
+ const { state } = useFormGroupContext();
974
+ return /* @__PURE__ */ jsx(ColorInput, { state, ...props, ref });
975
+ };
976
+ var toMessage = (entry) => typeof entry === "string" ? entry : entry?.message;
977
+ var FormGroupError = ({ children, className, errors, ...rest }) => {
978
+ const content = useMemo(() => {
979
+ if (children) return children;
980
+ const messages = (errors ?? []).map(toMessage).filter((message) => !!message);
981
+ if (messages.length === 0) return null;
982
+ if (messages.length === 1) return messages[0];
983
+ return /* @__PURE__ */ jsx("ul", { className: "tw:m-0 tw:flex tw:list-disc tw:flex-col tw:gap-0 tw:pl-4", children: messages.map((message, index) => /* @__PURE__ */ jsx("li", { children: message }, index)) });
984
+ }, [children, errors]);
985
+ if (!content) return null;
986
+ return /* @__PURE__ */ jsx("div", { ...rest, role: "alert", className: cn("tw:m-0 tw:text-xs tw:text-destructive", className), children: content });
987
+ };
988
+ var FormGroupHelp = ({ children, ...rest }) => {
989
+ const formGroupContext = useFormGroupContext();
990
+ return /* @__PURE__ */ jsx(HelpBlock, { state: formGroupContext.state === "warning" ? "warning" : "default", ...rest, children });
991
+ };
992
+ var FormGroupNumberInput = ({ ref, ...props }) => {
993
+ const { state } = useFormGroupContext();
994
+ return /* @__PURE__ */ jsx(NumberInput, { ...props, ref, state });
995
+ };
996
+ var FormGroupTextarea = (props) => {
997
+ const { state } = useFormGroupContext();
998
+ return /* @__PURE__ */ jsx(Textarea, { state, ...props });
999
+ };
1000
+ var FormGroupTextInput = ({ ref, ...props }) => {
1001
+ const { state } = useFormGroupContext();
1002
+ return /* @__PURE__ */ jsx(TextInput, { state, ...props, ref });
1003
+ };
1004
+ var FormGroup = ({ className, children, state, ...rest }) => {
1005
+ return /* @__PURE__ */ jsx(FormGroupProvider, { value: { state }, children: /* @__PURE__ */ jsx("div", { ...rest, className: cn("tw:flex tw:flex-col tw:gap-1", className), children }) });
1006
+ };
1007
+ FormGroup.Help = FormGroupHelp;
1008
+ FormGroup.Error = FormGroupError;
1009
+ FormGroup.TextInput = FormGroupTextInput;
1010
+ FormGroup.NumberInput = FormGroupNumberInput;
1011
+ FormGroup.ColorInput = FormGroupColorInput;
1012
+ FormGroup.Textarea = FormGroupTextarea;
1013
+
1014
+ export { ColorInput, FormGroup, InputGroup, Label, NumberInput, ScrollArea, ScrollBar, TextInput, Textarea, createChangeInputEvent, createPrefixedString, mergeRefs, useControllableState };
1015
+ //# sourceMappingURL=chunk-SYIEF644.js.map
1016
+ //# sourceMappingURL=chunk-SYIEF644.js.map