@chekinapp/ui 0.0.67 → 0.0.68

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
@@ -77,6 +77,11 @@ __export(index_exports, {
77
77
  CopyString: () => CopyString,
78
78
  CustomCheckboxDropdownGroup: () => CustomCheckboxDropdownGroup,
79
79
  DEVICE_BREAKPOINTS: () => DEVICE_BREAKPOINTS,
80
+ DashboardCreatableMultiSelect: () => DashboardCreatableMultiSelect,
81
+ DashboardInfiniteScrollSelect: () => DashboardInfiniteScrollSelect,
82
+ DashboardInput: () => DashboardInput,
83
+ DashboardMultiSelect: () => DashboardMultiSelect,
84
+ DashboardSelect: () => DashboardSelect,
80
85
  DataTable: () => DataTable,
81
86
  DatePicker: () => DatePicker,
82
87
  DateTableFilter: () => DateTableFilter,
@@ -4894,8 +4899,9 @@ var iconButtonVariants = (0, import_class_variance_authority10.cva)(
4894
4899
  variants: {
4895
4900
  size: {
4896
4901
  s: "w-8 h-8",
4897
- m: "w-10 h-10",
4898
- l: "w-[43px] h-[43px]"
4902
+ m: "w-8 h-8",
4903
+ l: "w-[43px] h-[43px]",
4904
+ default: "w-8 h-8"
4899
4905
  },
4900
4906
  shape: {
4901
4907
  rounded: "rounded-[var(--chekin-radius-input)]",
@@ -7407,13 +7413,13 @@ function SearchButton({ onClick, className, icon, ariaLabel }) {
7407
7413
  {
7408
7414
  onClick,
7409
7415
  className: cn(
7410
- "p-1.5 text-[var(--chekin-color-gray-1)] hover:text-[var(--chekin-color-brand-blue)]",
7416
+ "p-1.5 text-[#9696b9] hover:text-[var(--chekin-color-brand-blue)]",
7411
7417
  className
7412
7418
  ),
7413
7419
  "data-testid": "search-button",
7414
7420
  "aria-label": ariaLabel,
7415
7421
  type: "button",
7416
- children: icon || /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(import_lucide_react26.Search, { size: 14, strokeWidth: 4 })
7422
+ children: icon || /* @__PURE__ */ (0, import_jsx_runtime93.jsx)(import_lucide_react26.Search, { size: 12, strokeWidth: 4 })
7417
7423
  }
7418
7424
  );
7419
7425
  }
@@ -9747,11 +9753,23 @@ ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
9747
9753
  var import_react76 = require("react");
9748
9754
  var import_jsx_runtime127 = require("react/jsx-runtime");
9749
9755
  var getValueArray = (value) => {
9750
- if (value) {
9756
+ if (value !== void 0 && value !== null) {
9751
9757
  return Array.isArray(value) ? value : [value];
9752
9758
  }
9753
9759
  return [];
9754
9760
  };
9761
+ var convertStringToValue = (stringValue, option) => {
9762
+ if (option) {
9763
+ return option.value;
9764
+ }
9765
+ if (stringValue === "true") return true;
9766
+ if (stringValue === "false") return false;
9767
+ const numValue = Number(stringValue);
9768
+ if (!isNaN(numValue) && stringValue !== "") {
9769
+ return numValue;
9770
+ }
9771
+ return stringValue;
9772
+ };
9755
9773
  function getToggleContent(label, disabled, readOnly, active) {
9756
9774
  if ((0, import_react76.isValidElement)(label)) {
9757
9775
  return (0, import_react76.cloneElement)(label, {
@@ -9788,7 +9806,7 @@ function TogglesInternal({
9788
9806
  const newValueArray = Array.isArray(newValue) ? newValue : [newValue];
9789
9807
  const typedValues = newValueArray.map((item) => {
9790
9808
  const option2 = options.find((opt) => String(opt.value) === item);
9791
- return option2 ? option2.value : item;
9809
+ return convertStringToValue(item, option2);
9792
9810
  });
9793
9811
  onChange?.(
9794
9812
  typedValues,
@@ -9798,7 +9816,7 @@ function TogglesInternal({
9798
9816
  }
9799
9817
  const singleValue = Array.isArray(newValue) ? newValue[0] : newValue;
9800
9818
  const option = options.find((opt) => String(opt.value) === singleValue);
9801
- const typedValue = option ? option.value : singleValue;
9819
+ const typedValue = convertStringToValue(singleValue, option);
9802
9820
  onChange?.(
9803
9821
  typedValue,
9804
9822
  {}
@@ -13642,259 +13660,1833 @@ var AirbnbSearchInput = React52.forwardRef(({ onReset, placeholder, wrapperClass
13642
13660
  });
13643
13661
  AirbnbSearchInput.displayName = "SearchInput";
13644
13662
 
13645
- // src/searchable-select/SearchableSelect.tsx
13663
+ // src/dashboard/input/Input.tsx
13646
13664
  var React53 = __toESM(require("react"), 1);
13647
13665
  var import_lucide_react46 = require("lucide-react");
13648
- var import_react_virtual2 = require("@tanstack/react-virtual");
13649
- var import_react82 = require("react");
13666
+
13667
+ // src/dashboard/_fieldset/Fieldset.tsx
13650
13668
  var import_jsx_runtime154 = require("react/jsx-runtime");
13651
- var ROW_HEIGHT = 48;
13652
- var DESKTOP_LIST_HEIGHT = 280;
13653
- var MOBILE_LIST_HEIGHT = 420;
13654
- var LOAD_MORE_THRESHOLD = 6;
13655
- function defaultFilter(option, searchValue) {
13656
- return String(option.label).toLowerCase().includes(searchValue.trim().toLowerCase());
13657
- }
13658
- var SearchableSelectInternal = ({
13659
- options,
13660
- value,
13661
- onChange,
13662
- onBlur,
13663
- onOpenChange,
13664
- searchValue,
13665
- onSearchChange,
13666
- filterOption = defaultFilter,
13667
- loading,
13668
- hasNextPage,
13669
- onLoadMore,
13670
- variant = "default",
13671
- label,
13672
- topLabel,
13673
- placeholder,
13674
- searchPlaceholder = "Search...",
13675
- mobileTitle,
13676
- getValueLabel,
13677
- disabled,
13678
- error,
13669
+ function Fieldset({
13670
+ isActivated,
13671
+ isFocused,
13672
+ isEmpty,
13679
13673
  invalid,
13680
- optional,
13674
+ label,
13681
13675
  tooltip,
13682
- hideErrorMessage,
13683
- name,
13676
+ legend,
13677
+ onClick,
13678
+ htmlFor,
13679
+ labelId,
13680
+ readOnly,
13681
+ loading,
13682
+ disabled,
13684
13683
  className,
13685
- dropdownClassName,
13686
- menuClassName,
13687
- noOptionsMessage,
13688
- loadingMessage
13689
- }, ref) => {
13690
- const { isMatch: isMobile2 } = useScreenResize(DEVICE.mobileXL);
13691
- const reactId = React53.useId();
13692
- const [open, setOpen] = React53.useState(false);
13693
- const [internalSearchValue, setInternalSearchValue] = React53.useState("");
13694
- const [highlightedIndex, setHighlightedIndex] = React53.useState(-1);
13695
- const containerRef = React53.useRef(null);
13696
- const triggerRef = React53.useRef(null);
13697
- const inputRef = React53.useRef(null);
13698
- const listboxId = `${reactId}-listbox`;
13699
- const labelId = `${reactId}-label`;
13700
- const valueId = `${reactId}-value`;
13701
- const helperTextId = `${reactId}-helper`;
13702
- const errorId = `${reactId}-error`;
13703
- const searchInputId = `${reactId}-search`;
13704
- const effectiveSearchValue = searchValue ?? internalSearchValue;
13705
- const shouldFilterLocally = !onSearchChange && filterOption !== null;
13706
- const visibleOptions = React53.useMemo(() => {
13707
- if (!shouldFilterLocally || !effectiveSearchValue) {
13708
- return options;
13709
- }
13710
- return options.filter((option) => filterOption(option, effectiveSearchValue));
13711
- }, [effectiveSearchValue, filterOption, options, shouldFilterLocally]);
13712
- const selectedIndex = React53.useMemo(
13713
- () => visibleOptions.findIndex((option) => option.value === value?.value),
13714
- [value?.value, visibleOptions]
13715
- );
13716
- const helperText = placeholder ?? label;
13717
- const valueLabel = value ? getValueLabel?.(value) ?? String(value.label) : void 0;
13718
- const isBlocked = Boolean(disabled) || Boolean(loading);
13719
- const triggerError = error ?? invalid;
13720
- const describedBy = error && !hideErrorMessage ? errorId : void 0;
13721
- const activeOptionId = highlightedIndex >= 0 ? getOptionId(reactId, highlightedIndex) : void 0;
13722
- useOutsideClick({
13723
- elementRef: containerRef,
13724
- onOutsideClick: () => closeSelect(),
13725
- isDisabled: !open || isMobile2
13726
- });
13727
- const handleOnOpenChange = useEvent(onOpenChange);
13728
- const setSelectOpen = (0, import_react82.useCallback)(
13729
- (nextOpen, options2) => {
13730
- setOpen(nextOpen);
13731
- handleOnOpenChange?.(nextOpen);
13732
- if (!nextOpen && options2?.restoreFocus) {
13733
- triggerRef.current?.focus();
13734
- }
13735
- },
13736
- [handleOnOpenChange]
13737
- );
13738
- React53.useEffect(() => {
13739
- if (isBlocked) {
13740
- setSelectOpen(false);
13741
- return;
13742
- }
13743
- if (!open) return;
13744
- const frameId = window.requestAnimationFrame(() => {
13745
- inputRef.current?.focus();
13746
- });
13747
- return () => {
13748
- window.cancelAnimationFrame(frameId);
13749
- };
13750
- }, [isBlocked, open, setSelectOpen]);
13751
- React53.useEffect(() => {
13752
- if (!open) {
13753
- setHighlightedIndex(-1);
13754
- return;
13755
- }
13756
- setHighlightedIndex((currentIndex) => {
13757
- if (currentIndex >= 0 && currentIndex < visibleOptions.length && !visibleOptions[currentIndex]?.isDisabled) {
13758
- return currentIndex;
13759
- }
13760
- return selectedIndex >= 0 ? selectedIndex : getFirstEnabledIndex(visibleOptions);
13761
- });
13762
- }, [open, selectedIndex, visibleOptions]);
13763
- function openSelect() {
13764
- if (isBlocked) return;
13765
- setSelectOpen(true);
13766
- }
13767
- function closeSelect() {
13768
- setSelectOpen(false, { restoreFocus: true });
13769
- }
13770
- function handleSearchChange(nextValue) {
13771
- if (!onSearchChange) {
13772
- setInternalSearchValue(nextValue);
13773
- }
13774
- onSearchChange?.(nextValue);
13775
- }
13776
- function handleSelect(option) {
13777
- if (isBlocked || option.isDisabled) return;
13778
- onChange(option);
13779
- setSelectOpen(false, { restoreFocus: true });
13780
- }
13781
- function moveHighlight(step) {
13782
- const startIndex = highlightedIndex >= 0 ? highlightedIndex + step : step === 1 ? 0 : visibleOptions.length - 1;
13783
- const nextIndex = getNextEnabledIndex(visibleOptions, startIndex, step);
13784
- if (nextIndex >= 0) {
13785
- setHighlightedIndex(nextIndex);
13786
- }
13787
- }
13788
- function handleTriggerKeyDown(event) {
13789
- if (isBlocked) return;
13790
- if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown" || event.key === "ArrowUp") {
13791
- event.preventDefault();
13792
- openSelect();
13793
- }
13794
- }
13795
- function handleSearchKeyDown(event) {
13796
- if (event.key === "Escape") {
13797
- event.preventDefault();
13798
- closeSelect();
13799
- return;
13800
- }
13801
- if (event.key === "ArrowDown") {
13802
- event.preventDefault();
13803
- moveHighlight(1);
13804
- return;
13805
- }
13806
- if (event.key === "ArrowUp") {
13807
- event.preventDefault();
13808
- moveHighlight(-1);
13809
- return;
13810
- }
13811
- if (event.key === "Enter") {
13812
- event.preventDefault();
13813
- const option = visibleOptions[highlightedIndex];
13814
- if (option) {
13815
- handleSelect(option);
13684
+ labelClassName
13685
+ }) {
13686
+ const showLegendText = Boolean(legend || typeof label === "string");
13687
+ const raised = !isEmpty || isFocused;
13688
+ return /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)(import_jsx_runtime154.Fragment, { children: [
13689
+ /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)(
13690
+ "div",
13691
+ {
13692
+ onClick,
13693
+ className: cn(
13694
+ "absolute box-border inline-flex max-w-full cursor-text items-center pl-[3px] pr-5 transition-all duration-100 ease-in",
13695
+ "left-[13px] text-[var(--chekin-color-gray-1)]",
13696
+ isEmpty && !isFocused ? "top-[14px]" : "top-[-8px] !pl-1 !pr-[22px]",
13697
+ isFocused && "text-[var(--chekin-color-brand-blue)]",
13698
+ raised && invalid && "text-[var(--error-message-color)]",
13699
+ readOnly && "cursor-default",
13700
+ disabled && "pointer-events-none cursor-not-allowed",
13701
+ loading && "cursor-progress",
13702
+ labelClassName
13703
+ ),
13704
+ children: [
13705
+ /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
13706
+ "label",
13707
+ {
13708
+ id: labelId,
13709
+ htmlFor,
13710
+ className: cn(
13711
+ "block cursor-[inherit] truncate font-medium transition-all duration-100 ease-in",
13712
+ raised ? "text-[14px]" : "text-[16px]"
13713
+ ),
13714
+ children: label
13715
+ }
13716
+ ),
13717
+ tooltip && /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("span", { className: "ml-1 inline-flex", children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
13718
+ HelpTooltip,
13719
+ {
13720
+ content: tooltip,
13721
+ size: 16,
13722
+ className: cn(isFocused && "text-[var(--chekin-color-brand-blue)]")
13723
+ }
13724
+ ) })
13725
+ ]
13816
13726
  }
13817
- }
13818
- }
13819
- const content = /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
13820
- SearchableSelectContent,
13821
- {
13822
- inputId: searchInputId,
13823
- listboxId,
13824
- labelId,
13825
- activeOptionId,
13826
- inputRef,
13827
- options: visibleOptions,
13828
- value,
13829
- searchValue: effectiveSearchValue,
13830
- searchPlaceholder,
13831
- highlightedIndex,
13832
- loading,
13833
- hasNextPage,
13834
- onLoadMore,
13835
- menuClassName,
13836
- noOptionsMessage,
13837
- loadingMessage,
13838
- height: isMobile2 ? MOBILE_LIST_HEIGHT : DESKTOP_LIST_HEIGHT,
13839
- idPrefix: reactId,
13840
- onSearchChange: handleSearchChange,
13841
- onSearchKeyDown: handleSearchKeyDown,
13842
- onOptionClick: handleSelect,
13843
- onOptionHover: setHighlightedIndex
13844
- }
13845
- );
13846
- React53.useImperativeHandle(ref, () => triggerRef.current, []);
13847
- return /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)("div", { ref: containerRef, className: cn("relative w-full max-w-[425px]", className), children: [
13848
- name && /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("input", { type: "hidden", name, value: value ? String(value.value) : "" }),
13727
+ ),
13849
13728
  /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
13850
- FieldTrigger,
13729
+ "fieldset",
13851
13730
  {
13852
- id: `${reactId}-trigger`,
13853
- ref: triggerRef,
13854
- variant,
13855
- "aria-haspopup": "listbox",
13856
- "aria-expanded": open,
13857
- "aria-controls": listboxId,
13858
- label,
13859
- topLabel,
13860
- labelId,
13861
- valueId,
13862
- helperTextId,
13863
- errorId: error ? errorId : void 0,
13864
- labelText: topLabel ? helperText : void 0,
13865
- valueText: valueLabel,
13866
- placeholder: helperText,
13867
- describedBy,
13868
- error: triggerError,
13869
- loading,
13870
- optional,
13871
- tooltip,
13872
- forceLabelText: Boolean(optional) || Boolean(tooltip),
13873
- hideErrorMessage,
13874
- disabled,
13875
- onClick: () => {
13876
- if (open) {
13877
- closeSelect();
13878
- return;
13879
- }
13880
- openSelect();
13881
- },
13882
- onKeyDown: handleTriggerKeyDown,
13883
- onBlur,
13884
- trailingAdornment: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
13885
- import_lucide_react46.ChevronDown,
13731
+ "aria-hidden": "true",
13732
+ className: cn(
13733
+ "pointer-events-none absolute -top-[5px] bottom-0 left-0 right-0 m-0 min-w-0 rounded-[6px] border px-[13px] transition-colors duration-75",
13734
+ "border-[var(--chekin-color-gray-3)]",
13735
+ isActivated && "border-[var(--chekin-color-gray-2)]",
13736
+ isFocused && "border-[var(--chekin-color-brand-blue)]",
13737
+ invalid && "border-[var(--error-message-color)]",
13738
+ className
13739
+ ),
13740
+ children: /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)(
13741
+ "legend",
13886
13742
  {
13887
13743
  className: cn(
13888
- "h-6 w-6 text-[#1F1F1B] transition-transform",
13889
- open && "rotate-180"
13890
- )
13744
+ "invisible float-none block h-[11px] max-w-[0.01px] whitespace-nowrap p-0 text-[0.75em]",
13745
+ "transition-[max-width] duration-[50ms] ease-out",
13746
+ raised && "max-w-full !duration-100 !delay-[50ms]",
13747
+ !label && "w-0"
13748
+ ),
13749
+ children: [
13750
+ showLegendText && /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("span", { className: "visible inline-block pr-[6px] text-[14px] font-medium opacity-0", children: legend || label }),
13751
+ tooltip && /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("span", { className: "visible inline-block w-[20px] opacity-0", children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("span", { className: "inline-block h-4 w-4" }) })
13752
+ ]
13891
13753
  }
13892
13754
  )
13893
13755
  }
13894
- ),
13895
- isMobile2 ? /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
13896
- Drawer,
13897
- {
13756
+ )
13757
+ ] });
13758
+ }
13759
+
13760
+ // src/dashboard/input/Input.tsx
13761
+ var import_jsx_runtime155 = require("react/jsx-runtime");
13762
+ var checkIfEmpty = ({
13763
+ empty,
13764
+ defaultValue,
13765
+ value
13766
+ }) => {
13767
+ if (typeof empty !== "undefined") return empty;
13768
+ if (value === 0 || defaultValue === 0) return false;
13769
+ return !value && !defaultValue;
13770
+ };
13771
+ var DashboardInput = React53.forwardRef(
13772
+ ({
13773
+ value,
13774
+ defaultValue,
13775
+ className,
13776
+ wrapperClassName,
13777
+ fieldClassName,
13778
+ contentClassName,
13779
+ inputClassName,
13780
+ label,
13781
+ topLabel,
13782
+ tooltip,
13783
+ disabled,
13784
+ loading,
13785
+ readOnly,
13786
+ name,
13787
+ id,
13788
+ type,
13789
+ error,
13790
+ optional = false,
13791
+ invalid,
13792
+ empty,
13793
+ showNumberButtons,
13794
+ onIncrement,
13795
+ onDecrement,
13796
+ sign,
13797
+ footer,
13798
+ width,
13799
+ onReset,
13800
+ onChange,
13801
+ onFocus,
13802
+ onBlur,
13803
+ helperText,
13804
+ placeholder,
13805
+ leftIcon,
13806
+ trailingAdornment,
13807
+ renderErrorMessage = true,
13808
+ ...props
13809
+ }, ref) => {
13810
+ const generatedId = React53.useId();
13811
+ const inputId = id ?? name ?? generatedId;
13812
+ const errorId = `${inputId}-error`;
13813
+ const isEmpty = checkIfEmpty({ empty, value, defaultValue });
13814
+ const [inputType, setInputType] = React53.useState(type);
13815
+ const [isPasswordRevealed, setIsPasswordRevealed] = React53.useState(false);
13816
+ const [isFocused, setIsFocused] = React53.useState(false);
13817
+ const prevInputType = usePrevious(inputType);
13818
+ const isPasswordReveal = (prevInputType === "password" || type === "password") && !isEmpty;
13819
+ const hasInvalidState = Boolean(invalid) || Boolean(error) && error !== "NONE";
13820
+ const errorMessage = typeof error === "string" && error !== "NONE" ? error : void 0;
13821
+ const wrapperWidth = toCssSize(width);
13822
+ const togglePasswordReveal = () => {
13823
+ if (isPasswordRevealed) {
13824
+ setInputType("password");
13825
+ setIsPasswordRevealed(false);
13826
+ } else {
13827
+ setInputType("text");
13828
+ setIsPasswordRevealed(true);
13829
+ }
13830
+ };
13831
+ React53.useEffect(() => {
13832
+ setInputType(type);
13833
+ }, [type]);
13834
+ const handleChange = (event) => {
13835
+ if (readOnly || disabled || !onChange) return;
13836
+ onChange(event);
13837
+ };
13838
+ const handleLabelClick = () => {
13839
+ if (readOnly || disabled) return;
13840
+ setIsFocused(true);
13841
+ };
13842
+ const handleFocus = (event) => {
13843
+ if (readOnly || disabled) return;
13844
+ onFocus?.(event);
13845
+ setIsFocused(true);
13846
+ };
13847
+ const handleBlur = (event) => {
13848
+ onBlur?.(event);
13849
+ setIsFocused(false);
13850
+ };
13851
+ const showRightPaddingForReset = Boolean(onReset);
13852
+ const showRightPaddingForReveal = isPasswordReveal;
13853
+ return /* @__PURE__ */ (0, import_jsx_runtime155.jsxs)(
13854
+ "div",
13855
+ {
13856
+ className: cn(
13857
+ "relative block min-h-[68px]",
13858
+ disabled && "cursor-not-allowed opacity-50",
13859
+ loading && "cursor-progress",
13860
+ wrapperClassName,
13861
+ className
13862
+ ),
13863
+ style: wrapperWidth ? { width: wrapperWidth } : void 0,
13864
+ children: [
13865
+ topLabel && /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
13866
+ "label",
13867
+ {
13868
+ htmlFor: inputId,
13869
+ className: "mb-2 block text-[14px] font-medium text-[var(--chekin-color-brand-navy)]",
13870
+ children: topLabel
13871
+ }
13872
+ ),
13873
+ /* @__PURE__ */ (0, import_jsx_runtime155.jsxs)(
13874
+ "div",
13875
+ {
13876
+ className: cn(
13877
+ "relative block w-full",
13878
+ readOnly && "bg-[var(--chekin-color-surface-input-empty)]",
13879
+ fieldClassName
13880
+ ),
13881
+ children: [
13882
+ /* @__PURE__ */ (0, import_jsx_runtime155.jsxs)("div", { className: cn("relative w-full cursor-text", contentClassName), children: [
13883
+ /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
13884
+ Fieldset,
13885
+ {
13886
+ isFocused: isFocused && !readOnly,
13887
+ invalid: hasInvalidState,
13888
+ isEmpty,
13889
+ onClick: handleLabelClick,
13890
+ isActivated: !isEmpty || isFocused,
13891
+ readOnly,
13892
+ loading,
13893
+ disabled,
13894
+ htmlFor: inputId,
13895
+ labelId: `${inputId}-label`,
13896
+ legend: typeof label === "string" ? label : void 0,
13897
+ label,
13898
+ tooltip
13899
+ }
13900
+ ),
13901
+ leftIcon && /* @__PURE__ */ (0, import_jsx_runtime155.jsx)("span", { className: "pointer-events-none absolute left-0 top-0 flex h-full max-w-10 items-center justify-center text-[var(--chekin-color-gray-2)]", children: /* @__PURE__ */ (0, import_jsx_runtime155.jsx)("span", { className: "flex h-full w-10 items-center justify-center", children: leftIcon }) }),
13902
+ /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
13903
+ "input",
13904
+ {
13905
+ ...props,
13906
+ ref,
13907
+ id: inputId,
13908
+ name,
13909
+ type: inputType,
13910
+ "data-testid": "input",
13911
+ value,
13912
+ defaultValue,
13913
+ disabled: disabled || loading,
13914
+ readOnly,
13915
+ required: !optional,
13916
+ "aria-label": typeof label === "string" ? label : void 0,
13917
+ "aria-invalid": hasInvalidState,
13918
+ "aria-busy": loading,
13919
+ "aria-describedby": errorMessage && renderErrorMessage ? errorId : void 0,
13920
+ placeholder: isFocused || !label ? placeholder : void 0,
13921
+ onChange: handleChange,
13922
+ onFocus: handleFocus,
13923
+ onBlur: handleBlur,
13924
+ className: cn(
13925
+ "m-0 box-border h-12 w-full rounded-[6px] border-0 px-4 text-[16px] font-medium leading-5 text-[var(--chekin-color-brand-navy)] outline-none transition-colors duration-200 [text-overflow:ellipsis] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none",
13926
+ "placeholder:font-medium placeholder:text-[var(--chekin-color-gray-1)] placeholder:opacity-100",
13927
+ isEmpty && !isFocused ? "bg-[var(--chekin-color-surface-input-empty)]" : "bg-transparent",
13928
+ isEmpty && "text-[var(--chekin-color-gray-1)]",
13929
+ inputType === "password" && "[&:not(:placeholder-shown)]:font-bold [&:not(:placeholder-shown)]:tracking-[2px]",
13930
+ (disabled || readOnly) && "cursor-not-allowed",
13931
+ loading && "cursor-progress",
13932
+ leftIcon && "pl-10",
13933
+ (showRightPaddingForReset || showRightPaddingForReveal) && "pr-10",
13934
+ sign && "pr-10",
13935
+ inputClassName
13936
+ )
13937
+ }
13938
+ ),
13939
+ sign && /* @__PURE__ */ (0, import_jsx_runtime155.jsx)("span", { className: "pointer-events-none absolute right-[14px] top-0 flex h-full items-center text-[18px] font-medium leading-6 text-[var(--chekin-color-brand-navy)]", children: sign }),
13940
+ trailingAdornment && /* @__PURE__ */ (0, import_jsx_runtime155.jsx)("span", { className: "pointer-events-none absolute right-[14px] top-0 flex h-full items-center", children: trailingAdornment }),
13941
+ onReset && /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
13942
+ "button",
13943
+ {
13944
+ type: "button",
13945
+ onClick: onReset,
13946
+ disabled,
13947
+ className: "absolute right-0 top-0 flex h-full w-10 items-center justify-center border-0 bg-transparent p-0 text-[#9696b9] hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50",
13948
+ "aria-label": "Reset",
13949
+ children: /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(import_lucide_react46.X, { size: 14 })
13950
+ }
13951
+ ),
13952
+ isPasswordReveal && /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
13953
+ "button",
13954
+ {
13955
+ type: "button",
13956
+ onClick: togglePasswordReveal,
13957
+ className: "absolute right-[14px] top-[13px] flex h-[13px] w-[21px] cursor-pointer items-center justify-center border-0 bg-transparent p-0 hover:opacity-85",
13958
+ "aria-label": isPasswordRevealed ? "Hide password" : "Show password",
13959
+ children: /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
13960
+ import_lucide_react46.Eye,
13961
+ {
13962
+ className: cn(
13963
+ "h-[13px] w-[21px]",
13964
+ isPasswordRevealed ? "text-[#fc98dd]" : "text-[var(--chekin-color-gray-2)]"
13965
+ )
13966
+ }
13967
+ )
13968
+ }
13969
+ )
13970
+ ] }),
13971
+ type === "number" && showNumberButtons && /* @__PURE__ */ (0, import_jsx_runtime155.jsxs)("div", { className: "absolute right-[18px] top-[10px] inline-flex items-center text-right", children: [
13972
+ /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
13973
+ "button",
13974
+ {
13975
+ type: "button",
13976
+ onClick: onDecrement,
13977
+ className: "mr-2 inline-flex h-[23px] w-8 cursor-pointer items-center justify-center rounded-[3px] border-0 bg-[var(--chekin-color-brand-blue)] p-0 text-[20px] font-bold text-white outline-none hover:opacity-90 active:opacity-100",
13978
+ "aria-label": "Decrement",
13979
+ children: /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(import_lucide_react46.Minus, { size: 16, strokeWidth: 3, "aria-hidden": true })
13980
+ }
13981
+ ),
13982
+ /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
13983
+ "button",
13984
+ {
13985
+ type: "button",
13986
+ onClick: onIncrement,
13987
+ className: "inline-flex h-[23px] w-8 cursor-pointer items-center justify-center rounded-[3px] border-0 bg-[var(--chekin-color-brand-blue)] p-0 text-[20px] font-bold text-white outline-none hover:opacity-90 active:opacity-100",
13988
+ "aria-label": "Increment",
13989
+ children: /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(import_lucide_react46.Plus, { size: 16, strokeWidth: 3, "aria-hidden": true })
13990
+ }
13991
+ )
13992
+ ] })
13993
+ ]
13994
+ }
13995
+ ),
13996
+ !errorMessage && optional && /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
13997
+ "span",
13998
+ {
13999
+ "data-testid": `${name}-optional`,
14000
+ className: "mt-[1px] block text-left text-[14px] font-medium text-[var(--chekin-color-gray-1)]",
14001
+ children: typeof optional === "string" ? optional : "optional"
14002
+ }
14003
+ ),
14004
+ !errorMessage && helperText && /* @__PURE__ */ (0, import_jsx_runtime155.jsx)("span", { className: "mt-[1px] block text-[12px] font-normal text-[var(--chekin-color-gray-1)]", children: helperText }),
14005
+ errorMessage && renderErrorMessage && /* @__PURE__ */ (0, import_jsx_runtime155.jsx)(
14006
+ FieldErrorMessage,
14007
+ {
14008
+ id: errorId,
14009
+ message: errorMessage,
14010
+ "data-testid": name ? `${name}-error` : void 0,
14011
+ className: "mt-[1px] text-[14px]"
14012
+ }
14013
+ ),
14014
+ footer
14015
+ ]
14016
+ }
14017
+ );
14018
+ }
14019
+ );
14020
+ DashboardInput.displayName = "DashboardInput";
14021
+
14022
+ // src/dashboard/select/Select.tsx
14023
+ var React55 = __toESM(require("react"), 1);
14024
+ var import_lucide_react47 = require("lucide-react");
14025
+
14026
+ // src/dashboard/_select-internals/utils.ts
14027
+ function getOptionIndex2(options, option) {
14028
+ if (!option) return -1;
14029
+ return options.findIndex((item) => item.value === option.value);
14030
+ }
14031
+ function getFirstEnabledOptionIndex2(options) {
14032
+ return options.findIndex((option) => !option.isDisabled);
14033
+ }
14034
+ function getNextEnabledOptionIndex2(options, startIndex, step) {
14035
+ let nextIndex = startIndex;
14036
+ while (nextIndex >= 0 && nextIndex < options.length) {
14037
+ if (!options[nextIndex]?.isDisabled) return nextIndex;
14038
+ nextIndex += step;
14039
+ }
14040
+ return -1;
14041
+ }
14042
+ function defaultFilterOption(option, input) {
14043
+ if (!input) return true;
14044
+ const text = typeof option.label === "string" ? option.label : String(option.value);
14045
+ return text.toLowerCase().includes(input.toLowerCase());
14046
+ }
14047
+ function isOptionSelected(option, selectedValue, selectedValues) {
14048
+ if (selectedValues?.length) {
14049
+ return selectedValues.some((item) => item.value === option.value);
14050
+ }
14051
+ return selectedValue?.value === option.value;
14052
+ }
14053
+
14054
+ // src/dashboard/_select-internals/SelectMenu.tsx
14055
+ var import_jsx_runtime156 = require("react/jsx-runtime");
14056
+ function SelectMenu({
14057
+ id,
14058
+ options,
14059
+ labelledBy,
14060
+ describedBy,
14061
+ selectedValue,
14062
+ selectedValues,
14063
+ highlightedIndex,
14064
+ onOptionClick,
14065
+ onOptionHover,
14066
+ onKeyDown,
14067
+ disabled,
14068
+ menuClassName,
14069
+ listRef,
14070
+ selectedOptionRef,
14071
+ getOptionId: getOptionId2,
14072
+ noOptionsMessage,
14073
+ isMulti,
14074
+ emptyContent,
14075
+ footer
14076
+ }) {
14077
+ const emptyMessage = noOptionsMessage?.();
14078
+ const hasOptions = options.length > 0;
14079
+ return /* @__PURE__ */ (0, import_jsx_runtime156.jsxs)(
14080
+ "div",
14081
+ {
14082
+ id,
14083
+ ref: listRef,
14084
+ role: "listbox",
14085
+ tabIndex: -1,
14086
+ "aria-labelledby": labelledBy,
14087
+ "aria-describedby": describedBy,
14088
+ "aria-multiselectable": isMulti,
14089
+ "aria-activedescendant": highlightedIndex !== void 0 && highlightedIndex >= 0 ? getOptionId2(highlightedIndex) : void 0,
14090
+ onKeyDown,
14091
+ className: cn(
14092
+ "h-auto max-h-[322px] min-h-[75px] overflow-y-auto px-4 pb-[19px] pt-[17px] outline-none",
14093
+ menuClassName
14094
+ ),
14095
+ children: [
14096
+ !hasOptions && emptyMessage && /* @__PURE__ */ (0, import_jsx_runtime156.jsx)("div", { className: "mt-[10px] text-left text-[16px] text-[var(--chekin-color-brand-navy)]", children: emptyMessage }),
14097
+ !hasOptions && !emptyMessage && emptyContent,
14098
+ options.map((option, index) => {
14099
+ const isSelected = isOptionSelected(option, selectedValue, selectedValues);
14100
+ const isHighlighted = index === highlightedIndex;
14101
+ const optionKey = `${String(option.value)}-${index}`;
14102
+ const isOptionDisabled = Boolean(disabled || option.isDisabled);
14103
+ return /* @__PURE__ */ (0, import_jsx_runtime156.jsxs)(
14104
+ "button",
14105
+ {
14106
+ id: getOptionId2(index),
14107
+ ref: (node) => {
14108
+ selectedOptionRef?.(index, node);
14109
+ },
14110
+ type: "button",
14111
+ role: "option",
14112
+ "aria-selected": isSelected,
14113
+ "aria-disabled": isOptionDisabled,
14114
+ tabIndex: -1,
14115
+ disabled: isOptionDisabled,
14116
+ onClick: () => onOptionClick(option),
14117
+ onMouseMove: () => onOptionHover?.(index),
14118
+ className: cn(
14119
+ "flex w-full items-start justify-between border-0 border-b border-[#f2f4f8] bg-white px-4 py-[20px] text-left text-[16px] font-medium leading-5 text-[var(--chekin-color-brand-navy)] outline-none transition-colors",
14120
+ "last:border-b-transparent",
14121
+ isHighlighted && !isSelected && "cursor-pointer text-[var(--chekin-color-brand-blue)]",
14122
+ isSelected && "cursor-default font-bold text-[var(--chekin-color-brand-navy)]",
14123
+ isOptionDisabled && "cursor-default opacity-30"
14124
+ ),
14125
+ children: [
14126
+ /* @__PURE__ */ (0, import_jsx_runtime156.jsx)("span", { className: "block break-words", children: option.label }),
14127
+ option.description && /* @__PURE__ */ (0, import_jsx_runtime156.jsx)("span", { className: "ml-2 mt-[3px] shrink-0 text-[12px] font-bold italic text-[#777e91]", children: option.description })
14128
+ ]
14129
+ },
14130
+ optionKey
14131
+ );
14132
+ }),
14133
+ footer
14134
+ ]
14135
+ }
14136
+ );
14137
+ }
14138
+
14139
+ // src/dashboard/_select-internals/useSelectIds.ts
14140
+ var React54 = __toESM(require("react"), 1);
14141
+ function useSelectIds2({
14142
+ name,
14143
+ hasValue,
14144
+ error,
14145
+ hideErrorMessage
14146
+ }) {
14147
+ const reactId = React54.useId().replace(/:/g, "");
14148
+ const baseId = name ? `dash-select-${name}` : `dash-select-${reactId}`;
14149
+ const triggerId = `${baseId}-trigger`;
14150
+ const labelId = `${baseId}-label`;
14151
+ const valueId = `${baseId}-value`;
14152
+ const helperTextId = `${baseId}-helper`;
14153
+ const errorId = `${baseId}-error`;
14154
+ const listboxId = `${baseId}-listbox`;
14155
+ const describedErrorId = error && !hideErrorMessage ? errorId : void 0;
14156
+ const describedBy = [!hasValue ? helperTextId : null, describedErrorId].filter(Boolean).join(" ") || void 0;
14157
+ const getOptionId2 = React54.useCallback(
14158
+ (index) => `${baseId}-option-${index}`,
14159
+ [baseId]
14160
+ );
14161
+ return {
14162
+ triggerId,
14163
+ labelId,
14164
+ valueId,
14165
+ helperTextId,
14166
+ errorId,
14167
+ describedErrorId,
14168
+ listboxId,
14169
+ describedBy,
14170
+ getOptionId: getOptionId2
14171
+ };
14172
+ }
14173
+
14174
+ // src/dashboard/select/Select.tsx
14175
+ var import_jsx_runtime157 = require("react/jsx-runtime");
14176
+ function DashboardSelectInternal({
14177
+ options = [],
14178
+ value,
14179
+ onChange,
14180
+ onBlur,
14181
+ label,
14182
+ topLabel,
14183
+ placeholder,
14184
+ getValueLabel,
14185
+ disabled,
14186
+ loading,
14187
+ optional,
14188
+ tooltip,
14189
+ error,
14190
+ invalid,
14191
+ hideErrorMessage,
14192
+ className,
14193
+ menuClassName,
14194
+ dropdownClassName,
14195
+ name,
14196
+ width,
14197
+ noOptionsMessage,
14198
+ searchable = true,
14199
+ searchPlaceholder,
14200
+ filterOption = defaultFilterOption,
14201
+ helperText
14202
+ }, ref) {
14203
+ const containerRef = React55.useRef(null);
14204
+ const triggerRef = React55.useRef(null);
14205
+ const searchInputRef = React55.useRef(null);
14206
+ const listRef = React55.useRef(null);
14207
+ const optionRefs = React55.useRef([]);
14208
+ const [isOpen, setIsOpen] = React55.useState(false);
14209
+ const [searchValue, setSearchValue] = React55.useState("");
14210
+ const [highlightedIndex, setHighlightedIndex] = React55.useState(-1);
14211
+ const hasValue = Boolean(value);
14212
+ const isEmpty = !hasValue;
14213
+ const isBlocked = Boolean(disabled) || Boolean(loading);
14214
+ const triggerError = error ?? invalid;
14215
+ const hasInvalidState = Boolean(triggerError);
14216
+ const errorMessage = typeof error === "string" ? error : void 0;
14217
+ const wrapperWidth = toCssSize(width);
14218
+ const valueLabel = value ? getValueLabel?.(value) ?? String(value.label) : void 0;
14219
+ const { triggerId, labelId, valueId, listboxId, describedErrorId, errorId, getOptionId: getOptionId2 } = useSelectIds2({ name, hasValue, error, hideErrorMessage });
14220
+ const filteredOptions = React55.useMemo(() => {
14221
+ if (!searchable || !searchValue) return options;
14222
+ return options.filter((option) => filterOption(option, searchValue));
14223
+ }, [options, searchable, searchValue, filterOption]);
14224
+ React55.useImperativeHandle(ref, () => triggerRef.current, []);
14225
+ useOutsideClick({
14226
+ elementRef: containerRef,
14227
+ onOutsideClick: () => setIsOpen(false),
14228
+ isDisabled: !isOpen
14229
+ });
14230
+ React55.useEffect(() => {
14231
+ if (isBlocked) setIsOpen(false);
14232
+ }, [isBlocked]);
14233
+ React55.useEffect(() => {
14234
+ if (!isOpen) {
14235
+ setSearchValue("");
14236
+ setHighlightedIndex(-1);
14237
+ return;
14238
+ }
14239
+ const selectedIndex = getOptionIndex2(filteredOptions, value);
14240
+ setHighlightedIndex(
14241
+ selectedIndex >= 0 ? selectedIndex : getFirstEnabledOptionIndex2(filteredOptions)
14242
+ );
14243
+ if (searchable) {
14244
+ const frame = window.requestAnimationFrame(() => searchInputRef.current?.focus());
14245
+ return () => window.cancelAnimationFrame(frame);
14246
+ }
14247
+ }, [isOpen, filteredOptions, searchable, value]);
14248
+ React55.useEffect(() => {
14249
+ if (!isOpen || highlightedIndex < 0) return;
14250
+ optionRefs.current[highlightedIndex]?.scrollIntoView({ block: "nearest" });
14251
+ }, [highlightedIndex, isOpen]);
14252
+ React55.useEffect(
14253
+ function setCorrectOptionIfThereIsOnlyValue() {
14254
+ if (value?.value === void 0 || value.value === null || value.label !== "")
14255
+ return;
14256
+ const validOption = options.find((option) => option.value === value.value);
14257
+ if (validOption) onChange(validOption);
14258
+ },
14259
+ [onChange, options, value]
14260
+ );
14261
+ const toggleMenu = () => {
14262
+ if (isBlocked) return;
14263
+ setIsOpen((prev) => !prev);
14264
+ };
14265
+ const handleSelect = (option) => {
14266
+ if (option.isDisabled) return;
14267
+ onChange(option);
14268
+ setIsOpen(false);
14269
+ triggerRef.current?.focus();
14270
+ };
14271
+ const handleTriggerKeyDown = (event) => {
14272
+ if (isBlocked) return;
14273
+ if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Enter" || event.key === " ") {
14274
+ event.preventDefault();
14275
+ setIsOpen(true);
14276
+ }
14277
+ };
14278
+ const handleSearchKeyDown = (event) => {
14279
+ if (event.key === "ArrowDown") {
14280
+ event.preventDefault();
14281
+ const next = getNextEnabledOptionIndex2(filteredOptions, highlightedIndex + 1, 1);
14282
+ if (next >= 0) setHighlightedIndex(next);
14283
+ return;
14284
+ }
14285
+ if (event.key === "ArrowUp") {
14286
+ event.preventDefault();
14287
+ const next = getNextEnabledOptionIndex2(filteredOptions, highlightedIndex - 1, -1);
14288
+ if (next >= 0) setHighlightedIndex(next);
14289
+ return;
14290
+ }
14291
+ if (event.key === "Enter") {
14292
+ event.preventDefault();
14293
+ const option = filteredOptions[highlightedIndex];
14294
+ if (option && !option.isDisabled) handleSelect(option);
14295
+ return;
14296
+ }
14297
+ if (event.key === "Escape") {
14298
+ event.preventDefault();
14299
+ setIsOpen(false);
14300
+ triggerRef.current?.focus();
14301
+ return;
14302
+ }
14303
+ if (event.key === "Tab") {
14304
+ setIsOpen(false);
14305
+ }
14306
+ };
14307
+ return /* @__PURE__ */ (0, import_jsx_runtime157.jsxs)(
14308
+ "div",
14309
+ {
14310
+ ref: containerRef,
14311
+ className: cn(
14312
+ "relative w-full max-w-[var(--max-field-width)]",
14313
+ disabled && "cursor-not-allowed opacity-50",
14314
+ loading && "cursor-progress",
14315
+ className
14316
+ ),
14317
+ style: wrapperWidth ? { width: wrapperWidth } : void 0,
14318
+ children: [
14319
+ name && /* @__PURE__ */ (0, import_jsx_runtime157.jsx)("input", { type: "hidden", name, value: value ? String(value.value) : "" }),
14320
+ /* @__PURE__ */ (0, import_jsx_runtime157.jsxs)("div", { className: "relative w-full min-h-[68px]", children: [
14321
+ topLabel && /* @__PURE__ */ (0, import_jsx_runtime157.jsx)(
14322
+ "label",
14323
+ {
14324
+ htmlFor: triggerId,
14325
+ className: "mb-2 block text-[14px] font-medium text-[var(--chekin-color-brand-navy)]",
14326
+ children: topLabel
14327
+ }
14328
+ ),
14329
+ /* @__PURE__ */ (0, import_jsx_runtime157.jsxs)("div", { className: "relative w-full", children: [
14330
+ /* @__PURE__ */ (0, import_jsx_runtime157.jsxs)(
14331
+ "button",
14332
+ {
14333
+ id: triggerId,
14334
+ ref: triggerRef,
14335
+ type: "button",
14336
+ "aria-haspopup": "listbox",
14337
+ "aria-expanded": isOpen,
14338
+ "aria-controls": listboxId,
14339
+ "aria-labelledby": hasValue && valueId ? `${labelId} ${valueId}` : labelId,
14340
+ "aria-describedby": describedErrorId,
14341
+ "aria-invalid": hasInvalidState,
14342
+ "aria-busy": loading,
14343
+ disabled: isBlocked,
14344
+ onClick: toggleMenu,
14345
+ onKeyDown: handleTriggerKeyDown,
14346
+ onBlur,
14347
+ className: cn(
14348
+ "relative m-0 box-border flex h-12 w-full cursor-pointer items-center justify-between gap-2 rounded-[6px] border-0 px-4 text-left text-[16px] font-medium leading-5 outline-none transition-colors duration-200",
14349
+ isEmpty ? "bg-[var(--chekin-color-surface-input-empty)] text-[var(--chekin-color-gray-1)]" : "bg-transparent text-[var(--chekin-color-brand-navy)]",
14350
+ disabled && "cursor-not-allowed opacity-50",
14351
+ loading && "cursor-progress"
14352
+ ),
14353
+ children: [
14354
+ /* @__PURE__ */ (0, import_jsx_runtime157.jsx)("span", { id: valueId, className: "block min-w-0 flex-1 truncate text-left", children: valueLabel ?? placeholder ?? label }),
14355
+ /* @__PURE__ */ (0, import_jsx_runtime157.jsxs)("span", { className: "pointer-events-none flex items-center gap-2 text-[var(--chekin-color-gray-2)]", children: [
14356
+ loading && /* @__PURE__ */ (0, import_jsx_runtime157.jsx)(ThreeDotsLoader, { height: 18, width: 18 }),
14357
+ /* @__PURE__ */ (0, import_jsx_runtime157.jsx)(
14358
+ import_lucide_react47.ChevronDown,
14359
+ {
14360
+ size: 16,
14361
+ className: cn(
14362
+ "transition-transform duration-200",
14363
+ isOpen && "rotate-180 text-[var(--chekin-color-brand-blue)]"
14364
+ )
14365
+ }
14366
+ )
14367
+ ] })
14368
+ ]
14369
+ }
14370
+ ),
14371
+ /* @__PURE__ */ (0, import_jsx_runtime157.jsx)(
14372
+ Fieldset,
14373
+ {
14374
+ isFocused: isOpen,
14375
+ invalid: hasInvalidState,
14376
+ isEmpty,
14377
+ isActivated: !isEmpty || isOpen,
14378
+ disabled,
14379
+ loading,
14380
+ htmlFor: triggerId,
14381
+ labelId,
14382
+ legend: typeof label === "string" ? label : void 0,
14383
+ label,
14384
+ tooltip,
14385
+ onClick: !isBlocked ? toggleMenu : void 0
14386
+ }
14387
+ ),
14388
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime157.jsxs)(
14389
+ "div",
14390
+ {
14391
+ className: cn(
14392
+ "absolute left-0 right-0 top-full z-20 overflow-hidden rounded-b-lg bg-white shadow-[0_30px_30px_0_rgba(33,72,255,0.2)]",
14393
+ dropdownClassName
14394
+ ),
14395
+ children: [
14396
+ searchable && /* @__PURE__ */ (0, import_jsx_runtime157.jsx)("div", { className: "border-b border-[#f2f4f8] px-4 pb-2 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime157.jsx)(
14397
+ "input",
14398
+ {
14399
+ ref: searchInputRef,
14400
+ type: "text",
14401
+ value: searchValue,
14402
+ placeholder: searchPlaceholder,
14403
+ onChange: (event) => setSearchValue(event.target.value),
14404
+ onKeyDown: handleSearchKeyDown,
14405
+ autoComplete: "off",
14406
+ "aria-controls": listboxId,
14407
+ "aria-activedescendant": highlightedIndex >= 0 ? getOptionId2(highlightedIndex) : void 0,
14408
+ className: "m-0 box-border h-9 w-full rounded-md border border-[var(--chekin-color-gray-3)] bg-white px-3 text-[16px] font-medium text-[var(--chekin-color-brand-navy)] outline-none transition-colors placeholder:text-[var(--chekin-color-gray-1)] focus:border-[var(--chekin-color-brand-blue)]"
14409
+ }
14410
+ ) }),
14411
+ /* @__PURE__ */ (0, import_jsx_runtime157.jsx)(
14412
+ SelectMenu,
14413
+ {
14414
+ id: listboxId,
14415
+ options: filteredOptions,
14416
+ labelledBy: labelId,
14417
+ describedBy: describedErrorId,
14418
+ selectedValue: value,
14419
+ highlightedIndex,
14420
+ onOptionClick: handleSelect,
14421
+ onOptionHover: setHighlightedIndex,
14422
+ disabled: isBlocked,
14423
+ menuClassName,
14424
+ listRef,
14425
+ selectedOptionRef: (index, node) => {
14426
+ optionRefs.current[index] = node;
14427
+ },
14428
+ getOptionId: getOptionId2,
14429
+ noOptionsMessage
14430
+ }
14431
+ )
14432
+ ]
14433
+ }
14434
+ )
14435
+ ] }),
14436
+ !errorMessage && optional && /* @__PURE__ */ (0, import_jsx_runtime157.jsx)("span", { className: "mt-[1px] block text-left text-[14px] font-medium text-[var(--chekin-color-gray-1)]", children: typeof optional === "string" ? optional : "optional" }),
14437
+ !errorMessage && helperText && /* @__PURE__ */ (0, import_jsx_runtime157.jsx)("span", { className: "mt-[1px] block text-[12px] font-normal text-[var(--chekin-color-gray-1)]", children: helperText }),
14438
+ errorMessage && !hideErrorMessage && /* @__PURE__ */ (0, import_jsx_runtime157.jsx)(
14439
+ FieldErrorMessage,
14440
+ {
14441
+ id: errorId,
14442
+ message: errorMessage,
14443
+ className: "mt-[1px] text-[14px]"
14444
+ }
14445
+ )
14446
+ ] })
14447
+ ]
14448
+ }
14449
+ );
14450
+ }
14451
+ var DashboardSelect = React55.forwardRef(
14452
+ DashboardSelectInternal
14453
+ );
14454
+
14455
+ // src/dashboard/multi-select/MultiSelect.tsx
14456
+ var React56 = __toESM(require("react"), 1);
14457
+ var import_lucide_react48 = require("lucide-react");
14458
+ var import_jsx_runtime158 = require("react/jsx-runtime");
14459
+ var isValueSelected = (selected, option) => selected.some((item) => item.value === option.value);
14460
+ function DashboardMultiSelectInternal({
14461
+ options = [],
14462
+ value,
14463
+ onChange,
14464
+ onBlur,
14465
+ label,
14466
+ topLabel,
14467
+ placeholder,
14468
+ disabled,
14469
+ readOnly,
14470
+ loading,
14471
+ optional,
14472
+ tooltip,
14473
+ error,
14474
+ invalid,
14475
+ hideErrorMessage,
14476
+ className,
14477
+ menuClassName,
14478
+ dropdownClassName,
14479
+ name,
14480
+ width,
14481
+ noOptionsMessage,
14482
+ filterOption = defaultFilterOption,
14483
+ closeMenuOnSelect = false,
14484
+ renderChip,
14485
+ helperText,
14486
+ isCreatable = false,
14487
+ onCreateOption,
14488
+ formatCreateLabel = (input) => `Create "${input}"`,
14489
+ isValidNewOption
14490
+ }, ref) {
14491
+ const containerRef = React56.useRef(null);
14492
+ const inputRef = React56.useRef(null);
14493
+ const listRef = React56.useRef(null);
14494
+ const optionRefs = React56.useRef([]);
14495
+ const [isOpen, setIsOpen] = React56.useState(false);
14496
+ const [searchValue, setSearchValue] = React56.useState("");
14497
+ const [isFocused, setIsFocused] = React56.useState(false);
14498
+ const [highlightedIndex, setHighlightedIndex] = React56.useState(-1);
14499
+ const selectedValues = React56.useMemo(() => value ?? [], [value]);
14500
+ const hasValue = selectedValues.length > 0;
14501
+ const isEmpty = !hasValue;
14502
+ const isBlocked = Boolean(disabled) || Boolean(loading) || Boolean(readOnly);
14503
+ const triggerError = error ?? invalid;
14504
+ const hasInvalidState = Boolean(triggerError);
14505
+ const errorMessage = typeof error === "string" ? error : void 0;
14506
+ const wrapperWidth = toCssSize(width);
14507
+ const { triggerId, labelId, valueId, listboxId, describedErrorId, errorId, getOptionId: getOptionId2 } = useSelectIds2({ name, hasValue, error, hideErrorMessage });
14508
+ const filteredOptions = React56.useMemo(
14509
+ () => options.filter((option) => filterOption(option, searchValue)),
14510
+ [options, searchValue, filterOption]
14511
+ );
14512
+ const trimmedSearch = searchValue.trim();
14513
+ const canCreateNewOption = React56.useMemo(() => {
14514
+ if (!isCreatable || !trimmedSearch) return false;
14515
+ if (isValidNewOption) return isValidNewOption(trimmedSearch, selectedValues, options);
14516
+ const lower = trimmedSearch.toLowerCase();
14517
+ const existsInOptions = options.some(
14518
+ (option) => typeof option.label === "string" && option.label.toLowerCase() === lower
14519
+ );
14520
+ const existsInSelected = selectedValues.some(
14521
+ (option) => typeof option.label === "string" && option.label.toLowerCase() === lower
14522
+ );
14523
+ return !existsInOptions && !existsInSelected;
14524
+ }, [isCreatable, trimmedSearch, isValidNewOption, options, selectedValues]);
14525
+ React56.useImperativeHandle(
14526
+ ref,
14527
+ () => containerRef.current
14528
+ );
14529
+ useOutsideClick({
14530
+ elementRef: containerRef,
14531
+ onOutsideClick: () => {
14532
+ setIsOpen(false);
14533
+ setIsFocused(false);
14534
+ },
14535
+ isDisabled: !isOpen
14536
+ });
14537
+ React56.useEffect(() => {
14538
+ if (isBlocked) setIsOpen(false);
14539
+ }, [isBlocked]);
14540
+ React56.useEffect(() => {
14541
+ if (!isOpen) {
14542
+ setSearchValue("");
14543
+ setHighlightedIndex(-1);
14544
+ }
14545
+ }, [isOpen]);
14546
+ React56.useEffect(() => {
14547
+ if (!isOpen || filteredOptions.length === 0) {
14548
+ setHighlightedIndex(-1);
14549
+ return;
14550
+ }
14551
+ setHighlightedIndex((current) => {
14552
+ if (current >= 0 && current < filteredOptions.length) return current;
14553
+ return getFirstEnabledOptionIndex2(filteredOptions);
14554
+ });
14555
+ }, [isOpen, filteredOptions]);
14556
+ const openMenu = () => {
14557
+ if (isBlocked) return;
14558
+ setIsOpen(true);
14559
+ setIsFocused(true);
14560
+ };
14561
+ const toggleOption = (option) => {
14562
+ if (option.isDisabled) return;
14563
+ const exists = isValueSelected(selectedValues, option);
14564
+ const next = exists ? selectedValues.filter((item) => item.value !== option.value) : [...selectedValues, option];
14565
+ onChange(next);
14566
+ setSearchValue("");
14567
+ if (closeMenuOnSelect) {
14568
+ setIsOpen(false);
14569
+ } else {
14570
+ inputRef.current?.focus();
14571
+ }
14572
+ };
14573
+ const removeOption = (option) => {
14574
+ if (isBlocked) return;
14575
+ onChange(selectedValues.filter((item) => item.value !== option.value));
14576
+ inputRef.current?.focus();
14577
+ };
14578
+ const clearAll = () => {
14579
+ if (isBlocked) return;
14580
+ onChange([]);
14581
+ inputRef.current?.focus();
14582
+ };
14583
+ const createOption = React56.useCallback(() => {
14584
+ if (!canCreateNewOption) return;
14585
+ const newOption = onCreateOption?.(trimmedSearch) ?? { value: trimmedSearch, label: trimmedSearch };
14586
+ onChange([...selectedValues, newOption]);
14587
+ setSearchValue("");
14588
+ inputRef.current?.focus();
14589
+ if (closeMenuOnSelect) setIsOpen(false);
14590
+ }, [
14591
+ canCreateNewOption,
14592
+ closeMenuOnSelect,
14593
+ onChange,
14594
+ onCreateOption,
14595
+ selectedValues,
14596
+ trimmedSearch
14597
+ ]);
14598
+ const handleInputKeyDown = (event) => {
14599
+ if (event.key === "Backspace" && !searchValue && selectedValues.length > 0) {
14600
+ event.preventDefault();
14601
+ onChange(selectedValues.slice(0, -1));
14602
+ return;
14603
+ }
14604
+ if (event.key === "ArrowDown") {
14605
+ event.preventDefault();
14606
+ if (!isOpen) {
14607
+ openMenu();
14608
+ return;
14609
+ }
14610
+ const next = getNextEnabledOptionIndex2(filteredOptions, highlightedIndex + 1, 1);
14611
+ if (next >= 0) setHighlightedIndex(next);
14612
+ return;
14613
+ }
14614
+ if (event.key === "ArrowUp") {
14615
+ event.preventDefault();
14616
+ if (!isOpen) {
14617
+ openMenu();
14618
+ return;
14619
+ }
14620
+ const next = getNextEnabledOptionIndex2(filteredOptions, highlightedIndex - 1, -1);
14621
+ if (next >= 0) setHighlightedIndex(next);
14622
+ return;
14623
+ }
14624
+ if (event.key === "Enter") {
14625
+ if (!isOpen) return;
14626
+ event.preventDefault();
14627
+ const option = filteredOptions[highlightedIndex];
14628
+ if (option && !option.isDisabled) {
14629
+ toggleOption(option);
14630
+ } else if (canCreateNewOption) {
14631
+ createOption();
14632
+ }
14633
+ return;
14634
+ }
14635
+ if (event.key === "Escape") {
14636
+ event.preventDefault();
14637
+ setIsOpen(false);
14638
+ }
14639
+ };
14640
+ const handleContainerClick = () => {
14641
+ if (isBlocked) return;
14642
+ inputRef.current?.focus();
14643
+ setIsOpen(true);
14644
+ };
14645
+ const handleInputBlur = (event) => {
14646
+ if (containerRef.current?.contains(event.relatedTarget)) return;
14647
+ setIsFocused(false);
14648
+ onBlur?.(event);
14649
+ };
14650
+ return /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)(
14651
+ "div",
14652
+ {
14653
+ ref: containerRef,
14654
+ onBlur: handleInputBlur,
14655
+ className: cn(
14656
+ "relative min-h-[68px] w-full max-w-[var(--max-field-width)]",
14657
+ disabled && "cursor-not-allowed opacity-50",
14658
+ loading && "cursor-progress",
14659
+ className
14660
+ ),
14661
+ style: wrapperWidth ? { width: wrapperWidth } : void 0,
14662
+ children: [
14663
+ topLabel && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14664
+ "label",
14665
+ {
14666
+ htmlFor: triggerId,
14667
+ className: "mb-2 block text-[14px] font-medium text-[var(--chekin-color-brand-navy)]",
14668
+ children: topLabel
14669
+ }
14670
+ ),
14671
+ name && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14672
+ "input",
14673
+ {
14674
+ type: "hidden",
14675
+ name,
14676
+ value: selectedValues.map((item) => String(item.value)).join(",")
14677
+ }
14678
+ ),
14679
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)("div", { className: "relative w-full", children: [
14680
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)(
14681
+ "div",
14682
+ {
14683
+ id: triggerId,
14684
+ role: "combobox",
14685
+ "aria-haspopup": "listbox",
14686
+ "aria-expanded": isOpen,
14687
+ "aria-controls": listboxId,
14688
+ "aria-labelledby": hasValue && valueId ? `${labelId} ${valueId}` : labelId,
14689
+ "aria-describedby": describedErrorId,
14690
+ "aria-invalid": hasInvalidState,
14691
+ "aria-busy": loading,
14692
+ "aria-disabled": isBlocked,
14693
+ onClick: handleContainerClick,
14694
+ className: cn(
14695
+ "relative box-border flex w-full cursor-text flex-wrap items-center gap-2 rounded-[6px] border-0 px-4 py-[10px] text-left text-[16px] font-medium leading-5 outline-none transition-colors duration-200",
14696
+ "min-h-12",
14697
+ isEmpty && !isFocused ? "bg-[var(--chekin-color-surface-input-empty)]" : "bg-transparent",
14698
+ disabled && "cursor-not-allowed",
14699
+ loading && "cursor-progress"
14700
+ ),
14701
+ children: [
14702
+ selectedValues.map(
14703
+ (option) => renderChip ? /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(React56.Fragment, { children: renderChip(option, () => removeOption(option)) }, String(option.value)) : /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)(
14704
+ "span",
14705
+ {
14706
+ className: "inline-flex items-center gap-2 rounded-[4px] border border-[#acacd5] bg-[#f0f0f8] py-[2px] pl-[10px] pr-1 text-[12px] font-medium text-[var(--chekin-color-brand-navy)]",
14707
+ children: [
14708
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsx)("span", { className: "whitespace-nowrap", children: option.label }),
14709
+ !readOnly && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14710
+ "button",
14711
+ {
14712
+ type: "button",
14713
+ onClick: (event) => {
14714
+ event.stopPropagation();
14715
+ removeOption(option);
14716
+ },
14717
+ className: "flex h-[15px] w-[15px] items-center justify-center rounded-[3px] border-0 bg-transparent p-0 text-[#9696b9] hover:shadow-[0_3px_3px_#0f477734]",
14718
+ "aria-label": `Remove ${typeof option.label === "string" ? option.label : String(option.value)}`,
14719
+ children: /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(import_lucide_react48.SquareX, { size: 15, fill: "#9696b9", color: "#f8f8f8", strokeWidth: 1.8 })
14720
+ }
14721
+ )
14722
+ ]
14723
+ },
14724
+ String(option.value)
14725
+ )
14726
+ ),
14727
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14728
+ "input",
14729
+ {
14730
+ ref: inputRef,
14731
+ type: "text",
14732
+ id: `${triggerId}-input`,
14733
+ value: searchValue,
14734
+ onChange: (event) => {
14735
+ setSearchValue(event.target.value);
14736
+ if (!isOpen) setIsOpen(true);
14737
+ },
14738
+ onFocus: () => {
14739
+ setIsFocused(true);
14740
+ if (!isBlocked) setIsOpen(true);
14741
+ },
14742
+ onKeyDown: handleInputKeyDown,
14743
+ disabled: isBlocked,
14744
+ readOnly,
14745
+ placeholder: hasValue ? "" : placeholder ?? "",
14746
+ autoComplete: "off",
14747
+ className: cn(
14748
+ "m-0 box-border min-w-[40px] flex-1 border-0 bg-transparent p-0 text-[16px] font-medium leading-5 text-[var(--chekin-color-brand-navy)] outline-none placeholder:text-[var(--chekin-color-gray-1)]",
14749
+ isBlocked && "cursor-not-allowed"
14750
+ ),
14751
+ "aria-autocomplete": "list",
14752
+ "aria-controls": listboxId,
14753
+ "aria-activedescendant": isOpen && highlightedIndex >= 0 ? getOptionId2(highlightedIndex) : void 0
14754
+ }
14755
+ ),
14756
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)("span", { className: "ml-auto flex items-center gap-2 pl-2 text-[var(--chekin-color-gray-2)]", children: [
14757
+ loading && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(ThreeDotsLoader, { height: 18, width: 18 }),
14758
+ hasValue && !readOnly && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14759
+ "button",
14760
+ {
14761
+ type: "button",
14762
+ onClick: (event) => {
14763
+ event.stopPropagation();
14764
+ clearAll();
14765
+ },
14766
+ className: "flex h-5 w-5 items-center justify-center rounded-[3px] border-0 bg-transparent p-0 text-[#9696b9] hover:shadow-[0_3px_3px_#0f477734]",
14767
+ "aria-label": "Clear all",
14768
+ children: /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(import_lucide_react48.SquareX, { size: 15, fill: "#9696b9", color: "#f8f8f8", strokeWidth: 1.8 })
14769
+ }
14770
+ ),
14771
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14772
+ RotateArrow,
14773
+ {
14774
+ shouldRotate: isOpen,
14775
+ className: cn(
14776
+ isFocused || isOpen ? "text-[var(--chekin-color-brand-blue)]" : "text-[var(--chekin-color-gray-2)]"
14777
+ )
14778
+ }
14779
+ )
14780
+ ] })
14781
+ ]
14782
+ }
14783
+ ),
14784
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14785
+ Fieldset,
14786
+ {
14787
+ isFocused: isFocused || isOpen,
14788
+ invalid: hasInvalidState,
14789
+ isEmpty: isEmpty && !searchValue,
14790
+ isActivated: !isEmpty || isFocused || isOpen || Boolean(searchValue),
14791
+ disabled,
14792
+ loading,
14793
+ readOnly,
14794
+ htmlFor: `${triggerId}-input`,
14795
+ labelId,
14796
+ legend: typeof label === "string" ? label : void 0,
14797
+ label,
14798
+ tooltip,
14799
+ onClick: handleContainerClick
14800
+ }
14801
+ ),
14802
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)(
14803
+ "div",
14804
+ {
14805
+ className: cn(
14806
+ "absolute left-0 right-0 top-full z-20 overflow-hidden rounded-b-lg bg-white shadow-[0_30px_30px_0_rgba(33,72,255,0.2)]",
14807
+ dropdownClassName
14808
+ ),
14809
+ children: [
14810
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14811
+ SelectMenu,
14812
+ {
14813
+ id: listboxId,
14814
+ options: filteredOptions,
14815
+ labelledBy: labelId,
14816
+ describedBy: describedErrorId,
14817
+ selectedValues,
14818
+ highlightedIndex,
14819
+ onOptionClick: toggleOption,
14820
+ onOptionHover: setHighlightedIndex,
14821
+ disabled: isBlocked,
14822
+ menuClassName,
14823
+ listRef,
14824
+ selectedOptionRef: (index, node) => {
14825
+ optionRefs.current[index] = node;
14826
+ },
14827
+ getOptionId: getOptionId2,
14828
+ noOptionsMessage,
14829
+ isMulti: true
14830
+ }
14831
+ ),
14832
+ canCreateNewOption && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14833
+ "button",
14834
+ {
14835
+ type: "button",
14836
+ onClick: createOption,
14837
+ className: "flex w-full items-center justify-start border-0 border-t border-[#f2f4f8] bg-white px-4 py-[16px] text-left text-[16px] font-medium leading-5 text-[var(--chekin-color-brand-blue)] outline-none hover:bg-[var(--chekin-color-surface-pressed)]",
14838
+ children: formatCreateLabel(trimmedSearch)
14839
+ }
14840
+ )
14841
+ ]
14842
+ }
14843
+ )
14844
+ ] }),
14845
+ !errorMessage && optional && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)("span", { className: "mt-[1px] block text-left text-[14px] font-medium text-[var(--chekin-color-gray-1)]", children: typeof optional === "string" ? optional : "optional" }),
14846
+ !errorMessage && helperText && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)("span", { className: "mt-[1px] block text-[12px] font-normal text-[var(--chekin-color-gray-1)]", children: helperText }),
14847
+ errorMessage && !hideErrorMessage && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14848
+ FieldErrorMessage,
14849
+ {
14850
+ id: errorId,
14851
+ message: errorMessage,
14852
+ className: "mt-[1px] text-[14px]"
14853
+ }
14854
+ )
14855
+ ]
14856
+ }
14857
+ );
14858
+ }
14859
+ var DashboardMultiSelect = React56.forwardRef(
14860
+ DashboardMultiSelectInternal
14861
+ );
14862
+
14863
+ // src/dashboard/creatable-multi-select/CreatableMultiSelect.tsx
14864
+ var React57 = __toESM(require("react"), 1);
14865
+ var import_jsx_runtime159 = require("react/jsx-runtime");
14866
+ var DashboardCreatableMultiSelect = React57.forwardRef(
14867
+ function DashboardCreatableMultiSelect2(props, ref) {
14868
+ return /* @__PURE__ */ (0, import_jsx_runtime159.jsx)(DashboardMultiSelect, { ref, ...props, isCreatable: true });
14869
+ }
14870
+ );
14871
+
14872
+ // src/dashboard/infinite-scroll-select/InfiniteScrollSelect.tsx
14873
+ var React58 = __toESM(require("react"), 1);
14874
+ var import_lucide_react49 = require("lucide-react");
14875
+ var import_react_virtual2 = require("@tanstack/react-virtual");
14876
+ var import_jsx_runtime160 = require("react/jsx-runtime");
14877
+ var DEFAULT_ITEM_HEIGHT = 60;
14878
+ var DEFAULT_LIST_HEIGHT = 322;
14879
+ var DEFAULT_OVERSCAN = 5;
14880
+ var DEFAULT_LOAD_MORE_THRESHOLD = 5;
14881
+ function DashboardInfiniteScrollSelectInternal({
14882
+ options = [],
14883
+ value,
14884
+ onChange,
14885
+ onBlur,
14886
+ label,
14887
+ topLabel,
14888
+ placeholder,
14889
+ getValueLabel,
14890
+ disabled,
14891
+ loading,
14892
+ optional,
14893
+ tooltip,
14894
+ error,
14895
+ invalid,
14896
+ hideErrorMessage,
14897
+ className,
14898
+ menuClassName,
14899
+ dropdownClassName,
14900
+ name,
14901
+ width,
14902
+ noOptionsMessage,
14903
+ searchable = true,
14904
+ searchPlaceholder,
14905
+ filterOption = defaultFilterOption,
14906
+ helperText,
14907
+ canLoadMore,
14908
+ isLoadingMore,
14909
+ loadMoreItems,
14910
+ loadingMoreText = "Loading\u2026",
14911
+ onSearchChange,
14912
+ itemHeight = DEFAULT_ITEM_HEIGHT,
14913
+ listHeight = DEFAULT_LIST_HEIGHT,
14914
+ overscan = DEFAULT_OVERSCAN,
14915
+ loadMoreThreshold = DEFAULT_LOAD_MORE_THRESHOLD
14916
+ }, ref) {
14917
+ const containerRef = React58.useRef(null);
14918
+ const triggerRef = React58.useRef(null);
14919
+ const searchInputRef = React58.useRef(null);
14920
+ const scrollRef = React58.useRef(null);
14921
+ const [isOpen, setIsOpen] = React58.useState(false);
14922
+ const [searchValue, setSearchValue] = React58.useState("");
14923
+ const [highlightedIndex, setHighlightedIndex] = React58.useState(-1);
14924
+ const hasValue = Boolean(value);
14925
+ const isEmpty = !hasValue;
14926
+ const isBlocked = Boolean(disabled) || Boolean(loading);
14927
+ const triggerError = error ?? invalid;
14928
+ const hasInvalidState = Boolean(triggerError);
14929
+ const errorMessage = typeof error === "string" ? error : void 0;
14930
+ const wrapperWidth = toCssSize(width);
14931
+ const valueLabel = value ? getValueLabel?.(value) ?? String(value.label) : void 0;
14932
+ const { triggerId, labelId, valueId, listboxId, describedErrorId, errorId, getOptionId: getOptionId2 } = useSelectIds2({ name, hasValue, error, hideErrorMessage });
14933
+ const filteredOptions = React58.useMemo(() => {
14934
+ if (!searchable || !searchValue) return options;
14935
+ return options.filter((option) => filterOption(option, searchValue));
14936
+ }, [options, searchable, searchValue, filterOption]);
14937
+ const itemCount = filteredOptions.length + (canLoadMore || isLoadingMore ? 1 : 0);
14938
+ const virtualizer = (0, import_react_virtual2.useVirtualizer)({
14939
+ count: itemCount,
14940
+ getScrollElement: () => scrollRef.current,
14941
+ estimateSize: () => itemHeight,
14942
+ overscan
14943
+ });
14944
+ React58.useImperativeHandle(ref, () => triggerRef.current, []);
14945
+ useOutsideClick({
14946
+ elementRef: containerRef,
14947
+ onOutsideClick: () => setIsOpen(false),
14948
+ isDisabled: !isOpen
14949
+ });
14950
+ React58.useEffect(() => {
14951
+ if (isBlocked) setIsOpen(false);
14952
+ }, [isBlocked]);
14953
+ React58.useEffect(() => {
14954
+ if (!isOpen) {
14955
+ setSearchValue("");
14956
+ setHighlightedIndex(-1);
14957
+ return;
14958
+ }
14959
+ const selectedIndex = getOptionIndex2(filteredOptions, value);
14960
+ setHighlightedIndex(
14961
+ selectedIndex >= 0 ? selectedIndex : getFirstEnabledOptionIndex2(filteredOptions)
14962
+ );
14963
+ if (searchable) {
14964
+ const frame = window.requestAnimationFrame(() => searchInputRef.current?.focus());
14965
+ return () => window.cancelAnimationFrame(frame);
14966
+ }
14967
+ }, [isOpen, filteredOptions, searchable, value]);
14968
+ const virtualItems = virtualizer.getVirtualItems();
14969
+ React58.useEffect(() => {
14970
+ if (!isOpen || !canLoadMore || isLoadingMore || !loadMoreItems) return;
14971
+ if (virtualItems.length === 0) return;
14972
+ const lastItem = virtualItems[virtualItems.length - 1];
14973
+ if (lastItem && lastItem.index >= filteredOptions.length - loadMoreThreshold) {
14974
+ loadMoreItems();
14975
+ }
14976
+ }, [
14977
+ canLoadMore,
14978
+ filteredOptions.length,
14979
+ isLoadingMore,
14980
+ isOpen,
14981
+ loadMoreItems,
14982
+ loadMoreThreshold,
14983
+ virtualItems
14984
+ ]);
14985
+ React58.useEffect(() => {
14986
+ if (!isOpen || highlightedIndex < 0) return;
14987
+ virtualizer.scrollToIndex(highlightedIndex, { align: "auto" });
14988
+ }, [highlightedIndex, isOpen, virtualizer]);
14989
+ const toggleMenu = () => {
14990
+ if (isBlocked) return;
14991
+ setIsOpen((prev) => !prev);
14992
+ };
14993
+ const handleSelect = (option) => {
14994
+ if (option.isDisabled) return;
14995
+ onChange(option);
14996
+ setIsOpen(false);
14997
+ triggerRef.current?.focus();
14998
+ };
14999
+ const handleTriggerKeyDown = (event) => {
15000
+ if (isBlocked) return;
15001
+ if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Enter" || event.key === " ") {
15002
+ event.preventDefault();
15003
+ setIsOpen(true);
15004
+ }
15005
+ };
15006
+ const handleSearchKeyDown = (event) => {
15007
+ if (event.key === "ArrowDown") {
15008
+ event.preventDefault();
15009
+ const next = getNextEnabledOptionIndex2(filteredOptions, highlightedIndex + 1, 1);
15010
+ if (next >= 0) setHighlightedIndex(next);
15011
+ return;
15012
+ }
15013
+ if (event.key === "ArrowUp") {
15014
+ event.preventDefault();
15015
+ const next = getNextEnabledOptionIndex2(filteredOptions, highlightedIndex - 1, -1);
15016
+ if (next >= 0) setHighlightedIndex(next);
15017
+ return;
15018
+ }
15019
+ if (event.key === "Enter") {
15020
+ event.preventDefault();
15021
+ const option = filteredOptions[highlightedIndex];
15022
+ if (option && !option.isDisabled) handleSelect(option);
15023
+ return;
15024
+ }
15025
+ if (event.key === "Escape") {
15026
+ event.preventDefault();
15027
+ setIsOpen(false);
15028
+ triggerRef.current?.focus();
15029
+ return;
15030
+ }
15031
+ if (event.key === "Tab") {
15032
+ setIsOpen(false);
15033
+ }
15034
+ };
15035
+ const handleSearchChange = (event) => {
15036
+ const next = event.target.value;
15037
+ setSearchValue(next);
15038
+ onSearchChange?.(next);
15039
+ };
15040
+ const emptyMessage = noOptionsMessage?.();
15041
+ const totalSize = virtualizer.getTotalSize();
15042
+ const measuredListHeight = Math.min(listHeight, Math.max(totalSize, itemHeight));
15043
+ return /* @__PURE__ */ (0, import_jsx_runtime160.jsxs)(
15044
+ "div",
15045
+ {
15046
+ ref: containerRef,
15047
+ className: cn(
15048
+ "relative w-full max-w-[var(--max-field-width)]",
15049
+ disabled && "cursor-not-allowed opacity-50",
15050
+ loading && "cursor-progress",
15051
+ className
15052
+ ),
15053
+ style: wrapperWidth ? { width: wrapperWidth } : void 0,
15054
+ children: [
15055
+ name && /* @__PURE__ */ (0, import_jsx_runtime160.jsx)("input", { type: "hidden", name, value: value ? String(value.value) : "" }),
15056
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsxs)("div", { className: "relative min-h-[68px] w-full", children: [
15057
+ topLabel && /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(
15058
+ "label",
15059
+ {
15060
+ htmlFor: triggerId,
15061
+ className: "mb-2 block text-[14px] font-medium text-[var(--chekin-color-brand-navy)]",
15062
+ children: topLabel
15063
+ }
15064
+ ),
15065
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsxs)("div", { className: "relative w-full", children: [
15066
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsxs)(
15067
+ "button",
15068
+ {
15069
+ id: triggerId,
15070
+ ref: triggerRef,
15071
+ type: "button",
15072
+ "aria-haspopup": "listbox",
15073
+ "aria-expanded": isOpen,
15074
+ "aria-controls": listboxId,
15075
+ "aria-labelledby": hasValue && valueId ? `${labelId} ${valueId}` : labelId,
15076
+ "aria-describedby": describedErrorId,
15077
+ "aria-invalid": hasInvalidState,
15078
+ "aria-busy": loading,
15079
+ disabled: isBlocked,
15080
+ onClick: toggleMenu,
15081
+ onKeyDown: handleTriggerKeyDown,
15082
+ onBlur,
15083
+ className: cn(
15084
+ "relative m-0 box-border flex h-12 w-full cursor-pointer items-center justify-between gap-2 rounded-[6px] border-0 px-4 text-left text-[16px] font-medium leading-5 outline-none transition-colors duration-200",
15085
+ isEmpty ? "bg-[var(--chekin-color-surface-input-empty)] text-[var(--chekin-color-gray-1)]" : "bg-transparent text-[var(--chekin-color-brand-navy)]",
15086
+ disabled && "cursor-not-allowed opacity-50",
15087
+ loading && "cursor-progress"
15088
+ ),
15089
+ children: [
15090
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsx)("span", { id: valueId, className: "block min-w-0 flex-1 truncate text-left", children: valueLabel ?? placeholder ?? label }),
15091
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsxs)("span", { className: "pointer-events-none flex items-center gap-2 text-[var(--chekin-color-gray-2)]", children: [
15092
+ loading && /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(ThreeDotsLoader, { height: 18, width: 18 }),
15093
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(
15094
+ import_lucide_react49.ChevronDown,
15095
+ {
15096
+ size: 16,
15097
+ className: cn(
15098
+ "transition-transform duration-200",
15099
+ isOpen && "rotate-180 text-[var(--chekin-color-brand-blue)]"
15100
+ )
15101
+ }
15102
+ )
15103
+ ] })
15104
+ ]
15105
+ }
15106
+ ),
15107
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(
15108
+ Fieldset,
15109
+ {
15110
+ isFocused: isOpen,
15111
+ invalid: hasInvalidState,
15112
+ isEmpty,
15113
+ isActivated: !isEmpty || isOpen,
15114
+ disabled,
15115
+ loading,
15116
+ htmlFor: triggerId,
15117
+ labelId,
15118
+ legend: typeof label === "string" ? label : void 0,
15119
+ label,
15120
+ tooltip,
15121
+ onClick: !isBlocked ? toggleMenu : void 0
15122
+ }
15123
+ ),
15124
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime160.jsxs)(
15125
+ "div",
15126
+ {
15127
+ className: cn(
15128
+ "absolute left-0 right-0 top-full z-20 overflow-hidden rounded-b-lg bg-white shadow-[0_30px_30px_0_rgba(33,72,255,0.2)]",
15129
+ dropdownClassName
15130
+ ),
15131
+ children: [
15132
+ searchable && /* @__PURE__ */ (0, import_jsx_runtime160.jsx)("div", { className: "border-b border-[#f2f4f8] px-4 pb-2 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(
15133
+ "input",
15134
+ {
15135
+ ref: searchInputRef,
15136
+ type: "text",
15137
+ value: searchValue,
15138
+ placeholder: searchPlaceholder,
15139
+ onChange: handleSearchChange,
15140
+ onKeyDown: handleSearchKeyDown,
15141
+ autoComplete: "off",
15142
+ "aria-controls": listboxId,
15143
+ "aria-activedescendant": highlightedIndex >= 0 ? getOptionId2(highlightedIndex) : void 0,
15144
+ className: "m-0 box-border h-9 w-full rounded-md border border-[var(--chekin-color-gray-3)] bg-white px-3 text-[16px] font-medium text-[var(--chekin-color-brand-navy)] outline-none transition-colors placeholder:text-[var(--chekin-color-gray-1)] focus:border-[var(--chekin-color-brand-blue)]"
15145
+ }
15146
+ ) }),
15147
+ itemCount === 0 ? /* @__PURE__ */ (0, import_jsx_runtime160.jsx)("div", { className: "px-4 py-[20px] text-left text-[16px] text-[var(--chekin-color-brand-navy)]", children: emptyMessage ?? "No options" }) : /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(
15148
+ "div",
15149
+ {
15150
+ ref: scrollRef,
15151
+ className: cn("overflow-y-auto", menuClassName),
15152
+ style: { height: `${measuredListHeight}px` },
15153
+ children: /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(
15154
+ "div",
15155
+ {
15156
+ id: listboxId,
15157
+ role: "listbox",
15158
+ tabIndex: -1,
15159
+ "aria-labelledby": labelId,
15160
+ "aria-describedby": describedErrorId,
15161
+ "aria-activedescendant": highlightedIndex >= 0 ? getOptionId2(highlightedIndex) : void 0,
15162
+ className: "relative w-full",
15163
+ style: { height: `${totalSize}px` },
15164
+ children: virtualItems.map((virtualItem) => {
15165
+ const isLoaderRow = virtualItem.index >= filteredOptions.length;
15166
+ const option = filteredOptions[virtualItem.index];
15167
+ const isSelected = !isLoaderRow && option ? option.value === value?.value : false;
15168
+ const isHighlighted = virtualItem.index === highlightedIndex;
15169
+ const isOptionDisabled = Boolean(isBlocked || option?.isDisabled);
15170
+ return /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(
15171
+ "div",
15172
+ {
15173
+ "data-index": virtualItem.index,
15174
+ className: "absolute left-0 top-0 w-full",
15175
+ style: {
15176
+ height: `${virtualItem.size}px`,
15177
+ transform: `translateY(${virtualItem.start}px)`
15178
+ },
15179
+ children: isLoaderRow ? /* @__PURE__ */ (0, import_jsx_runtime160.jsxs)("div", { className: "flex h-full items-center justify-center gap-2 px-4 text-[14px] font-medium text-[var(--chekin-color-gray-1)]", children: [
15180
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(ThreeDotsLoader, { height: 18, width: 18 }),
15181
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsx)("span", { children: loadingMoreText })
15182
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime160.jsxs)(
15183
+ "button",
15184
+ {
15185
+ id: getOptionId2(virtualItem.index),
15186
+ type: "button",
15187
+ role: "option",
15188
+ "aria-selected": isSelected,
15189
+ "aria-disabled": isOptionDisabled,
15190
+ tabIndex: -1,
15191
+ disabled: isOptionDisabled,
15192
+ onClick: () => option && handleSelect(option),
15193
+ onMouseMove: () => setHighlightedIndex(virtualItem.index),
15194
+ className: cn(
15195
+ "flex h-full w-full items-start justify-between border-0 border-b border-[#f2f4f8] bg-white px-4 text-left text-[16px] font-medium leading-5 text-[var(--chekin-color-brand-navy)] outline-none transition-colors",
15196
+ isHighlighted && !isSelected && "cursor-pointer text-[var(--chekin-color-brand-blue)]",
15197
+ isSelected && "cursor-default font-bold text-[var(--chekin-color-brand-navy)]",
15198
+ isOptionDisabled && "cursor-default opacity-30"
15199
+ ),
15200
+ children: [
15201
+ /* @__PURE__ */ (0, import_jsx_runtime160.jsx)("span", { className: "block break-words", children: option?.label }),
15202
+ option?.description && /* @__PURE__ */ (0, import_jsx_runtime160.jsx)("span", { className: "ml-2 mt-[3px] shrink-0 text-[12px] font-bold italic text-[#777e91]", children: option.description })
15203
+ ]
15204
+ }
15205
+ )
15206
+ },
15207
+ virtualItem.key
15208
+ );
15209
+ })
15210
+ }
15211
+ )
15212
+ }
15213
+ )
15214
+ ]
15215
+ }
15216
+ )
15217
+ ] }),
15218
+ !errorMessage && optional && /* @__PURE__ */ (0, import_jsx_runtime160.jsx)("span", { className: "mt-[1px] block text-left text-[14px] font-medium text-[var(--chekin-color-gray-1)]", children: typeof optional === "string" ? optional : "optional" }),
15219
+ !errorMessage && helperText && /* @__PURE__ */ (0, import_jsx_runtime160.jsx)("span", { className: "mt-[1px] block text-[12px] font-normal text-[var(--chekin-color-gray-1)]", children: helperText }),
15220
+ errorMessage && !hideErrorMessage && /* @__PURE__ */ (0, import_jsx_runtime160.jsx)(
15221
+ FieldErrorMessage,
15222
+ {
15223
+ id: errorId,
15224
+ message: errorMessage,
15225
+ className: "mt-[1px] text-[14px]"
15226
+ }
15227
+ )
15228
+ ] })
15229
+ ]
15230
+ }
15231
+ );
15232
+ }
15233
+ var DashboardInfiniteScrollSelect = React58.forwardRef(
15234
+ DashboardInfiniteScrollSelectInternal
15235
+ );
15236
+
15237
+ // src/searchable-select/SearchableSelect.tsx
15238
+ var React59 = __toESM(require("react"), 1);
15239
+ var import_lucide_react50 = require("lucide-react");
15240
+ var import_react_virtual3 = require("@tanstack/react-virtual");
15241
+ var import_react82 = require("react");
15242
+ var import_jsx_runtime161 = require("react/jsx-runtime");
15243
+ var ROW_HEIGHT = 48;
15244
+ var DESKTOP_LIST_HEIGHT = 280;
15245
+ var MOBILE_LIST_HEIGHT = 420;
15246
+ var LOAD_MORE_THRESHOLD = 6;
15247
+ function defaultFilter(option, searchValue) {
15248
+ return String(option.label).toLowerCase().includes(searchValue.trim().toLowerCase());
15249
+ }
15250
+ var SearchableSelectInternal = ({
15251
+ options,
15252
+ value,
15253
+ onChange,
15254
+ onBlur,
15255
+ onOpenChange,
15256
+ searchValue,
15257
+ onSearchChange,
15258
+ filterOption = defaultFilter,
15259
+ loading,
15260
+ hasNextPage,
15261
+ onLoadMore,
15262
+ variant = "default",
15263
+ label,
15264
+ topLabel,
15265
+ placeholder,
15266
+ searchPlaceholder = "Search...",
15267
+ mobileTitle,
15268
+ getValueLabel,
15269
+ disabled,
15270
+ error,
15271
+ invalid,
15272
+ optional,
15273
+ tooltip,
15274
+ hideErrorMessage,
15275
+ name,
15276
+ className,
15277
+ dropdownClassName,
15278
+ menuClassName,
15279
+ noOptionsMessage,
15280
+ loadingMessage
15281
+ }, ref) => {
15282
+ const { isMatch: isMobile2 } = useScreenResize(DEVICE.mobileXL);
15283
+ const reactId = React59.useId();
15284
+ const [open, setOpen] = React59.useState(false);
15285
+ const [internalSearchValue, setInternalSearchValue] = React59.useState("");
15286
+ const [highlightedIndex, setHighlightedIndex] = React59.useState(-1);
15287
+ const containerRef = React59.useRef(null);
15288
+ const triggerRef = React59.useRef(null);
15289
+ const inputRef = React59.useRef(null);
15290
+ const listboxId = `${reactId}-listbox`;
15291
+ const labelId = `${reactId}-label`;
15292
+ const valueId = `${reactId}-value`;
15293
+ const helperTextId = `${reactId}-helper`;
15294
+ const errorId = `${reactId}-error`;
15295
+ const searchInputId = `${reactId}-search`;
15296
+ const effectiveSearchValue = searchValue ?? internalSearchValue;
15297
+ const shouldFilterLocally = !onSearchChange && filterOption !== null;
15298
+ const visibleOptions = React59.useMemo(() => {
15299
+ if (!shouldFilterLocally || !effectiveSearchValue) {
15300
+ return options;
15301
+ }
15302
+ return options.filter((option) => filterOption(option, effectiveSearchValue));
15303
+ }, [effectiveSearchValue, filterOption, options, shouldFilterLocally]);
15304
+ const selectedIndex = React59.useMemo(
15305
+ () => visibleOptions.findIndex((option) => option.value === value?.value),
15306
+ [value?.value, visibleOptions]
15307
+ );
15308
+ const helperText = placeholder ?? label;
15309
+ const valueLabel = value ? getValueLabel?.(value) ?? String(value.label) : void 0;
15310
+ const isBlocked = Boolean(disabled) || Boolean(loading);
15311
+ const triggerError = error ?? invalid;
15312
+ const describedBy = error && !hideErrorMessage ? errorId : void 0;
15313
+ const activeOptionId = highlightedIndex >= 0 ? getOptionId(reactId, highlightedIndex) : void 0;
15314
+ useOutsideClick({
15315
+ elementRef: containerRef,
15316
+ onOutsideClick: () => closeSelect(),
15317
+ isDisabled: !open || isMobile2
15318
+ });
15319
+ const handleOnOpenChange = useEvent(onOpenChange);
15320
+ const setSelectOpen = (0, import_react82.useCallback)(
15321
+ (nextOpen, options2) => {
15322
+ setOpen(nextOpen);
15323
+ handleOnOpenChange?.(nextOpen);
15324
+ if (!nextOpen && options2?.restoreFocus) {
15325
+ triggerRef.current?.focus();
15326
+ }
15327
+ },
15328
+ [handleOnOpenChange]
15329
+ );
15330
+ React59.useEffect(() => {
15331
+ if (isBlocked) {
15332
+ setSelectOpen(false);
15333
+ return;
15334
+ }
15335
+ if (!open) return;
15336
+ const frameId = window.requestAnimationFrame(() => {
15337
+ inputRef.current?.focus();
15338
+ });
15339
+ return () => {
15340
+ window.cancelAnimationFrame(frameId);
15341
+ };
15342
+ }, [isBlocked, open, setSelectOpen]);
15343
+ React59.useEffect(() => {
15344
+ if (!open) {
15345
+ setHighlightedIndex(-1);
15346
+ return;
15347
+ }
15348
+ setHighlightedIndex((currentIndex) => {
15349
+ if (currentIndex >= 0 && currentIndex < visibleOptions.length && !visibleOptions[currentIndex]?.isDisabled) {
15350
+ return currentIndex;
15351
+ }
15352
+ return selectedIndex >= 0 ? selectedIndex : getFirstEnabledIndex(visibleOptions);
15353
+ });
15354
+ }, [open, selectedIndex, visibleOptions]);
15355
+ function openSelect() {
15356
+ if (isBlocked) return;
15357
+ setSelectOpen(true);
15358
+ }
15359
+ function closeSelect() {
15360
+ setSelectOpen(false, { restoreFocus: true });
15361
+ }
15362
+ function handleSearchChange(nextValue) {
15363
+ if (!onSearchChange) {
15364
+ setInternalSearchValue(nextValue);
15365
+ }
15366
+ onSearchChange?.(nextValue);
15367
+ }
15368
+ function handleSelect(option) {
15369
+ if (isBlocked || option.isDisabled) return;
15370
+ onChange(option);
15371
+ setSelectOpen(false, { restoreFocus: true });
15372
+ }
15373
+ function moveHighlight(step) {
15374
+ const startIndex = highlightedIndex >= 0 ? highlightedIndex + step : step === 1 ? 0 : visibleOptions.length - 1;
15375
+ const nextIndex = getNextEnabledIndex(visibleOptions, startIndex, step);
15376
+ if (nextIndex >= 0) {
15377
+ setHighlightedIndex(nextIndex);
15378
+ }
15379
+ }
15380
+ function handleTriggerKeyDown(event) {
15381
+ if (isBlocked) return;
15382
+ if (event.key === "Enter" || event.key === " " || event.key === "ArrowDown" || event.key === "ArrowUp") {
15383
+ event.preventDefault();
15384
+ openSelect();
15385
+ }
15386
+ }
15387
+ function handleSearchKeyDown(event) {
15388
+ if (event.key === "Escape") {
15389
+ event.preventDefault();
15390
+ closeSelect();
15391
+ return;
15392
+ }
15393
+ if (event.key === "ArrowDown") {
15394
+ event.preventDefault();
15395
+ moveHighlight(1);
15396
+ return;
15397
+ }
15398
+ if (event.key === "ArrowUp") {
15399
+ event.preventDefault();
15400
+ moveHighlight(-1);
15401
+ return;
15402
+ }
15403
+ if (event.key === "Enter") {
15404
+ event.preventDefault();
15405
+ const option = visibleOptions[highlightedIndex];
15406
+ if (option) {
15407
+ handleSelect(option);
15408
+ }
15409
+ }
15410
+ }
15411
+ const content = /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
15412
+ SearchableSelectContent,
15413
+ {
15414
+ inputId: searchInputId,
15415
+ listboxId,
15416
+ labelId,
15417
+ activeOptionId,
15418
+ inputRef,
15419
+ options: visibleOptions,
15420
+ value,
15421
+ searchValue: effectiveSearchValue,
15422
+ searchPlaceholder,
15423
+ highlightedIndex,
15424
+ loading,
15425
+ hasNextPage,
15426
+ onLoadMore,
15427
+ menuClassName,
15428
+ noOptionsMessage,
15429
+ loadingMessage,
15430
+ height: isMobile2 ? MOBILE_LIST_HEIGHT : DESKTOP_LIST_HEIGHT,
15431
+ idPrefix: reactId,
15432
+ onSearchChange: handleSearchChange,
15433
+ onSearchKeyDown: handleSearchKeyDown,
15434
+ onOptionClick: handleSelect,
15435
+ onOptionHover: setHighlightedIndex
15436
+ }
15437
+ );
15438
+ React59.useImperativeHandle(ref, () => triggerRef.current, []);
15439
+ return /* @__PURE__ */ (0, import_jsx_runtime161.jsxs)("div", { ref: containerRef, className: cn("relative w-full max-w-[425px]", className), children: [
15440
+ name && /* @__PURE__ */ (0, import_jsx_runtime161.jsx)("input", { type: "hidden", name, value: value ? String(value.value) : "" }),
15441
+ /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
15442
+ FieldTrigger,
15443
+ {
15444
+ id: `${reactId}-trigger`,
15445
+ ref: triggerRef,
15446
+ variant,
15447
+ "aria-haspopup": "listbox",
15448
+ "aria-expanded": open,
15449
+ "aria-controls": listboxId,
15450
+ label,
15451
+ topLabel,
15452
+ labelId,
15453
+ valueId,
15454
+ helperTextId,
15455
+ errorId: error ? errorId : void 0,
15456
+ labelText: topLabel ? helperText : void 0,
15457
+ valueText: valueLabel,
15458
+ placeholder: helperText,
15459
+ describedBy,
15460
+ error: triggerError,
15461
+ loading,
15462
+ optional,
15463
+ tooltip,
15464
+ forceLabelText: Boolean(optional) || Boolean(tooltip),
15465
+ hideErrorMessage,
15466
+ disabled,
15467
+ onClick: () => {
15468
+ if (open) {
15469
+ closeSelect();
15470
+ return;
15471
+ }
15472
+ openSelect();
15473
+ },
15474
+ onKeyDown: handleTriggerKeyDown,
15475
+ onBlur,
15476
+ trailingAdornment: /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
15477
+ import_lucide_react50.ChevronDown,
15478
+ {
15479
+ className: cn(
15480
+ "h-6 w-6 text-[#1F1F1B] transition-transform",
15481
+ open && "rotate-180"
15482
+ )
15483
+ }
15484
+ )
15485
+ }
15486
+ ),
15487
+ isMobile2 ? /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
15488
+ Drawer,
15489
+ {
13898
15490
  open,
13899
15491
  onOpenChange: (nextOpen) => {
13900
15492
  if (isBlocked && nextOpen) return;
@@ -13904,13 +15496,13 @@ var SearchableSelectInternal = ({
13904
15496
  }
13905
15497
  closeSelect();
13906
15498
  },
13907
- children: /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)(DrawerContent, { onClose: closeSelect, lockScroll: false, children: [
13908
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(DrawerTitle, { className: "sr-only", children: mobileTitle ?? label }),
13909
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(DrawerDescription, { className: "sr-only", children: label }),
13910
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("div", { className: "px-5 pb-5 pt-1", children: content })
15499
+ children: /* @__PURE__ */ (0, import_jsx_runtime161.jsxs)(DrawerContent, { onClose: closeSelect, lockScroll: false, children: [
15500
+ /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(DrawerTitle, { className: "sr-only", children: mobileTitle ?? label }),
15501
+ /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(DrawerDescription, { className: "sr-only", children: label }),
15502
+ /* @__PURE__ */ (0, import_jsx_runtime161.jsx)("div", { className: "px-5 pb-5 pt-1", children: content })
13911
15503
  ] })
13912
15504
  }
13913
- ) : open ? /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
15505
+ ) : open ? /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
13914
15506
  "div",
13915
15507
  {
13916
15508
  className: cn(
@@ -13922,7 +15514,7 @@ var SearchableSelectInternal = ({
13922
15514
  ) : null
13923
15515
  ] });
13924
15516
  };
13925
- var SearchableSelect = React53.forwardRef(
15517
+ var SearchableSelect = React59.forwardRef(
13926
15518
  SearchableSelectInternal
13927
15519
  );
13928
15520
  function SearchableSelectContent({
@@ -13949,11 +15541,11 @@ function SearchableSelectContent({
13949
15541
  onOptionClick,
13950
15542
  onOptionHover
13951
15543
  }) {
13952
- const listRef = React53.useRef(null);
13953
- const lastLoadMoreOptionsLengthRef = React53.useRef(null);
13954
- const previousHighlightedIndexRef = React53.useRef(highlightedIndex);
15544
+ const listRef = React59.useRef(null);
15545
+ const lastLoadMoreOptionsLengthRef = React59.useRef(null);
15546
+ const previousHighlightedIndexRef = React59.useRef(highlightedIndex);
13955
15547
  const rowCount = options.length + (loading && options.length > 0 ? 1 : 0);
13956
- const virtualizer = (0, import_react_virtual2.useVirtualizer)({
15548
+ const virtualizer = (0, import_react_virtual3.useVirtualizer)({
13957
15549
  count: rowCount,
13958
15550
  getScrollElement: () => listRef.current,
13959
15551
  estimateSize: () => ROW_HEIGHT,
@@ -13962,7 +15554,7 @@ function SearchableSelectContent({
13962
15554
  const virtualItems = virtualizer.getVirtualItems();
13963
15555
  const emptyMessage = noOptionsMessage?.() ?? "No matches found";
13964
15556
  const loadingText = loadingMessage?.() ?? "Loading...";
13965
- React53.useEffect(() => {
15557
+ React59.useEffect(() => {
13966
15558
  const lastItem = virtualItems[virtualItems.length - 1];
13967
15559
  const shouldLoadMore = !!lastItem && hasNextPage && !loading && lastItem.index >= options.length - LOAD_MORE_THRESHOLD;
13968
15560
  if (shouldLoadMore && lastLoadMoreOptionsLengthRef.current !== options.length) {
@@ -13970,23 +15562,23 @@ function SearchableSelectContent({
13970
15562
  onLoadMore?.();
13971
15563
  }
13972
15564
  }, [hasNextPage, loading, onLoadMore, options.length, virtualItems]);
13973
- React53.useEffect(() => {
15565
+ React59.useEffect(() => {
13974
15566
  const hasHighlightedIndexChanged = previousHighlightedIndexRef.current !== highlightedIndex;
13975
15567
  previousHighlightedIndexRef.current = highlightedIndex;
13976
15568
  if (highlightedIndex >= 0 && hasHighlightedIndexChanged) {
13977
15569
  virtualizer.scrollToIndex(highlightedIndex, { align: "auto" });
13978
15570
  }
13979
15571
  }, [highlightedIndex, virtualizer]);
13980
- return /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)("div", { className: "p-2", children: [
13981
- /* @__PURE__ */ (0, import_jsx_runtime154.jsxs)("div", { className: "relative mb-2", children: [
13982
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
13983
- import_lucide_react46.Search,
15572
+ return /* @__PURE__ */ (0, import_jsx_runtime161.jsxs)("div", { className: "p-2", children: [
15573
+ /* @__PURE__ */ (0, import_jsx_runtime161.jsxs)("div", { className: "relative mb-2", children: [
15574
+ /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
15575
+ import_lucide_react50.Search,
13984
15576
  {
13985
15577
  "aria-hidden": "true",
13986
15578
  className: "absolute left-4 top-1/2 h-5 w-5 -translate-y-1/2 text-[#9696B9]"
13987
15579
  }
13988
15580
  ),
13989
- /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
15581
+ /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
13990
15582
  "input",
13991
15583
  {
13992
15584
  id: inputId,
@@ -14005,7 +15597,7 @@ function SearchableSelectContent({
14005
15597
  }
14006
15598
  )
14007
15599
  ] }),
14008
- loading && options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("div", { className: "px-4 py-5 text-center text-base leading-6 text-[#6C6C6C]", children: loadingText }) : options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("div", { className: "px-4 py-5 text-center text-base leading-6 text-[#6C6C6C]", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
15600
+ loading && options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime161.jsx)("div", { className: "px-4 py-5 text-center text-base leading-6 text-[#6C6C6C]", children: loadingText }) : options.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime161.jsx)("div", { className: "px-4 py-5 text-center text-base leading-6 text-[#6C6C6C]", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
14009
15601
  "div",
14010
15602
  {
14011
15603
  id: listboxId,
@@ -14014,7 +15606,7 @@ function SearchableSelectContent({
14014
15606
  "aria-labelledby": labelId,
14015
15607
  className: cn("overflow-y-auto outline-none", menuClassName),
14016
15608
  style: { height: Math.min(height, rowCount * ROW_HEIGHT) },
14017
- children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
15609
+ children: /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
14018
15610
  "div",
14019
15611
  {
14020
15612
  className: "relative w-full",
@@ -14022,7 +15614,7 @@ function SearchableSelectContent({
14022
15614
  children: virtualItems.map((virtualItem) => {
14023
15615
  const option = options[virtualItem.index];
14024
15616
  if (!option) {
14025
- return /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
15617
+ return /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
14026
15618
  "div",
14027
15619
  {
14028
15620
  className: "absolute left-0 top-0 flex w-full items-center px-4 text-base leading-6 text-[#6C6C6C]",
@@ -14037,7 +15629,7 @@ function SearchableSelectContent({
14037
15629
  }
14038
15630
  const isSelected = value?.value === option.value;
14039
15631
  const isHighlighted = virtualItem.index === highlightedIndex;
14040
- return /* @__PURE__ */ (0, import_jsx_runtime154.jsx)(
15632
+ return /* @__PURE__ */ (0, import_jsx_runtime161.jsx)(
14041
15633
  "button",
14042
15634
  {
14043
15635
  id: getOptionId(idPrefix, virtualItem.index),
@@ -14059,7 +15651,7 @@ function SearchableSelectContent({
14059
15651
  height: `${virtualItem.size}px`,
14060
15652
  transform: `translateY(${virtualItem.start}px)`
14061
15653
  },
14062
- children: /* @__PURE__ */ (0, import_jsx_runtime154.jsx)("span", { className: "truncate text-center", children: String(option.label) })
15654
+ children: /* @__PURE__ */ (0, import_jsx_runtime161.jsx)("span", { className: "truncate text-center", children: String(option.label) })
14063
15655
  },
14064
15656
  `${String(option.value)}-${virtualItem.index}`
14065
15657
  );
@@ -14145,14 +15737,14 @@ function getErrorMessage(error) {
14145
15737
 
14146
15738
  // src/lib/toastResponseError.tsx
14147
15739
  var import_i18next = __toESM(require("i18next"), 1);
14148
- var import_jsx_runtime155 = require("react/jsx-runtime");
15740
+ var import_jsx_runtime162 = require("react/jsx-runtime");
14149
15741
  function addSupportEmailToMessage(message, prefixText) {
14150
15742
  if (typeof message !== "string") {
14151
15743
  return message;
14152
15744
  }
14153
15745
  const builtMessage = `${prefixText ? `${prefixText} ` : ""}${message}`;
14154
- return /* @__PURE__ */ (0, import_jsx_runtime155.jsxs)("div", { children: [
14155
- /* @__PURE__ */ (0, import_jsx_runtime155.jsx)("div", { children: builtMessage }),
15746
+ return /* @__PURE__ */ (0, import_jsx_runtime162.jsxs)("div", { children: [
15747
+ /* @__PURE__ */ (0, import_jsx_runtime162.jsx)("div", { children: builtMessage }),
14156
15748
  import_i18next.default.t("reach_us_at_email")
14157
15749
  ] });
14158
15750
  }
@@ -14214,6 +15806,11 @@ function toastResponseError(error, options = {}) {
14214
15806
  CopyString,
14215
15807
  CustomCheckboxDropdownGroup,
14216
15808
  DEVICE_BREAKPOINTS,
15809
+ DashboardCreatableMultiSelect,
15810
+ DashboardInfiniteScrollSelect,
15811
+ DashboardInput,
15812
+ DashboardMultiSelect,
15813
+ DashboardSelect,
14217
15814
  DataTable,
14218
15815
  DatePicker,
14219
15816
  DateTableFilter,