@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
1 lines • 28.8 kB
Source Map (JSON)
{"version":3,"file":"email-field.cjs","sources":["../../../../src/components/forms/email-field.tsx"],"sourcesContent":["/**\n * @frank-auth/react - Email Field Component\n *\n * Email input field with comprehensive validation, domain suggestions,\n * and organization-specific email requirements for multi-tenant authentication.\n */\n\n\"use client\";\n\nimport type { FieldProps } from \"@/components/forms/shared\";\nimport { Button, Chip, Input } from \"@/components/ui\";\nimport { Listbox, ListboxItem, Popover } from \"@/components/ui\";\nimport { useTheme } from \"@/theme/context\";\nimport type { StyledProps } from \"@/theme/styled\";\nimport styled from \"@emotion/styled\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport React from \"react\";\nimport { useConfig } from \"../../hooks/use-config\";\nimport { FieldError } from \"./field-error\";\nimport { useFormField } from \"./form-wrapper\";\n\n// ============================================================================\n// Email Field Interface\n// ============================================================================\n\nexport interface EmailFieldProps extends FieldProps<string> {\n\t/**\n\t * Whether to show domain suggestions\n\t */\n\tshowSuggestions?: boolean;\n\n\t/**\n\t * Whether to validate email format\n\t */\n\tvalidateFormat?: boolean;\n\n\t/**\n\t * Whether to validate domain\n\t */\n\tvalidateDomain?: boolean;\n\n\t/**\n\t * Custom allowed domains (for organization restrictions)\n\t */\n\tallowedDomains?: string[];\n\n\t/**\n\t * Custom blocked domains\n\t */\n\tblockedDomains?: string[];\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 email is verified\n\t */\n\tisVerified?: boolean;\n\n\t/**\n\t * Verification handler\n\t */\n\tonRequestVerification?: () => void;\n}\n\n// ============================================================================\n// Email Validation Types\n// ============================================================================\n\nexport interface EmailValidation {\n\tisValid: boolean;\n\terrors: string[];\n\tsuggestions: string[];\n\tdomain: string | null;\n\tusername: string | null;\n}\n\n// ============================================================================\n// Styled Components\n// ============================================================================\n\n// Fixed: Reduced gap from spacing[2] (0.5rem) to spacing[1] (0.25rem) for tighter spacing\nconst EmailFieldContainer = styled.div<StyledProps>`\n display: flex;\n flex-direction: column;\n gap: ${(props) => props.theme.spacing[1]};\n`;\n\nconst PopoverContent = styled.div<StyledProps>`\n padding: ${(props) => props.theme.spacing[1]};\n`;\n\nconst DomainRestrictionsInfo = styled.div<StyledProps>`\n font-size: ${(props) => props.theme.fontSizes.xs};\n color: ${(props) => props.theme.colors.text.tertiary};\n`;\n\nconst DomainLabel = styled.span<StyledProps>`\n font-weight: ${(props) => props.theme.fontWeights.medium};\n`;\n\nconst SuggestionsContainer = styled(motion.div)<StyledProps>`\n display: flex;\n flex-direction: column;\n gap: ${(props) => props.theme.spacing[1]};\n`;\n\nconst SuggestionsTitle = styled.div<StyledProps>`\n font-size: ${(props) => props.theme.fontSizes.xs};\n color: ${(props) => props.theme.colors.text.secondary};\n font-weight: ${(props) => props.theme.fontWeights.medium};\n`;\n\nconst SuggestionsButtons = styled.div<StyledProps>`\n display: flex;\n flex-wrap: wrap;\n gap: ${(props) => props.theme.spacing[1]};\n`;\n\nconst EmailIconSvg = styled.svg<StyledProps>`\n width: ${(props) => props.theme.spacing[4]};\n height: ${(props) => props.theme.spacing[4]};\n color: ${(props) => props.theme.colors.text.quaternary};\n`;\n\nconst VerificationIconSvg = styled.svg<StyledProps>`\n width: ${(props) => props.theme.spacing[3]};\n height: ${(props) => props.theme.spacing[3]};\n`;\n\nconst PrimaryIconSvg = styled.svg<StyledProps>`\n width: ${(props) => props.theme.spacing[4]};\n height: ${(props) => props.theme.spacing[4]};\n color: ${(props) => props.theme.colors.primary[500]};\n`;\n\nconst SuggestionButton = styled(Button)<StyledProps>`\n font-size: ${(props) => props.theme.fontSizes.xs};\n height: ${(props) => props.theme.spacing[6]};\n`;\n\n// ============================================================================\n// Common Email Domains\n// ============================================================================\n\nconst commonDomains = [\n\t\"gmail.com\",\n\t\"yahoo.com\",\n\t\"hotmail.com\",\n\t\"outlook.com\",\n\t\"icloud.com\",\n\t\"aol.com\",\n\t\"live.com\",\n\t\"msn.com\",\n\t\"me.com\",\n\t\"mail.com\",\n\t\"protonmail.com\",\n\t\"yandex.com\",\n\t\"zoho.com\",\n\t\"fastmail.com\",\n];\n\nconst commonMisspellings = {\n\t\"gmial.com\": \"gmail.com\",\n\t\"gmai.com\": \"gmail.com\",\n\t\"gmil.com\": \"gmail.com\",\n\t\"yahho.com\": \"yahoo.com\",\n\t\"yaho.com\": \"yahoo.com\",\n\t\"hotmial.com\": \"hotmail.com\",\n\t\"hotmil.com\": \"hotmail.com\",\n\t\"outlok.com\": \"outlook.com\",\n\t\"outloo.com\": \"outlook.com\",\n};\n\n// ============================================================================\n// Email Validation Functions\n// ============================================================================\n\nfunction validateEmail(\n\temail: string,\n\toptions: {\n\t\tvalidateFormat?: boolean;\n\t\tvalidateDomain?: boolean;\n\t\tallowedDomains?: string[];\n\t\tblockedDomains?: string[];\n\t} = {},\n): EmailValidation {\n\tconst {\n\t\tvalidateFormat = true,\n\t\tvalidateDomain = false,\n\t\tallowedDomains = [],\n\t\tblockedDomains = [],\n\t} = options;\n\n\tconst errors: string[] = [];\n\tconst suggestions: string[] = [];\n\tlet domain: string | null = null;\n\tlet username: string | null = null;\n\n\t// Basic format validation\n\tif (validateFormat) {\n\t\tconst emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\t\tif (!emailRegex.test(email)) {\n\t\t\terrors.push(\"Please enter a valid email address\");\n\t\t}\n\t}\n\n\t// Extract domain and username\n\tconst emailParts = email.split(\"@\");\n\tif (emailParts.length === 2) {\n\t\tusername = emailParts[0];\n\t\tdomain = emailParts[1].toLowerCase();\n\n\t\t// Check for domain misspellings\n\t\tif (domain && commonMisspellings[domain]) {\n\t\t\tsuggestions.push(\n\t\t\t\t`Did you mean ${username}@${commonMisspellings[domain]}?`,\n\t\t\t);\n\t\t}\n\n\t\t// Domain validation\n\t\tif (validateDomain && domain) {\n\t\t\t// Check allowed domains\n\t\t\tif (allowedDomains.length > 0 && !allowedDomains.includes(domain)) {\n\t\t\t\terrors.push(\n\t\t\t\t\t`Email must be from one of these domains: ${allowedDomains.join(\", \")}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Check blocked domains\n\t\t\tif (blockedDomains.includes(domain)) {\n\t\t\t\terrors.push(\"This email domain is not allowed\");\n\t\t\t}\n\n\t\t\t// Basic domain format check\n\t\t\tif (!/^[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$/.test(domain)) {\n\t\t\t\terrors.push(\"Invalid email domain\");\n\t\t\t}\n\t\t}\n\n\t\t// Generate suggestions for incomplete domains\n\t\tif (username && domain && domain.length > 0 && !domain.includes(\".\")) {\n\t\t\tconst matchingDomains = commonDomains.filter((d) =>\n\t\t\t\td.toLowerCase().startsWith(domain.toLowerCase()),\n\t\t\t);\n\t\t\tmatchingDomains.slice(0, 3).forEach((d) => {\n\t\t\t\tsuggestions.push(`${username}@${d}`);\n\t\t\t});\n\t\t}\n\t}\n\n\treturn {\n\t\tisValid: errors.length === 0,\n\t\terrors,\n\t\tsuggestions,\n\t\tdomain,\n\t\tusername,\n\t};\n}\n\n// ============================================================================\n// Email Field Component\n// ============================================================================\n\nexport function EmailField({\n\tname = \"email\",\n\tlabel = \"Email\",\n\tplaceholder = \"Enter your email address\",\n\tvalue = \"\",\n\tonChange,\n\tonBlur,\n\tonFocus,\n\trequired = false,\n\tdisabled = false,\n\tshowSuggestions = true,\n\tvalidateFormat = true,\n\tvalidateDomain = false,\n\tallowedDomains = [],\n\tblockedDomains = [],\n\tsize = \"md\",\n\tradius = \"md\",\n\tvariant = \"bordered\",\n\tclassName = \"\",\n\tautoFocus = false,\n\tautoComplete = \"email\",\n\terror: externalError,\n\tdescription,\n\tshowVerificationStatus = false,\n\tisVerified = false,\n\tonRequestVerification,\n\tstartContent,\n\tendContent,\n}: EmailFieldProps) {\n\tconst { theme } = useTheme();\n\tconst { components, organizationSettings } = useConfig();\n\tconst formField = useFormField(name);\n\n\t// Custom component override\n\tconst RootInput = React.useMemo(\n\t\t() => components.Input ?? Input,\n\t\t[components.Input],\n\t);\n\tconst CustomEmailField = components.EmailField;\n\tif (CustomEmailField) {\n\t\treturn (\n\t\t\t<CustomEmailField\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\trequired,\n\t\t\t\t\tdisabled,\n\t\t\t\t\tshowSuggestions,\n\t\t\t\t\tvalidateFormat,\n\t\t\t\t\tvalidateDomain,\n\t\t\t\t\tallowedDomains,\n\t\t\t\t\tblockedDomains,\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\tstartContent,\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 [isFocused, setIsFocused] = React.useState(false);\n\tconst [showSuggestionPopover, setShowSuggestionPopover] =\n\t\tReact.useState(false);\n\n\t// Use external value if controlled\n\tconst currentValue = onChange ? value : internalValue;\n\n\t// Apply organization email restrictions if available\n\tconst effectiveAllowedDomains = React.useMemo(() => {\n\t\tconst orgDomains = organizationSettings?.emailRestrictions?.allowedDomains;\n\t\tif (orgDomains && orgDomains.length > 0) {\n\t\t\treturn orgDomains;\n\t\t}\n\t\treturn allowedDomains;\n\t}, [allowedDomains, organizationSettings]);\n\n\tconst effectiveBlockedDomains = React.useMemo(() => {\n\t\tconst orgBlockedDomains =\n\t\t\torganizationSettings?.emailRestrictions?.blockedDomains;\n\t\tif (orgBlockedDomains && orgBlockedDomains.length > 0) {\n\t\t\treturn [...blockedDomains, ...orgBlockedDomains];\n\t\t}\n\t\treturn blockedDomains;\n\t}, [blockedDomains, organizationSettings]);\n\n\t// Email validation\n\tconst validation = React.useMemo(() => {\n\t\tif (!currentValue) return null;\n\t\treturn validateEmail(currentValue, {\n\t\t\tvalidateFormat,\n\t\t\tvalidateDomain,\n\t\t\tallowedDomains: effectiveAllowedDomains,\n\t\t\tblockedDomains: effectiveBlockedDomains,\n\t\t});\n\t}, [\n\t\tcurrentValue,\n\t\tvalidateFormat,\n\t\tvalidateDomain,\n\t\teffectiveAllowedDomains,\n\t\teffectiveBlockedDomains,\n\t]);\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// Keep original value while typing - no transformations\n\t\t\tif (onChange) {\n\t\t\t\tonChange(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\n\t\t\t// Show suggestions if we have them and field is focused\n\t\t\tif (validation?.suggestions.length && isFocused && showSuggestions) {\n\t\t\t\tsetShowSuggestionPopover(true);\n\t\t\t} else {\n\t\t\t\tsetShowSuggestionPopover(false);\n\t\t\t}\n\t\t},\n\t\t[onChange, formField, validation, isFocused, showSuggestions],\n\t);\n\n\t// Handle blur\n\tconst handleBlur = React.useCallback(() => {\n\t\tsetIsFocused(false);\n\t\tsetShowSuggestionPopover(false);\n\n\t\t// Apply transformations only when user finishes typing\n\t\tif (currentValue) {\n\t\t\tconst trimmedValue = currentValue.trim().toLowerCase();\n\t\t\tif (trimmedValue !== currentValue) {\n\t\t\t\tif (onChange) {\n\t\t\t\t\tonChange(trimmedValue);\n\t\t\t\t} else {\n\t\t\t\t\tsetInternalValue(trimmedValue);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (formField.setTouched) {\n\t\t\tformField.setTouched(true);\n\t\t}\n\t\tonBlur?.();\n\t}, [formField, onBlur, currentValue, onChange]);\n\n\t// Handle focus\n\tconst handleFocus = React.useCallback(() => {\n\t\tsetIsFocused(true);\n\t\tonFocus?.();\n\t\tif (showSuggestions && validation?.suggestions.length) {\n\t\t\tsetShowSuggestionPopover(true);\n\t\t}\n\t}, [onFocus, showSuggestions, validation]);\n\n\t// Handle suggestion selection\n\tconst handleSuggestionSelect = React.useCallback(\n\t\t(suggestion: string) => {\n\t\t\thandleChange(suggestion);\n\t\t\tsetShowSuggestionPopover(false);\n\t\t},\n\t\t[handleChange],\n\t);\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<VerificationIconSvg\n\t\t\t\t\t\t\ttheme={theme}\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</VerificationIconSvg>\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=\"ghost\"\n\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\tonPress={onRequestVerification}\n\t\t\t\t>\n\t\t\t\t\tVerify\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\ttheme,\n\t]);\n\n\t// Email icon\n\tconst emailIcon = (\n\t\t<EmailIconSvg\n\t\t\ttheme={theme}\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t>\n\t\t\t<path\n\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\tstrokeWidth={2}\n\t\t\t\td=\"M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207\"\n\t\t\t/>\n\t\t</EmailIconSvg>\n\t);\n\n\tconst inputContent = (\n\t\t<RootInput\n\t\t\tname={name}\n\t\t\tlabel={label}\n\t\t\tplaceholder={placeholder}\n\t\t\tvalue={currentValue}\n\t\t\tonChange={(e: any) => handleChange(e.target.value)}\n\t\t\tonBlur={handleBlur}\n\t\t\tonFocus={handleFocus}\n\t\t\ttype=\"email\"\n\t\t\tisRequired={required}\n\t\t\trequired={required}\n\t\t\tisDisabled={disabled}\n\t\t\tdisabled={disabled}\n\t\t\tsize={size}\n\t\t\tradius={radius}\n\t\t\tvariant=\"bordered\"\n\t\t\tautoFocus={autoFocus}\n\t\t\tautoComplete={autoComplete}\n\t\t\tdescription={description}\n\t\t\tisInvalid={!!errors}\n\t\t\terrorMessage=\"\"\n\t\t\tstartContent={startContent || emailIcon}\n\t\t\tendContent={endContent || verificationContent}\n\t\t/>\n\t);\n\n\treturn (\n\t\t<EmailFieldContainer theme={theme} className={className}>\n\t\t\t{/* Input with suggestion popover */}\n\t\t\t{showSuggestions && validation?.suggestions.length ? (\n\t\t\t\t<Popover\n\t\t\t\t\tisOpen={showSuggestionPopover}\n\t\t\t\t\tonOpenChange={setShowSuggestionPopover}\n\t\t\t\t\tplacement=\"bottom-start\"\n\t\t\t\t\tshowArrow\n\t\t\t\t>\n\t\t\t\t\t<Popover.Trigger>{inputContent}</Popover.Trigger>\n\t\t\t\t\t<Popover.Content>\n\t\t\t\t\t\t<PopoverContent theme={theme}>\n\t\t\t\t\t\t\t<Listbox\n\t\t\t\t\t\t\t\taria-label=\"Email suggestions\"\n\t\t\t\t\t\t\t\tonAction={(key) => handleSuggestionSelect(key as string)}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{validation.suggestions.map((suggestion, index) => (\n\t\t\t\t\t\t\t\t\t<ListboxItem\n\t\t\t\t\t\t\t\t\t\tkey={suggestion}\n\t\t\t\t\t\t\t\t\t\tvalue={suggestion}\n\t\t\t\t\t\t\t\t\t\tstartContent={\n\t\t\t\t\t\t\t\t\t\t\t<PrimaryIconSvg\n\t\t\t\t\t\t\t\t\t\t\t\ttheme={theme}\n\t\t\t\t\t\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t\t\t\t\t\tstroke=\"currentColor\"\n\t\t\t\t\t\t\t\t\t\t\t\tviewBox=\"0 0 24 24\"\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t\t\t\t\t\t\tstrokeLinecap=\"round\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tstrokeLinejoin=\"round\"\n\t\t\t\t\t\t\t\t\t\t\t\t\tstrokeWidth={2}\n\t\t\t\t\t\t\t\t\t\t\t\t\td=\"M13 10V3L4 14h7v7l9-11h-7z\"\n\t\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t\t</PrimaryIconSvg>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{suggestion}\n\t\t\t\t\t\t\t\t\t</ListboxItem>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</Listbox>\n\t\t\t\t\t\t</PopoverContent>\n\t\t\t\t\t</Popover.Content>\n\t\t\t\t</Popover>\n\t\t\t) : (\n\t\t\t\tinputContent\n\t\t\t)}\n\n\t\t\t{/* Field Errors */}\n\t\t\t{errors && <FieldError error={errors} fieldName={name} />}\n\n\t\t\t{/* Domain Restrictions Info */}\n\t\t\t{effectiveAllowedDomains.length > 0 && (\n\t\t\t\t<DomainRestrictionsInfo theme={theme}>\n\t\t\t\t\t<DomainLabel theme={theme}>Allowed domains:</DomainLabel>{\" \"}\n\t\t\t\t\t{effectiveAllowedDomains.join(\", \")}\n\t\t\t\t</DomainRestrictionsInfo>\n\t\t\t)}\n\n\t\t\t{/* Suggestions (non-popover) */}\n\t\t\t<AnimatePresence>\n\t\t\t\t{!showSuggestionPopover &&\n\t\t\t\t\tvalidation?.suggestions.length &&\n\t\t\t\t\tisFocused && (\n\t\t\t\t\t\t<SuggestionsContainer\n\t\t\t\t\t\t\ttheme={theme}\n\t\t\t\t\t\t\tinitial={{ opacity: 0, y: -10 }}\n\t\t\t\t\t\t\tanimate={{ opacity: 1, y: 0 }}\n\t\t\t\t\t\t\texit={{ opacity: 0, y: -10 }}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<SuggestionsTitle theme={theme}>Did you mean:</SuggestionsTitle>\n\t\t\t\t\t\t\t<SuggestionsButtons theme={theme}>\n\t\t\t\t\t\t\t\t{validation.suggestions.slice(0, 3).map((suggestion, index) => (\n\t\t\t\t\t\t\t\t\t<SuggestionButton\n\t\t\t\t\t\t\t\t\t\tkey={index}\n\t\t\t\t\t\t\t\t\t\ttheme={theme}\n\t\t\t\t\t\t\t\t\t\tsize=\"sm\"\n\t\t\t\t\t\t\t\t\t\tvariant=\"ghost\"\n\t\t\t\t\t\t\t\t\t\tcolor=\"primary\"\n\t\t\t\t\t\t\t\t\t\tonClick={() => handleSuggestionSelect(suggestion)}\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{suggestion}\n\t\t\t\t\t\t\t\t\t</SuggestionButton>\n\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t</SuggestionsButtons>\n\t\t\t\t\t\t</SuggestionsContainer>\n\t\t\t\t\t)}\n\t\t\t</AnimatePresence>\n\t\t</EmailFieldContainer>\n\t);\n}\n\n// ============================================================================\n// Export\n// ============================================================================\n\nexport default EmailField;\n"],"names":["EmailFieldContainer","styled","props","PopoverContent","DomainRestrictionsInfo","DomainLabel","SuggestionsContainer","motion","SuggestionsTitle","SuggestionsButtons","EmailIconSvg","VerificationIconSvg","PrimaryIconSvg","SuggestionButton","Button","commonDomains","commonMisspellings","validateEmail","email","options","validateFormat","validateDomain","allowedDomains","blockedDomains","errors","suggestions","domain","username","emailParts","d","EmailField","name","label","placeholder","value","onChange","onBlur","onFocus","required","disabled","showSuggestions","size","radius","variant","className","autoFocus","autoComplete","externalError","description","showVerificationStatus","isVerified","onRequestVerification","startContent","endContent","theme","useTheme","components","organizationSettings","useConfig","formField","useFormField","RootInput","React","Input","CustomEmailField","jsx","internalValue","setInternalValue","isFocused","setIsFocused","showSuggestionPopover","setShowSuggestionPopover","currentValue","effectiveAllowedDomains","orgDomains","effectiveBlockedDomains","orgBlockedDomains","validation","allErrors","handleChange","newValue","handleBlur","trimmedValue","handleFocus","handleSuggestionSelect","suggestion","verificationContent","Chip","emailIcon","inputContent","e","jsxs","Popover","Listbox","key","index","ListboxItem","FieldError","AnimatePresence","email_field_default"],"mappings":"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"}