@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.cjs CHANGED
@@ -642,7 +642,9 @@ function IconButton({
642
642
  disabled = false,
643
643
  size = "lg",
644
644
  loading = false,
645
- loadingIcon
645
+ loadingIcon,
646
+ className = "",
647
+ style
646
648
  }) {
647
649
  const colorScheme = React8.useMemo(() => {
648
650
  if (type === "primary") {
@@ -659,7 +661,8 @@ function IconButton({
659
661
  type: buttonType,
660
662
  disabled: disabled || loading,
661
663
  onClick,
662
- 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`,
664
+ style,
665
+ 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(),
663
666
  children: loading ? loadingIcon : icon
664
667
  }
665
668
  );
@@ -710,7 +713,8 @@ function Button({
710
713
  disabled,
711
714
  style,
712
715
  icon,
713
- onClick
716
+ onClick,
717
+ className = ""
714
718
  }) {
715
719
  return /* @__PURE__ */ jsxRuntime.jsxs(
716
720
  "button",
@@ -725,8 +729,9 @@ function Button({
725
729
  "outline-none transition-colors duration-150 select-none",
726
730
  "whitespace-nowrap",
727
731
  SIZE_CLASSES[size],
728
- VARIANT_CLASSES[variant]
729
- ].join(" "),
732
+ VARIANT_CLASSES[variant],
733
+ className
734
+ ].filter(Boolean).join(" "),
730
735
  children: [
731
736
  loading ? /* @__PURE__ */ jsxRuntime.jsx(
732
737
  "svg",
@@ -761,7 +766,8 @@ function Modal({
761
766
  cancelText = "Cancel",
762
767
  hasFooter = true,
763
768
  title,
764
- children
769
+ children,
770
+ className = ""
765
771
  }) {
766
772
  const reduced = framerMotion.useReducedMotion();
767
773
  const maxWidth = width ?? size?.[0] ?? 600;
@@ -781,7 +787,7 @@ function Modal({
781
787
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxRuntime.jsx(Dialog__namespace.Content, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
782
788
  framerMotion.motion.div,
783
789
  {
784
- 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",
790
+ 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(),
785
791
  style: {
786
792
  maxWidth,
787
793
  x: "-50%",
@@ -843,7 +849,8 @@ function Drawer({
843
849
  onOk,
844
850
  onCancel,
845
851
  title,
846
- children
852
+ children,
853
+ className = ""
847
854
  }) {
848
855
  const reduced = framerMotion.useReducedMotion();
849
856
  const isRight = placement === "right";
@@ -864,7 +871,7 @@ function Drawer({
864
871
  /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: isOpen && /* @__PURE__ */ jsxRuntime.jsx(Dialog__namespace.Content, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
865
872
  framerMotion.motion.div,
866
873
  {
867
- className: `fixed top-0 bottom-0 ${isRight ? "right-0" : "left-0"} z-modal flex flex-col bg-surface shadow-xl focus:outline-none`,
874
+ 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(),
868
875
  style: { width: `min(calc(100vw - 1rem), ${width}px)` },
869
876
  initial: { x: reduced ? 0 : hiddenX, opacity: reduced ? 0 : 1 },
870
877
  animate: { x: 0, opacity: 1 },
@@ -1531,9 +1538,11 @@ function List2({
1531
1538
  items,
1532
1539
  onItemClick,
1533
1540
  activeKey,
1534
- density = "comfortable"
1541
+ density = "comfortable",
1542
+ className = "",
1543
+ style
1535
1544
  }) {
1536
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", className: "flex flex-col", children: items.map((item) => {
1545
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listbox", className: `flex flex-col ${className}`.trim(), style, children: items.map((item) => {
1537
1546
  const isActive = activeKey === item.key;
1538
1547
  const isDisabled = !!item.disabled;
1539
1548
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1655,8 +1664,8 @@ function CollapseIcon() {
1655
1664
  function ExpandIcon() {
1656
1665
  return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M4 8V4h4M20 8V4h-4M4 16v4h4M20 16v4h-4" }) });
1657
1666
  }
1658
- function GridCard({ item, buttonText = "Open Application", onOpen }) {
1659
- return /* @__PURE__ */ jsxRuntime.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: [
1667
+ function GridCard({ item, buttonText = "Open Application", onOpen, className = "", style }) {
1668
+ return /* @__PURE__ */ jsxRuntime.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: [
1660
1669
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-prussian-blue dark:text-white text-lg font-bold text-center h-1/4", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { children: item.title }) }),
1661
1670
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1/4 flex items-center justify-center", children: typeof item.cover === "string" ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.cover, alt: "Grid Card Cover" }) : item.cover }),
1662
1671
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-prussian-blue text-sm dark:text-white text-center h-1/4", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: item.description }) }),
@@ -2275,8 +2284,8 @@ function Field({
2275
2284
  );
2276
2285
  }
2277
2286
  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" }) });
2278
- var SearchInput = React8__default.default.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText }, ref) {
2279
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, layout, helperText, children: /* @__PURE__ */ jsxRuntime.jsxs(
2287
+ var SearchInput = React8__default.default.forwardRef(function SearchInput2({ value, onChange, disabled, label, htmlFor, placeholder, name, inputStyle, style, layout = "vertical", size = "md", icon, helperText, className }, ref) {
2288
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { className, label, htmlFor, layout, helperText, children: /* @__PURE__ */ jsxRuntime.jsxs(
2280
2289
  "div",
2281
2290
  {
2282
2291
  className: `flex items-center ${fieldShell({ size, disabled, focusWithin: true })}`,
@@ -2424,7 +2433,8 @@ function Dropdown({
2424
2433
  items = [],
2425
2434
  labelStyle = {},
2426
2435
  placeholder,
2427
- size = "md"
2436
+ size = "md",
2437
+ className = ""
2428
2438
  }) {
2429
2439
  const [open, setOpen] = React8.useState(false);
2430
2440
  const [selectedItems, setSelectedItems] = React8.useState([]);
@@ -2472,7 +2482,7 @@ function Dropdown({
2472
2482
  );
2473
2483
  };
2474
2484
  const isSelected = (key) => Array.isArray(value) ? value.includes(key) : value === key;
2475
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2485
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: className || void 0, children: [
2476
2486
  /* @__PURE__ */ jsxRuntime.jsxs(
2477
2487
  "div",
2478
2488
  {
@@ -2605,15 +2615,7 @@ function Dropdown({
2605
2615
  hasError && /* @__PURE__ */ jsxRuntime.jsx("div", { id: errorId, className: "text-status-error text-xs mt-1", children: errorMessage })
2606
2616
  ] });
2607
2617
  }
2608
- var SHIMMER = [
2609
- "relative overflow-hidden rounded-sm bg-surface-raised",
2610
- 'before:absolute before:inset-0 before:content-[""]',
2611
- "before:bg-gradient-to-r before:from-transparent before:via-white/30 before:to-transparent",
2612
- "before:animate-[shimmer_1.6s_linear_infinite]",
2613
- // Respect prefers-reduced-motion — the resting bg-surface-raised is still
2614
- // a perfectly legible placeholder for users who have animations off.
2615
- "motion-reduce:before:hidden"
2616
- ].join(" ");
2618
+ var SHIMMER = "oxy-skeleton rounded-sm bg-surface-raised";
2617
2619
  function SkeletonBox({ width, height = 16, radius, className = "", style }) {
2618
2620
  return /* @__PURE__ */ jsxRuntime.jsx(
2619
2621
  "span",
@@ -2888,7 +2890,9 @@ function Table({
2888
2890
  footer = null,
2889
2891
  header = null,
2890
2892
  loading = false,
2891
- loadingRowCount = 8
2893
+ loadingRowCount = 8,
2894
+ className = "",
2895
+ style
2892
2896
  }) {
2893
2897
  const searchRef = React8.useRef(null);
2894
2898
  const [searchTerm, setSearchTerm] = React8.useState("");
@@ -2948,7 +2952,7 @@ function Table({
2948
2952
  }
2949
2953
  setActivePage(newPage);
2950
2954
  };
2951
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full h-max rounded-lg", children: [
2955
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full h-max rounded-lg ${className}`.trim(), style, children: [
2952
2956
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
2953
2957
  hasSearch && /* @__PURE__ */ jsxRuntime.jsx(
2954
2958
  SearchInput_default,
@@ -3125,7 +3129,8 @@ function Sidebar({
3125
3129
  onToggle,
3126
3130
  expandedWidth = 220,
3127
3131
  collapsedWidth = 52,
3128
- footer
3132
+ footer,
3133
+ className = ""
3129
3134
  }) {
3130
3135
  return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ jsxRuntime.jsxs(
3131
3136
  framerMotion.motion.aside,
@@ -3133,7 +3138,7 @@ function Sidebar({
3133
3138
  initial: false,
3134
3139
  animate: { width: isExpanded ? expandedWidth : collapsedWidth },
3135
3140
  transition: { type: "tween", duration: 0.22, ease: [0.16, 1, 0.3, 1] },
3136
- className: "relative flex h-full flex-col border-r border-border bg-surface overflow-hidden flex-shrink-0",
3141
+ className: `relative flex h-full flex-col border-r border-border bg-surface overflow-hidden flex-shrink-0 ${className}`.trim(),
3137
3142
  children: [
3138
3143
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: [
3139
3144
  "flex h-14 flex-shrink-0 items-center border-b border-border",
@@ -3459,6 +3464,7 @@ function TextInput({
3459
3464
  onBlur,
3460
3465
  errorMessage,
3461
3466
  helperText,
3467
+ className,
3462
3468
  required,
3463
3469
  prefix,
3464
3470
  suffix
@@ -3487,6 +3493,7 @@ function TextInput({
3487
3493
  return /* @__PURE__ */ jsxRuntime.jsx(
3488
3494
  Field,
3489
3495
  {
3496
+ className,
3490
3497
  label,
3491
3498
  htmlFor,
3492
3499
  errorId,
@@ -3521,6 +3528,7 @@ function NumberInput({
3521
3528
  size = "md",
3522
3529
  errorMessage,
3523
3530
  helperText,
3531
+ className,
3524
3532
  required,
3525
3533
  inputStyle,
3526
3534
  labelStyle,
@@ -3565,6 +3573,7 @@ function NumberInput({
3565
3573
  return /* @__PURE__ */ jsxRuntime.jsx(
3566
3574
  Field,
3567
3575
  {
3576
+ className,
3568
3577
  label,
3569
3578
  htmlFor,
3570
3579
  errorId,
@@ -3656,6 +3665,7 @@ function Password({
3656
3665
  onBlur,
3657
3666
  errorMessage,
3658
3667
  helperText,
3668
+ className,
3659
3669
  required,
3660
3670
  showIcon,
3661
3671
  hideIcon
@@ -3666,6 +3676,7 @@ function Password({
3666
3676
  return /* @__PURE__ */ jsxRuntime.jsx(
3667
3677
  Field,
3668
3678
  {
3679
+ className,
3669
3680
  label,
3670
3681
  htmlFor,
3671
3682
  errorId,
@@ -3728,7 +3739,8 @@ function Checkbox({
3728
3739
  disabled = false,
3729
3740
  required,
3730
3741
  layout = "horizontal",
3731
- labelPosition = "right"
3742
+ labelPosition = "right",
3743
+ className = ""
3732
3744
  }) {
3733
3745
  const isChecked = checked ?? value ?? false;
3734
3746
  const labelFirst = labelPosition === "left";
@@ -3806,7 +3818,7 @@ function Checkbox({
3806
3818
  ] })
3807
3819
  ] });
3808
3820
  }
3809
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
3821
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `flex flex-col gap-1 ${className}`.trim(), children: [
3810
3822
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-1", children: [
3811
3823
  content,
3812
3824
  helperText != null && /* @__PURE__ */ jsxRuntime.jsx(FieldHelpIcon, { text: helperText })
@@ -3837,6 +3849,7 @@ function RadioGroup({
3837
3849
  disabled,
3838
3850
  required,
3839
3851
  helperText,
3852
+ className,
3840
3853
  errorMessage
3841
3854
  }) {
3842
3855
  const errorId = React8.useId();
@@ -3846,6 +3859,7 @@ function RadioGroup({
3846
3859
  return /* @__PURE__ */ jsxRuntime.jsx(
3847
3860
  Field,
3848
3861
  {
3862
+ className,
3849
3863
  label,
3850
3864
  htmlFor: groupId,
3851
3865
  errorId,
@@ -3931,6 +3945,7 @@ function Switch({
3931
3945
  label,
3932
3946
  layout = "horizontal",
3933
3947
  helperText,
3948
+ className,
3934
3949
  offLabel,
3935
3950
  onLabel,
3936
3951
  name,
@@ -3956,6 +3971,7 @@ function Switch({
3956
3971
  return /* @__PURE__ */ jsxRuntime.jsx(
3957
3972
  Field,
3958
3973
  {
3974
+ className,
3959
3975
  label,
3960
3976
  htmlFor: id,
3961
3977
  errorId,
@@ -4010,6 +4026,7 @@ function AutoComplete({
4010
4026
  icon,
4011
4027
  errorMessage,
4012
4028
  helperText,
4029
+ className,
4013
4030
  required,
4014
4031
  htmlFor
4015
4032
  }) {
@@ -4064,6 +4081,7 @@ function AutoComplete({
4064
4081
  return /* @__PURE__ */ jsxRuntime.jsx(
4065
4082
  Field,
4066
4083
  {
4084
+ className,
4067
4085
  label,
4068
4086
  htmlFor,
4069
4087
  errorId,
@@ -4169,6 +4187,7 @@ function TreeSelect({
4169
4187
  disabled,
4170
4188
  layout = "horizontal",
4171
4189
  helperText,
4190
+ className,
4172
4191
  required,
4173
4192
  errorMessage,
4174
4193
  style,
@@ -4256,6 +4275,7 @@ function TreeSelect({
4256
4275
  return /* @__PURE__ */ jsxRuntime.jsx(
4257
4276
  Field,
4258
4277
  {
4278
+ className,
4259
4279
  label,
4260
4280
  htmlFor,
4261
4281
  errorId,
@@ -4422,6 +4442,7 @@ function FileInput({
4422
4442
  maxSize,
4423
4443
  errorMessage,
4424
4444
  helperText,
4445
+ className,
4425
4446
  disabled,
4426
4447
  required,
4427
4448
  icon
@@ -4464,6 +4485,7 @@ function FileInput({
4464
4485
  return /* @__PURE__ */ jsxRuntime.jsxs(
4465
4486
  Field,
4466
4487
  {
4488
+ className,
4467
4489
  label,
4468
4490
  htmlFor,
4469
4491
  errorId,
@@ -4927,6 +4949,7 @@ function TextArea({
4927
4949
  resize,
4928
4950
  errorMessage,
4929
4951
  helperText,
4952
+ className,
4930
4953
  required,
4931
4954
  style,
4932
4955
  inputStyle
@@ -4948,6 +4971,7 @@ function TextArea({
4948
4971
  return /* @__PURE__ */ jsxRuntime.jsxs(
4949
4972
  Field,
4950
4973
  {
4974
+ className,
4951
4975
  label,
4952
4976
  htmlFor,
4953
4977
  errorId,
@@ -4996,6 +5020,7 @@ function SegmentedControl({
4996
5020
  label,
4997
5021
  layout = "vertical",
4998
5022
  helperText,
5023
+ className,
4999
5024
  name,
5000
5025
  required,
5001
5026
  errorMessage,
@@ -5016,6 +5041,7 @@ function SegmentedControl({
5016
5041
  return /* @__PURE__ */ jsxRuntime.jsxs(
5017
5042
  Field,
5018
5043
  {
5044
+ className,
5019
5045
  label,
5020
5046
  htmlFor: groupId,
5021
5047
  errorId,
@@ -5094,6 +5120,7 @@ function Slider({
5094
5120
  disabled,
5095
5121
  errorMessage,
5096
5122
  helperText,
5123
+ className,
5097
5124
  required,
5098
5125
  name,
5099
5126
  htmlFor
@@ -5112,7 +5139,7 @@ function Slider({
5112
5139
  onChange?.(next);
5113
5140
  };
5114
5141
  const valueText = current.map(formatValue).join(" \u2013 ");
5115
- return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label: void 0, errorId, errorMessage, children: [
5142
+ return /* @__PURE__ */ jsxRuntime.jsxs(Field, { className, label: void 0, errorId, errorMessage, children: [
5116
5143
  (label || showValue) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
5117
5144
  label && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1", children: [
5118
5145
  /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor, className: "text-sm font-medium text-foreground select-none", children: [
@@ -5193,6 +5220,7 @@ function TagsInput({
5193
5220
  disabled,
5194
5221
  errorMessage,
5195
5222
  helperText,
5223
+ className,
5196
5224
  required,
5197
5225
  maxTags,
5198
5226
  dedupe = true,
@@ -5256,6 +5284,7 @@ function TagsInput({
5256
5284
  return /* @__PURE__ */ jsxRuntime.jsx(
5257
5285
  Field,
5258
5286
  {
5287
+ className,
5259
5288
  label,
5260
5289
  htmlFor,
5261
5290
  errorId,
@@ -5330,6 +5359,7 @@ function OtpInput({
5330
5359
  required,
5331
5360
  layout = "vertical",
5332
5361
  helperText,
5362
+ className,
5333
5363
  groupAfter
5334
5364
  }) {
5335
5365
  const errorId = React8.useId();
@@ -5383,7 +5413,7 @@ function OtpInput({
5383
5413
  emit(valid.join(""));
5384
5414
  focusBox(valid.length);
5385
5415
  };
5386
- 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: [
5416
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { className, 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: [
5387
5417
  /* @__PURE__ */ jsxRuntime.jsx(
5388
5418
  "input",
5389
5419
  {
@@ -5438,6 +5468,7 @@ function Rating({
5438
5468
  name,
5439
5469
  layout = "vertical",
5440
5470
  helperText,
5471
+ className,
5441
5472
  required
5442
5473
  }) {
5443
5474
  const errorId = React8.useId();
@@ -5468,7 +5499,7 @@ function Rating({
5468
5499
  commit(count);
5469
5500
  }
5470
5501
  };
5471
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, errorId, errorMessage, layout, required, helperText, children: /* @__PURE__ */ jsxRuntime.jsxs(
5502
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { className, label, errorId, errorMessage, layout, required, helperText, children: /* @__PURE__ */ jsxRuntime.jsxs(
5472
5503
  "div",
5473
5504
  {
5474
5505
  role: interactive ? "slider" : "img",
@@ -5561,6 +5592,7 @@ function TimePicker({
5561
5592
  disabled,
5562
5593
  errorMessage,
5563
5594
  helperText,
5595
+ className,
5564
5596
  required,
5565
5597
  style
5566
5598
  }) {
@@ -5593,7 +5625,7 @@ function TimePicker({
5593
5625
  },
5594
5626
  n
5595
5627
  )) });
5596
- return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5628
+ return /* @__PURE__ */ jsxRuntime.jsxs(Field, { className, label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5597
5629
  /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
5598
5630
  /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
5599
5631
  "button",
@@ -5686,6 +5718,7 @@ function DateRangePicker({
5686
5718
  disabled,
5687
5719
  errorMessage,
5688
5720
  helperText,
5721
+ className,
5689
5722
  required,
5690
5723
  style
5691
5724
  }) {
@@ -5758,7 +5791,7 @@ function DateRangePicker({
5758
5791
  ] })
5759
5792
  ] });
5760
5793
  };
5761
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => {
5794
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { className, label, htmlFor, errorId, errorMessage, helperText, layout, required, children: /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => {
5762
5795
  if (!disabled) {
5763
5796
  setOpen(o);
5764
5797
  if (!o) {
@@ -5867,6 +5900,7 @@ function ColorPicker({
5867
5900
  disabled,
5868
5901
  errorMessage,
5869
5902
  helperText,
5903
+ className,
5870
5904
  required,
5871
5905
  placeholder = "Pick a colour\u2026"
5872
5906
  }) {
@@ -5884,7 +5918,7 @@ function ColorPicker({
5884
5918
  setDraft(hex);
5885
5919
  if (HEX_RE.test(hex)) onChange?.(hex);
5886
5920
  };
5887
- return /* @__PURE__ */ jsxRuntime.jsxs(Field, { label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5921
+ return /* @__PURE__ */ jsxRuntime.jsxs(Field, { className, label, htmlFor, errorId, errorMessage, helperText, layout, required, children: [
5888
5922
  /* @__PURE__ */ jsxRuntime.jsxs(Popover__namespace.Root, { open: open && !disabled, onOpenChange: (o) => !disabled && setOpen(o), children: [
5889
5923
  /* @__PURE__ */ jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
5890
5924
  "button",
@@ -6281,7 +6315,7 @@ function useForm(options = {}) {
6281
6315
  isValid: store.isValid,
6282
6316
  getValue: store.getValue,
6283
6317
  getValues: store.getValues,
6284
- setValue: (name, value) => store.setValue(name, value),
6318
+ setValue: (name, value, opts) => store.setValue(name, value, opts),
6285
6319
  setValues: (patch) => store.setValues(patch),
6286
6320
  setError: store.setError,
6287
6321
  validateField: (name) => store.validateField(name),
@@ -6391,6 +6425,208 @@ function useFieldArray(name) {
6391
6425
  };
6392
6426
  }
6393
6427
 
6428
+ // src/components/forms/creditCard.ts
6429
+ var CARD_BRANDS = [
6430
+ { id: "amex", label: "American Express", short: "AMEX", color: "#1F72CD", pattern: /^3[47]/, lengths: [15], cvv: 4, gaps: [4, 10] },
6431
+ { id: "visa", label: "Visa", short: "VISA", color: "#1A1F71", pattern: /^4/, lengths: [16, 18, 19], cvv: 3, gaps: [4, 8, 12, 16] },
6432
+ { id: "mastercard", label: "Mastercard", short: "MC", color: "#EB001B", pattern: /^(5[1-5]|2[2-7])/, lengths: [16], cvv: 3, gaps: [4, 8, 12] },
6433
+ { id: "discover", label: "Discover", short: "DISC", color: "#FF6000", pattern: /^(6011|64[4-9]|65)/, lengths: [16, 19], cvv: 3, gaps: [4, 8, 12] },
6434
+ { id: "diners", label: "Diners Club", short: "DINERS", color: "#0079BE", pattern: /^(36|38|30[0-5])/, lengths: [14, 16, 19], cvv: 3, gaps: [4, 10] },
6435
+ { id: "jcb", label: "JCB", short: "JCB", color: "#0B4EA2", pattern: /^35/, lengths: [16, 17, 18, 19], cvv: 3, gaps: [4, 8, 12] }
6436
+ ];
6437
+ var onlyDigits = (s) => (s || "").replace(/\D/g, "");
6438
+ function detectBrand(value) {
6439
+ const d = onlyDigits(value);
6440
+ if (!d) return null;
6441
+ return CARD_BRANDS.find((b) => b.pattern.test(d)) ?? null;
6442
+ }
6443
+ function maxCardLength(value) {
6444
+ const b = detectBrand(value);
6445
+ return b ? Math.max(...b.lengths) : 19;
6446
+ }
6447
+ function luhnValid(value) {
6448
+ const s = onlyDigits(value);
6449
+ if (s.length < 12) return false;
6450
+ let sum = 0;
6451
+ let double = false;
6452
+ for (let i = s.length - 1; i >= 0; i--) {
6453
+ let n = s.charCodeAt(i) - 48;
6454
+ if (double) {
6455
+ n *= 2;
6456
+ if (n > 9) n -= 9;
6457
+ }
6458
+ sum += n;
6459
+ double = !double;
6460
+ }
6461
+ return sum % 10 === 0;
6462
+ }
6463
+ function formatCardNumber(value) {
6464
+ const brand = detectBrand(value);
6465
+ const digits = onlyDigits(value).slice(0, maxCardLength(value));
6466
+ const gaps = brand?.gaps ?? [4, 8, 12, 16];
6467
+ let out = "";
6468
+ for (let i = 0; i < digits.length; i++) {
6469
+ if (gaps.includes(i)) out += " ";
6470
+ out += digits[i];
6471
+ }
6472
+ return out;
6473
+ }
6474
+ function cardNumberError(value) {
6475
+ const d = onlyDigits(value);
6476
+ if (!d) return "Card number is required";
6477
+ const brand = detectBrand(d);
6478
+ if (!brand) return "Unsupported card type";
6479
+ if (!brand.lengths.includes(d.length)) return "Card number is incomplete";
6480
+ if (!luhnValid(d)) return "Card number looks invalid";
6481
+ return void 0;
6482
+ }
6483
+ function formatExpiry(value) {
6484
+ let d = onlyDigits(value).slice(0, 4);
6485
+ if (d.length === 1 && d > "1") d = "0" + d;
6486
+ if (d.length <= 2) return d;
6487
+ return `${d.slice(0, 2)}/${d.slice(2)}`;
6488
+ }
6489
+ function expiryError(value, now = /* @__PURE__ */ new Date()) {
6490
+ if (!value) return "Expiry is required";
6491
+ const m = value.match(/^(\d{2})\/(\d{2})$/);
6492
+ if (!m) return "Use MM/YY";
6493
+ const mm = Number(m[1]);
6494
+ const yy = Number(m[2]);
6495
+ if (mm < 1 || mm > 12) return "Invalid month";
6496
+ const endOfMonth = new Date(2e3 + yy, mm, 0, 23, 59, 59, 999);
6497
+ if (endOfMonth < now) return "Card has expired";
6498
+ return void 0;
6499
+ }
6500
+ function cvvError(value, cardNumber) {
6501
+ const need = detectBrand(cardNumber)?.cvv ?? 3;
6502
+ const d = onlyDigits(value);
6503
+ if (!d) return "CVV is required";
6504
+ if (d.length !== need) return `CVV must be ${need} digits`;
6505
+ return void 0;
6506
+ }
6507
+ var toCard = (vals) => {
6508
+ const number = String(vals.number ?? "");
6509
+ return {
6510
+ number: onlyDigits(number),
6511
+ name: String(vals.name ?? ""),
6512
+ expiry: String(vals.expiry ?? ""),
6513
+ cvv: onlyDigits(String(vals.cvv ?? "")),
6514
+ brand: detectBrand(number)?.id ?? null
6515
+ };
6516
+ };
6517
+ function BrandMark({ brand }) {
6518
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1.5", "aria-live": "polite", children: [
6519
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "28", height: "18", viewBox: "0 0 28 18", fill: "none", "aria-hidden": "true", children: [
6520
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "0.5", y: "0.5", width: "27", height: "17", rx: "3", fill: "var(--color-surface-raised)", stroke: "var(--color-border)" }),
6521
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "0.5", y: "3.75", width: "27", height: "3.5", fill: brand ? brand.color : "var(--color-border-strong)" })
6522
+ ] }),
6523
+ brand && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold uppercase tracking-wide", style: { color: brand.color }, children: brand.short }),
6524
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: brand ? brand.label : "Unknown card type" })
6525
+ ] });
6526
+ }
6527
+ function CreditCardForm({
6528
+ onSubmit,
6529
+ onChange,
6530
+ defaultValue,
6531
+ size = "md",
6532
+ disabled,
6533
+ requireName = true,
6534
+ hideSubmit = false,
6535
+ submitLabel = "Pay",
6536
+ className = "",
6537
+ style
6538
+ }) {
6539
+ const initial = React8.useRef({
6540
+ number: formatCardNumber(defaultValue?.number ?? ""),
6541
+ name: defaultValue?.name ?? "",
6542
+ expiry: formatExpiry(defaultValue?.expiry ?? ""),
6543
+ cvv: onlyDigits(defaultValue?.cvv ?? "")
6544
+ }).current;
6545
+ const form = useForm({ initialValues: initial });
6546
+ const numberStr = String(form.values.number ?? "");
6547
+ const brand = detectBrand(numberStr);
6548
+ React8.useEffect(() => {
6549
+ onChange?.(toCard(form.values));
6550
+ }, [form.values.number, form.values.name, form.values.expiry, form.values.cvv]);
6551
+ const numberBind = form.fieldNative("number", {
6552
+ required: "Card number is required",
6553
+ validate: (v) => cardNumberError(String(v))
6554
+ });
6555
+ const nameBind = form.fieldNative("name", requireName ? { required: "Cardholder name is required" } : void 0);
6556
+ const expiryBind = form.fieldNative("expiry", {
6557
+ required: "Expiry is required",
6558
+ validate: (v) => expiryError(String(v))
6559
+ });
6560
+ const cvvBind = form.fieldNative("cvv", {
6561
+ required: "CVV is required",
6562
+ validate: (v) => cvvError(String(v), numberStr)
6563
+ });
6564
+ const cvvLen = brand?.cvv ?? 3;
6565
+ return /* @__PURE__ */ jsxRuntime.jsxs(
6566
+ Form,
6567
+ {
6568
+ form,
6569
+ onFinish: (vals) => onSubmit?.(toCard(vals)),
6570
+ className: `flex flex-col gap-4 ${className}`.trim(),
6571
+ style,
6572
+ children: [
6573
+ /* @__PURE__ */ jsxRuntime.jsx(
6574
+ TextInput,
6575
+ {
6576
+ ...numberBind,
6577
+ label: "Card number",
6578
+ placeholder: "1234 5678 9012 3456",
6579
+ size,
6580
+ disabled,
6581
+ value: numberStr,
6582
+ onChange: (e) => form.setValue("number", formatCardNumber(e.target.value), { touch: true }),
6583
+ suffix: /* @__PURE__ */ jsxRuntime.jsx(BrandMark, { brand })
6584
+ }
6585
+ ),
6586
+ /* @__PURE__ */ jsxRuntime.jsx(
6587
+ TextInput,
6588
+ {
6589
+ ...nameBind,
6590
+ label: "Cardholder name",
6591
+ placeholder: "Jane Appleseed",
6592
+ size,
6593
+ disabled,
6594
+ value: String(form.values.name ?? ""),
6595
+ onChange: (e) => form.setValue("name", e.target.value, { touch: true })
6596
+ }
6597
+ ),
6598
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
6599
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
6600
+ TextInput,
6601
+ {
6602
+ ...expiryBind,
6603
+ label: "Expiry",
6604
+ placeholder: "MM/YY",
6605
+ size,
6606
+ disabled,
6607
+ value: String(form.values.expiry ?? ""),
6608
+ onChange: (e) => form.setValue("expiry", formatExpiry(e.target.value), { touch: true })
6609
+ }
6610
+ ) }),
6611
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
6612
+ TextInput,
6613
+ {
6614
+ ...cvvBind,
6615
+ label: "CVV",
6616
+ placeholder: cvvLen === 4 ? "1234" : "123",
6617
+ size,
6618
+ disabled,
6619
+ value: String(form.values.cvv ?? ""),
6620
+ onChange: (e) => form.setValue("cvv", onlyDigits(e.target.value).slice(0, cvvLen), { touch: true })
6621
+ }
6622
+ ) })
6623
+ ] }),
6624
+ !hideSubmit && /* @__PURE__ */ jsxRuntime.jsx(Button, { content: submitLabel, buttonType: "submit", variant: "primary", disabled })
6625
+ ]
6626
+ }
6627
+ );
6628
+ }
6629
+
6394
6630
  Object.defineProperty(exports, "COLORS", {
6395
6631
  enumerable: true,
6396
6632
  get: function () { return chunk255PCZIW_cjs.colors_default; }
@@ -6412,12 +6648,14 @@ exports.AutoComplete = AutoComplete;
6412
6648
  exports.Avatar = Avatar;
6413
6649
  exports.Box = Box;
6414
6650
  exports.Button = Button;
6651
+ exports.CARD_BRANDS = CARD_BRANDS;
6415
6652
  exports.Catalog = Catalog;
6416
6653
  exports.CatalogCarousel = CatalogCarousel;
6417
6654
  exports.CatalogGrid = CatalogGrid;
6418
6655
  exports.Checkbox = Checkbox;
6419
6656
  exports.ColorPicker = ColorPicker;
6420
6657
  exports.ContextMenu = ContextMenu;
6658
+ exports.CreditCardForm = CreditCardForm;
6421
6659
  exports.DateRangePicker = DateRangePicker;
6422
6660
  exports.Drawer = Drawer;
6423
6661
  exports.Dropdown = Dropdown;
@@ -6472,8 +6710,16 @@ exports.Tree = Tree;
6472
6710
  exports.TreeSelect = TreeSelect;
6473
6711
  exports.Typography = Typography;
6474
6712
  exports.Wizard = Wizard;
6713
+ exports.cardNumberError = cardNumberError;
6714
+ exports.cvvError = cvvError;
6715
+ exports.detectBrand = detectBrand;
6716
+ exports.expiryError = expiryError;
6475
6717
  exports.fieldShell = fieldShell;
6718
+ exports.formatCardNumber = formatCardNumber;
6719
+ exports.formatExpiry = formatExpiry;
6476
6720
  exports.isRequired = isRequired;
6721
+ exports.luhnValid = luhnValid;
6722
+ exports.onlyDigits = onlyDigits;
6477
6723
  exports.patterns = patterns;
6478
6724
  exports.runFieldRules = runFieldRules;
6479
6725
  exports.useFieldArray = useFieldArray;