@geomak/ui 5.5.2 → 5.6.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/dist/index.js CHANGED
@@ -2144,6 +2144,51 @@ function fieldShell({
2144
2144
  "placeholder:text-foreground-muted"
2145
2145
  ].filter(Boolean).join(" ");
2146
2146
  }
2147
+ function FieldHelpIcon({ text }) {
2148
+ return /* @__PURE__ */ jsx(Tooltip, { title: text, placement: "top", children: /* @__PURE__ */ jsx(
2149
+ "button",
2150
+ {
2151
+ type: "button",
2152
+ "aria-label": "More information",
2153
+ className: "inline-flex items-center justify-center rounded-full text-foreground-muted transition-colors hover:text-foreground focus:outline-none focus-visible:text-accent",
2154
+ children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 16 16", className: "h-3.5 w-3.5", fill: "none", stroke: "currentColor", strokeWidth: 1.5, "aria-hidden": "true", children: [
2155
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "6.25" }),
2156
+ /* @__PURE__ */ jsx("path", { strokeLinecap: "round", d: "M8 7.4v3.4" }),
2157
+ /* @__PURE__ */ jsx("circle", { cx: "8", cy: "5.1", r: "0.65", fill: "currentColor", stroke: "none" })
2158
+ ] })
2159
+ }
2160
+ ) });
2161
+ }
2162
+ function FieldLabel({
2163
+ label,
2164
+ htmlFor,
2165
+ required,
2166
+ helperText,
2167
+ horizontal = false,
2168
+ style,
2169
+ width,
2170
+ className = ""
2171
+ }) {
2172
+ if (label == null && helperText == null) return null;
2173
+ return /* @__PURE__ */ jsxs(
2174
+ "div",
2175
+ {
2176
+ style: { width: horizontal ? width : void 0, ...style },
2177
+ className: [
2178
+ "flex items-center gap-1",
2179
+ horizontal ? "mt-2 flex-shrink-0 whitespace-nowrap" : "",
2180
+ className
2181
+ ].filter(Boolean).join(" "),
2182
+ children: [
2183
+ label != null && /* @__PURE__ */ jsxs("label", { htmlFor, className: "text-sm font-medium text-foreground select-none", children: [
2184
+ label,
2185
+ required && /* @__PURE__ */ jsx("span", { className: "text-status-error ml-0.5", "aria-hidden": "true", children: "*" })
2186
+ ] }),
2187
+ helperText != null && /* @__PURE__ */ jsx(FieldHelpIcon, { text: helperText })
2188
+ ]
2189
+ }
2190
+ );
2191
+ }
2147
2192
  function Field({
2148
2193
  label,
2149
2194
  htmlFor,
@@ -2151,6 +2196,7 @@ function Field({
2151
2196
  errorMessage,
2152
2197
  layout = "vertical",
2153
2198
  required,
2199
+ helperText,
2154
2200
  labelStyle,
2155
2201
  labelWidth,
2156
2202
  className = "",
@@ -2167,21 +2213,16 @@ function Field({
2167
2213
  className
2168
2214
  ].filter(Boolean).join(" "),
2169
2215
  children: [
2170
- label && /* @__PURE__ */ jsxs(
2171
- "label",
2216
+ /* @__PURE__ */ jsx(
2217
+ FieldLabel,
2172
2218
  {
2219
+ label,
2173
2220
  htmlFor,
2174
- style: { width: horizontal ? labelWidth : void 0, ...labelStyle },
2175
- className: [
2176
- "text-sm font-medium text-foreground select-none",
2177
- // In horizontal layout the label must not wrap onto
2178
- // multiple lines (e.g. "Report date", "Select option").
2179
- horizontal ? "mt-2 flex-shrink-0 whitespace-nowrap" : ""
2180
- ].filter(Boolean).join(" "),
2181
- children: [
2182
- label,
2183
- required && /* @__PURE__ */ jsx("span", { className: "text-status-error ml-0.5", "aria-hidden": "true", children: "*" })
2184
- ]
2221
+ required,
2222
+ helperText,
2223
+ horizontal,
2224
+ style: labelStyle,
2225
+ width: labelWidth
2185
2226
  }
2186
2227
  ),
2187
2228
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
@@ -2193,8 +2234,8 @@ function Field({
2193
2234
  );
2194
2235
  }
2195
2236
  var SearchIcon = /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "currentColor", className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M10.5 3.75a6.75 6.75 0 100 13.5 6.75 6.75 0 000-13.5zM2.25 10.5a8.25 8.25 0 1114.59 5.28l4.69 4.69a.75.75 0 11-1.06 1.06l-4.69-4.69A8.25 8.25 0 012.25 10.5z", clipRule: "evenodd" }) });
2196
- var SearchInput = React8.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon }, ref) {
2197
- return /* @__PURE__ */ jsx(Field, { label, htmlFor, layout, children: /* @__PURE__ */ jsxs(
2237
+ var SearchInput = React8.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText }, ref) {
2238
+ return /* @__PURE__ */ jsx(Field, { label, htmlFor, layout, helperText, children: /* @__PURE__ */ jsxs(
2198
2239
  "div",
2199
2240
  {
2200
2241
  className: `flex items-center ${fieldShell({ size, disabled, focusWithin: true })}`,
@@ -2241,6 +2282,90 @@ function Tag({ children, onRemove, removeLabel, disabled }) {
2241
2282
  )
2242
2283
  ] });
2243
2284
  }
2285
+ function MultiTagRow({
2286
+ values,
2287
+ disabled,
2288
+ labelFor,
2289
+ onRemove
2290
+ }) {
2291
+ const wrapRef = useRef(null);
2292
+ const measureRef = useRef(null);
2293
+ const [visibleCount, setVisibleCount] = useState(values.length);
2294
+ const key = values.map(String).join("|");
2295
+ useLayoutEffect(() => {
2296
+ const wrap = wrapRef.current;
2297
+ const measure = measureRef.current;
2298
+ if (!wrap || !measure) return;
2299
+ const GAP = 6;
2300
+ const recompute = () => {
2301
+ const avail = wrap.clientWidth;
2302
+ const tagEls = Array.from(measure.querySelectorAll("[data-mt]"));
2303
+ const moreEl = measure.querySelector("[data-mm]");
2304
+ const widths = tagEls.map((e) => e.offsetWidth);
2305
+ const moreW = moreEl ? moreEl.offsetWidth : 0;
2306
+ if (widths.length === 0) {
2307
+ setVisibleCount(0);
2308
+ return;
2309
+ }
2310
+ let used = 0;
2311
+ let count = 0;
2312
+ for (let i = 0; i < widths.length; i++) {
2313
+ const w = widths[i] + (i > 0 ? GAP : 0);
2314
+ if (used + w <= avail) {
2315
+ used += w;
2316
+ count++;
2317
+ } else break;
2318
+ }
2319
+ if (count < widths.length) {
2320
+ while (count > 0) {
2321
+ let t = 0;
2322
+ for (let i = 0; i < count; i++) t += widths[i] + (i > 0 ? GAP : 0);
2323
+ t += GAP + moreW;
2324
+ if (t <= avail) break;
2325
+ count--;
2326
+ }
2327
+ }
2328
+ setVisibleCount(count);
2329
+ };
2330
+ recompute();
2331
+ const ro = new ResizeObserver(recompute);
2332
+ ro.observe(wrap);
2333
+ return () => ro.disconnect();
2334
+ }, [key]);
2335
+ const hidden = values.length - visibleCount;
2336
+ const moreChip = (n) => /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center flex-shrink-0 rounded-md border border-border bg-surface-raised text-foreground-secondary text-xs px-2 py-0.5", children: [
2337
+ "+",
2338
+ n,
2339
+ " more"
2340
+ ] });
2341
+ return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "relative flex-1 min-w-0 flex flex-nowrap items-center gap-1.5 overflow-hidden", children: [
2342
+ /* @__PURE__ */ jsxs(
2343
+ "div",
2344
+ {
2345
+ ref: measureRef,
2346
+ "aria-hidden": "true",
2347
+ className: "absolute invisible pointer-events-none flex flex-nowrap items-center gap-1.5",
2348
+ style: { left: -9999, top: -9999 },
2349
+ children: [
2350
+ values.map((val) => /* @__PURE__ */ jsx("span", { "data-mt": true, children: /* @__PURE__ */ jsx(Tag, { removeLabel: "x", onRemove: () => {
2351
+ }, children: labelFor(val) }) }, `m-${val}`)),
2352
+ /* @__PURE__ */ jsx("span", { "data-mm": true, children: moreChip(values.length) })
2353
+ ]
2354
+ }
2355
+ ),
2356
+ values.slice(0, visibleCount).map((val) => /* @__PURE__ */ jsx(
2357
+ Tag,
2358
+ {
2359
+ disabled,
2360
+ removeLabel: `Remove ${labelFor(val)}`,
2361
+ onRemove: () => onRemove(val),
2362
+ children: labelFor(val)
2363
+ },
2364
+ String(val)
2365
+ )),
2366
+ hidden > 0 && moreChip(hidden)
2367
+ ] });
2368
+ }
2244
2369
  function Dropdown({
2245
2370
  isMultiselect = false,
2246
2371
  hasSearch = true,
@@ -2250,6 +2375,8 @@ function Dropdown({
2250
2375
  onChange,
2251
2376
  disabled,
2252
2377
  layout = "horizontal",
2378
+ helperText,
2379
+ required,
2253
2380
  errorMessage,
2254
2381
  style = {},
2255
2382
  htmlFor,
@@ -2310,13 +2437,15 @@ function Dropdown({
2310
2437
  {
2311
2438
  className: `flex ${layout === "vertical" ? "flex-col gap-1.5" : "flex-row items-start gap-3"}`,
2312
2439
  children: [
2313
- label && /* @__PURE__ */ jsx(
2314
- "label",
2440
+ /* @__PURE__ */ jsx(
2441
+ FieldLabel,
2315
2442
  {
2316
- className: `text-sm font-medium select-none text-foreground ${layout === "horizontal" ? "mt-2 flex-shrink-0 whitespace-nowrap" : ""}`,
2443
+ label,
2317
2444
  htmlFor,
2318
- style: labelStyle,
2319
- children: label
2445
+ required,
2446
+ helperText,
2447
+ horizontal: layout === "horizontal",
2448
+ style: labelStyle
2320
2449
  }
2321
2450
  ),
2322
2451
  /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
@@ -2329,8 +2458,8 @@ function Dropdown({
2329
2458
  "aria-haspopup": "listbox",
2330
2459
  "aria-invalid": hasError || void 0,
2331
2460
  "aria-describedby": hasError ? errorId : void 0,
2332
- style,
2333
- className: `flex items-center justify-between gap-1 cursor-pointer select-none min-h-[36px] px-3 py-1.5 ${fieldShell({ size, hasError, disabled, sized: false })}`,
2461
+ style: { width: 240, ...style },
2462
+ className: `flex items-center justify-between gap-2 cursor-pointer select-none min-h-[36px] px-3 py-1.5 ${fieldShell({ size, hasError, disabled, sized: false })}`,
2334
2463
  tabIndex: disabled ? -1 : 0,
2335
2464
  onKeyDown: (e) => {
2336
2465
  if (disabled) return;
@@ -2340,31 +2469,24 @@ function Dropdown({
2340
2469
  }
2341
2470
  },
2342
2471
  children: [
2343
- /* @__PURE__ */ jsx(
2344
- "div",
2472
+ !value || Array.isArray(value) && value.length === 0 ? /* @__PURE__ */ jsx("span", { className: "flex-1 min-w-0 truncate text-foreground-muted text-sm", children: placeholder }) : Array.isArray(value) ? /* @__PURE__ */ jsx(
2473
+ MultiTagRow,
2345
2474
  {
2346
- className: `${!style?.width ? "min-w-[200px]" : ""} flex flex-wrap items-center gap-1.5`,
2347
- children: !value || Array.isArray(value) && value.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-foreground-muted text-sm", children: placeholder }) : Array.isArray(value) ? value.map((val) => /* @__PURE__ */ jsx(
2348
- Tag,
2349
- {
2350
- disabled,
2351
- removeLabel: `Remove ${labelFor(val)}`,
2352
- onRemove: () => removeSelected(val),
2353
- children: labelFor(val)
2354
- },
2355
- String(val)
2356
- )) : /* @__PURE__ */ jsx(
2357
- Tag,
2358
- {
2359
- disabled,
2360
- removeLabel: `Remove ${labelFor(value)}`,
2361
- onRemove: () => removeSelected(value),
2362
- children: labelFor(value)
2363
- }
2364
- )
2475
+ values: value,
2476
+ disabled,
2477
+ labelFor,
2478
+ onRemove: removeSelected
2365
2479
  }
2366
- ),
2367
- /* @__PURE__ */ jsx("div", { className: `flex-shrink-0 ml-2 text-foreground-muted transition-transform duration-200 ${open ? "rotate-180" : "rotate-0"}`, "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
2480
+ ) : /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0 flex items-center overflow-hidden", children: /* @__PURE__ */ jsx(
2481
+ Tag,
2482
+ {
2483
+ disabled,
2484
+ removeLabel: `Remove ${labelFor(value)}`,
2485
+ onRemove: () => removeSelected(value),
2486
+ children: labelFor(value)
2487
+ }
2488
+ ) }),
2489
+ /* @__PURE__ */ jsx("div", { className: `flex-shrink-0 text-foreground-muted transition-transform duration-200 ${open ? "rotate-180" : "rotate-0"}`, "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
2368
2490
  ]
2369
2491
  }
2370
2492
  ) }),
@@ -3295,6 +3417,7 @@ function TextInput({
3295
3417
  size = "md",
3296
3418
  onBlur,
3297
3419
  errorMessage,
3420
+ helperText,
3298
3421
  required,
3299
3422
  prefix,
3300
3423
  suffix
@@ -3327,9 +3450,9 @@ function TextInput({
3327
3450
  htmlFor,
3328
3451
  errorId,
3329
3452
  errorMessage,
3453
+ helperText,
3330
3454
  layout,
3331
3455
  required,
3332
- className: style ? void 0 : void 0,
3333
3456
  children: hasAdornment ? /* @__PURE__ */ jsxs(
3334
3457
  "div",
3335
3458
  {
@@ -3356,6 +3479,7 @@ function NumberInput({
3356
3479
  layout = "vertical",
3357
3480
  size = "md",
3358
3481
  errorMessage,
3482
+ helperText,
3359
3483
  required,
3360
3484
  inputStyle,
3361
3485
  labelStyle,
@@ -3404,6 +3528,7 @@ function NumberInput({
3404
3528
  htmlFor,
3405
3529
  errorId,
3406
3530
  errorMessage,
3531
+ helperText,
3407
3532
  layout,
3408
3533
  required,
3409
3534
  labelStyle,
@@ -3489,6 +3614,7 @@ function Password({
3489
3614
  size = "md",
3490
3615
  onBlur,
3491
3616
  errorMessage,
3617
+ helperText,
3492
3618
  required,
3493
3619
  showIcon,
3494
3620
  hideIcon
@@ -3503,6 +3629,7 @@ function Password({
3503
3629
  htmlFor,
3504
3630
  errorId,
3505
3631
  errorMessage,
3632
+ helperText,
3506
3633
  layout,
3507
3634
  required,
3508
3635
  children: /* @__PURE__ */ jsxs(
@@ -3557,10 +3684,14 @@ function Checkbox({
3557
3684
  errorMessage,
3558
3685
  disabled = false,
3559
3686
  layout = "horizontal",
3560
- labelPosition = "right"
3687
+ labelPosition = "right",
3688
+ helperText,
3689
+ required
3561
3690
  }) {
3562
3691
  const isChecked = checked ?? value ?? false;
3563
3692
  const labelFirst = labelPosition === "left";
3693
+ const errorId = useId();
3694
+ const hasError = errorMessage != null;
3564
3695
  const box = /* @__PURE__ */ jsx(
3565
3696
  CheckboxPrimitive.Root,
3566
3697
  {
@@ -3579,30 +3710,38 @@ function Checkbox({
3579
3710
  "disabled:cursor-not-allowed"
3580
3711
  ].join(" "),
3581
3712
  "aria-label": typeof label === "string" ? label : void 0,
3713
+ "aria-invalid": hasError || void 0,
3714
+ "aria-describedby": hasError ? errorId : void 0,
3582
3715
  children: /* @__PURE__ */ jsx(CheckboxPrimitive.Indicator, { className: "flex items-center justify-center data-[state=checked]:animate-check-pop", children: /* @__PURE__ */ jsx("svg", { width: "11", height: "9", viewBox: "0 0 11 9", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M1 4.5L4 7.5L10 1", stroke: "white", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
3583
3716
  }
3584
3717
  );
3585
- const labelEl = label && /* @__PURE__ */ jsx("span", { className: "text-sm text-foreground-secondary select-none leading-snug", children: label });
3718
+ const labelEl = label && /* @__PURE__ */ jsxs("span", { className: "text-sm text-foreground-secondary select-none leading-snug", children: [
3719
+ label,
3720
+ required && /* @__PURE__ */ jsx("span", { className: "text-status-error ml-0.5", "aria-hidden": "true", children: "*" })
3721
+ ] });
3586
3722
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3587
- /* @__PURE__ */ jsx(
3588
- "label",
3589
- {
3590
- htmlFor,
3591
- className: [
3592
- "inline-flex",
3593
- layout === "vertical" ? "flex-col items-start gap-1.5" : "flex-row items-center gap-2.5",
3594
- disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"
3595
- ].join(" "),
3596
- children: labelFirst ? /* @__PURE__ */ jsxs(Fragment, { children: [
3597
- labelEl,
3598
- box
3599
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3600
- box,
3601
- labelEl
3602
- ] })
3603
- }
3604
- ),
3605
- errorMessage && /* @__PURE__ */ jsx("span", { className: "text-xs text-status-error mt-0.5", children: errorMessage })
3723
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
3724
+ /* @__PURE__ */ jsx(
3725
+ "label",
3726
+ {
3727
+ htmlFor,
3728
+ className: [
3729
+ "inline-flex",
3730
+ layout === "vertical" ? "flex-col items-start gap-1.5" : "flex-row items-center gap-2.5",
3731
+ disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"
3732
+ ].join(" "),
3733
+ children: labelFirst ? /* @__PURE__ */ jsxs(Fragment, { children: [
3734
+ labelEl,
3735
+ box
3736
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3737
+ box,
3738
+ labelEl
3739
+ ] })
3740
+ }
3741
+ ),
3742
+ helperText != null && /* @__PURE__ */ jsx(FieldHelpIcon, { text: helperText })
3743
+ ] }),
3744
+ errorMessage && /* @__PURE__ */ jsx("span", { id: errorId, className: "text-xs text-status-error mt-0.5", children: errorMessage })
3606
3745
  ] });
3607
3746
  }
3608
3747
  var DOT_SIZE = {
@@ -3622,15 +3761,18 @@ function RadioGroup({
3622
3761
  onChange,
3623
3762
  name,
3624
3763
  label,
3625
- orientation = "vertical",
3764
+ layout = "vertical",
3765
+ labelPosition = "right",
3626
3766
  size = "md",
3627
3767
  disabled,
3628
3768
  required,
3769
+ helperText,
3629
3770
  errorMessage
3630
3771
  }) {
3631
3772
  const errorId = useId();
3632
3773
  const groupId = useId();
3633
3774
  const hasError = errorMessage != null;
3775
+ const labelFirst = labelPosition === "left";
3634
3776
  return /* @__PURE__ */ jsx(
3635
3777
  Field,
3636
3778
  {
@@ -3639,6 +3781,7 @@ function RadioGroup({
3639
3781
  errorId,
3640
3782
  errorMessage,
3641
3783
  required,
3784
+ helperText,
3642
3785
  children: /* @__PURE__ */ jsx(
3643
3786
  RadioGroupPrimitive.Root,
3644
3787
  {
@@ -3651,44 +3794,52 @@ function RadioGroup({
3651
3794
  required,
3652
3795
  "aria-invalid": hasError || void 0,
3653
3796
  "aria-describedby": hasError ? errorId : void 0,
3654
- orientation,
3655
- className: orientation === "horizontal" ? "flex flex-row flex-wrap gap-5" : "flex flex-col gap-3",
3797
+ orientation: layout,
3798
+ className: layout === "horizontal" ? "flex flex-row flex-wrap gap-5" : "flex flex-col gap-3",
3656
3799
  children: options.map((opt) => {
3657
3800
  const itemId = `${groupId}-${opt.value}`;
3658
- return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2.5", children: [
3659
- /* @__PURE__ */ jsx(
3660
- RadioGroupPrimitive.Item,
3661
- {
3662
- id: itemId,
3663
- value: opt.value,
3664
- disabled: opt.disabled,
3665
- className: [
3666
- DOT_SIZE[size],
3667
- "mt-0.5 flex-shrink-0 rounded-full border bg-surface transition-colors duration-150",
3668
- "border-border-strong",
3669
- "hover:border-accent",
3670
- "data-[state=checked]:border-accent",
3671
- "focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring",
3672
- "disabled:cursor-not-allowed disabled:opacity-50"
3673
- ].join(" "),
3674
- children: /* @__PURE__ */ jsx(RadioGroupPrimitive.Indicator, { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "block h-1/2 w-1/2 rounded-full bg-accent" }) })
3675
- }
3676
- ),
3677
- /* @__PURE__ */ jsxs(
3678
- "label",
3679
- {
3680
- htmlFor: itemId,
3681
- className: [
3682
- "select-none",
3683
- opt.disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"
3684
- ].join(" "),
3685
- children: [
3686
- /* @__PURE__ */ jsx("span", { className: `block ${TEXT_SIZE[size]} text-foreground`, children: opt.label }),
3687
- opt.description && /* @__PURE__ */ jsx("span", { className: "block text-xs text-foreground-secondary mt-0.5", children: opt.description })
3688
- ]
3689
- }
3690
- )
3691
- ] }, opt.value);
3801
+ const dot = /* @__PURE__ */ jsx(
3802
+ RadioGroupPrimitive.Item,
3803
+ {
3804
+ id: itemId,
3805
+ value: opt.value,
3806
+ disabled: opt.disabled,
3807
+ className: [
3808
+ DOT_SIZE[size],
3809
+ "mt-0.5 flex-shrink-0 rounded-full border bg-surface transition-colors duration-150",
3810
+ "border-border-strong",
3811
+ "hover:border-accent",
3812
+ "data-[state=checked]:border-accent",
3813
+ // Border-only focus, consistent with the fields.
3814
+ "focus:outline-none focus-visible:border-accent",
3815
+ "disabled:cursor-not-allowed disabled:opacity-50"
3816
+ ].join(" "),
3817
+ children: /* @__PURE__ */ jsx(RadioGroupPrimitive.Indicator, { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ jsx("span", { className: "block h-1/2 w-1/2 rounded-full bg-accent" }) })
3818
+ }
3819
+ );
3820
+ const labelEl = /* @__PURE__ */ jsxs(
3821
+ "label",
3822
+ {
3823
+ htmlFor: itemId,
3824
+ className: [
3825
+ "select-none",
3826
+ opt.disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
3827
+ labelFirst ? "text-right" : ""
3828
+ ].filter(Boolean).join(" "),
3829
+ children: [
3830
+ /* @__PURE__ */ jsx("span", { className: `block ${TEXT_SIZE[size]} text-foreground`, children: opt.label }),
3831
+ opt.description && /* @__PURE__ */ jsx("span", { className: "block text-xs text-foreground-secondary mt-0.5", children: opt.description })
3832
+ ]
3833
+ }
3834
+ );
3835
+ const rowClass = labelFirst && layout === "vertical" ? "grid grid-cols-[1fr_auto] items-start gap-2.5" : "flex items-start gap-2.5";
3836
+ return /* @__PURE__ */ jsx("div", { className: rowClass, children: labelFirst ? /* @__PURE__ */ jsxs(Fragment, { children: [
3837
+ labelEl,
3838
+ dot
3839
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
3840
+ dot,
3841
+ labelEl
3842
+ ] }) }, opt.value);
3692
3843
  })
3693
3844
  }
3694
3845
  )
@@ -3696,28 +3847,73 @@ function RadioGroup({
3696
3847
  );
3697
3848
  }
3698
3849
  function Switch({
3699
- checked = false,
3850
+ checked,
3851
+ defaultChecked = false,
3700
3852
  onChange,
3701
3853
  checkedIcon,
3702
- uncheckedIcon
3854
+ uncheckedIcon,
3855
+ label,
3856
+ layout = "horizontal",
3857
+ helperText,
3858
+ offLabel,
3859
+ onLabel,
3860
+ name,
3861
+ required,
3862
+ disabled,
3863
+ errorMessage
3703
3864
  }) {
3704
3865
  const id = useId();
3705
- return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("label", { htmlFor: id, className: "flex items-center cursor-pointer select-none", children: /* @__PURE__ */ jsx(
3706
- SwitchPrimitive.Root,
3866
+ const errorId = useId();
3867
+ const hasError = errorMessage != null;
3868
+ const isControlled = checked !== void 0;
3869
+ const [internal, setInternal] = useState(defaultChecked);
3870
+ const isOn = isControlled ? checked : internal;
3871
+ const handle = (c) => {
3872
+ if (!isControlled) setInternal(c);
3873
+ onChange?.({ target: { checked: c, name } });
3874
+ };
3875
+ const stateLabel = (active) => [
3876
+ "text-sm select-none transition-colors",
3877
+ active ? "text-foreground font-medium" : "text-foreground-muted",
3878
+ disabled ? "opacity-50" : "cursor-pointer"
3879
+ ].filter(Boolean).join(" ");
3880
+ return /* @__PURE__ */ jsx(
3881
+ Field,
3707
3882
  {
3708
- id,
3709
- checked,
3710
- onCheckedChange: (c) => onChange?.({ target: { checked: c } }),
3711
- className: "relative inline-flex h-6 w-11 flex-shrink-0 items-center rounded-full bg-foreground-secondary data-[state=checked]:bg-accent transition-colors focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring",
3712
- children: /* @__PURE__ */ jsx(
3713
- SwitchPrimitive.Thumb,
3714
- {
3715
- className: "pointer-events-none flex h-5 w-5 items-center justify-center rounded-full bg-background text-foreground shadow transition-transform duration-200 data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-[2px]",
3716
- children: checkedIcon && uncheckedIcon ? checked ? /* @__PURE__ */ jsx("span", { className: "flex items-center justify-center w-3 h-3", children: checkedIcon }) : /* @__PURE__ */ jsx("span", { className: "flex items-center justify-center w-3 h-3", children: uncheckedIcon }) : null
3717
- }
3718
- )
3883
+ label,
3884
+ htmlFor: id,
3885
+ errorId,
3886
+ errorMessage,
3887
+ layout,
3888
+ required,
3889
+ helperText,
3890
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2.5", children: [
3891
+ offLabel != null && /* @__PURE__ */ jsx("label", { htmlFor: id, className: stateLabel(!isOn), children: offLabel }),
3892
+ /* @__PURE__ */ jsx(
3893
+ SwitchPrimitive.Root,
3894
+ {
3895
+ id,
3896
+ name,
3897
+ checked: isOn,
3898
+ onCheckedChange: handle,
3899
+ disabled,
3900
+ required,
3901
+ "aria-invalid": hasError || void 0,
3902
+ "aria-describedby": hasError ? errorId : void 0,
3903
+ className: "relative inline-flex h-6 w-11 flex-shrink-0 items-center rounded-full bg-foreground-secondary data-[state=checked]:bg-accent transition-colors focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring disabled:opacity-50 disabled:cursor-not-allowed",
3904
+ children: /* @__PURE__ */ jsx(
3905
+ SwitchPrimitive.Thumb,
3906
+ {
3907
+ className: "pointer-events-none flex h-5 w-5 items-center justify-center rounded-full bg-background text-foreground shadow transition-transform duration-200 data-[state=checked]:translate-x-[22px] data-[state=unchecked]:translate-x-[2px]",
3908
+ children: checkedIcon && uncheckedIcon ? /* @__PURE__ */ jsx("span", { className: "flex items-center justify-center w-3 h-3", children: isOn ? checkedIcon : uncheckedIcon }) : null
3909
+ }
3910
+ )
3911
+ }
3912
+ ),
3913
+ onLabel != null && /* @__PURE__ */ jsx("label", { htmlFor: id, className: stateLabel(isOn), children: onLabel })
3914
+ ] })
3719
3915
  }
3720
- ) }) });
3916
+ );
3721
3917
  }
3722
3918
  function AutoComplete({
3723
3919
  disabled,
@@ -3736,6 +3932,7 @@ function AutoComplete({
3736
3932
  size = "md",
3737
3933
  icon,
3738
3934
  errorMessage,
3935
+ helperText,
3739
3936
  required,
3740
3937
  htmlFor
3741
3938
  }) {
@@ -3794,6 +3991,7 @@ function AutoComplete({
3794
3991
  htmlFor,
3795
3992
  errorId,
3796
3993
  errorMessage,
3994
+ helperText,
3797
3995
  layout,
3798
3996
  required,
3799
3997
  children: /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
@@ -3893,6 +4091,8 @@ function TreeSelect({
3893
4091
  onChange,
3894
4092
  disabled,
3895
4093
  layout = "horizontal",
4094
+ helperText,
4095
+ required,
3896
4096
  errorMessage,
3897
4097
  style,
3898
4098
  htmlFor,
@@ -3978,12 +4178,14 @@ function TreeSelect({
3978
4178
  };
3979
4179
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3980
4180
  /* @__PURE__ */ jsxs("div", { className: `flex ${layout === "vertical" ? "flex-col gap-1" : "flex-row items-center gap-2"}`, children: [
3981
- label && /* @__PURE__ */ jsx(
3982
- "label",
4181
+ /* @__PURE__ */ jsx(
4182
+ FieldLabel,
3983
4183
  {
3984
- className: "text-sm font-medium ml-1 max-content select-none text-foreground",
4184
+ label,
3985
4185
  htmlFor,
3986
- children: label
4186
+ required,
4187
+ helperText,
4188
+ horizontal: layout === "horizontal"
3987
4189
  }
3988
4190
  ),
3989
4191
  /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
@@ -4145,6 +4347,7 @@ function FileInput({
4145
4347
  hint,
4146
4348
  maxSize,
4147
4349
  errorMessage,
4350
+ helperText,
4148
4351
  disabled,
4149
4352
  required,
4150
4353
  icon
@@ -4191,6 +4394,7 @@ function FileInput({
4191
4394
  htmlFor,
4192
4395
  errorId,
4193
4396
  errorMessage: effectiveError,
4397
+ helperText,
4194
4398
  required,
4195
4399
  children: [
4196
4400
  /* @__PURE__ */ jsxs(
@@ -4329,6 +4533,8 @@ function DatePicker({
4329
4533
  htmlFor,
4330
4534
  name: _name,
4331
4535
  layout = "horizontal",
4536
+ helperText,
4537
+ required,
4332
4538
  disabled,
4333
4539
  errorMessage,
4334
4540
  min,
@@ -4419,13 +4625,15 @@ function DatePicker({
4419
4625
  };
4420
4626
  const displayValue = value ? format(value) : "";
4421
4627
  return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
4422
- /* @__PURE__ */ jsxs("div", { className: `flex ${layout === "vertical" ? "flex-col gap-1" : "flex-row items-center gap-2"}`, children: [
4423
- label && /* @__PURE__ */ jsx(
4424
- "label",
4628
+ /* @__PURE__ */ jsxs("div", { className: `flex ${layout === "vertical" ? "flex-col gap-1.5" : "flex-row items-start gap-3"}`, children: [
4629
+ /* @__PURE__ */ jsx(
4630
+ FieldLabel,
4425
4631
  {
4426
- className: "text-sm font-medium ml-1 max-content select-none text-foreground",
4632
+ label,
4427
4633
  htmlFor,
4428
- children: label
4634
+ required,
4635
+ helperText,
4636
+ horizontal: layout === "horizontal"
4429
4637
  }
4430
4638
  ),
4431
4639
  /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
@@ -4644,6 +4852,7 @@ function TextArea({
4644
4852
  showCount = false,
4645
4853
  resize,
4646
4854
  errorMessage,
4855
+ helperText,
4647
4856
  required,
4648
4857
  style,
4649
4858
  inputStyle
@@ -4669,6 +4878,7 @@ function TextArea({
4669
4878
  htmlFor,
4670
4879
  errorId,
4671
4880
  errorMessage,
4881
+ helperText,
4672
4882
  layout,
4673
4883
  required,
4674
4884
  children: [
@@ -4709,51 +4919,84 @@ function SegmentedControl({
4709
4919
  size = "md",
4710
4920
  fullWidth = false,
4711
4921
  disabled,
4922
+ label,
4923
+ layout = "vertical",
4924
+ helperText,
4925
+ name,
4926
+ required,
4927
+ errorMessage,
4712
4928
  "aria-label": ariaLabel
4713
4929
  }) {
4714
4930
  const sz = SIZE[size];
4715
- return /* @__PURE__ */ jsx(
4716
- ToggleGroup.Root,
4931
+ const groupId = useId();
4932
+ const errorId = useId();
4933
+ const hasError = errorMessage != null;
4934
+ const isControlled = value !== void 0;
4935
+ const [internal, setInternal] = useState(defaultValue);
4936
+ const current = isControlled ? value : internal;
4937
+ const handle = (v) => {
4938
+ if (!v) return;
4939
+ if (!isControlled) setInternal(v);
4940
+ onChange?.(v);
4941
+ };
4942
+ return /* @__PURE__ */ jsxs(
4943
+ Field,
4717
4944
  {
4718
- type: "single",
4719
- value,
4720
- defaultValue,
4721
- onValueChange: (v) => {
4722
- if (v) onChange?.(v);
4723
- },
4724
- disabled,
4725
- "aria-label": ariaLabel,
4726
- className: [
4727
- "inline-flex items-center gap-1 rounded-lg border border-border bg-surface-raised p-1",
4728
- sz.h,
4729
- fullWidth ? "flex w-full" : "",
4730
- disabled ? "opacity-60 cursor-not-allowed" : ""
4731
- ].filter(Boolean).join(" "),
4732
- children: options.map((opt) => /* @__PURE__ */ jsxs(
4733
- ToggleGroup.Item,
4734
- {
4735
- value: opt.value,
4736
- disabled: opt.disabled,
4737
- className: [
4738
- "inline-flex items-center justify-center gap-1.5 rounded-md select-none whitespace-nowrap",
4739
- "transition-colors duration-150 h-full",
4740
- sz.text,
4741
- sz.pad,
4742
- fullWidth ? "flex-1" : "",
4743
- // Resting: muted text, transparent. Hover lifts the text.
4744
- "text-foreground-secondary hover:text-foreground",
4745
- // Active: surface-white pill + accent text + subtle shadow.
4746
- "data-[state=on]:bg-surface data-[state=on]:text-accent data-[state=on]:shadow-sm",
4747
- "focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring",
4748
- "disabled:opacity-40 disabled:cursor-not-allowed"
4749
- ].filter(Boolean).join(" "),
4750
- children: [
4751
- opt.icon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: opt.icon }),
4752
- opt.label
4753
- ]
4754
- },
4755
- opt.value
4756
- ))
4945
+ label,
4946
+ htmlFor: groupId,
4947
+ errorId,
4948
+ errorMessage,
4949
+ layout,
4950
+ required,
4951
+ helperText,
4952
+ children: [
4953
+ name && /* @__PURE__ */ jsx("input", { type: "hidden", name, value: current ?? "" }),
4954
+ /* @__PURE__ */ jsx(
4955
+ ToggleGroup.Root,
4956
+ {
4957
+ id: groupId,
4958
+ type: "single",
4959
+ value: current,
4960
+ onValueChange: handle,
4961
+ disabled,
4962
+ "aria-label": ariaLabel ?? (typeof label === "string" ? label : void 0),
4963
+ "aria-invalid": hasError || void 0,
4964
+ "aria-describedby": hasError ? errorId : void 0,
4965
+ className: [
4966
+ "inline-flex items-center gap-1 rounded-lg border bg-surface-raised p-1",
4967
+ hasError ? "border-status-error" : "border-border",
4968
+ sz.h,
4969
+ fullWidth ? "flex w-full" : "w-fit",
4970
+ disabled ? "opacity-60 cursor-not-allowed" : ""
4971
+ ].filter(Boolean).join(" "),
4972
+ children: options.map((opt) => /* @__PURE__ */ jsxs(
4973
+ ToggleGroup.Item,
4974
+ {
4975
+ value: opt.value,
4976
+ disabled: opt.disabled,
4977
+ className: [
4978
+ "inline-flex items-center justify-center gap-1.5 rounded-md select-none whitespace-nowrap",
4979
+ "transition-colors duration-150 h-full",
4980
+ sz.text,
4981
+ sz.pad,
4982
+ fullWidth ? "flex-1" : "",
4983
+ // Resting: muted text, transparent. Hover lifts the text.
4984
+ "text-foreground-secondary hover:text-foreground",
4985
+ // Active: surface-white pill + accent text + subtle shadow.
4986
+ "data-[state=on]:bg-surface data-[state=on]:text-accent data-[state=on]:shadow-sm",
4987
+ "focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring",
4988
+ "disabled:opacity-40 disabled:cursor-not-allowed"
4989
+ ].filter(Boolean).join(" "),
4990
+ children: [
4991
+ opt.icon && /* @__PURE__ */ jsx("span", { className: "flex-shrink-0", children: opt.icon }),
4992
+ opt.label
4993
+ ]
4994
+ },
4995
+ opt.value
4996
+ ))
4997
+ }
4998
+ )
4999
+ ]
4757
5000
  }
4758
5001
  );
4759
5002
  }
@@ -4776,6 +5019,8 @@ function Slider({
4776
5019
  size = "md",
4777
5020
  disabled,
4778
5021
  errorMessage,
5022
+ helperText,
5023
+ required,
4779
5024
  name,
4780
5025
  htmlFor
4781
5026
  }) {
@@ -4795,7 +5040,13 @@ function Slider({
4795
5040
  const valueText = current.map(formatValue).join(" \u2013 ");
4796
5041
  return /* @__PURE__ */ jsxs(Field, { label: void 0, errorId, errorMessage, children: [
4797
5042
  (label || showValue) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
4798
- label && /* @__PURE__ */ jsx("label", { htmlFor, className: "text-sm font-medium text-foreground select-none", children: label }),
5043
+ label && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
5044
+ /* @__PURE__ */ jsxs("label", { htmlFor, className: "text-sm font-medium text-foreground select-none", children: [
5045
+ label,
5046
+ required && /* @__PURE__ */ jsx("span", { className: "text-status-error ml-0.5", "aria-hidden": "true", children: "*" })
5047
+ ] }),
5048
+ helperText != null && /* @__PURE__ */ jsx(FieldHelpIcon, { text: helperText })
5049
+ ] }),
4799
5050
  showValue && /* @__PURE__ */ jsx("span", { className: "text-sm text-foreground-secondary tabular-nums", children: valueText })
4800
5051
  ] }),
4801
5052
  /* @__PURE__ */ jsxs(
@@ -4867,6 +5118,7 @@ function TagsInput({
4867
5118
  size = "md",
4868
5119
  disabled,
4869
5120
  errorMessage,
5121
+ helperText,
4870
5122
  required,
4871
5123
  maxTags,
4872
5124
  dedupe = true,
@@ -4934,6 +5186,7 @@ function TagsInput({
4934
5186
  htmlFor,
4935
5187
  errorId,
4936
5188
  errorMessage: errorText,
5189
+ helperText,
4937
5190
  layout,
4938
5191
  required,
4939
5192
  children: /* @__PURE__ */ jsxs(
@@ -5001,6 +5254,8 @@ function OtpInput({
5001
5254
  disabled,
5002
5255
  errorMessage,
5003
5256
  required,
5257
+ layout = "vertical",
5258
+ helperText,
5004
5259
  groupAfter
5005
5260
  }) {
5006
5261
  const errorId = useId();
@@ -5054,7 +5309,7 @@ function OtpInput({
5054
5309
  emit(valid.join(""));
5055
5310
  focusBox(valid.length);
5056
5311
  };
5057
- return /* @__PURE__ */ jsx(Field, { label, htmlFor, errorId, errorMessage, required, children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", role: "group", "aria-label": typeof label === "string" ? label : "One-time code", children: chars.map((char, idx) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
5312
+ return /* @__PURE__ */ jsx(Field, { label, htmlFor, errorId, errorMessage, required, layout, helperText, children: /* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", role: "group", "aria-label": typeof label === "string" ? label : "One-time code", children: chars.map((char, idx) => /* @__PURE__ */ jsxs(React8.Fragment, { children: [
5058
5313
  /* @__PURE__ */ jsx(
5059
5314
  "input",
5060
5315
  {
@@ -5079,10 +5334,11 @@ function OtpInput({
5079
5334
  className: [
5080
5335
  BOX_SIZE[size],
5081
5336
  "text-center font-medium rounded-lg border bg-surface text-foreground",
5082
- "transition-[border-color,box-shadow] duration-150",
5337
+ "transition-[border-color] duration-150",
5083
5338
  hasError ? "border-status-error" : "border-border",
5084
5339
  "hover:border-border-strong",
5085
- "focus:outline-none focus:border-accent focus:ring-[3px] focus:ring-focus-ring",
5340
+ // Border-only focus, consistent with every field (no clip-prone ring).
5341
+ "focus:outline-none focus:border-accent",
5086
5342
  "disabled:bg-surface-raised disabled:text-foreground-muted disabled:cursor-not-allowed"
5087
5343
  ].join(" ")
5088
5344
  }
@@ -5105,7 +5361,10 @@ function Rating({
5105
5361
  disabled,
5106
5362
  icon = Star,
5107
5363
  errorMessage,
5108
- name
5364
+ name,
5365
+ layout = "vertical",
5366
+ helperText,
5367
+ required
5109
5368
  }) {
5110
5369
  const errorId = useId();
5111
5370
  const [internal, setInternal] = useState(defaultValue);
@@ -5135,7 +5394,7 @@ function Rating({
5135
5394
  commit(count);
5136
5395
  }
5137
5396
  };
5138
- return /* @__PURE__ */ jsx(Field, { label, errorId, errorMessage, children: /* @__PURE__ */ jsxs(
5397
+ return /* @__PURE__ */ jsx(Field, { label, errorId, errorMessage, layout, required, helperText, children: /* @__PURE__ */ jsxs(
5139
5398
  "div",
5140
5399
  {
5141
5400
  role: interactive ? "slider" : "img",
@@ -5227,6 +5486,7 @@ function TimePicker({
5227
5486
  minuteStep = 1,
5228
5487
  disabled,
5229
5488
  errorMessage,
5489
+ helperText,
5230
5490
  required,
5231
5491
  style
5232
5492
  }) {
@@ -5259,7 +5519,7 @@ function TimePicker({
5259
5519
  },
5260
5520
  n
5261
5521
  )) });
5262
- return /* @__PURE__ */ jsxs(Field, { label, htmlFor, errorId, errorMessage, layout, required, children: [
5522
+ return /* @__PURE__ */ jsxs(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5263
5523
  /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
5264
5524
  /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
5265
5525
  "button",
@@ -5351,6 +5611,7 @@ function DateRangePicker({
5351
5611
  format = defaultFmt,
5352
5612
  disabled,
5353
5613
  errorMessage,
5614
+ helperText,
5354
5615
  required,
5355
5616
  style
5356
5617
  }) {
@@ -5423,7 +5684,7 @@ function DateRangePicker({
5423
5684
  ] })
5424
5685
  ] });
5425
5686
  };
5426
- return /* @__PURE__ */ jsx(Field, { label, htmlFor, errorId, errorMessage, layout, required, children: /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => {
5687
+ return /* @__PURE__ */ jsx(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => {
5427
5688
  if (!disabled) {
5428
5689
  setOpen(o);
5429
5690
  if (!o) {
@@ -5531,6 +5792,7 @@ function ColorPicker({
5531
5792
  allowCustom = true,
5532
5793
  disabled,
5533
5794
  errorMessage,
5795
+ helperText,
5534
5796
  required,
5535
5797
  placeholder = "Pick a colour\u2026"
5536
5798
  }) {
@@ -5548,7 +5810,7 @@ function ColorPicker({
5548
5810
  setDraft(hex);
5549
5811
  if (HEX_RE.test(hex)) onChange?.(hex);
5550
5812
  };
5551
- return /* @__PURE__ */ jsxs(Field, { label, htmlFor, errorId, errorMessage, layout, required, children: [
5813
+ return /* @__PURE__ */ jsxs(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5552
5814
  /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
5553
5815
  /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
5554
5816
  "button",