UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

1 lines 28.3 kB
{"version":3,"file":"phone-field.cjs","sources":["../../../../src/components/forms/phone-field.tsx"],"sourcesContent":["/**\n * @frank-auth/react - Phone Field Component\n *\n * International phone number input with country selection, formatting,\n * and validation. Supports SMS MFA and organization restrictions.\n */\n\n\"use client\";\n\nimport { Button, Chip, Input, Select } from \"@/components/ui\";\nimport React from \"react\";\nimport { useConfig } from \"../../hooks/use-config\";\nimport { FieldError } from \"./field-error\";\nimport { useFormField } from \"./form-wrapper\";\n\n// ============================================================================\n// Phone Field Interface\n// ============================================================================\n\nexport interface PhoneFieldProps {\n\t/**\n\t * Field name for form handling\n\t */\n\tname?: string;\n\n\t/**\n\t * Field label\n\t */\n\tlabel?: string;\n\n\t/**\n\t * Placeholder text\n\t */\n\tplaceholder?: string;\n\n\t/**\n\t * Phone number value (E.164 format or formatted)\n\t */\n\tvalue?: string;\n\n\t/**\n\t * Change handler (receives E.164 format)\n\t */\n\tonChange?: (value: string, formatted: string) => void;\n\n\t/**\n\t * Blur handler\n\t */\n\tonBlur?: () => void;\n\n\t/**\n\t * Focus handler\n\t */\n\tonFocus?: () => void;\n\n\t/**\n\t * Default country code (ISO 3166-1 alpha-2)\n\t */\n\tdefaultCountry?: string;\n\n\t/**\n\t * Preferred countries (shown at top of list)\n\t */\n\tpreferredCountries?: string[];\n\n\t/**\n\t * Allowed countries (if restricted)\n\t */\n\tallowedCountries?: string[];\n\n\t/**\n\t * Blocked countries\n\t */\n\tblockedCountries?: string[];\n\n\t/**\n\t * Whether field is required\n\t */\n\trequired?: boolean;\n\n\t/**\n\t * Whether field is disabled\n\t */\n\tdisabled?: boolean;\n\n\t/**\n\t * Whether to validate phone number format\n\t */\n\tvalidateFormat?: boolean;\n\n\t/**\n\t * Field size\n\t */\n\tsize?: \"sm\" | \"md\" | \"lg\";\n\n\t/**\n\t * Field variant\n\t */\n\tvariant?: \"flat\" | \"bordered\" | \"underlined\" | \"faded\";\n\n\t/**\n\t * Custom className\n\t */\n\tclassName?: string;\n\n\t/**\n\t * Auto focus\n\t */\n\tautoFocus?: boolean;\n\n\t/**\n\t * Auto complete\n\t */\n\tautoComplete?: string;\n\n\t/**\n\t * Custom validation error\n\t */\n\terror?: string | string[];\n\n\t/**\n\t * Help text\n\t */\n\tdescription?: string;\n\n\t/**\n\t * Whether to show verification status\n\t */\n\tshowVerificationStatus?: boolean;\n\n\t/**\n\t * Whether phone is verified\n\t */\n\tisVerified?: boolean;\n\n\t/**\n\t * Verification handler\n\t */\n\tonRequestVerification?: () => void;\n\n\t/**\n\t * End content (overrides verification status)\n\t */\n\tendContent?: React.ReactNode;\n}\n\n// ============================================================================\n// Country Data Types\n// ============================================================================\n\nexport interface Country {\n\tcode: string; // ISO 3166-1 alpha-2\n\tname: string;\n\tdialCode: string;\n\tflag: string;\n\tformat?: string; // Phone number format pattern\n}\n\n// ============================================================================\n// Country Data\n// ============================================================================\n\nconst countries: Country[] = [\n\t{\n\t\tcode: \"US\",\n\t\tname: \"United States\",\n\t\tdialCode: \"+1\",\n\t\tflag: \"🇺🇸\",\n\t\tformat: \"(###) ###-####\",\n\t},\n\t{\n\t\tcode: \"CA\",\n\t\tname: \"Canada\",\n\t\tdialCode: \"+1\",\n\t\tflag: \"🇨🇦\",\n\t\tformat: \"(###) ###-####\",\n\t},\n\t{\n\t\tcode: \"GB\",\n\t\tname: \"United Kingdom\",\n\t\tdialCode: \"+44\",\n\t\tflag: \"🇬🇧\",\n\t\tformat: \"#### ### ####\",\n\t},\n\t{\n\t\tcode: \"AU\",\n\t\tname: \"Australia\",\n\t\tdialCode: \"+61\",\n\t\tflag: \"🇦🇺\",\n\t\tformat: \"#### ### ###\",\n\t},\n\t{\n\t\tcode: \"DE\",\n\t\tname: \"Germany\",\n\t\tdialCode: \"+49\",\n\t\tflag: \"🇩🇪\",\n\t\tformat: \"### ### ####\",\n\t},\n\t{\n\t\tcode: \"FR\",\n\t\tname: \"France\",\n\t\tdialCode: \"+33\",\n\t\tflag: \"🇫🇷\",\n\t\tformat: \"## ## ## ## ##\",\n\t},\n\t{\n\t\tcode: \"ES\",\n\t\tname: \"Spain\",\n\t\tdialCode: \"+34\",\n\t\tflag: \"🇪🇸\",\n\t\tformat: \"### ### ###\",\n\t},\n\t{\n\t\tcode: \"IT\",\n\t\tname: \"Italy\",\n\t\tdialCode: \"+39\",\n\t\tflag: \"🇮🇹\",\n\t\tformat: \"### ### ####\",\n\t},\n\t{\n\t\tcode: \"JP\",\n\t\tname: \"Japan\",\n\t\tdialCode: \"+81\",\n\t\tflag: \"🇯🇵\",\n\t\tformat: \"###-####-####\",\n\t},\n\t{\n\t\tcode: \"KR\",\n\t\tname: \"South Korea\",\n\t\tdialCode: \"+82\",\n\t\tflag: \"🇰🇷\",\n\t\tformat: \"###-####-####\",\n\t},\n\t{\n\t\tcode: \"CN\",\n\t\tname: \"China\",\n\t\tdialCode: \"+86\",\n\t\tflag: \"🇨🇳\",\n\t\tformat: \"### #### ####\",\n\t},\n\t{\n\t\tcode: \"IN\",\n\t\tname: \"India\",\n\t\tdialCode: \"+91\",\n\t\tflag: \"🇮🇳\",\n\t\tformat: \"##### #####\",\n\t},\n\t{\n\t\tcode: \"BR\",\n\t\tname: \"Brazil\",\n\t\tdialCode: \"+55\",\n\t\tflag: \"🇧🇷\",\n\t\tformat: \"(##) #####-####\",\n\t},\n\t{\n\t\tcode: \"MX\",\n\t\tname: \"Mexico\",\n\t\tdialCode: \"+52\",\n\t\tflag: \"🇲🇽\",\n\t\tformat: \"### ### ####\",\n\t},\n\t{\n\t\tcode: \"AR\",\n\t\tname: \"Argentina\",\n\t\tdialCode: \"+54\",\n\t\tflag: \"🇦🇷\",\n\t\tformat: \"### ###-####\",\n\t},\n\t{\n\t\tcode: \"RU\",\n\t\tname: \"Russia\",\n\t\tdialCode: \"+7\",\n\t\tflag: \"🇷🇺\",\n\t\tformat: \"### ###-##-##\",\n\t},\n\t{\n\t\tcode: \"ZA\",\n\t\tname: \"South Africa\",\n\t\tdialCode: \"+27\",\n\t\tflag: \"🇿🇦\",\n\t\tformat: \"## ### ####\",\n\t},\n\t{\n\t\tcode: \"EG\",\n\t\tname: \"Egypt\",\n\t\tdialCode: \"+20\",\n\t\tflag: \"🇪🇬\",\n\t\tformat: \"### ### ####\",\n\t},\n\t{\n\t\tcode: \"NG\",\n\t\tname: \"Nigeria\",\n\t\tdialCode: \"+234\",\n\t\tflag: \"🇳🇬\",\n\t\tformat: \"### ### ####\",\n\t},\n\t{\n\t\tcode: \"SG\",\n\t\tname: \"Singapore\",\n\t\tdialCode: \"+65\",\n\t\tflag: \"🇸🇬\",\n\t\tformat: \"#### ####\",\n\t},\n];\n\n// ============================================================================\n// Phone Validation Functions\n// ============================================================================\n\nfunction parsePhoneNumber(\n\tphoneNumber: string,\n\tcountry: Country,\n): {\n\tisValid: boolean;\n\te164: string;\n\tnational: string;\n\tformatted: string;\n\terrors: string[];\n} {\n\tconst errors: string[] = [];\n\n\t// Remove all non-digit characters except +\n\tconst cleaned = phoneNumber.replace(/[^\\d+]/g, \"\");\n\n\t// Check if it starts with the country's dial code\n\tlet nationalNumber = cleaned;\n\tlet e164 = cleaned;\n\n\tif (cleaned.startsWith(\"+\")) {\n\t\te164 = cleaned;\n\t\tif (cleaned.startsWith(country.dialCode)) {\n\t\t\tnationalNumber = cleaned.substring(country.dialCode.length);\n\t\t} else {\n\t\t\terrors.push(\"Phone number does not match selected country\");\n\t\t}\n\t} else {\n\t\t// Assume it's a national number\n\t\te164 = country.dialCode + cleaned;\n\t\tnationalNumber = cleaned;\n\t}\n\n\t// Basic validation - phone numbers should be 7-15 digits (excluding country code)\n\tif (nationalNumber.length < 7) {\n\t\terrors.push(\"Phone number is too short\");\n\t} else if (nationalNumber.length > 15) {\n\t\terrors.push(\"Phone number is too long\");\n\t}\n\n\t// Format the national number if format is available\n\tlet formatted = nationalNumber;\n\tif (country.format && nationalNumber.length >= 7) {\n\t\tformatted = formatPhoneNumber(nationalNumber, country.format);\n\t}\n\n\treturn {\n\t\tisValid: errors.length === 0,\n\t\te164,\n\t\tnational: nationalNumber,\n\t\tformatted: `${country.dialCode} ${formatted}`,\n\t\terrors,\n\t};\n}\n\nfunction formatPhoneNumber(number: string, format: string): string {\n\tlet formattedNumber = format;\n\tlet numberIndex = 0;\n\n\tfor (let i = 0; i < format.length && numberIndex < number.length; i++) {\n\t\tif (format[i] === \"#\") {\n\t\t\tformattedNumber =\n\t\t\t\tformattedNumber.substring(0, i) +\n\t\t\t\tnumber[numberIndex] +\n\t\t\t\tformattedNumber.substring(i + 1);\n\t\t\tnumberIndex++;\n\t\t}\n\t}\n\n\treturn formattedNumber.substring(0, formattedNumber.lastIndexOf(\"#\") + 1);\n}\n\nfunction detectCountryFromNumber(phoneNumber: string): Country | null {\n\tconst cleaned = phoneNumber.replace(/[^\\d+]/g, \"\");\n\n\tif (!cleaned.startsWith(\"+\")) return null;\n\n\t// Sort by dial code length (longest first) to match more specific codes first\n\tconst sortedCountries = [...countries].sort(\n\t\t(a, b) => b.dialCode.length - a.dialCode.length,\n\t);\n\n\tfor (const country of sortedCountries) {\n\t\tif (cleaned.startsWith(country.dialCode)) {\n\t\t\treturn country;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// ============================================================================\n// Phone Field Component\n// ============================================================================\n\nexport function PhoneField({\n\tname = \"phone\",\n\tlabel = \"Phone Number\",\n\tplaceholder = \"Enter your phone number\",\n\tvalue = \"\",\n\tonChange,\n\tonBlur,\n\tonFocus,\n\tdefaultCountry = \"US\",\n\tpreferredCountries = [\"US\", \"CA\", \"GB\"],\n\tallowedCountries = [],\n\tblockedCountries = [],\n\trequired = false,\n\tdisabled = false,\n\tvalidateFormat = true,\n\tsize = \"md\",\n\tvariant = \"bordered\",\n\tclassName = \"\",\n\tautoFocus = false,\n\tautoComplete = \"tel\",\n\terror: externalError,\n\tdescription,\n\tshowVerificationStatus = false,\n\tisVerified = false,\n\tonRequestVerification,\n\tendContent,\n}: PhoneFieldProps) {\n\tconst { components, organizationSettings } = useConfig();\n\tconst formField = useFormField(name);\n\n\t// Custom component override\n\tconst CustomPhoneField = components.PhoneField;\n\tif (CustomPhoneField) {\n\t\treturn (\n\t\t\t<CustomPhoneField\n\t\t\t\t{...{\n\t\t\t\t\tname,\n\t\t\t\t\tlabel,\n\t\t\t\t\tplaceholder,\n\t\t\t\t\tvalue,\n\t\t\t\t\tonChange,\n\t\t\t\t\tonBlur,\n\t\t\t\t\tonFocus,\n\t\t\t\t\tdefaultCountry,\n\t\t\t\t\tpreferredCountries,\n\t\t\t\t\tallowedCountries,\n\t\t\t\t\tblockedCountries,\n\t\t\t\t\trequired,\n\t\t\t\t\tdisabled,\n\t\t\t\t\tvalidateFormat,\n\t\t\t\t\tsize,\n\t\t\t\t\tvariant,\n\t\t\t\t\tclassName,\n\t\t\t\t\tautoFocus,\n\t\t\t\t\tautoComplete,\n\t\t\t\t\terror: externalError,\n\t\t\t\t\tdescription,\n\t\t\t\t\tshowVerificationStatus,\n\t\t\t\t\tisVerified,\n\t\t\t\t\tonRequestVerification,\n\t\t\t\t\tendContent,\n\t\t\t\t}}\n\t\t\t/>\n\t\t);\n\t}\n\n\t// State\n\tconst [internalValue, setInternalValue] = React.useState(value);\n\tconst [selectedCountry, setSelectedCountry] = React.useState<Country>(() => {\n\t\t// Try to detect country from initial value\n\t\tif (value) {\n\t\t\tconst detectedCountry = detectCountryFromNumber(value);\n\t\t\tif (detectedCountry) return detectedCountry;\n\t\t}\n\t\treturn countries.find((c) => c.code === defaultCountry) || countries[0];\n\t});\n\n\t// Use external value if controlled\n\tconst currentValue = onChange ? value : internalValue;\n\n\t// Apply organization phone restrictions if available\n\tconst effectiveAllowedCountries = React.useMemo(() => {\n\t\tconst orgCountries =\n\t\t\torganizationSettings?.phoneRestrictions?.allowedCountries;\n\t\tif (orgCountries && orgCountries.length > 0) {\n\t\t\treturn orgCountries;\n\t\t}\n\t\treturn allowedCountries;\n\t}, [allowedCountries, organizationSettings]);\n\n\tconst effectiveBlockedCountries = React.useMemo(() => {\n\t\tconst orgBlockedCountries =\n\t\t\torganizationSettings?.phoneRestrictions?.blockedCountries;\n\t\tif (orgBlockedCountries && orgBlockedCountries.length > 0) {\n\t\t\treturn [...blockedCountries, ...orgBlockedCountries];\n\t\t}\n\t\treturn blockedCountries;\n\t}, [blockedCountries, organizationSettings]);\n\n\t// Filter countries based on restrictions\n\tconst availableCountries = React.useMemo(() => {\n\t\tlet filtered = countries;\n\n\t\tif (effectiveAllowedCountries.length > 0) {\n\t\t\tfiltered = filtered.filter((c) =>\n\t\t\t\teffectiveAllowedCountries.includes(c.code),\n\t\t\t);\n\t\t}\n\n\t\tif (effectiveBlockedCountries.length > 0) {\n\t\t\tfiltered = filtered.filter(\n\t\t\t\t(c) => !effectiveBlockedCountries.includes(c.code),\n\t\t\t);\n\t\t}\n\n\t\t// Sort with preferred countries first\n\t\tconst preferred = filtered.filter((c) =>\n\t\t\tpreferredCountries.includes(c.code),\n\t\t);\n\t\tconst others = filtered.filter((c) => !preferredCountries.includes(c.code));\n\n\t\treturn [...preferred, ...others];\n\t}, [\n\t\teffectiveAllowedCountries,\n\t\teffectiveBlockedCountries,\n\t\tpreferredCountries,\n\t]);\n\n\t// Phone validation\n\tconst validation = React.useMemo(() => {\n\t\tif (!currentValue || !validateFormat) return null;\n\t\treturn parsePhoneNumber(currentValue, selectedCountry);\n\t}, [currentValue, selectedCountry, validateFormat]);\n\n\t// Combined errors\n\tconst errors = React.useMemo(() => {\n\t\tconst allErrors: string[] = [];\n\n\t\tif (externalError) {\n\t\t\tif (Array.isArray(externalError)) {\n\t\t\t\tallErrors.push(...externalError);\n\t\t\t} else {\n\t\t\t\tallErrors.push(externalError);\n\t\t\t}\n\t\t}\n\n\t\tif (formField.error) {\n\t\t\tif (Array.isArray(formField.error)) {\n\t\t\t\tallErrors.push(...formField.error);\n\t\t\t} else {\n\t\t\t\tallErrors.push(formField.error);\n\t\t\t}\n\t\t}\n\n\t\tif (validation && !validation.isValid) {\n\t\t\tallErrors.push(...validation.errors);\n\t\t}\n\n\t\treturn allErrors.length > 0 ? allErrors : null;\n\t}, [externalError, formField.error, validation]);\n\n\t// Handle value change\n\tconst handleChange = React.useCallback(\n\t\t(newValue: string) => {\n\t\t\t// Auto-detect country if value includes country code\n\t\t\tconst detectedCountry = detectCountryFromNumber(newValue);\n\t\t\tif (detectedCountry && availableCountries.includes(detectedCountry)) {\n\t\t\t\tsetSelectedCountry(detectedCountry);\n\t\t\t}\n\n\t\t\tif (onChange && validation) {\n\t\t\t\tonChange(validation.e164, validation.formatted);\n\t\t\t} else if (onChange) {\n\t\t\t\t// Fallback if validation not available\n\t\t\t\tconst cleaned = newValue.replace(/[^\\d+]/g, \"\");\n\t\t\t\tconst e164 = cleaned.startsWith(\"+\")\n\t\t\t\t\t? cleaned\n\t\t\t\t\t: selectedCountry.dialCode + cleaned.replace(/^\\d/, \"\");\n\t\t\t\tonChange(e164, newValue);\n\t\t\t} else {\n\t\t\t\tsetInternalValue(newValue);\n\t\t\t}\n\n\t\t\t// Clear errors when user starts typing\n\t\t\tif (formField.clearError) {\n\t\t\t\tformField.clearError();\n\t\t\t}\n\t\t},\n\t\t[onChange, validation, formField, selectedCountry, availableCountries],\n\t);\n\n\t// Handle country change\n\tconst handleCountryChange = React.useCallback(\n\t\t(countryCode: string) => {\n\t\t\tconst country = availableCountries.find((c) => c.code === countryCode);\n\t\t\tif (country) {\n\t\t\t\tsetSelectedCountry(country);\n\n\t\t\t\t// Update phone number with new country code if there's a value\n\t\t\t\tif (currentValue) {\n\t\t\t\t\tconst newValidation = parsePhoneNumber(currentValue, country);\n\t\t\t\t\tif (onChange) {\n\t\t\t\t\t\tonChange(newValidation.e164, newValidation.formatted);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[availableCountries, currentValue, onChange],\n\t);\n\n\t// Handle blur\n\tconst handleBlur = React.useCallback(() => {\n\t\tif (formField.setTouched) {\n\t\t\tformField.setTouched(true);\n\t\t}\n\t\tonBlur?.();\n\t}, [formField, onBlur]);\n\n\t// Handle focus\n\tconst handleFocus = React.useCallback(() => {\n\t\tonFocus?.();\n\t}, [onFocus]);\n\n\t// Verification status content\n\tconst verificationContent = React.useMemo(() => {\n\t\tif (!showVerificationStatus || endContent) return null;\n\n\t\tif (isVerified) {\n\t\t\treturn (\n\t\t\t\t<Chip\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tcolor=\"success\"\n\t\t\t\t\tvariant=\"flat\"\n\t\t\t\t\tstartContent={\n\t\t\t\t\t\t<svg\n\t\t\t\t\t\t\tclassName=\"w-3 h-3\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t\t\td=\"M5 13l4 4L19 7\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</svg>\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\tVerified\n\t\t\t\t</Chip>\n\t\t\t);\n\t\t}\n\n\t\tif (currentValue && validation?.isValid && onRequestVerification) {\n\t\t\treturn (\n\t\t\t\t<Button\n\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\tvariant=\"flat\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\tonPress={onRequestVerification}\n\t\t\t\t>\n\t\t\t\t\tSend SMS\n\t\t\t\t</Button>\n\t\t\t);\n\t\t}\n\n\t\treturn null;\n\t}, [\n\t\tshowVerificationStatus,\n\t\tendContent,\n\t\tisVerified,\n\t\tcurrentValue,\n\t\tvalidation,\n\t\tonRequestVerification,\n\t]);\n\n\t// Country selector\n\tconst countrySelector = (\n\t\t<Select\n\t\t\tvalue={selectedCountry.code}\n\t\t\tonChange={(e) => handleCountryChange(e.target.value)}\n\t\t\tclassName=\"min-w-32\"\n\t\t\tsize={size}\n\t\t\tvariant={variant}\n\t\t\tisDisabled={disabled}\n\t\t\tplaceholder=\"Country\"\n\t\t\toptions={availableCountries.map((country) => ({\n\t\t\t\tlabel: country.name,\n\t\t\t\tvalue: country.code,\n\t\t\t}))}\n\t\t\t// renderValue={(items) => {\n\t\t\t// \tconst country = availableCountries.find(\n\t\t\t// \t\t(c) => c.code === selectedCountry.code,\n\t\t\t// \t);\n\t\t\t// \treturn country ? (\n\t\t\t// \t\t<div className=\"flex items-center gap-1\">\n\t\t\t// \t\t\t<span>{country.flag}</span>\n\t\t\t// \t\t\t<span className=\"text-sm\">{country.dialCode}</span>\n\t\t\t// \t\t</div>\n\t\t\t// \t) : null;\n\t\t\t// }}\n\t\t>\n\t\t\t{/*{availableCountries.map((country) => (*/}\n\t\t\t{/*\t<SelectItem*/}\n\t\t\t{/*\t\tkey={country.code}*/}\n\t\t\t{/*\t\tvalue={country.code}*/}\n\t\t\t{/*\t\tstartContent={<span className=\"text-lg\">{country.flag}</span>}*/}\n\t\t\t{/*\t>*/}\n\t\t\t{/*\t\t<div className=\"flex items-center justify-between w-full\">*/}\n\t\t\t{/*\t\t\t<span>{country.name}</span>*/}\n\t\t\t{/*\t\t\t<span className=\"text-sm text-default-500\">{country.dialCode}</span>*/}\n\t\t\t{/*\t\t</div>*/}\n\t\t\t{/*\t</SelectItem>*/}\n\t\t\t{/*))}*/}\n\t\t</Select>\n\t);\n\n\treturn (\n\t\t<div className={`space-y-2 ${className}`}>\n\t\t\t<div className=\"flex gap-2\">\n\t\t\t\t{/* Country Selector */}\n\t\t\t\t<div className=\"shrink-0\">{countrySelector}</div>\n\n\t\t\t\t{/* Phone Input */}\n\t\t\t\t<div className=\"flex-1\">\n\t\t\t\t\t<Input\n\t\t\t\t\t\tname={name}\n\t\t\t\t\t\tlabel={label}\n\t\t\t\t\t\tplaceholder={placeholder}\n\t\t\t\t\t\tvalue={currentValue}\n\t\t\t\t\t\tonValueChange={handleChange}\n\t\t\t\t\t\tonBlur={handleBlur}\n\t\t\t\t\t\tonFocus={handleFocus}\n\t\t\t\t\t\ttype=\"tel\"\n\t\t\t\t\t\tisRequired={required}\n\t\t\t\t\t\tisDisabled={disabled}\n\t\t\t\t\t\tsize={size}\n\t\t\t\t\t\tvariant={variant}\n\t\t\t\t\t\tautoFocus={autoFocus}\n\t\t\t\t\t\tautoComplete={autoComplete}\n\t\t\t\t\t\tdescription={description}\n\t\t\t\t\t\tisInvalid={!!errors}\n\t\t\t\t\t\terrorMessage=\"\"\n\t\t\t\t\t\tendContent={endContent || verificationContent}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t{/* Field Errors */}\n\t\t\t{errors && <FieldError error={errors} fieldName={name} />}\n\n\t\t\t{/* Format Preview */}\n\t\t\t{validation && validation.isValid && (\n\t\t\t\t<div className=\"text-xs text-default-500\">\n\t\t\t\t\t<span className=\"font-medium\">Format:</span> {validation.formatted}\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{/* Country Restrictions Info */}\n\t\t\t{effectiveAllowedCountries.length > 0 && (\n\t\t\t\t<div className=\"text-xs text-default-500\">\n\t\t\t\t\t<span className=\"font-medium\">Allowed countries:</span>{\" \"}\n\t\t\t\t\t{effectiveAllowedCountries.join(\", \")}\n\t\t\t\t</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n\n// ============================================================================\n// Export\n// ============================================================================\n\nexport default PhoneField;\n"],"names":["countries","parsePhoneNumber","phoneNumber","country","errors","cleaned","nationalNumber","e164","formatted","formatPhoneNumber","number","format","formattedNumber","numberIndex","i","detectCountryFromNumber","sortedCountries","a","b","PhoneField","name","label","placeholder","value","onChange","onBlur","onFocus","defaultCountry","preferredCountries","allowedCountries","blockedCountries","required","disabled","validateFormat","size","variant","className","autoFocus","autoComplete","externalError","description","showVerificationStatus","isVerified","onRequestVerification","endContent","components","organizationSettings","useConfig","formField","useFormField","CustomPhoneField","jsx","internalValue","setInternalValue","React","selectedCountry","setSelectedCountry","detectedCountry","c","currentValue","effectiveAllowedCountries","orgCountries","effectiveBlockedCountries","orgBlockedCountries","availableCountries","filtered","preferred","others","validation","allErrors","handleChange","newValue","handleCountryChange","countryCode","newValidation","handleBlur","handleFocus","verificationContent","Chip","Button","countrySelector","Select","jsxs","Input","FieldError"],"mappings":"mdAkKMA,EAAuB,CAC5B,CACC,KAAM,KACN,KAAM,gBACN,SAAU,KACV,KAAM,OACN,OAAQ,gBACT,EACA,CACC,KAAM,KACN,KAAM,SACN,SAAU,KACV,KAAM,OACN,OAAQ,gBACT,EACA,CACC,KAAM,KACN,KAAM,iBACN,SAAU,MACV,KAAM,OACN,OAAQ,eACT,EACA,CACC,KAAM,KACN,KAAM,YACN,SAAU,MACV,KAAM,OACN,OAAQ,cACT,EACA,CACC,KAAM,KACN,KAAM,UACN,SAAU,MACV,KAAM,OACN,OAAQ,cACT,EACA,CACC,KAAM,KACN,KAAM,SACN,SAAU,MACV,KAAM,OACN,OAAQ,gBACT,EACA,CACC,KAAM,KACN,KAAM,QACN,SAAU,MACV,KAAM,OACN,OAAQ,aACT,EACA,CACC,KAAM,KACN,KAAM,QACN,SAAU,MACV,KAAM,OACN,OAAQ,cACT,EACA,CACC,KAAM,KACN,KAAM,QACN,SAAU,MACV,KAAM,OACN,OAAQ,eACT,EACA,CACC,KAAM,KACN,KAAM,cACN,SAAU,MACV,KAAM,OACN,OAAQ,eACT,EACA,CACC,KAAM,KACN,KAAM,QACN,SAAU,MACV,KAAM,OACN,OAAQ,eACT,EACA,CACC,KAAM,KACN,KAAM,QACN,SAAU,MACV,KAAM,OACN,OAAQ,aACT,EACA,CACC,KAAM,KACN,KAAM,SACN,SAAU,MACV,KAAM,OACN,OAAQ,iBACT,EACA,CACC,KAAM,KACN,KAAM,SACN,SAAU,MACV,KAAM,OACN,OAAQ,cACT,EACA,CACC,KAAM,KACN,KAAM,YACN,SAAU,MACV,KAAM,OACN,OAAQ,cACT,EACA,CACC,KAAM,KACN,KAAM,SACN,SAAU,KACV,KAAM,OACN,OAAQ,eACT,EACA,CACC,KAAM,KACN,KAAM,eACN,SAAU,MACV,KAAM,OACN,OAAQ,aACT,EACA,CACC,KAAM,KACN,KAAM,QACN,SAAU,MACV,KAAM,OACN,OAAQ,cACT,EACA,CACC,KAAM,KACN,KAAM,UACN,SAAU,OACV,KAAM,OACN,OAAQ,cACT,EACA,CACC,KAAM,KACN,KAAM,YACN,SAAU,MACV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"}