@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 +1868 -271
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +180 -11
- package/dist/index.d.ts +180 -11
- package/dist/index.js +1867 -275
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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-
|
|
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-[
|
|
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:
|
|
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
|
|
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 =
|
|
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/
|
|
13663
|
+
// src/dashboard/input/Input.tsx
|
|
13646
13664
|
var React53 = __toESM(require("react"), 1);
|
|
13647
13665
|
var import_lucide_react46 = require("lucide-react");
|
|
13648
|
-
|
|
13649
|
-
|
|
13666
|
+
|
|
13667
|
+
// src/dashboard/_fieldset/Fieldset.tsx
|
|
13650
13668
|
var import_jsx_runtime154 = require("react/jsx-runtime");
|
|
13651
|
-
|
|
13652
|
-
|
|
13653
|
-
|
|
13654
|
-
|
|
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
|
-
|
|
13674
|
+
label,
|
|
13681
13675
|
tooltip,
|
|
13682
|
-
|
|
13683
|
-
|
|
13676
|
+
legend,
|
|
13677
|
+
onClick,
|
|
13678
|
+
htmlFor,
|
|
13679
|
+
labelId,
|
|
13680
|
+
readOnly,
|
|
13681
|
+
loading,
|
|
13682
|
+
disabled,
|
|
13684
13683
|
className,
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13708
|
-
|
|
13709
|
-
|
|
13710
|
-
|
|
13711
|
-
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
|
|
13715
|
-
|
|
13716
|
-
|
|
13717
|
-
|
|
13718
|
-
|
|
13719
|
-
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
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
|
-
|
|
13729
|
+
"fieldset",
|
|
13851
13730
|
{
|
|
13852
|
-
|
|
13853
|
-
|
|
13854
|
-
|
|
13855
|
-
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
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-
|
|
13889
|
-
|
|
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
|
-
|
|
13896
|
-
|
|
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,
|
|
13908
|
-
/* @__PURE__ */ (0,
|
|
13909
|
-
/* @__PURE__ */ (0,
|
|
13910
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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 =
|
|
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 =
|
|
13953
|
-
const lastLoadMoreOptionsLengthRef =
|
|
13954
|
-
const previousHighlightedIndexRef =
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
13981
|
-
/* @__PURE__ */ (0,
|
|
13982
|
-
/* @__PURE__ */ (0,
|
|
13983
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
14155
|
-
/* @__PURE__ */ (0,
|
|
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,
|