@thunderid/react 1.4.0 → 1.4.1

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.
Files changed (78) hide show
  1. package/dist/cjs/components/presentation/auth/SignIn/BaseSignIn.cjs +1 -0
  2. package/dist/cjs/components/presentation/auth/SignIn/BaseSignIn.cjs.map +1 -1
  3. package/dist/cjs/components/presentation/auth/SignIn/SignIn.cjs +2 -3
  4. package/dist/cjs/components/presentation/auth/SignIn/SignIn.cjs.map +1 -1
  5. package/dist/cjs/components/presentation/auth/SignUp/BaseSignUp.cjs +1 -0
  6. package/dist/cjs/components/presentation/auth/SignUp/BaseSignUp.cjs.map +1 -1
  7. package/dist/cjs/components/primitives/AffixedField/AffixedField.cjs +11 -1
  8. package/dist/cjs/components/primitives/AffixedField/AffixedField.cjs.map +1 -1
  9. package/dist/cjs/components/primitives/Checkbox/Checkbox.cjs +11 -1
  10. package/dist/cjs/components/primitives/Checkbox/Checkbox.cjs.map +1 -1
  11. package/dist/cjs/components/primitives/DatePicker/DatePicker.cjs +11 -1
  12. package/dist/cjs/components/primitives/DatePicker/DatePicker.cjs.map +1 -1
  13. package/dist/cjs/components/primitives/FormControl/FormControl.cjs +2 -1
  14. package/dist/cjs/components/primitives/FormControl/FormControl.cjs.map +1 -1
  15. package/dist/cjs/components/primitives/MultiInput/MultiInput.cjs +11 -2
  16. package/dist/cjs/components/primitives/MultiInput/MultiInput.cjs.map +1 -1
  17. package/dist/cjs/components/primitives/OtpField/OtpField.cjs +9 -0
  18. package/dist/cjs/components/primitives/OtpField/OtpField.cjs.map +1 -1
  19. package/dist/cjs/components/primitives/Select/Select.cjs +8 -0
  20. package/dist/cjs/components/primitives/Select/Select.cjs.map +1 -1
  21. package/dist/cjs/components/primitives/TextField/TextField.cjs +11 -1
  22. package/dist/cjs/components/primitives/TextField/TextField.cjs.map +1 -1
  23. package/dist/cjs/components/primitives/Toggle/Toggle.cjs +10 -1
  24. package/dist/cjs/components/primitives/Toggle/Toggle.cjs.map +1 -1
  25. package/dist/cjs/contexts/Theme/ThemeProvider.cjs +1 -1
  26. package/dist/cjs/contexts/Theme/ThemeProvider.cjs.map +1 -1
  27. package/dist/cjs/contexts/ThunderID/ThunderIDContext.cjs.map +1 -1
  28. package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs +1 -1
  29. package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs.map +1 -1
  30. package/dist/components/presentation/auth/SignIn/BaseSignIn.d.ts +4 -0
  31. package/dist/components/presentation/auth/SignIn/BaseSignIn.d.ts.map +1 -1
  32. package/dist/components/presentation/auth/SignIn/BaseSignIn.js +1 -0
  33. package/dist/components/presentation/auth/SignIn/BaseSignIn.js.map +1 -1
  34. package/dist/components/presentation/auth/SignIn/SignIn.d.ts.map +1 -1
  35. package/dist/components/presentation/auth/SignIn/SignIn.js +2 -3
  36. package/dist/components/presentation/auth/SignIn/SignIn.js.map +1 -1
  37. package/dist/components/presentation/auth/SignUp/BaseSignUp.d.ts +4 -0
  38. package/dist/components/presentation/auth/SignUp/BaseSignUp.d.ts.map +1 -1
  39. package/dist/components/presentation/auth/SignUp/BaseSignUp.js +1 -0
  40. package/dist/components/presentation/auth/SignUp/BaseSignUp.js.map +1 -1
  41. package/dist/components/primitives/AffixedField/AffixedField.d.ts.map +1 -1
  42. package/dist/components/primitives/AffixedField/AffixedField.js +11 -1
  43. package/dist/components/primitives/AffixedField/AffixedField.js.map +1 -1
  44. package/dist/components/primitives/Checkbox/Checkbox.d.ts.map +1 -1
  45. package/dist/components/primitives/Checkbox/Checkbox.js +10 -1
  46. package/dist/components/primitives/Checkbox/Checkbox.js.map +1 -1
  47. package/dist/components/primitives/DatePicker/DatePicker.d.ts.map +1 -1
  48. package/dist/components/primitives/DatePicker/DatePicker.js +10 -1
  49. package/dist/components/primitives/DatePicker/DatePicker.js.map +1 -1
  50. package/dist/components/primitives/FormControl/FormControl.d.ts +4 -0
  51. package/dist/components/primitives/FormControl/FormControl.d.ts.map +1 -1
  52. package/dist/components/primitives/FormControl/FormControl.js +2 -1
  53. package/dist/components/primitives/FormControl/FormControl.js.map +1 -1
  54. package/dist/components/primitives/MultiInput/MultiInput.d.ts.map +1 -1
  55. package/dist/components/primitives/MultiInput/MultiInput.js +12 -3
  56. package/dist/components/primitives/MultiInput/MultiInput.js.map +1 -1
  57. package/dist/components/primitives/OtpField/OtpField.d.ts.map +1 -1
  58. package/dist/components/primitives/OtpField/OtpField.js +10 -1
  59. package/dist/components/primitives/OtpField/OtpField.js.map +1 -1
  60. package/dist/components/primitives/Select/Select.d.ts.map +1 -1
  61. package/dist/components/primitives/Select/Select.js +9 -1
  62. package/dist/components/primitives/Select/Select.js.map +1 -1
  63. package/dist/components/primitives/TextField/TextField.d.ts.map +1 -1
  64. package/dist/components/primitives/TextField/TextField.js +10 -1
  65. package/dist/components/primitives/TextField/TextField.js.map +1 -1
  66. package/dist/components/primitives/Toggle/Toggle.d.ts.map +1 -1
  67. package/dist/components/primitives/Toggle/Toggle.js +9 -1
  68. package/dist/components/primitives/Toggle/Toggle.js.map +1 -1
  69. package/dist/contexts/Theme/ThemeProvider.d.ts.map +1 -1
  70. package/dist/contexts/Theme/ThemeProvider.js +1 -1
  71. package/dist/contexts/Theme/ThemeProvider.js.map +1 -1
  72. package/dist/contexts/ThunderID/ThunderIDContext.d.ts +4 -3
  73. package/dist/contexts/ThunderID/ThunderIDContext.d.ts.map +1 -1
  74. package/dist/contexts/ThunderID/ThunderIDContext.js.map +1 -1
  75. package/dist/contexts/ThunderID/ThunderIDProvider.d.ts.map +1 -1
  76. package/dist/contexts/ThunderID/ThunderIDProvider.js +1 -1
  77. package/dist/contexts/ThunderID/ThunderIDProvider.js.map +1 -1
  78. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"BaseSignUp.cjs","names":["logger: ReturnType<typeof createPackageComponentLogger>","BaseSignUpContent: FC<BaseSignUpProps>","useTheme","customRenderers: ComponentRendererMap","ComponentRendererContext","useTranslation","useFlow","useThunderID","styles: any","useStyles","challengeTokenRef: any","initializationAttemptedRef: any","passkeyProcessedRef: any","tempData: any","storageManager: any","handleError: any","errorMessage: string","extractErrorMessage","normalizeFlowResponseLocal: any","normalizeFlowResponse","extractFormFields: any","fields: FormField[]","EmbeddedFlowComponentType","fieldName: any","useForm","responseFieldErrors: FieldError[] | undefined","errors: Record<string, string>","touched: Record<string, boolean>","setupFormFields: any","fields: any","initialValues: Record<string, string>","data: any","components: unknown[] | undefined","EmbeddedSignUpFlowStatus","normalized: any","EmbeddedSignUpFlowType","redirectUrl: any","expectedState: string | null","reusablePopup: Window | null","popup: Window | null","hasProcessedCallback: any","popupMonitor: ReturnType<typeof setInterval> | null","messageHandler: ((event: MessageEvent) => Promise<void>) | null","payload: EmbeddedSignUpFlowRequest","continueResponse: any","normalizedContinueResponse: any","popupError: Error","expectedOrigin: any","popupUrl: any","url: any","code: any","state: any","error: any","composedData: Record<string, any> | undefined","composeAffixedInputs","filteredInputs: Record<string, any>","response: any","effectiveExecutionIdForPasskey: any","passkeyResponse: any","handlePasskeyRegistration","passkeyResponseObj: any","inputs: any","processedResponse: any","containerClasses: any","cx","inputClasses: any","buttonClasses: any","errorClasses: any","messageClasses: any","renderComponents: any","renderSignUpComponents","urlParams: any","payload: any","url: URL","result: any","CardPrimitive","Spinner","AlertPrimitive","getAuthComponentHeadings","Typography","BaseSignUp: FC<BaseSignUpProps>","content: ReactElement","Logo","FlowProvider","ComponentPreferencesContext"],"sources":["../../../../../../src/components/presentation/auth/SignUp/BaseSignUp.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n EmbeddedSignUpFlowRequest,\n EmbeddedSignUpFlowResponse,\n EmbeddedSignUpFlowStatus,\n EmbeddedSignUpFlowType,\n withVendorCSSClassPrefix,\n EmbeddedFlowComponentType,\n FieldError,\n createPackageComponentLogger,\n buildValidatorFromRules,\n Preferences,\n} from '@thunderid/browser';\nimport {FC, ReactElement, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';\nimport useStyles from './BaseSignUp.styles';\nimport ComponentRendererContext, {\n ComponentRendererMap,\n} from '../../../../contexts/ComponentRenderer/ComponentRendererContext';\nimport FlowProvider from '../../../../contexts/Flow/FlowProvider';\nimport useFlow from '../../../../contexts/Flow/useFlow';\nimport ComponentPreferencesContext from '../../../../contexts/I18n/ComponentPreferencesContext';\nimport useTheme from '../../../../contexts/Theme/useTheme';\nimport useThunderID from '../../../../contexts/ThunderID/useThunderID';\nimport {useForm, FormField} from '../../../../hooks/useForm';\nimport useTranslation from '../../../../hooks/useTranslation';\nimport {cx} from '../../../../styles/emotion';\nimport composeAffixedInputs from '../../../../utils/composeAffixedInputs';\nimport {normalizeFlowResponse, extractErrorMessage} from '../../../../utils/flowTransformer';\nimport getAuthComponentHeadings from '../../../../utils/getAuthComponentHeadings';\nimport {handlePasskeyRegistration} from '../../../../utils/passkey';\nimport AlertPrimitive from '../../../primitives/Alert/Alert';\n// eslint-disable-next-line import/no-named-as-default\nimport CardPrimitive, {CardProps} from '../../../primitives/Card/Card';\nimport Logo from '../../../primitives/Logo/Logo';\nimport Spinner from '../../../primitives/Spinner/Spinner';\nimport Typography from '../../../primitives/Typography/Typography';\nimport {renderSignUpComponents} from '../AuthOptionFactory';\n\nconst logger: ReturnType<typeof createPackageComponentLogger> = createPackageComponentLogger(\n '@thunderid/react',\n 'BaseSignUp',\n);\n\n/**\n * State for tracking passkey registration\n */\ninterface PasskeyState {\n actionId: string | null;\n creationOptions: string | null;\n error: Error | null;\n executionId: string | null;\n isActive: boolean;\n}\n\n/**\n * Render props for custom UI rendering\n */\nexport interface BaseSignUpRenderProps {\n /**\n * Flow components\n */\n components: any[];\n\n /**\n * API error (if any)\n */\n error?: Error | null;\n\n /**\n * Field validation errors\n */\n fieldErrors: Record<string, string>;\n\n /**\n * Function to handle input changes\n */\n handleInputChange: (name: string, value: string) => void;\n\n /**\n * Function to handle form submission\n */\n handleSubmit: (component: any, data?: Record<string, any>) => Promise<void>;\n\n /**\n * Loading state\n */\n isLoading: boolean;\n\n /**\n * Whether the form is valid\n */\n isValid: boolean;\n\n /**\n * Flow messages\n */\n messages: {message: string; type: string}[];\n\n /**\n * Flow subtitle\n */\n subtitle: string;\n\n /**\n * Flow title\n */\n title: string;\n\n /**\n * Touched fields\n */\n touched: Record<string, boolean>;\n\n /**\n * Function to validate the form\n */\n validateForm: () => {fieldErrors: Record<string, string>; isValid: boolean};\n\n /**\n * Form values\n */\n values: Record<string, string>;\n}\n\n/**\n * Props for the BaseSignUp component.\n */\nexport interface BaseSignUpProps {\n /**\n * URL to redirect after successful sign-up.\n */\n afterSignUpUrl?: string;\n\n /**\n * Custom CSS class name for the submit button.\n */\n buttonClassName?: string;\n\n /**\n * Render props function for custom UI\n */\n children?: (props: BaseSignUpRenderProps) => ReactNode;\n\n /**\n * Custom CSS class name for the form container.\n */\n className?: string;\n\n /**\n * Error object to display\n */\n error?: Error | null;\n\n /**\n * Custom CSS class name for error messages.\n */\n errorClassName?: string;\n\n /**\n * HTML id attribute for the form container.\n */\n id?: string;\n\n /**\n * Custom CSS class name for form inputs.\n */\n inputClassName?: string;\n\n isInitialized?: boolean;\n\n /**\n * Custom CSS class name for info messages.\n */\n messageClassName?: string;\n\n /**\n * Callback function called when the sign-up flow completes and requires redirection.\n * This allows platform-specific handling of redirects (e.g., Next.js router.push).\n * @param response - The response from the sign-up flow containing the redirect URL, etc.\n */\n onComplete?: (response: EmbeddedSignUpFlowResponse) => void;\n\n /**\n * Callback function called when sign-up fails.\n * @param error - The error that occurred during sign-up.\n */\n onError?: (error: Error) => void;\n\n /**\n * Callback function called when sign-up flow status changes.\n * @param response - The current sign-up response.\n */\n onFlowChange?: (response: EmbeddedSignUpFlowResponse) => void;\n\n /**\n * Function to initialize sign-up flow.\n * @returns Promise resolving to the initial sign-up response.\n */\n onInitialize?: (payload?: EmbeddedSignUpFlowRequest) => Promise<EmbeddedSignUpFlowResponse>;\n\n /**\n * Function to handle sign-up steps.\n * @param payload - The sign-up payload.\n * @returns Promise resolving to the sign-up response.\n */\n onSubmit?: (payload: EmbeddedSignUpFlowRequest) => Promise<EmbeddedSignUpFlowResponse>;\n /**\n * Component-level preferences to override global i18n and theme settings.\n * Preferences are deep-merged with global ones, with component preferences\n * taking precedence. Affects this component and all its descendants.\n */\n preferences?: Preferences;\n\n /**\n * When a field has been blurred at least once, re-run validation on every subsequent\n * keystroke so a rendered error clears the moment the value becomes valid. Doesn't\n * affect fields that have never been blurred — the user isn't shown errors while\n * initially typing. Default `false` preserves prior behavior.\n */\n revalidateOnChangeAfterBlur?: boolean;\n\n /**\n * Whether to redirect after sign-up.\n */\n shouldRedirectAfterSignUp?: boolean;\n\n /**\n * Whether to show the logo.\n */\n showLogo?: boolean;\n\n /**\n * Whether to show the subtitle.\n */\n showSubtitle?: boolean;\n\n /**\n * Whether to show the title.\n */\n showTitle?: boolean;\n\n /**\n * Size variant for the component.\n */\n size?: 'small' | 'medium' | 'large';\n\n /**\n * Theme variant for the component.\n */\n variant?: CardProps['variant'];\n}\n\n/**\n * Internal component that consumes FlowContext and renders the sign-up UI.\n */\nconst BaseSignUpContent: FC<BaseSignUpProps> = ({\n afterSignUpUrl,\n onInitialize,\n onSubmit,\n onError,\n onFlowChange,\n onComplete,\n error: externalError,\n id,\n className = '',\n inputClassName = '',\n buttonClassName = '',\n errorClassName = '',\n messageClassName = '',\n size = 'medium',\n variant = 'outlined',\n isInitialized,\n children,\n showTitle = true,\n showSubtitle = true,\n revalidateOnChangeAfterBlur = false,\n}: BaseSignUpProps): ReactElement => {\n const {theme, colorScheme} = useTheme();\n const customRenderers: ComponentRendererMap = useContext(ComponentRendererContext);\n const {t} = useTranslation();\n const {subtitle: flowSubtitle, title: flowTitle, messages: flowMessages, addMessage, clearMessages} = useFlow();\n const {meta, isInitialized: isSdkInitialized, getStorageManager, vendor} = useThunderID();\n const styles: any = useStyles(theme, colorScheme);\n\n const [isLoading, setIsLoading] = useState(false);\n const [isFlowInitialized, setIsFlowInitialized] = useState(false);\n const [currentFlow, setCurrentFlow] = useState<EmbeddedSignUpFlowResponse | null>(null);\n const [apiError, setApiError] = useState<Error | null>(null);\n const [isStorageReady, setIsStorageReady] = useState(false);\n const [passkeyState, setPasskeyState] = useState<PasskeyState>({\n actionId: null,\n creationOptions: null,\n error: null,\n executionId: null,\n isActive: false,\n });\n const challengeTokenRef: any = useRef<string | null>(null);\n\n const initializationAttemptedRef: any = useRef(false);\n const passkeyProcessedRef: any = useRef(false);\n // A completed flow leaves its last step rendered while the consumer navigates away, and the\n // redirect is not instantaneous. Latch the completion so the still-visible submit actions cannot\n // fire again: the executionId is spent, and re-submitting would start a whole new sign-up flow.\n const isFlowCompletedRef = useRef(false);\n // Tears down the active popup's listener and poll, so neither outlives the component.\n const cleanupActivePopupRef = useRef<(() => void) | null>(null);\n\n useEffect(() => () => cleanupActivePopupRef.current?.(), []);\n\n /**\n * Restore any challenge token persisted before an OAuth redirect.\n */\n useEffect(() => {\n if (!isSdkInitialized) return;\n\n (async (): Promise<void> => {\n try {\n const storageManager: any = await getStorageManager();\n const tempData: any = await storageManager?.getTemporaryData();\n if (tempData?.challengeToken) {\n challengeTokenRef.current = tempData.challengeToken as string;\n }\n } catch {\n // StorageManager unavailable — continue without persisted token\n } finally {\n setIsStorageReady(true);\n }\n })();\n }, [isSdkInitialized]);\n\n /**\n * Updates challengeTokenRef immediately (stale-closure safe) and persists via\n * the provider's StorageManager so the token survives OAuth redirects.\n */\n const setChallengeToken = async (challengeToken: string | null): Promise<void> => {\n challengeTokenRef.current = challengeToken;\n try {\n const storageManager: any = await getStorageManager();\n if (storageManager) {\n if (challengeToken) {\n await storageManager.setTemporaryDataParameter('challengeToken', challengeToken);\n } else {\n await storageManager.removeTemporaryDataParameter('challengeToken');\n }\n }\n } catch {\n logger.warn('Failed to persist challenge token in storage.');\n }\n };\n\n /**\n * Handle error responses and extract meaningful error messages\n * Uses the transformer's extractErrorMessage function.\n */\n const handleError: any = useCallback(\n (error: any) => {\n const errorMessage: string = extractErrorMessage(error, t);\n\n // Set the API error state\n setApiError(error instanceof Error ? error : new Error(errorMessage));\n\n // Clear existing messages and add the error message\n clearMessages();\n addMessage({\n message: errorMessage,\n type: 'error',\n });\n },\n [t, addMessage, clearMessages],\n );\n\n /**\n * Normalize flow response to ensure component-driven format\n * Uses normalizeFlowResponse for modern API format responses\n */\n const normalizeFlowResponseLocal: any = useCallback(\n (response: EmbeddedSignUpFlowResponse): EmbeddedSignUpFlowResponse => {\n if (response?.data) {\n const {components} = normalizeFlowResponse(\n response,\n t,\n {\n defaultErrorKey: 'components.signUp.errors.generic',\n resolveTranslations: false,\n },\n meta,\n );\n\n return {\n ...response,\n data: {\n ...(response.data as any),\n components,\n },\n } as EmbeddedSignUpFlowResponse;\n }\n\n return response;\n },\n [t, meta],\n );\n\n /**\n * Extract form fields from flow components\n */\n const extractFormFields: any = useCallback(\n (components: any[]): FormField[] => {\n const fields: FormField[] = [];\n\n const processComponents = (comps: any[]): any => {\n comps.forEach((component: any) => {\n if (\n component.type === EmbeddedFlowComponentType.TextInput ||\n component.type === EmbeddedFlowComponentType.PasswordInput ||\n component.type === EmbeddedFlowComponentType.EmailInput ||\n component.type === EmbeddedFlowComponentType.Select ||\n component.type === EmbeddedFlowComponentType.DateInput\n ) {\n // Use component.ref (mapped identifier) as the field name instead of component.id\n // This ensures form field names match what the input components use\n const fieldName: any = component.ref || component.id;\n const ruleValidator = buildValidatorFromRules(component.validation);\n\n fields.push({\n initialValue: '',\n name: fieldName,\n required: component.required || false,\n validator: (value: string) => {\n if (component.required && (!value || value.trim() === '')) {\n return t('validations.required.field.error');\n }\n // Evaluate declarative validation rules from meta.components[].validation.\n if (ruleValidator && value) {\n const ruleMessage = ruleValidator(value);\n if (ruleMessage) {\n return t(ruleMessage);\n }\n }\n // Add email validation if it's an email field\n if (\n (component.type === EmbeddedFlowComponentType.EmailInput || component.variant === 'EMAIL') &&\n value &&\n !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)\n ) {\n return t('field.email.invalid');\n }\n\n return null;\n },\n });\n }\n\n if (component.components && Array.isArray(component.components)) {\n processComponents(component.components);\n }\n });\n };\n\n processComponents(components);\n return fields;\n },\n [t],\n );\n\n const formFields: any = useMemo(\n () => ((currentFlow?.data as any)?.components ? extractFormFields((currentFlow!.data as any).components) : []),\n [currentFlow, extractFormFields],\n );\n\n const form: any = useForm<Record<string, string>>({\n fields: formFields,\n initialValues: {},\n requiredMessage: t('validations.required.field.error'),\n revalidateOnChangeAfterBlur,\n validateOnBlur: true,\n validateOnChange: false,\n });\n\n const {\n values: formValues,\n touched: touchedFields,\n errors: formErrors,\n isValid: isFormValid,\n setValue: setFormValue,\n setTouched: setFormTouched,\n setTouchedFields,\n setErrors: setFormErrors,\n clearErrors: clearFormErrors,\n validateForm,\n touchAllFields,\n reset: resetForm,\n } = form;\n\n // Project server-side fieldErrors from the flow response into form state.\n // `setTouchedFields` avoids re-running client-side validation that would wipe\n // server errors when the client rules happen to pass.\n useEffect(() => {\n clearFormErrors();\n const responseFieldErrors: FieldError[] | undefined = (currentFlow?.data as any)?.fieldErrors;\n if (!responseFieldErrors || responseFieldErrors.length === 0) {\n return;\n }\n const errors: Record<string, string> = {};\n const touched: Record<string, boolean> = {};\n for (const fe of responseFieldErrors) {\n if (!(fe.identifier in errors)) {\n errors[fe.identifier] = fe.message;\n touched[fe.identifier] = true;\n }\n }\n setTouchedFields(touched);\n setFormErrors(errors);\n }, [currentFlow, setFormErrors, setTouchedFields, clearFormErrors]);\n\n /**\n * Setup form fields based on the current flow.\n */\n const setupFormFields: any = useCallback(\n (flowResponse: EmbeddedSignUpFlowResponse) => {\n const fields: any = extractFormFields((flowResponse.data as any)?.components || []);\n const initialValues: Record<string, string> = {};\n\n fields.forEach((field: any) => {\n initialValues[field.name] = field.initialValue || '';\n });\n\n resetForm();\n\n Object.keys(initialValues).forEach((key: any) => {\n setFormValue(key, initialValues[key]);\n });\n },\n [extractFormFields, resetForm, setFormValue],\n );\n\n /**\n * Determine whether a completed flow finished on a display-only screen.\n * Such a completion must be rendered, not redirected past.\n */\n const isDisplayOnlyCompletion = (response: EmbeddedSignUpFlowResponse): boolean => {\n const data: any = response?.data;\n const components: unknown[] | undefined = data?.components ?? data?.meta?.components;\n\n return (\n response?.flowStatus === EmbeddedSignUpFlowStatus.Complete &&\n Array.isArray(components) &&\n components.length > 0 &&\n !(response as {assertion?: string})?.assertion &&\n !data?.redirectURL &&\n !(response as any)?.redirectUrl\n );\n };\n\n /**\n * Handle a completed flow. A flow can complete on a display-only screen; in\n * that case render the screen and skip onComplete so the wrapper does not\n * immediately redirect away from it. Otherwise hand off to onComplete.\n */\n const handleFlowCompletion = (response: EmbeddedSignUpFlowResponse): void => {\n if (isDisplayOnlyCompletion(response)) {\n const normalized: any = normalizeFlowResponseLocal(response);\n setCurrentFlow(normalized);\n setupFormFields(normalized);\n return;\n }\n\n isFlowCompletedRef.current = true;\n onComplete?.(response);\n };\n\n /**\n * Handle input value changes.\n * Only updates the value without marking as touched.\n * Touched state is set on blur to avoid premature validation.\n */\n const handleInputChange = (name: string, value: string): void => {\n setFormValue(name, value);\n };\n\n /**\n * Handle input blur event.\n * Marks the field as touched, which triggers validation.\n */\n const handleInputBlur = (name: string): void => {\n setFormTouched(name, true);\n };\n\n /**\n * Check if the response contains a redirection URL and perform the redirect if necessary.\n * @param response - The sign-up response\n * @param existingPopup - A popup still open from the previous redirect, navigated instead of opening a new one\n * @returns true if a redirect was performed, false otherwise\n */\n const handleRedirectionIfNeeded = (response: EmbeddedSignUpFlowResponse, existingPopup?: Window): boolean => {\n if (response?.type === EmbeddedSignUpFlowType.Redirection && (response?.data as any)?.redirectURL) {\n /**\n * Open a popup window to handle redirection prompts for social sign-up\n */\n const redirectUrl: any = (response.data as any).redirectURL;\n // The reused popup can still deliver the previous round's callback (a late postMessage, or the old callback URL\n // until the new navigation commits), so only a callback carrying this round's state is accepted.\n const expectedState: string | null = new URL(redirectUrl as string).searchParams.get('state');\n const isThisRound = (state: unknown): boolean => !expectedState || state === expectedState;\n // A chained redirect arrives after an async round trip, with no user activation to open a new popup, so the\n // popup from the previous redirect is navigated instead.\n const reusablePopup: Window | null = existingPopup && !existingPopup.closed ? existingPopup : null;\n\n if (reusablePopup) {\n reusablePopup.location.href = redirectUrl;\n }\n\n const popup: Window | null =\n reusablePopup ?? window.open(redirectUrl, 'oauth_popup', 'width=500,height=600,scrollbars=yes,resizable=yes');\n\n if (!popup) {\n logger.error('Failed to open popup window');\n return false;\n }\n\n let hasProcessedCallback: any = false; // Prevent multiple processing\n let popupMonitor: ReturnType<typeof setInterval> | null = null;\n let messageHandler: ((event: MessageEvent) => Promise<void>) | null = null;\n\n /**\n * Clean up event listener and popup monitor\n */\n const cleanup = (): void => {\n if (messageHandler) {\n window.removeEventListener('message', messageHandler);\n }\n if (popupMonitor) {\n clearInterval(popupMonitor);\n }\n };\n cleanupActivePopupRef.current = cleanup;\n\n /**\n * Continue the flow with the provider's callback, then close the popup, unless a chained REDIRECTION\n * (e.g. the account-linking re-authentication) takes it over.\n */\n const continueWithCode = async (code: string, state: string): Promise<void> => {\n const payload: EmbeddedSignUpFlowRequest = {\n ...(currentFlow?.executionId && {executionId: currentFlow.executionId}),\n inputs: {\n code,\n state,\n },\n ...(challengeTokenRef.current ? {challengeToken: challengeTokenRef.current} : {}),\n };\n\n try {\n const continueResponse: any = await onSubmit!(payload);\n cleanup();\n await setChallengeToken(continueResponse.challengeToken ?? null);\n onFlowChange?.(continueResponse);\n\n if (continueResponse.flowStatus === EmbeddedSignUpFlowStatus.Error) {\n handleError(continueResponse);\n onError?.(continueResponse);\n } else if (continueResponse.flowStatus === EmbeddedSignUpFlowStatus.Complete) {\n handleFlowCompletion(continueResponse as EmbeddedSignUpFlowResponse);\n } else if (continueResponse.flowStatus === EmbeddedSignUpFlowStatus.Incomplete) {\n const normalizedContinueResponse: any = normalizeFlowResponseLocal(continueResponse);\n\n // The provider callback can lead straight into another redirect, so follow it in the same popup.\n if (normalizedContinueResponse?.type === EmbeddedSignUpFlowType.Redirection) {\n if (!handleRedirectionIfNeeded(normalizedContinueResponse, popup)) {\n // Keep the current step rather than showing the redirect as a step of its own.\n popup.close();\n const popupError: Error = new Error(t('errors.signup.popup.failure'));\n handleError(popupError);\n onError?.(popupError);\n }\n return;\n }\n\n setCurrentFlow(normalizedContinueResponse);\n setupFormFields(normalizedContinueResponse);\n\n // Display error from INCOMPLETE response\n if (normalizedContinueResponse?.error) {\n handleError(normalizedContinueResponse);\n }\n }\n popup.close();\n } catch (err) {\n handleError(err);\n onError?.(err as Error);\n popup.close();\n cleanup();\n }\n };\n\n /**\n * Add an event listener to the window to capture the message from the popup\n */\n messageHandler = async function messageEventHandler(event: MessageEvent): Promise<void> {\n /**\n * Check if the message is from our popup window\n */\n if (event.source !== popup) {\n return;\n }\n\n /**\n * Check the origin of the message to ensure it's from a trusted source\n */\n const expectedOrigin: any = afterSignUpUrl ? new URL(afterSignUpUrl).origin : window.location.origin;\n if (event.origin !== expectedOrigin && event.origin !== window.location.origin) {\n return;\n }\n\n const {code, state} = event.data;\n\n // The poll may already have picked up this callback.\n if (code && state && isThisRound(state) && !hasProcessedCallback) {\n hasProcessedCallback = true;\n await continueWithCode(code, state);\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n /**\n * Monitor popup for closure and URL changes\n */\n popupMonitor = setInterval(async () => {\n try {\n if (popup.closed) {\n cleanup();\n return;\n }\n\n // Skip if we've already processed a callback\n if (hasProcessedCallback) {\n return;\n }\n\n // Try to access popup URL to check for callback\n try {\n const popupUrl: any = popup.location.href;\n\n // Check if we've been redirected to the callback URL\n if (popupUrl && (popupUrl.includes('code=') || popupUrl.includes('error='))) {\n // Parse the URL for OAuth parameters\n const url: any = new URL(popupUrl);\n const code: any = url.searchParams.get('code');\n const state: any = url.searchParams.get('state');\n const error: any = url.searchParams.get('error');\n\n // Still the previous round's callback page.\n if (!isThisRound(state)) {\n return;\n }\n\n hasProcessedCallback = true; // Set flag to prevent multiple processing\n\n if (error) {\n logger.error('OAuth error:');\n popup.close();\n cleanup();\n return;\n }\n\n if (code && state) {\n await continueWithCode(code, state);\n }\n }\n } catch (e) {\n // Cross-origin error is expected when popup navigates to OAuth provider\n // This is normal and we can ignore it\n }\n } catch (e) {\n logger.error('Error monitoring popup:');\n }\n }, 1000);\n\n return true;\n }\n\n return false;\n };\n\n /**\n * Handle component submission (for buttons outside forms).\n */\n const handleSubmit = async (component: any, data?: Record<string, any>, skipValidation?: boolean): Promise<void> => {\n if (!currentFlow || isFlowCompletedRef.current) {\n return;\n }\n\n // Only validate for form submit actions, skip for social/trigger actions\n if (!skipValidation) {\n // Mark all fields as touched before validation\n touchAllFields();\n\n const validation: ReturnType<typeof validateForm> = validateForm();\n\n if (!validation.isValid) {\n return;\n }\n }\n\n setIsLoading(true);\n setApiError(null);\n clearMessages();\n\n try {\n const composedData: Record<string, any> | undefined = data\n ? composeAffixedInputs(data as Record<string, string>, vendor)\n : undefined;\n\n // Filter out empty or undefined input values\n const filteredInputs: Record<string, any> = {};\n if (composedData) {\n Object.entries(composedData).forEach(([key, value]: [string, any]) => {\n if (value !== null && value !== undefined && value !== '') {\n filteredInputs[key] = value;\n }\n });\n }\n\n const payload: EmbeddedSignUpFlowRequest = {\n ...(currentFlow.executionId && {executionId: currentFlow.executionId}),\n ...(component.id && {action: component.id}),\n ...(challengeTokenRef.current ? {challengeToken: challengeTokenRef.current} : {}),\n inputs: filteredInputs,\n };\n\n const rawResponse: any = await onSubmit!(payload);\n const response: any = normalizeFlowResponseLocal(rawResponse);\n onFlowChange?.(response);\n\n await setChallengeToken(response.challengeToken ?? null);\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Error) {\n handleError(response);\n onError?.(new Error(extractErrorMessage(response, t)));\n return;\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Complete) {\n handleFlowCompletion(response as EmbeddedSignUpFlowResponse);\n return;\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Incomplete) {\n if (handleRedirectionIfNeeded(response)) {\n return;\n }\n\n if (response.data?.additionalData?.passkeyCreationOptions) {\n const {passkeyCreationOptions}: any = response.data.additionalData;\n const effectiveExecutionIdForPasskey: any = response.executionId ?? currentFlow?.executionId;\n\n // Reset passkey processed ref to allow processing\n passkeyProcessedRef.current = false;\n\n // Set passkey state to trigger the passkey\n setPasskeyState({\n actionId: component.id || 'submit',\n creationOptions: passkeyCreationOptions,\n error: null,\n executionId: effectiveExecutionIdForPasskey,\n isActive: true,\n });\n setIsLoading(false);\n return;\n }\n setCurrentFlow(response);\n setupFormFields(response);\n\n // Display error from INCOMPLETE response\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (response?.error) {\n handleError(response);\n }\n }\n } catch (err) {\n handleError(err);\n onError?.(err as Error);\n } finally {\n setIsLoading(false);\n }\n };\n\n /**\n * Handle passkey registration when passkey state becomes active.\n * This effect auto-triggers the browser passkey popup and submits the result.\n */\n useEffect(() => {\n if (!passkeyState.isActive || !passkeyState.creationOptions || !passkeyState.executionId) {\n return;\n }\n\n // Prevent re-processing\n if (passkeyProcessedRef.current) {\n return;\n }\n passkeyProcessedRef.current = true;\n\n const performPasskeyRegistration = async (): Promise<void> => {\n const passkeyResponse: any = await handlePasskeyRegistration(passkeyState.creationOptions!);\n const passkeyResponseObj: any = JSON.parse(passkeyResponse);\n\n const inputs: any = {\n attestationObject: passkeyResponseObj.response.attestationObject,\n clientDataJSON: passkeyResponseObj.response.clientDataJSON,\n credentialId: passkeyResponseObj.id,\n };\n\n // After successful registration, submit the result to the server\n const payload: EmbeddedSignUpFlowRequest = {\n executionId: passkeyState.executionId ?? undefined,\n inputs,\n ...(challengeTokenRef.current ? {challengeToken: challengeTokenRef.current} : {}),\n } as any;\n\n const nextResponse: any = await onSubmit!(payload);\n const processedResponse: any = normalizeFlowResponseLocal(nextResponse);\n onFlowChange?.(processedResponse);\n\n if (processedResponse.flowStatus === EmbeddedSignUpFlowStatus.Complete) {\n handleFlowCompletion(processedResponse as EmbeddedSignUpFlowResponse);\n } else {\n setCurrentFlow(processedResponse);\n setupFormFields(processedResponse);\n }\n };\n\n performPasskeyRegistration()\n .then(() => {\n setPasskeyState({actionId: null, creationOptions: null, error: null, executionId: null, isActive: false});\n })\n .catch((error: any) => {\n setPasskeyState((prev: any) => ({...prev, error: error as Error, isActive: false}));\n handleError(error);\n onError?.(error as Error);\n });\n }, [passkeyState.isActive, passkeyState.creationOptions, passkeyState.executionId]);\n\n const containerClasses: any = cx(\n [\n withVendorCSSClassPrefix('signup'),\n withVendorCSSClassPrefix(`signup--${size}`),\n withVendorCSSClassPrefix(`signup--${variant}`),\n ],\n className,\n );\n\n const inputClasses: any = cx(\n [\n withVendorCSSClassPrefix('signup__input'),\n size === 'small' && withVendorCSSClassPrefix('signup__input--small'),\n size === 'large' && withVendorCSSClassPrefix('signup__input--large'),\n ],\n inputClassName,\n );\n\n const buttonClasses: any = cx(\n [\n withVendorCSSClassPrefix('signup__button'),\n size === 'small' && withVendorCSSClassPrefix('signup__button--small'),\n size === 'large' && withVendorCSSClassPrefix('signup__button--large'),\n ],\n buttonClassName,\n );\n\n const errorClasses: any = cx([withVendorCSSClassPrefix('signup__error')], errorClassName);\n\n const messageClasses: any = cx([withVendorCSSClassPrefix('signup__messages')], messageClassName);\n\n /**\n * Render form components based on flow data using the factory\n */\n const renderComponents: any = useCallback(\n (components: any[]): ReactElement[] =>\n renderSignUpComponents(\n components,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n handleInputChange,\n {\n _customRenderers: customRenderers,\n _theme: theme,\n additionalData: currentFlow?.data?.additionalData,\n buttonClassName: buttonClasses,\n inputClassName: inputClasses,\n meta,\n onInputBlur: handleInputBlur,\n onSubmit: handleSubmit,\n size,\n t,\n variant,\n vendor,\n },\n ),\n [\n currentFlow,\n customRenderers,\n meta,\n t,\n formValues,\n touchedFields,\n formErrors,\n isFormValid,\n isLoading,\n size,\n theme,\n variant,\n vendor,\n inputClasses,\n buttonClasses,\n handleSubmit,\n handleInputBlur,\n ],\n );\n\n /**\n * Parse URL parameters to check for OAuth redirect state.\n */\n const getUrlParams = (): any => {\n const urlParams: any = new URL(window?.location?.href ?? '').searchParams;\n return {\n code: urlParams.get('code'),\n error: urlParams.get('error'),\n state: urlParams.get('state'),\n };\n };\n\n // Initialize the flow on component mount\n useEffect(() => {\n // Skip initialization if we're in an OAuth redirect state.\n const urlParams: any = getUrlParams();\n if (urlParams.code || urlParams.state) {\n return;\n }\n\n if (isInitialized && isStorageReady && !isFlowInitialized && !initializationAttemptedRef.current) {\n initializationAttemptedRef.current = true;\n\n (async (): Promise<void> => {\n setIsLoading(true);\n setApiError(null);\n clearMessages();\n\n try {\n const payload: any = challengeTokenRef.current ? {challengeToken: challengeTokenRef.current} : undefined;\n const rawResponse: any = await onInitialize?.(payload);\n const response: any = normalizeFlowResponseLocal(rawResponse);\n\n await setChallengeToken(response.challengeToken ?? null);\n setCurrentFlow(response);\n setIsFlowInitialized(true);\n onFlowChange?.(response);\n\n // Clean up executionId and applicationId from URL after storing in state\n if (window?.location?.href) {\n const url: URL = new URL(window.location.href);\n url.searchParams.delete('executionId');\n url.searchParams.delete('applicationId');\n window.history.replaceState({}, '', url.toString());\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Error) {\n handleError(response);\n onError?.(new Error(extractErrorMessage(response, t)));\n return;\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Complete) {\n handleFlowCompletion(response as EmbeddedSignUpFlowResponse);\n return;\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Incomplete) {\n setupFormFields(response);\n\n // Display error from INCOMPLETE response\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (response?.error) {\n handleError(response);\n }\n }\n } catch (err) {\n handleError(err);\n onError?.(err as Error);\n } finally {\n setIsLoading(false);\n }\n })();\n }\n }, [\n isInitialized,\n isStorageReady,\n isFlowInitialized,\n onInitialize,\n onComplete,\n onError,\n onFlowChange,\n setupFormFields,\n normalizeFlowResponseLocal,\n afterSignUpUrl,\n t,\n ]);\n\n // If render props are provided, use them\n if (children) {\n const renderProps: BaseSignUpRenderProps = {\n components: (currentFlow?.data as any)?.components || [],\n error: apiError,\n fieldErrors: formErrors,\n handleInputChange,\n handleSubmit,\n isLoading,\n isValid: isFormValid,\n messages: flowMessages || [],\n subtitle: flowSubtitle || t('signup.subheading'),\n title: flowTitle || t('signup.heading'),\n touched: touchedFields,\n validateForm: () => {\n const result: any = validateForm();\n return {fieldErrors: result.errors, isValid: result.isValid};\n },\n values: formValues,\n };\n\n return (\n <div id={id} className={containerClasses}>\n {children(renderProps)}\n </div>\n );\n }\n\n if (!isFlowInitialized && isLoading) {\n return (\n <CardPrimitive id={id} className={cx(containerClasses, styles.card)} variant={variant}>\n <CardPrimitive.Content>\n <div className={styles.loadingContainer}>\n <Spinner size=\"medium\" />\n </div>\n </CardPrimitive.Content>\n </CardPrimitive>\n );\n }\n\n if (!currentFlow) {\n return (\n <CardPrimitive id={id} className={cx(containerClasses, styles.card)} variant={variant}>\n <CardPrimitive.Content>\n <AlertPrimitive variant=\"error\" className={errorClasses}>\n <AlertPrimitive.Title>{t('errors.heading')}</AlertPrimitive.Title>\n <AlertPrimitive.Description>{t('errors.signup.flow.initialization.failure')}</AlertPrimitive.Description>\n </AlertPrimitive>\n </CardPrimitive.Content>\n </CardPrimitive>\n );\n }\n\n // Extract heading and subheading components and filter them from the main components\n const componentsToRender: any = (currentFlow.data as any)?.components || [];\n const {title, subtitle, componentsWithoutHeadings} = getAuthComponentHeadings(\n componentsToRender,\n flowTitle,\n flowSubtitle,\n t('signup.heading'),\n t('signup.subheading'),\n );\n\n return (\n <CardPrimitive id={id} className={cx(containerClasses, styles.card)} variant={variant}>\n {(showTitle || showSubtitle) && (\n <CardPrimitive.Header className={styles.header}>\n {showTitle && (\n <CardPrimitive.Title level={2} className={styles.title}>\n {title}\n </CardPrimitive.Title>\n )}\n {showSubtitle && (\n <Typography variant=\"body1\" className={styles.subtitle}>\n {subtitle}\n </Typography>\n )}\n </CardPrimitive.Header>\n )}\n <CardPrimitive.Content>\n {externalError && (\n <div className={styles.flowMessagesContainer}>\n <AlertPrimitive variant=\"error\" className={cx(styles.flowMessageItem, messageClasses)}>\n <AlertPrimitive.Description>{externalError.message}</AlertPrimitive.Description>\n </AlertPrimitive>\n </div>\n )}\n {flowMessages && flowMessages.length > 0 && (\n <div className={styles.flowMessagesContainer}>\n {flowMessages.map((message: any, index: number) => (\n <AlertPrimitive\n key={message.id || index}\n variant={message.type?.toLowerCase() === 'error' ? 'error' : 'info'}\n className={cx(styles.flowMessageItem, messageClasses)}\n >\n <AlertPrimitive.Description>{message.message}</AlertPrimitive.Description>\n </AlertPrimitive>\n ))}\n </div>\n )}\n <div className={styles.contentContainer}>\n {componentsWithoutHeadings && componentsWithoutHeadings.length > 0 ? (\n renderComponents(componentsWithoutHeadings)\n ) : (\n <AlertPrimitive variant=\"warning\">\n <Typography variant=\"body1\">{t('errors.signup.components.not.available')}</Typography>\n </AlertPrimitive>\n )}\n </div>\n </CardPrimitive.Content>\n </CardPrimitive>\n );\n};\n\n/**\n * BaseSignUp component that provides embedded sign-up flow for ThunderIDV2.\n * This component handles both the presentation layer and sign-up flow logic.\n * It accepts API functions as props to maintain framework independence.\n */\nconst BaseSignUp: FC<BaseSignUpProps> = ({preferences, showLogo = true, ...rest}: BaseSignUpProps): ReactElement => {\n const {theme, colorScheme} = useTheme();\n const styles: any = useStyles(theme, colorScheme);\n\n const content: ReactElement = (\n <div>\n {showLogo && (\n <div className={styles.logoContainer}>\n <Logo size=\"large\" />\n </div>\n )}\n <FlowProvider>\n <BaseSignUpContent showLogo={showLogo} {...rest} />\n </FlowProvider>\n </div>\n );\n\n if (!preferences) return content;\n\n return <ComponentPreferencesContext.Provider value={preferences}>{content}</ComponentPreferencesContext.Provider>;\n};\n\nexport default BaseSignUp;\n"],"mappings":"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"}
1
+ {"version":3,"file":"BaseSignUp.cjs","names":["logger: ReturnType<typeof createPackageComponentLogger>","BaseSignUpContent: FC<BaseSignUpProps>","useTheme","customRenderers: ComponentRendererMap","ComponentRendererContext","useTranslation","useFlow","useThunderID","styles: any","useStyles","challengeTokenRef: any","initializationAttemptedRef: any","passkeyProcessedRef: any","tempData: any","storageManager: any","handleError: any","errorMessage: string","extractErrorMessage","normalizeFlowResponseLocal: any","normalizeFlowResponse","extractFormFields: any","fields: FormField[]","EmbeddedFlowComponentType","fieldName: any","useForm","responseFieldErrors: FieldError[] | undefined","errors: Record<string, string>","touched: Record<string, boolean>","setupFormFields: any","fields: any","initialValues: Record<string, string>","data: any","components: unknown[] | undefined","EmbeddedSignUpFlowStatus","normalized: any","EmbeddedSignUpFlowType","redirectUrl: any","expectedState: string | null","reusablePopup: Window | null","popup: Window | null","hasProcessedCallback: any","popupMonitor: ReturnType<typeof setInterval> | null","messageHandler: ((event: MessageEvent) => Promise<void>) | null","payload: EmbeddedSignUpFlowRequest","continueResponse: any","normalizedContinueResponse: any","popupError: Error","expectedOrigin: any","popupUrl: any","url: any","code: any","state: any","error: any","composedData: Record<string, any> | undefined","composeAffixedInputs","filteredInputs: Record<string, any>","response: any","effectiveExecutionIdForPasskey: any","passkeyResponse: any","handlePasskeyRegistration","passkeyResponseObj: any","inputs: any","processedResponse: any","containerClasses: any","cx","inputClasses: any","buttonClasses: any","errorClasses: any","messageClasses: any","renderComponents: any","renderSignUpComponents","urlParams: any","payload: any","url: URL","result: any","CardPrimitive","Spinner","AlertPrimitive","getAuthComponentHeadings","Typography","BaseSignUp: FC<BaseSignUpProps>","content: ReactElement","Logo","FlowProvider","ComponentPreferencesContext"],"sources":["../../../../../../src/components/presentation/auth/SignUp/BaseSignUp.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n EmbeddedSignUpFlowRequest,\n EmbeddedSignUpFlowResponse,\n EmbeddedSignUpFlowStatus,\n EmbeddedSignUpFlowType,\n withVendorCSSClassPrefix,\n EmbeddedFlowComponentType,\n FieldError,\n createPackageComponentLogger,\n buildValidatorFromRules,\n Preferences,\n} from '@thunderid/browser';\nimport {FC, ReactElement, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';\nimport useStyles from './BaseSignUp.styles';\nimport ComponentRendererContext, {\n ComponentRendererMap,\n} from '../../../../contexts/ComponentRenderer/ComponentRendererContext';\nimport FlowProvider from '../../../../contexts/Flow/FlowProvider';\nimport useFlow from '../../../../contexts/Flow/useFlow';\nimport ComponentPreferencesContext from '../../../../contexts/I18n/ComponentPreferencesContext';\nimport useTheme from '../../../../contexts/Theme/useTheme';\nimport useThunderID from '../../../../contexts/ThunderID/useThunderID';\nimport {useForm, FormField} from '../../../../hooks/useForm';\nimport useTranslation from '../../../../hooks/useTranslation';\nimport {cx} from '../../../../styles/emotion';\nimport composeAffixedInputs from '../../../../utils/composeAffixedInputs';\nimport {normalizeFlowResponse, extractErrorMessage} from '../../../../utils/flowTransformer';\nimport getAuthComponentHeadings from '../../../../utils/getAuthComponentHeadings';\nimport {handlePasskeyRegistration} from '../../../../utils/passkey';\nimport AlertPrimitive from '../../../primitives/Alert/Alert';\n// eslint-disable-next-line import/no-named-as-default\nimport CardPrimitive, {CardProps} from '../../../primitives/Card/Card';\nimport Logo from '../../../primitives/Logo/Logo';\nimport Spinner from '../../../primitives/Spinner/Spinner';\nimport Typography from '../../../primitives/Typography/Typography';\nimport {renderSignUpComponents} from '../AuthOptionFactory';\n\nconst logger: ReturnType<typeof createPackageComponentLogger> = createPackageComponentLogger(\n '@thunderid/react',\n 'BaseSignUp',\n);\n\n/**\n * State for tracking passkey registration\n */\ninterface PasskeyState {\n actionId: string | null;\n creationOptions: string | null;\n error: Error | null;\n executionId: string | null;\n isActive: boolean;\n}\n\n/**\n * Render props for custom UI rendering\n */\nexport interface BaseSignUpRenderProps {\n /**\n * Additional data from the current flow step (e.g. `source` lookups for `KEY_VALUE_LIST`)\n */\n additionalData: Record<string, unknown>;\n\n /**\n * Flow components\n */\n components: any[];\n\n /**\n * API error (if any)\n */\n error?: Error | null;\n\n /**\n * Field validation errors\n */\n fieldErrors: Record<string, string>;\n\n /**\n * Function to handle input changes\n */\n handleInputChange: (name: string, value: string) => void;\n\n /**\n * Function to handle form submission\n */\n handleSubmit: (component: any, data?: Record<string, any>) => Promise<void>;\n\n /**\n * Loading state\n */\n isLoading: boolean;\n\n /**\n * Whether the form is valid\n */\n isValid: boolean;\n\n /**\n * Flow messages\n */\n messages: {message: string; type: string}[];\n\n /**\n * Flow subtitle\n */\n subtitle: string;\n\n /**\n * Flow title\n */\n title: string;\n\n /**\n * Touched fields\n */\n touched: Record<string, boolean>;\n\n /**\n * Function to validate the form\n */\n validateForm: () => {fieldErrors: Record<string, string>; isValid: boolean};\n\n /**\n * Form values\n */\n values: Record<string, string>;\n}\n\n/**\n * Props for the BaseSignUp component.\n */\nexport interface BaseSignUpProps {\n /**\n * URL to redirect after successful sign-up.\n */\n afterSignUpUrl?: string;\n\n /**\n * Custom CSS class name for the submit button.\n */\n buttonClassName?: string;\n\n /**\n * Render props function for custom UI\n */\n children?: (props: BaseSignUpRenderProps) => ReactNode;\n\n /**\n * Custom CSS class name for the form container.\n */\n className?: string;\n\n /**\n * Error object to display\n */\n error?: Error | null;\n\n /**\n * Custom CSS class name for error messages.\n */\n errorClassName?: string;\n\n /**\n * HTML id attribute for the form container.\n */\n id?: string;\n\n /**\n * Custom CSS class name for form inputs.\n */\n inputClassName?: string;\n\n isInitialized?: boolean;\n\n /**\n * Custom CSS class name for info messages.\n */\n messageClassName?: string;\n\n /**\n * Callback function called when the sign-up flow completes and requires redirection.\n * This allows platform-specific handling of redirects (e.g., Next.js router.push).\n * @param response - The response from the sign-up flow containing the redirect URL, etc.\n */\n onComplete?: (response: EmbeddedSignUpFlowResponse) => void;\n\n /**\n * Callback function called when sign-up fails.\n * @param error - The error that occurred during sign-up.\n */\n onError?: (error: Error) => void;\n\n /**\n * Callback function called when sign-up flow status changes.\n * @param response - The current sign-up response.\n */\n onFlowChange?: (response: EmbeddedSignUpFlowResponse) => void;\n\n /**\n * Function to initialize sign-up flow.\n * @returns Promise resolving to the initial sign-up response.\n */\n onInitialize?: (payload?: EmbeddedSignUpFlowRequest) => Promise<EmbeddedSignUpFlowResponse>;\n\n /**\n * Function to handle sign-up steps.\n * @param payload - The sign-up payload.\n * @returns Promise resolving to the sign-up response.\n */\n onSubmit?: (payload: EmbeddedSignUpFlowRequest) => Promise<EmbeddedSignUpFlowResponse>;\n /**\n * Component-level preferences to override global i18n and theme settings.\n * Preferences are deep-merged with global ones, with component preferences\n * taking precedence. Affects this component and all its descendants.\n */\n preferences?: Preferences;\n\n /**\n * When a field has been blurred at least once, re-run validation on every subsequent\n * keystroke so a rendered error clears the moment the value becomes valid. Doesn't\n * affect fields that have never been blurred — the user isn't shown errors while\n * initially typing. Default `false` preserves prior behavior.\n */\n revalidateOnChangeAfterBlur?: boolean;\n\n /**\n * Whether to redirect after sign-up.\n */\n shouldRedirectAfterSignUp?: boolean;\n\n /**\n * Whether to show the logo.\n */\n showLogo?: boolean;\n\n /**\n * Whether to show the subtitle.\n */\n showSubtitle?: boolean;\n\n /**\n * Whether to show the title.\n */\n showTitle?: boolean;\n\n /**\n * Size variant for the component.\n */\n size?: 'small' | 'medium' | 'large';\n\n /**\n * Theme variant for the component.\n */\n variant?: CardProps['variant'];\n}\n\n/**\n * Internal component that consumes FlowContext and renders the sign-up UI.\n */\nconst BaseSignUpContent: FC<BaseSignUpProps> = ({\n afterSignUpUrl,\n onInitialize,\n onSubmit,\n onError,\n onFlowChange,\n onComplete,\n error: externalError,\n id,\n className = '',\n inputClassName = '',\n buttonClassName = '',\n errorClassName = '',\n messageClassName = '',\n size = 'medium',\n variant = 'outlined',\n isInitialized,\n children,\n showTitle = true,\n showSubtitle = true,\n revalidateOnChangeAfterBlur = false,\n}: BaseSignUpProps): ReactElement => {\n const {theme, colorScheme} = useTheme();\n const customRenderers: ComponentRendererMap = useContext(ComponentRendererContext);\n const {t} = useTranslation();\n const {subtitle: flowSubtitle, title: flowTitle, messages: flowMessages, addMessage, clearMessages} = useFlow();\n const {meta, isInitialized: isSdkInitialized, getStorageManager, vendor} = useThunderID();\n const styles: any = useStyles(theme, colorScheme);\n\n const [isLoading, setIsLoading] = useState(false);\n const [isFlowInitialized, setIsFlowInitialized] = useState(false);\n const [currentFlow, setCurrentFlow] = useState<EmbeddedSignUpFlowResponse | null>(null);\n const [apiError, setApiError] = useState<Error | null>(null);\n const [isStorageReady, setIsStorageReady] = useState(false);\n const [passkeyState, setPasskeyState] = useState<PasskeyState>({\n actionId: null,\n creationOptions: null,\n error: null,\n executionId: null,\n isActive: false,\n });\n const challengeTokenRef: any = useRef<string | null>(null);\n\n const initializationAttemptedRef: any = useRef(false);\n const passkeyProcessedRef: any = useRef(false);\n // A completed flow leaves its last step rendered while the consumer navigates away, and the\n // redirect is not instantaneous. Latch the completion so the still-visible submit actions cannot\n // fire again: the executionId is spent, and re-submitting would start a whole new sign-up flow.\n const isFlowCompletedRef = useRef(false);\n // Tears down the active popup's listener and poll, so neither outlives the component.\n const cleanupActivePopupRef = useRef<(() => void) | null>(null);\n\n useEffect(() => () => cleanupActivePopupRef.current?.(), []);\n\n /**\n * Restore any challenge token persisted before an OAuth redirect.\n */\n useEffect(() => {\n if (!isSdkInitialized) return;\n\n (async (): Promise<void> => {\n try {\n const storageManager: any = await getStorageManager();\n const tempData: any = await storageManager?.getTemporaryData();\n if (tempData?.challengeToken) {\n challengeTokenRef.current = tempData.challengeToken as string;\n }\n } catch {\n // StorageManager unavailable — continue without persisted token\n } finally {\n setIsStorageReady(true);\n }\n })();\n }, [isSdkInitialized]);\n\n /**\n * Updates challengeTokenRef immediately (stale-closure safe) and persists via\n * the provider's StorageManager so the token survives OAuth redirects.\n */\n const setChallengeToken = async (challengeToken: string | null): Promise<void> => {\n challengeTokenRef.current = challengeToken;\n try {\n const storageManager: any = await getStorageManager();\n if (storageManager) {\n if (challengeToken) {\n await storageManager.setTemporaryDataParameter('challengeToken', challengeToken);\n } else {\n await storageManager.removeTemporaryDataParameter('challengeToken');\n }\n }\n } catch {\n logger.warn('Failed to persist challenge token in storage.');\n }\n };\n\n /**\n * Handle error responses and extract meaningful error messages\n * Uses the transformer's extractErrorMessage function.\n */\n const handleError: any = useCallback(\n (error: any) => {\n const errorMessage: string = extractErrorMessage(error, t);\n\n // Set the API error state\n setApiError(error instanceof Error ? error : new Error(errorMessage));\n\n // Clear existing messages and add the error message\n clearMessages();\n addMessage({\n message: errorMessage,\n type: 'error',\n });\n },\n [t, addMessage, clearMessages],\n );\n\n /**\n * Normalize flow response to ensure component-driven format\n * Uses normalizeFlowResponse for modern API format responses\n */\n const normalizeFlowResponseLocal: any = useCallback(\n (response: EmbeddedSignUpFlowResponse): EmbeddedSignUpFlowResponse => {\n if (response?.data) {\n const {components} = normalizeFlowResponse(\n response,\n t,\n {\n defaultErrorKey: 'components.signUp.errors.generic',\n resolveTranslations: false,\n },\n meta,\n );\n\n return {\n ...response,\n data: {\n ...(response.data as any),\n components,\n },\n } as EmbeddedSignUpFlowResponse;\n }\n\n return response;\n },\n [t, meta],\n );\n\n /**\n * Extract form fields from flow components\n */\n const extractFormFields: any = useCallback(\n (components: any[]): FormField[] => {\n const fields: FormField[] = [];\n\n const processComponents = (comps: any[]): any => {\n comps.forEach((component: any) => {\n if (\n component.type === EmbeddedFlowComponentType.TextInput ||\n component.type === EmbeddedFlowComponentType.PasswordInput ||\n component.type === EmbeddedFlowComponentType.EmailInput ||\n component.type === EmbeddedFlowComponentType.Select ||\n component.type === EmbeddedFlowComponentType.DateInput\n ) {\n // Use component.ref (mapped identifier) as the field name instead of component.id\n // This ensures form field names match what the input components use\n const fieldName: any = component.ref || component.id;\n const ruleValidator = buildValidatorFromRules(component.validation);\n\n fields.push({\n initialValue: '',\n name: fieldName,\n required: component.required || false,\n validator: (value: string) => {\n if (component.required && (!value || value.trim() === '')) {\n return t('validations.required.field.error');\n }\n // Evaluate declarative validation rules from meta.components[].validation.\n if (ruleValidator && value) {\n const ruleMessage = ruleValidator(value);\n if (ruleMessage) {\n return t(ruleMessage);\n }\n }\n // Add email validation if it's an email field\n if (\n (component.type === EmbeddedFlowComponentType.EmailInput || component.variant === 'EMAIL') &&\n value &&\n !/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)\n ) {\n return t('field.email.invalid');\n }\n\n return null;\n },\n });\n }\n\n if (component.components && Array.isArray(component.components)) {\n processComponents(component.components);\n }\n });\n };\n\n processComponents(components);\n return fields;\n },\n [t],\n );\n\n const formFields: any = useMemo(\n () => ((currentFlow?.data as any)?.components ? extractFormFields((currentFlow!.data as any).components) : []),\n [currentFlow, extractFormFields],\n );\n\n const form: any = useForm<Record<string, string>>({\n fields: formFields,\n initialValues: {},\n requiredMessage: t('validations.required.field.error'),\n revalidateOnChangeAfterBlur,\n validateOnBlur: true,\n validateOnChange: false,\n });\n\n const {\n values: formValues,\n touched: touchedFields,\n errors: formErrors,\n isValid: isFormValid,\n setValue: setFormValue,\n setTouched: setFormTouched,\n setTouchedFields,\n setErrors: setFormErrors,\n clearErrors: clearFormErrors,\n validateForm,\n touchAllFields,\n reset: resetForm,\n } = form;\n\n // Project server-side fieldErrors from the flow response into form state.\n // `setTouchedFields` avoids re-running client-side validation that would wipe\n // server errors when the client rules happen to pass.\n useEffect(() => {\n clearFormErrors();\n const responseFieldErrors: FieldError[] | undefined = (currentFlow?.data as any)?.fieldErrors;\n if (!responseFieldErrors || responseFieldErrors.length === 0) {\n return;\n }\n const errors: Record<string, string> = {};\n const touched: Record<string, boolean> = {};\n for (const fe of responseFieldErrors) {\n if (!(fe.identifier in errors)) {\n errors[fe.identifier] = fe.message;\n touched[fe.identifier] = true;\n }\n }\n setTouchedFields(touched);\n setFormErrors(errors);\n }, [currentFlow, setFormErrors, setTouchedFields, clearFormErrors]);\n\n /**\n * Setup form fields based on the current flow.\n */\n const setupFormFields: any = useCallback(\n (flowResponse: EmbeddedSignUpFlowResponse) => {\n const fields: any = extractFormFields((flowResponse.data as any)?.components || []);\n const initialValues: Record<string, string> = {};\n\n fields.forEach((field: any) => {\n initialValues[field.name] = field.initialValue || '';\n });\n\n resetForm();\n\n Object.keys(initialValues).forEach((key: any) => {\n setFormValue(key, initialValues[key]);\n });\n },\n [extractFormFields, resetForm, setFormValue],\n );\n\n /**\n * Determine whether a completed flow finished on a display-only screen.\n * Such a completion must be rendered, not redirected past.\n */\n const isDisplayOnlyCompletion = (response: EmbeddedSignUpFlowResponse): boolean => {\n const data: any = response?.data;\n const components: unknown[] | undefined = data?.components ?? data?.meta?.components;\n\n return (\n response?.flowStatus === EmbeddedSignUpFlowStatus.Complete &&\n Array.isArray(components) &&\n components.length > 0 &&\n !(response as {assertion?: string})?.assertion &&\n !data?.redirectURL &&\n !(response as any)?.redirectUrl\n );\n };\n\n /**\n * Handle a completed flow. A flow can complete on a display-only screen; in\n * that case render the screen and skip onComplete so the wrapper does not\n * immediately redirect away from it. Otherwise hand off to onComplete.\n */\n const handleFlowCompletion = (response: EmbeddedSignUpFlowResponse): void => {\n if (isDisplayOnlyCompletion(response)) {\n const normalized: any = normalizeFlowResponseLocal(response);\n setCurrentFlow(normalized);\n setupFormFields(normalized);\n return;\n }\n\n isFlowCompletedRef.current = true;\n onComplete?.(response);\n };\n\n /**\n * Handle input value changes.\n * Only updates the value without marking as touched.\n * Touched state is set on blur to avoid premature validation.\n */\n const handleInputChange = (name: string, value: string): void => {\n setFormValue(name, value);\n };\n\n /**\n * Handle input blur event.\n * Marks the field as touched, which triggers validation.\n */\n const handleInputBlur = (name: string): void => {\n setFormTouched(name, true);\n };\n\n /**\n * Check if the response contains a redirection URL and perform the redirect if necessary.\n * @param response - The sign-up response\n * @param existingPopup - A popup still open from the previous redirect, navigated instead of opening a new one\n * @returns true if a redirect was performed, false otherwise\n */\n const handleRedirectionIfNeeded = (response: EmbeddedSignUpFlowResponse, existingPopup?: Window): boolean => {\n if (response?.type === EmbeddedSignUpFlowType.Redirection && (response?.data as any)?.redirectURL) {\n /**\n * Open a popup window to handle redirection prompts for social sign-up\n */\n const redirectUrl: any = (response.data as any).redirectURL;\n // The reused popup can still deliver the previous round's callback (a late postMessage, or the old callback URL\n // until the new navigation commits), so only a callback carrying this round's state is accepted.\n const expectedState: string | null = new URL(redirectUrl as string).searchParams.get('state');\n const isThisRound = (state: unknown): boolean => !expectedState || state === expectedState;\n // A chained redirect arrives after an async round trip, with no user activation to open a new popup, so the\n // popup from the previous redirect is navigated instead.\n const reusablePopup: Window | null = existingPopup && !existingPopup.closed ? existingPopup : null;\n\n if (reusablePopup) {\n reusablePopup.location.href = redirectUrl;\n }\n\n const popup: Window | null =\n reusablePopup ?? window.open(redirectUrl, 'oauth_popup', 'width=500,height=600,scrollbars=yes,resizable=yes');\n\n if (!popup) {\n logger.error('Failed to open popup window');\n return false;\n }\n\n let hasProcessedCallback: any = false; // Prevent multiple processing\n let popupMonitor: ReturnType<typeof setInterval> | null = null;\n let messageHandler: ((event: MessageEvent) => Promise<void>) | null = null;\n\n /**\n * Clean up event listener and popup monitor\n */\n const cleanup = (): void => {\n if (messageHandler) {\n window.removeEventListener('message', messageHandler);\n }\n if (popupMonitor) {\n clearInterval(popupMonitor);\n }\n };\n cleanupActivePopupRef.current = cleanup;\n\n /**\n * Continue the flow with the provider's callback, then close the popup, unless a chained REDIRECTION\n * (e.g. the account-linking re-authentication) takes it over.\n */\n const continueWithCode = async (code: string, state: string): Promise<void> => {\n const payload: EmbeddedSignUpFlowRequest = {\n ...(currentFlow?.executionId && {executionId: currentFlow.executionId}),\n inputs: {\n code,\n state,\n },\n ...(challengeTokenRef.current ? {challengeToken: challengeTokenRef.current} : {}),\n };\n\n try {\n const continueResponse: any = await onSubmit!(payload);\n cleanup();\n await setChallengeToken(continueResponse.challengeToken ?? null);\n onFlowChange?.(continueResponse);\n\n if (continueResponse.flowStatus === EmbeddedSignUpFlowStatus.Error) {\n handleError(continueResponse);\n onError?.(continueResponse);\n } else if (continueResponse.flowStatus === EmbeddedSignUpFlowStatus.Complete) {\n handleFlowCompletion(continueResponse as EmbeddedSignUpFlowResponse);\n } else if (continueResponse.flowStatus === EmbeddedSignUpFlowStatus.Incomplete) {\n const normalizedContinueResponse: any = normalizeFlowResponseLocal(continueResponse);\n\n // The provider callback can lead straight into another redirect, so follow it in the same popup.\n if (normalizedContinueResponse?.type === EmbeddedSignUpFlowType.Redirection) {\n if (!handleRedirectionIfNeeded(normalizedContinueResponse, popup)) {\n // Keep the current step rather than showing the redirect as a step of its own.\n popup.close();\n const popupError: Error = new Error(t('errors.signup.popup.failure'));\n handleError(popupError);\n onError?.(popupError);\n }\n return;\n }\n\n setCurrentFlow(normalizedContinueResponse);\n setupFormFields(normalizedContinueResponse);\n\n // Display error from INCOMPLETE response\n if (normalizedContinueResponse?.error) {\n handleError(normalizedContinueResponse);\n }\n }\n popup.close();\n } catch (err) {\n handleError(err);\n onError?.(err as Error);\n popup.close();\n cleanup();\n }\n };\n\n /**\n * Add an event listener to the window to capture the message from the popup\n */\n messageHandler = async function messageEventHandler(event: MessageEvent): Promise<void> {\n /**\n * Check if the message is from our popup window\n */\n if (event.source !== popup) {\n return;\n }\n\n /**\n * Check the origin of the message to ensure it's from a trusted source\n */\n const expectedOrigin: any = afterSignUpUrl ? new URL(afterSignUpUrl).origin : window.location.origin;\n if (event.origin !== expectedOrigin && event.origin !== window.location.origin) {\n return;\n }\n\n const {code, state} = event.data;\n\n // The poll may already have picked up this callback.\n if (code && state && isThisRound(state) && !hasProcessedCallback) {\n hasProcessedCallback = true;\n await continueWithCode(code, state);\n }\n };\n\n window.addEventListener('message', messageHandler);\n\n /**\n * Monitor popup for closure and URL changes\n */\n popupMonitor = setInterval(async () => {\n try {\n if (popup.closed) {\n cleanup();\n return;\n }\n\n // Skip if we've already processed a callback\n if (hasProcessedCallback) {\n return;\n }\n\n // Try to access popup URL to check for callback\n try {\n const popupUrl: any = popup.location.href;\n\n // Check if we've been redirected to the callback URL\n if (popupUrl && (popupUrl.includes('code=') || popupUrl.includes('error='))) {\n // Parse the URL for OAuth parameters\n const url: any = new URL(popupUrl);\n const code: any = url.searchParams.get('code');\n const state: any = url.searchParams.get('state');\n const error: any = url.searchParams.get('error');\n\n // Still the previous round's callback page.\n if (!isThisRound(state)) {\n return;\n }\n\n hasProcessedCallback = true; // Set flag to prevent multiple processing\n\n if (error) {\n logger.error('OAuth error:');\n popup.close();\n cleanup();\n return;\n }\n\n if (code && state) {\n await continueWithCode(code, state);\n }\n }\n } catch (e) {\n // Cross-origin error is expected when popup navigates to OAuth provider\n // This is normal and we can ignore it\n }\n } catch (e) {\n logger.error('Error monitoring popup:');\n }\n }, 1000);\n\n return true;\n }\n\n return false;\n };\n\n /**\n * Handle component submission (for buttons outside forms).\n */\n const handleSubmit = async (component: any, data?: Record<string, any>, skipValidation?: boolean): Promise<void> => {\n if (!currentFlow || isFlowCompletedRef.current) {\n return;\n }\n\n // Only validate for form submit actions, skip for social/trigger actions\n if (!skipValidation) {\n // Mark all fields as touched before validation\n touchAllFields();\n\n const validation: ReturnType<typeof validateForm> = validateForm();\n\n if (!validation.isValid) {\n return;\n }\n }\n\n setIsLoading(true);\n setApiError(null);\n clearMessages();\n\n try {\n const composedData: Record<string, any> | undefined = data\n ? composeAffixedInputs(data as Record<string, string>, vendor)\n : undefined;\n\n // Filter out empty or undefined input values\n const filteredInputs: Record<string, any> = {};\n if (composedData) {\n Object.entries(composedData).forEach(([key, value]: [string, any]) => {\n if (value !== null && value !== undefined && value !== '') {\n filteredInputs[key] = value;\n }\n });\n }\n\n const payload: EmbeddedSignUpFlowRequest = {\n ...(currentFlow.executionId && {executionId: currentFlow.executionId}),\n ...(component.id && {action: component.id}),\n ...(challengeTokenRef.current ? {challengeToken: challengeTokenRef.current} : {}),\n inputs: filteredInputs,\n };\n\n const rawResponse: any = await onSubmit!(payload);\n const response: any = normalizeFlowResponseLocal(rawResponse);\n onFlowChange?.(response);\n\n await setChallengeToken(response.challengeToken ?? null);\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Error) {\n handleError(response);\n onError?.(new Error(extractErrorMessage(response, t)));\n return;\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Complete) {\n handleFlowCompletion(response as EmbeddedSignUpFlowResponse);\n return;\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Incomplete) {\n if (handleRedirectionIfNeeded(response)) {\n return;\n }\n\n if (response.data?.additionalData?.passkeyCreationOptions) {\n const {passkeyCreationOptions}: any = response.data.additionalData;\n const effectiveExecutionIdForPasskey: any = response.executionId ?? currentFlow?.executionId;\n\n // Reset passkey processed ref to allow processing\n passkeyProcessedRef.current = false;\n\n // Set passkey state to trigger the passkey\n setPasskeyState({\n actionId: component.id || 'submit',\n creationOptions: passkeyCreationOptions,\n error: null,\n executionId: effectiveExecutionIdForPasskey,\n isActive: true,\n });\n setIsLoading(false);\n return;\n }\n setCurrentFlow(response);\n setupFormFields(response);\n\n // Display error from INCOMPLETE response\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (response?.error) {\n handleError(response);\n }\n }\n } catch (err) {\n handleError(err);\n onError?.(err as Error);\n } finally {\n setIsLoading(false);\n }\n };\n\n /**\n * Handle passkey registration when passkey state becomes active.\n * This effect auto-triggers the browser passkey popup and submits the result.\n */\n useEffect(() => {\n if (!passkeyState.isActive || !passkeyState.creationOptions || !passkeyState.executionId) {\n return;\n }\n\n // Prevent re-processing\n if (passkeyProcessedRef.current) {\n return;\n }\n passkeyProcessedRef.current = true;\n\n const performPasskeyRegistration = async (): Promise<void> => {\n const passkeyResponse: any = await handlePasskeyRegistration(passkeyState.creationOptions!);\n const passkeyResponseObj: any = JSON.parse(passkeyResponse);\n\n const inputs: any = {\n attestationObject: passkeyResponseObj.response.attestationObject,\n clientDataJSON: passkeyResponseObj.response.clientDataJSON,\n credentialId: passkeyResponseObj.id,\n };\n\n // After successful registration, submit the result to the server\n const payload: EmbeddedSignUpFlowRequest = {\n executionId: passkeyState.executionId ?? undefined,\n inputs,\n ...(challengeTokenRef.current ? {challengeToken: challengeTokenRef.current} : {}),\n } as any;\n\n const nextResponse: any = await onSubmit!(payload);\n const processedResponse: any = normalizeFlowResponseLocal(nextResponse);\n onFlowChange?.(processedResponse);\n\n if (processedResponse.flowStatus === EmbeddedSignUpFlowStatus.Complete) {\n handleFlowCompletion(processedResponse as EmbeddedSignUpFlowResponse);\n } else {\n setCurrentFlow(processedResponse);\n setupFormFields(processedResponse);\n }\n };\n\n performPasskeyRegistration()\n .then(() => {\n setPasskeyState({actionId: null, creationOptions: null, error: null, executionId: null, isActive: false});\n })\n .catch((error: any) => {\n setPasskeyState((prev: any) => ({...prev, error: error as Error, isActive: false}));\n handleError(error);\n onError?.(error as Error);\n });\n }, [passkeyState.isActive, passkeyState.creationOptions, passkeyState.executionId]);\n\n const containerClasses: any = cx(\n [\n withVendorCSSClassPrefix('signup'),\n withVendorCSSClassPrefix(`signup--${size}`),\n withVendorCSSClassPrefix(`signup--${variant}`),\n ],\n className,\n );\n\n const inputClasses: any = cx(\n [\n withVendorCSSClassPrefix('signup__input'),\n size === 'small' && withVendorCSSClassPrefix('signup__input--small'),\n size === 'large' && withVendorCSSClassPrefix('signup__input--large'),\n ],\n inputClassName,\n );\n\n const buttonClasses: any = cx(\n [\n withVendorCSSClassPrefix('signup__button'),\n size === 'small' && withVendorCSSClassPrefix('signup__button--small'),\n size === 'large' && withVendorCSSClassPrefix('signup__button--large'),\n ],\n buttonClassName,\n );\n\n const errorClasses: any = cx([withVendorCSSClassPrefix('signup__error')], errorClassName);\n\n const messageClasses: any = cx([withVendorCSSClassPrefix('signup__messages')], messageClassName);\n\n /**\n * Render form components based on flow data using the factory\n */\n const renderComponents: any = useCallback(\n (components: any[]): ReactElement[] =>\n renderSignUpComponents(\n components,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n handleInputChange,\n {\n _customRenderers: customRenderers,\n _theme: theme,\n additionalData: currentFlow?.data?.additionalData,\n buttonClassName: buttonClasses,\n inputClassName: inputClasses,\n meta,\n onInputBlur: handleInputBlur,\n onSubmit: handleSubmit,\n size,\n t,\n variant,\n vendor,\n },\n ),\n [\n currentFlow,\n customRenderers,\n meta,\n t,\n formValues,\n touchedFields,\n formErrors,\n isFormValid,\n isLoading,\n size,\n theme,\n variant,\n vendor,\n inputClasses,\n buttonClasses,\n handleSubmit,\n handleInputBlur,\n ],\n );\n\n /**\n * Parse URL parameters to check for OAuth redirect state.\n */\n const getUrlParams = (): any => {\n const urlParams: any = new URL(window?.location?.href ?? '').searchParams;\n return {\n code: urlParams.get('code'),\n error: urlParams.get('error'),\n state: urlParams.get('state'),\n };\n };\n\n // Initialize the flow on component mount\n useEffect(() => {\n // Skip initialization if we're in an OAuth redirect state.\n const urlParams: any = getUrlParams();\n if (urlParams.code || urlParams.state) {\n return;\n }\n\n if (isInitialized && isStorageReady && !isFlowInitialized && !initializationAttemptedRef.current) {\n initializationAttemptedRef.current = true;\n\n (async (): Promise<void> => {\n setIsLoading(true);\n setApiError(null);\n clearMessages();\n\n try {\n const payload: any = challengeTokenRef.current ? {challengeToken: challengeTokenRef.current} : undefined;\n const rawResponse: any = await onInitialize?.(payload);\n const response: any = normalizeFlowResponseLocal(rawResponse);\n\n await setChallengeToken(response.challengeToken ?? null);\n setCurrentFlow(response);\n setIsFlowInitialized(true);\n onFlowChange?.(response);\n\n // Clean up executionId and applicationId from URL after storing in state\n if (window?.location?.href) {\n const url: URL = new URL(window.location.href);\n url.searchParams.delete('executionId');\n url.searchParams.delete('applicationId');\n window.history.replaceState({}, '', url.toString());\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Error) {\n handleError(response);\n onError?.(new Error(extractErrorMessage(response, t)));\n return;\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Complete) {\n handleFlowCompletion(response as EmbeddedSignUpFlowResponse);\n return;\n }\n\n if (response.flowStatus === EmbeddedSignUpFlowStatus.Incomplete) {\n setupFormFields(response);\n\n // Display error from INCOMPLETE response\n // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n if (response?.error) {\n handleError(response);\n }\n }\n } catch (err) {\n handleError(err);\n onError?.(err as Error);\n } finally {\n setIsLoading(false);\n }\n })();\n }\n }, [\n isInitialized,\n isStorageReady,\n isFlowInitialized,\n onInitialize,\n onComplete,\n onError,\n onFlowChange,\n setupFormFields,\n normalizeFlowResponseLocal,\n afterSignUpUrl,\n t,\n ]);\n\n // If render props are provided, use them\n if (children) {\n const renderProps: BaseSignUpRenderProps = {\n additionalData: currentFlow?.data?.additionalData ?? {},\n components: (currentFlow?.data as any)?.components || [],\n error: apiError,\n fieldErrors: formErrors,\n handleInputChange,\n handleSubmit,\n isLoading,\n isValid: isFormValid,\n messages: flowMessages || [],\n subtitle: flowSubtitle || t('signup.subheading'),\n title: flowTitle || t('signup.heading'),\n touched: touchedFields,\n validateForm: () => {\n const result: any = validateForm();\n return {fieldErrors: result.errors, isValid: result.isValid};\n },\n values: formValues,\n };\n\n return (\n <div id={id} className={containerClasses}>\n {children(renderProps)}\n </div>\n );\n }\n\n if (!isFlowInitialized && isLoading) {\n return (\n <CardPrimitive id={id} className={cx(containerClasses, styles.card)} variant={variant}>\n <CardPrimitive.Content>\n <div className={styles.loadingContainer}>\n <Spinner size=\"medium\" />\n </div>\n </CardPrimitive.Content>\n </CardPrimitive>\n );\n }\n\n if (!currentFlow) {\n return (\n <CardPrimitive id={id} className={cx(containerClasses, styles.card)} variant={variant}>\n <CardPrimitive.Content>\n <AlertPrimitive variant=\"error\" className={errorClasses}>\n <AlertPrimitive.Title>{t('errors.heading')}</AlertPrimitive.Title>\n <AlertPrimitive.Description>{t('errors.signup.flow.initialization.failure')}</AlertPrimitive.Description>\n </AlertPrimitive>\n </CardPrimitive.Content>\n </CardPrimitive>\n );\n }\n\n // Extract heading and subheading components and filter them from the main components\n const componentsToRender: any = (currentFlow.data as any)?.components || [];\n const {title, subtitle, componentsWithoutHeadings} = getAuthComponentHeadings(\n componentsToRender,\n flowTitle,\n flowSubtitle,\n t('signup.heading'),\n t('signup.subheading'),\n );\n\n return (\n <CardPrimitive id={id} className={cx(containerClasses, styles.card)} variant={variant}>\n {(showTitle || showSubtitle) && (\n <CardPrimitive.Header className={styles.header}>\n {showTitle && (\n <CardPrimitive.Title level={2} className={styles.title}>\n {title}\n </CardPrimitive.Title>\n )}\n {showSubtitle && (\n <Typography variant=\"body1\" className={styles.subtitle}>\n {subtitle}\n </Typography>\n )}\n </CardPrimitive.Header>\n )}\n <CardPrimitive.Content>\n {externalError && (\n <div className={styles.flowMessagesContainer}>\n <AlertPrimitive variant=\"error\" className={cx(styles.flowMessageItem, messageClasses)}>\n <AlertPrimitive.Description>{externalError.message}</AlertPrimitive.Description>\n </AlertPrimitive>\n </div>\n )}\n {flowMessages && flowMessages.length > 0 && (\n <div className={styles.flowMessagesContainer}>\n {flowMessages.map((message: any, index: number) => (\n <AlertPrimitive\n key={message.id || index}\n variant={message.type?.toLowerCase() === 'error' ? 'error' : 'info'}\n className={cx(styles.flowMessageItem, messageClasses)}\n >\n <AlertPrimitive.Description>{message.message}</AlertPrimitive.Description>\n </AlertPrimitive>\n ))}\n </div>\n )}\n <div className={styles.contentContainer}>\n {componentsWithoutHeadings && componentsWithoutHeadings.length > 0 ? (\n renderComponents(componentsWithoutHeadings)\n ) : (\n <AlertPrimitive variant=\"warning\">\n <Typography variant=\"body1\">{t('errors.signup.components.not.available')}</Typography>\n </AlertPrimitive>\n )}\n </div>\n </CardPrimitive.Content>\n </CardPrimitive>\n );\n};\n\n/**\n * BaseSignUp component that provides embedded sign-up flow for ThunderIDV2.\n * This component handles both the presentation layer and sign-up flow logic.\n * It accepts API functions as props to maintain framework independence.\n */\nconst BaseSignUp: FC<BaseSignUpProps> = ({preferences, showLogo = true, ...rest}: BaseSignUpProps): ReactElement => {\n const {theme, colorScheme} = useTheme();\n const styles: any = useStyles(theme, colorScheme);\n\n const content: ReactElement = (\n <div>\n {showLogo && (\n <div className={styles.logoContainer}>\n <Logo size=\"large\" />\n </div>\n )}\n <FlowProvider>\n <BaseSignUpContent showLogo={showLogo} {...rest} />\n </FlowProvider>\n </div>\n );\n\n if (!preferences) return content;\n\n return <ComponentPreferencesContext.Provider value={preferences}>{content}</ComponentPreferencesContext.Provider>;\n};\n\nexport default BaseSignUp;\n"],"mappings":"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"}
@@ -31,6 +31,9 @@ const AffixedField = ({ label, error, required, className, disabled, helperText,
31
31
  const hasFixedPrefix = prefixList.length === 1;
32
32
  const styles = require_AffixedField_styles.default(theme, colorScheme, disabled ?? false, hasError, hasPrefix);
33
33
  const prefixDescriptionId = `${(0, react.useId)()}-prefix`;
34
+ const generatedId = (0, react.useId)();
35
+ const inputId = rest.id ?? generatedId;
36
+ const helperTextId = error || helperText ? `${inputId}-helper-text` : void 0;
34
37
  const containerClassName = require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("affixed-field", "container")), styles["inputContainer"]);
35
38
  const inputClassName = require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("affixed-field", "input")), styles["input"]);
36
39
  const renderPrefix = () => {
@@ -60,9 +63,11 @@ const AffixedField = ({ label, error, required, className, disabled, helperText,
60
63
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_FormControl.default, {
61
64
  error,
62
65
  helperText,
66
+ helperTextId,
63
67
  className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("affixed-field")), className),
64
68
  style,
65
69
  children: [label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_InputLabel.default, {
70
+ htmlFor: inputId,
66
71
  required,
67
72
  error: hasError,
68
73
  children: label
@@ -75,7 +80,12 @@ const AffixedField = ({ label, error, required, className, disabled, helperText,
75
80
  "aria-invalid": hasError,
76
81
  "aria-required": required,
77
82
  ...rest,
78
- "aria-describedby": [rest["aria-describedby"], hasFixedPrefix ? prefixDescriptionId : void 0].filter(Boolean).join(" ") || void 0
83
+ id: inputId,
84
+ "aria-describedby": [
85
+ rest["aria-describedby"],
86
+ hasFixedPrefix ? prefixDescriptionId : void 0,
87
+ helperTextId
88
+ ].filter(Boolean).join(" ") || void 0
79
89
  })]
80
90
  })]
81
91
  });
@@ -1 +1 @@
1
- {"version":3,"file":"AffixedField.cjs","names":["AffixedField: FC<AffixedFieldProps>","useTheme","hasError: boolean","prefixList: PrefixOption[]","hasPrefix: boolean","hasFixedPrefix: boolean","styles: Record<string, string>","useStyles","prefixDescriptionId: string","containerClassName: string","cx","inputClassName: string","selectedValue: string","FormControl","InputLabel"],"sources":["../../../../../src/components/primitives/AffixedField/AffixedField.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {PrefixOption, bem, withVendorCSSClassPrefix} from '@thunderid/browser';\nimport {ChangeEvent, FC, InputHTMLAttributes, ReactElement, useId} from 'react';\nimport useStyles from './AffixedField.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\n\nexport interface AffixedFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className' | 'prefix'> {\n /** Additional CSS class names applied to the outer form control. */\n className?: string;\n /** Whether the field is disabled. */\n disabled?: boolean;\n /** Error message to render below the field. */\n error?: string;\n /** Helper text to render below the field. */\n helperText?: string;\n /** Label rendered above the field. */\n label?: string;\n /**\n * Called when the user changes the selected prefix. Only fires when `prefixes` is an\n * array with two or more entries and the user picks a different one.\n */\n onPrefixChange?: (prefixValue: string) => void;\n /**\n * Currently selected prefix `value` (must match one of the resolved prefix entries'\n * `value`). Required when `prefixes` resolves to a non-empty list. Ignored otherwise.\n */\n prefixValue?: string;\n /**\n * Leading affix. `string` renders as a fixed span; `PrefixOption[]` renders as a fixed\n * span (single entry) or dropdown (multiple entries). Empty or undefined renders a\n * plain input with no leading element.\n */\n prefixes?: string | PrefixOption[];\n /** Whether the field is required. */\n required?: boolean;\n}\n\n/**\n * Converts the polymorphic `prefixes` prop into a uniform list. A string is treated\n * as a single fixed entry so the rest of the component can iterate a single shape.\n */\nconst normalizePrefixes = (prefixes: string | PrefixOption[] | undefined): PrefixOption[] => {\n if (typeof prefixes === 'string') {\n return prefixes.length > 0 ? [{label: prefixes, value: prefixes}] : [];\n }\n return prefixes ?? [];\n};\n\nconst AffixedField: FC<AffixedFieldProps> = ({\n label,\n error,\n required,\n className,\n disabled,\n helperText,\n prefixes,\n prefixValue,\n onPrefixChange,\n type = 'text',\n style = {},\n ...rest\n}: AffixedFieldProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const hasError: boolean = !!error;\n const prefixList: PrefixOption[] = normalizePrefixes(prefixes);\n const hasPrefix: boolean = prefixList.length > 0;\n const hasFixedPrefix: boolean = prefixList.length === 1;\n const styles: Record<string, string> = useStyles(theme, colorScheme, disabled ?? false, hasError, hasPrefix);\n // Stable id for the visually-hidden prefix announcement; only referenced when a\n // fixed prefix is present, but generated unconditionally so the hook order is stable.\n const prefixDescriptionId: string = `${useId()}-prefix`;\n\n const containerClassName: string = cx(\n withVendorCSSClassPrefix(bem('affixed-field', 'container')),\n styles['inputContainer'],\n );\n\n const inputClassName: string = cx(withVendorCSSClassPrefix(bem('affixed-field', 'input')), styles['input']);\n\n const renderPrefix = (): ReactElement | null => {\n if (prefixList.length === 0) return null;\n\n if (prefixList.length === 1) {\n return (\n <>\n <span\n className={cx(withVendorCSSClassPrefix(bem('affixed-field', 'prefix-span')), styles['prefixSpan'])}\n aria-hidden=\"true\"\n >\n {prefixList[0].label}\n </span>\n {/* Assistive-tech-only mirror of the fixed prefix; wired to the input via aria-describedby. */}\n <span id={prefixDescriptionId} className={styles['visuallyHidden']}>\n {prefixList[0].label}\n </span>\n </>\n );\n }\n\n const selectedValue: string = prefixValue ?? prefixList[0].value;\n return (\n <select\n className={cx(withVendorCSSClassPrefix(bem('affixed-field', 'prefix-select')), styles['prefixSelect'])}\n value={selectedValue}\n disabled={disabled}\n onChange={(e: ChangeEvent<HTMLSelectElement>): void => onPrefixChange?.(e.target.value)}\n aria-label=\"Prefix\"\n >\n {prefixList.map((p: PrefixOption) => (\n <option key={p.value} value={p.value}>\n {p.label}\n </option>\n ))}\n </select>\n );\n };\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n className={cx(withVendorCSSClassPrefix(bem('affixed-field')), className)}\n style={style}\n >\n {label && (\n <InputLabel required={required} error={hasError}>\n {label}\n </InputLabel>\n )}\n <div className={containerClassName}>\n {renderPrefix()}\n <input\n className={inputClassName}\n type={type}\n disabled={disabled}\n aria-invalid={hasError}\n aria-required={required}\n {...rest}\n aria-describedby={\n [rest['aria-describedby'], hasFixedPrefix ? prefixDescriptionId : undefined].filter(Boolean).join(' ') ||\n undefined\n }\n />\n </div>\n </FormControl>\n );\n};\n\nexport default AffixedField;\n"],"mappings":";;;;;;;;;;;;;;;;;;AA8CA,MAAM,qBAAqB,aAAkE;AAC3F,KAAI,OAAO,aAAa,SACtB,QAAO,SAAS,SAAS,IAAI,CAAC;EAAC,OAAO;EAAU,OAAO;EAAS,CAAC,GAAG,EAAE;AAExE,QAAO,YAAY,EAAE;;AAGvB,MAAMA,gBAAuC,EAC3C,OACA,OACA,UACA,WACA,UACA,YACA,UACA,aACA,gBACA,OAAO,QACP,QAAQ,EAAE,CACV,GAAG,WACoB;CACvB,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAMC,WAAoB,CAAC,CAAC;CAC5B,MAAMC,aAA6B,kBAAkB,SAAS;CAC9D,MAAMC,YAAqB,WAAW,SAAS;CAC/C,MAAMC,iBAA0B,WAAW,WAAW;CACtD,MAAMC,SAAiCC,oCAAU,OAAO,aAAa,YAAY,OAAO,UAAU,UAAU;CAG5G,MAAMC,sBAA8B,qBAAU,CAAC;CAE/C,MAAMC,qBAA6BC,kGACJ,iBAAiB,YAAY,CAAC,EAC3D,OAAO,kBACR;CAED,MAAMC,iBAAyBD,kGAAgC,iBAAiB,QAAQ,CAAC,EAAE,OAAO,SAAS;CAE3G,MAAM,qBAA0C;AAC9C,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,MAAI,WAAW,WAAW,EACxB,QACE,qFACE,2CAAC;GACC,WAAWA,kGAAgC,iBAAiB,cAAc,CAAC,EAAE,OAAO,cAAc;GAClG,eAAY;aAEX,WAAW,GAAG;IACV,EAEP,2CAAC;GAAK,IAAI;GAAqB,WAAW,OAAO;aAC9C,WAAW,GAAG;IACV,IACN;EAIP,MAAME,gBAAwB,eAAe,WAAW,GAAG;AAC3D,SACE,2CAAC;GACC,WAAWF,kGAAgC,iBAAiB,gBAAgB,CAAC,EAAE,OAAO,gBAAgB;GACtG,OAAO;GACG;GACV,WAAW,MAA4C,iBAAiB,EAAE,OAAO,MAAM;GACvF,cAAW;aAEV,WAAW,KAAK,MACf,2CAAC;IAAqB,OAAO,EAAE;cAC5B,EAAE;MADQ,EAAE,MAEN,CACT;IACK;;AAIb,QACE,4CAACG;EACQ;EACK;EACZ,WAAWH,kGAAgC,gBAAgB,CAAC,EAAE,UAAU;EACjE;aAEN,SACC,2CAACI;GAAqB;GAAU,OAAO;aACpC;IACU,EAEf,4CAAC;GAAI,WAAW;cACb,cAAc,EACf,2CAAC;IACC,WAAW;IACL;IACI;IACV,gBAAc;IACd,iBAAe;IACf,GAAI;IACJ,oBACE,CAAC,KAAK,qBAAqB,iBAAiB,sBAAsB,OAAU,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IACtG;KAEF;IACE;GACM;;AAIlB,2BAAe"}
1
+ {"version":3,"file":"AffixedField.cjs","names":["AffixedField: FC<AffixedFieldProps>","useTheme","hasError: boolean","prefixList: PrefixOption[]","hasPrefix: boolean","hasFixedPrefix: boolean","styles: Record<string, string>","useStyles","prefixDescriptionId: string","generatedId: string","inputId: string","helperTextId: string | undefined","containerClassName: string","cx","inputClassName: string","selectedValue: string","FormControl","InputLabel"],"sources":["../../../../../src/components/primitives/AffixedField/AffixedField.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {PrefixOption, bem, withVendorCSSClassPrefix} from '@thunderid/browser';\nimport {ChangeEvent, FC, InputHTMLAttributes, ReactElement, useId} from 'react';\nimport useStyles from './AffixedField.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\n\nexport interface AffixedFieldProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className' | 'prefix'> {\n /** Additional CSS class names applied to the outer form control. */\n className?: string;\n /** Whether the field is disabled. */\n disabled?: boolean;\n /** Error message to render below the field. */\n error?: string;\n /** Helper text to render below the field. */\n helperText?: string;\n /** Label rendered above the field. */\n label?: string;\n /**\n * Called when the user changes the selected prefix. Only fires when `prefixes` is an\n * array with two or more entries and the user picks a different one.\n */\n onPrefixChange?: (prefixValue: string) => void;\n /**\n * Currently selected prefix `value` (must match one of the resolved prefix entries'\n * `value`). Required when `prefixes` resolves to a non-empty list. Ignored otherwise.\n */\n prefixValue?: string;\n /**\n * Leading affix. `string` renders as a fixed span; `PrefixOption[]` renders as a fixed\n * span (single entry) or dropdown (multiple entries). Empty or undefined renders a\n * plain input with no leading element.\n */\n prefixes?: string | PrefixOption[];\n /** Whether the field is required. */\n required?: boolean;\n}\n\n/**\n * Converts the polymorphic `prefixes` prop into a uniform list. A string is treated\n * as a single fixed entry so the rest of the component can iterate a single shape.\n */\nconst normalizePrefixes = (prefixes: string | PrefixOption[] | undefined): PrefixOption[] => {\n if (typeof prefixes === 'string') {\n return prefixes.length > 0 ? [{label: prefixes, value: prefixes}] : [];\n }\n return prefixes ?? [];\n};\n\nconst AffixedField: FC<AffixedFieldProps> = ({\n label,\n error,\n required,\n className,\n disabled,\n helperText,\n prefixes,\n prefixValue,\n onPrefixChange,\n type = 'text',\n style = {},\n ...rest\n}: AffixedFieldProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const hasError: boolean = !!error;\n const prefixList: PrefixOption[] = normalizePrefixes(prefixes);\n const hasPrefix: boolean = prefixList.length > 0;\n const hasFixedPrefix: boolean = prefixList.length === 1;\n const styles: Record<string, string> = useStyles(theme, colorScheme, disabled ?? false, hasError, hasPrefix);\n // Stable id for the visually-hidden prefix announcement; only referenced when a\n // fixed prefix is present, but generated unconditionally so the hook order is stable.\n const prefixDescriptionId: string = `${useId()}-prefix`;\n const generatedId: string = useId();\n const inputId: string = rest.id ?? generatedId;\n const helperTextId: string | undefined = error || helperText ? `${inputId}-helper-text` : undefined;\n\n const containerClassName: string = cx(\n withVendorCSSClassPrefix(bem('affixed-field', 'container')),\n styles['inputContainer'],\n );\n\n const inputClassName: string = cx(withVendorCSSClassPrefix(bem('affixed-field', 'input')), styles['input']);\n\n const renderPrefix = (): ReactElement | null => {\n if (prefixList.length === 0) return null;\n\n if (prefixList.length === 1) {\n return (\n <>\n <span\n className={cx(withVendorCSSClassPrefix(bem('affixed-field', 'prefix-span')), styles['prefixSpan'])}\n aria-hidden=\"true\"\n >\n {prefixList[0].label}\n </span>\n {/* Assistive-tech-only mirror of the fixed prefix; wired to the input via aria-describedby. */}\n <span id={prefixDescriptionId} className={styles['visuallyHidden']}>\n {prefixList[0].label}\n </span>\n </>\n );\n }\n\n const selectedValue: string = prefixValue ?? prefixList[0].value;\n return (\n <select\n className={cx(withVendorCSSClassPrefix(bem('affixed-field', 'prefix-select')), styles['prefixSelect'])}\n value={selectedValue}\n disabled={disabled}\n onChange={(e: ChangeEvent<HTMLSelectElement>): void => onPrefixChange?.(e.target.value)}\n aria-label=\"Prefix\"\n >\n {prefixList.map((p: PrefixOption) => (\n <option key={p.value} value={p.value}>\n {p.label}\n </option>\n ))}\n </select>\n );\n };\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n helperTextId={helperTextId}\n className={cx(withVendorCSSClassPrefix(bem('affixed-field')), className)}\n style={style}\n >\n {label && (\n <InputLabel htmlFor={inputId} required={required} error={hasError}>\n {label}\n </InputLabel>\n )}\n <div className={containerClassName}>\n {renderPrefix()}\n <input\n className={inputClassName}\n type={type}\n disabled={disabled}\n aria-invalid={hasError}\n aria-required={required}\n {...rest}\n id={inputId}\n aria-describedby={\n [rest['aria-describedby'], hasFixedPrefix ? prefixDescriptionId : undefined, helperTextId]\n .filter(Boolean)\n .join(' ') || undefined\n }\n />\n </div>\n </FormControl>\n );\n};\n\nexport default AffixedField;\n"],"mappings":";;;;;;;;;;;;;;;;;;AA8CA,MAAM,qBAAqB,aAAkE;AAC3F,KAAI,OAAO,aAAa,SACtB,QAAO,SAAS,SAAS,IAAI,CAAC;EAAC,OAAO;EAAU,OAAO;EAAS,CAAC,GAAG,EAAE;AAExE,QAAO,YAAY,EAAE;;AAGvB,MAAMA,gBAAuC,EAC3C,OACA,OACA,UACA,WACA,UACA,YACA,UACA,aACA,gBACA,OAAO,QACP,QAAQ,EAAE,CACV,GAAG,WACoB;CACvB,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAMC,WAAoB,CAAC,CAAC;CAC5B,MAAMC,aAA6B,kBAAkB,SAAS;CAC9D,MAAMC,YAAqB,WAAW,SAAS;CAC/C,MAAMC,iBAA0B,WAAW,WAAW;CACtD,MAAMC,SAAiCC,oCAAU,OAAO,aAAa,YAAY,OAAO,UAAU,UAAU;CAG5G,MAAMC,sBAA8B,qBAAU,CAAC;CAC/C,MAAMC,gCAA6B;CACnC,MAAMC,UAAkB,KAAK,MAAM;CACnC,MAAMC,eAAmC,SAAS,aAAa,GAAG,QAAQ,gBAAgB;CAE1F,MAAMC,qBAA6BC,kGACJ,iBAAiB,YAAY,CAAC,EAC3D,OAAO,kBACR;CAED,MAAMC,iBAAyBD,kGAAgC,iBAAiB,QAAQ,CAAC,EAAE,OAAO,SAAS;CAE3G,MAAM,qBAA0C;AAC9C,MAAI,WAAW,WAAW,EAAG,QAAO;AAEpC,MAAI,WAAW,WAAW,EACxB,QACE,qFACE,2CAAC;GACC,WAAWA,kGAAgC,iBAAiB,cAAc,CAAC,EAAE,OAAO,cAAc;GAClG,eAAY;aAEX,WAAW,GAAG;IACV,EAEP,2CAAC;GAAK,IAAI;GAAqB,WAAW,OAAO;aAC9C,WAAW,GAAG;IACV,IACN;EAIP,MAAME,gBAAwB,eAAe,WAAW,GAAG;AAC3D,SACE,2CAAC;GACC,WAAWF,kGAAgC,iBAAiB,gBAAgB,CAAC,EAAE,OAAO,gBAAgB;GACtG,OAAO;GACG;GACV,WAAW,MAA4C,iBAAiB,EAAE,OAAO,MAAM;GACvF,cAAW;aAEV,WAAW,KAAK,MACf,2CAAC;IAAqB,OAAO,EAAE;cAC5B,EAAE;MADQ,EAAE,MAEN,CACT;IACK;;AAIb,QACE,4CAACG;EACQ;EACK;EACE;EACd,WAAWH,kGAAgC,gBAAgB,CAAC,EAAE,UAAU;EACjE;aAEN,SACC,2CAACI;GAAW,SAAS;GAAmB;GAAU,OAAO;aACtD;IACU,EAEf,4CAAC;GAAI,WAAW;cACb,cAAc,EACf,2CAAC;IACC,WAAW;IACL;IACI;IACV,gBAAc;IACd,iBAAe;IACf,GAAI;IACJ,IAAI;IACJ,oBACE;KAAC,KAAK;KAAqB,iBAAiB,sBAAsB;KAAW;KAAa,CACvF,OAAO,QAAQ,CACf,KAAK,IAAI,IAAI;KAElB;IACE;GACM;;AAIlB,2BAAe"}
@@ -6,6 +6,8 @@ const require_InputLabel = require('../InputLabel/InputLabel.cjs');
6
6
  const require_Checkbox_styles = require('./Checkbox.styles.cjs');
7
7
  let __thunderid_browser = require("@thunderid/browser");
8
8
  __thunderid_browser = require_rolldown_runtime.__toESM(__thunderid_browser);
9
+ let react = require("react");
10
+ react = require_rolldown_runtime.__toESM(react);
9
11
  let react_jsx_runtime = require("react/jsx-runtime");
10
12
  react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
11
13
 
@@ -13,10 +15,15 @@ react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
13
15
  const Checkbox = ({ label, error, className, required, helperText, style = {},...rest }) => {
14
16
  const { theme, colorScheme } = require_useTheme.default();
15
17
  const hasError = !!error;
18
+ const generatedId = (0, react.useId)();
19
+ const inputId = rest.id ?? generatedId;
20
+ const helperTextId = error || helperText ? `${inputId}-helper-text` : void 0;
21
+ const describedBy = [rest["aria-describedby"], helperTextId].filter(Boolean).join(" ") || void 0;
16
22
  const styles = require_Checkbox_styles.default(theme, colorScheme, hasError, !!required);
17
23
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_FormControl.default, {
18
24
  error,
19
25
  helperText,
26
+ helperTextId,
20
27
  className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("checkbox")), className),
21
28
  helperTextMarginLeft: `calc(${theme.vars.spacing.unit} * 3.5)`,
22
29
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -27,8 +34,11 @@ const Checkbox = ({ label, error, className, required, helperText, style = {},..
27
34
  className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("checkbox", "input")), styles["input"], styles["errorInput"], { [(0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("checkbox", "input", "error"))]: hasError }),
28
35
  "aria-invalid": hasError,
29
36
  "aria-required": required,
30
- ...rest
37
+ ...rest,
38
+ id: inputId,
39
+ "aria-describedby": describedBy
31
40
  }), label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_InputLabel.default, {
41
+ htmlFor: inputId,
32
42
  required,
33
43
  error: hasError,
34
44
  variant: "inline",
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.cjs","names":["Checkbox: FC<CheckboxProps>","useTheme","styles: Record<string, string>","useStyles","FormControl","cx","InputLabel"],"sources":["../../../../../src/components/primitives/Checkbox/Checkbox.tsx"],"sourcesContent":["// Copyright 2024 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {FC, InputHTMLAttributes} from 'react';\nimport useStyles from './Checkbox.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\n\nexport interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className' | 'type'> {\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Error message to display below the checkbox\n */\n error?: string;\n /**\n * Helper text to display below the checkbox\n */\n helperText?: string;\n /**\n * Label text to display next to the checkbox\n */\n label?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n}\n\nconst Checkbox: FC<CheckboxProps> = ({\n label,\n error,\n className,\n required,\n helperText,\n style = {},\n ...rest\n}: CheckboxProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const hasError = !!error;\n const styles: Record<string, string> = useStyles(theme, colorScheme, hasError, !!required);\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n className={cx(withVendorCSSClassPrefix(bem('checkbox')), className)}\n helperTextMarginLeft={`calc(${theme.vars.spacing.unit} * 3.5)`}\n >\n <div style={style} className={cx(withVendorCSSClassPrefix(bem('checkbox', 'container')), styles['container'])}>\n <input\n type=\"checkbox\"\n className={cx(withVendorCSSClassPrefix(bem('checkbox', 'input')), styles['input'], styles['errorInput'], {\n [withVendorCSSClassPrefix(bem('checkbox', 'input', 'error'))]: hasError,\n })}\n aria-invalid={hasError}\n aria-required={required}\n {...rest}\n />\n {label && (\n <InputLabel\n required={required}\n error={hasError}\n variant=\"inline\"\n className={cx(withVendorCSSClassPrefix(bem('checkbox', 'label')), styles['label'], styles['errorLabel'], {\n [withVendorCSSClassPrefix(bem('checkbox', 'label', 'error'))]: hasError,\n })}\n >\n {label}\n </InputLabel>\n )}\n </div>\n </FormControl>\n );\n};\n\nexport default Checkbox;\n"],"mappings":";;;;;;;;;;;;AAkCA,MAAMA,YAA+B,EACnC,OACA,OACA,WACA,UACA,YACA,QAAQ,EAAE,CACV,GAAG,WACgB;CACnB,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAM,WAAW,CAAC,CAAC;CACnB,MAAMC,SAAiCC,gCAAU,OAAO,aAAa,UAAU,CAAC,CAAC,SAAS;AAE1F,QACE,2CAACC;EACQ;EACK;EACZ,WAAWC,kGAAgC,WAAW,CAAC,EAAE,UAAU;EACnE,sBAAsB,QAAQ,MAAM,KAAK,QAAQ,KAAK;YAEtD,4CAAC;GAAW;GAAO,WAAWA,kGAAgC,YAAY,YAAY,CAAC,EAAE,OAAO,aAAa;cAC3G,2CAAC;IACC,MAAK;IACL,WAAWA,kGAAgC,YAAY,QAAQ,CAAC,EAAE,OAAO,UAAU,OAAO,eAAe,kFACzE,YAAY,SAAS,QAAQ,CAAC,GAAG,UAChE,CAAC;IACF,gBAAc;IACd,iBAAe;IACf,GAAI;KACJ,EACD,SACC,2CAACC;IACW;IACV,OAAO;IACP,SAAQ;IACR,WAAWD,kGAAgC,YAAY,QAAQ,CAAC,EAAE,OAAO,UAAU,OAAO,eAAe,kFACzE,YAAY,SAAS,QAAQ,CAAC,GAAG,UAChE,CAAC;cAED;KACU;IAEX;GACM;;AAIlB,uBAAe"}
1
+ {"version":3,"file":"Checkbox.cjs","names":["Checkbox: FC<CheckboxProps>","useTheme","generatedId: string","inputId: string","helperTextId: string | undefined","describedBy: string | undefined","styles: Record<string, string>","useStyles","FormControl","cx","InputLabel"],"sources":["../../../../../src/components/primitives/Checkbox/Checkbox.tsx"],"sourcesContent":["// Copyright 2024 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {FC, InputHTMLAttributes, useId} from 'react';\nimport useStyles from './Checkbox.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\n\nexport interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className' | 'type'> {\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Error message to display below the checkbox\n */\n error?: string;\n /**\n * Helper text to display below the checkbox\n */\n helperText?: string;\n /**\n * Label text to display next to the checkbox\n */\n label?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n}\n\nconst Checkbox: FC<CheckboxProps> = ({\n label,\n error,\n className,\n required,\n helperText,\n style = {},\n ...rest\n}: CheckboxProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const hasError = !!error;\n const generatedId: string = useId();\n const inputId: string = rest.id ?? generatedId;\n const helperTextId: string | undefined = error || helperText ? `${inputId}-helper-text` : undefined;\n const describedBy: string | undefined =\n [rest['aria-describedby'], helperTextId].filter(Boolean).join(' ') || undefined;\n const styles: Record<string, string> = useStyles(theme, colorScheme, hasError, !!required);\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n helperTextId={helperTextId}\n className={cx(withVendorCSSClassPrefix(bem('checkbox')), className)}\n helperTextMarginLeft={`calc(${theme.vars.spacing.unit} * 3.5)`}\n >\n <div style={style} className={cx(withVendorCSSClassPrefix(bem('checkbox', 'container')), styles['container'])}>\n <input\n type=\"checkbox\"\n className={cx(withVendorCSSClassPrefix(bem('checkbox', 'input')), styles['input'], styles['errorInput'], {\n [withVendorCSSClassPrefix(bem('checkbox', 'input', 'error'))]: hasError,\n })}\n aria-invalid={hasError}\n aria-required={required}\n {...rest}\n id={inputId}\n aria-describedby={describedBy}\n />\n {label && (\n <InputLabel\n htmlFor={inputId}\n required={required}\n error={hasError}\n variant=\"inline\"\n className={cx(withVendorCSSClassPrefix(bem('checkbox', 'label')), styles['label'], styles['errorLabel'], {\n [withVendorCSSClassPrefix(bem('checkbox', 'label', 'error'))]: hasError,\n })}\n >\n {label}\n </InputLabel>\n )}\n </div>\n </FormControl>\n );\n};\n\nexport default Checkbox;\n"],"mappings":";;;;;;;;;;;;;;AAkCA,MAAMA,YAA+B,EACnC,OACA,OACA,WACA,UACA,YACA,QAAQ,EAAE,CACV,GAAG,WACgB;CACnB,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAM,WAAW,CAAC,CAAC;CACnB,MAAMC,gCAA6B;CACnC,MAAMC,UAAkB,KAAK,MAAM;CACnC,MAAMC,eAAmC,SAAS,aAAa,GAAG,QAAQ,gBAAgB;CAC1F,MAAMC,cACJ,CAAC,KAAK,qBAAqB,aAAa,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;CACxE,MAAMC,SAAiCC,gCAAU,OAAO,aAAa,UAAU,CAAC,CAAC,SAAS;AAE1F,QACE,2CAACC;EACQ;EACK;EACE;EACd,WAAWC,kGAAgC,WAAW,CAAC,EAAE,UAAU;EACnE,sBAAsB,QAAQ,MAAM,KAAK,QAAQ,KAAK;YAEtD,4CAAC;GAAW;GAAO,WAAWA,kGAAgC,YAAY,YAAY,CAAC,EAAE,OAAO,aAAa;cAC3G,2CAAC;IACC,MAAK;IACL,WAAWA,kGAAgC,YAAY,QAAQ,CAAC,EAAE,OAAO,UAAU,OAAO,eAAe,kFACzE,YAAY,SAAS,QAAQ,CAAC,GAAG,UAChE,CAAC;IACF,gBAAc;IACd,iBAAe;IACf,GAAI;IACJ,IAAI;IACJ,oBAAkB;KAClB,EACD,SACC,2CAACC;IACC,SAAS;IACC;IACV,OAAO;IACP,SAAQ;IACR,WAAWD,kGAAgC,YAAY,QAAQ,CAAC,EAAE,OAAO,UAAU,OAAO,eAAe,kFACzE,YAAY,SAAS,QAAQ,CAAC,GAAG,UAChE,CAAC;cAED;KACU;IAEX;GACM;;AAIlB,uBAAe"}
@@ -6,6 +6,8 @@ const require_InputLabel = require('../InputLabel/InputLabel.cjs');
6
6
  const require_DatePicker_styles = require('./DatePicker.styles.cjs');
7
7
  let __thunderid_browser = require("@thunderid/browser");
8
8
  __thunderid_browser = require_rolldown_runtime.__toESM(__thunderid_browser);
9
+ let react = require("react");
10
+ react = require_rolldown_runtime.__toESM(react);
9
11
  let react_jsx_runtime = require("react/jsx-runtime");
10
12
  react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
11
13
 
@@ -13,13 +15,19 @@ react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
13
15
  const DatePicker = ({ label, error, className, required, disabled, helperText, dateFormat = "yyyy-MM-dd", style = {},...rest }) => {
14
16
  const { theme, colorScheme } = require_useTheme.default();
15
17
  const hasError = !!error;
18
+ const generatedId = (0, react.useId)();
19
+ const inputId = rest.id ?? generatedId;
20
+ const helperTextId = error || helperText ? `${inputId}-helper-text` : void 0;
21
+ const describedBy = [rest["aria-describedby"], helperTextId].filter(Boolean).join(" ") || void 0;
16
22
  const styles = require_DatePicker_styles.default(theme, colorScheme, hasError, !!disabled);
17
23
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_FormControl.default, {
18
24
  error,
19
25
  helperText,
26
+ helperTextId,
20
27
  className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("date-picker")), className),
21
28
  style,
22
29
  children: [label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_InputLabel.default, {
30
+ htmlFor: inputId,
23
31
  required,
24
32
  error: hasError,
25
33
  className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("date-picker", "label")), styles["label"]),
@@ -35,7 +43,9 @@ const DatePicker = ({ label, error, className, required, disabled, helperText, d
35
43
  disabled,
36
44
  "aria-invalid": hasError,
37
45
  "aria-required": required,
38
- ...rest
46
+ ...rest,
47
+ id: inputId,
48
+ "aria-describedby": describedBy
39
49
  })]
40
50
  });
41
51
  };
@@ -1 +1 @@
1
- {"version":3,"file":"DatePicker.cjs","names":["DatePicker: FC<DatePickerProps>","useTheme","styles: Record<string, string>","useStyles","FormControl","cx","InputLabel"],"sources":["../../../../../src/components/primitives/DatePicker/DatePicker.tsx"],"sourcesContent":["// Copyright 2024 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {FC, InputHTMLAttributes} from 'react';\nimport useStyles from './DatePicker.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\n\nexport interface DatePickerProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className' | 'type'> {\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Custom date format for the regex pattern\n */\n dateFormat?: string;\n /**\n * Whether the field is disabled\n */\n disabled?: boolean;\n /**\n * Error message to display below the input\n */\n error?: string;\n /**\n * Helper text to display below the input\n */\n helperText?: string;\n /**\n * Label text to display above the input\n */\n label?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n}\n\nconst DatePicker: FC<DatePickerProps> = ({\n label,\n error,\n className,\n required,\n disabled,\n helperText,\n dateFormat = 'yyyy-MM-dd',\n style = {},\n ...rest\n}: DatePickerProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const hasError = !!error;\n const styles: Record<string, string> = useStyles(theme, colorScheme, hasError, !!disabled);\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n className={cx(withVendorCSSClassPrefix(bem('date-picker')), className)}\n style={style}\n >\n {label && (\n <InputLabel\n required={required}\n error={hasError}\n className={cx(withVendorCSSClassPrefix(bem('date-picker', 'label')), styles['label'])}\n >\n {label}\n </InputLabel>\n )}\n <input\n type=\"date\"\n pattern=\"\\d{4}-\\d{2}-\\d{2}\"\n placeholder={dateFormat}\n className={cx(\n withVendorCSSClassPrefix(bem('date-picker', 'input')),\n styles['input'],\n styles['errorInput'],\n styles['disabledInput'],\n {\n [withVendorCSSClassPrefix(bem('date-picker', 'input', 'error'))]: hasError,\n [withVendorCSSClassPrefix(bem('date-picker', 'input', 'disabled'))]: disabled,\n },\n )}\n disabled={disabled}\n aria-invalid={hasError}\n aria-required={required}\n {...rest}\n />\n </FormControl>\n );\n};\n\nexport default DatePicker;\n"],"mappings":";;;;;;;;;;;;AA0CA,MAAMA,cAAmC,EACvC,OACA,OACA,WACA,UACA,UACA,YACA,aAAa,cACb,QAAQ,EAAE,CACV,GAAG,WACkB;CACrB,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAM,WAAW,CAAC,CAAC;CACnB,MAAMC,SAAiCC,kCAAU,OAAO,aAAa,UAAU,CAAC,CAAC,SAAS;AAE1F,QACE,4CAACC;EACQ;EACK;EACZ,WAAWC,kGAAgC,cAAc,CAAC,EAAE,UAAU;EAC/D;aAEN,SACC,2CAACC;GACW;GACV,OAAO;GACP,WAAWD,kGAAgC,eAAe,QAAQ,CAAC,EAAE,OAAO,SAAS;aAEpF;IACU,EAEf,2CAAC;GACC,MAAK;GACL,SAAQ;GACR,aAAa;GACb,WAAWA,kGACoB,eAAe,QAAQ,CAAC,EACrD,OAAO,UACP,OAAO,eACP,OAAO,kBACP;oFACgC,eAAe,SAAS,QAAQ,CAAC,GAAG;oFACpC,eAAe,SAAS,WAAW,CAAC,GAAG;IACtE,CACF;GACS;GACV,gBAAc;GACd,iBAAe;GACf,GAAI;IACJ;GACU;;AAIlB,yBAAe"}
1
+ {"version":3,"file":"DatePicker.cjs","names":["DatePicker: FC<DatePickerProps>","useTheme","generatedId: string","inputId: string","helperTextId: string | undefined","describedBy: string | undefined","styles: Record<string, string>","useStyles","FormControl","cx","InputLabel"],"sources":["../../../../../src/components/primitives/DatePicker/DatePicker.tsx"],"sourcesContent":["// Copyright 2024 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {FC, InputHTMLAttributes, useId} from 'react';\nimport useStyles from './DatePicker.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport FormControl from '../FormControl/FormControl';\nimport InputLabel from '../InputLabel/InputLabel';\n\nexport interface DatePickerProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'className' | 'type'> {\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Custom date format for the regex pattern\n */\n dateFormat?: string;\n /**\n * Whether the field is disabled\n */\n disabled?: boolean;\n /**\n * Error message to display below the input\n */\n error?: string;\n /**\n * Helper text to display below the input\n */\n helperText?: string;\n /**\n * Label text to display above the input\n */\n label?: string;\n /**\n * Whether the field is required\n */\n required?: boolean;\n}\n\nconst DatePicker: FC<DatePickerProps> = ({\n label,\n error,\n className,\n required,\n disabled,\n helperText,\n dateFormat = 'yyyy-MM-dd',\n style = {},\n ...rest\n}: DatePickerProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const hasError = !!error;\n const generatedId: string = useId();\n const inputId: string = rest.id ?? generatedId;\n const helperTextId: string | undefined = error || helperText ? `${inputId}-helper-text` : undefined;\n const describedBy: string | undefined =\n [rest['aria-describedby'], helperTextId].filter(Boolean).join(' ') || undefined;\n const styles: Record<string, string> = useStyles(theme, colorScheme, hasError, !!disabled);\n\n return (\n <FormControl\n error={error}\n helperText={helperText}\n helperTextId={helperTextId}\n className={cx(withVendorCSSClassPrefix(bem('date-picker')), className)}\n style={style}\n >\n {label && (\n <InputLabel\n htmlFor={inputId}\n required={required}\n error={hasError}\n className={cx(withVendorCSSClassPrefix(bem('date-picker', 'label')), styles['label'])}\n >\n {label}\n </InputLabel>\n )}\n <input\n type=\"date\"\n pattern=\"\\d{4}-\\d{2}-\\d{2}\"\n placeholder={dateFormat}\n className={cx(\n withVendorCSSClassPrefix(bem('date-picker', 'input')),\n styles['input'],\n styles['errorInput'],\n styles['disabledInput'],\n {\n [withVendorCSSClassPrefix(bem('date-picker', 'input', 'error'))]: hasError,\n [withVendorCSSClassPrefix(bem('date-picker', 'input', 'disabled'))]: disabled,\n },\n )}\n disabled={disabled}\n aria-invalid={hasError}\n aria-required={required}\n {...rest}\n id={inputId}\n aria-describedby={describedBy}\n />\n </FormControl>\n );\n};\n\nexport default DatePicker;\n"],"mappings":";;;;;;;;;;;;;;AA0CA,MAAMA,cAAmC,EACvC,OACA,OACA,WACA,UACA,UACA,YACA,aAAa,cACb,QAAQ,EAAE,CACV,GAAG,WACkB;CACrB,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAM,WAAW,CAAC,CAAC;CACnB,MAAMC,gCAA6B;CACnC,MAAMC,UAAkB,KAAK,MAAM;CACnC,MAAMC,eAAmC,SAAS,aAAa,GAAG,QAAQ,gBAAgB;CAC1F,MAAMC,cACJ,CAAC,KAAK,qBAAqB,aAAa,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI,IAAI;CACxE,MAAMC,SAAiCC,kCAAU,OAAO,aAAa,UAAU,CAAC,CAAC,SAAS;AAE1F,QACE,4CAACC;EACQ;EACK;EACE;EACd,WAAWC,kGAAgC,cAAc,CAAC,EAAE,UAAU;EAC/D;aAEN,SACC,2CAACC;GACC,SAAS;GACC;GACV,OAAO;GACP,WAAWD,kGAAgC,eAAe,QAAQ,CAAC,EAAE,OAAO,SAAS;aAEpF;IACU,EAEf,2CAAC;GACC,MAAK;GACL,SAAQ;GACR,aAAa;GACb,WAAWA,kGACoB,eAAe,QAAQ,CAAC,EACrD,OAAO,UACP,OAAO,eACP,OAAO,kBACP;oFACgC,eAAe,SAAS,QAAQ,CAAC,GAAG;oFACpC,eAAe,SAAS,WAAW,CAAC,GAAG;IACtE,CACF;GACS;GACV,gBAAc;GACd,iBAAe;GACf,GAAI;GACJ,IAAI;GACJ,oBAAkB;IAClB;GACU;;AAIlB,yBAAe"}
@@ -9,13 +9,14 @@ let react_jsx_runtime = require("react/jsx-runtime");
9
9
  react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
10
10
 
11
11
  //#region src/components/primitives/FormControl/FormControl.tsx
12
- const FormControl = ({ children, error, helperText, className, id, helperTextAlign = "left", helperTextMarginLeft }) => {
12
+ const FormControl = ({ children, error, helperText, helperTextId, className, id, helperTextAlign = "left", helperTextMarginLeft }) => {
13
13
  const { theme, colorScheme } = require_useTheme.default();
14
14
  const styles = require_FormControl_styles.default(theme, colorScheme, helperTextAlign, helperTextMarginLeft, !!error);
15
15
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
16
16
  id,
17
17
  className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("form-control")), styles["formControl"], className),
18
18
  children: [children, (error || helperText) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Typography.default, {
19
+ id: helperTextId,
19
20
  variant: "caption",
20
21
  color: error ? "error" : "textSecondary",
21
22
  className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("form-control", "helper-text")), styles["helperText"], {
@@ -1 +1 @@
1
- {"version":3,"file":"FormControl.cjs","names":["FormControl: FC<FormControlProps>","useTheme","styles: Record<string, string>","useStyles","cx","Typography"],"sources":["../../../../../src/components/primitives/FormControl/FormControl.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {bem, withVendorCSSClassPrefix} from '@thunderid/browser';\nimport {CSSProperties, FC, ReactNode} from 'react';\nimport useStyles from './FormControl.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport Typography from '../Typography/Typography';\n\nexport type FormControlHelperTextAlign = 'left' | 'center';\n\nexport interface FormControlProps {\n /**\n * The content to be wrapped by the form control\n */\n children: ReactNode;\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Error message to display below the content\n */\n error?: string;\n /**\n * Helper text to display below the content\n */\n helperText?: string;\n /**\n * Custom alignment for helper text (default: left, center for OTP)\n */\n helperTextAlign?: FormControlHelperTextAlign;\n /**\n * Custom margin left for helper text (for components like Checkbox)\n */\n helperTextMarginLeft?: string;\n /**\n * HTML id attribute\n */\n id?: string;\n /**\n * Custom container style\n */\n style?: CSSProperties;\n}\n\nconst FormControl: FC<FormControlProps> = ({\n children,\n error,\n helperText,\n className,\n id,\n helperTextAlign = 'left',\n helperTextMarginLeft,\n}: FormControlProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme, helperTextAlign, helperTextMarginLeft, !!error);\n\n return (\n <div id={id} className={cx(withVendorCSSClassPrefix(bem('form-control')), styles['formControl'], className)}>\n {children}\n {(error || helperText) && (\n <Typography\n variant=\"caption\"\n color={error ? 'error' : 'textSecondary'}\n className={cx(withVendorCSSClassPrefix(bem('form-control', 'helper-text')), styles['helperText'], {\n [withVendorCSSClassPrefix(bem('form-control', 'helper-text', 'error'))]: !!error,\n [styles['helperTextError']]: !!error,\n })}\n >\n {error || helperText}\n </Typography>\n )}\n </div>\n );\n};\n\nexport default FormControl;\n"],"mappings":";;;;;;;;;;;AA+CA,MAAMA,eAAqC,EACzC,UACA,OACA,YACA,WACA,IACA,kBAAkB,QAClB,2BACsB;CACtB,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAMC,SAAiCC,mCAAU,OAAO,aAAa,iBAAiB,sBAAsB,CAAC,CAAC,MAAM;AAEpH,QACE,4CAAC;EAAQ;EAAI,WAAWC,kGAAgC,eAAe,CAAC,EAAE,OAAO,gBAAgB,UAAU;aACxG,WACC,SAAS,eACT,2CAACC;GACC,SAAQ;GACR,OAAO,QAAQ,UAAU;GACzB,WAAWD,kGAAgC,gBAAgB,cAAc,CAAC,EAAE,OAAO,eAAe;oFAClE,gBAAgB,eAAe,QAAQ,CAAC,GAAG,CAAC,CAAC;KAC1E,OAAO,qBAAqB,CAAC,CAAC;IAChC,CAAC;aAED,SAAS;IACC;GAEX;;AAIV,0BAAe"}
1
+ {"version":3,"file":"FormControl.cjs","names":["FormControl: FC<FormControlProps>","useTheme","styles: Record<string, string>","useStyles","cx","Typography"],"sources":["../../../../../src/components/primitives/FormControl/FormControl.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {bem, withVendorCSSClassPrefix} from '@thunderid/browser';\nimport {CSSProperties, FC, ReactNode} from 'react';\nimport useStyles from './FormControl.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {cx} from '../../../styles/emotion';\nimport Typography from '../Typography/Typography';\n\nexport type FormControlHelperTextAlign = 'left' | 'center';\n\nexport interface FormControlProps {\n /**\n * The content to be wrapped by the form control\n */\n children: ReactNode;\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * Error message to display below the content\n */\n error?: string;\n /**\n * Helper text to display below the content\n */\n helperText?: string;\n /**\n * id of the helper text element, so the field it describes can reference it with `aria-describedby`\n */\n helperTextId?: string;\n /**\n * Custom alignment for helper text (default: left, center for OTP)\n */\n helperTextAlign?: FormControlHelperTextAlign;\n /**\n * Custom margin left for helper text (for components like Checkbox)\n */\n helperTextMarginLeft?: string;\n /**\n * HTML id attribute\n */\n id?: string;\n /**\n * Custom container style\n */\n style?: CSSProperties;\n}\n\nconst FormControl: FC<FormControlProps> = ({\n children,\n error,\n helperText,\n helperTextId,\n className,\n id,\n helperTextAlign = 'left',\n helperTextMarginLeft,\n}: FormControlProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme, helperTextAlign, helperTextMarginLeft, !!error);\n\n return (\n <div id={id} className={cx(withVendorCSSClassPrefix(bem('form-control')), styles['formControl'], className)}>\n {children}\n {(error || helperText) && (\n <Typography\n id={helperTextId}\n variant=\"caption\"\n color={error ? 'error' : 'textSecondary'}\n className={cx(withVendorCSSClassPrefix(bem('form-control', 'helper-text')), styles['helperText'], {\n [withVendorCSSClassPrefix(bem('form-control', 'helper-text', 'error'))]: !!error,\n [styles['helperTextError']]: !!error,\n })}\n >\n {error || helperText}\n </Typography>\n )}\n </div>\n );\n};\n\nexport default FormControl;\n"],"mappings":";;;;;;;;;;;AAmDA,MAAMA,eAAqC,EACzC,UACA,OACA,YACA,cACA,WACA,IACA,kBAAkB,QAClB,2BACsB;CACtB,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAMC,SAAiCC,mCAAU,OAAO,aAAa,iBAAiB,sBAAsB,CAAC,CAAC,MAAM;AAEpH,QACE,4CAAC;EAAQ;EAAI,WAAWC,kGAAgC,eAAe,CAAC,EAAE,OAAO,gBAAgB,UAAU;aACxG,WACC,SAAS,eACT,2CAACC;GACC,IAAI;GACJ,SAAQ;GACR,OAAO,QAAQ,UAAU;GACzB,WAAWD,kGAAgC,gBAAgB,cAAc,CAAC,EAAE,OAAO,eAAe;oFAClE,gBAAgB,eAAe,QAAQ,CAAC,GAAG,CAAC,CAAC;KAC1E,OAAO,qBAAqB,CAAC,CAAC;IAChC,CAAC;aAED,SAAS;IACC;GAEX;;AAIV,0BAAe"}
@@ -17,6 +17,8 @@ react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
17
17
  //#region src/components/primitives/MultiInput/MultiInput.tsx
18
18
  const MultiInput = ({ label, error, required, className, disabled, helperText, placeholder = "Enter value", values = [], onChange, type = "text", fieldType = "STRING", startIcon, endIcon, minFields = 1, maxFields, style = {} }) => {
19
19
  const { theme, colorScheme } = require_useTheme.default();
20
+ const inputId = (0, react.useId)();
21
+ const helperTextId = error || helperText ? `${inputId}-description` : void 0;
20
22
  const canAddMore = !maxFields || values.length < maxFields;
21
23
  const canRemove = values.length > minFields;
22
24
  const styles = require_MultiInput_styles.default(theme, colorScheme, !!disabled, !!error, canAddMore, canRemove);
@@ -58,10 +60,13 @@ const MultiInput = ({ label, error, required, className, disabled, helperText, p
58
60
  onEndIconClick();
59
61
  }
60
62
  };
63
+ const finalEndIcon = attachedEndIcon || endIcon;
61
64
  const commonProps = {
65
+ "aria-describedby": helperTextId,
62
66
  disabled,
63
- endIcon: attachedEndIcon || endIcon,
67
+ endIcon: finalEndIcon,
64
68
  error,
69
+ id: inputId,
65
70
  onChange: handleInputChange,
66
71
  onEndIconClick,
67
72
  onKeyDown: handleKeyDown,
@@ -88,7 +93,9 @@ const MultiInput = ({ label, error, required, className, disabled, helperText, p
88
93
  endIcon,
89
94
  error,
90
95
  fieldType,
91
- type
96
+ type,
97
+ inputId,
98
+ helperTextId
92
99
  ]);
93
100
  const [currentInputValue, setCurrentInputValue] = (0, react.useState)("");
94
101
  const handleInputSubmit = (0, react.useCallback)(() => {
@@ -100,9 +107,11 @@ const MultiInput = ({ label, error, required, className, disabled, helperText, p
100
107
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_FormControl.default, {
101
108
  error,
102
109
  helperText,
110
+ helperTextId,
103
111
  className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("multi-input")), className),
104
112
  style,
105
113
  children: [label && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_InputLabel.default, {
114
+ htmlFor: inputId,
106
115
  required,
107
116
  error: !!error,
108
117
  children: label