@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.cjs CHANGED
@@ -2179,6 +2179,51 @@ function fieldShell({
2179
2179
  "placeholder:text-foreground-muted"
2180
2180
  ].filter(Boolean).join(" ");
2181
2181
  }
2182
+ function FieldHelpIcon({ text }) {
2183
+ return /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { title: text, placement: "top", children: /* @__PURE__ */ jsxRuntime.jsx(
2184
+ "button",
2185
+ {
2186
+ type: "button",
2187
+ "aria-label": "More information",
2188
+ className: "inline-flex items-center justify-center rounded-full text-foreground-muted transition-colors hover:text-foreground focus:outline-none focus-visible:text-accent",
2189
+ children: /* @__PURE__ */ jsxRuntime.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: [
2190
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8", cy: "8", r: "6.25" }),
2191
+ /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", d: "M8 7.4v3.4" }),
2192
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "8", cy: "5.1", r: "0.65", fill: "currentColor", stroke: "none" })
2193
+ ] })
2194
+ }
2195
+ ) });
2196
+ }
2197
+ function FieldLabel({
2198
+ label,
2199
+ htmlFor,
2200
+ required,
2201
+ helperText,
2202
+ horizontal = false,
2203
+ style,
2204
+ width,
2205
+ className = ""
2206
+ }) {
2207
+ if (label == null && helperText == null) return null;
2208
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2209
+ "div",
2210
+ {
2211
+ style: { width: horizontal ? width : void 0, ...style },
2212
+ className: [
2213
+ "flex items-center gap-1",
2214
+ horizontal ? "mt-2 flex-shrink-0 whitespace-nowrap" : "",
2215
+ className
2216
+ ].filter(Boolean).join(" "),
2217
+ children: [
2218
+ label != null && /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor, className: "text-sm font-medium text-foreground select-none", children: [
2219
+ label,
2220
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-status-error ml-0.5", "aria-hidden": "true", children: "*" })
2221
+ ] }),
2222
+ helperText != null && /* @__PURE__ */ jsxRuntime.jsx(FieldHelpIcon, { text: helperText })
2223
+ ]
2224
+ }
2225
+ );
2226
+ }
2182
2227
  function Field({
2183
2228
  label,
2184
2229
  htmlFor,
@@ -2186,6 +2231,7 @@ function Field({
2186
2231
  errorMessage,
2187
2232
  layout = "vertical",
2188
2233
  required,
2234
+ helperText,
2189
2235
  labelStyle,
2190
2236
  labelWidth,
2191
2237
  className = "",
@@ -2202,21 +2248,16 @@ function Field({
2202
2248
  className
2203
2249
  ].filter(Boolean).join(" "),
2204
2250
  children: [
2205
- label && /* @__PURE__ */ jsxRuntime.jsxs(
2206
- "label",
2251
+ /* @__PURE__ */ jsxRuntime.jsx(
2252
+ FieldLabel,
2207
2253
  {
2254
+ label,
2208
2255
  htmlFor,
2209
- style: { width: horizontal ? labelWidth : void 0, ...labelStyle },
2210
- className: [
2211
- "text-sm font-medium text-foreground select-none",
2212
- // In horizontal layout the label must not wrap onto
2213
- // multiple lines (e.g. "Report date", "Select option").
2214
- horizontal ? "mt-2 flex-shrink-0 whitespace-nowrap" : ""
2215
- ].filter(Boolean).join(" "),
2216
- children: [
2217
- label,
2218
- required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-status-error ml-0.5", "aria-hidden": "true", children: "*" })
2219
- ]
2256
+ required,
2257
+ helperText,
2258
+ horizontal,
2259
+ style: labelStyle,
2260
+ width: labelWidth
2220
2261
  }
2221
2262
  ),
2222
2263
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0 flex-1", children: [
@@ -2228,8 +2269,8 @@ function Field({
2228
2269
  );
2229
2270
  }
2230
2271
  var SearchIcon = /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.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" }) });
2231
- var SearchInput = React8__default.default.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon }, ref) {
2232
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, layout, children: /* @__PURE__ */ jsxRuntime.jsxs(
2272
+ var SearchInput = React8__default.default.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText }, ref) {
2273
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, layout, helperText, children: /* @__PURE__ */ jsxRuntime.jsxs(
2233
2274
  "div",
2234
2275
  {
2235
2276
  className: `flex items-center ${fieldShell({ size, disabled, focusWithin: true })}`,
@@ -2276,6 +2317,90 @@ function Tag({ children, onRemove, removeLabel, disabled }) {
2276
2317
  )
2277
2318
  ] });
2278
2319
  }
2320
+ function MultiTagRow({
2321
+ values,
2322
+ disabled,
2323
+ labelFor,
2324
+ onRemove
2325
+ }) {
2326
+ const wrapRef = React8.useRef(null);
2327
+ const measureRef = React8.useRef(null);
2328
+ const [visibleCount, setVisibleCount] = React8.useState(values.length);
2329
+ const key = values.map(String).join("|");
2330
+ React8.useLayoutEffect(() => {
2331
+ const wrap = wrapRef.current;
2332
+ const measure = measureRef.current;
2333
+ if (!wrap || !measure) return;
2334
+ const GAP = 6;
2335
+ const recompute = () => {
2336
+ const avail = wrap.clientWidth;
2337
+ const tagEls = Array.from(measure.querySelectorAll("[data-mt]"));
2338
+ const moreEl = measure.querySelector("[data-mm]");
2339
+ const widths = tagEls.map((e) => e.offsetWidth);
2340
+ const moreW = moreEl ? moreEl.offsetWidth : 0;
2341
+ if (widths.length === 0) {
2342
+ setVisibleCount(0);
2343
+ return;
2344
+ }
2345
+ let used = 0;
2346
+ let count = 0;
2347
+ for (let i = 0; i < widths.length; i++) {
2348
+ const w = widths[i] + (i > 0 ? GAP : 0);
2349
+ if (used + w <= avail) {
2350
+ used += w;
2351
+ count++;
2352
+ } else break;
2353
+ }
2354
+ if (count < widths.length) {
2355
+ while (count > 0) {
2356
+ let t = 0;
2357
+ for (let i = 0; i < count; i++) t += widths[i] + (i > 0 ? GAP : 0);
2358
+ t += GAP + moreW;
2359
+ if (t <= avail) break;
2360
+ count--;
2361
+ }
2362
+ }
2363
+ setVisibleCount(count);
2364
+ };
2365
+ recompute();
2366
+ const ro = new ResizeObserver(recompute);
2367
+ ro.observe(wrap);
2368
+ return () => ro.disconnect();
2369
+ }, [key]);
2370
+ const hidden = values.length - visibleCount;
2371
+ const moreChip = (n) => /* @__PURE__ */ jsxRuntime.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: [
2372
+ "+",
2373
+ n,
2374
+ " more"
2375
+ ] });
2376
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapRef, className: "relative flex-1 min-w-0 flex flex-nowrap items-center gap-1.5 overflow-hidden", children: [
2377
+ /* @__PURE__ */ jsxRuntime.jsxs(
2378
+ "div",
2379
+ {
2380
+ ref: measureRef,
2381
+ "aria-hidden": "true",
2382
+ className: "absolute invisible pointer-events-none flex flex-nowrap items-center gap-1.5",
2383
+ style: { left: -9999, top: -9999 },
2384
+ children: [
2385
+ values.map((val) => /* @__PURE__ */ jsxRuntime.jsx("span", { "data-mt": true, children: /* @__PURE__ */ jsxRuntime.jsx(Tag, { removeLabel: "x", onRemove: () => {
2386
+ }, children: labelFor(val) }) }, `m-${val}`)),
2387
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "data-mm": true, children: moreChip(values.length) })
2388
+ ]
2389
+ }
2390
+ ),
2391
+ values.slice(0, visibleCount).map((val) => /* @__PURE__ */ jsxRuntime.jsx(
2392
+ Tag,
2393
+ {
2394
+ disabled,
2395
+ removeLabel: `Remove ${labelFor(val)}`,
2396
+ onRemove: () => onRemove(val),
2397
+ children: labelFor(val)
2398
+ },
2399
+ String(val)
2400
+ )),
2401
+ hidden > 0 && moreChip(hidden)
2402
+ ] });
2403
+ }
2279
2404
  function Dropdown({
2280
2405
  isMultiselect = false,
2281
2406
  hasSearch = true,
@@ -2285,6 +2410,8 @@ function Dropdown({
2285
2410
  onChange,
2286
2411
  disabled,
2287
2412
  layout = "horizontal",
2413
+ helperText,
2414
+ required,
2288
2415
  errorMessage,
2289
2416
  style = {},
2290
2417
  htmlFor,
@@ -2345,13 +2472,15 @@ function Dropdown({
2345
2472
  {
2346
2473
  className: `flex ${layout === "vertical" ? "flex-col gap-1.5" : "flex-row items-start gap-3"}`,
2347
2474
  children: [
2348
- label && /* @__PURE__ */ jsxRuntime.jsx(
2349
- "label",
2475
+ /* @__PURE__ */ jsxRuntime.jsx(
2476
+ FieldLabel,
2350
2477
  {
2351
- className: `text-sm font-medium select-none text-foreground ${layout === "horizontal" ? "mt-2 flex-shrink-0 whitespace-nowrap" : ""}`,
2478
+ label,
2352
2479
  htmlFor,
2353
- style: labelStyle,
2354
- children: label
2480
+ required,
2481
+ helperText,
2482
+ horizontal: layout === "horizontal",
2483
+ style: labelStyle
2355
2484
  }
2356
2485
  ),
2357
2486
  /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
@@ -2364,8 +2493,8 @@ function Dropdown({
2364
2493
  "aria-haspopup": "listbox",
2365
2494
  "aria-invalid": hasError || void 0,
2366
2495
  "aria-describedby": hasError ? errorId : void 0,
2367
- style,
2368
- 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 })}`,
2496
+ style: { width: 240, ...style },
2497
+ 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 })}`,
2369
2498
  tabIndex: disabled ? -1 : 0,
2370
2499
  onKeyDown: (e) => {
2371
2500
  if (disabled) return;
@@ -2375,31 +2504,24 @@ function Dropdown({
2375
2504
  }
2376
2505
  },
2377
2506
  children: [
2378
- /* @__PURE__ */ jsxRuntime.jsx(
2379
- "div",
2507
+ !value || Array.isArray(value) && value.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 min-w-0 truncate text-foreground-muted text-sm", children: placeholder }) : Array.isArray(value) ? /* @__PURE__ */ jsxRuntime.jsx(
2508
+ MultiTagRow,
2380
2509
  {
2381
- className: `${!style?.width ? "min-w-[200px]" : ""} flex flex-wrap items-center gap-1.5`,
2382
- children: !value || Array.isArray(value) && value.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-foreground-muted text-sm", children: placeholder }) : Array.isArray(value) ? value.map((val) => /* @__PURE__ */ jsxRuntime.jsx(
2383
- Tag,
2384
- {
2385
- disabled,
2386
- removeLabel: `Remove ${labelFor(val)}`,
2387
- onRemove: () => removeSelected(val),
2388
- children: labelFor(val)
2389
- },
2390
- String(val)
2391
- )) : /* @__PURE__ */ jsxRuntime.jsx(
2392
- Tag,
2393
- {
2394
- disabled,
2395
- removeLabel: `Remove ${labelFor(value)}`,
2396
- onRemove: () => removeSelected(value),
2397
- children: labelFor(value)
2398
- }
2399
- )
2510
+ values: value,
2511
+ disabled,
2512
+ labelFor,
2513
+ onRemove: removeSelected
2400
2514
  }
2401
- ),
2402
- /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
2515
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-w-0 flex items-center overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
2516
+ Tag,
2517
+ {
2518
+ disabled,
2519
+ removeLabel: `Remove ${labelFor(value)}`,
2520
+ onRemove: () => removeSelected(value),
2521
+ children: labelFor(value)
2522
+ }
2523
+ ) }),
2524
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex-shrink-0 text-foreground-muted transition-transform duration-200 ${open ? "rotate-180" : "rotate-0"}`, "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "h-4 w-4", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19 9l-7 7-7-7" }) }) })
2403
2525
  ]
2404
2526
  }
2405
2527
  ) }),
@@ -3330,6 +3452,7 @@ function TextInput({
3330
3452
  size = "md",
3331
3453
  onBlur,
3332
3454
  errorMessage,
3455
+ helperText,
3333
3456
  required,
3334
3457
  prefix,
3335
3458
  suffix
@@ -3362,9 +3485,9 @@ function TextInput({
3362
3485
  htmlFor,
3363
3486
  errorId,
3364
3487
  errorMessage,
3488
+ helperText,
3365
3489
  layout,
3366
3490
  required,
3367
- className: style ? void 0 : void 0,
3368
3491
  children: hasAdornment ? /* @__PURE__ */ jsxRuntime.jsxs(
3369
3492
  "div",
3370
3493
  {
@@ -3391,6 +3514,7 @@ function NumberInput({
3391
3514
  layout = "vertical",
3392
3515
  size = "md",
3393
3516
  errorMessage,
3517
+ helperText,
3394
3518
  required,
3395
3519
  inputStyle,
3396
3520
  labelStyle,
@@ -3439,6 +3563,7 @@ function NumberInput({
3439
3563
  htmlFor,
3440
3564
  errorId,
3441
3565
  errorMessage,
3566
+ helperText,
3442
3567
  layout,
3443
3568
  required,
3444
3569
  labelStyle,
@@ -3524,6 +3649,7 @@ function Password({
3524
3649
  size = "md",
3525
3650
  onBlur,
3526
3651
  errorMessage,
3652
+ helperText,
3527
3653
  required,
3528
3654
  showIcon,
3529
3655
  hideIcon
@@ -3538,6 +3664,7 @@ function Password({
3538
3664
  htmlFor,
3539
3665
  errorId,
3540
3666
  errorMessage,
3667
+ helperText,
3541
3668
  layout,
3542
3669
  required,
3543
3670
  children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -3592,10 +3719,14 @@ function Checkbox({
3592
3719
  errorMessage,
3593
3720
  disabled = false,
3594
3721
  layout = "horizontal",
3595
- labelPosition = "right"
3722
+ labelPosition = "right",
3723
+ helperText,
3724
+ required
3596
3725
  }) {
3597
3726
  const isChecked = checked ?? value ?? false;
3598
3727
  const labelFirst = labelPosition === "left";
3728
+ const errorId = React8.useId();
3729
+ const hasError = errorMessage != null;
3599
3730
  const box = /* @__PURE__ */ jsxRuntime.jsx(
3600
3731
  CheckboxPrimitive__namespace.Root,
3601
3732
  {
@@ -3614,30 +3745,38 @@ function Checkbox({
3614
3745
  "disabled:cursor-not-allowed"
3615
3746
  ].join(" "),
3616
3747
  "aria-label": typeof label === "string" ? label : void 0,
3748
+ "aria-invalid": hasError || void 0,
3749
+ "aria-describedby": hasError ? errorId : void 0,
3617
3750
  children: /* @__PURE__ */ jsxRuntime.jsx(CheckboxPrimitive__namespace.Indicator, { className: "flex items-center justify-center data-[state=checked]:animate-check-pop", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "11", height: "9", viewBox: "0 0 11 9", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 4.5L4 7.5L10 1", stroke: "white", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) })
3618
3751
  }
3619
3752
  );
3620
- const labelEl = label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground-secondary select-none leading-snug", children: label });
3753
+ const labelEl = label && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-sm text-foreground-secondary select-none leading-snug", children: [
3754
+ label,
3755
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-status-error ml-0.5", "aria-hidden": "true", children: "*" })
3756
+ ] });
3621
3757
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
3622
- /* @__PURE__ */ jsxRuntime.jsx(
3623
- "label",
3624
- {
3625
- htmlFor,
3626
- className: [
3627
- "inline-flex",
3628
- layout === "vertical" ? "flex-col items-start gap-1.5" : "flex-row items-center gap-2.5",
3629
- disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"
3630
- ].join(" "),
3631
- children: labelFirst ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3632
- labelEl,
3633
- box
3634
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3635
- box,
3636
- labelEl
3637
- ] })
3638
- }
3639
- ),
3640
- errorMessage && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-status-error mt-0.5", children: errorMessage })
3758
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
3759
+ /* @__PURE__ */ jsxRuntime.jsx(
3760
+ "label",
3761
+ {
3762
+ htmlFor,
3763
+ className: [
3764
+ "inline-flex",
3765
+ layout === "vertical" ? "flex-col items-start gap-1.5" : "flex-row items-center gap-2.5",
3766
+ disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"
3767
+ ].join(" "),
3768
+ children: labelFirst ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3769
+ labelEl,
3770
+ box
3771
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3772
+ box,
3773
+ labelEl
3774
+ ] })
3775
+ }
3776
+ ),
3777
+ helperText != null && /* @__PURE__ */ jsxRuntime.jsx(FieldHelpIcon, { text: helperText })
3778
+ ] }),
3779
+ errorMessage && /* @__PURE__ */ jsxRuntime.jsx("span", { id: errorId, className: "text-xs text-status-error mt-0.5", children: errorMessage })
3641
3780
  ] });
3642
3781
  }
3643
3782
  var DOT_SIZE = {
@@ -3657,15 +3796,18 @@ function RadioGroup({
3657
3796
  onChange,
3658
3797
  name,
3659
3798
  label,
3660
- orientation = "vertical",
3799
+ layout = "vertical",
3800
+ labelPosition = "right",
3661
3801
  size = "md",
3662
3802
  disabled,
3663
3803
  required,
3804
+ helperText,
3664
3805
  errorMessage
3665
3806
  }) {
3666
3807
  const errorId = React8.useId();
3667
3808
  const groupId = React8.useId();
3668
3809
  const hasError = errorMessage != null;
3810
+ const labelFirst = labelPosition === "left";
3669
3811
  return /* @__PURE__ */ jsxRuntime.jsx(
3670
3812
  Field,
3671
3813
  {
@@ -3674,6 +3816,7 @@ function RadioGroup({
3674
3816
  errorId,
3675
3817
  errorMessage,
3676
3818
  required,
3819
+ helperText,
3677
3820
  children: /* @__PURE__ */ jsxRuntime.jsx(
3678
3821
  RadioGroupPrimitive__namespace.Root,
3679
3822
  {
@@ -3686,44 +3829,52 @@ function RadioGroup({
3686
3829
  required,
3687
3830
  "aria-invalid": hasError || void 0,
3688
3831
  "aria-describedby": hasError ? errorId : void 0,
3689
- orientation,
3690
- className: orientation === "horizontal" ? "flex flex-row flex-wrap gap-5" : "flex flex-col gap-3",
3832
+ orientation: layout,
3833
+ className: layout === "horizontal" ? "flex flex-row flex-wrap gap-5" : "flex flex-col gap-3",
3691
3834
  children: options.map((opt) => {
3692
3835
  const itemId = `${groupId}-${opt.value}`;
3693
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2.5", children: [
3694
- /* @__PURE__ */ jsxRuntime.jsx(
3695
- RadioGroupPrimitive__namespace.Item,
3696
- {
3697
- id: itemId,
3698
- value: opt.value,
3699
- disabled: opt.disabled,
3700
- className: [
3701
- DOT_SIZE[size],
3702
- "mt-0.5 flex-shrink-0 rounded-full border bg-surface transition-colors duration-150",
3703
- "border-border-strong",
3704
- "hover:border-accent",
3705
- "data-[state=checked]:border-accent",
3706
- "focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring",
3707
- "disabled:cursor-not-allowed disabled:opacity-50"
3708
- ].join(" "),
3709
- children: /* @__PURE__ */ jsxRuntime.jsx(RadioGroupPrimitive__namespace.Indicator, { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block h-1/2 w-1/2 rounded-full bg-accent" }) })
3710
- }
3711
- ),
3712
- /* @__PURE__ */ jsxRuntime.jsxs(
3713
- "label",
3714
- {
3715
- htmlFor: itemId,
3716
- className: [
3717
- "select-none",
3718
- opt.disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer"
3719
- ].join(" "),
3720
- children: [
3721
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `block ${TEXT_SIZE[size]} text-foreground`, children: opt.label }),
3722
- opt.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs text-foreground-secondary mt-0.5", children: opt.description })
3723
- ]
3724
- }
3725
- )
3726
- ] }, opt.value);
3836
+ const dot = /* @__PURE__ */ jsxRuntime.jsx(
3837
+ RadioGroupPrimitive__namespace.Item,
3838
+ {
3839
+ id: itemId,
3840
+ value: opt.value,
3841
+ disabled: opt.disabled,
3842
+ className: [
3843
+ DOT_SIZE[size],
3844
+ "mt-0.5 flex-shrink-0 rounded-full border bg-surface transition-colors duration-150",
3845
+ "border-border-strong",
3846
+ "hover:border-accent",
3847
+ "data-[state=checked]:border-accent",
3848
+ // Border-only focus, consistent with the fields.
3849
+ "focus:outline-none focus-visible:border-accent",
3850
+ "disabled:cursor-not-allowed disabled:opacity-50"
3851
+ ].join(" "),
3852
+ children: /* @__PURE__ */ jsxRuntime.jsx(RadioGroupPrimitive__namespace.Indicator, { className: "flex h-full w-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block h-1/2 w-1/2 rounded-full bg-accent" }) })
3853
+ }
3854
+ );
3855
+ const labelEl = /* @__PURE__ */ jsxRuntime.jsxs(
3856
+ "label",
3857
+ {
3858
+ htmlFor: itemId,
3859
+ className: [
3860
+ "select-none",
3861
+ opt.disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
3862
+ labelFirst ? "text-right" : ""
3863
+ ].filter(Boolean).join(" "),
3864
+ children: [
3865
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: `block ${TEXT_SIZE[size]} text-foreground`, children: opt.label }),
3866
+ opt.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block text-xs text-foreground-secondary mt-0.5", children: opt.description })
3867
+ ]
3868
+ }
3869
+ );
3870
+ const rowClass = labelFirst && layout === "vertical" ? "grid grid-cols-[1fr_auto] items-start gap-2.5" : "flex items-start gap-2.5";
3871
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: rowClass, children: labelFirst ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3872
+ labelEl,
3873
+ dot
3874
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3875
+ dot,
3876
+ labelEl
3877
+ ] }) }, opt.value);
3727
3878
  })
3728
3879
  }
3729
3880
  )
@@ -3731,28 +3882,73 @@ function RadioGroup({
3731
3882
  );
3732
3883
  }
3733
3884
  function Switch({
3734
- checked = false,
3885
+ checked,
3886
+ defaultChecked = false,
3735
3887
  onChange,
3736
3888
  checkedIcon,
3737
- uncheckedIcon
3889
+ uncheckedIcon,
3890
+ label,
3891
+ layout = "horizontal",
3892
+ helperText,
3893
+ offLabel,
3894
+ onLabel,
3895
+ name,
3896
+ required,
3897
+ disabled,
3898
+ errorMessage
3738
3899
  }) {
3739
3900
  const id = React8.useId();
3740
- return /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: "flex items-center cursor-pointer select-none", children: /* @__PURE__ */ jsxRuntime.jsx(
3741
- SwitchPrimitive__namespace.Root,
3901
+ const errorId = React8.useId();
3902
+ const hasError = errorMessage != null;
3903
+ const isControlled = checked !== void 0;
3904
+ const [internal, setInternal] = React8.useState(defaultChecked);
3905
+ const isOn = isControlled ? checked : internal;
3906
+ const handle = (c) => {
3907
+ if (!isControlled) setInternal(c);
3908
+ onChange?.({ target: { checked: c, name } });
3909
+ };
3910
+ const stateLabel = (active) => [
3911
+ "text-sm select-none transition-colors",
3912
+ active ? "text-foreground font-medium" : "text-foreground-muted",
3913
+ disabled ? "opacity-50" : "cursor-pointer"
3914
+ ].filter(Boolean).join(" ");
3915
+ return /* @__PURE__ */ jsxRuntime.jsx(
3916
+ Field,
3742
3917
  {
3743
- id,
3744
- checked,
3745
- onCheckedChange: (c) => onChange?.({ target: { checked: c } }),
3746
- 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",
3747
- children: /* @__PURE__ */ jsxRuntime.jsx(
3748
- SwitchPrimitive__namespace.Thumb,
3749
- {
3750
- 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]",
3751
- children: checkedIcon && uncheckedIcon ? checked ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-3 h-3", children: checkedIcon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-3 h-3", children: uncheckedIcon }) : null
3752
- }
3753
- )
3918
+ label,
3919
+ htmlFor: id,
3920
+ errorId,
3921
+ errorMessage,
3922
+ layout,
3923
+ required,
3924
+ helperText,
3925
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
3926
+ offLabel != null && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: stateLabel(!isOn), children: offLabel }),
3927
+ /* @__PURE__ */ jsxRuntime.jsx(
3928
+ SwitchPrimitive__namespace.Root,
3929
+ {
3930
+ id,
3931
+ name,
3932
+ checked: isOn,
3933
+ onCheckedChange: handle,
3934
+ disabled,
3935
+ required,
3936
+ "aria-invalid": hasError || void 0,
3937
+ "aria-describedby": hasError ? errorId : void 0,
3938
+ 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",
3939
+ children: /* @__PURE__ */ jsxRuntime.jsx(
3940
+ SwitchPrimitive__namespace.Thumb,
3941
+ {
3942
+ 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]",
3943
+ children: checkedIcon && uncheckedIcon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-3 h-3", children: isOn ? checkedIcon : uncheckedIcon }) : null
3944
+ }
3945
+ )
3946
+ }
3947
+ ),
3948
+ onLabel != null && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: id, className: stateLabel(isOn), children: onLabel })
3949
+ ] })
3754
3950
  }
3755
- ) }) });
3951
+ );
3756
3952
  }
3757
3953
  function AutoComplete({
3758
3954
  disabled,
@@ -3771,6 +3967,7 @@ function AutoComplete({
3771
3967
  size = "md",
3772
3968
  icon,
3773
3969
  errorMessage,
3970
+ helperText,
3774
3971
  required,
3775
3972
  htmlFor
3776
3973
  }) {
@@ -3829,6 +4026,7 @@ function AutoComplete({
3829
4026
  htmlFor,
3830
4027
  errorId,
3831
4028
  errorMessage,
4029
+ helperText,
3832
4030
  layout,
3833
4031
  required,
3834
4032
  children: /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
@@ -3928,6 +4126,8 @@ function TreeSelect({
3928
4126
  onChange,
3929
4127
  disabled,
3930
4128
  layout = "horizontal",
4129
+ helperText,
4130
+ required,
3931
4131
  errorMessage,
3932
4132
  style,
3933
4133
  htmlFor,
@@ -4013,12 +4213,14 @@ function TreeSelect({
4013
4213
  };
4014
4214
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
4015
4215
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex ${layout === "vertical" ? "flex-col gap-1" : "flex-row items-center gap-2"}`, children: [
4016
- label && /* @__PURE__ */ jsxRuntime.jsx(
4017
- "label",
4216
+ /* @__PURE__ */ jsxRuntime.jsx(
4217
+ FieldLabel,
4018
4218
  {
4019
- className: "text-sm font-medium ml-1 max-content select-none text-foreground",
4219
+ label,
4020
4220
  htmlFor,
4021
- children: label
4221
+ required,
4222
+ helperText,
4223
+ horizontal: layout === "horizontal"
4022
4224
  }
4023
4225
  ),
4024
4226
  /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
@@ -4180,6 +4382,7 @@ function FileInput({
4180
4382
  hint,
4181
4383
  maxSize,
4182
4384
  errorMessage,
4385
+ helperText,
4183
4386
  disabled,
4184
4387
  required,
4185
4388
  icon
@@ -4226,6 +4429,7 @@ function FileInput({
4226
4429
  htmlFor,
4227
4430
  errorId,
4228
4431
  errorMessage: effectiveError,
4432
+ helperText,
4229
4433
  required,
4230
4434
  children: [
4231
4435
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -4364,6 +4568,8 @@ function DatePicker({
4364
4568
  htmlFor,
4365
4569
  name: _name,
4366
4570
  layout = "horizontal",
4571
+ helperText,
4572
+ required,
4367
4573
  disabled,
4368
4574
  errorMessage,
4369
4575
  min,
@@ -4454,13 +4660,15 @@ function DatePicker({
4454
4660
  };
4455
4661
  const displayValue = value ? format(value) : "";
4456
4662
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
4457
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex ${layout === "vertical" ? "flex-col gap-1" : "flex-row items-center gap-2"}`, children: [
4458
- label && /* @__PURE__ */ jsxRuntime.jsx(
4459
- "label",
4663
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex ${layout === "vertical" ? "flex-col gap-1.5" : "flex-row items-start gap-3"}`, children: [
4664
+ /* @__PURE__ */ jsxRuntime.jsx(
4665
+ FieldLabel,
4460
4666
  {
4461
- className: "text-sm font-medium ml-1 max-content select-none text-foreground",
4667
+ label,
4462
4668
  htmlFor,
4463
- children: label
4669
+ required,
4670
+ helperText,
4671
+ horizontal: layout === "horizontal"
4464
4672
  }
4465
4673
  ),
4466
4674
  /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
@@ -4679,6 +4887,7 @@ function TextArea({
4679
4887
  showCount = false,
4680
4888
  resize,
4681
4889
  errorMessage,
4890
+ helperText,
4682
4891
  required,
4683
4892
  style,
4684
4893
  inputStyle
@@ -4704,6 +4913,7 @@ function TextArea({
4704
4913
  htmlFor,
4705
4914
  errorId,
4706
4915
  errorMessage,
4916
+ helperText,
4707
4917
  layout,
4708
4918
  required,
4709
4919
  children: [
@@ -4744,51 +4954,84 @@ function SegmentedControl({
4744
4954
  size = "md",
4745
4955
  fullWidth = false,
4746
4956
  disabled,
4957
+ label,
4958
+ layout = "vertical",
4959
+ helperText,
4960
+ name,
4961
+ required,
4962
+ errorMessage,
4747
4963
  "aria-label": ariaLabel
4748
4964
  }) {
4749
4965
  const sz = SIZE[size];
4750
- return /* @__PURE__ */ jsxRuntime.jsx(
4751
- ToggleGroup__namespace.Root,
4966
+ const groupId = React8.useId();
4967
+ const errorId = React8.useId();
4968
+ const hasError = errorMessage != null;
4969
+ const isControlled = value !== void 0;
4970
+ const [internal, setInternal] = React8.useState(defaultValue);
4971
+ const current = isControlled ? value : internal;
4972
+ const handle = (v) => {
4973
+ if (!v) return;
4974
+ if (!isControlled) setInternal(v);
4975
+ onChange?.(v);
4976
+ };
4977
+ return /* @__PURE__ */ jsxRuntime.jsxs(
4978
+ Field,
4752
4979
  {
4753
- type: "single",
4754
- value,
4755
- defaultValue,
4756
- onValueChange: (v) => {
4757
- if (v) onChange?.(v);
4758
- },
4759
- disabled,
4760
- "aria-label": ariaLabel,
4761
- className: [
4762
- "inline-flex items-center gap-1 rounded-lg border border-border bg-surface-raised p-1",
4763
- sz.h,
4764
- fullWidth ? "flex w-full" : "",
4765
- disabled ? "opacity-60 cursor-not-allowed" : ""
4766
- ].filter(Boolean).join(" "),
4767
- children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
4768
- ToggleGroup__namespace.Item,
4769
- {
4770
- value: opt.value,
4771
- disabled: opt.disabled,
4772
- className: [
4773
- "inline-flex items-center justify-center gap-1.5 rounded-md select-none whitespace-nowrap",
4774
- "transition-colors duration-150 h-full",
4775
- sz.text,
4776
- sz.pad,
4777
- fullWidth ? "flex-1" : "",
4778
- // Resting: muted text, transparent. Hover lifts the text.
4779
- "text-foreground-secondary hover:text-foreground",
4780
- // Active: surface-white pill + accent text + subtle shadow.
4781
- "data-[state=on]:bg-surface data-[state=on]:text-accent data-[state=on]:shadow-sm",
4782
- "focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring",
4783
- "disabled:opacity-40 disabled:cursor-not-allowed"
4784
- ].filter(Boolean).join(" "),
4785
- children: [
4786
- opt.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: opt.icon }),
4787
- opt.label
4788
- ]
4789
- },
4790
- opt.value
4791
- ))
4980
+ label,
4981
+ htmlFor: groupId,
4982
+ errorId,
4983
+ errorMessage,
4984
+ layout,
4985
+ required,
4986
+ helperText,
4987
+ children: [
4988
+ name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: current ?? "" }),
4989
+ /* @__PURE__ */ jsxRuntime.jsx(
4990
+ ToggleGroup__namespace.Root,
4991
+ {
4992
+ id: groupId,
4993
+ type: "single",
4994
+ value: current,
4995
+ onValueChange: handle,
4996
+ disabled,
4997
+ "aria-label": ariaLabel ?? (typeof label === "string" ? label : void 0),
4998
+ "aria-invalid": hasError || void 0,
4999
+ "aria-describedby": hasError ? errorId : void 0,
5000
+ className: [
5001
+ "inline-flex items-center gap-1 rounded-lg border bg-surface-raised p-1",
5002
+ hasError ? "border-status-error" : "border-border",
5003
+ sz.h,
5004
+ fullWidth ? "flex w-full" : "w-fit",
5005
+ disabled ? "opacity-60 cursor-not-allowed" : ""
5006
+ ].filter(Boolean).join(" "),
5007
+ children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
5008
+ ToggleGroup__namespace.Item,
5009
+ {
5010
+ value: opt.value,
5011
+ disabled: opt.disabled,
5012
+ className: [
5013
+ "inline-flex items-center justify-center gap-1.5 rounded-md select-none whitespace-nowrap",
5014
+ "transition-colors duration-150 h-full",
5015
+ sz.text,
5016
+ sz.pad,
5017
+ fullWidth ? "flex-1" : "",
5018
+ // Resting: muted text, transparent. Hover lifts the text.
5019
+ "text-foreground-secondary hover:text-foreground",
5020
+ // Active: surface-white pill + accent text + subtle shadow.
5021
+ "data-[state=on]:bg-surface data-[state=on]:text-accent data-[state=on]:shadow-sm",
5022
+ "focus:outline-none focus-visible:ring-[3px] focus-visible:ring-focus-ring",
5023
+ "disabled:opacity-40 disabled:cursor-not-allowed"
5024
+ ].filter(Boolean).join(" "),
5025
+ children: [
5026
+ opt.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0", children: opt.icon }),
5027
+ opt.label
5028
+ ]
5029
+ },
5030
+ opt.value
5031
+ ))
5032
+ }
5033
+ )
5034
+ ]
4792
5035
  }
4793
5036
  );
4794
5037
  }
@@ -4811,6 +5054,8 @@ function Slider({
4811
5054
  size = "md",
4812
5055
  disabled,
4813
5056
  errorMessage,
5057
+ helperText,
5058
+ required,
4814
5059
  name,
4815
5060
  htmlFor
4816
5061
  }) {
@@ -4830,7 +5075,13 @@ function Slider({
4830
5075
  const valueText = current.map(formatValue).join(" \u2013 ");
4831
5076
  return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label: void 0, errorId, errorMessage, children: [
4832
5077
  (label || showValue) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
4833
- label && /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor, className: "text-sm font-medium text-foreground select-none", children: label }),
5078
+ label && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1", children: [
5079
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor, className: "text-sm font-medium text-foreground select-none", children: [
5080
+ label,
5081
+ required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-status-error ml-0.5", "aria-hidden": "true", children: "*" })
5082
+ ] }),
5083
+ helperText != null && /* @__PURE__ */ jsxRuntime.jsx(FieldHelpIcon, { text: helperText })
5084
+ ] }),
4834
5085
  showValue && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-foreground-secondary tabular-nums", children: valueText })
4835
5086
  ] }),
4836
5087
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -4902,6 +5153,7 @@ function TagsInput({
4902
5153
  size = "md",
4903
5154
  disabled,
4904
5155
  errorMessage,
5156
+ helperText,
4905
5157
  required,
4906
5158
  maxTags,
4907
5159
  dedupe = true,
@@ -4969,6 +5221,7 @@ function TagsInput({
4969
5221
  htmlFor,
4970
5222
  errorId,
4971
5223
  errorMessage: errorText,
5224
+ helperText,
4972
5225
  layout,
4973
5226
  required,
4974
5227
  children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -5036,6 +5289,8 @@ function OtpInput({
5036
5289
  disabled,
5037
5290
  errorMessage,
5038
5291
  required,
5292
+ layout = "vertical",
5293
+ helperText,
5039
5294
  groupAfter
5040
5295
  }) {
5041
5296
  const errorId = React8.useId();
@@ -5089,7 +5344,7 @@ function OtpInput({
5089
5344
  emit(valid.join(""));
5090
5345
  focusBox(valid.length);
5091
5346
  };
5092
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, errorId, errorMessage, required, children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs(React8__default.default.Fragment, { children: [
5347
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, errorId, errorMessage, required, layout, helperText, children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs(React8__default.default.Fragment, { children: [
5093
5348
  /* @__PURE__ */ jsxRuntime.jsx(
5094
5349
  "input",
5095
5350
  {
@@ -5114,10 +5369,11 @@ function OtpInput({
5114
5369
  className: [
5115
5370
  BOX_SIZE[size],
5116
5371
  "text-center font-medium rounded-lg border bg-surface text-foreground",
5117
- "transition-[border-color,box-shadow] duration-150",
5372
+ "transition-[border-color] duration-150",
5118
5373
  hasError ? "border-status-error" : "border-border",
5119
5374
  "hover:border-border-strong",
5120
- "focus:outline-none focus:border-accent focus:ring-[3px] focus:ring-focus-ring",
5375
+ // Border-only focus, consistent with every field (no clip-prone ring).
5376
+ "focus:outline-none focus:border-accent",
5121
5377
  "disabled:bg-surface-raised disabled:text-foreground-muted disabled:cursor-not-allowed"
5122
5378
  ].join(" ")
5123
5379
  }
@@ -5140,7 +5396,10 @@ function Rating({
5140
5396
  disabled,
5141
5397
  icon = Star,
5142
5398
  errorMessage,
5143
- name
5399
+ name,
5400
+ layout = "vertical",
5401
+ helperText,
5402
+ required
5144
5403
  }) {
5145
5404
  const errorId = React8.useId();
5146
5405
  const [internal, setInternal] = React8.useState(defaultValue);
@@ -5170,7 +5429,7 @@ function Rating({
5170
5429
  commit(count);
5171
5430
  }
5172
5431
  };
5173
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, errorId, errorMessage, children: /* @__PURE__ */ jsxRuntime.jsxs(
5432
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, errorId, errorMessage, layout, required, helperText, children: /* @__PURE__ */ jsxRuntime.jsxs(
5174
5433
  "div",
5175
5434
  {
5176
5435
  role: interactive ? "slider" : "img",
@@ -5262,6 +5521,7 @@ function TimePicker({
5262
5521
  minuteStep = 1,
5263
5522
  disabled,
5264
5523
  errorMessage,
5524
+ helperText,
5265
5525
  required,
5266
5526
  style
5267
5527
  }) {
@@ -5294,7 +5554,7 @@ function TimePicker({
5294
5554
  },
5295
5555
  n
5296
5556
  )) });
5297
- return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label, htmlFor, errorId, errorMessage, layout, required, children: [
5557
+ return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5298
5558
  /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
5299
5559
  /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
5300
5560
  "button",
@@ -5386,6 +5646,7 @@ function DateRangePicker({
5386
5646
  format = defaultFmt,
5387
5647
  disabled,
5388
5648
  errorMessage,
5649
+ helperText,
5389
5650
  required,
5390
5651
  style
5391
5652
  }) {
@@ -5458,7 +5719,7 @@ function DateRangePicker({
5458
5719
  ] })
5459
5720
  ] });
5460
5721
  };
5461
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, errorId, errorMessage, layout, required, children: /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => {
5722
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => {
5462
5723
  if (!disabled) {
5463
5724
  setOpen(o);
5464
5725
  if (!o) {
@@ -5566,6 +5827,7 @@ function ColorPicker({
5566
5827
  allowCustom = true,
5567
5828
  disabled,
5568
5829
  errorMessage,
5830
+ helperText,
5569
5831
  required,
5570
5832
  placeholder = "Pick a colour\u2026"
5571
5833
  }) {
@@ -5583,7 +5845,7 @@ function ColorPicker({
5583
5845
  setDraft(hex);
5584
5846
  if (HEX_RE.test(hex)) onChange?.(hex);
5585
5847
  };
5586
- return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label, htmlFor, errorId, errorMessage, layout, required, children: [
5848
+ return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5587
5849
  /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
5588
5850
  /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
5589
5851
  "button",