infinity-ui-elements 1.8.58 → 1.8.60

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.esm.js CHANGED
@@ -5,7 +5,7 @@ import { Slot } from '@radix-ui/react-slot';
5
5
  import { PulseLoader, ClipLoader } from 'react-spinners';
6
6
  import { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
8
- import { ExternalLink, Calendar, X, Loader2, Search, ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react';
8
+ import { ExternalLink, Calendar, X, Loader2, Search, ChevronLeft, ChevronRight, ChevronDown } from 'lucide-react';
9
9
  import { createPortal } from 'react-dom';
10
10
  import Calendar$1 from 'react-calendar';
11
11
  import 'react-calendar/dist/Calendar.css';
@@ -38,9 +38,10 @@ import { flexRender } from '@tanstack/react-table';
38
38
  */
39
39
  const iconRegistry = {
40
40
  // Tick/Check icon
41
- tick: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
42
- <path d="M10.364 15.1924L19.5564 6L20.9706 7.41421L10.364 18.0208L4 11.6569L5.41422 10.2427L10.364 15.1924Z" fill="#081416"/>
43
- </svg>`,
41
+ tick: `<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
42
+ <path d="M7.99907 1.77063L8.63188 2.42981L8.69829 2.49915L8.63188 2.56848L3.88188 7.50891L3.80962 7.58411L3.73833 7.50891L0.887741 4.54504L0.821335 4.47571L0.887741 4.40637L1.52153 3.74719L1.5938 3.672L1.66508 3.74719L3.80962 5.97766L7.85454 1.77063L7.9268 1.69543L7.99907 1.77063Z" fill="white" stroke="white" stroke-width="0.2"/>
43
+ </svg>
44
+ `,
44
45
  // Alias: check points to the same icon as tick
45
46
  check: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
46
47
  <path d="M10.364 15.1924L19.5564 6L20.9706 7.41421L10.364 18.0208L4 11.6569L5.41422 10.2427L10.364 15.1924Z" fill="#081416"/>
@@ -68,6 +69,14 @@ const iconRegistry = {
68
69
  file: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
69
70
  <path d="M19.1111 21H4.88889C4.39797 21 4 20.5971 4 20.1V3.9C4 3.40295 4.39797 3 4.88889 3H19.1111C19.602 3 20 3.40295 20 3.9V20.1C20 20.5971 19.602 21 19.1111 21ZM18.2222 19.2V4.8H5.77778V19.2H18.2222ZM8.44444 9.3H15.5556V11.1H8.44444V9.3ZM8.44444 12.9H15.5556V14.7H8.44444V12.9Z" fill="#081416"/>
70
71
  </svg>
72
+ `,
73
+ chevronDown: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
74
+ <path d="M12 13.7272L17.4445 8L19 9.63635L12 17L5 9.63635L6.55555 8L12 13.7272Z" fill="#081416"/>
75
+ </svg>
76
+ `,
77
+ chevronUp: `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
78
+ <path d="M12 11.2727L6.55555 17L5 15.3637L12 8L19 15.3637L17.4445 17L12 11.2727Z" fill="#081416"/>
79
+ </svg>
71
80
  `,
72
81
  };
73
82
  const Icon = ({ name, size = 24, className = "", style = {}, ...props }) => {
@@ -1485,9 +1494,9 @@ FormFooter.displayName = "FormFooter";
1485
1494
  const checkboxVariants = cva("relative inline-flex items-center justify-center shrink-0 transition-all cursor-pointer box-border", {
1486
1495
  variants: {
1487
1496
  size: {
1488
- small: "w-[10px] h-[10px] rounded-small border-[1.5px]",
1489
- medium: "w-[12px] h-[12px] rounded-small border-[1.5px]",
1490
- large: "w-[16px] h-[16px] rounded-medium border-[2px]",
1497
+ small: "w-[14px] h-[14px] rounded-small border-[1.5px]",
1498
+ medium: "w-[16px] h-[16px] rounded-small border-[1.5px]",
1499
+ large: "w-[20px] h-[20px] rounded-medium border-[2px]",
1491
1500
  },
1492
1501
  validationState: {
1493
1502
  none: "",
@@ -1555,7 +1564,6 @@ const Checkbox = React.forwardRef(({ label, errorText, size = "medium", validati
1555
1564
  const [internalChecked, setInternalChecked] = React.useState(false);
1556
1565
  const [showRipple, setShowRipple] = React.useState(false);
1557
1566
  const inputRef = React.useRef(null);
1558
- const rippleTimeoutRef = React.useRef(null);
1559
1567
  // Use forwarded ref or internal ref
1560
1568
  React.useImperativeHandle(ref, () => inputRef.current);
1561
1569
  const isChecked = checked !== undefined ? checked : internalChecked;
@@ -1565,14 +1573,6 @@ const Checkbox = React.forwardRef(({ label, errorText, size = "medium", validati
1565
1573
  inputRef.current.indeterminate = isIndeterminate;
1566
1574
  }
1567
1575
  }, [isIndeterminate]);
1568
- // Cleanup timeout on unmount
1569
- React.useEffect(() => {
1570
- return () => {
1571
- if (rippleTimeoutRef.current) {
1572
- clearTimeout(rippleTimeoutRef.current);
1573
- }
1574
- };
1575
- }, []);
1576
1576
  const handleChange = (e) => {
1577
1577
  if (onChange) {
1578
1578
  onChange(e);
@@ -1582,28 +1582,31 @@ const Checkbox = React.forwardRef(({ label, errorText, size = "medium", validati
1582
1582
  }
1583
1583
  };
1584
1584
  const triggerRipple = () => {
1585
- if (!isDisabled && !showRipple) {
1586
- // Clear any existing timeout
1587
- if (rippleTimeoutRef.current) {
1588
- clearTimeout(rippleTimeoutRef.current);
1589
- }
1585
+ if (!isDisabled) {
1590
1586
  setShowRipple(true);
1591
- rippleTimeoutRef.current = setTimeout(() => {
1587
+ setTimeout(() => {
1592
1588
  setShowRipple(false);
1593
- rippleTimeoutRef.current = null;
1594
- }, 400); // Match animation duration (0.4s)
1589
+ }, 360); // Match animation duration (0.36s)
1595
1590
  }
1596
1591
  };
1597
1592
  const handleContainerClick = () => {
1598
1593
  if (!isDisabled && inputRef.current) {
1599
- triggerRipple();
1594
+ // Only show ripple when checking or entering indeterminate state (not unchecking)
1595
+ const willBeChecked = !isChecked || isIndeterminate;
1596
+ if (willBeChecked) {
1597
+ triggerRipple();
1598
+ }
1600
1599
  inputRef.current.click();
1601
1600
  }
1602
1601
  };
1603
1602
  const handleKeyDown = (e) => {
1604
1603
  if ((e.key === " " || e.key === "Enter") && !isDisabled) {
1605
1604
  e.preventDefault();
1606
- triggerRipple();
1605
+ // Only show ripple when checking or entering indeterminate state (not unchecking)
1606
+ const willBeChecked = !isChecked || isIndeterminate;
1607
+ if (willBeChecked) {
1608
+ triggerRipple();
1609
+ }
1607
1610
  inputRef.current?.click();
1608
1611
  }
1609
1612
  };
@@ -1612,23 +1615,23 @@ const Checkbox = React.forwardRef(({ label, errorText, size = "medium", validati
1612
1615
  small: {
1613
1616
  gap: "gap-2",
1614
1617
  labelSize: "text-body-small-regular",
1615
- iconSize: 10,
1618
+ iconSize: 7,
1616
1619
  },
1617
1620
  medium: {
1618
1621
  gap: "gap-2",
1619
1622
  labelSize: "text-body-small-regular",
1620
- iconSize: 12,
1623
+ iconSize: 9.6,
1621
1624
  },
1622
1625
  large: {
1623
1626
  gap: "gap-3",
1624
1627
  labelSize: "text-body-medium-regular",
1625
- iconSize: 14,
1628
+ iconSize: 13.33,
1626
1629
  },
1627
1630
  };
1628
1631
  const config = sizeConfig[size];
1629
1632
  // Determine if we should show the error text
1630
1633
  const shouldShowError = errorText && showErrorText;
1631
- return (jsxs("div", { className: cn("inline-flex flex-col px-2", containerClassName), children: [jsxs("div", { className: cn("inline-flex items-center", config.gap, isDisabled ? "cursor-not-allowed" : "cursor-pointer"), onClick: handleContainerClick, onKeyDown: handleKeyDown, role: "checkbox", "aria-checked": isIndeterminate ? "mixed" : isChecked, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, children: [jsx("input", { ref: inputRef, type: "checkbox", 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"
1634
+ return (jsxs("div", { className: cn("inline-flex flex-col py-0.5", containerClassName), children: [jsxs("div", { className: cn("inline-flex items-center", config.gap, isDisabled ? "cursor-not-allowed" : "cursor-pointer"), onClick: handleContainerClick, onKeyDown: handleKeyDown, role: "checkbox", "aria-checked": isIndeterminate ? "mixed" : isChecked, "aria-disabled": isDisabled, tabIndex: isDisabled ? -1 : 0, children: [jsx("input", { ref: inputRef, type: "checkbox", 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"
1632
1635
  ? "bg-action-outline-negative-faded"
1633
1636
  : "bg-action-outline-primary-faded"), style: {
1634
1637
  animation: "var(--animate-checkbox-ripple)",
@@ -2830,7 +2833,7 @@ const Modal = React.forwardRef(({ isOpen, onClose, title, description, footer, c
2830
2833
  });
2831
2834
  Modal.displayName = "Modal";
2832
2835
 
2833
- const selectVariants = cva("relative flex items-center gap-2 border rounded-large transition-all font-functional font-size-100 leading-100", {
2836
+ const textFieldVariants = cva("relative flex items-center gap-3 border rounded-large transition-all font-functional font-size-100 leading-100", {
2834
2837
  variants: {
2835
2838
  size: {
2836
2839
  small: "h-[28px] px-3 text-xs gap-2",
@@ -2840,10 +2843,11 @@ const selectVariants = cva("relative flex items-center gap-2 border rounded-larg
2840
2843
  validationState: {
2841
2844
  none: `
2842
2845
  border-action-outline-neutral-faded
2843
- hover:border-action-outline-primary-hover
2844
- focus-within:border-action-outline-primary-hover
2846
+ hover:border-action-outline-neutral-faded-hover
2847
+ hover:bg-action-fill-neutral-faded-hover
2848
+ focus-within:border-action-outline-primary-default
2845
2849
  focus-within:ring-2
2846
- ring-action-outline-primary-faded-hover`,
2850
+ ring-surface-outline-primary-muted`,
2847
2851
  positive: `
2848
2852
  border-action-outline-positive-default
2849
2853
  focus-within:border-action-outline-positive-hover
@@ -2856,11 +2860,13 @@ const selectVariants = cva("relative flex items-center gap-2 border rounded-larg
2856
2860
  },
2857
2861
  isDisabled: {
2858
2862
  true: `
2859
- border-[var(--border-width-thinner)]
2860
- hover:border-action-outline-neutral-disabled
2863
+ border
2861
2864
  border-action-outline-neutral-disabled
2862
- bg-surface-fill-neutral-intense cursor-not-allowed opacity-60`,
2863
- false: "bg-surface-fill-neutral-intense",
2865
+ hover:border-action-outline-neutral-disabled
2866
+ bg-surface-fill-neutral-intense
2867
+ hover:bg-surface-fill-neutral-intense
2868
+ cursor-not-allowed`,
2869
+ false: "",
2864
2870
  },
2865
2871
  },
2866
2872
  defaultVariants: {
@@ -2869,23 +2875,83 @@ const selectVariants = cva("relative flex items-center gap-2 border rounded-larg
2869
2875
  isDisabled: false,
2870
2876
  },
2871
2877
  });
2878
+ const TextField = React.forwardRef(({ label, helperText, errorText, successText, size = "medium", validationState = "none", isDisabled = false, isLoading = false, isRequired = false, isOptional = false, prefix, suffix, showClearButton = false, infoDescription, infoHeading, LinkComponent, linkText, linkHref, onLinkClick, onClear, containerClassName, labelClassName, inputClassName, className, value, onChange, ...props }, ref) => {
2879
+ const [internalValue, setInternalValue] = React.useState("");
2880
+ const inputValue = value !== undefined ? value : internalValue;
2881
+ const hasValue = inputValue && String(inputValue).length > 0;
2882
+ const handleChange = (e) => {
2883
+ if (onChange) {
2884
+ onChange(e);
2885
+ }
2886
+ else {
2887
+ setInternalValue(e.target.value);
2888
+ }
2889
+ };
2890
+ const handleClear = () => {
2891
+ if (onClear) {
2892
+ onClear();
2893
+ }
2894
+ else {
2895
+ setInternalValue("");
2896
+ }
2897
+ // Focus the input after clearing
2898
+ const input = document.getElementById(props.id || "");
2899
+ if (input) {
2900
+ input.focus();
2901
+ }
2902
+ };
2903
+ // Determine which helper text to show
2904
+ const displayHelperText = errorText || successText || helperText;
2905
+ const currentValidationState = errorText
2906
+ ? "negative"
2907
+ : successText
2908
+ ? "positive"
2909
+ : validationState;
2910
+ const sizeConfig = {
2911
+ small: {
2912
+ gap: "gap-2",
2913
+ },
2914
+ medium: {
2915
+ gap: "gap-2",
2916
+ },
2917
+ large: {
2918
+ gap: "gap-3",
2919
+ },
2920
+ };
2921
+ 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, LinkComponent: LinkComponent, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsxs("div", { className: cn(textFieldVariants({
2922
+ size,
2923
+ validationState: currentValidationState,
2924
+ isDisabled,
2925
+ }), isLoading && "text-field-loading", className), children: [prefix && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
2926
+ ? "text-surface-ink-neutral-disabled"
2927
+ : currentValidationState === "positive"
2928
+ ? "text-feedback-ink-positive-intense"
2929
+ : currentValidationState === "negative"
2930
+ ? "text-feedback-ink-negative-subtle"
2931
+ : "text-surface-ink-neutral-muted"), children: prefix })), jsx("input", { ref: ref, value: inputValue, onChange: handleChange, disabled: isDisabled, required: isRequired, className: cn("flex-1 bg-transparent border-none outline-none text-surface-ink-neutral-normal placeholder:text-surface-ink-neutral-muted disabled:cursor-not-allowed disabled:text-surface-ink-neutral-disabled", inputClassName), ...props }), showClearButton && hasValue && !isDisabled && (jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })), suffix && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
2932
+ ? "text-surface-ink-neutral-disabled"
2933
+ : currentValidationState === "positive"
2934
+ ? "text-feedback-ink-positive-intense"
2935
+ : currentValidationState === "negative"
2936
+ ? "text-feedback-ink-negative-subtle"
2937
+ : "text-surface-ink-neutral-muted"), children: suffix }))] }), jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
2938
+ ? "default"
2939
+ : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
2940
+ });
2941
+ TextField.displayName = "TextField";
2942
+
2872
2943
  const Select = React.forwardRef(({ className, options = [], value: controlledValue, defaultValue, onChange, placeholder = "Select an option", label, helperText, errorText, successText, validationState = "none", isDisabled = false, isRequired = false, isOptional = false, isLoading = false, size = "medium", prefix, suffix, showClearButton = false, onClear, showLeadingIcon = false, containerClassName, labelClassName, triggerClassName, menuClassName, menuWidth = "full", sectionHeading, emptyTitle = "No options available", emptyDescription = "There are no options to select from.", emptyIcon, infoHeading, infoDescription, LinkComponent, linkText, linkHref, onLinkClick, ...props }, ref) => {
2873
2944
  const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
2874
2945
  const [isOpen, setIsOpen] = React.useState(false);
2875
2946
  const [dropdownPlacement, setDropdownPlacement] = React.useState("bottom");
2876
- const selectRef = React.useRef(null);
2947
+ const containerRef = React.useRef(null);
2877
2948
  const dropdownContainerRef = React.useRef(null);
2949
+ const inputRef = React.useRef(null);
2950
+ React.useImperativeHandle(ref, () => inputRef.current);
2878
2951
  const value = controlledValue !== undefined ? controlledValue : uncontrolledValue;
2879
2952
  // Find the selected option
2880
2953
  const selectedOption = options.find((opt) => opt.value === value);
2881
2954
  const hasValue = value !== undefined && value !== "";
2882
- // Determine which helper text to show
2883
- const displayHelperText = errorText || successText || helperText;
2884
- const currentValidationState = errorText
2885
- ? "negative"
2886
- : successText
2887
- ? "positive"
2888
- : validationState;
2889
2955
  const handleOpenChange = (newOpen) => {
2890
2956
  if (!isDisabled && !isLoading) {
2891
2957
  setIsOpen(newOpen);
@@ -2900,9 +2966,9 @@ const Select = React.forwardRef(({ className, options = [], value: controlledVal
2900
2966
  }
2901
2967
  onChange?.(option.value, option);
2902
2968
  setIsOpen(false);
2969
+ inputRef.current?.focus();
2903
2970
  };
2904
- const handleClear = (e) => {
2905
- e.stopPropagation();
2971
+ const handleClear = () => {
2906
2972
  if (onClear) {
2907
2973
  onClear();
2908
2974
  }
@@ -2916,7 +2982,7 @@ const Select = React.forwardRef(({ className, options = [], value: controlledVal
2916
2982
  const updateDropdownPlacement = React.useCallback(() => {
2917
2983
  if (typeof window === "undefined")
2918
2984
  return;
2919
- const trigger = selectRef.current;
2985
+ const trigger = containerRef.current;
2920
2986
  if (!trigger)
2921
2987
  return;
2922
2988
  const triggerRect = trigger.getBoundingClientRect();
@@ -2965,8 +3031,10 @@ const Select = React.forwardRef(({ className, options = [], value: controlledVal
2965
3031
  // Close dropdown when clicking outside
2966
3032
  React.useEffect(() => {
2967
3033
  const handleClickOutside = (event) => {
2968
- if (selectRef.current &&
2969
- !selectRef.current.contains(event.target)) {
3034
+ if (containerRef.current &&
3035
+ !containerRef.current.contains(event.target) &&
3036
+ dropdownContainerRef.current &&
3037
+ !dropdownContainerRef.current.contains(event.target)) {
2970
3038
  handleOpenChange(false);
2971
3039
  }
2972
3040
  };
@@ -2992,35 +3060,27 @@ const Select = React.forwardRef(({ className, options = [], value: controlledVal
2992
3060
  }
2993
3061
  }, [isOpen]);
2994
3062
  // Handle keyboard navigation
2995
- React.useEffect(() => {
2996
- const handleKeyDown = (event) => {
2997
- if (isDisabled || isLoading)
2998
- return;
2999
- if (!isOpen && (event.key === "Enter" || event.key === " ")) {
3063
+ const handleKeyDown = (event) => {
3064
+ if (isDisabled || isLoading)
3065
+ return;
3066
+ if (!isOpen && (event.key === "Enter" || event.key === " ")) {
3067
+ event.preventDefault();
3068
+ setIsOpen(true);
3069
+ return;
3070
+ }
3071
+ if (isOpen) {
3072
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
3000
3073
  event.preventDefault();
3001
- setIsOpen(true);
3002
- return;
3003
- }
3004
- if (isOpen) {
3005
- if (event.key === "ArrowDown" || event.key === "ArrowUp") {
3006
- event.preventDefault();
3007
- const currentIndex = options.findIndex((opt) => opt.value === value);
3008
- const nextIndex = event.key === "ArrowDown"
3009
- ? Math.min(currentIndex + 1, options.length - 1)
3010
- : Math.max(currentIndex - 1, 0);
3011
- if (options[nextIndex] && !options[nextIndex].isDisabled) {
3012
- handleSelect(options[nextIndex]);
3013
- }
3074
+ const currentIndex = options.findIndex((opt) => opt.value === value);
3075
+ const nextIndex = event.key === "ArrowDown"
3076
+ ? Math.min(currentIndex + 1, options.length - 1)
3077
+ : Math.max(currentIndex - 1, 0);
3078
+ if (options[nextIndex] && !options[nextIndex].isDisabled) {
3079
+ handleSelect(options[nextIndex]);
3014
3080
  }
3015
3081
  }
3016
- };
3017
- if (selectRef.current) {
3018
- selectRef.current.addEventListener("keydown", handleKeyDown);
3019
- return () => {
3020
- selectRef.current?.removeEventListener("keydown", handleKeyDown);
3021
- };
3022
3082
  }
3023
- }, [isOpen, value, options, isDisabled, isLoading]);
3083
+ };
3024
3084
  // Transform options to dropdown menu items
3025
3085
  const menuItems = options.map((option) => ({
3026
3086
  value: option.value,
@@ -3033,50 +3093,20 @@ const Select = React.forwardRef(({ className, options = [], value: controlledVal
3033
3093
  onClick: () => handleSelect(option),
3034
3094
  }));
3035
3095
  const widthStyle = menuWidth === "full" ? "100%" : menuWidth === "auto" ? "auto" : menuWidth;
3036
- const sizeConfig = {
3037
- small: {
3038
- gap: "gap-2",
3039
- },
3040
- medium: {
3041
- gap: "gap-2",
3042
- },
3043
- large: {
3044
- gap: "gap-3",
3045
- },
3046
- };
3047
- 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, LinkComponent: LinkComponent, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsxs("div", { ref: selectRef, className: cn(selectVariants({
3048
- size,
3049
- validationState: currentValidationState,
3050
- isDisabled,
3051
- }), "relative w-full cursor-pointer", className), onClick: !isDisabled && !isLoading ? toggleOpen : undefined, role: "combobox", "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-disabled": isDisabled, ...props, children: [prefix ? (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
3052
- ? "text-surface-ink-neutral-disabled"
3053
- : currentValidationState === "positive"
3054
- ? "text-feedback-ink-positive-intense"
3055
- : currentValidationState === "negative"
3056
- ? "text-feedback-ink-negative-subtle"
3057
- : "text-surface-ink-neutral-muted"), children: prefix })) : showLeadingIcon && selectedOption?.leadingIcon ? (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
3058
- ? "text-surface-ink-neutral-disabled"
3059
- : currentValidationState === "positive"
3060
- ? "text-feedback-ink-positive-intense"
3061
- : currentValidationState === "negative"
3062
- ? "text-feedback-ink-negative-subtle"
3063
- : "text-surface-ink-neutral-muted"), children: selectedOption.leadingIcon })) : null, jsx("span", { className: cn("flex-1 text-left truncate", !selectedOption && "text-surface-ink-neutral-muted", isDisabled && "text-surface-ink-neutral-disabled"), children: isLoading ? "Loading..." : selectedOption?.label || placeholder }), showClearButton && hasValue && !isDisabled && !isLoading && (jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })), suffix && !showClearButton && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
3064
- ? "text-surface-ink-neutral-disabled"
3065
- : currentValidationState === "positive"
3066
- ? "text-feedback-ink-positive-intense"
3067
- : currentValidationState === "negative"
3068
- ? "text-feedback-ink-negative-subtle"
3069
- : "text-surface-ink-neutral-muted"), children: suffix })), jsx(ChevronDown, { className: cn("shrink-0 w-4 h-4 transition-transform", isDisabled
3070
- ? "text-surface-ink-neutral-disabled"
3071
- : currentValidationState === "positive"
3072
- ? "text-feedback-ink-positive-intense"
3073
- : currentValidationState === "negative"
3074
- ? "text-feedback-ink-negative-subtle"
3075
- : "text-surface-ink-neutral-muted", isOpen && "transform rotate-180") }), isOpen && !isDisabled && !isLoading && (jsx("div", { ref: dropdownContainerRef, className: cn("absolute z-50 left-0 right-0", dropdownPlacement === "bottom"
3076
- ? "top-full mt-1"
3077
- : "bottom-full mb-1"), children: jsx(DropdownMenu, { ref: ref, items: menuItems, sectionHeading: sectionHeading, isEmpty: options.length === 0, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyIcon: emptyIcon, disableFooter: true, onClose: () => handleOpenChange(false), className: menuClassName, width: widthStyle }) }))] }), jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
3078
- ? "default"
3079
- : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
3096
+ // Get the display value for the TextField
3097
+ const displayValue = isLoading ? "Loading..." : selectedOption?.label || "";
3098
+ // Build the prefix: either provided prefix or selected option's leadingIcon
3099
+ const displayPrefix = prefix
3100
+ ? prefix
3101
+ : showLeadingIcon && selectedOption?.leadingIcon
3102
+ ? selectedOption.leadingIcon
3103
+ : undefined;
3104
+ // Build the suffix: include both the optional suffix and the chevron icon
3105
+ const chevronIcon = (jsx(Icon, { name: isOpen ? "chevronUp" : "chevronDown", size: 16, className: "shrink-0 transition-colors" }));
3106
+ const displaySuffix = suffix ? (jsxs(Fragment, { children: [suffix, chevronIcon] })) : (chevronIcon);
3107
+ return (jsxs("div", { ref: containerRef, className: "relative", children: [jsx(TextField, { ref: inputRef, label: label, helperText: helperText, errorText: errorText, successText: successText, validationState: validationState, isDisabled: isDisabled, isRequired: isRequired, isOptional: isOptional, isLoading: isLoading, size: size, prefix: displayPrefix, suffix: displaySuffix, showClearButton: showClearButton && hasValue && !isLoading, onClear: handleClear, placeholder: placeholder, value: displayValue, readOnly: true, containerClassName: containerClassName, labelClassName: labelClassName, className: cn("cursor-pointer", triggerClassName, className), inputClassName: "cursor-pointer", infoHeading: infoHeading, infoDescription: infoDescription, LinkComponent: LinkComponent, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, onClick: toggleOpen, onKeyDown: handleKeyDown, role: "combobox", "aria-haspopup": "listbox", "aria-expanded": isOpen, ...props }), isOpen && !isDisabled && !isLoading && (jsx("div", { ref: dropdownContainerRef, className: cn("absolute z-50 left-0 right-0", dropdownPlacement === "bottom"
3108
+ ? "top-full mt-1"
3109
+ : "bottom-full mb-1"), children: jsx(DropdownMenu, { items: menuItems, sectionHeading: sectionHeading, isEmpty: options.length === 0, emptyTitle: emptyTitle, emptyDescription: emptyDescription, emptyIcon: emptyIcon, disableFooter: true, onClose: () => handleOpenChange(false), className: menuClassName, width: widthStyle }) }))] }));
3080
3110
  });
3081
3111
  Select.displayName = "Select";
3082
3112
 
@@ -3504,110 +3534,6 @@ const RadioGroup = React.forwardRef(({ value: controlledValue, defaultValue, onC
3504
3534
  });
3505
3535
  RadioGroup.displayName = "RadioGroup";
3506
3536
 
3507
- const textFieldVariants = cva("relative flex items-center gap-2 border rounded-large transition-all font-functional font-size-100 leading-100", {
3508
- variants: {
3509
- size: {
3510
- small: "h-[28px] px-3 text-xs gap-2",
3511
- medium: "h-[36px] px-4 text-sm gap-2",
3512
- large: "h-[44px] px-5 text-base gap-3",
3513
- },
3514
- validationState: {
3515
- none: `
3516
- border-action-outline-neutral-faded
3517
- hover:border-action-outline-primary-hover
3518
- focus-within:border-action-outline-primary-hover
3519
- focus-within:ring-2
3520
- ring-action-outline-primary-faded-hover`,
3521
- positive: `
3522
- border-action-outline-positive-default
3523
- focus-within:border-action-outline-positive-hover
3524
- focus-within:ring-2
3525
- ring-action-outline-positive-faded-hover`,
3526
- negative: `border-action-outline-negative-default
3527
- focus-within:border-action-outline-negative-hover
3528
- focus-within:ring-2
3529
- ring-action-outline-negative-faded-hover`,
3530
- },
3531
- isDisabled: {
3532
- true: `
3533
- border-[var(--border-width-thinner)]
3534
- hover:border-action-outline-neutral-disabled
3535
- border-action-outline-neutral-disabled
3536
- bg-surface-fill-neutral-intense cursor-not-allowed opacity-60`,
3537
- false: "bg-surface-fill-neutral-intense",
3538
- },
3539
- },
3540
- defaultVariants: {
3541
- size: "medium",
3542
- validationState: "none",
3543
- isDisabled: false,
3544
- },
3545
- });
3546
- const TextField = React.forwardRef(({ label, helperText, errorText, successText, size = "medium", validationState = "none", isDisabled = false, isLoading = false, isRequired = false, isOptional = false, prefix, suffix, showClearButton = false, infoDescription, infoHeading, LinkComponent, linkText, linkHref, onLinkClick, onClear, containerClassName, labelClassName, inputClassName, className, value, onChange, ...props }, ref) => {
3547
- const [internalValue, setInternalValue] = React.useState("");
3548
- const inputValue = value !== undefined ? value : internalValue;
3549
- const hasValue = inputValue && String(inputValue).length > 0;
3550
- const handleChange = (e) => {
3551
- if (onChange) {
3552
- onChange(e);
3553
- }
3554
- else {
3555
- setInternalValue(e.target.value);
3556
- }
3557
- };
3558
- const handleClear = () => {
3559
- if (onClear) {
3560
- onClear();
3561
- }
3562
- else {
3563
- setInternalValue("");
3564
- }
3565
- // Focus the input after clearing
3566
- const input = document.getElementById(props.id || "");
3567
- if (input) {
3568
- input.focus();
3569
- }
3570
- };
3571
- // Determine which helper text to show
3572
- const displayHelperText = errorText || successText || helperText;
3573
- const currentValidationState = errorText
3574
- ? "negative"
3575
- : successText
3576
- ? "positive"
3577
- : validationState;
3578
- const sizeConfig = {
3579
- small: {
3580
- gap: "gap-2",
3581
- },
3582
- medium: {
3583
- gap: "gap-2",
3584
- },
3585
- large: {
3586
- gap: "gap-3",
3587
- },
3588
- };
3589
- 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, LinkComponent: LinkComponent, linkText: linkText, linkHref: linkHref, onLinkClick: onLinkClick, htmlFor: props.id, className: "mb-2", labelClassName: labelClassName })), jsxs("div", { className: cn(textFieldVariants({
3590
- size,
3591
- validationState: currentValidationState,
3592
- isDisabled,
3593
- }), isLoading && "text-field-loading", className), children: [prefix && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
3594
- ? "text-surface-ink-neutral-disabled"
3595
- : currentValidationState === "positive"
3596
- ? "text-feedback-ink-positive-intense"
3597
- : currentValidationState === "negative"
3598
- ? "text-feedback-ink-negative-subtle"
3599
- : "text-surface-ink-neutral-muted"), children: prefix })), jsx("input", { ref: ref, value: inputValue, onChange: handleChange, disabled: isDisabled, required: isRequired, className: cn("flex-1 bg-transparent border-none outline-none text-surface-ink-neutral-normal placeholder:text-surface-ink-neutral-muted disabled:cursor-not-allowed disabled:text-surface-ink-neutral-disabled", inputClassName), ...props }), showClearButton && hasValue && !isDisabled && (jsx("button", { type: "button", onClick: handleClear, className: "shrink-0 flex items-center justify-center text-surface-ink-neutral-muted hover:text-surface-ink-neutral-normal transition-colors", tabIndex: -1, children: jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M12 4L4 12M4 4L12 12", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })), suffix && (jsx("span", { className: cn("shrink-0 flex items-center", isDisabled
3600
- ? "text-surface-ink-neutral-disabled"
3601
- : currentValidationState === "positive"
3602
- ? "text-feedback-ink-positive-intense"
3603
- : currentValidationState === "negative"
3604
- ? "text-feedback-ink-negative-subtle"
3605
- : "text-surface-ink-neutral-muted"), children: suffix }))] }), jsx(FormFooter, { helperText: displayHelperText, validationState: currentValidationState === "none"
3606
- ? "default"
3607
- : currentValidationState, size: size, isDisabled: isDisabled, className: "mt-1" })] }));
3608
- });
3609
- TextField.displayName = "TextField";
3610
-
3611
3537
  const defaultFilter = (item, query) => {
3612
3538
  const searchQuery = query?.toLowerCase();
3613
3539
  return (item.label?.toLowerCase()?.includes(searchQuery) ||
@@ -5181,5 +5107,5 @@ const UploadBox = React.forwardRef(({ label, helperText, errorText, successText,
5181
5107
  });
5182
5108
  UploadBox.displayName = "UploadBox";
5183
5109
 
5184
- export { Alert, Amount, Avatar, AvatarCell, Badge, Button, ButtonGroup, Checkbox, Counter, DatePicker, Divider, Dropdown, DropdownMenu, FormFooter, FormHeader, Icon, IconButton, IconCell, Link, ListItem, Modal, NumberCell, Pagination, Radio, RadioGroup, SearchableDropdown, Select, SelectTextField, SidePanel, Skeleton, SlotCell, SpacerCell, Switch, TabItem, Table, TableDetailPanel, Tabs, Text, TextArea, TextField, Tooltip, UploadBox, alertVariants, avatarVariants, badgeVariants, buttonGroupVariants, buttonVariants, checkboxVariants, cn, counterVariants, datePickerVariants, dropdownVariants, getAvailableIcons, hasIcon, iconButtonVariants, iconRegistry, linkVariants, listItemVariants, paginationVariants, radioVariants, selectTriggerVariants, selectVariants, switchVariants, tableCellVariants, tableHeaderVariants, tableVariants, textAreaVariants, textFieldVariants, tooltipVariants, uploadBoxVariants };
5110
+ export { Alert, Amount, Avatar, AvatarCell, Badge, Button, ButtonGroup, Checkbox, Counter, DatePicker, Divider, Dropdown, DropdownMenu, FormFooter, FormHeader, Icon, IconButton, IconCell, Link, ListItem, Modal, NumberCell, Pagination, Radio, RadioGroup, SearchableDropdown, Select, SelectTextField, SidePanel, Skeleton, SlotCell, SpacerCell, Switch, TabItem, Table, TableDetailPanel, Tabs, Text, TextArea, TextField, Tooltip, UploadBox, alertVariants, avatarVariants, badgeVariants, buttonGroupVariants, buttonVariants, checkboxVariants, cn, counterVariants, datePickerVariants, dropdownVariants, getAvailableIcons, hasIcon, iconButtonVariants, iconRegistry, linkVariants, listItemVariants, paginationVariants, radioVariants, selectTriggerVariants, switchVariants, tableCellVariants, tableHeaderVariants, tableVariants, textAreaVariants, textFieldVariants, tooltipVariants, uploadBoxVariants };
5185
5111
  //# sourceMappingURL=index.esm.js.map