@chekinapp/ui 0.0.139 → 0.0.141

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -13527,6 +13527,7 @@ function useSelectState(params) {
13527
13527
  onKeyDown,
13528
13528
  onFocus,
13529
13529
  onBlur,
13530
+ inputValue: controlledInputValue,
13530
13531
  onInputChange,
13531
13532
  isSearchInDropdown,
13532
13533
  searchable = true
@@ -13544,9 +13545,17 @@ function useSelectState(params) {
13544
13545
  [singleSelected, getValueLabel]
13545
13546
  );
13546
13547
  const isSearchOnlyInput = searchable && (isMulti || Boolean(isSearchInDropdown));
13547
- const [inputValue, setInputValue] = React48.useState(
13548
+ const isInputControlled = controlledInputValue !== void 0;
13549
+ const [internalInputValue, setInternalInputValue] = React48.useState(
13548
13550
  searchable && !isSearchOnlyInput ? valueLabel : ""
13549
13551
  );
13552
+ const inputValue = isInputControlled ? controlledInputValue : internalInputValue;
13553
+ const setInputValue = React48.useCallback(
13554
+ (next) => {
13555
+ if (!isInputControlled) setInternalInputValue(next);
13556
+ },
13557
+ [isInputControlled]
13558
+ );
13550
13559
  const hasValue = selectedOptions.length > 0;
13551
13560
  const isBlocked = Boolean(disabled) || Boolean(loading) || Boolean(readOnly);
13552
13561
  const hasInvalidState = Boolean(error);
@@ -13713,7 +13722,7 @@ function useSelectState(params) {
13713
13722
  onInputChange?.(nextValue);
13714
13723
  if (!isOpen) setIsOpen(true);
13715
13724
  },
13716
- [isOpen, onInputChange, searchable, setIsOpen]
13725
+ [isOpen, onInputChange, searchable, setIsOpen, setInputValue]
13717
13726
  );
13718
13727
  const handleInputFocus = React48.useCallback(
13719
13728
  (event) => {
@@ -14241,6 +14250,7 @@ function SelectInternal(props, ref) {
14241
14250
  hideIndicator,
14242
14251
  openMenuOnFocus,
14243
14252
  components: userComponents,
14253
+ inputValue,
14244
14254
  onInputChange,
14245
14255
  searchable = true,
14246
14256
  searchPosition = "trigger",
@@ -14310,6 +14320,7 @@ function SelectInternal(props, ref) {
14310
14320
  onKeyDown,
14311
14321
  onFocus,
14312
14322
  onBlur,
14323
+ inputValue,
14313
14324
  onInputChange,
14314
14325
  isSearchInDropdown,
14315
14326
  searchable
@@ -14490,6 +14501,30 @@ var Select = React49.forwardRef(SelectInternal);
14490
14501
 
14491
14502
  // src/dashboard/phone-input/utils.ts
14492
14503
  var PREFIX_REGEX = /^\+/;
14504
+ function isPhoneInputValue(value) {
14505
+ if (typeof value === "string" || typeof value === "number") {
14506
+ return false;
14507
+ }
14508
+ return Boolean(value && ("code" in value || "number" in value));
14509
+ }
14510
+ function getPhoneValuePart(value) {
14511
+ if (typeof value === "string" || typeof value === "number") {
14512
+ return String(value);
14513
+ }
14514
+ return void 0;
14515
+ }
14516
+ function toPhoneValue(value, fallbackCode, fallbackNumber) {
14517
+ if (value === null || value === void 0) {
14518
+ return { code: fallbackCode ?? "", number: fallbackNumber ?? "" };
14519
+ }
14520
+ if (isPhoneInputValue(value)) {
14521
+ return {
14522
+ code: getPhoneValuePart(value.code) ?? fallbackCode ?? "",
14523
+ number: getPhoneValuePart(value.number) ?? fallbackNumber ?? ""
14524
+ };
14525
+ }
14526
+ return { code: fallbackCode ?? "", number: fallbackNumber ?? String(value) };
14527
+ }
14493
14528
  function clearPhoneNumber(value) {
14494
14529
  return value.replace(/[^0-9]/g, "");
14495
14530
  }
@@ -14533,190 +14568,228 @@ function formatPhoneCodeOptionLabel(option) {
14533
14568
 
14534
14569
  // src/dashboard/phone-input/PhoneInput.tsx
14535
14570
  var import_jsx_runtime158 = require("react/jsx-runtime");
14536
- var EMPTY_VALUE = { code: "", number: "" };
14537
- var PhoneInput = React50.forwardRef(function PhoneInput2({
14538
- options,
14539
- value,
14540
- onChange,
14541
- onFocus,
14542
- onBlur,
14543
- name,
14544
- codeName,
14545
- numberName,
14546
- label,
14547
- topLabel,
14548
- prefixLabel,
14549
- placeholder,
14550
- codePlaceholder = "+00",
14551
- disabled,
14552
- loading,
14553
- readOnly,
14554
- codeReadOnly,
14555
- optional,
14556
- tooltip,
14557
- error,
14558
- invalid,
14559
- className,
14560
- autoDetectCode = true,
14561
- searchable = true,
14562
- defaultCode
14563
- }, ref) {
14564
- const { t } = (0, import_react_i18next33.useTranslation)();
14565
- const groupLabelId = React50.useId();
14566
- const errorMsgId = React50.useId();
14567
- const numberInputRef = React50.useRef(null);
14568
- const safeValue = value ?? EMPTY_VALUE;
14569
- const effectiveCode = safeValue.code || defaultCode || "";
14570
- const resolvedLabel = label ?? "";
14571
- const hasExternalError = Boolean(error);
14572
- const isPrefixRequired = autoDetectCode && Boolean(safeValue.number) && !effectiveCode;
14573
- const hasInvalidState = hasExternalError || Boolean(invalid) || isPrefixRequired;
14574
- const errorMessage = error ?? (isPrefixRequired ? t("prefix_required") : void 0);
14575
- const combinedValue = effectiveCode || safeValue.number ? `${effectiveCode}${safeValue.number}` : "";
14576
- const codeOptions = React50.useMemo(
14577
- () => options.map((option) => ({
14578
- value: option.value,
14579
- label: formatPhoneCodeOptionLabel(option),
14580
- data: option.data,
14581
- isDisabled: option.disabled
14582
- })),
14583
- [options]
14584
- );
14585
- const selectedCodeOption = React50.useMemo(
14586
- () => codeOptions.find((option) => option.value === effectiveCode) ?? null,
14587
- [codeOptions, effectiveCode]
14588
- );
14589
- const parsePhoneValue = React50.useMemo(
14590
- () => parsePhoneValueWithOptions(options),
14591
- [options]
14592
- );
14593
- const emitChange = (next) => {
14594
- onChange?.(next, name);
14595
- };
14596
- const handleCodeChange = (option) => {
14597
- if (!option) return;
14598
- emitChange({ code: option.value, number: safeValue.number });
14599
- if (!disabled && !readOnly) {
14600
- setTimeout(() => numberInputRef.current?.focus(), 0);
14601
- }
14602
- };
14603
- const handleNumberChange = (event) => {
14604
- if (readOnly || disabled) return;
14605
- const rawValue = event.target.value;
14606
- if (!autoDetectCode) {
14607
- emitChange({ code: effectiveCode, number: clearPhoneNumber(rawValue) });
14608
- return;
14609
- }
14610
- const parsed = parsePhoneValue(rawValue);
14611
- const cleanedNumber = clearPhoneNumber(parsed.number);
14612
- if (parsed.code) {
14613
- emitChange({ code: parsed.code, number: cleanedNumber });
14614
- return;
14615
- }
14616
- emitChange({ code: effectiveCode, number: cleanedNumber });
14617
- };
14618
- return /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)(
14619
- "div",
14620
- {
14621
- className: cn(
14622
- "relative w-[var(--field-width,100%)] max-w-[var(--field-max-width,296px)]",
14623
- disabled && "cursor-not-allowed opacity-50",
14624
- loading && "cursor-progress",
14625
- className
14626
- ),
14627
- children: [
14628
- name && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)("input", { type: "hidden", name, value: combinedValue, disabled }),
14629
- codeName && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)("input", { type: "hidden", name: codeName, value: effectiveCode, disabled }),
14630
- numberName && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14631
- "input",
14632
- {
14633
- type: "hidden",
14634
- name: numberName,
14635
- value: safeValue.number,
14636
- disabled
14637
- }
14638
- ),
14639
- topLabel && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14640
- "span",
14641
- {
14642
- id: groupLabelId,
14643
- className: "mb-2 block text-[14px] font-medium text-[var(--chekin-color-brand-navy)]",
14644
- children: topLabel
14645
- }
14646
- ),
14647
- /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)(
14648
- "div",
14649
- {
14650
- role: "group",
14651
- "aria-labelledby": topLabel ? groupLabelId : void 0,
14652
- className: "grid grid-cols-[96px_minmax(0,1fr)] gap-2",
14653
- children: [
14654
- /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14655
- Select,
14656
- {
14657
- ref,
14658
- options: codeOptions,
14659
- value: selectedCodeOption,
14660
- onChange: handleCodeChange,
14661
- label: prefixLabel,
14662
- placeholder: codePlaceholder,
14663
- disabled,
14664
- readOnly: Boolean(readOnly) || Boolean(codeReadOnly),
14665
- loading,
14666
- invalid: hasInvalidState,
14667
- hideErrorMessage: true,
14668
- searchPosition: searchable ? "dropdown" : "trigger",
14669
- searchable,
14670
- filterOption: countriesFilter,
14671
- clearable: false,
14672
- getValueLabel: (option) => option.value,
14673
- className: "max-w-none w-auto",
14674
- dropdownClassName: "right-auto w-[280px]"
14675
- }
14676
- ),
14677
- /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14678
- Input,
14679
- {
14680
- ref: numberInputRef,
14681
- type: "tel",
14682
- inputMode: "tel",
14683
- autoComplete: "tel-national",
14684
- label: resolvedLabel,
14685
- value: safeValue.number,
14686
- placeholder,
14687
- disabled,
14688
- readOnly,
14689
- loading,
14690
- invalid: hasInvalidState,
14691
- tooltip,
14692
- "aria-label": resolvedLabel || name,
14693
- "aria-describedby": errorMessage ? errorMsgId : void 0,
14694
- onChange: handleNumberChange,
14695
- onFocus,
14696
- onBlur,
14697
- renderErrorMessage: false,
14698
- wrapperClassName: "max-w-none w-auto",
14699
- contentClassName: readOnly ? "!cursor-default" : void 0,
14700
- inputClassName: readOnly ? "!cursor-default" : void 0
14701
- }
14702
- )
14703
- ]
14704
- }
14571
+ var PhoneInput = React50.forwardRef(
14572
+ function PhoneInput2({
14573
+ options,
14574
+ value,
14575
+ onChange,
14576
+ onFocus,
14577
+ onBlur,
14578
+ name,
14579
+ codeName,
14580
+ numberName,
14581
+ label,
14582
+ topLabel,
14583
+ prefixLabel,
14584
+ placeholder,
14585
+ codePlaceholder = "+00",
14586
+ disabled,
14587
+ loading,
14588
+ readOnly,
14589
+ codeReadOnly,
14590
+ optional,
14591
+ tooltip,
14592
+ error,
14593
+ invalid,
14594
+ className,
14595
+ autoDetectCode = true,
14596
+ searchable = true,
14597
+ defaultCode
14598
+ }, ref) {
14599
+ const { t } = (0, import_react_i18next33.useTranslation)();
14600
+ const groupLabelId = React50.useId();
14601
+ const errorMsgId = React50.useId();
14602
+ const numberInputRef = React50.useRef(null);
14603
+ const [codeSearchValue, setCodeSearchValue] = React50.useState("");
14604
+ const safeValue = toPhoneValue(value);
14605
+ const effectiveCode = safeValue.code || defaultCode || "";
14606
+ const resolvedLabel = label ?? "";
14607
+ const hasExternalError = Boolean(error);
14608
+ const isPrefixRequired = autoDetectCode && Boolean(safeValue.number) && !effectiveCode;
14609
+ const hasInvalidState = hasExternalError || Boolean(invalid) || isPrefixRequired;
14610
+ const errorMessage = error ?? (isPrefixRequired ? t("prefix_required") : void 0);
14611
+ const combinedValue = effectiveCode || safeValue.number ? `${effectiveCode}${safeValue.number}` : "";
14612
+ const codeOptions = React50.useMemo(
14613
+ () => options.map((option) => ({
14614
+ value: option.value,
14615
+ label: formatPhoneCodeOptionLabel(option),
14616
+ data: option.data,
14617
+ isDisabled: option.disabled
14618
+ })),
14619
+ [options]
14620
+ );
14621
+ const selectedCodeOption = React50.useMemo(
14622
+ () => codeOptions.find((option) => option.value === effectiveCode) ?? null,
14623
+ [codeOptions, effectiveCode]
14624
+ );
14625
+ const parsePhoneValue = React50.useMemo(
14626
+ () => parsePhoneValueWithOptions(options),
14627
+ [options]
14628
+ );
14629
+ const emitChange = (next) => {
14630
+ onChange?.(next, name);
14631
+ };
14632
+ const handleCodeChange = (option) => {
14633
+ if (!option) return;
14634
+ emitChange({ code: option.value, number: safeValue.number });
14635
+ if (!disabled && !readOnly) {
14636
+ setTimeout(() => numberInputRef.current?.focus(), 0);
14637
+ }
14638
+ };
14639
+ const handleNumberChange = (event) => {
14640
+ if (readOnly || disabled) return;
14641
+ const rawValue = event.target.value;
14642
+ if (!autoDetectCode) {
14643
+ emitChange({ code: effectiveCode, number: clearPhoneNumber(rawValue) });
14644
+ return;
14645
+ }
14646
+ const parsed = parsePhoneValue(rawValue);
14647
+ const cleanedNumber = clearPhoneNumber(parsed.number);
14648
+ if (parsed.code) {
14649
+ emitChange({ code: parsed.code, number: cleanedNumber });
14650
+ return;
14651
+ }
14652
+ emitChange({ code: effectiveCode, number: cleanedNumber });
14653
+ };
14654
+ const effectiveCodeRef = React50.useRef(effectiveCode);
14655
+ const numberValueRef = React50.useRef(safeValue.number);
14656
+ const codeSearchValueRef = React50.useRef(codeSearchValue);
14657
+ const onChangeRef = React50.useRef(onChange);
14658
+ const nameRef = React50.useRef(name);
14659
+ effectiveCodeRef.current = effectiveCode;
14660
+ numberValueRef.current = safeValue.number;
14661
+ codeSearchValueRef.current = codeSearchValue;
14662
+ onChangeRef.current = onChange;
14663
+ nameRef.current = name;
14664
+ React50.useImperativeHandle(
14665
+ ref,
14666
+ () => ({
14667
+ getCodeSearchValue: () => codeSearchValueRef.current,
14668
+ setCodeSearchValue: (next) => setCodeSearchValue(next),
14669
+ getNumberValue: () => numberValueRef.current,
14670
+ setNumberValue: (next) => {
14671
+ const cleanedNumber = clearPhoneNumber(next);
14672
+ onChangeRef.current?.(
14673
+ { code: effectiveCodeRef.current, number: cleanedNumber },
14674
+ nameRef.current
14675
+ );
14676
+ },
14677
+ focus: () => numberInputRef.current?.focus()
14678
+ }),
14679
+ []
14680
+ );
14681
+ return /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)(
14682
+ "div",
14683
+ {
14684
+ className: cn(
14685
+ "relative w-[var(--field-width,100%)] max-w-[var(--field-max-width,296px)]",
14686
+ disabled && "cursor-not-allowed opacity-50",
14687
+ loading && "cursor-progress",
14688
+ className
14705
14689
  ),
14706
- !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 : t("optional") }),
14707
- errorMessage && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14708
- FieldErrorMessage,
14709
- {
14710
- id: errorMsgId,
14711
- message: errorMessage,
14712
- "data-testid": name ? `${name}-error` : void 0,
14713
- className: "mt-[1px] text-[14px]"
14714
- }
14715
- )
14716
- ]
14717
- }
14718
- );
14719
- });
14690
+ children: [
14691
+ name && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)("input", { type: "hidden", name, value: combinedValue, disabled }),
14692
+ codeName && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14693
+ "input",
14694
+ {
14695
+ type: "hidden",
14696
+ name: codeName,
14697
+ value: effectiveCode,
14698
+ disabled
14699
+ }
14700
+ ),
14701
+ numberName && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14702
+ "input",
14703
+ {
14704
+ type: "hidden",
14705
+ name: numberName,
14706
+ value: safeValue.number,
14707
+ disabled
14708
+ }
14709
+ ),
14710
+ topLabel && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14711
+ "span",
14712
+ {
14713
+ id: groupLabelId,
14714
+ className: "mb-2 block text-[14px] font-medium text-[var(--chekin-color-brand-navy)]",
14715
+ children: topLabel
14716
+ }
14717
+ ),
14718
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsxs)(
14719
+ "div",
14720
+ {
14721
+ role: "group",
14722
+ "aria-labelledby": topLabel ? groupLabelId : void 0,
14723
+ className: "grid grid-cols-[96px_minmax(0,1fr)] gap-2",
14724
+ children: [
14725
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14726
+ Select,
14727
+ {
14728
+ options: codeOptions,
14729
+ value: selectedCodeOption,
14730
+ onChange: handleCodeChange,
14731
+ label: prefixLabel,
14732
+ placeholder: codePlaceholder,
14733
+ disabled,
14734
+ readOnly: Boolean(readOnly) || Boolean(codeReadOnly),
14735
+ loading,
14736
+ invalid: hasInvalidState,
14737
+ hideErrorMessage: true,
14738
+ searchPosition: searchable ? "dropdown" : "trigger",
14739
+ searchable,
14740
+ filterOption: countriesFilter,
14741
+ clearable: false,
14742
+ getValueLabel: (option) => option.value,
14743
+ className: "max-w-none w-auto",
14744
+ dropdownClassName: "right-auto w-[280px]",
14745
+ inputValue: searchable ? codeSearchValue : void 0,
14746
+ onInputChange: setCodeSearchValue
14747
+ }
14748
+ ),
14749
+ /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14750
+ Input,
14751
+ {
14752
+ ref: numberInputRef,
14753
+ type: "tel",
14754
+ inputMode: "tel",
14755
+ autoComplete: "tel-national",
14756
+ label: resolvedLabel,
14757
+ value: safeValue.number,
14758
+ placeholder,
14759
+ disabled,
14760
+ readOnly,
14761
+ loading,
14762
+ invalid: hasInvalidState,
14763
+ tooltip,
14764
+ "aria-label": resolvedLabel || name,
14765
+ "aria-describedby": errorMessage ? errorMsgId : void 0,
14766
+ onChange: handleNumberChange,
14767
+ onFocus,
14768
+ onBlur,
14769
+ renderErrorMessage: false,
14770
+ wrapperClassName: "max-w-none w-auto",
14771
+ contentClassName: readOnly ? "!cursor-default" : void 0,
14772
+ inputClassName: readOnly ? "!cursor-default" : void 0
14773
+ }
14774
+ )
14775
+ ]
14776
+ }
14777
+ ),
14778
+ !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 : t("optional") }),
14779
+ errorMessage && /* @__PURE__ */ (0, import_jsx_runtime158.jsx)(
14780
+ FieldErrorMessage,
14781
+ {
14782
+ id: errorMsgId,
14783
+ message: errorMessage,
14784
+ "data-testid": name ? `${name}-error` : void 0,
14785
+ className: "mt-[1px] text-[14px]"
14786
+ }
14787
+ )
14788
+ ]
14789
+ }
14790
+ );
14791
+ }
14792
+ );
14720
14793
  PhoneInput.displayName = "PhoneInput";
14721
14794
 
14722
14795
  // src/dashboard/creatable-select/CreatableSelect.tsx