infinity-ui-elements 1.4.0 → 1.4.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/components/Badge/Badge.d.ts +28 -0
  2. package/dist/components/Badge/Badge.d.ts.map +1 -0
  3. package/dist/components/Badge/Badge.stories.d.ts +16 -0
  4. package/dist/components/Badge/Badge.stories.d.ts.map +1 -0
  5. package/dist/components/Badge/index.d.ts +3 -0
  6. package/dist/components/Badge/index.d.ts.map +1 -0
  7. package/dist/components/Button/Button.d.ts +1 -1
  8. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
  9. package/dist/components/Counter/Counter.d.ts +24 -0
  10. package/dist/components/Counter/Counter.d.ts.map +1 -0
  11. package/dist/components/Counter/Counter.stories.d.ts +14 -0
  12. package/dist/components/Counter/Counter.stories.d.ts.map +1 -0
  13. package/dist/components/Counter/index.d.ts +3 -0
  14. package/dist/components/Counter/index.d.ts.map +1 -0
  15. package/dist/components/Divider/Divider.d.ts +37 -0
  16. package/dist/components/Divider/Divider.d.ts.map +1 -0
  17. package/dist/components/Divider/Divider.stories.d.ts +12 -0
  18. package/dist/components/Divider/Divider.stories.d.ts.map +1 -0
  19. package/dist/components/Divider/index.d.ts +2 -0
  20. package/dist/components/Divider/index.d.ts.map +1 -0
  21. package/dist/components/ListItem/ListItem.d.ts +63 -0
  22. package/dist/components/ListItem/ListItem.d.ts.map +1 -0
  23. package/dist/components/ListItem/ListItem.stories.d.ts +66 -0
  24. package/dist/components/ListItem/ListItem.stories.d.ts.map +1 -0
  25. package/dist/components/ListItem/index.d.ts +3 -0
  26. package/dist/components/ListItem/index.d.ts.map +1 -0
  27. package/dist/components/Radio/Radio.d.ts +45 -0
  28. package/dist/components/Radio/Radio.d.ts.map +1 -0
  29. package/dist/components/Radio/Radio.stories.d.ts +23 -0
  30. package/dist/components/Radio/Radio.stories.d.ts.map +1 -0
  31. package/dist/components/Radio/index.d.ts +3 -0
  32. package/dist/components/Radio/index.d.ts.map +1 -0
  33. package/dist/components/Switch/Switch.d.ts +39 -0
  34. package/dist/components/Switch/Switch.d.ts.map +1 -0
  35. package/dist/components/Switch/Switch.stories.d.ts +37 -0
  36. package/dist/components/Switch/Switch.stories.d.ts.map +1 -0
  37. package/dist/components/Switch/index.d.ts +3 -0
  38. package/dist/components/Switch/index.d.ts.map +1 -0
  39. package/dist/components/TextArea/TextArea.d.ts.map +1 -1
  40. package/dist/index.css +1 -1
  41. package/dist/index.d.ts +6 -0
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.esm.js +756 -23
  44. package/dist/index.esm.js.map +1 -1
  45. package/dist/index.js +765 -21
  46. package/dist/index.js.map +1 -1
  47. package/package.json +6 -2
package/dist/index.esm.js CHANGED
@@ -1,10 +1,10 @@
1
- import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
1
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import { Slot } from '@radix-ui/react-slot';
4
3
  import { cva } from 'class-variance-authority';
5
- import { PulseLoader, ClipLoader } from 'react-spinners';
6
4
  import { clsx } from 'clsx';
7
5
  import { twMerge } from 'tailwind-merge';
6
+ import { Slot } from '@radix-ui/react-slot';
7
+ import { PulseLoader, ClipLoader } from 'react-spinners';
8
8
 
9
9
  // Define patterns for custom classes that should be preserved
10
10
  // This approach is more scalable than hardcoding individual class names
@@ -45,6 +45,132 @@ function cn(...inputs) {
45
45
  return clsx(mergedStandard, customClasses);
46
46
  }
47
47
 
48
+ const badgeVariants = cva("inline-flex items-center whitespace-nowrap transition-colors", {
49
+ variants: {
50
+ variant: {
51
+ light: "",
52
+ filled: "",
53
+ },
54
+ color: {
55
+ primary: "",
56
+ positive: "",
57
+ negative: "",
58
+ notice: "",
59
+ info: "",
60
+ neutral: "",
61
+ },
62
+ size: {
63
+ small: "px-2 h-[var(--size-20)] gap-2 rounded-large text-body-small-medium",
64
+ medium: "px-3 h-[var(--size-24)] gap-3 rounded-large text-body-medium-medium",
65
+ large: "px-4 h-[var(--size-28)] gap-3 rounded-xlarge text-body-large-medium",
66
+ },
67
+ },
68
+ compoundVariants: [
69
+ // Light variant colors
70
+ {
71
+ variant: "light",
72
+ color: "primary",
73
+ class: "bg-action-fill-primary-faded text-action-ink-primary-normal",
74
+ },
75
+ {
76
+ variant: "light",
77
+ color: "positive",
78
+ class: "bg-action-fill-positive-faded text-action-ink-positive-normal",
79
+ },
80
+ {
81
+ variant: "light",
82
+ color: "negative",
83
+ class: "bg-action-fill-negative-faded text-action-ink-negative-normal",
84
+ },
85
+ {
86
+ variant: "light",
87
+ color: "notice",
88
+ class: "bg-action-fill-notice-faded text-action-ink-notice-normal",
89
+ },
90
+ {
91
+ variant: "light",
92
+ color: "info",
93
+ class: "bg-action-fill-info-faded text-action-ink-info-normal",
94
+ },
95
+ {
96
+ variant: "light",
97
+ color: "neutral",
98
+ class: "bg-action-fill-neutral-faded text-action-ink-neutral-normal",
99
+ },
100
+ // Filled variant colors
101
+ {
102
+ variant: "filled",
103
+ color: "primary",
104
+ class: "bg-action-fill-primary-default text-action-ink-on-primary-normal",
105
+ },
106
+ {
107
+ variant: "filled",
108
+ color: "positive",
109
+ class: "bg-action-fill-positive-default text-action-ink-on-primary-normal",
110
+ },
111
+ {
112
+ variant: "filled",
113
+ color: "negative",
114
+ class: "bg-action-fill-negative-default text-action-ink-on-primary-normal",
115
+ },
116
+ {
117
+ variant: "filled",
118
+ color: "notice",
119
+ class: "bg-action-fill-notice-default text-action-ink-on-primary-normal",
120
+ },
121
+ {
122
+ variant: "filled",
123
+ color: "info",
124
+ class: "bg-action-fill-info-default text-action-ink-on-primary-normal",
125
+ },
126
+ {
127
+ variant: "filled",
128
+ color: "neutral",
129
+ class: "bg-action-fill-neutral-default text-action-ink-on-primary-normal",
130
+ },
131
+ ],
132
+ defaultVariants: {
133
+ variant: "light",
134
+ color: "info",
135
+ size: "medium",
136
+ },
137
+ });
138
+ const Badge = React.forwardRef(({ className, variant, size, color, showDot = false, children, ...props }, ref) => {
139
+ const getDotColor = () => {
140
+ if (variant === "filled") {
141
+ return "bg-action-ink-on-primary-normal";
142
+ }
143
+ // Light variant - use the corresponding action color
144
+ switch (color) {
145
+ case "primary":
146
+ return "bg-action-fill-primary-default";
147
+ case "positive":
148
+ return "bg-action-fill-positive-default";
149
+ case "negative":
150
+ return "bg-action-fill-negative-default";
151
+ case "notice":
152
+ return "bg-action-fill-notice-default";
153
+ case "info":
154
+ return "bg-action-fill-info-default";
155
+ case "neutral":
156
+ return "bg-action-fill-neutral-default";
157
+ default:
158
+ return "bg-action-fill-info-default";
159
+ }
160
+ };
161
+ const getDotSize = () => {
162
+ if (size === "small") {
163
+ return "h-2 w-2";
164
+ }
165
+ if (size === "medium") {
166
+ return "h-[6px] w-[6px]";
167
+ }
168
+ return "h-3 w-3";
169
+ };
170
+ return (jsxs("div", { ref: ref, className: cn(badgeVariants({ variant, size, color }), className), ...props, children: [showDot && (jsx("span", { className: cn("rounded-full", getDotColor(), getDotSize()), "aria-hidden": "true" })), children] }));
171
+ });
172
+ Badge.displayName = "Badge";
173
+
48
174
  const buttonVariants = cva("items-center gap-3 justify-center whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none", {
49
175
  variants: {
50
176
  variant: {
@@ -492,7 +618,7 @@ function hasIcon(name) {
492
618
  return name in iconRegistry;
493
619
  }
494
620
 
495
- const checkboxVariants = cva("relative inline-flex items-center justify-center shrink-0 border transition-all cursor-pointer", {
621
+ const checkboxVariants = cva("relative inline-flex items-center justify-center shrink-0 transition-all cursor-pointer", {
496
622
  variants: {
497
623
  size: {
498
624
  small: "w-[14px] h-[14px] rounded-small border-[1.5px]",
@@ -529,7 +655,7 @@ const checkboxVariants = cva("relative inline-flex items-center justify-center s
529
655
  isChecked: true,
530
656
  validationState: "none",
531
657
  isDisabled: false,
532
- class: "bg-action-fill-primary-hover border-surface-outline-neutral-muted",
658
+ class: "bg-action-fill-primary-default hover:bg-action-fill-primary-hover hover:border-action-fill-primary-hover border-action-fill-primary-default",
533
659
  },
534
660
  // Checked or Indeterminate state - error validation
535
661
  {
@@ -565,6 +691,7 @@ const Checkbox = React.forwardRef(({ label, errorText, size = "medium", validati
565
691
  const [internalChecked, setInternalChecked] = React.useState(false);
566
692
  const [showRipple, setShowRipple] = React.useState(false);
567
693
  const inputRef = React.useRef(null);
694
+ const rippleTimeoutRef = React.useRef(null);
568
695
  // Use forwarded ref or internal ref
569
696
  React.useImperativeHandle(ref, () => inputRef.current);
570
697
  const isChecked = checked !== undefined ? checked : internalChecked;
@@ -574,6 +701,14 @@ const Checkbox = React.forwardRef(({ label, errorText, size = "medium", validati
574
701
  inputRef.current.indeterminate = isIndeterminate;
575
702
  }
576
703
  }, [isIndeterminate]);
704
+ // Cleanup timeout on unmount
705
+ React.useEffect(() => {
706
+ return () => {
707
+ if (rippleTimeoutRef.current) {
708
+ clearTimeout(rippleTimeoutRef.current);
709
+ }
710
+ };
711
+ }, []);
577
712
  const handleChange = (e) => {
578
713
  if (onChange) {
579
714
  onChange(e);
@@ -583,31 +718,28 @@ const Checkbox = React.forwardRef(({ label, errorText, size = "medium", validati
583
718
  }
584
719
  };
585
720
  const triggerRipple = () => {
586
- if (!isDisabled) {
721
+ if (!isDisabled && !showRipple) {
722
+ // Clear any existing timeout
723
+ if (rippleTimeoutRef.current) {
724
+ clearTimeout(rippleTimeoutRef.current);
725
+ }
587
726
  setShowRipple(true);
588
- setTimeout(() => {
727
+ rippleTimeoutRef.current = setTimeout(() => {
589
728
  setShowRipple(false);
590
- }, 360); // Match animation duration (0.36s)
729
+ rippleTimeoutRef.current = null;
730
+ }, 400); // Match animation duration (0.4s)
591
731
  }
592
732
  };
593
733
  const handleContainerClick = () => {
594
734
  if (!isDisabled && inputRef.current) {
595
- // Only show ripple when checking (not unchecking)
596
- const willBeChecked = !isChecked && !isIndeterminate;
597
- if (willBeChecked) {
598
- triggerRipple();
599
- }
735
+ triggerRipple();
600
736
  inputRef.current.click();
601
737
  }
602
738
  };
603
739
  const handleKeyDown = (e) => {
604
740
  if ((e.key === " " || e.key === "Enter") && !isDisabled) {
605
741
  e.preventDefault();
606
- // Only show ripple when checking (not unchecking)
607
- const willBeChecked = !isChecked && !isIndeterminate;
608
- if (willBeChecked) {
609
- triggerRipple();
610
- }
742
+ triggerRipple();
611
743
  inputRef.current?.click();
612
744
  }
613
745
  };
@@ -648,6 +780,215 @@ const Checkbox = React.forwardRef(({ label, errorText, size = "medium", validati
648
780
  });
649
781
  Checkbox.displayName = "Checkbox";
650
782
 
783
+ const counterVariants = cva("inline-flex items-center justify-center transition-colors", {
784
+ variants: {
785
+ size: {
786
+ small: "text-body-xsmall-medium rounded-small px-1 py-0.5 min-w-[20px] h-[16px]",
787
+ medium: "text-body-small-medium rounded-medium px-2 py-1 min-w-[24px] h-[20px]",
788
+ large: "text-body-medium-medium rounded-medium px-2 py-1 min-w-[28px] h-[24px]",
789
+ },
790
+ color: {
791
+ positive: "",
792
+ negative: "",
793
+ notice: "",
794
+ information: "",
795
+ neutral: "",
796
+ primary: "",
797
+ },
798
+ emphasis: {
799
+ subtle: "",
800
+ intense: "",
801
+ },
802
+ },
803
+ compoundVariants: [
804
+ // Positive - Subtle
805
+ {
806
+ color: "positive",
807
+ emphasis: "subtle",
808
+ class: "bg-feedback-fill-positive-subtle text-feedback-ink-positive-intense",
809
+ },
810
+ // Positive - Intense
811
+ {
812
+ color: "positive",
813
+ emphasis: "intense",
814
+ class: "bg-feedback-fill-positive-intense text-action-ink-on-primary-normal",
815
+ },
816
+ // Negative - Subtle
817
+ {
818
+ color: "negative",
819
+ emphasis: "subtle",
820
+ class: "bg-feedback-fill-negative-subtle text-feedback-ink-negative-subtle",
821
+ },
822
+ // Negative - Intense
823
+ {
824
+ color: "negative",
825
+ emphasis: "intense",
826
+ class: "bg-feedback-fill-negative-intense text-action-ink-on-primary-normal",
827
+ },
828
+ // Notice - Subtle
829
+ {
830
+ color: "notice",
831
+ emphasis: "subtle",
832
+ class: "bg-feedback-fill-notice-subtle text-feedback-ink-notice-subtle",
833
+ },
834
+ // Notice - Intense
835
+ {
836
+ color: "notice",
837
+ emphasis: "intense",
838
+ class: "bg-feedback-fill-notice-intense text-action-ink-on-primary-normal",
839
+ },
840
+ // Information - Subtle
841
+ {
842
+ color: "information",
843
+ emphasis: "subtle",
844
+ class: "bg-feedback-fill-info-subtle text-feedback-ink-info-subtle",
845
+ },
846
+ // Information - Intense
847
+ {
848
+ color: "information",
849
+ emphasis: "intense",
850
+ class: "bg-feedback-fill-info-intense text-action-ink-on-primary-normal",
851
+ },
852
+ // Neutral - Subtle
853
+ {
854
+ color: "neutral",
855
+ emphasis: "subtle",
856
+ class: "bg-surface-fill-neutral-subtle text-surface-ink-neutral-normal",
857
+ },
858
+ // Neutral - Intense
859
+ {
860
+ color: "neutral",
861
+ emphasis: "intense",
862
+ class: "bg-feedback-fill-neutral-intense text-action-ink-on-primary-normal",
863
+ },
864
+ // Primary - Subtle
865
+ {
866
+ color: "primary",
867
+ emphasis: "subtle",
868
+ class: "bg-surface-fill-primary-moderate text-surface-ink-primary-normal",
869
+ },
870
+ // Primary - Intense
871
+ {
872
+ color: "primary",
873
+ emphasis: "intense",
874
+ class: "bg-surface-fill-primary-intense text-action-ink-on-primary-normal",
875
+ },
876
+ ],
877
+ defaultVariants: {
878
+ size: "medium",
879
+ color: "neutral",
880
+ emphasis: "subtle",
881
+ },
882
+ });
883
+ const Counter = React.forwardRef(({ value, max, size = "medium", color = "neutral", emphasis = "subtle", className, ...props }, ref) => {
884
+ // Handle max value logic
885
+ const displayValue = React.useMemo(() => {
886
+ if (max !== undefined && typeof value === "number" && value > max) {
887
+ return `${max}+`;
888
+ }
889
+ return value;
890
+ }, [value, max]);
891
+ return (jsx("span", { ref: ref, className: cn(counterVariants({
892
+ size,
893
+ color,
894
+ emphasis,
895
+ }), className), ...props, children: displayValue }));
896
+ });
897
+ Counter.displayName = "Counter";
898
+
899
+ const dividerVariants = cva("", {
900
+ variants: {
901
+ orientation: {
902
+ horizontal: "w-full",
903
+ vertical: "h-full",
904
+ },
905
+ thickness: {
906
+ thinner: "",
907
+ thin: "",
908
+ thick: "",
909
+ thicker: "",
910
+ },
911
+ lineStyle: {
912
+ solid: "border-solid",
913
+ dashed: "border-dashed",
914
+ },
915
+ variant: {
916
+ normal: "",
917
+ subtle: "",
918
+ muted: "",
919
+ },
920
+ },
921
+ compoundVariants: [
922
+ // Horizontal orientation with thickness
923
+ {
924
+ orientation: "horizontal",
925
+ thickness: "thinner",
926
+ class: "border-t-[0.5px]",
927
+ },
928
+ {
929
+ orientation: "horizontal",
930
+ thickness: "thin",
931
+ class: "border-t-[1px]",
932
+ },
933
+ {
934
+ orientation: "horizontal",
935
+ thickness: "thick",
936
+ class: "border-t-[2px]",
937
+ },
938
+ {
939
+ orientation: "horizontal",
940
+ thickness: "thicker",
941
+ class: "border-t-[3px]",
942
+ },
943
+ // Vertical orientation with thickness
944
+ {
945
+ orientation: "vertical",
946
+ thickness: "thinner",
947
+ class: "border-l-[0.5px]",
948
+ },
949
+ {
950
+ orientation: "vertical",
951
+ thickness: "thin",
952
+ class: "border-l-[1px]",
953
+ },
954
+ {
955
+ orientation: "vertical",
956
+ thickness: "thick",
957
+ class: "border-l-[2px]",
958
+ },
959
+ {
960
+ orientation: "vertical",
961
+ thickness: "thicker",
962
+ class: "border-l-[3px]",
963
+ },
964
+ // Normal variant colors
965
+ {
966
+ variant: "normal",
967
+ class: "border-surface-outline-neutral-normal",
968
+ },
969
+ // Subtle variant colors
970
+ {
971
+ variant: "subtle",
972
+ class: "border-surface-outline-neutral-subtle",
973
+ },
974
+ // Muted variant colors
975
+ {
976
+ variant: "muted",
977
+ class: "border-surface-outline-neutral-muted",
978
+ },
979
+ ],
980
+ defaultVariants: {
981
+ orientation: "horizontal",
982
+ thickness: "thin",
983
+ lineStyle: "solid",
984
+ variant: "normal",
985
+ },
986
+ });
987
+ const Divider = React.forwardRef(({ className, orientation = "horizontal", thickness = "thin", lineStyle = "solid", variant = "normal", ...props }, ref) => {
988
+ return (jsx("div", { ref: ref, role: "separator", "aria-orientation": orientation, className: cn(dividerVariants({ orientation, thickness, lineStyle, variant }), className), ...props }));
989
+ });
990
+ Divider.displayName = "Divider";
991
+
651
992
  const tooltipVariants = cva("fixed z-50 bg-popup-fill-intense text-action-ink-on-primary-normal rounded-medium border border-popup-outline-subtle flex flex-col p-4 rounded-xlarge min-w-[200px] max-w-[300px] transition-opacity duration-200", {
652
993
  variants: {
653
994
  isVisible: {
@@ -902,6 +1243,389 @@ const FormHeader = React.forwardRef(({ label, size = "medium", isOptional = fals
902
1243
  });
903
1244
  FormHeader.displayName = "FormHeader";
904
1245
 
1246
+ const listItemVariants = cva("flex items-start gap-3 p-3 rounded-medium transition-colors cursor-pointer", {
1247
+ variants: {
1248
+ variant: {
1249
+ default: `hover:bg-action-fill-neutral-faded
1250
+ focus:bg-action-fill-neutral-faded
1251
+ focus:ring-2
1252
+ ring-action-outline-primary-faded-hover
1253
+ border border-transparent
1254
+ `,
1255
+ bordered: "border border-action-outline-primary-faded hover:bg-surface-fill-primary-subtle",
1256
+ primary: `hover:bg-action-fill-neutral-faded
1257
+ focus:bg-action-fill-neutral-faded
1258
+ focus:ring-2
1259
+ ring-action-outline-primary-faded-hover
1260
+ border border-transparent
1261
+ `,
1262
+ negative: `hover:bg-action-fill-negative-faded
1263
+ focus:bg-action-fill-negative-faded
1264
+ focus:ring-2 ring-action-outline-negative-faded-hover
1265
+ border border-transparent
1266
+ `,
1267
+ },
1268
+ isDisabled: {
1269
+ true: "cursor-not-allowed opacity-60",
1270
+ false: "",
1271
+ },
1272
+ isSelected: {
1273
+ true: "bg-action-fill-primary-faded border-action-outline-primary-faded",
1274
+ false: "",
1275
+ },
1276
+ },
1277
+ defaultVariants: {
1278
+ variant: "default",
1279
+ isDisabled: false,
1280
+ isSelected: false,
1281
+ },
1282
+ });
1283
+ const ChevronRightIcon = ({ className }) => (jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", className: className, children: jsx("path", { d: "M7.5 15L12.5 10L7.5 5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }));
1284
+ const ListItem = React.forwardRef(({ className, type = "single", leadingIcon, title, description, trailingIcon, showChevron = true, variant = "default", isDisabled = false, isSelected = false, onSelectionChange, checkboxSize = "small", containerClassName, contentClassName, onClick, ...props }, ref) => {
1285
+ const [internalSelected, setInternalSelected] = React.useState(isSelected);
1286
+ // Sync internal state with prop
1287
+ React.useEffect(() => {
1288
+ setInternalSelected(isSelected);
1289
+ }, [isSelected]);
1290
+ const handleClick = (e) => {
1291
+ if (isDisabled)
1292
+ return;
1293
+ if (type === "multiple") {
1294
+ const newSelected = !internalSelected;
1295
+ setInternalSelected(newSelected);
1296
+ onSelectionChange?.(newSelected);
1297
+ }
1298
+ onClick?.(e);
1299
+ };
1300
+ const handleCheckboxChange = (e) => {
1301
+ e.stopPropagation();
1302
+ if (isDisabled)
1303
+ return;
1304
+ const newSelected = e.target.checked;
1305
+ setInternalSelected(newSelected);
1306
+ onSelectionChange?.(newSelected);
1307
+ };
1308
+ return (jsxs("div", { ref: ref, className: cn(listItemVariants({
1309
+ variant,
1310
+ isDisabled,
1311
+ isSelected: type === "multiple" ? internalSelected : false,
1312
+ }), containerClassName), onClick: handleClick, role: type === "multiple" ? "checkbox" : "button", "aria-checked": type === "multiple" ? internalSelected : undefined, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, ...props, children: [type === "multiple" && (jsx(Checkbox, { checked: internalSelected, onChange: handleCheckboxChange, isDisabled: isDisabled, size: checkboxSize, className: "shrink-0 mt-0.5" })), leadingIcon && (jsx("div", { className: cn(`shrink-0 flex items-center justify-center mt-0.5`, variant === "primary"
1313
+ ? "text-action-ink-primary-normal"
1314
+ : variant === "negative"
1315
+ ? "text-action-ink-negative-normal"
1316
+ : "text-action-ink-neutral-subtle", isDisabled && "text-surface-ink-neutral-disabled"), children: leadingIcon })), jsxs("div", { className: cn("flex-1 min-w-0 flex flex-col justify-center", contentClassName), children: [jsx("div", { className: cn("text-body-medium-regular truncate", variant === "primary"
1317
+ ? "text-action-ink-primary-normal"
1318
+ : variant === "negative"
1319
+ ? "text-action-ink-negative-normal"
1320
+ : "text-action-ink-neutral-normal", isDisabled && "text-surface-ink-neutral-disabled"), children: title }), description && (jsx("div", { className: cn("text-body-small-regular text-surface-ink-neutral-muted mt-0.5 line-clamp-2", isDisabled && "text-surface-ink-neutral-disabled"), children: description }))] }), (trailingIcon || showChevron) && (jsx("div", { className: "shrink-0 self-center text-action-ink-neutral-subtle", children: trailingIcon || jsx(ChevronRightIcon, {}) }))] }));
1321
+ });
1322
+ ListItem.displayName = "ListItem";
1323
+
1324
+ const radioVariants = cva("relative inline-flex items-center justify-center shrink-0 border transition-all cursor-pointer rounded-full", {
1325
+ variants: {
1326
+ size: {
1327
+ small: "w-[14px] h-[14px] border-[1.5px]",
1328
+ medium: "w-[16px] h-[16px] border-[1.5px]",
1329
+ large: "w-[20px] h-[20px] border-[2px]",
1330
+ },
1331
+ validationState: {
1332
+ none: "",
1333
+ error: "border-action-outline-negative-default hover:border-action-outline-negative-hover",
1334
+ },
1335
+ isChecked: {
1336
+ true: "",
1337
+ false: "",
1338
+ },
1339
+ isDisabled: {
1340
+ true: "cursor-not-allowed opacity-60 border-action-outline-neutral-disabled bg-surface-fill-neutral-subtle",
1341
+ false: "",
1342
+ },
1343
+ isFocused: {
1344
+ true: "",
1345
+ false: "",
1346
+ },
1347
+ },
1348
+ compoundVariants: [
1349
+ // Unchecked state - none validation
1350
+ {
1351
+ isChecked: false,
1352
+ validationState: "none",
1353
+ isDisabled: false,
1354
+ class: `border-action-outline-neutral-faded
1355
+ hover:bg-action-fill-neutral-faded
1356
+ hover:border-action-outline-neutral-faded
1357
+ `,
1358
+ },
1359
+ // Checked state - none validation
1360
+ {
1361
+ isChecked: true,
1362
+ validationState: "none",
1363
+ isDisabled: false,
1364
+ class: "bg-action-fill-primary-default hover:bg-action-fill-primary-hover border-action-fill-primary-default hover:border-action-fill-primary-hover",
1365
+ },
1366
+ // Checked state - error validation
1367
+ {
1368
+ isChecked: true,
1369
+ validationState: "error",
1370
+ isDisabled: false,
1371
+ class: "bg-action-fill-negative-default hover:bg-action-fill-negative-hover border-action-fill-negative-default hover:border-action-fill-negative-hover",
1372
+ },
1373
+ // Focused state - none validation
1374
+ {
1375
+ isFocused: true,
1376
+ validationState: "none",
1377
+ isDisabled: false,
1378
+ class: "ring-2 ring-action-outline-primary-faded",
1379
+ },
1380
+ // Focused state - error validation
1381
+ {
1382
+ isFocused: true,
1383
+ validationState: "error",
1384
+ isDisabled: false,
1385
+ class: "ring-2 ring-action-outline-negative-faded",
1386
+ },
1387
+ ],
1388
+ defaultVariants: {
1389
+ size: "medium",
1390
+ validationState: "none",
1391
+ isChecked: false,
1392
+ isDisabled: false,
1393
+ isFocused: false,
1394
+ },
1395
+ });
1396
+ const Radio = React.forwardRef(({ label, errorText, size = "medium", validationState = "none", isDisabled = false, showErrorText = true, containerClassName, labelClassName, className, checked, onChange, ...props }, ref) => {
1397
+ const [internalChecked, setInternalChecked] = React.useState(false);
1398
+ const [showRipple, setShowRipple] = React.useState(false);
1399
+ const [isFocused, setIsFocused] = React.useState(false);
1400
+ const inputRef = React.useRef(null);
1401
+ // Use forwarded ref or internal ref
1402
+ React.useImperativeHandle(ref, () => inputRef.current);
1403
+ const isChecked = checked !== undefined ? checked : internalChecked;
1404
+ const handleChange = (e) => {
1405
+ if (onChange) {
1406
+ onChange(e);
1407
+ }
1408
+ else {
1409
+ setInternalChecked(e.target.checked);
1410
+ }
1411
+ };
1412
+ const triggerRipple = () => {
1413
+ if (!isDisabled) {
1414
+ setShowRipple(true);
1415
+ setTimeout(() => {
1416
+ setShowRipple(false);
1417
+ }, 360); // Match animation duration (0.36s)
1418
+ }
1419
+ };
1420
+ const handleContainerClick = () => {
1421
+ if (!isDisabled && inputRef.current) {
1422
+ // Only show ripple when checking (not unchecking)
1423
+ const willBeChecked = !isChecked;
1424
+ if (willBeChecked) {
1425
+ triggerRipple();
1426
+ }
1427
+ inputRef.current.click();
1428
+ }
1429
+ };
1430
+ const handleKeyDown = (e) => {
1431
+ if ((e.key === " " || e.key === "Enter") && !isDisabled) {
1432
+ e.preventDefault();
1433
+ // Only show ripple when checking (not unchecking)
1434
+ const willBeChecked = !isChecked;
1435
+ if (willBeChecked) {
1436
+ triggerRipple();
1437
+ }
1438
+ inputRef.current?.click();
1439
+ }
1440
+ };
1441
+ const handleFocus = () => {
1442
+ if (!isDisabled) {
1443
+ setIsFocused(true);
1444
+ }
1445
+ };
1446
+ const handleBlur = () => {
1447
+ setIsFocused(false);
1448
+ };
1449
+ // Size-based configurations
1450
+ const sizeConfig = {
1451
+ small: {
1452
+ gap: "gap-2",
1453
+ labelSize: "text-body-small-regular",
1454
+ innerCircleSize: 6,
1455
+ },
1456
+ medium: {
1457
+ gap: "gap-2.5",
1458
+ labelSize: "text-body-medium-regular",
1459
+ innerCircleSize: 7,
1460
+ },
1461
+ large: {
1462
+ gap: "gap-3",
1463
+ labelSize: "text-body-large-regular",
1464
+ innerCircleSize: 8,
1465
+ },
1466
+ };
1467
+ const config = sizeConfig[size];
1468
+ // Determine if we should show the error text
1469
+ const shouldShowError = errorText && showErrorText;
1470
+ return (jsxs("div", { className: cn("inline-flex flex-col", containerClassName), children: [jsxs("div", { className: cn("inline-flex items-center", config.gap, isDisabled ? "cursor-not-allowed" : "cursor-pointer"), onClick: handleContainerClick, onKeyDown: handleKeyDown, onFocus: handleFocus, onBlur: handleBlur, role: "radio", "aria-checked": isChecked, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, children: [jsx("input", { ref: inputRef, type: "radio", className: "sr-only", checked: isChecked, onChange: handleChange, disabled: isDisabled, ...props }), jsxs("div", { className: "relative inline-flex shrink-0", children: [showRipple && (jsx("div", { className: cn("absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full pointer-events-none w-full h-full", validationState === "error"
1471
+ ? "bg-action-outline-negative-faded"
1472
+ : "bg-action-outline-primary-faded"), style: {
1473
+ animation: "var(--animate-checkbox-ripple)",
1474
+ } })), jsx("div", { className: cn(radioVariants({
1475
+ size,
1476
+ validationState,
1477
+ isChecked,
1478
+ isDisabled,
1479
+ isFocused,
1480
+ }), className), children: isChecked && (jsx("div", { className: "rounded-full bg-white transition-all", style: {
1481
+ width: `${config.innerCircleSize}px`,
1482
+ height: `${config.innerCircleSize}px`,
1483
+ } })) })] }), label && (jsx("label", { className: cn(config.labelSize, "select-none inline-flex items-center", isDisabled
1484
+ ? "text-surface-ink-neutral-disabled"
1485
+ : "text-surface-ink-neutral-normal", labelClassName), children: label }))] }), shouldShowError && (jsx(FormFooter, { helperText: errorText, validationState: "negative", size: size, isDisabled: isDisabled }))] }));
1486
+ });
1487
+ Radio.displayName = "Radio";
1488
+
1489
+ const switchVariants = cva("relative inline-flex items-center shrink-0 cursor-pointer rounded-full transition-all duration-200", {
1490
+ variants: {
1491
+ size: {
1492
+ small: "w-[20px] h-[12px]",
1493
+ medium: "w-[28px] h-[16px]",
1494
+ large: "w-[36px] h-[20px]",
1495
+ },
1496
+ isChecked: {
1497
+ true: "bg-action-fill-primary-default ",
1498
+ false: "bg-surface-fill-neutral-subtle",
1499
+ },
1500
+ isDisabled: {
1501
+ true: "cursor-not-allowed opacity-60",
1502
+ false: "",
1503
+ },
1504
+ },
1505
+ compoundVariants: [
1506
+ {
1507
+ isChecked: true,
1508
+ isDisabled: false,
1509
+ class: "hover:bg-action-fill-primary-hover ",
1510
+ },
1511
+ {
1512
+ isChecked: false,
1513
+ isDisabled: false,
1514
+ class: "hover:bg-action-fill-neutral-faded",
1515
+ },
1516
+ ],
1517
+ defaultVariants: {
1518
+ size: "medium",
1519
+ isChecked: false,
1520
+ isDisabled: false,
1521
+ },
1522
+ });
1523
+ const switchThumbVariants = cva("inline-block rounded-full bg-neutral-00 shadow-sm transition-transform duration-200", {
1524
+ variants: {
1525
+ size: {
1526
+ small: "h-[8px] w-[8px]",
1527
+ medium: "h-[12px] w-[12px]",
1528
+ large: "h-[16px] w-[16px]",
1529
+ },
1530
+ isChecked: {
1531
+ true: "",
1532
+ false: "",
1533
+ },
1534
+ },
1535
+ compoundVariants: [
1536
+ // Small size translations
1537
+ {
1538
+ size: "small",
1539
+ isChecked: false,
1540
+ class: "translate-x-[2px]",
1541
+ },
1542
+ {
1543
+ size: "small",
1544
+ isChecked: true,
1545
+ class: "translate-x-[10px]",
1546
+ },
1547
+ // Medium size translations
1548
+ {
1549
+ size: "medium",
1550
+ isChecked: false,
1551
+ class: "translate-x-[2px]",
1552
+ },
1553
+ {
1554
+ size: "medium",
1555
+ isChecked: true,
1556
+ class: "translate-x-[14px]",
1557
+ },
1558
+ // Large size translations
1559
+ {
1560
+ size: "large",
1561
+ isChecked: false,
1562
+ class: "translate-x-[2px]",
1563
+ },
1564
+ {
1565
+ size: "large",
1566
+ isChecked: true,
1567
+ class: "translate-x-[18px]",
1568
+ },
1569
+ ],
1570
+ defaultVariants: {
1571
+ size: "medium",
1572
+ isChecked: false,
1573
+ },
1574
+ });
1575
+ const Switch = React.forwardRef(({ label, size = "medium", isDisabled = false, containerClassName, labelClassName, trackClassName, thumbClassName, className, checked, onChange, ...props }, ref) => {
1576
+ const [internalChecked, setInternalChecked] = React.useState(false);
1577
+ const inputRef = React.useRef(null);
1578
+ // Use forwarded ref or internal ref
1579
+ React.useImperativeHandle(ref, () => inputRef.current);
1580
+ const isChecked = checked !== undefined ? checked : internalChecked;
1581
+ const handleChange = (e) => {
1582
+ if (onChange) {
1583
+ onChange(e);
1584
+ }
1585
+ else {
1586
+ setInternalChecked(e.target.checked);
1587
+ }
1588
+ };
1589
+ const handleContainerClick = () => {
1590
+ if (!isDisabled && inputRef.current) {
1591
+ inputRef.current.click();
1592
+ }
1593
+ };
1594
+ const handleKeyDown = (e) => {
1595
+ if ((e.key === " " || e.key === "Enter") && !isDisabled) {
1596
+ e.preventDefault();
1597
+ inputRef.current?.click();
1598
+ }
1599
+ };
1600
+ // Size-based configurations
1601
+ const sizeConfig = {
1602
+ small: {
1603
+ gap: "gap-2",
1604
+ labelSize: "text-body-small-regular",
1605
+ },
1606
+ medium: {
1607
+ gap: "gap-2.5",
1608
+ labelSize: "text-body-medium-regular",
1609
+ },
1610
+ large: {
1611
+ gap: "gap-3",
1612
+ labelSize: "text-body-large-regular",
1613
+ },
1614
+ };
1615
+ const config = sizeConfig[size];
1616
+ return (jsx("div", { className: cn("inline-flex flex-col", containerClassName), children: jsxs("div", { className: cn("inline-flex items-center", config.gap, isDisabled ? "cursor-not-allowed" : "cursor-pointer"), onClick: handleContainerClick, onKeyDown: handleKeyDown, role: "switch", "aria-checked": isChecked, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, children: [jsx("input", { ref: inputRef, type: "checkbox", role: "switch", className: "sr-only", checked: isChecked, onChange: handleChange, disabled: isDisabled, ...props }), jsx("div", { className: "relative inline-flex shrink-0", children: jsx("div", { className: cn(switchVariants({
1617
+ size,
1618
+ isChecked,
1619
+ isDisabled,
1620
+ }), trackClassName, className, "focus-visible:ring-2 focus-visible:ring-action-outline-primary-faded focus-visible:ring-offset-2"), children: jsx("span", { className: cn(switchThumbVariants({
1621
+ size,
1622
+ isChecked,
1623
+ }), thumbClassName) }) }) }), label && (jsx("label", { className: cn(config.labelSize, "select-none inline-flex items-center", isDisabled
1624
+ ? "text-surface-ink-neutral-disabled"
1625
+ : "text-surface-ink-neutral-normal", labelClassName), children: label }))] }) }));
1626
+ });
1627
+ Switch.displayName = "Switch";
1628
+
905
1629
  const textAreaVariants = cva("relative flex flex-col border rounded-medium transition-all font-display font-size-100 leading-100", {
906
1630
  variants: {
907
1631
  size: {
@@ -911,19 +1635,17 @@ const textAreaVariants = cva("relative flex flex-col border rounded-medium trans
911
1635
  },
912
1636
  validationState: {
913
1637
  none: `
914
- border-action-outline-neutral-default
1638
+ border-action-outline-neutral-faded
915
1639
  hover:border-action-outline-primary-hover
916
1640
  focus-within:border-action-outline-primary-hover
917
1641
  focus-within:ring-2
918
1642
  ring-action-outline-primary-faded-hover`,
919
1643
  positive: `
920
1644
  border-action-outline-positive-default
921
- hover:border-action-outline-positive-hover
922
1645
  focus-within:border-action-outline-positive-hover
923
1646
  focus-within:ring-2
924
1647
  ring-action-outline-positive-faded-hover`,
925
1648
  negative: `border-action-outline-negative-default
926
- hover:border-action-outline-negative-hover
927
1649
  focus-within:border-action-outline-negative-hover
928
1650
  focus-within:ring-2
929
1651
  ring-action-outline-negative-faded-hover`,
@@ -970,7 +1692,18 @@ const TextArea = React.forwardRef(({ label, helperText, errorText, successText,
970
1692
  // Check if we're approaching or at the limit
971
1693
  const isNearLimit = maxChar && currentLength >= maxChar * 0.9;
972
1694
  const isAtLimit = maxChar && currentLength >= maxChar;
973
- return (jsxs("div", { className: cn("w-full flex flex-col gap-3", containerClassName), children: [label && (jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: infoHeading, infoDescription: infoDescription, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsx("div", { className: cn(textAreaVariants({
1695
+ const sizeConfig = {
1696
+ small: {
1697
+ gap: "gap-2",
1698
+ },
1699
+ medium: {
1700
+ gap: "gap-2",
1701
+ },
1702
+ large: {
1703
+ gap: "gap-3",
1704
+ },
1705
+ };
1706
+ return (jsxs("div", { className: cn("w-full flex flex-col", sizeConfig[size].gap, containerClassName), children: [label && (jsx(FormHeader, { label: label, size: size, isRequired: isRequired, isOptional: isOptional, infoHeading: infoHeading, infoDescription: infoDescription, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsx("div", { className: cn(textAreaVariants({
974
1707
  size,
975
1708
  validationState: currentValidationState,
976
1709
  isDisabled,
@@ -1088,5 +1821,5 @@ const TextField = React.forwardRef(({ label, helperText, errorText, successText,
1088
1821
  });
1089
1822
  TextField.displayName = "TextField";
1090
1823
 
1091
- export { Button, Checkbox, FormFooter, FormHeader, Icon, Text, TextArea, TextField, Tooltip, buttonVariants, checkboxVariants, cn, getAvailableIcons, hasIcon, iconRegistry, textAreaVariants, textFieldVariants, tooltipVariants };
1824
+ export { Badge, Button, Checkbox, Counter, Divider, FormFooter, FormHeader, Icon, ListItem, Radio, Switch, Text, TextArea, TextField, Tooltip, badgeVariants, buttonVariants, checkboxVariants, cn, counterVariants, getAvailableIcons, hasIcon, iconRegistry, listItemVariants, radioVariants, switchVariants, textAreaVariants, textFieldVariants, tooltipVariants };
1092
1825
  //# sourceMappingURL=index.esm.js.map