@thunderid/react 1.8.0 → 1.9.0

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 (188) hide show
  1. package/dist/cjs/components/account/UserProfile/BaseUserProfile.cjs +1 -1
  2. package/dist/cjs/components/admin/AgentDetails/AgentDetails.cjs +13 -2
  3. package/dist/cjs/components/admin/AgentDetails/AgentDetails.cjs.map +1 -1
  4. package/dist/cjs/components/admin/AgentDetails/BaseAgentDetails.cjs +25 -7
  5. package/dist/cjs/components/admin/AgentDetails/BaseAgentDetails.cjs.map +1 -1
  6. package/dist/cjs/components/admin/ApplicationDetails/ApplicationDetails.cjs +15 -2
  7. package/dist/cjs/components/admin/ApplicationDetails/ApplicationDetails.cjs.map +1 -1
  8. package/dist/cjs/components/admin/ApplicationDetails/BaseApplicationDetails.cjs +24 -7
  9. package/dist/cjs/components/admin/ApplicationDetails/BaseApplicationDetails.cjs.map +1 -1
  10. package/dist/cjs/components/admin/GroupMembers/GroupMembers.cjs +2 -1
  11. package/dist/cjs/components/admin/GroupMembers/GroupMembers.cjs.map +1 -1
  12. package/dist/cjs/components/admin/RoleAssignments/RoleAssignments.cjs +2 -1
  13. package/dist/cjs/components/admin/RoleAssignments/RoleAssignments.cjs.map +1 -1
  14. package/dist/cjs/components/admin/UserDetails/BaseUserDetails.cjs +32 -14
  15. package/dist/cjs/components/admin/UserDetails/BaseUserDetails.cjs.map +1 -1
  16. package/dist/cjs/components/admin/UserDetails/UserDetails.cjs +14 -2
  17. package/dist/cjs/components/admin/UserDetails/UserDetails.cjs.map +1 -1
  18. package/dist/cjs/components/admin/shared/AccountLifecycleParts.cjs +105 -0
  19. package/dist/cjs/components/admin/shared/AccountLifecycleParts.cjs.map +1 -0
  20. package/dist/cjs/components/admin/shared/ApplicationFormFields.cjs +1 -1
  21. package/dist/cjs/components/auth/AcceptInvite/BaseAcceptInvite.cjs +4 -5
  22. package/dist/cjs/components/auth/AcceptInvite/BaseAcceptInvite.cjs.map +1 -1
  23. package/dist/cjs/components/auth/SignIn/SignIn.cjs +5 -5
  24. package/dist/cjs/components/auth/SignIn/SignIn.cjs.map +1 -1
  25. package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs +4 -5
  26. package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs.map +1 -1
  27. package/dist/cjs/components/auth/flow/Consent.cjs +53 -28
  28. package/dist/cjs/components/auth/flow/Consent.cjs.map +1 -1
  29. package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.cjs +104 -0
  30. package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.cjs.map +1 -0
  31. package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.styles.cjs +59 -0
  32. package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.styles.cjs.map +1 -0
  33. package/dist/cjs/components/auth/flow/ConsentDetailField.cjs +171 -0
  34. package/dist/cjs/components/auth/flow/ConsentDetailField.cjs.map +1 -0
  35. package/dist/cjs/components/auth/flow/ConsentDetailField.styles.cjs +85 -0
  36. package/dist/cjs/components/auth/flow/ConsentDetailField.styles.cjs.map +1 -0
  37. package/dist/cjs/components/auth/flow/ConsentDetailText.cjs +63 -0
  38. package/dist/cjs/components/auth/flow/ConsentDetailText.cjs.map +1 -0
  39. package/dist/cjs/components/auth/flow/ConsentDetailText.styles.cjs +83 -0
  40. package/dist/cjs/components/auth/flow/ConsentDetailText.styles.cjs.map +1 -0
  41. package/dist/cjs/components/auth/flow/FieldFactory.cjs +1 -1
  42. package/dist/cjs/components/auth/flow/resolveConsentText.cjs +25 -0
  43. package/dist/cjs/components/auth/flow/resolveConsentText.cjs.map +1 -0
  44. package/dist/cjs/components/primitives/KeyValueInput/KeyValueInput.cjs +1 -1
  45. package/dist/cjs/components/primitives/MultiInput/MultiInput.cjs +1 -1
  46. package/dist/cjs/components/primitives/PasswordField/PasswordField.cjs +1 -1
  47. package/dist/cjs/hooks/auth/useConsentDetailField.cjs +357 -0
  48. package/dist/cjs/hooks/auth/useConsentDetailField.cjs.map +1 -0
  49. package/dist/cjs/hooks/management/useAccountLifecycle.cjs +59 -0
  50. package/dist/cjs/hooks/management/useAccountLifecycle.cjs.map +1 -0
  51. package/dist/cjs/index.cjs +66 -1
  52. package/dist/cjs/utils/formatConsentDetailValue.cjs +26 -0
  53. package/dist/cjs/utils/formatConsentDetailValue.cjs.map +1 -0
  54. package/dist/cjs/utils/getConsentDetailLayout.cjs +44 -0
  55. package/dist/cjs/utils/getConsentDetailLayout.cjs.map +1 -0
  56. package/dist/cjs/utils/getConsentDetailListDisplay.cjs +30 -0
  57. package/dist/cjs/utils/getConsentDetailListDisplay.cjs.map +1 -0
  58. package/dist/cjs/utils/isConsentApprovalBlocked.cjs +41 -0
  59. package/dist/cjs/utils/isConsentApprovalBlocked.cjs.map +1 -0
  60. package/dist/cjs/utils/isConsentDetailPlainList.cjs +24 -0
  61. package/dist/cjs/utils/isConsentDetailPlainList.cjs.map +1 -0
  62. package/dist/cjs/utils/isConsentDetailStructured.cjs +15 -0
  63. package/dist/cjs/utils/isConsentDetailStructured.cjs.map +1 -0
  64. package/dist/cjs/utils/isConsentDetailTextClamped.cjs +25 -0
  65. package/dist/cjs/utils/isConsentDetailTextClamped.cjs.map +1 -0
  66. package/dist/components/account/UserProfile/BaseUserProfile.js +1 -1
  67. package/dist/components/admin/AgentDetails/AgentDetails.d.ts +8 -1
  68. package/dist/components/admin/AgentDetails/AgentDetails.d.ts.map +1 -1
  69. package/dist/components/admin/AgentDetails/AgentDetails.js +13 -2
  70. package/dist/components/admin/AgentDetails/AgentDetails.js.map +1 -1
  71. package/dist/components/admin/AgentDetails/BaseAgentDetails.d.ts +21 -1
  72. package/dist/components/admin/AgentDetails/BaseAgentDetails.d.ts.map +1 -1
  73. package/dist/components/admin/AgentDetails/BaseAgentDetails.js +25 -7
  74. package/dist/components/admin/AgentDetails/BaseAgentDetails.js.map +1 -1
  75. package/dist/components/admin/ApplicationDetails/ApplicationDetails.d.ts +15 -1
  76. package/dist/components/admin/ApplicationDetails/ApplicationDetails.d.ts.map +1 -1
  77. package/dist/components/admin/ApplicationDetails/ApplicationDetails.js +15 -2
  78. package/dist/components/admin/ApplicationDetails/ApplicationDetails.js.map +1 -1
  79. package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.d.ts +20 -1
  80. package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.d.ts.map +1 -1
  81. package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.js +24 -7
  82. package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.js.map +1 -1
  83. package/dist/components/admin/GroupMembers/GroupMembers.d.ts +7 -0
  84. package/dist/components/admin/GroupMembers/GroupMembers.d.ts.map +1 -1
  85. package/dist/components/admin/GroupMembers/GroupMembers.js +2 -1
  86. package/dist/components/admin/GroupMembers/GroupMembers.js.map +1 -1
  87. package/dist/components/admin/RoleAssignments/RoleAssignments.d.ts +7 -0
  88. package/dist/components/admin/RoleAssignments/RoleAssignments.d.ts.map +1 -1
  89. package/dist/components/admin/RoleAssignments/RoleAssignments.js +2 -1
  90. package/dist/components/admin/RoleAssignments/RoleAssignments.js.map +1 -1
  91. package/dist/components/admin/UserDetails/BaseUserDetails.d.ts +22 -1
  92. package/dist/components/admin/UserDetails/BaseUserDetails.d.ts.map +1 -1
  93. package/dist/components/admin/UserDetails/BaseUserDetails.js +32 -14
  94. package/dist/components/admin/UserDetails/BaseUserDetails.js.map +1 -1
  95. package/dist/components/admin/UserDetails/UserDetails.d.ts +15 -1
  96. package/dist/components/admin/UserDetails/UserDetails.d.ts.map +1 -1
  97. package/dist/components/admin/UserDetails/UserDetails.js +14 -2
  98. package/dist/components/admin/UserDetails/UserDetails.js.map +1 -1
  99. package/dist/components/admin/shared/AccountLifecycleParts.d.ts +32 -0
  100. package/dist/components/admin/shared/AccountLifecycleParts.d.ts.map +1 -0
  101. package/dist/components/admin/shared/AccountLifecycleParts.js +101 -0
  102. package/dist/components/admin/shared/AccountLifecycleParts.js.map +1 -0
  103. package/dist/components/admin/shared/ApplicationFormFields.js +1 -1
  104. package/dist/components/auth/AcceptInvite/BaseAcceptInvite.d.ts.map +1 -1
  105. package/dist/components/auth/AcceptInvite/BaseAcceptInvite.js +5 -6
  106. package/dist/components/auth/AcceptInvite/BaseAcceptInvite.js.map +1 -1
  107. package/dist/components/auth/SignIn/SignIn.d.ts.map +1 -1
  108. package/dist/components/auth/SignIn/SignIn.js +6 -6
  109. package/dist/components/auth/SignIn/SignIn.js.map +1 -1
  110. package/dist/components/auth/flow/AuthOptionFactory.d.ts.map +1 -1
  111. package/dist/components/auth/flow/AuthOptionFactory.js +5 -6
  112. package/dist/components/auth/flow/AuthOptionFactory.js.map +1 -1
  113. package/dist/components/auth/flow/Consent.d.ts +6 -0
  114. package/dist/components/auth/flow/Consent.d.ts.map +1 -1
  115. package/dist/components/auth/flow/Consent.js +54 -29
  116. package/dist/components/auth/flow/Consent.js.map +1 -1
  117. package/dist/components/auth/flow/ConsentAuthorizationDetail.d.ts +68 -0
  118. package/dist/components/auth/flow/ConsentAuthorizationDetail.d.ts.map +1 -0
  119. package/dist/components/auth/flow/ConsentAuthorizationDetail.js +100 -0
  120. package/dist/components/auth/flow/ConsentAuthorizationDetail.js.map +1 -0
  121. package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.d.ts +10 -0
  122. package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.d.ts.map +1 -0
  123. package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.js +57 -0
  124. package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.js.map +1 -0
  125. package/dist/components/auth/flow/ConsentDetailField.d.ts +39 -0
  126. package/dist/components/auth/flow/ConsentDetailField.d.ts.map +1 -0
  127. package/dist/components/auth/flow/ConsentDetailField.js +168 -0
  128. package/dist/components/auth/flow/ConsentDetailField.js.map +1 -0
  129. package/dist/components/auth/flow/ConsentDetailField.styles.d.ts +11 -0
  130. package/dist/components/auth/flow/ConsentDetailField.styles.d.ts.map +1 -0
  131. package/dist/components/auth/flow/ConsentDetailField.styles.js +83 -0
  132. package/dist/components/auth/flow/ConsentDetailField.styles.js.map +1 -0
  133. package/dist/components/auth/flow/ConsentDetailText.d.ts +53 -0
  134. package/dist/components/auth/flow/ConsentDetailText.d.ts.map +1 -0
  135. package/dist/components/auth/flow/ConsentDetailText.js +58 -0
  136. package/dist/components/auth/flow/ConsentDetailText.js.map +1 -0
  137. package/dist/components/auth/flow/ConsentDetailText.styles.d.ts +20 -0
  138. package/dist/components/auth/flow/ConsentDetailText.styles.d.ts.map +1 -0
  139. package/dist/components/auth/flow/ConsentDetailText.styles.js +80 -0
  140. package/dist/components/auth/flow/ConsentDetailText.styles.js.map +1 -0
  141. package/dist/components/auth/flow/FieldFactory.js +1 -1
  142. package/dist/components/auth/flow/resolveConsentText.d.ts +13 -0
  143. package/dist/components/auth/flow/resolveConsentText.d.ts.map +1 -0
  144. package/dist/components/auth/flow/resolveConsentText.js +23 -0
  145. package/dist/components/auth/flow/resolveConsentText.js.map +1 -0
  146. package/dist/components/primitives/KeyValueInput/KeyValueInput.js +1 -1
  147. package/dist/components/primitives/MultiInput/MultiInput.js +1 -1
  148. package/dist/components/primitives/PasswordField/PasswordField.js +1 -1
  149. package/dist/hooks/auth/useConsentDetailField.d.ts +130 -0
  150. package/dist/hooks/auth/useConsentDetailField.d.ts.map +1 -0
  151. package/dist/hooks/auth/useConsentDetailField.js +354 -0
  152. package/dist/hooks/auth/useConsentDetailField.js.map +1 -0
  153. package/dist/hooks/management/useAccountLifecycle.d.ts +49 -0
  154. package/dist/hooks/management/useAccountLifecycle.d.ts.map +1 -0
  155. package/dist/hooks/management/useAccountLifecycle.js +56 -0
  156. package/dist/hooks/management/useAccountLifecycle.js.map +1 -0
  157. package/dist/index.d.ts +16 -4
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.js +11 -3
  160. package/dist/utils/formatConsentDetailValue.d.ts +16 -0
  161. package/dist/utils/formatConsentDetailValue.d.ts.map +1 -0
  162. package/dist/utils/formatConsentDetailValue.js +25 -0
  163. package/dist/utils/formatConsentDetailValue.js.map +1 -0
  164. package/dist/utils/getConsentDetailLayout.d.ts +32 -0
  165. package/dist/utils/getConsentDetailLayout.d.ts.map +1 -0
  166. package/dist/utils/getConsentDetailLayout.js +43 -0
  167. package/dist/utils/getConsentDetailLayout.js.map +1 -0
  168. package/dist/utils/getConsentDetailListDisplay.d.ts +30 -0
  169. package/dist/utils/getConsentDetailListDisplay.d.ts.map +1 -0
  170. package/dist/utils/getConsentDetailListDisplay.js +30 -0
  171. package/dist/utils/getConsentDetailListDisplay.js.map +1 -0
  172. package/dist/utils/isConsentApprovalBlocked.d.ts +17 -0
  173. package/dist/utils/isConsentApprovalBlocked.d.ts.map +1 -0
  174. package/dist/utils/isConsentApprovalBlocked.js +39 -0
  175. package/dist/utils/isConsentApprovalBlocked.js.map +1 -0
  176. package/dist/utils/isConsentDetailPlainList.d.ts +15 -0
  177. package/dist/utils/isConsentDetailPlainList.d.ts.map +1 -0
  178. package/dist/utils/isConsentDetailPlainList.js +23 -0
  179. package/dist/utils/isConsentDetailPlainList.js.map +1 -0
  180. package/dist/utils/isConsentDetailStructured.d.ts +10 -0
  181. package/dist/utils/isConsentDetailStructured.d.ts.map +1 -0
  182. package/dist/utils/isConsentDetailStructured.js +14 -0
  183. package/dist/utils/isConsentDetailStructured.js.map +1 -0
  184. package/dist/utils/isConsentDetailTextClamped.d.ts +20 -0
  185. package/dist/utils/isConsentDetailTextClamped.d.ts.map +1 -0
  186. package/dist/utils/isConsentDetailTextClamped.js +24 -0
  187. package/dist/utils/isConsentDetailTextClamped.js.map +1 -0
  188. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"AuthOptionFactory.js","names":["logger: ReturnType<typeof createPackageComponentLogger>","richTextClassCache: string | undefined","authOptionIconClassCache: string | undefined","providerId: any","providerMatches: any","theme: any","customRenderers: ComponentRendererMap","key: string | number","customRenderer: ComponentRenderer | undefined","rendered: ReactElement | null","identifier: string","isTouched: boolean","value: string","error: string","fieldType: string","hasPrefixes: boolean","hasPostfix: boolean","prefixStateKey: string","postfixStateKey: string","defaultPrefixValue: string","selectedPrefix: string","AffixedField","reportedLength: number","otpLength: number | undefined","numericOnly: boolean","actionId: string","eventType: string","buttonText: string","componentVariant: string","shouldSkipValidation: boolean","buttonType: HTMLButtonElement['type']","formData: Record<string, any>","consentPrompt: ConsentPromptData | undefined","isDeny: boolean","decisions: ConsentDecisions","socialButtonClassName: string","GoogleButton","GitHubButton","FacebookButton","MicrosoftButton","LinkedInButton","SignInWithEthereumButton","SmsOtpButton","startIconEl: ReactElement | null","endIconEl: ReactElement | null","Button","variant: any","textAlignClass: string","Typography","Divider","selectOptions: any","Select","DatePicker","BaseUserSelect","BaseAuthFlowSelect","BaseUserTypeSelect","formClass: string","blockComponents: any","richTextAction: EmbeddedFlowComponentAction | undefined","syntheticAction: EmbeddedFlowComponent","formData: Record<string, string>","handleRichTextClick: React.MouseEventHandler<HTMLDivElement> | undefined","anchor: HTMLAnchorElement | null","handleRichTextKeyDown: React.KeyboardEventHandler<HTMLDivElement> | undefined","explicitHeight: string","explicitWidth: string","ImageComponent","iconName: string","IconComponent: any","flowIconRegistry","direction: string","gap: number","align: string","justify: string","rawItems: string | number | undefined","parsedItems: number","items: number | null","isColumn: boolean","gridJustify: string","track: string","stackClass: string","stackChildren: (ReactElement | null)[]","consentPromptRawData: ConsentPromptData | string | undefined","Consent","textTemplate: string","timeoutMs: number","FlowTimer","sourceKey: string | undefined","CopyableText","pairs: KeyValuePair[]","KeyValueList"],"sources":["../../../../src/components/auth/flow/AuthOptionFactory.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type {CSSInterpolation} from '@emotion/css/create-instance';\nimport {\n ConsentConstants,\n FieldType,\n FlowMetadataResponse,\n EmbeddedFlowComponent,\n EmbeddedFlowComponentAction,\n EmbeddedFlowComponentType,\n EmbeddedFlowTextVariant,\n EmbeddedFlowEventType,\n createPackageComponentLogger,\n resolveFlowTemplateLiterals,\n resolveEmojiUrisInHtml,\n ConsentPurposeData,\n ConsentPromptData,\n ConsentDecisions,\n ConsentPurposeDecision,\n ConsentAttributeElement,\n OrganizationUnitListResponse,\n PrefixOption,\n KeyValuePair,\n parseKeyValuePairs,\n FetchAuthFlows,\n FetchUserTypes,\n FetchUsers,\n} from '@thunderid/browser';\nimport DOMPurify from 'dompurify';\nimport {ChangeEvent, cloneElement, CSSProperties, FormEvent, ReactElement} from 'react';\nimport Consent from './Consent';\nimport {getConsentOptionalKey} from './ConsentCheckboxList';\nimport {createField} from './FieldFactory';\nimport FlowTimer from './FlowTimer';\nimport ImageComponent from './ImageComponent';\nimport {\n ComponentRenderer,\n ComponentRenderContext,\n ComponentRendererMap,\n} from '../../../contexts/ComponentRenderer/ComponentRendererContext';\nimport {UseTranslation} from '../../../hooks/useTranslation';\nimport {css, cx} from '../../../styles/emotion';\nimport {affixPostfixKey, affixPrefixKey} from '../../../utils/composeAffixedInputs';\nimport AffixedField from '../../primitives/AffixedField/AffixedField';\nimport BaseAuthFlowSelect from '../../primitives/AuthFlowSelect/BaseAuthFlowSelect';\nimport Button from '../../primitives/Button/Button';\nimport CopyableText from '../../primitives/CopyableText/CopyableText';\nimport DatePicker from '../../primitives/DatePicker/DatePicker';\nimport Divider from '../../primitives/Divider/Divider';\nimport flowIconRegistry from '../../primitives/Icons/flowIconRegistry';\nimport KeyValueList from '../../primitives/KeyValueList/KeyValueList';\nimport Select from '../../primitives/Select/Select';\nimport Typography from '../../primitives/Typography/Typography';\nimport {TypographyVariant} from '../../primitives/Typography/Typography.styles';\nimport BaseUserSelect, {BaseUserSelectProps} from '../../primitives/UserSelect/BaseUserSelect';\nimport BaseUserTypeSelect from '../../primitives/UserTypeSelect/BaseUserTypeSelect';\nimport FacebookButton from '../buttons/FacebookButton';\nimport GitHubButton from '../buttons/GitHubButton';\nimport GoogleButton from '../buttons/GoogleButton';\nimport LinkedInButton from '../buttons/LinkedInButton';\nimport MicrosoftButton from '../buttons/MicrosoftButton';\nimport SignInWithEthereumButton from '../buttons/SignInWithEthereumButton';\nimport SmsOtpButton from '../buttons/SmsOtpButton';\n\nconst logger: ReturnType<typeof createPackageComponentLogger> = createPackageComponentLogger(\n '@thunderid/react',\n 'AuthOptionFactory',\n);\n\n/**\n * Replaces `emoji:` URIs embedded in HTML before DOMPurify sanitization.\n *\n * DOMPurify strips unknown URI schemes from attributes (e.g. `src=\"emoji:🦊\"` → `src=\"\"`).\n * This function converts:\n * - `<img src=\"emoji:X\" alt=\"Y\">` → `<span role=\"img\" aria-label=\"Y\">X</span>`\n * - Any remaining `emoji:X` text occurrences → `X`\n */\n\n// This module's functions (renderSignInComponents, etc.) are called imperatively from a\n// component's render, not React components/hooks themselves — so these classes can't be computed\n// at module scope: that runs at import time, before <ThunderIDProvider> has had a chance to\n// configure Emotion's CSP nonce, which would insert them into an un-nonced <style> tag. Instead\n// they're computed lazily, on first actual use (still just once — Emotion's own cache dedupes any\n// further calls to a no-op after that).\nlet richTextClassCache: string | undefined;\n\n/** Ensures rich-text content (including all inner elements from the server) always word-wraps. */\nfunction getRichTextClass(): string {\n richTextClassCache ??= css`\n overflow-wrap: anywhere;\n & * {\n overflow-wrap: anywhere;\n word-break: break-word;\n }\n & .rich-text-align-left {\n text-align: left;\n }\n & .rich-text-align-center {\n text-align: center;\n }\n & .rich-text-align-right {\n text-align: right;\n }\n & .rich-text-align-justify {\n text-align: justify;\n }\n & a,\n & .rich-text-link {\n text-decoration: underline;\n }\n & span[role='img'] {\n display: inline-block;\n }\n `;\n return richTextClassCache;\n}\n\nlet authOptionIconClassCache: string | undefined;\n\nfunction getAuthOptionIconClass(): string {\n authOptionIconClassCache ??= css({height: '1.25em', objectFit: 'contain', width: '1.25em'});\n return authOptionIconClassCache;\n}\n\nexport type AuthType = 'signin' | 'signup' | 'recovery';\n\n/**\n * Get the appropriate FieldType for an input component.\n */\n/** Upper bound on STACK grid slots, so a mistyped `items` cannot render thousands of cells. */\nconst MAX_STACK_ITEMS = 12;\n\nconst getFieldType = (variant: EmbeddedFlowComponentType): FieldType => {\n switch (variant) {\n case EmbeddedFlowComponentType.EmailInput:\n return FieldType.Email;\n case EmbeddedFlowComponentType.PhoneInput:\n return FieldType.Tel;\n case EmbeddedFlowComponentType.PasswordInput:\n return FieldType.Password;\n case EmbeddedFlowComponentType.TextInput:\n default:\n return FieldType.Text;\n }\n};\n\n/**\n * Get typography variant from component variant.\n */\nconst getTypographyVariant = (variant: string): any => {\n const variantMap: Record<EmbeddedFlowTextVariant, TypographyVariant> = {\n BODY_1: 'body1',\n BODY_2: 'body2',\n BUTTON_TEXT: 'button',\n CAPTION: 'caption',\n HEADING_1: 'h1',\n HEADING_2: 'h2',\n HEADING_3: 'h3',\n HEADING_4: 'h4',\n HEADING_5: 'h5',\n HEADING_6: 'h6',\n OVERLINE: 'overline',\n SUBTITLE_1: 'subtitle1',\n SUBTITLE_2: 'subtitle2',\n };\n\n return variantMap[variant] || 'h3';\n};\n\n/**\n * Check if a button text or action matches a social provider.\n */\nconst matchesSocialProvider = (\n actionId: string,\n eventType: string,\n buttonText: string,\n provider: string,\n authType: AuthType,\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n _componentVariant?: string,\n): boolean => {\n const providerId: any = `${provider}_auth`;\n const providerMatches: any = actionId === providerId || eventType === providerId;\n\n // Social buttons usually have \"Sign in with X\" or \"Continue with X\" text,\n // so also check button text for the provider name to increase chances of correct detection (especially for signup flows where action IDs are less standardized)\n if (buttonText.toLowerCase().includes(provider)) {\n return true;\n }\n\n // For signup, also check button text\n if (authType === 'signup') {\n return providerMatches || buttonText.toLowerCase().includes(provider);\n }\n\n return providerMatches;\n};\n\n/**\n * Create an auth component from flow component configuration.\n */\nconst createAuthComponentFromFlow = (\n component: EmbeddedFlowComponent,\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n authType: AuthType,\n options: {\n /** @internal Passed from the host React component so hooks aren't called inside a loop. */\n _customRenderers?: ComponentRendererMap;\n /** @internal Passed from the host React component so hooks aren't called inside a loop. */\n _theme?: any;\n /** Additional data from the flow response, used for different dynamic data */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n /** Current consent purpose being rendered. Set by CONSENT_PURPOSE block iteration. */\n currentConsentPurpose?: ConsentPurposeData;\n inStack?: boolean;\n inputClassName?: string;\n /** Flag to determine if the step timeline has expired */\n isTimeoutDisabled?: boolean;\n key?: string | number;\n /** Data source for AUTH_FLOW_SELECT fields. */\n fetchAuthFlows?: FetchAuthFlows;\n /** Data source for USER_SELECT fields. */\n fetchUsers?: FetchUsers;\n /** Data source for USER_TYPE_SELECT fields. */\n fetchUserTypes?: FetchUserTypes;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n /** Called with the error of a failed picker load. The form itself shows no error for it. */\n onPickerError?: (error: Error) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n } = {},\n): ReactElement | null => {\n const theme: any = options._theme;\n const customRenderers: ComponentRendererMap = options._customRenderers ?? {};\n\n const key: string | number = options.key || component.id;\n\n const customRenderer: ComponentRenderer | undefined =\n customRenderers[component.id] ?? customRenderers[component.type];\n if (customRenderer) {\n const renderCtx: ComponentRenderContext = {\n additionalData: options.additionalData,\n authType,\n formErrors,\n formValues,\n isFormValid,\n isLoading,\n meta: options.meta,\n resetForm,\n onInputBlur: options.onInputBlur,\n onInputChange,\n onSubmit: options.onSubmit,\n touchedFields,\n };\n // Key the element here so a renderer does not have to, as the built-in cases below do.\n const rendered: ReactElement | null = customRenderer(component, renderCtx);\n\n return rendered ? cloneElement(rendered, {key}) : null;\n }\n\n /** Resolve any remaining {{t()}} or {{meta()}} template expressions in a string at render time. */\n const resolve = (text: string | undefined): string => {\n if (!text || (!options.t && !options.meta)) {\n return text || '';\n }\n return resolveFlowTemplateLiterals(text, {meta: options.meta, t: options.t || ((k: string): string => k)});\n };\n\n // The props a flow gives each of the resource pickers (USER_SELECT, AUTH_FLOW_SELECT, USER_TYPE_SELECT).\n const resourceSelectProps = (): Omit<BaseUserSelectProps, 'fetchUsers' | 'mapping'> => {\n const identifier: string = component.ref!;\n const isTouched: boolean = touchedFields[identifier] || false;\n\n return {\n className: cx(options.inputClassName, component.classes),\n component,\n error: isTouched ? formErrors[identifier] : undefined,\n id: component.id,\n label: resolve(component.label) || '',\n name: identifier,\n onBlur: (): void => options.onInputBlur?.(identifier),\n onChange: (event: ChangeEvent<HTMLSelectElement>): void => onInputChange(identifier, event.target.value),\n onError: options.onPickerError,\n placeholder: resolve(component.placeholder),\n required: component.required,\n value: formValues[identifier] || '',\n };\n };\n\n // A component type this render cannot draw is logged and left out.\n const skipUnsupported = (typeName: string): null => {\n logger.warn(`${typeName} component type is not supported. Skipping render.`);\n\n return null;\n };\n\n switch (component.type) {\n case EmbeddedFlowComponentType.TextInput:\n case EmbeddedFlowComponentType.PasswordInput:\n case EmbeddedFlowComponentType.EmailInput:\n case EmbeddedFlowComponentType.PhoneInput: {\n const identifier: string = component.ref!;\n const value: string = formValues[identifier] || '';\n const isTouched: boolean = touchedFields[identifier] || false;\n const error: string = isTouched ? formErrors[identifier] : undefined!;\n const fieldType: string = getFieldType(component.type);\n\n // Prefix/postfix are accepted on any text-family input. When either is present,\n // route to AffixedField so the leading affix renders and submit-time composition\n // is picked up by composeAffixedInputs via the sentinel keys.\n // Both string.length and Array.length are defined, so a single truthy+length\n // check covers `prefixes?: string | PrefixOption[]`.\n const hasPrefixes: boolean = !!component.prefixes && component.prefixes.length > 0;\n const hasPostfix: boolean = typeof component.postfix === 'string' && component.postfix.length > 0;\n\n if (hasPrefixes || hasPostfix) {\n const prefixStateKey: string = affixPrefixKey(identifier, options.vendor);\n const postfixStateKey: string = affixPostfixKey(identifier, options.vendor);\n const defaultPrefixValue: string = hasPrefixes\n ? typeof component.prefixes === 'string'\n ? component.prefixes\n : (component.prefixes as PrefixOption[])[0].value\n : '';\n const selectedPrefix: string = formValues[prefixStateKey] ?? defaultPrefixValue;\n\n return (\n <AffixedField\n key={key}\n className={cx(options.inputClassName, component.classes)}\n id={component.id}\n label={resolve(component.label) || ''}\n name={identifier}\n placeholder={resolve(component.placeholder) || ''}\n required={component.required || false}\n error={error}\n value={value}\n type={fieldType}\n prefixes={component.prefixes}\n prefixValue={selectedPrefix}\n onChange={(e: ChangeEvent<HTMLInputElement>): void => onInputChange(identifier, e.target.value)}\n onBlur={(): void => options.onInputBlur?.(identifier)}\n onPrefixChange={(newPrefix: string): void => onInputChange(prefixStateKey, newPrefix)}\n onFocus={(): void => {\n if (hasPrefixes && formValues[prefixStateKey] === undefined) {\n onInputChange(prefixStateKey, defaultPrefixValue);\n }\n if (hasPostfix && formValues[postfixStateKey] === undefined) {\n onInputChange(postfixStateKey, component.postfix!);\n }\n }}\n />\n );\n }\n\n const field: any = createField({\n className: cx(options.inputClassName, component.classes),\n error,\n id: component.id,\n label: resolve(component.label) || '',\n name: identifier,\n onBlur: () => options.onInputBlur?.(identifier),\n onChange: (newValue: string) => onInputChange(identifier, newValue),\n placeholder: resolve(component.placeholder) || '',\n required: component.required || false,\n type: fieldType as FieldType,\n value,\n });\n\n return cloneElement(field, {key});\n }\n\n case EmbeddedFlowComponentType.OtpInput: {\n const identifier: string = component.ref!;\n const value: string = formValues[identifier] || '';\n const isTouched: boolean = touchedFields[identifier] || false;\n const error: string = isTouched ? formErrors[identifier] : undefined!;\n\n // The server reports the length and character set of the code it generated, so the field\n // matches the OTP the user received. An older server omits both and the defaults apply.\n const reportedLength: number = Number(options.additionalData?.['otpLength']);\n const otpLength: number | undefined =\n Number.isInteger(reportedLength) && reportedLength > 0 ? reportedLength : undefined;\n const numericOnly: boolean = options.additionalData?.['otpNumericOnly'] !== 'false';\n\n const field: any = createField({\n className: cx(options.inputClassName, component.classes),\n error,\n id: component.id,\n label: resolve(component.label) || '',\n length: otpLength,\n name: identifier,\n numericOnly,\n onBlur: () => options.onInputBlur?.(identifier),\n onChange: (newValue: string) => onInputChange(identifier, newValue),\n placeholder: resolve(component.placeholder) || '',\n required: component.required || false,\n type: FieldType.Otp,\n value,\n });\n\n return cloneElement(field, {key});\n }\n\n case EmbeddedFlowComponentType.Action: {\n const actionId: string = component.id;\n const eventType: string = component.eventType || '';\n const buttonText: string = resolve(component.label);\n const componentVariant: string = component.variant || '';\n\n // Only validate on submit type events.\n const shouldSkipValidation: boolean = eventType.toUpperCase() !== EmbeddedFlowEventType.Submit;\n\n // Determine the button type based on the event type. Default to 'submit' if not recognized.\n const buttonTypeEnum = {\n [EmbeddedFlowEventType.Submit]: 'submit',\n [EmbeddedFlowEventType.Reset]: 'reset',\n [EmbeddedFlowEventType.Cancel]: 'button',\n [EmbeddedFlowEventType.Trigger]: 'button',\n [EmbeddedFlowEventType.Back]: 'button',\n };\n const buttonType: HTMLButtonElement['type'] = buttonTypeEnum[eventType.toUpperCase()] ?? 'submit';\n\n const handleClick = (): any => {\n if (options.onSubmit) {\n const formData: Record<string, any> = {};\n Object.keys(formValues).forEach((field: any) => {\n // Include all values, even empty strings, to ensure proper submission\n formData[field] = formValues[field];\n });\n\n // For consent actions, build the consent_decisions JSON from the form values.\n // The allow action captures per-attribute choices; the deny action sends\n // all purposes as rejected so the backend ConsentExecutor can fail the flow.\n const consentPrompt: ConsentPromptData | undefined = options.additionalData?.['consentPrompt'] as\n | ConsentPromptData\n | undefined;\n if (consentPrompt && eventType.toUpperCase() === EmbeddedFlowEventType.Submit) {\n const isDeny: boolean = componentVariant.toLowerCase() !== 'primary';\n const decisions: ConsentDecisions = {\n approved: !isDeny,\n ...(isDeny ? {reason: ConsentConstants.REASON_USER_DENIED} : {}),\n purposes: consentPrompt.purposes.map(\n (p: ConsentPurposeData): ConsentPurposeDecision => ({\n approved: !isDeny,\n elements: [\n // Permission purposes carry no essential elements, so the server sends null here\n ...(p.essential ?? []).map((e): ConsentAttributeElement => ({approved: !isDeny, name: e.name})),\n ...(p.optional ?? []).map(\n (e): ConsentAttributeElement => ({\n approved: !isDeny && formValues[getConsentOptionalKey(p.purposeId, e.name)] === 'true',\n name: e.name,\n }),\n ),\n ],\n purposeName: p.purposeName!,\n }),\n ),\n };\n formData['consent_decisions'] = JSON.stringify(decisions);\n }\n\n // For submit events, pass the form data to the onSubmit callback. For other event types, reset the form and call onSubmit with an empty data object.\n if (eventType.toUpperCase() === EmbeddedFlowEventType.Submit) {\n options.onSubmit(component, formData, shouldSkipValidation);\n } else {\n resetForm();\n options.onSubmit(component, {}, shouldSkipValidation);\n }\n }\n };\n\n // Render branded social login buttons for known action IDs\n\n const socialButtonClassName: string = cx(options.buttonClassName, component.classes);\n\n if (matchesSocialProvider(actionId, eventType, buttonText, 'google', authType, componentVariant)) {\n return <GoogleButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'github', authType, componentVariant)) {\n return <GitHubButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'facebook', authType, componentVariant)) {\n return <FacebookButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'microsoft', authType, componentVariant)) {\n return <MicrosoftButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'linkedin', authType, componentVariant)) {\n return <LinkedInButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'ethereum', authType, componentVariant)) {\n return (\n <SignInWithEthereumButton\n key={key}\n id={component.id}\n onClick={handleClick}\n className={socialButtonClassName}\n />\n );\n }\n if (actionId === 'prompt_mobile' || eventType === 'prompt_mobile') {\n return <SmsOtpButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n\n const startIconEl: ReactElement | null = component.startIcon ? (\n <img src={component.startIcon} alt=\"\" aria-hidden=\"true\" className={getAuthOptionIconClass()} />\n ) : null;\n\n const endIconEl: ReactElement | null = component.endIcon ? (\n <img src={component.endIcon} alt=\"\" aria-hidden=\"true\" className={getAuthOptionIconClass()} />\n ) : null;\n\n return (\n <Button\n fullWidth\n key={key}\n id={component.id}\n onClick={handleClick}\n disabled={\n isLoading ||\n (!isFormValid && !shouldSkipValidation) ||\n options.isTimeoutDisabled ||\n (component as any).config?.disabled\n }\n className={cx(options.buttonClassName, component.classes)}\n data-testid=\"thunderid-signin-submit\"\n variant={component.variant?.toLowerCase() === 'primary' ? 'solid' : 'outline'}\n color={component.variant?.toLowerCase() === 'primary' ? 'primary' : 'secondary'}\n startIcon={startIconEl}\n endIcon={endIconEl}\n type={buttonType}\n >\n {buttonText || 'Submit'}\n </Button>\n );\n }\n\n case EmbeddedFlowComponentType.Text: {\n const variant: any = getTypographyVariant(component.variant!);\n const textAlignClass: string = css({\n marginBottom: 2,\n textAlign:\n typeof component?.align === 'string' ? (component.align as React.CSSProperties['textAlign']) : 'left',\n });\n return (\n <Typography key={key} id={component.id} className={cx(component.classes, textAlignClass)} variant={variant}>\n {resolve(component.label)}\n </Typography>\n );\n }\n\n case EmbeddedFlowComponentType.Divider: {\n return <Divider key={key}>{resolve(component.label) || ''}</Divider>;\n }\n\n case EmbeddedFlowComponentType.Select: {\n const identifier: string = component.ref!;\n const value: string = formValues[identifier] || '';\n const isTouched: boolean = touchedFields[identifier] || false;\n const error: string = isTouched ? formErrors[identifier] : undefined!;\n\n // Options are pre-sanitized by flowTransformer to {value: string, label: string} format\n const selectOptions: any = (component.options || []).map((opt: any) => ({\n label: typeof opt === 'string' ? opt : String(opt.label ?? opt.value ?? ''),\n value: typeof opt === 'string' ? opt : String(opt.value ?? ''),\n }));\n\n return (\n <Select\n key={key}\n id={component.id}\n name={identifier}\n label={resolve(component.label) || ''}\n placeholder={resolve(component.placeholder)}\n required={component.required}\n options={selectOptions}\n value={value}\n error={error}\n onChange={(e: any): void => onInputChange(identifier, e.target.value)}\n onBlur={(): any => options.onInputBlur?.(identifier)}\n className={cx(options.inputClassName, component.classes)}\n />\n );\n }\n\n case EmbeddedFlowComponentType.DateInput: {\n const identifier: string = component.ref!;\n const value: string = formValues[identifier] || '';\n const isTouched: boolean = touchedFields[identifier] || false;\n const error: string = isTouched ? formErrors[identifier] : undefined!;\n\n return (\n <DatePicker\n key={key}\n id={component.id}\n name={identifier}\n label={resolve(component.label) || ''}\n placeholder={resolve(component.placeholder)}\n required={component.required}\n dateFormat={component.dateFormat}\n value={value}\n error={error}\n onChange={(e: any): void => onInputChange(identifier, e.target.value)}\n onBlur={(): any => options.onInputBlur?.(identifier)}\n className={cx(options.inputClassName, component.classes)}\n />\n );\n }\n\n case EmbeddedFlowComponentType.OuSelect:\n return skipUnsupported('OU_SELECT');\n\n // The resource pickers load with a signed-in user's access token, so without a data source, which is every flow\n // except InviteUser, they are not drawn.\n case EmbeddedFlowComponentType.UserSelect:\n return options.fetchUsers ? (\n <BaseUserSelect key={key} {...resourceSelectProps()} fetchUsers={options.fetchUsers} />\n ) : (\n skipUnsupported('USER_SELECT')\n );\n\n case EmbeddedFlowComponentType.AuthFlowSelect:\n return options.fetchAuthFlows ? (\n <BaseAuthFlowSelect key={key} {...resourceSelectProps()} fetchAuthFlows={options.fetchAuthFlows} />\n ) : (\n skipUnsupported('AUTH_FLOW_SELECT')\n );\n\n case EmbeddedFlowComponentType.UserTypeSelect:\n return options.fetchUserTypes ? (\n <BaseUserTypeSelect key={key} {...resourceSelectProps()} fetchUserTypes={options.fetchUserTypes} />\n ) : (\n skipUnsupported('USER_TYPE_SELECT')\n );\n\n case EmbeddedFlowComponentType.Block: {\n if (component.components && component.components.length > 0) {\n const formClass: string = css({\n display: 'flex',\n flexDirection: 'column',\n gap: `calc(${theme?.vars?.spacing?.unit ?? '4px'} * 2)`,\n });\n\n const blockComponents: any = component.components\n .map((childComponent: any, index: any) =>\n createAuthComponentFromFlow(\n childComponent,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n authType,\n {\n ...options,\n key: childComponent.id || `${component.id}_${index}`,\n },\n ),\n )\n .filter(Boolean);\n\n // The submit button's `type=\"submit\"` (and pressing Enter in a field) would\n // otherwise trigger the browser's native form submission — a GET request to\n // the current URL with all field values (including passwords) as query params.\n // Actual submission is handled entirely via `onClick`/`onSubmit` above.\n return (\n <form\n id={component.id}\n key={key}\n className={cx(component.classes, formClass)}\n onSubmit={(event: FormEvent<HTMLFormElement>): void => event.preventDefault()}\n >\n {blockComponents}\n </form>\n );\n }\n return null;\n }\n\n case EmbeddedFlowComponentType.RichText: {\n const richTextAction: EmbeddedFlowComponentAction | undefined = component.action;\n\n const dispatchRichTextAction = (): void => {\n if (!richTextAction || !options.onSubmit) {\n return;\n }\n const eventTypeValue = String(richTextAction.eventType ?? EmbeddedFlowEventType.Submit);\n const shouldSkipValidation: boolean = eventTypeValue.toUpperCase() === String(EmbeddedFlowEventType.Trigger);\n const syntheticAction: EmbeddedFlowComponent = {\n eventType: eventTypeValue,\n id: `${component.id}_action`,\n ref: richTextAction.ref,\n type: EmbeddedFlowComponentType.Action,\n };\n const formData: Record<string, string> = {};\n Object.keys(formValues).forEach((field: string) => {\n formData[field] = formValues[field];\n });\n options.onSubmit(syntheticAction, formData, shouldSkipValidation);\n };\n\n // Sentinel-anchor contract: only anchors carrying `data-action-ref` equal to\n // richTextAction.ref dispatch the action. Anchors without the sentinel (or with\n // a non-matching one) are treated as ordinary links and are ignored here.\n const isMatchingSentinelAnchor = (anchor: HTMLAnchorElement): boolean =>\n anchor.getAttribute('data-action-ref') === richTextAction?.ref;\n\n const handleRichTextClick: React.MouseEventHandler<HTMLDivElement> | undefined = richTextAction\n ? (event: React.MouseEvent<HTMLDivElement>): void => {\n const anchor: HTMLAnchorElement | null = (event.target as HTMLElement).closest('a');\n if (!anchor || !isMatchingSentinelAnchor(anchor)) {\n return;\n }\n event.preventDefault();\n dispatchRichTextAction();\n }\n : undefined;\n\n const handleRichTextKeyDown: React.KeyboardEventHandler<HTMLDivElement> | undefined = richTextAction\n ? (event: React.KeyboardEvent<HTMLDivElement>): void => {\n if (event.key !== 'Enter' && event.key !== ' ') {\n return;\n }\n const anchor: HTMLAnchorElement | null = (event.target as HTMLElement).closest('a');\n if (!anchor || !isMatchingSentinelAnchor(anchor)) {\n return;\n }\n event.preventDefault();\n dispatchRichTextAction();\n }\n : undefined;\n\n return (\n // Sentinel anchors are made keyboard-operable via the container's onKeyDown\n // (Enter/Space activate the matching anchor). Authors should ensure the anchor\n // is focusable (`href` or `tabIndex`); the click+keydown delegation covers both\n // pointer and keyboard activation once focus lands on the anchor.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n key={key}\n className={getRichTextClass()}\n onClick={handleRichTextClick}\n onKeyDown={handleRichTextKeyDown}\n // Manually sanitizes with `DOMPurify`.\n // IMPORTANT: DO NOT REMOVE OR MODIFY THIS SANITIZATION STEP.\n dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(resolveEmojiUrisInHtml(resolve(component.label)))}}\n />\n );\n }\n\n case EmbeddedFlowComponentType.Image: {\n const explicitHeight: string = resolve(component.height?.toString());\n const explicitWidth: string = resolve(component.width?.toString());\n return (\n <ImageComponent\n key={key}\n component={\n {\n config: {\n alt: resolve(component.alt) || resolve(component.label) || 'Image',\n height: explicitHeight || (options.inStack ? '50' : 'auto'),\n src: resolve(component.src),\n width: explicitWidth || (options.inStack ? '50' : '100%'),\n },\n } as any\n }\n formErrors={undefined!}\n formValues={undefined!}\n isFormValid={false}\n isLoading={false}\n onInputChange={(): void => {\n throw new Error('Function not implemented.');\n }}\n touchedFields={undefined!}\n />\n );\n }\n\n case EmbeddedFlowComponentType.Icon: {\n const iconName: string = component.name || '';\n const IconComponent: any = flowIconRegistry[iconName];\n if (!IconComponent) {\n logger.warn(`Unknown icon name: \"${iconName}\". Skipping render.`);\n return null;\n }\n return <IconComponent key={key} size={component.size || 24} color={component.color || 'currentColor'} />;\n }\n\n case EmbeddedFlowComponentType.Stack: {\n const direction: string = (component as any).direction || 'row';\n const gap: number = (component as any).gap ?? 2;\n const align: string = (component as any).align || 'center';\n const justify: string = (component as any).justify || 'flex-start';\n\n // `items` is the number of slots across the main axis and `direction` picks\n // that axis: with `row` it is the column count (items: 2 with four buttons\n // renders a 2 x 2 grid), and with `column` it is the row count and children\n // flow into further columns. Fewer than two slots keeps the flex layout, so\n // stacks authored before grid support are unaffected.\n const rawItems: string | number | undefined = component.items;\n const parsedItems: number =\n typeof rawItems === 'string' ? Number(rawItems) : typeof rawItems === 'number' ? rawItems : NaN;\n const items: number | null =\n Number.isFinite(parsedItems) && Math.floor(parsedItems) >= 2\n ? Math.min(Math.floor(parsedItems), MAX_STACK_ITEMS)\n : null;\n // CSS Grid has no reverse auto-flow, so the reverse variants fall back to\n // their base axis rather than silently becoming a row.\n const isColumn: boolean = direction.startsWith('column');\n const gridJustify: string = component.justify ?? 'stretch';\n // Equal `1fr` tracks fill the container, leaving `justify-content` no free\n // space to distribute. Content-sized tracks restore it, so every justify\n // value has a visible effect while the default stays an even split.\n const track: string = gridJustify === 'stretch' ? '1fr' : 'auto';\n\n const stackStyle: CSSProperties =\n items !== null\n ? {\n alignItems: component.align ?? 'stretch',\n display: 'grid',\n gap: `${gap * 0.5}rem`,\n gridAutoFlow: isColumn ? 'column' : 'row',\n justifyContent: gridJustify,\n width: '100%',\n ...(isColumn\n ? {gridTemplateRows: `repeat(${items}, ${track})`}\n : {gridTemplateColumns: `repeat(${items}, ${track})`}),\n }\n : {\n alignItems: align,\n display: 'flex',\n flexDirection: direction as CSSProperties['flexDirection'],\n flexWrap: 'wrap',\n gap: `${gap * 0.5}rem`,\n justifyContent: justify,\n };\n\n const stackClass: string = css(stackStyle as CSSInterpolation);\n\n const stackChildren: (ReactElement | null)[] = component.components\n ? component.components.map((childComponent: any, index: number) =>\n createAuthComponentFromFlow(\n childComponent,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n authType,\n {\n ...options,\n inStack: true,\n key: childComponent.id || `${component.id}_${index}`,\n },\n ),\n )\n : [];\n\n return (\n <div key={key} id={component.id} className={cx(component.classes, stackClass)}>\n {stackChildren}\n </div>\n );\n }\n\n case EmbeddedFlowComponentType.Consent: {\n const consentPromptRawData: ConsentPromptData | string | undefined = options.additionalData?.['consentPrompt'];\n\n return (\n <Consent\n key={key}\n consentData={consentPromptRawData as any}\n formValues={formValues}\n onInputChange={onInputChange}\n t={options.t}\n />\n );\n }\n\n case EmbeddedFlowComponentType.Timer: {\n const textTemplate: string = resolve((component as any).label) || 'Time remaining: {time}';\n const timeoutMs: number = Number(options.additionalData?.['stepTimeout']) || 0;\n const expiresIn: number = timeoutMs > 0 ? Math.max(0, Math.floor((timeoutMs - Date.now()) / 1000)) : 0;\n\n return <FlowTimer key={key} expiresIn={expiresIn} textTemplate={textTemplate} />;\n }\n\n case EmbeddedFlowComponentType.CopyableText: {\n const sourceKey: string | undefined = (component as any).source;\n const value: string = sourceKey && options.additionalData ? String(options.additionalData[sourceKey] ?? '') : '';\n const labelText: string | undefined = resolve((component as any).label) || undefined;\n\n return <CopyableText key={key} label={labelText} masked={Boolean(component.masked)} value={value} />;\n }\n\n case EmbeddedFlowComponentType.KeyValueList: {\n const sourceKey: string | undefined = component.source;\n const pairs: KeyValuePair[] = parseKeyValuePairs(\n sourceKey && options.additionalData ? options.additionalData[sourceKey] : undefined,\n ).map((pair: KeyValuePair) => ({...pair, label: resolve(pair.label)}));\n\n // An empty panel tells the user nothing, so a list with no pairs renders nothing at all.\n if (pairs.length === 0) {\n return null;\n }\n\n return <KeyValueList key={key} label={resolve(component.label) || undefined} pairs={pairs} />;\n }\n\n default:\n // Gracefully handle unsupported component types by returning null\n logger.warn(`Unsupported component type: ${component.type}. Skipping render.`);\n return null;\n }\n};\n\n/**\n * Processes an array of components and renders them as React elements for sign-in.\n */\nexport const renderSignInComponents = (\n components: EmbeddedFlowComponent[],\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n options?: {\n /** @internal */\n _customRenderers?: ComponentRendererMap;\n /** @internal */\n _theme?: any;\n /** Additional data from the flow response */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n inputClassName?: string;\n /** Flag to determine if the step timeline has expired */\n isTimeoutDisabled?: boolean;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n },\n): ReactElement[] =>\n components\n .map((component: any, index: any) =>\n createAuthComponentFromFlow(\n component,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n 'signin',\n {\n ...options,\n key: component.id || index,\n },\n ),\n )\n .filter((x): x is ReactElement => x !== null);\n\n/**\n * Processes an array of components and renders them as React elements for sign-up.\n */\nexport const renderSignUpComponents = (\n components: EmbeddedFlowComponent[],\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n options?: {\n /** @internal */\n _customRenderers?: ComponentRendererMap;\n /** @internal */\n _theme?: any;\n /** Additional data from the flow response */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n inputClassName?: string;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n },\n): ReactElement[] =>\n components\n .map((component: any, index: any) =>\n createAuthComponentFromFlow(\n component,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n 'signup',\n {\n ...options,\n key: component.id || index,\n },\n ),\n )\n .filter((x): x is ReactElement => x !== null);\n\n/**\n * Processes an array of components and renders them as React elements for recovery flow.\n */\nexport const renderRecoveryComponents = (\n components: EmbeddedFlowComponent[],\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n options?: {\n /** @internal */\n _customRenderers?: ComponentRendererMap;\n /** @internal */\n _theme?: any;\n /** Additional data from the flow response */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n inputClassName?: string;\n /** Flag to determine if the step timeline has expired */\n isTimeoutDisabled?: boolean;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n },\n): ReactElement[] =>\n components\n .map((component: any, index: any) =>\n createAuthComponentFromFlow(\n component,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n 'recovery',\n {\n ...options,\n key: component.id || index,\n },\n ),\n )\n .filter((x): x is ReactElement => x !== null);\n\n/**\n * Processes an array of components and renders them as React elements for invite user.\n * This is used by both InviteUser and AcceptInvite components.\n */\nexport const renderInviteUserComponents = (\n components: EmbeddedFlowComponent[],\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n options?: {\n /** @internal */\n _customRenderers?: ComponentRendererMap;\n /** @internal */\n _theme?: any;\n /** Additional data from the flow response */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n /** Function to fetch child organization units for OU_SELECT components. */\n fetchOrganizationUnitChildren?: (\n parentId: string,\n limit: number,\n offset: number,\n ) => Promise<OrganizationUnitListResponse>;\n inputClassName?: string;\n /** Data source for AUTH_FLOW_SELECT fields. */\n fetchAuthFlows?: FetchAuthFlows;\n /** Data source for USER_SELECT fields. */\n fetchUsers?: FetchUsers;\n /** Data source for USER_TYPE_SELECT fields. */\n fetchUserTypes?: FetchUserTypes;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n /** Called with the error of a failed picker load. The form itself shows no error for it. */\n onPickerError?: (error: Error) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n },\n): ReactElement[] =>\n components\n .map((component: any, index: any) =>\n createAuthComponentFromFlow(\n component,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n 'signup',\n {\n ...options,\n key: component.id || index,\n },\n ),\n )\n .filter((x): x is ReactElement => x !== null);\n"],"mappings":"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"}
1
+ {"version":3,"file":"AuthOptionFactory.js","names":["logger: ReturnType<typeof createPackageComponentLogger>","richTextClassCache: string | undefined","authOptionIconClassCache: string | undefined","providerId: any","providerMatches: any","theme: any","customRenderers: ComponentRendererMap","key: string | number","customRenderer: ComponentRenderer | undefined","rendered: ReactElement | null","identifier: string","isTouched: boolean","value: string","error: string","fieldType: string","hasPrefixes: boolean","hasPostfix: boolean","prefixStateKey: string","postfixStateKey: string","defaultPrefixValue: string","selectedPrefix: string","AffixedField","reportedLength: number","otpLength: number | undefined","numericOnly: boolean","actionId: string","eventType: string","buttonText: string","componentVariant: string","shouldSkipValidation: boolean","buttonType: HTMLButtonElement['type']","hasInvalidConsentApproval: boolean","isConsentApprovalBlocked","formData: Record<string, any>","consentPrompt: ConsentPromptData | undefined","isDeny: boolean","decisions: ConsentDecisions","socialButtonClassName: string","GoogleButton","GitHubButton","FacebookButton","MicrosoftButton","LinkedInButton","SignInWithEthereumButton","SmsOtpButton","startIconEl: ReactElement | null","endIconEl: ReactElement | null","Button","variant: any","textAlignClass: string","Typography","Divider","selectOptions: any","Select","DatePicker","BaseUserSelect","BaseAuthFlowSelect","BaseUserTypeSelect","formClass: string","blockComponents: any","richTextAction: EmbeddedFlowComponentAction | undefined","syntheticAction: EmbeddedFlowComponent","formData: Record<string, string>","handleRichTextClick: React.MouseEventHandler<HTMLDivElement> | undefined","anchor: HTMLAnchorElement | null","handleRichTextKeyDown: React.KeyboardEventHandler<HTMLDivElement> | undefined","explicitHeight: string","explicitWidth: string","ImageComponent","iconName: string","IconComponent: any","flowIconRegistry","direction: string","gap: number","align: string","justify: string","rawItems: string | number | undefined","parsedItems: number","items: number | null","isColumn: boolean","gridJustify: string","track: string","stackClass: string","stackChildren: (ReactElement | null)[]","consentPromptRawData: ConsentPromptData | string | undefined","Consent","textTemplate: string","timeoutMs: number","FlowTimer","sourceKey: string | undefined","CopyableText","pairs: KeyValuePair[]","KeyValueList"],"sources":["../../../../src/components/auth/flow/AuthOptionFactory.tsx"],"sourcesContent":["// Copyright 2025 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type {CSSInterpolation} from '@emotion/css/create-instance';\nimport {\n ConsentConstants,\n FieldType,\n FlowMetadataResponse,\n EmbeddedFlowComponent,\n EmbeddedFlowComponentAction,\n EmbeddedFlowComponentType,\n EmbeddedFlowTextVariant,\n EmbeddedFlowEventType,\n createPackageComponentLogger,\n resolveFlowTemplateLiterals,\n resolveEmojiUrisInHtml,\n ConsentPurposeData,\n ConsentPromptData,\n ConsentDecisions,\n ConsentPurposeDecision,\n ConsentAttributeElement,\n OrganizationUnitListResponse,\n PrefixOption,\n KeyValuePair,\n parseKeyValuePairs,\n FetchAuthFlows,\n FetchUserTypes,\n FetchUsers,\n getConsentElementDecision,\n} from '@thunderid/browser';\nimport DOMPurify from 'dompurify';\nimport {ChangeEvent, cloneElement, CSSProperties, FormEvent, ReactElement} from 'react';\nimport Consent from './Consent';\nimport {getConsentOptionalKey} from './ConsentCheckboxList';\nimport {createField} from './FieldFactory';\nimport FlowTimer from './FlowTimer';\nimport ImageComponent from './ImageComponent';\nimport {\n ComponentRenderer,\n ComponentRenderContext,\n ComponentRendererMap,\n} from '../../../contexts/ComponentRenderer/ComponentRendererContext';\nimport {UseTranslation} from '../../../hooks/useTranslation';\nimport {css, cx} from '../../../styles/emotion';\nimport {affixPostfixKey, affixPrefixKey} from '../../../utils/composeAffixedInputs';\nimport isConsentApprovalBlocked from '../../../utils/isConsentApprovalBlocked';\nimport AffixedField from '../../primitives/AffixedField/AffixedField';\nimport BaseAuthFlowSelect from '../../primitives/AuthFlowSelect/BaseAuthFlowSelect';\nimport Button from '../../primitives/Button/Button';\nimport CopyableText from '../../primitives/CopyableText/CopyableText';\nimport DatePicker from '../../primitives/DatePicker/DatePicker';\nimport Divider from '../../primitives/Divider/Divider';\nimport flowIconRegistry from '../../primitives/Icons/flowIconRegistry';\nimport KeyValueList from '../../primitives/KeyValueList/KeyValueList';\nimport Select from '../../primitives/Select/Select';\nimport Typography from '../../primitives/Typography/Typography';\nimport {TypographyVariant} from '../../primitives/Typography/Typography.styles';\nimport BaseUserSelect, {BaseUserSelectProps} from '../../primitives/UserSelect/BaseUserSelect';\nimport BaseUserTypeSelect from '../../primitives/UserTypeSelect/BaseUserTypeSelect';\nimport FacebookButton from '../buttons/FacebookButton';\nimport GitHubButton from '../buttons/GitHubButton';\nimport GoogleButton from '../buttons/GoogleButton';\nimport LinkedInButton from '../buttons/LinkedInButton';\nimport MicrosoftButton from '../buttons/MicrosoftButton';\nimport SignInWithEthereumButton from '../buttons/SignInWithEthereumButton';\nimport SmsOtpButton from '../buttons/SmsOtpButton';\n\nconst logger: ReturnType<typeof createPackageComponentLogger> = createPackageComponentLogger(\n '@thunderid/react',\n 'AuthOptionFactory',\n);\n\n/**\n * Replaces `emoji:` URIs embedded in HTML before DOMPurify sanitization.\n *\n * DOMPurify strips unknown URI schemes from attributes (e.g. `src=\"emoji:🦊\"` → `src=\"\"`).\n * This function converts:\n * - `<img src=\"emoji:X\" alt=\"Y\">` → `<span role=\"img\" aria-label=\"Y\">X</span>`\n * - Any remaining `emoji:X` text occurrences → `X`\n */\n\n// This module's functions (renderSignInComponents, etc.) are called imperatively from a\n// component's render, not React components/hooks themselves — so these classes can't be computed\n// at module scope: that runs at import time, before <ThunderIDProvider> has had a chance to\n// configure Emotion's CSP nonce, which would insert them into an un-nonced <style> tag. Instead\n// they're computed lazily, on first actual use (still just once — Emotion's own cache dedupes any\n// further calls to a no-op after that).\nlet richTextClassCache: string | undefined;\n\n/** Ensures rich-text content (including all inner elements from the server) always word-wraps. */\nfunction getRichTextClass(): string {\n richTextClassCache ??= css`\n overflow-wrap: anywhere;\n & * {\n overflow-wrap: anywhere;\n word-break: break-word;\n }\n & .rich-text-align-left {\n text-align: left;\n }\n & .rich-text-align-center {\n text-align: center;\n }\n & .rich-text-align-right {\n text-align: right;\n }\n & .rich-text-align-justify {\n text-align: justify;\n }\n & a,\n & .rich-text-link {\n text-decoration: underline;\n }\n & span[role='img'] {\n display: inline-block;\n }\n `;\n return richTextClassCache;\n}\n\nlet authOptionIconClassCache: string | undefined;\n\nfunction getAuthOptionIconClass(): string {\n authOptionIconClassCache ??= css({height: '1.25em', objectFit: 'contain', width: '1.25em'});\n return authOptionIconClassCache;\n}\n\nexport type AuthType = 'signin' | 'signup' | 'recovery';\n\n/**\n * Get the appropriate FieldType for an input component.\n */\n/** Upper bound on STACK grid slots, so a mistyped `items` cannot render thousands of cells. */\nconst MAX_STACK_ITEMS = 12;\n\nconst getFieldType = (variant: EmbeddedFlowComponentType): FieldType => {\n switch (variant) {\n case EmbeddedFlowComponentType.EmailInput:\n return FieldType.Email;\n case EmbeddedFlowComponentType.PhoneInput:\n return FieldType.Tel;\n case EmbeddedFlowComponentType.PasswordInput:\n return FieldType.Password;\n case EmbeddedFlowComponentType.TextInput:\n default:\n return FieldType.Text;\n }\n};\n\n/**\n * Get typography variant from component variant.\n */\nconst getTypographyVariant = (variant: string): any => {\n const variantMap: Record<EmbeddedFlowTextVariant, TypographyVariant> = {\n BODY_1: 'body1',\n BODY_2: 'body2',\n BUTTON_TEXT: 'button',\n CAPTION: 'caption',\n HEADING_1: 'h1',\n HEADING_2: 'h2',\n HEADING_3: 'h3',\n HEADING_4: 'h4',\n HEADING_5: 'h5',\n HEADING_6: 'h6',\n OVERLINE: 'overline',\n SUBTITLE_1: 'subtitle1',\n SUBTITLE_2: 'subtitle2',\n };\n\n return variantMap[variant] || 'h3';\n};\n\n/**\n * Check if a button text or action matches a social provider.\n */\nconst matchesSocialProvider = (\n actionId: string,\n eventType: string,\n buttonText: string,\n provider: string,\n authType: AuthType,\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n _componentVariant?: string,\n): boolean => {\n const providerId: any = `${provider}_auth`;\n const providerMatches: any = actionId === providerId || eventType === providerId;\n\n // Social buttons usually have \"Sign in with X\" or \"Continue with X\" text,\n // so also check button text for the provider name to increase chances of correct detection (especially for signup flows where action IDs are less standardized)\n if (buttonText.toLowerCase().includes(provider)) {\n return true;\n }\n\n // For signup, also check button text\n if (authType === 'signup') {\n return providerMatches || buttonText.toLowerCase().includes(provider);\n }\n\n return providerMatches;\n};\n\n/**\n * Create an auth component from flow component configuration.\n */\nconst createAuthComponentFromFlow = (\n component: EmbeddedFlowComponent,\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n authType: AuthType,\n options: {\n /** @internal Passed from the host React component so hooks aren't called inside a loop. */\n _customRenderers?: ComponentRendererMap;\n /** @internal Passed from the host React component so hooks aren't called inside a loop. */\n _theme?: any;\n /** Additional data from the flow response, used for different dynamic data */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n /** Current consent purpose being rendered. Set by CONSENT_PURPOSE block iteration. */\n currentConsentPurpose?: ConsentPurposeData;\n inStack?: boolean;\n inputClassName?: string;\n /** Flag to determine if the step timeline has expired */\n isTimeoutDisabled?: boolean;\n key?: string | number;\n /** Data source for AUTH_FLOW_SELECT fields. */\n fetchAuthFlows?: FetchAuthFlows;\n /** Data source for USER_SELECT fields. */\n fetchUsers?: FetchUsers;\n /** Data source for USER_TYPE_SELECT fields. */\n fetchUserTypes?: FetchUserTypes;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n /** Called with the error of a failed picker load. The form itself shows no error for it. */\n onPickerError?: (error: Error) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n } = {},\n): ReactElement | null => {\n const theme: any = options._theme;\n const customRenderers: ComponentRendererMap = options._customRenderers ?? {};\n\n const key: string | number = options.key || component.id;\n\n const customRenderer: ComponentRenderer | undefined =\n customRenderers[component.id] ?? customRenderers[component.type];\n if (customRenderer) {\n const renderCtx: ComponentRenderContext = {\n additionalData: options.additionalData,\n authType,\n formErrors,\n formValues,\n isFormValid,\n isLoading,\n meta: options.meta,\n resetForm,\n onInputBlur: options.onInputBlur,\n onInputChange,\n onSubmit: options.onSubmit,\n touchedFields,\n };\n // Key the element here so a renderer does not have to, as the built-in cases below do.\n const rendered: ReactElement | null = customRenderer(component, renderCtx);\n\n return rendered ? cloneElement(rendered, {key}) : null;\n }\n\n /** Resolve any remaining {{t()}} or {{meta()}} template expressions in a string at render time. */\n const resolve = (text: string | undefined): string => {\n if (!text || (!options.t && !options.meta)) {\n return text || '';\n }\n return resolveFlowTemplateLiterals(text, {meta: options.meta, t: options.t || ((k: string): string => k)});\n };\n\n // The props a flow gives each of the resource pickers (USER_SELECT, AUTH_FLOW_SELECT, USER_TYPE_SELECT).\n const resourceSelectProps = (): Omit<BaseUserSelectProps, 'fetchUsers' | 'mapping'> => {\n const identifier: string = component.ref!;\n const isTouched: boolean = touchedFields[identifier] || false;\n\n return {\n className: cx(options.inputClassName, component.classes),\n component,\n error: isTouched ? formErrors[identifier] : undefined,\n id: component.id,\n label: resolve(component.label) || '',\n name: identifier,\n onBlur: (): void => options.onInputBlur?.(identifier),\n onChange: (event: ChangeEvent<HTMLSelectElement>): void => onInputChange(identifier, event.target.value),\n onError: options.onPickerError,\n placeholder: resolve(component.placeholder),\n required: component.required,\n value: formValues[identifier] || '',\n };\n };\n\n // A component type this render cannot draw is logged and left out.\n const skipUnsupported = (typeName: string): null => {\n logger.warn(`${typeName} component type is not supported. Skipping render.`);\n\n return null;\n };\n\n switch (component.type) {\n case EmbeddedFlowComponentType.TextInput:\n case EmbeddedFlowComponentType.PasswordInput:\n case EmbeddedFlowComponentType.EmailInput:\n case EmbeddedFlowComponentType.PhoneInput: {\n const identifier: string = component.ref!;\n const value: string = formValues[identifier] || '';\n const isTouched: boolean = touchedFields[identifier] || false;\n const error: string = isTouched ? formErrors[identifier] : undefined!;\n const fieldType: string = getFieldType(component.type);\n\n // Prefix/postfix are accepted on any text-family input. When either is present,\n // route to AffixedField so the leading affix renders and submit-time composition\n // is picked up by composeAffixedInputs via the sentinel keys.\n // Both string.length and Array.length are defined, so a single truthy+length\n // check covers `prefixes?: string | PrefixOption[]`.\n const hasPrefixes: boolean = !!component.prefixes && component.prefixes.length > 0;\n const hasPostfix: boolean = typeof component.postfix === 'string' && component.postfix.length > 0;\n\n if (hasPrefixes || hasPostfix) {\n const prefixStateKey: string = affixPrefixKey(identifier, options.vendor);\n const postfixStateKey: string = affixPostfixKey(identifier, options.vendor);\n const defaultPrefixValue: string = hasPrefixes\n ? typeof component.prefixes === 'string'\n ? component.prefixes\n : (component.prefixes as PrefixOption[])[0].value\n : '';\n const selectedPrefix: string = formValues[prefixStateKey] ?? defaultPrefixValue;\n\n return (\n <AffixedField\n key={key}\n className={cx(options.inputClassName, component.classes)}\n id={component.id}\n label={resolve(component.label) || ''}\n name={identifier}\n placeholder={resolve(component.placeholder) || ''}\n required={component.required || false}\n error={error}\n value={value}\n type={fieldType}\n prefixes={component.prefixes}\n prefixValue={selectedPrefix}\n onChange={(e: ChangeEvent<HTMLInputElement>): void => onInputChange(identifier, e.target.value)}\n onBlur={(): void => options.onInputBlur?.(identifier)}\n onPrefixChange={(newPrefix: string): void => onInputChange(prefixStateKey, newPrefix)}\n onFocus={(): void => {\n if (hasPrefixes && formValues[prefixStateKey] === undefined) {\n onInputChange(prefixStateKey, defaultPrefixValue);\n }\n if (hasPostfix && formValues[postfixStateKey] === undefined) {\n onInputChange(postfixStateKey, component.postfix!);\n }\n }}\n />\n );\n }\n\n const field: any = createField({\n className: cx(options.inputClassName, component.classes),\n error,\n id: component.id,\n label: resolve(component.label) || '',\n name: identifier,\n onBlur: () => options.onInputBlur?.(identifier),\n onChange: (newValue: string) => onInputChange(identifier, newValue),\n placeholder: resolve(component.placeholder) || '',\n required: component.required || false,\n type: fieldType as FieldType,\n value,\n });\n\n return cloneElement(field, {key});\n }\n\n case EmbeddedFlowComponentType.OtpInput: {\n const identifier: string = component.ref!;\n const value: string = formValues[identifier] || '';\n const isTouched: boolean = touchedFields[identifier] || false;\n const error: string = isTouched ? formErrors[identifier] : undefined!;\n\n // The server reports the length and character set of the code it generated, so the field\n // matches the OTP the user received. An older server omits both and the defaults apply.\n const reportedLength: number = Number(options.additionalData?.['otpLength']);\n const otpLength: number | undefined =\n Number.isInteger(reportedLength) && reportedLength > 0 ? reportedLength : undefined;\n const numericOnly: boolean = options.additionalData?.['otpNumericOnly'] !== 'false';\n\n const field: any = createField({\n className: cx(options.inputClassName, component.classes),\n error,\n id: component.id,\n label: resolve(component.label) || '',\n length: otpLength,\n name: identifier,\n numericOnly,\n onBlur: () => options.onInputBlur?.(identifier),\n onChange: (newValue: string) => onInputChange(identifier, newValue),\n placeholder: resolve(component.placeholder) || '',\n required: component.required || false,\n type: FieldType.Otp,\n value,\n });\n\n return cloneElement(field, {key});\n }\n\n case EmbeddedFlowComponentType.Action: {\n const actionId: string = component.id;\n const eventType: string = component.eventType || '';\n const buttonText: string = resolve(component.label);\n const componentVariant: string = component.variant || '';\n\n // Only validate on submit type events.\n const shouldSkipValidation: boolean = eventType.toUpperCase() !== EmbeddedFlowEventType.Submit;\n\n // Determine the button type based on the event type. Default to 'submit' if not recognized.\n const buttonTypeEnum = {\n [EmbeddedFlowEventType.Submit]: 'submit',\n [EmbeddedFlowEventType.Reset]: 'reset',\n [EmbeddedFlowEventType.Cancel]: 'button',\n [EmbeddedFlowEventType.Trigger]: 'button',\n [EmbeddedFlowEventType.Back]: 'button',\n };\n const buttonType: HTMLButtonElement['type'] = buttonTypeEnum[eventType.toUpperCase()] ?? 'submit';\n\n // Approval waits while an approved authorization detail shows a modified value that cannot be submitted.\n const hasInvalidConsentApproval: boolean =\n !shouldSkipValidation &&\n componentVariant.toLowerCase() === 'primary' &&\n isConsentApprovalBlocked(\n (options.additionalData?.['consentPrompt'] as ConsentPromptData | undefined)?.purposes ?? [],\n formValues,\n );\n\n const handleClick = (): any => {\n if (options.onSubmit) {\n const formData: Record<string, any> = {};\n Object.keys(formValues).forEach((field: any) => {\n // Include all values, even empty strings, to ensure proper submission\n formData[field] = formValues[field];\n });\n\n // For consent actions, build the consent_decisions JSON from the form values.\n // The allow action captures per-attribute choices; the deny action sends\n // all purposes as rejected so the backend ConsentExecutor can fail the flow.\n const consentPrompt: ConsentPromptData | undefined = options.additionalData?.['consentPrompt'] as\n | ConsentPromptData\n | undefined;\n if (consentPrompt && eventType.toUpperCase() === EmbeddedFlowEventType.Submit) {\n const isDeny: boolean = componentVariant.toLowerCase() !== 'primary';\n const decisions: ConsentDecisions = {\n approved: !isDeny,\n ...(isDeny ? {reason: ConsentConstants.REASON_USER_DENIED} : {}),\n purposes: consentPrompt.purposes.map(\n (p: ConsentPurposeData): ConsentPurposeDecision => ({\n approved: !isDeny,\n elements: [\n // Permission purposes carry no essential elements, so the server sends null here\n ...(p.essential ?? []).map((e): ConsentAttributeElement => ({approved: !isDeny, name: e.name})),\n ...(p.optional ?? []).map(\n (e): ConsentAttributeElement =>\n getConsentElementDecision(\n p.purposeId,\n e,\n !isDeny && formValues[getConsentOptionalKey(p.purposeId, e.name)] === 'true',\n formValues,\n ),\n ),\n ],\n purposeName: p.purposeName!,\n }),\n ),\n };\n formData['consent_decisions'] = JSON.stringify(decisions);\n }\n\n // For submit events, pass the form data to the onSubmit callback. For other event types, reset the form and call onSubmit with an empty data object.\n if (eventType.toUpperCase() === EmbeddedFlowEventType.Submit) {\n options.onSubmit(component, formData, shouldSkipValidation);\n } else {\n resetForm();\n options.onSubmit(component, {}, shouldSkipValidation);\n }\n }\n };\n\n // Render branded social login buttons for known action IDs\n\n const socialButtonClassName: string = cx(options.buttonClassName, component.classes);\n\n if (matchesSocialProvider(actionId, eventType, buttonText, 'google', authType, componentVariant)) {\n return <GoogleButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'github', authType, componentVariant)) {\n return <GitHubButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'facebook', authType, componentVariant)) {\n return <FacebookButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'microsoft', authType, componentVariant)) {\n return <MicrosoftButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'linkedin', authType, componentVariant)) {\n return <LinkedInButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n if (matchesSocialProvider(actionId, eventType, buttonText, 'ethereum', authType, componentVariant)) {\n return (\n <SignInWithEthereumButton\n key={key}\n id={component.id}\n onClick={handleClick}\n className={socialButtonClassName}\n />\n );\n }\n if (actionId === 'prompt_mobile' || eventType === 'prompt_mobile') {\n return <SmsOtpButton key={key} id={component.id} onClick={handleClick} className={socialButtonClassName} />;\n }\n\n const startIconEl: ReactElement | null = component.startIcon ? (\n <img src={component.startIcon} alt=\"\" aria-hidden=\"true\" className={getAuthOptionIconClass()} />\n ) : null;\n\n const endIconEl: ReactElement | null = component.endIcon ? (\n <img src={component.endIcon} alt=\"\" aria-hidden=\"true\" className={getAuthOptionIconClass()} />\n ) : null;\n\n return (\n <Button\n fullWidth\n key={key}\n id={component.id}\n onClick={handleClick}\n disabled={\n isLoading ||\n (!isFormValid && !shouldSkipValidation) ||\n hasInvalidConsentApproval ||\n options.isTimeoutDisabled ||\n (component as any).config?.disabled\n }\n className={cx(options.buttonClassName, component.classes)}\n data-testid=\"thunderid-signin-submit\"\n variant={component.variant?.toLowerCase() === 'primary' ? 'solid' : 'outline'}\n color={component.variant?.toLowerCase() === 'primary' ? 'primary' : 'secondary'}\n startIcon={startIconEl}\n endIcon={endIconEl}\n type={buttonType}\n >\n {buttonText || 'Submit'}\n </Button>\n );\n }\n\n case EmbeddedFlowComponentType.Text: {\n const variant: any = getTypographyVariant(component.variant!);\n const textAlignClass: string = css({\n marginBottom: 2,\n textAlign:\n typeof component?.align === 'string' ? (component.align as React.CSSProperties['textAlign']) : 'left',\n });\n return (\n <Typography key={key} id={component.id} className={cx(component.classes, textAlignClass)} variant={variant}>\n {resolve(component.label)}\n </Typography>\n );\n }\n\n case EmbeddedFlowComponentType.Divider: {\n return <Divider key={key}>{resolve(component.label) || ''}</Divider>;\n }\n\n case EmbeddedFlowComponentType.Select: {\n const identifier: string = component.ref!;\n const value: string = formValues[identifier] || '';\n const isTouched: boolean = touchedFields[identifier] || false;\n const error: string = isTouched ? formErrors[identifier] : undefined!;\n\n // Options are pre-sanitized by flowTransformer to {value: string, label: string} format\n const selectOptions: any = (component.options || []).map((opt: any) => ({\n label: typeof opt === 'string' ? opt : String(opt.label ?? opt.value ?? ''),\n value: typeof opt === 'string' ? opt : String(opt.value ?? ''),\n }));\n\n return (\n <Select\n key={key}\n id={component.id}\n name={identifier}\n label={resolve(component.label) || ''}\n placeholder={resolve(component.placeholder)}\n required={component.required}\n options={selectOptions}\n value={value}\n error={error}\n onChange={(e: any): void => onInputChange(identifier, e.target.value)}\n onBlur={(): any => options.onInputBlur?.(identifier)}\n className={cx(options.inputClassName, component.classes)}\n />\n );\n }\n\n case EmbeddedFlowComponentType.DateInput: {\n const identifier: string = component.ref!;\n const value: string = formValues[identifier] || '';\n const isTouched: boolean = touchedFields[identifier] || false;\n const error: string = isTouched ? formErrors[identifier] : undefined!;\n\n return (\n <DatePicker\n key={key}\n id={component.id}\n name={identifier}\n label={resolve(component.label) || ''}\n placeholder={resolve(component.placeholder)}\n required={component.required}\n dateFormat={component.dateFormat}\n value={value}\n error={error}\n onChange={(e: any): void => onInputChange(identifier, e.target.value)}\n onBlur={(): any => options.onInputBlur?.(identifier)}\n className={cx(options.inputClassName, component.classes)}\n />\n );\n }\n\n case EmbeddedFlowComponentType.OuSelect:\n return skipUnsupported('OU_SELECT');\n\n // The resource pickers load with a signed-in user's access token, so without a data source, which is every flow\n // except InviteUser, they are not drawn.\n case EmbeddedFlowComponentType.UserSelect:\n return options.fetchUsers ? (\n <BaseUserSelect key={key} {...resourceSelectProps()} fetchUsers={options.fetchUsers} />\n ) : (\n skipUnsupported('USER_SELECT')\n );\n\n case EmbeddedFlowComponentType.AuthFlowSelect:\n return options.fetchAuthFlows ? (\n <BaseAuthFlowSelect key={key} {...resourceSelectProps()} fetchAuthFlows={options.fetchAuthFlows} />\n ) : (\n skipUnsupported('AUTH_FLOW_SELECT')\n );\n\n case EmbeddedFlowComponentType.UserTypeSelect:\n return options.fetchUserTypes ? (\n <BaseUserTypeSelect key={key} {...resourceSelectProps()} fetchUserTypes={options.fetchUserTypes} />\n ) : (\n skipUnsupported('USER_TYPE_SELECT')\n );\n\n case EmbeddedFlowComponentType.Block: {\n if (component.components && component.components.length > 0) {\n const formClass: string = css({\n display: 'flex',\n flexDirection: 'column',\n gap: `calc(${theme?.vars?.spacing?.unit ?? '4px'} * 2)`,\n });\n\n const blockComponents: any = component.components\n .map((childComponent: any, index: any) =>\n createAuthComponentFromFlow(\n childComponent,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n authType,\n {\n ...options,\n key: childComponent.id || `${component.id}_${index}`,\n },\n ),\n )\n .filter(Boolean);\n\n // The submit button's `type=\"submit\"` (and pressing Enter in a field) would\n // otherwise trigger the browser's native form submission — a GET request to\n // the current URL with all field values (including passwords) as query params.\n // Actual submission is handled entirely via `onClick`/`onSubmit` above.\n return (\n <form\n id={component.id}\n key={key}\n className={cx(component.classes, formClass)}\n onSubmit={(event: FormEvent<HTMLFormElement>): void => event.preventDefault()}\n >\n {blockComponents}\n </form>\n );\n }\n return null;\n }\n\n case EmbeddedFlowComponentType.RichText: {\n const richTextAction: EmbeddedFlowComponentAction | undefined = component.action;\n\n const dispatchRichTextAction = (): void => {\n if (!richTextAction || !options.onSubmit) {\n return;\n }\n const eventTypeValue = String(richTextAction.eventType ?? EmbeddedFlowEventType.Submit);\n const shouldSkipValidation: boolean = eventTypeValue.toUpperCase() === String(EmbeddedFlowEventType.Trigger);\n const syntheticAction: EmbeddedFlowComponent = {\n eventType: eventTypeValue,\n id: `${component.id}_action`,\n ref: richTextAction.ref,\n type: EmbeddedFlowComponentType.Action,\n };\n const formData: Record<string, string> = {};\n Object.keys(formValues).forEach((field: string) => {\n formData[field] = formValues[field];\n });\n options.onSubmit(syntheticAction, formData, shouldSkipValidation);\n };\n\n // Sentinel-anchor contract: only anchors carrying `data-action-ref` equal to\n // richTextAction.ref dispatch the action. Anchors without the sentinel (or with\n // a non-matching one) are treated as ordinary links and are ignored here.\n const isMatchingSentinelAnchor = (anchor: HTMLAnchorElement): boolean =>\n anchor.getAttribute('data-action-ref') === richTextAction?.ref;\n\n const handleRichTextClick: React.MouseEventHandler<HTMLDivElement> | undefined = richTextAction\n ? (event: React.MouseEvent<HTMLDivElement>): void => {\n const anchor: HTMLAnchorElement | null = (event.target as HTMLElement).closest('a');\n if (!anchor || !isMatchingSentinelAnchor(anchor)) {\n return;\n }\n event.preventDefault();\n dispatchRichTextAction();\n }\n : undefined;\n\n const handleRichTextKeyDown: React.KeyboardEventHandler<HTMLDivElement> | undefined = richTextAction\n ? (event: React.KeyboardEvent<HTMLDivElement>): void => {\n if (event.key !== 'Enter' && event.key !== ' ') {\n return;\n }\n const anchor: HTMLAnchorElement | null = (event.target as HTMLElement).closest('a');\n if (!anchor || !isMatchingSentinelAnchor(anchor)) {\n return;\n }\n event.preventDefault();\n dispatchRichTextAction();\n }\n : undefined;\n\n return (\n // Sentinel anchors are made keyboard-operable via the container's onKeyDown\n // (Enter/Space activate the matching anchor). Authors should ensure the anchor\n // is focusable (`href` or `tabIndex`); the click+keydown delegation covers both\n // pointer and keyboard activation once focus lands on the anchor.\n // eslint-disable-next-line jsx-a11y/no-static-element-interactions\n <div\n key={key}\n className={getRichTextClass()}\n onClick={handleRichTextClick}\n onKeyDown={handleRichTextKeyDown}\n // Manually sanitizes with `DOMPurify`.\n // IMPORTANT: DO NOT REMOVE OR MODIFY THIS SANITIZATION STEP.\n dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(resolveEmojiUrisInHtml(resolve(component.label)))}}\n />\n );\n }\n\n case EmbeddedFlowComponentType.Image: {\n const explicitHeight: string = resolve(component.height?.toString());\n const explicitWidth: string = resolve(component.width?.toString());\n return (\n <ImageComponent\n key={key}\n component={\n {\n config: {\n alt: resolve(component.alt) || resolve(component.label) || 'Image',\n height: explicitHeight || (options.inStack ? '50' : 'auto'),\n src: resolve(component.src),\n width: explicitWidth || (options.inStack ? '50' : '100%'),\n },\n } as any\n }\n formErrors={undefined!}\n formValues={undefined!}\n isFormValid={false}\n isLoading={false}\n onInputChange={(): void => {\n throw new Error('Function not implemented.');\n }}\n touchedFields={undefined!}\n />\n );\n }\n\n case EmbeddedFlowComponentType.Icon: {\n const iconName: string = component.name || '';\n const IconComponent: any = flowIconRegistry[iconName];\n if (!IconComponent) {\n logger.warn(`Unknown icon name: \"${iconName}\". Skipping render.`);\n return null;\n }\n return <IconComponent key={key} size={component.size || 24} color={component.color || 'currentColor'} />;\n }\n\n case EmbeddedFlowComponentType.Stack: {\n const direction: string = (component as any).direction || 'row';\n const gap: number = (component as any).gap ?? 2;\n const align: string = (component as any).align || 'center';\n const justify: string = (component as any).justify || 'flex-start';\n\n // `items` is the number of slots across the main axis and `direction` picks\n // that axis: with `row` it is the column count (items: 2 with four buttons\n // renders a 2 x 2 grid), and with `column` it is the row count and children\n // flow into further columns. Fewer than two slots keeps the flex layout, so\n // stacks authored before grid support are unaffected.\n const rawItems: string | number | undefined = component.items;\n const parsedItems: number =\n typeof rawItems === 'string' ? Number(rawItems) : typeof rawItems === 'number' ? rawItems : NaN;\n const items: number | null =\n Number.isFinite(parsedItems) && Math.floor(parsedItems) >= 2\n ? Math.min(Math.floor(parsedItems), MAX_STACK_ITEMS)\n : null;\n // CSS Grid has no reverse auto-flow, so the reverse variants fall back to\n // their base axis rather than silently becoming a row.\n const isColumn: boolean = direction.startsWith('column');\n const gridJustify: string = component.justify ?? 'stretch';\n // Equal `1fr` tracks fill the container, leaving `justify-content` no free\n // space to distribute. Content-sized tracks restore it, so every justify\n // value has a visible effect while the default stays an even split.\n const track: string = gridJustify === 'stretch' ? '1fr' : 'auto';\n\n const stackStyle: CSSProperties =\n items !== null\n ? {\n alignItems: component.align ?? 'stretch',\n display: 'grid',\n gap: `${gap * 0.5}rem`,\n gridAutoFlow: isColumn ? 'column' : 'row',\n justifyContent: gridJustify,\n width: '100%',\n ...(isColumn\n ? {gridTemplateRows: `repeat(${items}, ${track})`}\n : {gridTemplateColumns: `repeat(${items}, ${track})`}),\n }\n : {\n alignItems: align,\n display: 'flex',\n flexDirection: direction as CSSProperties['flexDirection'],\n flexWrap: 'wrap',\n gap: `${gap * 0.5}rem`,\n justifyContent: justify,\n };\n\n const stackClass: string = css(stackStyle as CSSInterpolation);\n\n const stackChildren: (ReactElement | null)[] = component.components\n ? component.components.map((childComponent: any, index: number) =>\n createAuthComponentFromFlow(\n childComponent,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n authType,\n {\n ...options,\n inStack: true,\n key: childComponent.id || `${component.id}_${index}`,\n },\n ),\n )\n : [];\n\n return (\n <div key={key} id={component.id} className={cx(component.classes, stackClass)}>\n {stackChildren}\n </div>\n );\n }\n\n case EmbeddedFlowComponentType.Consent: {\n const consentPromptRawData: ConsentPromptData | string | undefined = options.additionalData?.['consentPrompt'];\n\n return (\n <Consent\n key={key}\n consentData={consentPromptRawData as any}\n formValues={formValues}\n onInputChange={onInputChange}\n t={options.t}\n />\n );\n }\n\n case EmbeddedFlowComponentType.Timer: {\n const textTemplate: string = resolve((component as any).label) || 'Time remaining: {time}';\n const timeoutMs: number = Number(options.additionalData?.['stepTimeout']) || 0;\n const expiresIn: number = timeoutMs > 0 ? Math.max(0, Math.floor((timeoutMs - Date.now()) / 1000)) : 0;\n\n return <FlowTimer key={key} expiresIn={expiresIn} textTemplate={textTemplate} />;\n }\n\n case EmbeddedFlowComponentType.CopyableText: {\n const sourceKey: string | undefined = (component as any).source;\n const value: string = sourceKey && options.additionalData ? String(options.additionalData[sourceKey] ?? '') : '';\n const labelText: string | undefined = resolve((component as any).label) || undefined;\n\n return <CopyableText key={key} label={labelText} masked={Boolean(component.masked)} value={value} />;\n }\n\n case EmbeddedFlowComponentType.KeyValueList: {\n const sourceKey: string | undefined = component.source;\n const pairs: KeyValuePair[] = parseKeyValuePairs(\n sourceKey && options.additionalData ? options.additionalData[sourceKey] : undefined,\n ).map((pair: KeyValuePair) => ({...pair, label: resolve(pair.label)}));\n\n // An empty panel tells the user nothing, so a list with no pairs renders nothing at all.\n if (pairs.length === 0) {\n return null;\n }\n\n return <KeyValueList key={key} label={resolve(component.label) || undefined} pairs={pairs} />;\n }\n\n default:\n // Gracefully handle unsupported component types by returning null\n logger.warn(`Unsupported component type: ${component.type}. Skipping render.`);\n return null;\n }\n};\n\n/**\n * Processes an array of components and renders them as React elements for sign-in.\n */\nexport const renderSignInComponents = (\n components: EmbeddedFlowComponent[],\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n options?: {\n /** @internal */\n _customRenderers?: ComponentRendererMap;\n /** @internal */\n _theme?: any;\n /** Additional data from the flow response */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n inputClassName?: string;\n /** Flag to determine if the step timeline has expired */\n isTimeoutDisabled?: boolean;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n },\n): ReactElement[] =>\n components\n .map((component: any, index: any) =>\n createAuthComponentFromFlow(\n component,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n 'signin',\n {\n ...options,\n key: component.id || index,\n },\n ),\n )\n .filter((x): x is ReactElement => x !== null);\n\n/**\n * Processes an array of components and renders them as React elements for sign-up.\n */\nexport const renderSignUpComponents = (\n components: EmbeddedFlowComponent[],\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n options?: {\n /** @internal */\n _customRenderers?: ComponentRendererMap;\n /** @internal */\n _theme?: any;\n /** Additional data from the flow response */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n inputClassName?: string;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n },\n): ReactElement[] =>\n components\n .map((component: any, index: any) =>\n createAuthComponentFromFlow(\n component,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n 'signup',\n {\n ...options,\n key: component.id || index,\n },\n ),\n )\n .filter((x): x is ReactElement => x !== null);\n\n/**\n * Processes an array of components and renders them as React elements for recovery flow.\n */\nexport const renderRecoveryComponents = (\n components: EmbeddedFlowComponent[],\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n options?: {\n /** @internal */\n _customRenderers?: ComponentRendererMap;\n /** @internal */\n _theme?: any;\n /** Additional data from the flow response */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n inputClassName?: string;\n /** Flag to determine if the step timeline has expired */\n isTimeoutDisabled?: boolean;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n },\n): ReactElement[] =>\n components\n .map((component: any, index: any) =>\n createAuthComponentFromFlow(\n component,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n 'recovery',\n {\n ...options,\n key: component.id || index,\n },\n ),\n )\n .filter((x): x is ReactElement => x !== null);\n\n/**\n * Processes an array of components and renders them as React elements for invite user.\n * This is used by both InviteUser and AcceptInvite components.\n */\nexport const renderInviteUserComponents = (\n components: EmbeddedFlowComponent[],\n formValues: Record<string, string>,\n touchedFields: Record<string, boolean>,\n formErrors: Record<string, string>,\n isLoading: boolean,\n isFormValid: boolean,\n resetForm: () => void,\n onInputChange: (name: string, value: string) => void,\n options?: {\n /** @internal */\n _customRenderers?: ComponentRendererMap;\n /** @internal */\n _theme?: any;\n /** Additional data from the flow response */\n additionalData?: Record<string, any>;\n buttonClassName?: string;\n /** Function to fetch child organization units for OU_SELECT components. */\n fetchOrganizationUnitChildren?: (\n parentId: string,\n limit: number,\n offset: number,\n ) => Promise<OrganizationUnitListResponse>;\n inputClassName?: string;\n /** Data source for AUTH_FLOW_SELECT fields. */\n fetchAuthFlows?: FetchAuthFlows;\n /** Data source for USER_SELECT fields. */\n fetchUsers?: FetchUsers;\n /** Data source for USER_TYPE_SELECT fields. */\n fetchUserTypes?: FetchUserTypes;\n /** Flow metadata for resolving {{meta(...)}} expressions at render time */\n meta?: FlowMetadataResponse | null;\n onInputBlur?: (name: string) => void;\n /** Called with the error of a failed picker load. The form itself shows no error for it. */\n onPickerError?: (error: Error) => void;\n onSubmit?: (component: EmbeddedFlowComponent, data?: Record<string, any>, skipValidation?: boolean) => void;\n size?: 'small' | 'medium' | 'large';\n /** Translation function for resolving {{t(...)}} expressions at render time */\n t?: UseTranslation['t'];\n variant?: any;\n /** Vendor namespace used to derive affix sentinel keys for prefix/postfix-bearing inputs. */\n vendor?: string;\n },\n): ReactElement[] =>\n components\n .map((component: any, index: any) =>\n createAuthComponentFromFlow(\n component,\n formValues,\n touchedFields,\n formErrors,\n isLoading,\n isFormValid,\n resetForm,\n onInputChange,\n 'signup',\n {\n ...options,\n key: component.id || index,\n },\n ),\n )\n .filter((x): x is ReactElement => x !== null);\n"],"mappings":"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Aa,0BACX,YACA,YACA,eACA,YACA,WACA,aACA,WACA,eACA,YAqBA,WACG,KAAK,WAAgB,UACpB,4BACE,WACA,YACA,eACA,YACA,WACA,aACA,WACA,eACA,UACA;CACE,GAAG;CACH,KAAK,UAAU,MAAM;CACtB,CACF,CACF,CACA,QAAQ,MAAyB,MAAM,KAAK;;;;AAKjD,MAAa,4BACX,YACA,YACA,eACA,YACA,WACA,aACA,WACA,eACA,YAuBA,WACG,KAAK,WAAgB,UACpB,4BACE,WACA,YACA,eACA,YACA,WACA,aACA,WACA,eACA,YACA;CACE,GAAG;CACH,KAAK,UAAU,MAAM;CACtB,CACF,CACF,CACA,QAAQ,MAAyB,MAAM,KAAK;;;;;AAMjD,MAAa,8BACX,YACA,YACA,eACA,YACA,WACA,aACA,WACA,eACA,YAmCA,WACG,KAAK,WAAgB,UACpB,4BACE,WACA,YACA,eACA,YACA,WACA,aACA,WACA,eACA,UACA;CACE,GAAG;CACH,KAAK,UAAU,MAAM;CACtB,CACF,CACF,CACA,QAAQ,MAAyB,MAAM,KAAK"}
@@ -13,6 +13,12 @@ export type ConsentPurpose = ConsentPurposeData;
13
13
  export interface ConsentRenderProps {
14
14
  /** Current form values - used to read optional checkbox state. */
15
15
  formValues: Record<string, string>;
16
+ /**
17
+ * Whether the consent cannot be approved yet, because an authorization detail the user has not declined
18
+ * shows a modified value that cannot be submitted. Disable the approve action while it holds; denying
19
+ * stays possible.
20
+ */
21
+ isApprovalBlocked: boolean;
16
22
  /** Callback invoked when a user toggles an optional attribute. */
17
23
  onInputChange: (name: string, value: string) => void;
18
24
  /** The resolved list of consent purposes parsed from `consentData`. */
@@ -1 +1 @@
1
- {"version":3,"file":"Consent.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/flow/Consent.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,kBAAkB,EAAgB,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAmB,EAAE,EAAE,SAAS,EAAU,MAAM,OAAO,CAAC;AAM/D,OAAO,EAAC,cAAc,EAAC,MAAM,+BAA+B,CAAC;AAG7D;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,kEAAkE;IAClE,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,uEAAuE;IACvE,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,SAAS,CAAC;IACpD;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,kBAAkB,EAAE,GAAG;QAAC,QAAQ,EAAE,kBAAkB,EAAE,CAAA;KAAC,CAAC;IAC/E;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC;;OAEG;IACH,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAErD;;OAEG;IACH,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;CACzB;AAeD;;;;GAIG;AACH,QAAA,MAAM,OAAO,EAAE,EAAE,CAAC,YAAY,CAyM7B,CAAC;AAEF,eAAe,OAAO,CAAC"}
1
+ {"version":3,"file":"Consent.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/flow/Consent.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,kBAAkB,EAAgB,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAmB,EAAE,EAAE,SAAS,EAAqB,MAAM,OAAO,CAAC;AAO1E,OAAO,EAAC,cAAc,EAAC,MAAM,+BAA+B,CAAC;AAI7D;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG,kBAAkB,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC;;;;OAIG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAC3B,kEAAkE;IAClE,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,uEAAuE;IACvE,QAAQ,EAAE,kBAAkB,EAAE,CAAC;CAChC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,SAAS,CAAC;IACpD;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,kBAAkB,EAAE,GAAG;QAAC,QAAQ,EAAE,kBAAkB,EAAE,CAAA;KAAC,CAAC;IAC/E;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC;;OAEG;IACH,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAErD;;OAEG;IACH,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;CACzB;AAeD;;;;GAIG;AACH,QAAA,MAAM,OAAO,EAAE,EAAE,CAAC,YAAY,CA6O7B,CAAC;AAEF,eAAe,OAAO,CAAC"}
@@ -3,8 +3,10 @@ import Info_default from "../../primitives/Icons/Info.js";
3
3
  import Typography_default from "../../primitives/Typography/Typography.js";
4
4
  import Toggle_default from "../../primitives/Toggle/Toggle.js";
5
5
  import ConsentCheckboxList_default, { getConsentOptionalKey } from "./ConsentCheckboxList.js";
6
+ import ConsentAuthorizationDetail_default from "./ConsentAuthorizationDetail.js";
6
7
  import Tooltip_default from "../../primitives/Tooltip/Tooltip.js";
7
- import { useMemo } from "react";
8
+ import isConsentApprovalBlocked_default from "../../../utils/isConsentApprovalBlocked.js";
9
+ import { useEffect, useMemo } from "react";
8
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
9
11
 
10
12
  //#region src/components/auth/flow/Consent.tsx
@@ -119,9 +121,22 @@ const Consent = ({ consentData, formValues, onInputChange, children, t }) => {
119
121
  optional: toPromptElements(purpose["optional"])
120
122
  })).sort((a, b) => Number(b.type === "permissions") - Number(a.type === "permissions"));
121
123
  }, [consentData]);
124
+ useEffect(() => {
125
+ purposes.filter((purpose) => purpose.type === "authorization_details").forEach((purpose) => {
126
+ purpose.optional.forEach((element) => {
127
+ const key = getConsentOptionalKey(purpose.purposeId, element.name);
128
+ if (formValues[key] === void 0) onInputChange(key, "true");
129
+ });
130
+ });
131
+ }, [
132
+ purposes,
133
+ formValues,
134
+ onInputChange
135
+ ]);
122
136
  if (purposes.length === 0) return null;
123
137
  if (children) return /* @__PURE__ */ jsx(Fragment$1, { children: children({
124
138
  formValues,
139
+ isApprovalBlocked: isConsentApprovalBlocked_default(purposes, formValues),
125
140
  onInputChange,
126
141
  purposes
127
142
  }) });
@@ -131,39 +146,49 @@ const Consent = ({ consentData, formValues, onInputChange, children, t }) => {
131
146
  const isPermission = purpose.type === "permissions";
132
147
  return /* @__PURE__ */ jsxs("div", {
133
148
  className: purposeItemClass,
134
- children: [purpose.essential?.length > 0 && /* @__PURE__ */ jsxs("div", {
135
- className: sectionClass,
136
- children: [/* @__PURE__ */ jsx("div", {
137
- className: sectionHeaderClass,
138
- children: renderSectionTitle(isPermission ? essentialPermissionLabel : essentialLabel, isPermission ? essentialPermissionInfo : essentialInfo)
139
- }), /* @__PURE__ */ jsx(ConsentCheckboxList_default, {
140
- variant: "ESSENTIAL",
141
- purpose,
149
+ children: [
150
+ purpose.type === "authorization_details" && purpose.optional.map((element) => /* @__PURE__ */ jsx(ConsentAuthorizationDetail_default, {
151
+ purposeId: purpose.purposeId,
152
+ element,
142
153
  formValues,
143
154
  onInputChange,
144
155
  t
145
- })]
146
- }), purpose.optional?.length > 0 && /* @__PURE__ */ jsxs("div", {
147
- className: sectionClass,
148
- children: [/* @__PURE__ */ jsxs("div", {
149
- className: optionalSectionHeaderClass,
156
+ }, element.name)),
157
+ purpose.type !== "authorization_details" && purpose.essential?.length > 0 && /* @__PURE__ */ jsxs("div", {
158
+ className: sectionClass,
150
159
  children: [/* @__PURE__ */ jsx("div", {
151
- className: optionalSectionLabelClass,
152
- children: renderSectionTitle(isPermission ? optionalPermissionLabel : optionalLabel, isPermission ? optionalPermissionInfo : optionalInfo)
153
- }), /* @__PURE__ */ jsx(Toggle_default, {
154
- id: `consent_opt_${purpose.purposeId}_all`,
155
- checked: checkOptValue(purpose),
156
- "aria-label": isPermission ? toggleAllPermissionsLabel : toggleAllAttributesLabel,
157
- onChange: (e) => handleChange(purpose, e.target.checked)
160
+ className: sectionHeaderClass,
161
+ children: renderSectionTitle(isPermission ? essentialPermissionLabel : essentialLabel, isPermission ? essentialPermissionInfo : essentialInfo)
162
+ }), /* @__PURE__ */ jsx(ConsentCheckboxList_default, {
163
+ variant: "ESSENTIAL",
164
+ purpose,
165
+ formValues,
166
+ onInputChange,
167
+ t
158
168
  })]
159
- }), /* @__PURE__ */ jsx(ConsentCheckboxList_default, {
160
- variant: "OPTIONAL",
161
- purpose,
162
- formValues,
163
- onInputChange,
164
- t
165
- })]
166
- })]
169
+ }),
170
+ purpose.type !== "authorization_details" && purpose.optional?.length > 0 && /* @__PURE__ */ jsxs("div", {
171
+ className: sectionClass,
172
+ children: [/* @__PURE__ */ jsxs("div", {
173
+ className: optionalSectionHeaderClass,
174
+ children: [/* @__PURE__ */ jsx("div", {
175
+ className: optionalSectionLabelClass,
176
+ children: renderSectionTitle(isPermission ? optionalPermissionLabel : optionalLabel, isPermission ? optionalPermissionInfo : optionalInfo)
177
+ }), /* @__PURE__ */ jsx(Toggle_default, {
178
+ id: `consent_opt_${purpose.purposeId}_all`,
179
+ checked: checkOptValue(purpose),
180
+ "aria-label": isPermission ? toggleAllPermissionsLabel : toggleAllAttributesLabel,
181
+ onChange: (e) => handleChange(purpose, e.target.checked)
182
+ })]
183
+ }), /* @__PURE__ */ jsx(ConsentCheckboxList_default, {
184
+ variant: "OPTIONAL",
185
+ purpose,
186
+ formValues,
187
+ onInputChange,
188
+ t
189
+ })]
190
+ })
191
+ ]
167
192
  }, purpose.purposeId || purposeIndex);
168
193
  })
169
194
  });
@@ -1 +1 @@
1
- {"version":3,"file":"Consent.js","names":["Consent: FC<ConsentProps>","purposesContainerClass: string","purposeItemClass: string","sectionClass: string","sectionHeaderClass: string","optionalSectionHeaderClass: string","optionalSectionLabelClass: string","translated: string | undefined","Typography","Tooltip","Info","purposes: ConsentPurposeData[]","parsed: unknown","rawPurposes: unknown","isPermission: boolean","ConsentCheckboxList","Toggle"],"sources":["../../../../src/components/auth/flow/Consent.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {type ConsentPurposeData, PromptElement} from '@thunderid/browser';\nimport {type ChangeEvent, FC, ReactNode, useMemo} from 'react';\nimport ConsentCheckboxList, {getConsentOptionalKey} from './ConsentCheckboxList';\nimport Typography from '../../primitives/Typography/Typography';\nimport Toggle from '../../primitives/Toggle/Toggle';\nimport {Info} from '../../primitives/Icons';\nimport Tooltip from '../../primitives/Tooltip/Tooltip';\nimport {UseTranslation} from '../../../hooks/useTranslation';\nimport {css} from '../../../styles/emotion';\n\n/**\n * Backward-compatible consent purpose type exported by @thunderid/react.\n *\n * Some consumers import this name directly; keep it as an alias to the v2 model.\n */\nexport type ConsentPurpose = ConsentPurposeData;\n\n/**\n * Render props exposed by Consent when using the render-prop pattern.\n */\nexport interface ConsentRenderProps {\n /** Current form values - used to read optional checkbox state. */\n formValues: Record<string, string>;\n /** Callback invoked when a user toggles an optional attribute. */\n onInputChange: (name: string, value: string) => void;\n /** The resolved list of consent purposes parsed from `consentData`. */\n purposes: ConsentPurposeData[];\n}\n\n/**\n * Props for the Consent component.\n */\nexport interface ConsentProps {\n /**\n * Render-props callback. When provided, the default consent UI is replaced with\n * whatever JSX the callback returns. The parsed `purposes` list is injected so\n * consumers do not need to re-parse `consentData` themselves.\n *\n * @example\n * ```tsx\n * <Consent consentData={raw} formValues={formInputs} onInputChange={onChange} t={t}>\n * {({ purposes, formValues, onInputChange, t }) => (\n * <div>\n * {purposes.map(p => <MyConsentSection key={p.purposeId} purpose={p} />)}\n * </div>\n * )}\n * </Consent>\n * ```\n */\n children?: (props: ConsentRenderProps) => ReactNode;\n /**\n * The raw JSON string returned by the backend in `additionalData.consentPrompt`.\n */\n consentData?: string | ConsentPurposeData[] | {purposes: ConsentPurposeData[]};\n /**\n * Current form values - used to read optional checkbox state.\n */\n formValues: Record<string, string>;\n /**\n * Callback invoked when a user toggles an optional attribute.\n */\n onInputChange: (name: string, value: string) => void;\n\n /**\n * translation data\n */\n t?: UseTranslation['t'];\n}\n\nconst isObject = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null;\n\n/**\n * Keep only well-formed prompt elements (non-null objects with a string `name`).\n * @param value Raw `essential`/`optional` value from the consent payload\n */\nconst toPromptElements = (value: unknown): PromptElement[] =>\n Array.isArray(value)\n ? (value.filter(\n (element: unknown) => isObject(element) && typeof element['name'] === 'string',\n ) as unknown as PromptElement[])\n : [];\n\n/**\n * Consent component renders the list of purposes and their associated attributes (essential and optional)\n * based on the data provided by the backend. It allows users to toggle optional attributes while essential\n * attributes are displayed as read-only.\n */\nconst Consent: FC<ConsentProps> = ({consentData, formValues, onInputChange, children, t}: ConsentProps) => {\n // Computed per render (not at module scope): a CSP nonce configured on <ThunderIDProvider>\n // isn't known until the provider renders, and Emotion needs it applied before any style\n // insertion happens. These are static, so Emotion's own cache dedupes the repeat calls to a\n // no-op after the first render — this isn't a real per-render cost.\n const purposesContainerClass: string = css({\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n marginTop: '0.25rem',\n });\n const purposeItemClass: string = css({paddingBottom: '1rem'});\n const sectionClass: string = css({marginTop: '0.5rem'});\n const sectionHeaderClass: string = css({alignItems: 'center', display: 'flex', gap: '4px', marginBottom: '10px'});\n const optionalSectionHeaderClass: string = css({\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'space-between',\n marginBottom: '10px',\n paddingRight: '4px',\n });\n const optionalSectionLabelClass: string = css({alignItems: 'center', display: 'flex', gap: '4px'});\n\n /**\n * Resolve an i18n key, falling back to the given value when no translation is found.\n * `t` returns the key itself for missing translations, so that case is treated as \"not found\".\n * @param key Translation key\n * @param fallback Value to use when the key cannot be resolved\n */\n const resolve = (key: string, fallback = ''): string => {\n const translated: string | undefined = t?.(key);\n return translated && translated !== key ? translated : fallback;\n };\n\n const essentialInfo = resolve('consent.essential_claims.info');\n const optionalInfo = resolve('consent.optional_claims.info');\n const essentialPermissionInfo = resolve('consent.essential_scope.info');\n const optionalPermissionInfo = resolve('consent.optional_scope.info');\n const essentialLabel = resolve('consent.essential_claims', 'Essential Attributes');\n const optionalLabel = resolve('consent.optional_claims', 'Optional Attributes');\n const essentialPermissionLabel = resolve('consent.essential_scope', 'Essential Permissions');\n const optionalPermissionLabel = resolve('consent.optional_scope', 'Optional Permissions');\n const toggleAllAttributesLabel = resolve('consent.optional_claims.toggle_all', 'Toggle all optional attributes');\n const toggleAllPermissionsLabel = resolve('consent.optional_scope.toggle_all', 'Toggle all optional permissions');\n\n /**\n * Method to check whether master toggle button is checked or not\n * @param purpose Purpose object\n * @param checked boolean variable to check, whether toggle is checked or unchecked\n */\n const handleChange = (purpose: ConsentPurposeData, checked: boolean): void => {\n const checkValue = checked ? 'true' : 'false';\n purpose.optional.forEach((opt: PromptElement) => {\n const key: string = getConsentOptionalKey(purpose.purposeId, opt.name);\n onInputChange(key, checkValue);\n });\n };\n\n /**\n * Check all optional claims are selected or not\n * @param purpose Purpose object\n * @returns boolean value to denote all optional claims are selected\n */\n const checkOptValue = (purpose: ConsentPurposeData): boolean => {\n return purpose.optional.every((opt: PromptElement) => {\n const key: string = getConsentOptionalKey(purpose.purposeId, opt.name);\n return formValues[key] === 'true';\n });\n };\n\n /**\n * Renders a section title with an optional info tooltip.\n * @param label Section title\n * @param info Tooltip text; the tooltip is omitted when empty\n */\n const renderSectionTitle = (label: string, info: string): ReactNode => (\n <>\n <Typography variant=\"subtitle2\" fontWeight=\"bold\">\n {label}\n </Typography>\n {info && (\n <Tooltip helperText={info}>\n <Info width=\"1rem\" height=\"1rem\" />\n </Tooltip>\n )}\n </>\n );\n\n // Parse, validate and order the purposes once per `consentData` change rather than on every render\n // (e.g. each `formValues` update). Must run before any early return to respect the rules of hooks.\n const purposes: ConsentPurposeData[] = useMemo((): ConsentPurposeData[] => {\n if (!consentData) return [];\n\n let parsed: unknown;\n\n try {\n parsed = typeof consentData === 'string' ? JSON.parse(consentData) : consentData;\n } catch (e) {\n // Failed to parse consent prompt data\n return [];\n }\n\n const rawPurposes: unknown = Array.isArray(parsed) ? parsed : (parsed as {purposes?: unknown})?.purposes;\n\n if (!Array.isArray(rawPurposes)) return [];\n\n // `JSON.parse` doesn't validate the shape, so drop malformed purposes and elements here\n // instead of letting the sort or the render read properties off `null`. Purposes without a\n // `purposeId` are omitted too, since it keys the optional-element form values and they would collide.\n const normalized: ConsentPurposeData[] = rawPurposes\n .filter(\n (purpose: unknown): purpose is Record<string, unknown> =>\n isObject(purpose) && typeof purpose['purposeId'] === 'string',\n )\n .map(\n (purpose: Record<string, unknown>): ConsentPurposeData => ({\n ...(purpose as unknown as ConsentPurposeData),\n essential: toPromptElements(purpose['essential']),\n optional: toPromptElements(purpose['optional']),\n }),\n );\n\n // Order purposes so that permissions come first and attributes come last.\n // `normalized` is already a copy, so sorting doesn't mutate the caller's data; Array.prototype.sort\n // is stable, so purposes of the same type keep their original order.\n return normalized.sort(\n (a: ConsentPurposeData, b: ConsentPurposeData) =>\n Number(b.type === 'permissions') - Number(a.type === 'permissions'),\n );\n }, [consentData]);\n\n if (purposes.length === 0) return null;\n\n if (children) {\n return <>{children({formValues, onInputChange, purposes: purposes})}</>;\n }\n\n return (\n <div className={purposesContainerClass}>\n {purposes.map((purpose: ConsentPurposeData, purposeIndex: number) => {\n // Pick section labels/tooltips according to the purpose type (permissions vs attributes)\n const isPermission: boolean = purpose.type === 'permissions';\n\n return (\n <div key={purpose.purposeId || purposeIndex} className={purposeItemClass}>\n {/* TODO: Uncomment when the backend supports multiple purposes for a application */}\n {/* <Typography variant=\"h6\" fontWeight={600} gutterBottom color=\"inherit\">\n {purpose.purposeName}\n </Typography>\n <Typography variant=\"body2\" color=\"inherit\" style={{marginBottom: '1rem', opacity: 0.85}}>\n {purpose.description}\n </Typography> */}\n\n {purpose.essential?.length > 0 && (\n <div className={sectionClass}>\n <div className={sectionHeaderClass}>\n {renderSectionTitle(\n isPermission ? essentialPermissionLabel : essentialLabel,\n isPermission ? essentialPermissionInfo : essentialInfo,\n )}\n </div>\n <ConsentCheckboxList\n variant=\"ESSENTIAL\"\n purpose={purpose}\n formValues={formValues}\n onInputChange={onInputChange}\n t={t}\n />\n </div>\n )}\n\n {purpose.optional?.length > 0 && (\n <div className={sectionClass}>\n <div className={optionalSectionHeaderClass}>\n <div className={optionalSectionLabelClass}>\n {renderSectionTitle(\n isPermission ? optionalPermissionLabel : optionalLabel,\n isPermission ? optionalPermissionInfo : optionalInfo,\n )}\n </div>\n <Toggle\n id={`consent_opt_${purpose.purposeId}_all`}\n checked={checkOptValue(purpose)}\n aria-label={isPermission ? toggleAllPermissionsLabel : toggleAllAttributesLabel}\n onChange={(e: ChangeEvent<HTMLInputElement>): void => handleChange(purpose, e.target.checked)}\n />\n </div>\n <ConsentCheckboxList\n variant=\"OPTIONAL\"\n purpose={purpose}\n formValues={formValues}\n onInputChange={onInputChange}\n t={t}\n />\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n};\n\nexport default Consent;\n"],"mappings":"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"}
1
+ {"version":3,"file":"Consent.js","names":["Consent: FC<ConsentProps>","purposesContainerClass: string","purposeItemClass: string","sectionClass: string","sectionHeaderClass: string","optionalSectionHeaderClass: string","optionalSectionLabelClass: string","translated: string | undefined","Typography","Tooltip","Info","purposes: ConsentPurposeData[]","parsed: unknown","rawPurposes: unknown","key: string","isConsentApprovalBlocked","isPermission: boolean","ConsentAuthorizationDetail","ConsentCheckboxList","Toggle"],"sources":["../../../../src/components/auth/flow/Consent.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {type ConsentPurposeData, PromptElement} from '@thunderid/browser';\nimport {type ChangeEvent, FC, ReactNode, useEffect, useMemo} from 'react';\nimport ConsentAuthorizationDetail from './ConsentAuthorizationDetail';\nimport ConsentCheckboxList, {getConsentOptionalKey} from './ConsentCheckboxList';\nimport Typography from '../../primitives/Typography/Typography';\nimport Toggle from '../../primitives/Toggle/Toggle';\nimport {Info} from '../../primitives/Icons';\nimport Tooltip from '../../primitives/Tooltip/Tooltip';\nimport {UseTranslation} from '../../../hooks/useTranslation';\nimport {css} from '../../../styles/emotion';\nimport isConsentApprovalBlocked from '../../../utils/isConsentApprovalBlocked';\n\n/**\n * Backward-compatible consent purpose type exported by @thunderid/react.\n *\n * Some consumers import this name directly; keep it as an alias to the v2 model.\n */\nexport type ConsentPurpose = ConsentPurposeData;\n\n/**\n * Render props exposed by Consent when using the render-prop pattern.\n */\nexport interface ConsentRenderProps {\n /** Current form values - used to read optional checkbox state. */\n formValues: Record<string, string>;\n /**\n * Whether the consent cannot be approved yet, because an authorization detail the user has not declined\n * shows a modified value that cannot be submitted. Disable the approve action while it holds; denying\n * stays possible.\n */\n isApprovalBlocked: boolean;\n /** Callback invoked when a user toggles an optional attribute. */\n onInputChange: (name: string, value: string) => void;\n /** The resolved list of consent purposes parsed from `consentData`. */\n purposes: ConsentPurposeData[];\n}\n\n/**\n * Props for the Consent component.\n */\nexport interface ConsentProps {\n /**\n * Render-props callback. When provided, the default consent UI is replaced with\n * whatever JSX the callback returns. The parsed `purposes` list is injected so\n * consumers do not need to re-parse `consentData` themselves.\n *\n * @example\n * ```tsx\n * <Consent consentData={raw} formValues={formInputs} onInputChange={onChange} t={t}>\n * {({ purposes, formValues, onInputChange, t }) => (\n * <div>\n * {purposes.map(p => <MyConsentSection key={p.purposeId} purpose={p} />)}\n * </div>\n * )}\n * </Consent>\n * ```\n */\n children?: (props: ConsentRenderProps) => ReactNode;\n /**\n * The raw JSON string returned by the backend in `additionalData.consentPrompt`.\n */\n consentData?: string | ConsentPurposeData[] | {purposes: ConsentPurposeData[]};\n /**\n * Current form values - used to read optional checkbox state.\n */\n formValues: Record<string, string>;\n /**\n * Callback invoked when a user toggles an optional attribute.\n */\n onInputChange: (name: string, value: string) => void;\n\n /**\n * translation data\n */\n t?: UseTranslation['t'];\n}\n\nconst isObject = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null;\n\n/**\n * Keep only well-formed prompt elements (non-null objects with a string `name`).\n * @param value Raw `essential`/`optional` value from the consent payload\n */\nconst toPromptElements = (value: unknown): PromptElement[] =>\n Array.isArray(value)\n ? (value.filter(\n (element: unknown) => isObject(element) && typeof element['name'] === 'string',\n ) as unknown as PromptElement[])\n : [];\n\n/**\n * Consent component renders the list of purposes and their associated attributes (essential and optional)\n * based on the data provided by the backend. It allows users to toggle optional attributes while essential\n * attributes are displayed as read-only.\n */\nconst Consent: FC<ConsentProps> = ({consentData, formValues, onInputChange, children, t}: ConsentProps) => {\n // Computed per render (not at module scope): a CSP nonce configured on <ThunderIDProvider>\n // isn't known until the provider renders, and Emotion needs it applied before any style\n // insertion happens. These are static, so Emotion's own cache dedupes the repeat calls to a\n // no-op after the first render — this isn't a real per-render cost.\n const purposesContainerClass: string = css({\n display: 'flex',\n flexDirection: 'column',\n gap: '1rem',\n marginTop: '0.25rem',\n });\n const purposeItemClass: string = css({paddingBottom: '1rem'});\n const sectionClass: string = css({marginTop: '0.5rem'});\n const sectionHeaderClass: string = css({alignItems: 'center', display: 'flex', gap: '4px', marginBottom: '10px'});\n const optionalSectionHeaderClass: string = css({\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'space-between',\n marginBottom: '10px',\n paddingRight: '4px',\n });\n const optionalSectionLabelClass: string = css({alignItems: 'center', display: 'flex', gap: '4px'});\n\n /**\n * Resolve an i18n key, falling back to the given value when no translation is found.\n * `t` returns the key itself for missing translations, so that case is treated as \"not found\".\n * @param key Translation key\n * @param fallback Value to use when the key cannot be resolved\n */\n const resolve = (key: string, fallback = ''): string => {\n const translated: string | undefined = t?.(key);\n return translated && translated !== key ? translated : fallback;\n };\n\n const essentialInfo = resolve('consent.essential_claims.info');\n const optionalInfo = resolve('consent.optional_claims.info');\n const essentialPermissionInfo = resolve('consent.essential_scope.info');\n const optionalPermissionInfo = resolve('consent.optional_scope.info');\n const essentialLabel = resolve('consent.essential_claims', 'Essential Attributes');\n const optionalLabel = resolve('consent.optional_claims', 'Optional Attributes');\n const essentialPermissionLabel = resolve('consent.essential_scope', 'Essential Permissions');\n const optionalPermissionLabel = resolve('consent.optional_scope', 'Optional Permissions');\n const toggleAllAttributesLabel = resolve('consent.optional_claims.toggle_all', 'Toggle all optional attributes');\n const toggleAllPermissionsLabel = resolve('consent.optional_scope.toggle_all', 'Toggle all optional permissions');\n\n /**\n * Method to check whether master toggle button is checked or not\n * @param purpose Purpose object\n * @param checked boolean variable to check, whether toggle is checked or unchecked\n */\n const handleChange = (purpose: ConsentPurposeData, checked: boolean): void => {\n const checkValue = checked ? 'true' : 'false';\n purpose.optional.forEach((opt: PromptElement) => {\n const key: string = getConsentOptionalKey(purpose.purposeId, opt.name);\n onInputChange(key, checkValue);\n });\n };\n\n /**\n * Check all optional claims are selected or not\n * @param purpose Purpose object\n * @returns boolean value to denote all optional claims are selected\n */\n const checkOptValue = (purpose: ConsentPurposeData): boolean => {\n return purpose.optional.every((opt: PromptElement) => {\n const key: string = getConsentOptionalKey(purpose.purposeId, opt.name);\n return formValues[key] === 'true';\n });\n };\n\n /**\n * Renders a section title with an optional info tooltip.\n * @param label Section title\n * @param info Tooltip text; the tooltip is omitted when empty\n */\n const renderSectionTitle = (label: string, info: string): ReactNode => (\n <>\n <Typography variant=\"subtitle2\" fontWeight=\"bold\">\n {label}\n </Typography>\n {info && (\n <Tooltip helperText={info}>\n <Info width=\"1rem\" height=\"1rem\" />\n </Tooltip>\n )}\n </>\n );\n\n // Parse, validate and order the purposes once per `consentData` change rather than on every render\n // (e.g. each `formValues` update). Must run before any early return to respect the rules of hooks.\n const purposes: ConsentPurposeData[] = useMemo((): ConsentPurposeData[] => {\n if (!consentData) return [];\n\n let parsed: unknown;\n\n try {\n parsed = typeof consentData === 'string' ? JSON.parse(consentData) : consentData;\n } catch (e) {\n // Failed to parse consent prompt data\n return [];\n }\n\n const rawPurposes: unknown = Array.isArray(parsed) ? parsed : (parsed as {purposes?: unknown})?.purposes;\n\n if (!Array.isArray(rawPurposes)) return [];\n\n // `JSON.parse` doesn't validate the shape, so drop malformed purposes and elements here\n // instead of letting the sort or the render read properties off `null`. Purposes without a\n // `purposeId` are omitted too, since it keys the optional-element form values and they would collide.\n const normalized: ConsentPurposeData[] = rawPurposes\n .filter(\n (purpose: unknown): purpose is Record<string, unknown> =>\n isObject(purpose) && typeof purpose['purposeId'] === 'string',\n )\n .map(\n (purpose: Record<string, unknown>): ConsentPurposeData => ({\n ...(purpose as unknown as ConsentPurposeData),\n essential: toPromptElements(purpose['essential']),\n optional: toPromptElements(purpose['optional']),\n }),\n );\n\n // Order purposes so that permissions come first and attributes come last.\n // `normalized` is already a copy, so sorting doesn't mutate the caller's data; Array.prototype.sort\n // is stable, so purposes of the same type keep their original order.\n return normalized.sort(\n (a: ConsentPurposeData, b: ConsentPurposeData) =>\n Number(b.type === 'permissions') - Number(a.type === 'permissions'),\n );\n }, [consentData]);\n\n // An authorization detail is the transaction the user is asked to allow, so it starts approved. The value\n // is seeded into the form so the submitted decision matches the screen.\n useEffect(() => {\n purposes\n .filter((purpose: ConsentPurposeData) => purpose.type === 'authorization_details')\n .forEach((purpose: ConsentPurposeData) => {\n purpose.optional.forEach((element: PromptElement) => {\n const key: string = getConsentOptionalKey(purpose.purposeId, element.name);\n if (formValues[key] === undefined) {\n onInputChange(key, 'true');\n }\n });\n });\n }, [purposes, formValues, onInputChange]);\n\n if (purposes.length === 0) return null;\n\n if (children) {\n return (\n <>\n {children({\n formValues,\n isApprovalBlocked: isConsentApprovalBlocked(purposes, formValues),\n onInputChange,\n purposes,\n })}\n </>\n );\n }\n\n return (\n <div className={purposesContainerClass}>\n {purposes.map((purpose: ConsentPurposeData, purposeIndex: number) => {\n // Pick section labels/tooltips according to the purpose type (permissions vs attributes)\n const isPermission: boolean = purpose.type === 'permissions';\n\n return (\n <div key={purpose.purposeId || purposeIndex} className={purposeItemClass}>\n {/* TODO: Uncomment when the backend supports multiple purposes for a application */}\n {/* <Typography variant=\"h6\" fontWeight={600} gutterBottom color=\"inherit\">\n {purpose.purposeName}\n </Typography>\n <Typography variant=\"body2\" color=\"inherit\" style={{marginBottom: '1rem', opacity: 0.85}}>\n {purpose.description}\n </Typography> */}\n\n {purpose.type === 'authorization_details' &&\n purpose.optional.map((element: PromptElement) => (\n <ConsentAuthorizationDetail\n key={element.name}\n purposeId={purpose.purposeId}\n element={element}\n formValues={formValues}\n onInputChange={onInputChange}\n t={t}\n />\n ))}\n\n {purpose.type !== 'authorization_details' && purpose.essential?.length > 0 && (\n <div className={sectionClass}>\n <div className={sectionHeaderClass}>\n {renderSectionTitle(\n isPermission ? essentialPermissionLabel : essentialLabel,\n isPermission ? essentialPermissionInfo : essentialInfo,\n )}\n </div>\n <ConsentCheckboxList\n variant=\"ESSENTIAL\"\n purpose={purpose}\n formValues={formValues}\n onInputChange={onInputChange}\n t={t}\n />\n </div>\n )}\n\n {purpose.type !== 'authorization_details' && purpose.optional?.length > 0 && (\n <div className={sectionClass}>\n <div className={optionalSectionHeaderClass}>\n <div className={optionalSectionLabelClass}>\n {renderSectionTitle(\n isPermission ? optionalPermissionLabel : optionalLabel,\n isPermission ? optionalPermissionInfo : optionalInfo,\n )}\n </div>\n <Toggle\n id={`consent_opt_${purpose.purposeId}_all`}\n checked={checkOptValue(purpose)}\n aria-label={isPermission ? toggleAllPermissionsLabel : toggleAllAttributesLabel}\n onChange={(e: ChangeEvent<HTMLInputElement>): void => handleChange(purpose, e.target.checked)}\n />\n </div>\n <ConsentCheckboxList\n variant=\"OPTIONAL\"\n purpose={purpose}\n formValues={formValues}\n onInputChange={onInputChange}\n t={t}\n />\n </div>\n )}\n </div>\n );\n })}\n </div>\n );\n};\n\nexport default Consent;\n"],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ import { type ConsentDetailRow, type PromptElement } from '@thunderid/browser';
2
+ import { FC, ReactNode } from 'react';
3
+ import { UseTranslation } from '../../../hooks/useTranslation';
4
+ /**
5
+ * Render props exposed by ConsentAuthorizationDetail when using the render-prop pattern.
6
+ */
7
+ export interface ConsentAuthorizationDetailRenderProps {
8
+ /** RFC 9396 authorization details type of the detail. */
9
+ detailType?: string;
10
+ /** The detail's consent element. */
11
+ element: PromptElement;
12
+ /** Call this when the user approves or declines the detail as a whole. */
13
+ handleChange: (checked: boolean) => void;
14
+ /**
15
+ * Whether the detail is approved. A detail is the transaction the user is asked to allow, so it counts as
16
+ * approved until the user declines it.
17
+ */
18
+ isApproved: boolean;
19
+ /** Fields of the detail; render each with `ConsentDetailField` or `useConsentDetailField`. */
20
+ rows: ConsentDetailRow[];
21
+ /** Server-rendered sentence describing the detail, or its type or identifier when it has none. */
22
+ summary: string;
23
+ }
24
+ /**
25
+ * Props for the ConsentAuthorizationDetail component.
26
+ */
27
+ export interface ConsentAuthorizationDetailProps {
28
+ /**
29
+ * Render-props callback. When provided, the default detail UI is replaced with whatever JSX the
30
+ * callback returns.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * <ConsentAuthorizationDetail purposeId={purpose.purposeId} element={element} formValues={formValues} onInputChange={onChange}>
35
+ * {({summary, rows, isApproved, handleChange}) => (
36
+ * <section>
37
+ * <h3>{summary}</h3>
38
+ * {rows.map(row => (
39
+ * <ConsentDetailField key={row.path} purposeId={purpose.purposeId} detailId={element.name} row={row} formValues={formValues} onInputChange={onChange} />
40
+ * ))}
41
+ * <Switch checked={isApproved} onChange={e => handleChange(e.target.checked)} />
42
+ * </section>
43
+ * )}
44
+ * </ConsentAuthorizationDetail>
45
+ * ```
46
+ */
47
+ children?: (props: ConsentAuthorizationDetailRenderProps) => ReactNode;
48
+ /** The authorization detail element of the consent purpose. */
49
+ element: PromptElement;
50
+ /** Current form values, holding the approval of the detail and the values the user modified. */
51
+ formValues: Record<string, string>;
52
+ /** Callback invoked with a consent form key and its new value. */
53
+ onInputChange: (name: string, value: string) => void;
54
+ /** The identifier of the authorization details purpose the detail belongs to. */
55
+ purposeId: string;
56
+ /** translation data */
57
+ t?: UseTranslation['t'];
58
+ }
59
+ /**
60
+ * Renders one RFC 9396 authorization detail element: the server-rendered summary, the detail's fields,
61
+ * which are read-only unless the user may modify them, and a single toggle that approves or declines the
62
+ * detail as a whole. The summary and labels come from the server and are not translated again.
63
+ * Authorization details reach the consent step only on a sign-in started from an authorization request, so
64
+ * this renders in an authorization server UI (hosted login); an app-native sign-in flow cannot carry them.
65
+ */
66
+ declare const ConsentAuthorizationDetail: FC<ConsentAuthorizationDetailProps>;
67
+ export default ConsentAuthorizationDetail;
68
+ //# sourceMappingURL=ConsentAuthorizationDetail.d.ts.map