@geomak/ui 5.7.2 → 5.9.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
@@ -607,7 +607,9 @@ function IconButton({
607
607
  disabled = false,
608
608
  size = "lg",
609
609
  loading = false,
610
- loadingIcon
610
+ loadingIcon,
611
+ className = "",
612
+ style
611
613
  }) {
612
614
  const colorScheme = useMemo(() => {
613
615
  if (type === "primary") {
@@ -624,7 +626,8 @@ function IconButton({
624
626
  type: buttonType,
625
627
  disabled: disabled || loading,
626
628
  onClick,
627
- className: `${size === "sm" ? "p-1" : "p-2"} rounded-lg shadow-md transition-colors duration-150 ${colorScheme} disabled:bg-surface-raised disabled:text-foreground-muted disabled:cursor-not-allowed focus:outline-none focus-visible:ring-2 focus-visible:ring-accent`,
629
+ style,
630
+ className: `${size === "sm" ? "p-1" : "p-2"} rounded-lg shadow-md transition-colors duration-150 ${colorScheme} disabled:bg-surface-raised disabled:text-foreground-muted disabled:cursor-not-allowed focus:outline-none focus-visible:ring-2 focus-visible:ring-accent ${className}`.trim(),
628
631
  children: loading ? loadingIcon : icon
629
632
  }
630
633
  );
@@ -675,7 +678,8 @@ function Button({
675
678
  disabled,
676
679
  style,
677
680
  icon,
678
- onClick
681
+ onClick,
682
+ className = ""
679
683
  }) {
680
684
  return /* @__PURE__ */ jsxs(
681
685
  "button",
@@ -690,8 +694,9 @@ function Button({
690
694
  "outline-none transition-colors duration-150 select-none",
691
695
  "whitespace-nowrap",
692
696
  SIZE_CLASSES[size],
693
- VARIANT_CLASSES[variant]
694
- ].join(" "),
697
+ VARIANT_CLASSES[variant],
698
+ className
699
+ ].filter(Boolean).join(" "),
695
700
  children: [
696
701
  loading ? /* @__PURE__ */ jsx(
697
702
  "svg",
@@ -726,7 +731,8 @@ function Modal({
726
731
  cancelText = "Cancel",
727
732
  hasFooter = true,
728
733
  title,
729
- children
734
+ children,
735
+ className = ""
730
736
  }) {
731
737
  const reduced = useReducedMotion();
732
738
  const maxWidth = width ?? size?.[0] ?? 600;
@@ -746,7 +752,7 @@ function Modal({
746
752
  /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(Dialog.Content, { asChild: true, children: /* @__PURE__ */ jsxs(
747
753
  motion.div,
748
754
  {
749
- className: "fixed left-1/2 top-1/2 z-modal flex flex-col w-[calc(100%-2rem)] max-h-[90dvh] bg-surface rounded-2xl shadow-xl overflow-hidden focus:outline-none",
755
+ className: `fixed left-1/2 top-1/2 z-modal flex flex-col w-[calc(100%-2rem)] max-h-[90dvh] bg-surface rounded-2xl shadow-xl overflow-hidden focus:outline-none ${className}`.trim(),
750
756
  style: {
751
757
  maxWidth,
752
758
  x: "-50%",
@@ -808,7 +814,8 @@ function Drawer({
808
814
  onOk,
809
815
  onCancel,
810
816
  title,
811
- children
817
+ children,
818
+ className = ""
812
819
  }) {
813
820
  const reduced = useReducedMotion();
814
821
  const isRight = placement === "right";
@@ -829,7 +836,7 @@ function Drawer({
829
836
  /* @__PURE__ */ jsx(AnimatePresence, { children: isOpen && /* @__PURE__ */ jsx(Dialog.Content, { asChild: true, children: /* @__PURE__ */ jsxs(
830
837
  motion.div,
831
838
  {
832
- className: `fixed top-0 bottom-0 ${isRight ? "right-0" : "left-0"} z-modal flex flex-col bg-surface shadow-xl focus:outline-none`,
839
+ className: `fixed top-0 bottom-0 ${isRight ? "right-0" : "left-0"} z-modal flex flex-col bg-surface shadow-xl focus:outline-none ${className}`.trim(),
833
840
  style: { width: `min(calc(100vw - 1rem), ${width}px)` },
834
841
  initial: { x: reduced ? 0 : hiddenX, opacity: reduced ? 0 : 1 },
835
842
  animate: { x: 0, opacity: 1 },
@@ -1496,9 +1503,11 @@ function List2({
1496
1503
  items,
1497
1504
  onItemClick,
1498
1505
  activeKey,
1499
- density = "comfortable"
1506
+ density = "comfortable",
1507
+ className = "",
1508
+ style
1500
1509
  }) {
1501
- return /* @__PURE__ */ jsx("div", { role: "listbox", className: "flex flex-col", children: items.map((item) => {
1510
+ return /* @__PURE__ */ jsx("div", { role: "listbox", className: `flex flex-col ${className}`.trim(), style, children: items.map((item) => {
1502
1511
  const isActive = activeKey === item.key;
1503
1512
  const isDisabled = !!item.disabled;
1504
1513
  return /* @__PURE__ */ jsxs(
@@ -1620,8 +1629,8 @@ function CollapseIcon() {
1620
1629
  function ExpandIcon() {
1621
1630
  return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 8V4h4M20 8V4h-4M4 16v4h4M20 16v4h-4" }) });
1622
1631
  }
1623
- function GridCard({ item, buttonText = "Open Application", onOpen }) {
1624
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col w-[200px] h-[250px] rounded-lg bg-ice dark:bg-independence items-center justify-between p-2 shadow-2xl", children: [
1632
+ function GridCard({ item, buttonText = "Open Application", onOpen, className = "", style }) {
1633
+ return /* @__PURE__ */ jsxs("div", { className: `flex flex-col w-[200px] h-[250px] rounded-lg bg-ice dark:bg-independence items-center justify-between p-2 shadow-2xl ${className}`.trim(), style, children: [
1625
1634
  /* @__PURE__ */ jsx("div", { className: "text-prussian-blue dark:text-white text-lg font-bold text-center h-1/4", children: /* @__PURE__ */ jsx("h2", { children: item.title }) }),
1626
1635
  /* @__PURE__ */ jsx("div", { className: "h-1/4 flex items-center justify-center", children: typeof item.cover === "string" ? /* @__PURE__ */ jsx("img", { src: item.cover, alt: "Grid Card Cover" }) : item.cover }),
1627
1636
  /* @__PURE__ */ jsx("div", { className: "text-prussian-blue text-sm dark:text-white text-center h-1/4", children: /* @__PURE__ */ jsx("p", { children: item.description }) }),
@@ -2240,8 +2249,8 @@ function Field({
2240
2249
  );
2241
2250
  }
2242
2251
  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" }) });
2243
- var SearchInput = React8.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText }, ref) {
2244
- return /* @__PURE__ */ jsx(Field, { label, htmlFor, layout, helperText, children: /* @__PURE__ */ jsxs(
2252
+ var SearchInput = React8.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText, className }, ref) {
2253
+ return /* @__PURE__ */ jsx(Field, { className, label, htmlFor, layout, helperText, children: /* @__PURE__ */ jsxs(
2245
2254
  "div",
2246
2255
  {
2247
2256
  className: `flex items-center ${fieldShell({ size, disabled, focusWithin: true })}`,
@@ -2389,7 +2398,8 @@ function Dropdown({
2389
2398
  items = [],
2390
2399
  labelStyle = {},
2391
2400
  placeholder,
2392
- size = "md"
2401
+ size = "md",
2402
+ className = ""
2393
2403
  }) {
2394
2404
  const [open, setOpen] = useState(false);
2395
2405
  const [selectedItems, setSelectedItems] = useState([]);
@@ -2437,7 +2447,7 @@ function Dropdown({
2437
2447
  );
2438
2448
  };
2439
2449
  const isSelected = (key) => Array.isArray(value) ? value.includes(key) : value === key;
2440
- return /* @__PURE__ */ jsxs("div", { children: [
2450
+ return /* @__PURE__ */ jsxs("div", { className: className || void 0, children: [
2441
2451
  /* @__PURE__ */ jsxs(
2442
2452
  "div",
2443
2453
  {
@@ -2570,15 +2580,7 @@ function Dropdown({
2570
2580
  hasError && /* @__PURE__ */ jsx("div", { id: errorId, className: "text-status-error text-xs mt-1", children: errorMessage })
2571
2581
  ] });
2572
2582
  }
2573
- var SHIMMER = [
2574
- "relative overflow-hidden rounded-sm bg-surface-raised",
2575
- 'before:absolute before:inset-0 before:content-[""]',
2576
- "before:bg-gradient-to-r before:from-transparent before:via-white/30 before:to-transparent",
2577
- "before:animate-[shimmer_1.6s_linear_infinite]",
2578
- // Respect prefers-reduced-motion — the resting bg-surface-raised is still
2579
- // a perfectly legible placeholder for users who have animations off.
2580
- "motion-reduce:before:hidden"
2581
- ].join(" ");
2583
+ var SHIMMER = "oxy-skeleton rounded-sm bg-surface-raised";
2582
2584
  function SkeletonBox({ width, height = 16, radius, className = "", style }) {
2583
2585
  return /* @__PURE__ */ jsx(
2584
2586
  "span",
@@ -2853,7 +2855,9 @@ function Table({
2853
2855
  footer = null,
2854
2856
  header = null,
2855
2857
  loading = false,
2856
- loadingRowCount = 8
2858
+ loadingRowCount = 8,
2859
+ className = "",
2860
+ style
2857
2861
  }) {
2858
2862
  const searchRef = useRef(null);
2859
2863
  const [searchTerm, setSearchTerm] = useState("");
@@ -2913,7 +2917,7 @@ function Table({
2913
2917
  }
2914
2918
  setActivePage(newPage);
2915
2919
  };
2916
- return /* @__PURE__ */ jsxs("div", { className: "w-full h-max rounded-lg", children: [
2920
+ return /* @__PURE__ */ jsxs("div", { className: `w-full h-max rounded-lg ${className}`.trim(), style, children: [
2917
2921
  /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
2918
2922
  hasSearch && /* @__PURE__ */ jsx(
2919
2923
  SearchInput_default,
@@ -3090,7 +3094,8 @@ function Sidebar({
3090
3094
  onToggle,
3091
3095
  expandedWidth = 220,
3092
3096
  collapsedWidth = 52,
3093
- footer
3097
+ footer,
3098
+ className = ""
3094
3099
  }) {
3095
3100
  return /* @__PURE__ */ jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxs(
3096
3101
  motion.aside,
@@ -3098,7 +3103,7 @@ function Sidebar({
3098
3103
  initial: false,
3099
3104
  animate: { width: isExpanded ? expandedWidth : collapsedWidth },
3100
3105
  transition: { type: "tween", duration: 0.22, ease: [0.16, 1, 0.3, 1] },
3101
- className: "relative flex h-full flex-col border-r border-border bg-surface overflow-hidden flex-shrink-0",
3106
+ className: `relative flex h-full flex-col border-r border-border bg-surface overflow-hidden flex-shrink-0 ${className}`.trim(),
3102
3107
  children: [
3103
3108
  /* @__PURE__ */ jsxs("div", { className: [
3104
3109
  "flex h-14 flex-shrink-0 items-center border-b border-border",
@@ -3424,6 +3429,7 @@ function TextInput({
3424
3429
  onBlur,
3425
3430
  errorMessage,
3426
3431
  helperText,
3432
+ className,
3427
3433
  required,
3428
3434
  prefix,
3429
3435
  suffix
@@ -3452,6 +3458,7 @@ function TextInput({
3452
3458
  return /* @__PURE__ */ jsx(
3453
3459
  Field,
3454
3460
  {
3461
+ className,
3455
3462
  label,
3456
3463
  htmlFor,
3457
3464
  errorId,
@@ -3486,6 +3493,7 @@ function NumberInput({
3486
3493
  size = "md",
3487
3494
  errorMessage,
3488
3495
  helperText,
3496
+ className,
3489
3497
  required,
3490
3498
  inputStyle,
3491
3499
  labelStyle,
@@ -3530,6 +3538,7 @@ function NumberInput({
3530
3538
  return /* @__PURE__ */ jsx(
3531
3539
  Field,
3532
3540
  {
3541
+ className,
3533
3542
  label,
3534
3543
  htmlFor,
3535
3544
  errorId,
@@ -3621,6 +3630,7 @@ function Password({
3621
3630
  onBlur,
3622
3631
  errorMessage,
3623
3632
  helperText,
3633
+ className,
3624
3634
  required,
3625
3635
  showIcon,
3626
3636
  hideIcon
@@ -3631,6 +3641,7 @@ function Password({
3631
3641
  return /* @__PURE__ */ jsx(
3632
3642
  Field,
3633
3643
  {
3644
+ className,
3634
3645
  label,
3635
3646
  htmlFor,
3636
3647
  errorId,
@@ -3693,7 +3704,8 @@ function Checkbox({
3693
3704
  disabled = false,
3694
3705
  required,
3695
3706
  layout = "horizontal",
3696
- labelPosition = "right"
3707
+ labelPosition = "right",
3708
+ className = ""
3697
3709
  }) {
3698
3710
  const isChecked = checked ?? value ?? false;
3699
3711
  const labelFirst = labelPosition === "left";
@@ -3771,7 +3783,7 @@ function Checkbox({
3771
3783
  ] })
3772
3784
  ] });
3773
3785
  }
3774
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
3786
+ return /* @__PURE__ */ jsxs("div", { className: `flex flex-col gap-1 ${className}`.trim(), children: [
3775
3787
  /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-1", children: [
3776
3788
  content,
3777
3789
  helperText != null && /* @__PURE__ */ jsx(FieldHelpIcon, { text: helperText })
@@ -3802,6 +3814,7 @@ function RadioGroup({
3802
3814
  disabled,
3803
3815
  required,
3804
3816
  helperText,
3817
+ className,
3805
3818
  errorMessage
3806
3819
  }) {
3807
3820
  const errorId = useId();
@@ -3811,6 +3824,7 @@ function RadioGroup({
3811
3824
  return /* @__PURE__ */ jsx(
3812
3825
  Field,
3813
3826
  {
3827
+ className,
3814
3828
  label,
3815
3829
  htmlFor: groupId,
3816
3830
  errorId,
@@ -3896,6 +3910,7 @@ function Switch({
3896
3910
  label,
3897
3911
  layout = "horizontal",
3898
3912
  helperText,
3913
+ className,
3899
3914
  offLabel,
3900
3915
  onLabel,
3901
3916
  name,
@@ -3921,6 +3936,7 @@ function Switch({
3921
3936
  return /* @__PURE__ */ jsx(
3922
3937
  Field,
3923
3938
  {
3939
+ className,
3924
3940
  label,
3925
3941
  htmlFor: id,
3926
3942
  errorId,
@@ -3975,6 +3991,7 @@ function AutoComplete({
3975
3991
  icon,
3976
3992
  errorMessage,
3977
3993
  helperText,
3994
+ className,
3978
3995
  required,
3979
3996
  htmlFor
3980
3997
  }) {
@@ -4029,6 +4046,7 @@ function AutoComplete({
4029
4046
  return /* @__PURE__ */ jsx(
4030
4047
  Field,
4031
4048
  {
4049
+ className,
4032
4050
  label,
4033
4051
  htmlFor,
4034
4052
  errorId,
@@ -4134,6 +4152,7 @@ function TreeSelect({
4134
4152
  disabled,
4135
4153
  layout = "horizontal",
4136
4154
  helperText,
4155
+ className,
4137
4156
  required,
4138
4157
  errorMessage,
4139
4158
  style,
@@ -4221,6 +4240,7 @@ function TreeSelect({
4221
4240
  return /* @__PURE__ */ jsx(
4222
4241
  Field,
4223
4242
  {
4243
+ className,
4224
4244
  label,
4225
4245
  htmlFor,
4226
4246
  errorId,
@@ -4387,6 +4407,7 @@ function FileInput({
4387
4407
  maxSize,
4388
4408
  errorMessage,
4389
4409
  helperText,
4410
+ className,
4390
4411
  disabled,
4391
4412
  required,
4392
4413
  icon
@@ -4429,6 +4450,7 @@ function FileInput({
4429
4450
  return /* @__PURE__ */ jsxs(
4430
4451
  Field,
4431
4452
  {
4453
+ className,
4432
4454
  label,
4433
4455
  htmlFor,
4434
4456
  errorId,
@@ -4892,6 +4914,7 @@ function TextArea({
4892
4914
  resize,
4893
4915
  errorMessage,
4894
4916
  helperText,
4917
+ className,
4895
4918
  required,
4896
4919
  style,
4897
4920
  inputStyle
@@ -4913,6 +4936,7 @@ function TextArea({
4913
4936
  return /* @__PURE__ */ jsxs(
4914
4937
  Field,
4915
4938
  {
4939
+ className,
4916
4940
  label,
4917
4941
  htmlFor,
4918
4942
  errorId,
@@ -4961,6 +4985,7 @@ function SegmentedControl({
4961
4985
  label,
4962
4986
  layout = "vertical",
4963
4987
  helperText,
4988
+ className,
4964
4989
  name,
4965
4990
  required,
4966
4991
  errorMessage,
@@ -4981,6 +5006,7 @@ function SegmentedControl({
4981
5006
  return /* @__PURE__ */ jsxs(
4982
5007
  Field,
4983
5008
  {
5009
+ className,
4984
5010
  label,
4985
5011
  htmlFor: groupId,
4986
5012
  errorId,
@@ -5059,6 +5085,7 @@ function Slider({
5059
5085
  disabled,
5060
5086
  errorMessage,
5061
5087
  helperText,
5088
+ className,
5062
5089
  required,
5063
5090
  name,
5064
5091
  htmlFor
@@ -5077,7 +5104,7 @@ function Slider({
5077
5104
  onChange?.(next);
5078
5105
  };
5079
5106
  const valueText = current.map(formatValue).join(" \u2013 ");
5080
- return /* @__PURE__ */ jsxs(Field, { label: void 0, errorId, errorMessage, children: [
5107
+ return /* @__PURE__ */ jsxs(Field, { className, label: void 0, errorId, errorMessage, children: [
5081
5108
  (label || showValue) && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between mb-2", children: [
5082
5109
  label && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
5083
5110
  /* @__PURE__ */ jsxs("label", { htmlFor, className: "text-sm font-medium text-foreground select-none", children: [
@@ -5158,6 +5185,7 @@ function TagsInput({
5158
5185
  disabled,
5159
5186
  errorMessage,
5160
5187
  helperText,
5188
+ className,
5161
5189
  required,
5162
5190
  maxTags,
5163
5191
  dedupe = true,
@@ -5221,6 +5249,7 @@ function TagsInput({
5221
5249
  return /* @__PURE__ */ jsx(
5222
5250
  Field,
5223
5251
  {
5252
+ className,
5224
5253
  label,
5225
5254
  htmlFor,
5226
5255
  errorId,
@@ -5295,6 +5324,7 @@ function OtpInput({
5295
5324
  required,
5296
5325
  layout = "vertical",
5297
5326
  helperText,
5327
+ className,
5298
5328
  groupAfter
5299
5329
  }) {
5300
5330
  const errorId = useId();
@@ -5348,7 +5378,7 @@ function OtpInput({
5348
5378
  emit(valid.join(""));
5349
5379
  focusBox(valid.length);
5350
5380
  };
5351
- 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: [
5381
+ return /* @__PURE__ */ jsx(Field, { className, 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: [
5352
5382
  /* @__PURE__ */ jsx(
5353
5383
  "input",
5354
5384
  {
@@ -5403,6 +5433,7 @@ function Rating({
5403
5433
  name,
5404
5434
  layout = "vertical",
5405
5435
  helperText,
5436
+ className,
5406
5437
  required
5407
5438
  }) {
5408
5439
  const errorId = useId();
@@ -5433,7 +5464,7 @@ function Rating({
5433
5464
  commit(count);
5434
5465
  }
5435
5466
  };
5436
- return /* @__PURE__ */ jsx(Field, { label, errorId, errorMessage, layout, required, helperText, children: /* @__PURE__ */ jsxs(
5467
+ return /* @__PURE__ */ jsx(Field, { className, label, errorId, errorMessage, layout, required, helperText, children: /* @__PURE__ */ jsxs(
5437
5468
  "div",
5438
5469
  {
5439
5470
  role: interactive ? "slider" : "img",
@@ -5526,6 +5557,7 @@ function TimePicker({
5526
5557
  disabled,
5527
5558
  errorMessage,
5528
5559
  helperText,
5560
+ className,
5529
5561
  required,
5530
5562
  style
5531
5563
  }) {
@@ -5558,7 +5590,7 @@ function TimePicker({
5558
5590
  },
5559
5591
  n
5560
5592
  )) });
5561
- return /* @__PURE__ */ jsxs(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5593
+ return /* @__PURE__ */ jsxs(Field, { className, label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5562
5594
  /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
5563
5595
  /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
5564
5596
  "button",
@@ -5651,6 +5683,7 @@ function DateRangePicker({
5651
5683
  disabled,
5652
5684
  errorMessage,
5653
5685
  helperText,
5686
+ className,
5654
5687
  required,
5655
5688
  style
5656
5689
  }) {
@@ -5723,7 +5756,7 @@ function DateRangePicker({
5723
5756
  ] })
5724
5757
  ] });
5725
5758
  };
5726
- return /* @__PURE__ */ jsx(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => {
5759
+ return /* @__PURE__ */ jsx(Field, { className, label, htmlFor, errorId, errorMessage, helperText, layout, required, children: /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => {
5727
5760
  if (!disabled) {
5728
5761
  setOpen(o);
5729
5762
  if (!o) {
@@ -5832,6 +5865,7 @@ function ColorPicker({
5832
5865
  disabled,
5833
5866
  errorMessage,
5834
5867
  helperText,
5868
+ className,
5835
5869
  required,
5836
5870
  placeholder = "Pick a colour\u2026"
5837
5871
  }) {
@@ -5849,7 +5883,7 @@ function ColorPicker({
5849
5883
  setDraft(hex);
5850
5884
  if (HEX_RE.test(hex)) onChange?.(hex);
5851
5885
  };
5852
- return /* @__PURE__ */ jsxs(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5886
+ return /* @__PURE__ */ jsxs(Field, { className, label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5853
5887
  /* @__PURE__ */ jsxs(Popover.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
5854
5888
  /* @__PURE__ */ jsx(Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
5855
5889
  "button",
@@ -6246,7 +6280,7 @@ function useForm(options = {}) {
6246
6280
  isValid: store.isValid,
6247
6281
  getValue: store.getValue,
6248
6282
  getValues: store.getValues,
6249
- setValue: (name, value) => store.setValue(name, value),
6283
+ setValue: (name, value, opts) => store.setValue(name, value, opts),
6250
6284
  setValues: (patch) => store.setValues(patch),
6251
6285
  setError: store.setError,
6252
6286
  validateField: (name) => store.validateField(name),
@@ -6356,6 +6390,208 @@ function useFieldArray(name) {
6356
6390
  };
6357
6391
  }
6358
6392
 
6359
- export { AppShell, AutoComplete, Avatar, Box, Button, Catalog, CatalogCarousel, CatalogGrid, Checkbox, ColorPicker, ContextMenu, DateRangePicker, Drawer, Dropdown, FadingBase, Field, FieldHelpIcon, FieldLabel, FileInput, Flex, Form, FormContext, FormField, FormStore, Grid2 as Grid, GridCard, icons_default as Icon, IconButton, List2 as List, LoadingSpinner, Modal, NotificationProvider, NumberInput, OpaqueGridCard, OtpInput, Password, Portal, RadioGroup, Rating, ScalableContainer, SearchInput_default as SearchInput, SegmentedControl, Sidebar, SkeletonBox, SkeletonCard, SkeletonCircle, SkeletonText, Slider, Switch, Table, Tabs, TagsInput, DatePicker as Temporal, TextArea, TextInput, ThemeProvider, ThemeSwitch, TimePicker, Tooltip, TooltipProvider, TopBar, Tree, TreeSelect, Typography, Wizard, fieldShell, isRequired, patterns, runFieldRules, useFieldArray, useForm, useFormField, useFormStore, useNotification };
6393
+ // src/components/forms/creditCard.ts
6394
+ var CARD_BRANDS = [
6395
+ { id: "amex", label: "American Express", short: "AMEX", color: "#1F72CD", pattern: /^3[47]/, lengths: [15], cvv: 4, gaps: [4, 10] },
6396
+ { id: "visa", label: "Visa", short: "VISA", color: "#1A1F71", pattern: /^4/, lengths: [16, 18, 19], cvv: 3, gaps: [4, 8, 12, 16] },
6397
+ { id: "mastercard", label: "Mastercard", short: "MC", color: "#EB001B", pattern: /^(5[1-5]|2[2-7])/, lengths: [16], cvv: 3, gaps: [4, 8, 12] },
6398
+ { id: "discover", label: "Discover", short: "DISC", color: "#FF6000", pattern: /^(6011|64[4-9]|65)/, lengths: [16, 19], cvv: 3, gaps: [4, 8, 12] },
6399
+ { id: "diners", label: "Diners Club", short: "DINERS", color: "#0079BE", pattern: /^(36|38|30[0-5])/, lengths: [14, 16, 19], cvv: 3, gaps: [4, 10] },
6400
+ { id: "jcb", label: "JCB", short: "JCB", color: "#0B4EA2", pattern: /^35/, lengths: [16, 17, 18, 19], cvv: 3, gaps: [4, 8, 12] }
6401
+ ];
6402
+ var onlyDigits = (s) => (s || "").replace(/\D/g, "");
6403
+ function detectBrand(value) {
6404
+ const d = onlyDigits(value);
6405
+ if (!d) return null;
6406
+ return CARD_BRANDS.find((b) => b.pattern.test(d)) ?? null;
6407
+ }
6408
+ function maxCardLength(value) {
6409
+ const b = detectBrand(value);
6410
+ return b ? Math.max(...b.lengths) : 19;
6411
+ }
6412
+ function luhnValid(value) {
6413
+ const s = onlyDigits(value);
6414
+ if (s.length < 12) return false;
6415
+ let sum = 0;
6416
+ let double = false;
6417
+ for (let i = s.length - 1; i >= 0; i--) {
6418
+ let n = s.charCodeAt(i) - 48;
6419
+ if (double) {
6420
+ n *= 2;
6421
+ if (n > 9) n -= 9;
6422
+ }
6423
+ sum += n;
6424
+ double = !double;
6425
+ }
6426
+ return sum % 10 === 0;
6427
+ }
6428
+ function formatCardNumber(value) {
6429
+ const brand = detectBrand(value);
6430
+ const digits = onlyDigits(value).slice(0, maxCardLength(value));
6431
+ const gaps = brand?.gaps ?? [4, 8, 12, 16];
6432
+ let out = "";
6433
+ for (let i = 0; i < digits.length; i++) {
6434
+ if (gaps.includes(i)) out += " ";
6435
+ out += digits[i];
6436
+ }
6437
+ return out;
6438
+ }
6439
+ function cardNumberError(value) {
6440
+ const d = onlyDigits(value);
6441
+ if (!d) return "Card number is required";
6442
+ const brand = detectBrand(d);
6443
+ if (!brand) return "Unsupported card type";
6444
+ if (!brand.lengths.includes(d.length)) return "Card number is incomplete";
6445
+ if (!luhnValid(d)) return "Card number looks invalid";
6446
+ return void 0;
6447
+ }
6448
+ function formatExpiry(value) {
6449
+ let d = onlyDigits(value).slice(0, 4);
6450
+ if (d.length === 1 && d > "1") d = "0" + d;
6451
+ if (d.length <= 2) return d;
6452
+ return `${d.slice(0, 2)}/${d.slice(2)}`;
6453
+ }
6454
+ function expiryError(value, now = /* @__PURE__ */ new Date()) {
6455
+ if (!value) return "Expiry is required";
6456
+ const m = value.match(/^(\d{2})\/(\d{2})$/);
6457
+ if (!m) return "Use MM/YY";
6458
+ const mm = Number(m[1]);
6459
+ const yy = Number(m[2]);
6460
+ if (mm < 1 || mm > 12) return "Invalid month";
6461
+ const endOfMonth = new Date(2e3 + yy, mm, 0, 23, 59, 59, 999);
6462
+ if (endOfMonth < now) return "Card has expired";
6463
+ return void 0;
6464
+ }
6465
+ function cvvError(value, cardNumber) {
6466
+ const need = detectBrand(cardNumber)?.cvv ?? 3;
6467
+ const d = onlyDigits(value);
6468
+ if (!d) return "CVV is required";
6469
+ if (d.length !== need) return `CVV must be ${need} digits`;
6470
+ return void 0;
6471
+ }
6472
+ var toCard = (vals) => {
6473
+ const number = String(vals.number ?? "");
6474
+ return {
6475
+ number: onlyDigits(number),
6476
+ name: String(vals.name ?? ""),
6477
+ expiry: String(vals.expiry ?? ""),
6478
+ cvv: onlyDigits(String(vals.cvv ?? "")),
6479
+ brand: detectBrand(number)?.id ?? null
6480
+ };
6481
+ };
6482
+ function BrandMark({ brand }) {
6483
+ return /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1.5", "aria-live": "polite", children: [
6484
+ /* @__PURE__ */ jsxs("svg", { width: "28", height: "18", viewBox: "0 0 28 18", fill: "none", "aria-hidden": "true", children: [
6485
+ /* @__PURE__ */ jsx("rect", { x: "0.5", y: "0.5", width: "27", height: "17", rx: "3", fill: "var(--color-surface-raised)", stroke: "var(--color-border)" }),
6486
+ /* @__PURE__ */ jsx("rect", { x: "0.5", y: "3.75", width: "27", height: "3.5", fill: brand ? brand.color : "var(--color-border-strong)" })
6487
+ ] }),
6488
+ brand && /* @__PURE__ */ jsx("span", { className: "text-[10px] font-bold uppercase tracking-wide", style: { color: brand.color }, children: brand.short }),
6489
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: brand ? brand.label : "Unknown card type" })
6490
+ ] });
6491
+ }
6492
+ function CreditCardForm({
6493
+ onSubmit,
6494
+ onChange,
6495
+ defaultValue,
6496
+ size = "md",
6497
+ disabled,
6498
+ requireName = true,
6499
+ hideSubmit = false,
6500
+ submitLabel = "Pay",
6501
+ className = "",
6502
+ style
6503
+ }) {
6504
+ const initial = useRef({
6505
+ number: formatCardNumber(defaultValue?.number ?? ""),
6506
+ name: defaultValue?.name ?? "",
6507
+ expiry: formatExpiry(defaultValue?.expiry ?? ""),
6508
+ cvv: onlyDigits(defaultValue?.cvv ?? "")
6509
+ }).current;
6510
+ const form = useForm({ initialValues: initial });
6511
+ const numberStr = String(form.values.number ?? "");
6512
+ const brand = detectBrand(numberStr);
6513
+ useEffect(() => {
6514
+ onChange?.(toCard(form.values));
6515
+ }, [form.values.number, form.values.name, form.values.expiry, form.values.cvv]);
6516
+ const numberBind = form.fieldNative("number", {
6517
+ required: "Card number is required",
6518
+ validate: (v) => cardNumberError(String(v))
6519
+ });
6520
+ const nameBind = form.fieldNative("name", requireName ? { required: "Cardholder name is required" } : void 0);
6521
+ const expiryBind = form.fieldNative("expiry", {
6522
+ required: "Expiry is required",
6523
+ validate: (v) => expiryError(String(v))
6524
+ });
6525
+ const cvvBind = form.fieldNative("cvv", {
6526
+ required: "CVV is required",
6527
+ validate: (v) => cvvError(String(v), numberStr)
6528
+ });
6529
+ const cvvLen = brand?.cvv ?? 3;
6530
+ return /* @__PURE__ */ jsxs(
6531
+ Form,
6532
+ {
6533
+ form,
6534
+ onFinish: (vals) => onSubmit?.(toCard(vals)),
6535
+ className: `flex flex-col gap-4 ${className}`.trim(),
6536
+ style,
6537
+ children: [
6538
+ /* @__PURE__ */ jsx(
6539
+ TextInput,
6540
+ {
6541
+ ...numberBind,
6542
+ label: "Card number",
6543
+ placeholder: "1234 5678 9012 3456",
6544
+ size,
6545
+ disabled,
6546
+ value: numberStr,
6547
+ onChange: (e) => form.setValue("number", formatCardNumber(e.target.value), { touch: true }),
6548
+ suffix: /* @__PURE__ */ jsx(BrandMark, { brand })
6549
+ }
6550
+ ),
6551
+ /* @__PURE__ */ jsx(
6552
+ TextInput,
6553
+ {
6554
+ ...nameBind,
6555
+ label: "Cardholder name",
6556
+ placeholder: "Jane Appleseed",
6557
+ size,
6558
+ disabled,
6559
+ value: String(form.values.name ?? ""),
6560
+ onChange: (e) => form.setValue("name", e.target.value, { touch: true })
6561
+ }
6562
+ ),
6563
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
6564
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
6565
+ TextInput,
6566
+ {
6567
+ ...expiryBind,
6568
+ label: "Expiry",
6569
+ placeholder: "MM/YY",
6570
+ size,
6571
+ disabled,
6572
+ value: String(form.values.expiry ?? ""),
6573
+ onChange: (e) => form.setValue("expiry", formatExpiry(e.target.value), { touch: true })
6574
+ }
6575
+ ) }),
6576
+ /* @__PURE__ */ jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsx(
6577
+ TextInput,
6578
+ {
6579
+ ...cvvBind,
6580
+ label: "CVV",
6581
+ placeholder: cvvLen === 4 ? "1234" : "123",
6582
+ size,
6583
+ disabled,
6584
+ value: String(form.values.cvv ?? ""),
6585
+ onChange: (e) => form.setValue("cvv", onlyDigits(e.target.value).slice(0, cvvLen), { touch: true })
6586
+ }
6587
+ ) })
6588
+ ] }),
6589
+ !hideSubmit && /* @__PURE__ */ jsx(Button, { content: submitLabel, buttonType: "submit", variant: "primary", disabled })
6590
+ ]
6591
+ }
6592
+ );
6593
+ }
6594
+
6595
+ export { AppShell, AutoComplete, Avatar, Box, Button, CARD_BRANDS, Catalog, CatalogCarousel, CatalogGrid, Checkbox, ColorPicker, ContextMenu, CreditCardForm, DateRangePicker, Drawer, Dropdown, FadingBase, Field, FieldHelpIcon, FieldLabel, FileInput, Flex, Form, FormContext, FormField, FormStore, Grid2 as Grid, GridCard, icons_default as Icon, IconButton, List2 as List, LoadingSpinner, Modal, NotificationProvider, NumberInput, OpaqueGridCard, OtpInput, Password, Portal, RadioGroup, Rating, ScalableContainer, SearchInput_default as SearchInput, SegmentedControl, Sidebar, SkeletonBox, SkeletonCard, SkeletonCircle, SkeletonText, Slider, Switch, Table, Tabs, TagsInput, DatePicker as Temporal, TextArea, TextInput, ThemeProvider, ThemeSwitch, TimePicker, Tooltip, TooltipProvider, TopBar, Tree, TreeSelect, Typography, Wizard, cardNumberError, cvvError, detectBrand, expiryError, fieldShell, formatCardNumber, formatExpiry, isRequired, luhnValid, onlyDigits, patterns, runFieldRules, useFieldArray, useForm, useFormField, useFormStore, useNotification };
6360
6596
  //# sourceMappingURL=index.js.map
6361
6597
  //# sourceMappingURL=index.js.map