@thunderid/react 1.0.4 → 1.0.6

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 (61) hide show
  1. package/dist/cjs/components/adapters/Consent.cjs +21 -26
  2. package/dist/cjs/components/adapters/Consent.cjs.map +1 -1
  3. package/dist/cjs/components/adapters/ConsentCheckboxList.cjs +9 -3
  4. package/dist/cjs/components/adapters/ConsentCheckboxList.cjs.map +1 -1
  5. package/dist/cjs/components/presentation/LanguageSwitcher/LanguageSwitcher.cjs +10 -2
  6. package/dist/cjs/components/presentation/LanguageSwitcher/LanguageSwitcher.cjs.map +1 -1
  7. package/dist/cjs/components/presentation/auth/AuthOptionFactory.cjs +1 -2
  8. package/dist/cjs/components/presentation/auth/AuthOptionFactory.cjs.map +1 -1
  9. package/dist/cjs/components/presentation/auth/Recovery/BaseRecovery.cjs +1 -1
  10. package/dist/cjs/components/presentation/auth/Recovery/BaseRecovery.cjs.map +1 -1
  11. package/dist/cjs/components/presentation/auth/SignIn/BaseSignIn.cjs +6 -3
  12. package/dist/cjs/components/presentation/auth/SignIn/BaseSignIn.cjs.map +1 -1
  13. package/dist/cjs/components/presentation/auth/SignUp/BaseSignUp.cjs +1 -1
  14. package/dist/cjs/components/presentation/auth/SignUp/BaseSignUp.cjs.map +1 -1
  15. package/dist/cjs/contexts/FlowMeta/FlowMetaProvider.cjs +21 -9
  16. package/dist/cjs/contexts/FlowMeta/FlowMetaProvider.cjs.map +1 -1
  17. package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs +2 -1
  18. package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs.map +1 -1
  19. package/dist/cjs/hooks/useForm.cjs +42 -5
  20. package/dist/cjs/hooks/useForm.cjs.map +1 -1
  21. package/dist/cjs/utils/resolveTranslationsInObject.cjs +3 -1
  22. package/dist/cjs/utils/resolveTranslationsInObject.cjs.map +1 -1
  23. package/dist/components/adapters/Consent.d.ts +1 -18
  24. package/dist/components/adapters/Consent.d.ts.map +1 -1
  25. package/dist/components/adapters/Consent.js +21 -25
  26. package/dist/components/adapters/Consent.js.map +1 -1
  27. package/dist/components/adapters/ConsentCheckboxList.d.ts +5 -0
  28. package/dist/components/adapters/ConsentCheckboxList.d.ts.map +1 -1
  29. package/dist/components/adapters/ConsentCheckboxList.js +9 -3
  30. package/dist/components/adapters/ConsentCheckboxList.js.map +1 -1
  31. package/dist/components/presentation/LanguageSwitcher/LanguageSwitcher.d.ts.map +1 -1
  32. package/dist/components/presentation/LanguageSwitcher/LanguageSwitcher.js +11 -3
  33. package/dist/components/presentation/LanguageSwitcher/LanguageSwitcher.js.map +1 -1
  34. package/dist/components/presentation/auth/AuthOptionFactory.d.ts.map +1 -1
  35. package/dist/components/presentation/auth/AuthOptionFactory.js +1 -2
  36. package/dist/components/presentation/auth/AuthOptionFactory.js.map +1 -1
  37. package/dist/components/presentation/auth/Recovery/BaseRecovery.d.ts.map +1 -1
  38. package/dist/components/presentation/auth/Recovery/BaseRecovery.js +1 -1
  39. package/dist/components/presentation/auth/Recovery/BaseRecovery.js.map +1 -1
  40. package/dist/components/presentation/auth/SignIn/BaseSignIn.d.ts.map +1 -1
  41. package/dist/components/presentation/auth/SignIn/BaseSignIn.js +6 -3
  42. package/dist/components/presentation/auth/SignIn/BaseSignIn.js.map +1 -1
  43. package/dist/components/presentation/auth/SignUp/BaseSignUp.js +1 -1
  44. package/dist/components/presentation/auth/SignUp/BaseSignUp.js.map +1 -1
  45. package/dist/contexts/FlowMeta/FlowMetaProvider.d.ts +15 -0
  46. package/dist/contexts/FlowMeta/FlowMetaProvider.d.ts.map +1 -1
  47. package/dist/contexts/FlowMeta/FlowMetaProvider.js +21 -9
  48. package/dist/contexts/FlowMeta/FlowMetaProvider.js.map +1 -1
  49. package/dist/contexts/ThunderID/ThunderIDProvider.d.ts.map +1 -1
  50. package/dist/contexts/ThunderID/ThunderIDProvider.js +2 -1
  51. package/dist/contexts/ThunderID/ThunderIDProvider.js.map +1 -1
  52. package/dist/hooks/useForm.d.ts +5 -0
  53. package/dist/hooks/useForm.d.ts.map +1 -1
  54. package/dist/hooks/useForm.js +43 -6
  55. package/dist/hooks/useForm.js.map +1 -1
  56. package/dist/models/config.d.ts +2 -0
  57. package/dist/models/config.d.ts.map +1 -1
  58. package/dist/utils/resolveTranslationsInObject.d.ts.map +1 -1
  59. package/dist/utils/resolveTranslationsInObject.js +3 -1
  60. package/dist/utils/resolveTranslationsInObject.js.map +1 -1
  61. package/package.json +2 -2
@@ -5,22 +5,16 @@ const require_Typography = require('../primitives/Typography/Typography.cjs');
5
5
  const require_Toggle = require('../primitives/Toggle/Toggle.cjs');
6
6
  const require_ConsentCheckboxList = require('./ConsentCheckboxList.cjs');
7
7
  const require_Tooltip = require('../primitives/Tooltip/Tooltip.cjs');
8
- let __thunderid_browser = require("@thunderid/browser");
9
- __thunderid_browser = require_rolldown_runtime.__toESM(__thunderid_browser);
10
8
  let react_jsx_runtime = require("react/jsx-runtime");
11
9
  react_jsx_runtime = require_rolldown_runtime.__toESM(react_jsx_runtime);
12
10
 
13
11
  //#region src/components/adapters/Consent.tsx
14
- const defaultConfig = {
15
- essential: "Essential Attributtes",
16
- optional: "Optional Attributes"
17
- };
18
12
  /**
19
13
  * Consent component renders the list of purposes and their associated attributes (essential and optional)
20
14
  * based on the data provided by the backend. It allows users to toggle optional attributes while essential
21
15
  * attributes are displayed as read-only.
22
16
  */
23
- const Consent = ({ consentData, formValues, config: suppliedConfig = {}, onInputChange, children, meta, t }) => {
17
+ const Consent = ({ consentData, formValues, onInputChange, children, t }) => {
24
18
  const purposesContainerClass = require_emotion.css({
25
19
  display: "flex",
26
20
  flexDirection: "column",
@@ -47,22 +41,21 @@ const Consent = ({ consentData, formValues, config: suppliedConfig = {}, onInput
47
41
  display: "flex",
48
42
  gap: "4px"
49
43
  });
50
- /** Resolve any remaining {{t()}} or {{meta()}} template expressions in a string at render time. */
44
+ /** Resolve i18n keys */
51
45
  const resolve = (text) => {
52
- if (!text || !t && !meta) return text || "";
53
- return (0, __thunderid_browser.resolveFlowTemplateLiterals)(text, {
54
- meta,
55
- t: t || ((k) => k)
56
- });
57
- };
58
- const config = {
59
- ...defaultConfig,
60
- ...suppliedConfig
46
+ if (!text || !t) return text || "";
47
+ return t(text);
61
48
  };
62
- const essentialInfo = typeof config.essentialInfo === "string" ? resolve(config.essentialInfo.trim()) : "";
63
- const optionalInfo = typeof config.optionalInfo === "string" ? resolve(config.optionalInfo.trim()) : "";
64
- const essentialLabel = resolve(config["essential"]);
65
- const optionalLabel = resolve(config["optional"]);
49
+ const essentialInfo = resolve(`consent.essential_claims.info`);
50
+ const optionalInfo = resolve(`consent.optional_claims.info`);
51
+ const permissionInfo = resolve(`consent.authorize_scope.info`);
52
+ /**
53
+ * Falls back to default config values if essential/optional
54
+ * keys cannot be resolved via translation files .
55
+ */
56
+ const essentialLabel = resolve(`consent.essential_claims`) || "Essential Attributes";
57
+ const optionalLabel = resolve(`consent.optional_claims`) || "Optional Attributes";
58
+ const permissionLabel = resolve(`consent.authorize_scope`) || "Permissions";
66
59
  /**
67
60
  * Method to check whether master toggle button is checked or not
68
61
  * @param purpose Purpose object
@@ -121,7 +114,8 @@ const Consent = ({ consentData, formValues, config: suppliedConfig = {}, onInput
121
114
  variant: "ESSENTIAL",
122
115
  purpose,
123
116
  formValues,
124
- onInputChange
117
+ onInputChange,
118
+ t
125
119
  })]
126
120
  }), purpose.optional && purpose.optional.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
127
121
  className: sectionClass,
@@ -132,9 +126,9 @@ const Consent = ({ consentData, formValues, config: suppliedConfig = {}, onInput
132
126
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Typography.default, {
133
127
  variant: "subtitle2",
134
128
  fontWeight: "bold",
135
- children: purpose.type === "permissions" ? "Permissions" : optionalLabel
136
- }), optionalInfo !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Tooltip.default, {
137
- helperText: optionalInfo,
129
+ children: purpose.type === "permissions" ? permissionLabel : optionalLabel
130
+ }), Boolean(purpose.type === "permissions" ? permissionInfo : optionalInfo) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Tooltip.default, {
131
+ helperText: purpose.type === "permissions" ? permissionInfo : optionalInfo,
138
132
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Info.default, {
139
133
  width: "1rem",
140
134
  height: "1rem"
@@ -150,7 +144,8 @@ const Consent = ({ consentData, formValues, config: suppliedConfig = {}, onInput
150
144
  variant: "OPTIONAL",
151
145
  purpose,
152
146
  formValues,
153
- onInputChange
147
+ onInputChange,
148
+ t
154
149
  })]
155
150
  })]
156
151
  }, purpose.purposeId || purposeIndex))
@@ -1 +1 @@
1
- {"version":3,"file":"Consent.cjs","names":["defaultConfig: Required<Pick<ConsentConfig, 'essential' | 'optional'>>","Consent: FC<ConsentProps>","purposesContainerClass: string","css","purposeItemClass: string","sectionClass: string","sectionHeaderClass: string","optionalSectionHeaderClass: string","optionalSectionLabelClass: string","config: ConsentConfig","getConsentOptionalKey","purposes: ConsentPurposeData[]","parsed: ConsentPurposeData[] | {purposes: ConsentPurposeData[]}","Typography","Tooltip","Info","ConsentCheckboxList","Toggle"],"sources":["../../../../src/components/adapters/Consent.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n type ConsentPurposeData,\n FlowMetadataResponse,\n PromptElement,\n resolveFlowTemplateLiterals,\n} from '@thunderid/browser';\nimport {type ChangeEvent, FC, ReactNode} 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 * Interface for consent configuration\n */\nexport interface ConsentConfig {\n essential?: string;\n optional?: string;\n essentialInfo?: string;\n optionalInfo?: string;\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 * Config to modified detail in consent page\n */\n config?: Record<string, unknown>;\n\n /**\n * Config of meta response\n */\n meta?: FlowMetadataResponse | null;\n\n /**\n * translation data\n */\n t?: UseTranslation['t'];\n}\n\nconst defaultConfig: Required<Pick<ConsentConfig, 'essential' | 'optional'>> = {\n essential: 'Essential Attributtes',\n optional: 'Optional Attributes',\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> = ({\n consentData,\n formValues,\n config: suppliedConfig = {},\n onInputChange,\n children,\n meta,\n t,\n}: 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 /** Resolve any remaining {{t()}} or {{meta()}} template expressions in a string at render time. */\n const resolve = (text: string | undefined): string => {\n if (!text || (!t && !meta)) {\n return text || '';\n }\n return resolveFlowTemplateLiterals(text, {meta, t: t || ((k: string): string => k)});\n };\n\n const config: ConsentConfig = {...defaultConfig, ...suppliedConfig};\n const essentialInfo = typeof config.essentialInfo === 'string' ? resolve(config.essentialInfo.trim()) : '';\n const optionalInfo = typeof config.optionalInfo === 'string' ? resolve(config.optionalInfo.trim()) : '';\n const essentialLabel = resolve(config['essential']);\n const optionalLabel = resolve(config['optional']);\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.map((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 if (!consentData) return null;\n\n let purposes: ConsentPurposeData[] = [];\n\n try {\n const parsed: ConsentPurposeData[] | {purposes: ConsentPurposeData[]} =\n typeof consentData === 'string' ? JSON.parse(consentData) : consentData;\n\n purposes = Array.isArray(parsed) ? parsed : parsed.purposes || [];\n } catch (e) {\n // Failed to parse consent prompt data\n return null;\n }\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 <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 && purpose.essential.length > 0 && (\n <div className={sectionClass}>\n <div className={sectionHeaderClass}>\n <Typography variant=\"subtitle2\" fontWeight=\"bold\">\n {essentialLabel}\n </Typography>\n {essentialInfo !== '' && (\n <Tooltip helperText={essentialInfo}>\n <Info width=\"1rem\" height=\"1rem\" />\n </Tooltip>\n )}\n </div>\n <ConsentCheckboxList\n variant=\"ESSENTIAL\"\n purpose={purpose}\n formValues={formValues}\n onInputChange={onInputChange}\n />\n </div>\n )}\n\n {purpose.optional && purpose.optional.length > 0 && (\n <div className={sectionClass}>\n <div className={optionalSectionHeaderClass}>\n <div className={optionalSectionLabelClass}>\n <Typography variant=\"subtitle2\" fontWeight=\"bold\">\n {purpose.type === 'permissions' ? 'Permissions' : optionalLabel}\n </Typography>\n {optionalInfo !== '' && (\n <Tooltip helperText={optionalInfo}>\n <Info width=\"1rem\" height=\"1rem\" />\n </Tooltip>\n )}\n </div>\n <Toggle\n id={`consent_opt_${purpose.purposeId}_all`}\n checked={checkOptValue(purpose)}\n aria-label=\"Toggle all optional attributes\"\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 />\n </div>\n )}\n </div>\n ))}\n </div>\n );\n};\n\nexport default Consent;\n"],"mappings":";;;;;;;;;;;;;AAgGA,MAAMA,gBAAyE;CAC7E,WAAW;CACX,UAAU;CACX;;;;;;AAOD,MAAMC,WAA6B,EACjC,aACA,YACA,QAAQ,iBAAiB,EAAE,EAC3B,eACA,UACA,MACA,QACkB;CAKlB,MAAMC,yBAAiCC,oBAAI;EACzC,SAAS;EACT,eAAe;EACf,KAAK;EACL,WAAW;EACZ,CAAC;CACF,MAAMC,mBAA2BD,oBAAI,EAAC,eAAe,QAAO,CAAC;CAC7D,MAAME,eAAuBF,oBAAI,EAAC,WAAW,UAAS,CAAC;CACvD,MAAMG,qBAA6BH,oBAAI;EAAC,YAAY;EAAU,SAAS;EAAQ,KAAK;EAAO,cAAc;EAAO,CAAC;CACjH,MAAMI,6BAAqCJ,oBAAI;EAC7C,YAAY;EACZ,SAAS;EACT,gBAAgB;EAChB,cAAc;EACd,cAAc;EACf,CAAC;CACF,MAAMK,4BAAoCL,oBAAI;EAAC,YAAY;EAAU,SAAS;EAAQ,KAAK;EAAM,CAAC;;CAGlG,MAAM,WAAW,SAAqC;AACpD,MAAI,CAAC,QAAS,CAAC,KAAK,CAAC,KACnB,QAAO,QAAQ;AAEjB,8DAAmC,MAAM;GAAC;GAAM,GAAG,OAAO,MAAsB;GAAG,CAAC;;CAGtF,MAAMM,SAAwB;EAAC,GAAG;EAAe,GAAG;EAAe;CACnE,MAAM,gBAAgB,OAAO,OAAO,kBAAkB,WAAW,QAAQ,OAAO,cAAc,MAAM,CAAC,GAAG;CACxG,MAAM,eAAe,OAAO,OAAO,iBAAiB,WAAW,QAAQ,OAAO,aAAa,MAAM,CAAC,GAAG;CACrG,MAAM,iBAAiB,QAAQ,OAAO,aAAa;CACnD,MAAM,gBAAgB,QAAQ,OAAO,YAAY;;;;;;CAOjD,MAAM,gBAAgB,SAA6B,YAA2B;EAC5E,MAAM,aAAa,UAAU,SAAS;AACtC,UAAQ,SAAS,KAAK,QAAuB;AAE3C,iBADoBC,kDAAsB,QAAQ,WAAW,IAAI,KAAK,EACnD,WAAW;IAC9B;;;;;;;CAQJ,MAAM,iBAAiB,YAAyC;AAC9D,SAAO,QAAQ,SAAS,OAAO,QAAuB;AAEpD,UAAO,WADaA,kDAAsB,QAAQ,WAAW,IAAI,KAAK,MAC3C;IAC3B;;AAGJ,KAAI,CAAC,YAAa,QAAO;CAEzB,IAAIC,WAAiC,EAAE;AAEvC,KAAI;EACF,MAAMC,SACJ,OAAO,gBAAgB,WAAW,KAAK,MAAM,YAAY,GAAG;AAE9D,aAAW,MAAM,QAAQ,OAAO,GAAG,SAAS,OAAO,YAAY,EAAE;UAC1D,GAAG;AAEV,SAAO;;AAGT,KAAI,SAAS,WAAW,EAAG,QAAO;AAElC,KAAI,SACF,QAAO,mFAAG,SAAS;EAAC;EAAY;EAAyB;EAAS,CAAC,GAAI;AAGzE,QACE,2CAAC;EAAI,WAAW;YACb,SAAS,KAAK,SAA6B,iBAC1C,4CAAC;GAA4C,WAAW;cASrD,QAAQ,aAAa,QAAQ,UAAU,SAAS,KAC/C,4CAAC;IAAI,WAAW;eACd,4CAAC;KAAI,WAAW;gBACd,2CAACC;MAAW,SAAQ;MAAY,YAAW;gBACxC;OACU,EACZ,kBAAkB,MACjB,2CAACC;MAAQ,YAAY;gBACnB,2CAACC;OAAK,OAAM;OAAO,QAAO;QAAS;OAC3B;MAER,EACN,2CAACC;KACC,SAAQ;KACC;KACG;KACG;MACf;KACE,EAGP,QAAQ,YAAY,QAAQ,SAAS,SAAS,KAC7C,4CAAC;IAAI,WAAW;eACd,4CAAC;KAAI,WAAW;gBACd,4CAAC;MAAI,WAAW;iBACd,2CAACH;OAAW,SAAQ;OAAY,YAAW;iBACxC,QAAQ,SAAS,gBAAgB,gBAAgB;QACvC,EACZ,iBAAiB,MAChB,2CAACC;OAAQ,YAAY;iBACnB,2CAACC;QAAK,OAAM;QAAO,QAAO;SAAS;QAC3B;OAER,EACN,2CAACE;MACC,IAAI,eAAe,QAAQ,UAAU;MACrC,SAAS,cAAc,QAAQ;MAC/B,cAAW;MACX,WAAW,MAA2C,aAAa,SAAS,EAAE,OAAO,QAAQ;OAC7F;MACE,EACN,2CAACD;KACC,SAAQ;KACC;KACG;KACG;MACf;KACE;KAxDA,QAAQ,aAAa,aA0DzB,CACN;GACE;;AAIV,sBAAe"}
1
+ {"version":3,"file":"Consent.cjs","names":["Consent: FC<ConsentProps>","purposesContainerClass: string","css","purposeItemClass: string","sectionClass: string","sectionHeaderClass: string","optionalSectionHeaderClass: string","optionalSectionLabelClass: string","getConsentOptionalKey","purposes: ConsentPurposeData[]","parsed: ConsentPurposeData[] | {purposes: ConsentPurposeData[]}","Typography","Tooltip","Info","ConsentCheckboxList","Toggle"],"sources":["../../../../src/components/adapters/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} 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\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 /** Resolve i18n keys */\n const resolve = (text: string | undefined): string => {\n if (!text || !t) {\n return text || '';\n }\n return t(text);\n };\n\n const essentialInfo = resolve(`consent.essential_claims.info`);\n const optionalInfo = resolve(`consent.optional_claims.info`);\n const permissionInfo = resolve(`consent.authorize_scope.info`);\n /**\n * Falls back to default config values if essential/optional\n * keys cannot be resolved via translation files .\n */\n const essentialLabel = resolve(`consent.essential_claims`) || 'Essential Attributes';\n const optionalLabel = resolve(`consent.optional_claims`) || 'Optional Attributes';\n const permissionLabel = resolve(`consent.authorize_scope`) || '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.map((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 if (!consentData) return null;\n\n let purposes: ConsentPurposeData[] = [];\n\n try {\n const parsed: ConsentPurposeData[] | {purposes: ConsentPurposeData[]} =\n typeof consentData === 'string' ? JSON.parse(consentData) : consentData;\n\n purposes = Array.isArray(parsed) ? parsed : parsed.purposes || [];\n } catch (e) {\n // Failed to parse consent prompt data\n return null;\n }\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 <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 && purpose.essential.length > 0 && (\n <div className={sectionClass}>\n <div className={sectionHeaderClass}>\n <Typography variant=\"subtitle2\" fontWeight=\"bold\">\n {essentialLabel}\n </Typography>\n {essentialInfo !== '' && (\n <Tooltip helperText={essentialInfo}>\n <Info width=\"1rem\" height=\"1rem\" />\n </Tooltip>\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 && purpose.optional.length > 0 && (\n <div className={sectionClass}>\n <div className={optionalSectionHeaderClass}>\n <div className={optionalSectionLabelClass}>\n <Typography variant=\"subtitle2\" fontWeight=\"bold\">\n {purpose.type === 'permissions' ? permissionLabel : optionalLabel}\n </Typography>\n {/* Show tooltip for optional claims/permissions according to their type */}\n {Boolean(purpose.type === 'permissions' ? permissionInfo : optionalInfo) && (\n <Tooltip helperText={purpose.type === 'permissions' ? permissionInfo : optionalInfo}>\n <Info width=\"1rem\" height=\"1rem\" />\n </Tooltip>\n )}\n </div>\n <Toggle\n id={`consent_opt_${purpose.purposeId}_all`}\n checked={checkOptValue(purpose)}\n aria-label=\"Toggle all optional attributes\"\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 </div>\n );\n};\n\nexport default Consent;\n"],"mappings":"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"}
@@ -25,9 +25,15 @@ const getConsentOptionalKey = (purposeId, attrName) => `__consent_opt__${purpose
25
25
  * - OPTIONAL variant: renders toggleable checkboxes for optional attributes.
26
26
  * Opt-in is the default when no prior form value exists.
27
27
  */
28
- const ConsentCheckboxList = ({ variant, purpose, formValues, onInputChange, children }) => {
28
+ const ConsentCheckboxList = ({ variant, purpose, formValues, onInputChange, children, t }) => {
29
29
  const { theme, colorScheme } = require_useTheme.default();
30
30
  const styles = require_ConsentCheckboxList_styles.default(theme, colorScheme);
31
+ const resolve = (text) => {
32
+ if (!text || !t) return text || "";
33
+ const key = `consent.${text}`;
34
+ const translated = t(key);
35
+ return translated === key ? text : translated;
36
+ };
31
37
  const attributes = (variant === "ESSENTIAL" ? purpose.essential : purpose.optional).map((e) => e.name);
32
38
  if (!attributes || attributes.length === 0) return null;
33
39
  const isEssential = variant === "ESSENTIAL";
@@ -58,11 +64,11 @@ const ConsentCheckboxList = ({ variant, purpose, formValues, onInputChange, chil
58
64
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("consent-checkbox-list", "bullet")), styles["bullet"]) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Typography.default, {
59
65
  variant: "body2",
60
66
  className: require_emotion.cx((0, __thunderid_browser.withVendorCSSClassPrefix)((0, __thunderid_browser.bem)("consent-checkbox-list", "typography")), styles["typography"]),
61
- children: attr
67
+ children: resolve(attr)
62
68
  })]
63
69
  }), isEssential ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Typography.default, {
64
70
  variant: "body2",
65
- children: "Required"
71
+ children: resolve("required") || "Required"
66
72
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_Toggle.default, {
67
73
  id: inputId,
68
74
  checked,
@@ -1 +1 @@
1
- {"version":3,"file":"ConsentCheckboxList.cjs","names":["ConsentCheckboxList: FC<ConsentCheckboxListProps>","useTheme","styles: Record<string, string>","useStyles","attributes: string[]","isEssential: boolean","cx","checked: boolean","Typography","Toggle"],"sources":["../../../../src/components/adapters/ConsentCheckboxList.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {type ConsentPurposeData, withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {type ChangeEvent, FC, ReactNode} from 'react';\nimport useStyles from './ConsentCheckboxList.styles';\nimport useTheme from '../../contexts/Theme/useTheme';\nimport {cx} from '../../styles/emotion';\nimport Toggle from '../primitives/Toggle/Toggle';\nimport Typography from '../primitives/Typography/Typography';\n\n/**\n * Computes the form value key for tracking an optional attribute's consent state.\n *\n * @param purposeId - The ID of the consent purpose.\n * @param attrName - The name of the attribute.\n * @returns A stable form key string.\n */\nexport const getConsentOptionalKey = (purposeId: string, attrName: string): string =>\n `__consent_opt__${purposeId}__${attrName}`;\n\n/**\n * ConsentInputVariant defines whether the ConsentCheckboxList is rendering essential (read-only) or\n * optional (toggleable) attributes.\n */\nexport type ConsentInputVariant = 'ESSENTIAL' | 'OPTIONAL';\n\n/**\n * Render props exposed by ConsentCheckboxList when using the render-prop pattern.\n */\nexport interface ConsentCheckboxListRenderProps {\n /** The list of attribute names to render. */\n attributes: string[];\n /**\n * Call this when an optional attribute checkbox is toggled.\n * No-op for ESSENTIAL attributes (they cannot be changed).\n */\n handleChange: (attrName: string, checked: boolean) => void;\n /**\n * Returns the current checked state for the given attribute name.\n * Always returns true for ESSENTIAL attributes.\n */\n isChecked: (attrName: string) => boolean;\n /** Whether the list is rendering essential or optional attributes. */\n variant: ConsentInputVariant;\n}\n\n/**\n * Props for the ConsentCheckboxList component.\n */\nexport interface ConsentCheckboxListProps {\n /**\n * Render-props callback. When provided, the default checkbox list UI is replaced\n * with whatever JSX the callback returns.\n *\n * @example\n * ```tsx\n * <ConsentCheckboxList variant=\"OPTIONAL\" purpose={purpose} formValues={formValues} onInputChange={onChange}>\n * {({ attributes, isChecked, handleChange }) => (\n * <ul>\n * {attributes.map(attr => (\n * <li key={attr}>\n * <Checkbox checked={isChecked(attr)} onChange={e => handleChange(attr, e.target.checked)} />\n * {attr}\n * </li>\n * ))}\n * </ul>\n * )}\n * </ConsentCheckboxList>\n * ```\n */\n children?: (props: ConsentCheckboxListRenderProps) => ReactNode;\n /** Current form values - used to read optional checkbox state */\n formValues: Record<string, string>;\n /** Callback invoked when an optional attribute checkbox is toggled */\n onInputChange: (name: string, value: string) => void;\n /** The consent purpose data containing attribute lists */\n purpose: ConsentPurposeData;\n /** Whether to render essential (disabled) or optional (toggleable) attributes */\n variant: ConsentInputVariant;\n}\n\n/**\n * Renders a list of consent attribute checkboxes.\n *\n * - ESSENTIAL variant: renders read-only checked checkboxes for required attributes.\n * - OPTIONAL variant: renders toggleable checkboxes for optional attributes.\n * Opt-in is the default when no prior form value exists.\n */\nconst ConsentCheckboxList: FC<ConsentCheckboxListProps> = ({\n variant,\n purpose,\n formValues,\n onInputChange,\n children,\n}: ConsentCheckboxListProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme);\n\n const attributes: string[] = (variant === 'ESSENTIAL' ? purpose.essential : purpose.optional).map(\n (e): string => e.name,\n );\n\n if (!attributes || attributes.length === 0) {\n return null;\n }\n\n const isEssential: boolean = variant === 'ESSENTIAL';\n\n const isChecked = (attrName: string): boolean => {\n if (isEssential) {\n return true;\n }\n const key: string = getConsentOptionalKey(purpose.purposeId, attrName);\n // Default to be false when there's no explicit form value\n return formValues[key] === 'true';\n };\n\n const handleChange = (attrName: string, checked: boolean): void => {\n const key: string = getConsentOptionalKey(purpose.purposeId, attrName);\n onInputChange(key, checked ? 'true' : 'false');\n };\n\n if (children) {\n return <>{children({attributes, handleChange, isChecked, variant})}</>;\n }\n\n return (\n <div className={cx(withVendorCSSClassPrefix(bem('consent-checkbox-list')), styles['listContainer'])}>\n {attributes.map((attr: string) => {\n const inputId = `consent_${isEssential ? 'ess' : 'opt'}_${purpose.purposeId}_${attr}`;\n const checked: boolean = isChecked(attr);\n\n return (\n <div\n key={attr}\n className={cx(withVendorCSSClassPrefix(bem('consent-checkbox-list', 'item')), styles['listItem'])}\n >\n <div className={cx(withVendorCSSClassPrefix(bem('consent-checkbox-list', 'row')), styles['listRow'])}>\n <div\n className={cx(\n withVendorCSSClassPrefix(bem('consent-checkbox-list', 'label-container')),\n styles['labelContainer'],\n )}\n >\n <div\n className={cx(withVendorCSSClassPrefix(bem('consent-checkbox-list', 'bullet')), styles['bullet'])}\n />\n <Typography\n variant=\"body2\"\n className={cx(\n withVendorCSSClassPrefix(bem('consent-checkbox-list', 'typography')),\n styles['typography'],\n )}\n >\n {attr}\n </Typography>\n </div>\n {isEssential ? (\n <Typography variant=\"body2\">Required</Typography>\n ) : (\n <Toggle\n id={inputId}\n checked={checked}\n disabled={isEssential}\n onChange={\n isEssential\n ? undefined\n : (e: ChangeEvent<HTMLInputElement>): void => handleChange(attr, e.target.checked)\n }\n />\n )}\n </div>\n </div>\n );\n })}\n </div>\n );\n};\n\nexport default ConsentCheckboxList;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,MAAa,yBAAyB,WAAmB,aACvD,kBAAkB,UAAU,IAAI;;;;;;;;AAsElC,MAAMA,uBAAqD,EACzD,SACA,SACA,YACA,eACA,eAC8B;CAC9B,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAMC,SAAiCC,2CAAU,OAAO,YAAY;CAEpE,MAAMC,cAAwB,YAAY,cAAc,QAAQ,YAAY,QAAQ,UAAU,KAC3F,MAAc,EAAE,KAClB;AAED,KAAI,CAAC,cAAc,WAAW,WAAW,EACvC,QAAO;CAGT,MAAMC,cAAuB,YAAY;CAEzC,MAAM,aAAa,aAA8B;AAC/C,MAAI,YACF,QAAO;AAIT,SAAO,WAFa,sBAAsB,QAAQ,WAAW,SAAS,MAE3C;;CAG7B,MAAM,gBAAgB,UAAkB,YAA2B;AAEjE,gBADoB,sBAAsB,QAAQ,WAAW,SAAS,EACnD,UAAU,SAAS,QAAQ;;AAGhD,KAAI,SACF,QAAO,mFAAG,SAAS;EAAC;EAAY;EAAc;EAAW;EAAQ,CAAC,GAAI;AAGxE,QACE,2CAAC;EAAI,WAAWC,kGAAgC,wBAAwB,CAAC,EAAE,OAAO,iBAAiB;YAChG,WAAW,KAAK,SAAiB;GAChC,MAAM,UAAU,WAAW,cAAc,QAAQ,MAAM,GAAG,QAAQ,UAAU,GAAG;GAC/E,MAAMC,UAAmB,UAAU,KAAK;AAExC,UACE,2CAAC;IAEC,WAAWD,kGAAgC,yBAAyB,OAAO,CAAC,EAAE,OAAO,YAAY;cAEjG,4CAAC;KAAI,WAAWA,kGAAgC,yBAAyB,MAAM,CAAC,EAAE,OAAO,WAAW;gBAClG,4CAAC;MACC,WAAWA,kGACoB,yBAAyB,kBAAkB,CAAC,EACzE,OAAO,kBACR;iBAED,2CAAC,SACC,WAAWA,kGAAgC,yBAAyB,SAAS,CAAC,EAAE,OAAO,UAAU,GACjG,EACF,2CAACE;OACC,SAAQ;OACR,WAAWF,kGACoB,yBAAyB,aAAa,CAAC,EACpE,OAAO,cACR;iBAEA;QACU;OACT,EACL,cACC,2CAACE;MAAW,SAAQ;gBAAQ;OAAqB,GAEjD,2CAACC;MACC,IAAI;MACK;MACT,UAAU;MACV,UACE,cACI,UACC,MAA2C,aAAa,MAAM,EAAE,OAAO,QAAQ;OAEtF;MAEA;MArCD,KAsCD;IAER;GACE;;AAIV,kCAAe"}
1
+ {"version":3,"file":"ConsentCheckboxList.cjs","names":["ConsentCheckboxList: FC<ConsentCheckboxListProps>","useTheme","styles: Record<string, string>","useStyles","key: string","translated: string","attributes: string[]","isEssential: boolean","cx","checked: boolean","Typography","Toggle"],"sources":["../../../../src/components/adapters/ConsentCheckboxList.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {type ConsentPurposeData, withVendorCSSClassPrefix, bem} from '@thunderid/browser';\nimport {type ChangeEvent, FC, ReactNode} from 'react';\nimport useStyles from './ConsentCheckboxList.styles';\nimport useTheme from '../../contexts/Theme/useTheme';\nimport {cx} from '../../styles/emotion';\nimport Toggle from '../primitives/Toggle/Toggle';\nimport Typography from '../primitives/Typography/Typography';\nimport {UseTranslation} from '../../hooks/useTranslation';\n\n/**\n * Computes the form value key for tracking an optional attribute's consent state.\n *\n * @param purposeId - The ID of the consent purpose.\n * @param attrName - The name of the attribute.\n * @returns A stable form key string.\n */\nexport const getConsentOptionalKey = (purposeId: string, attrName: string): string =>\n `__consent_opt__${purposeId}__${attrName}`;\n\n/**\n * ConsentInputVariant defines whether the ConsentCheckboxList is rendering essential (read-only) or\n * optional (toggleable) attributes.\n */\nexport type ConsentInputVariant = 'ESSENTIAL' | 'OPTIONAL';\n\n/**\n * Render props exposed by ConsentCheckboxList when using the render-prop pattern.\n */\nexport interface ConsentCheckboxListRenderProps {\n /** The list of attribute names to render. */\n attributes: string[];\n /**\n * Call this when an optional attribute checkbox is toggled.\n * No-op for ESSENTIAL attributes (they cannot be changed).\n */\n handleChange: (attrName: string, checked: boolean) => void;\n /**\n * Returns the current checked state for the given attribute name.\n * Always returns true for ESSENTIAL attributes.\n */\n isChecked: (attrName: string) => boolean;\n /** Whether the list is rendering essential or optional attributes. */\n variant: ConsentInputVariant;\n}\n\n/**\n * Props for the ConsentCheckboxList component.\n */\nexport interface ConsentCheckboxListProps {\n /**\n * Render-props callback. When provided, the default checkbox list UI is replaced\n * with whatever JSX the callback returns.\n *\n * @example\n * ```tsx\n * <ConsentCheckboxList variant=\"OPTIONAL\" purpose={purpose} formValues={formValues} onInputChange={onChange}>\n * {({ attributes, isChecked, handleChange }) => (\n * <ul>\n * {attributes.map(attr => (\n * <li key={attr}>\n * <Checkbox checked={isChecked(attr)} onChange={e => handleChange(attr, e.target.checked)} />\n * {attr}\n * </li>\n * ))}\n * </ul>\n * )}\n * </ConsentCheckboxList>\n * ```\n */\n children?: (props: ConsentCheckboxListRenderProps) => ReactNode;\n /** Current form values - used to read optional checkbox state */\n formValues: Record<string, string>;\n /** Callback invoked when an optional attribute checkbox is toggled */\n onInputChange: (name: string, value: string) => void;\n /** The consent purpose data containing attribute lists */\n purpose: ConsentPurposeData;\n /** Whether to render essential (disabled) or optional (toggleable) attributes */\n variant: ConsentInputVariant;\n /**\n * translation data\n */\n t?: UseTranslation['t'];\n}\n\n/**\n * Renders a list of consent attribute checkboxes.\n *\n * - ESSENTIAL variant: renders read-only checked checkboxes for required attributes.\n * - OPTIONAL variant: renders toggleable checkboxes for optional attributes.\n * Opt-in is the default when no prior form value exists.\n */\nconst ConsentCheckboxList: FC<ConsentCheckboxListProps> = ({\n variant,\n purpose,\n formValues,\n onInputChange,\n children,\n t,\n}: ConsentCheckboxListProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme);\n\n const resolve = (text: string | undefined): string => {\n if (!text || !t) {\n return text || '';\n }\n\n const key: string = `consent.${text}`;\n const translated: string = t(key);\n return translated === key ? text : translated;\n };\n\n const attributes: string[] = (variant === 'ESSENTIAL' ? purpose.essential : purpose.optional).map(\n (e): string => e.name,\n );\n\n if (!attributes || attributes.length === 0) {\n return null;\n }\n\n const isEssential: boolean = variant === 'ESSENTIAL';\n\n const isChecked = (attrName: string): boolean => {\n if (isEssential) {\n return true;\n }\n const key: string = getConsentOptionalKey(purpose.purposeId, attrName);\n // Default to be false when there's no explicit form value\n return formValues[key] === 'true';\n };\n\n const handleChange = (attrName: string, checked: boolean): void => {\n const key: string = getConsentOptionalKey(purpose.purposeId, attrName);\n onInputChange(key, checked ? 'true' : 'false');\n };\n\n if (children) {\n return <>{children({attributes, handleChange, isChecked, variant})}</>;\n }\n\n return (\n <div className={cx(withVendorCSSClassPrefix(bem('consent-checkbox-list')), styles['listContainer'])}>\n {attributes.map((attr: string) => {\n const inputId = `consent_${isEssential ? 'ess' : 'opt'}_${purpose.purposeId}_${attr}`;\n const checked: boolean = isChecked(attr);\n\n return (\n <div\n key={attr}\n className={cx(withVendorCSSClassPrefix(bem('consent-checkbox-list', 'item')), styles['listItem'])}\n >\n <div className={cx(withVendorCSSClassPrefix(bem('consent-checkbox-list', 'row')), styles['listRow'])}>\n <div\n className={cx(\n withVendorCSSClassPrefix(bem('consent-checkbox-list', 'label-container')),\n styles['labelContainer'],\n )}\n >\n <div\n className={cx(withVendorCSSClassPrefix(bem('consent-checkbox-list', 'bullet')), styles['bullet'])}\n />\n <Typography\n variant=\"body2\"\n className={cx(\n withVendorCSSClassPrefix(bem('consent-checkbox-list', 'typography')),\n styles['typography'],\n )}\n >\n {resolve(attr)}\n </Typography>\n </div>\n {isEssential ? (\n <Typography variant=\"body2\">{resolve('required') || 'Required'}</Typography>\n ) : (\n <Toggle\n id={inputId}\n checked={checked}\n disabled={isEssential}\n onChange={\n isEssential\n ? undefined\n : (e: ChangeEvent<HTMLInputElement>): void => handleChange(attr, e.target.checked)\n }\n />\n )}\n </div>\n </div>\n );\n })}\n </div>\n );\n};\n\nexport default ConsentCheckboxList;\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAmBA,MAAa,yBAAyB,WAAmB,aACvD,kBAAkB,UAAU,IAAI;;;;;;;;AA0ElC,MAAMA,uBAAqD,EACzD,SACA,SACA,YACA,eACA,UACA,QAC8B;CAC9B,MAAM,EAAC,OAAO,gBAA4CC,0BAAU;CACpE,MAAMC,SAAiCC,2CAAU,OAAO,YAAY;CAEpE,MAAM,WAAW,SAAqC;AACpD,MAAI,CAAC,QAAQ,CAAC,EACZ,QAAO,QAAQ;EAGjB,MAAMC,MAAc,WAAW;EAC/B,MAAMC,aAAqB,EAAE,IAAI;AACjC,SAAO,eAAe,MAAM,OAAO;;CAGrC,MAAMC,cAAwB,YAAY,cAAc,QAAQ,YAAY,QAAQ,UAAU,KAC3F,MAAc,EAAE,KAClB;AAED,KAAI,CAAC,cAAc,WAAW,WAAW,EACvC,QAAO;CAGT,MAAMC,cAAuB,YAAY;CAEzC,MAAM,aAAa,aAA8B;AAC/C,MAAI,YACF,QAAO;AAIT,SAAO,WAFa,sBAAsB,QAAQ,WAAW,SAAS,MAE3C;;CAG7B,MAAM,gBAAgB,UAAkB,YAA2B;AAEjE,gBADoB,sBAAsB,QAAQ,WAAW,SAAS,EACnD,UAAU,SAAS,QAAQ;;AAGhD,KAAI,SACF,QAAO,mFAAG,SAAS;EAAC;EAAY;EAAc;EAAW;EAAQ,CAAC,GAAI;AAGxE,QACE,2CAAC;EAAI,WAAWC,kGAAgC,wBAAwB,CAAC,EAAE,OAAO,iBAAiB;YAChG,WAAW,KAAK,SAAiB;GAChC,MAAM,UAAU,WAAW,cAAc,QAAQ,MAAM,GAAG,QAAQ,UAAU,GAAG;GAC/E,MAAMC,UAAmB,UAAU,KAAK;AAExC,UACE,2CAAC;IAEC,WAAWD,kGAAgC,yBAAyB,OAAO,CAAC,EAAE,OAAO,YAAY;cAEjG,4CAAC;KAAI,WAAWA,kGAAgC,yBAAyB,MAAM,CAAC,EAAE,OAAO,WAAW;gBAClG,4CAAC;MACC,WAAWA,kGACoB,yBAAyB,kBAAkB,CAAC,EACzE,OAAO,kBACR;iBAED,2CAAC,SACC,WAAWA,kGAAgC,yBAAyB,SAAS,CAAC,EAAE,OAAO,UAAU,GACjG,EACF,2CAACE;OACC,SAAQ;OACR,WAAWF,kGACoB,yBAAyB,aAAa,CAAC,EACpE,OAAO,cACR;iBAEA,QAAQ,KAAK;QACH;OACT,EACL,cACC,2CAACE;MAAW,SAAQ;gBAAS,QAAQ,WAAW,IAAI;OAAwB,GAE5E,2CAACC;MACC,IAAI;MACK;MACT,UAAU;MACV,UACE,cACI,UACC,MAA2C,aAAa,MAAM,EAAE,OAAO,QAAQ;OAEtF;MAEA;MArCD,KAsCD;IAER;GACE;;AAIV,kCAAe"}
@@ -51,17 +51,25 @@ const LanguageSwitcher = ({ children, className }) => {
51
51
  emoji: (0, __thunderid_browser.resolveLocaleEmoji)(code)
52
52
  })), [effectiveLanguageCodes]);
53
53
  (0, react.useEffect)(() => {
54
- if (availableLanguageCodes.length > 0 && !availableLanguageCodes.includes(currentLanguage)) switchLanguage(availableLanguageCodes[0]);
54
+ if (availableLanguageCodes.length === 0) return;
55
+ const currentBase = (0, __thunderid_browser.getBaseLanguage)(currentLanguage);
56
+ if (availableLanguageCodes.some((code) => (0, __thunderid_browser.getBaseLanguage)(code) === currentBase)) return;
57
+ switchLanguage(availableLanguageCodes.find((code) => (0, __thunderid_browser.getBaseLanguage)(code) === "en") ?? availableLanguageCodes[0]);
55
58
  }, [
56
59
  availableLanguageCodes,
57
60
  currentLanguage,
58
61
  switchLanguage
59
62
  ]);
63
+ const displayLanguage = (0, react.useMemo)(() => {
64
+ const exactMatch = languages.find((option) => (0, __thunderid_browser.normalizeLocaleTag)(option.code) === (0, __thunderid_browser.normalizeLocaleTag)(currentLanguage));
65
+ if (exactMatch) return exactMatch.code;
66
+ return languages.find((option) => (0, __thunderid_browser.getBaseLanguage)(option.code) === (0, __thunderid_browser.getBaseLanguage)(currentLanguage))?.code ?? currentLanguage;
67
+ }, [languages, currentLanguage]);
60
68
  const handleLanguageChange = (language) => {
61
69
  if (language !== currentLanguage) switchLanguage(language);
62
70
  };
63
71
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_BaseLanguageSwitcher.default, {
64
- currentLanguage,
72
+ currentLanguage: displayLanguage,
65
73
  isLoading,
66
74
  languages,
67
75
  onLanguageChange: handleLanguageChange,
@@ -1 +1 @@
1
- {"version":3,"file":"LanguageSwitcher.cjs","names":["LanguageSwitcher: FC<LanguageSwitcherProps>","useFlowMeta","useTranslation","availableLanguageCodes: string[]","effectiveLanguageCodes: string[]","languages: LanguageOption[]","BaseLanguageSwitcher"],"sources":["../../../../../src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {resolveLocaleDisplayName, resolveLocaleEmoji} from '@thunderid/browser';\nimport {FC, ReactElement, ReactNode, useEffect, useMemo} from 'react';\nimport BaseLanguageSwitcher, {LanguageOption, LanguageSwitcherRenderProps} from './BaseLanguageSwitcher';\nimport useFlowMeta from '../../../contexts/FlowMeta/useFlowMeta';\nimport useTranslation from '../../../hooks/useTranslation';\n\nexport type {LanguageOption, LanguageSwitcherRenderProps};\n\nexport interface LanguageSwitcherProps {\n /**\n * Render-props callback for fully custom UI.\n *\n * @example\n * ```tsx\n * <LanguageSwitcher>\n * {({languages, currentLanguage, onLanguageChange, isLoading}) => (\n * <select\n * value={currentLanguage}\n * disabled={isLoading}\n * onChange={e => onLanguageChange(e.target.value)}\n * >\n * {languages.map(l => (\n * <option key={l.code} value={l.code}>{l.emoji} {l.displayName}</option>\n * ))}\n * </select>\n * )}\n * </LanguageSwitcher>\n * ```\n */\n children?: (props: LanguageSwitcherRenderProps) => ReactNode;\n /** Additional CSS class for the root element (default UI only) */\n className?: string;\n}\n\n/**\n * A v2 LanguageSwitcher component that reads available languages from `FlowMetaContext`\n * and switches both the UI language (via `I18nContext`) and the flow metadata translations\n * (by re-fetching `GET /flow/meta` with the new language).\n *\n * Must be rendered inside a `FlowMetaProvider`.\n *\n * @example\n * ```tsx\n * // Default dropdown UI\n * <LanguageSwitcher />\n *\n * // Custom UI with render props\n * <LanguageSwitcher>\n * {({languages, currentLanguage, onLanguageChange}) => (\n * <div>\n * {languages.map(lang => (\n * <button\n * key={lang.code}\n * onClick={() => onLanguageChange(lang.code)}\n * style={{fontWeight: lang.code === currentLanguage ? 'bold' : 'normal'}}\n * >\n * {lang.emoji} {lang.displayName}\n * </button>\n * ))}\n * </div>\n * )}\n * </LanguageSwitcher>\n * ```\n */\nconst LanguageSwitcher: FC<LanguageSwitcherProps> = ({children, className}: LanguageSwitcherProps): ReactElement => {\n const {meta, switchLanguage, isLoading} = useFlowMeta();\n const {currentLanguage} = useTranslation();\n\n const availableLanguageCodes: string[] = meta?.i18n?.languages ?? [];\n // Only fall back to the detected browser language when the server returns no configured languages.\n // Do NOT inject currentLanguage unconditionally — a browser locale like \"en-GB\" must not appear\n // in the picker when the server only supports \"en-US\".\n const effectiveLanguageCodes: string[] = useMemo(\n () => (availableLanguageCodes.length > 0 ? availableLanguageCodes : [currentLanguage]),\n [availableLanguageCodes, currentLanguage],\n );\n\n const languages: LanguageOption[] = useMemo(\n () =>\n effectiveLanguageCodes.map((code: string) => ({\n code,\n // Resolve each label in its own locale so option names stay stable across UI language switches.\n displayName: resolveLocaleDisplayName(code, code) || code,\n emoji: resolveLocaleEmoji(code),\n })),\n [effectiveLanguageCodes],\n );\n\n // If the detected language isn't supported by the server, fall back to the first available language.\n useEffect(() => {\n if (availableLanguageCodes.length > 0 && !availableLanguageCodes.includes(currentLanguage)) {\n switchLanguage(availableLanguageCodes[0]);\n }\n }, [availableLanguageCodes, currentLanguage, switchLanguage]);\n\n const handleLanguageChange = (language: string): void => {\n if (language !== currentLanguage) {\n switchLanguage(language);\n }\n };\n\n return (\n <BaseLanguageSwitcher\n currentLanguage={currentLanguage}\n isLoading={isLoading}\n languages={languages}\n onLanguageChange={handleLanguageChange}\n className={className}\n >\n {children}\n </BaseLanguageSwitcher>\n );\n};\n\nexport default LanguageSwitcher;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmEA,MAAMA,oBAA+C,EAAC,UAAU,gBAAoD;CAClH,MAAM,EAAC,MAAM,gBAAgB,cAAaC,6BAAa;CACvD,MAAM,EAAC,oBAAmBC,gCAAgB;CAE1C,MAAMC,yBAAmC,MAAM,MAAM,aAAa,EAAE;CAIpE,MAAMC,kDACG,uBAAuB,SAAS,IAAI,yBAAyB,CAAC,gBAAgB,EACrF,CAAC,wBAAwB,gBAAgB,CAC1C;CAED,MAAMC,qCAEF,uBAAuB,KAAK,UAAkB;EAC5C;EAEA,+DAAsC,MAAM,KAAK,IAAI;EACrD,mDAA0B,KAAK;EAChC,EAAE,EACL,CAAC,uBAAuB,CACzB;AAGD,4BAAgB;AACd,MAAI,uBAAuB,SAAS,KAAK,CAAC,uBAAuB,SAAS,gBAAgB,CACxF,gBAAe,uBAAuB,GAAG;IAE1C;EAAC;EAAwB;EAAiB;EAAe,CAAC;CAE7D,MAAM,wBAAwB,aAA2B;AACvD,MAAI,aAAa,gBACf,gBAAe,SAAS;;AAI5B,QACE,2CAACC;EACkB;EACN;EACA;EACX,kBAAkB;EACP;EAEV;GACoB;;AAI3B,+BAAe"}
1
+ {"version":3,"file":"LanguageSwitcher.cjs","names":["LanguageSwitcher: FC<LanguageSwitcherProps>","useFlowMeta","useTranslation","availableLanguageCodes: string[]","effectiveLanguageCodes: string[]","languages: LanguageOption[]","currentBase: string","displayLanguage: string","exactMatch: LanguageOption | undefined","BaseLanguageSwitcher"],"sources":["../../../../../src/components/presentation/LanguageSwitcher/LanguageSwitcher.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {getBaseLanguage, normalizeLocaleTag, resolveLocaleDisplayName, resolveLocaleEmoji} from '@thunderid/browser';\nimport {FC, ReactElement, ReactNode, useEffect, useMemo} from 'react';\nimport BaseLanguageSwitcher, {LanguageOption, LanguageSwitcherRenderProps} from './BaseLanguageSwitcher';\nimport useFlowMeta from '../../../contexts/FlowMeta/useFlowMeta';\nimport useTranslation from '../../../hooks/useTranslation';\n\nexport type {LanguageOption, LanguageSwitcherRenderProps};\n\nexport interface LanguageSwitcherProps {\n /**\n * Render-props callback for fully custom UI.\n *\n * @example\n * ```tsx\n * <LanguageSwitcher>\n * {({languages, currentLanguage, onLanguageChange, isLoading}) => (\n * <select\n * value={currentLanguage}\n * disabled={isLoading}\n * onChange={e => onLanguageChange(e.target.value)}\n * >\n * {languages.map(l => (\n * <option key={l.code} value={l.code}>{l.emoji} {l.displayName}</option>\n * ))}\n * </select>\n * )}\n * </LanguageSwitcher>\n * ```\n */\n children?: (props: LanguageSwitcherRenderProps) => ReactNode;\n /** Additional CSS class for the root element (default UI only) */\n className?: string;\n}\n\n/**\n * A v2 LanguageSwitcher component that reads available languages from `FlowMetaContext`\n * and switches both the UI language (via `I18nContext`) and the flow metadata translations\n * (by re-fetching `GET /flow/meta` with the new language).\n *\n * Must be rendered inside a `FlowMetaProvider`.\n *\n * @example\n * ```tsx\n * // Default dropdown UI\n * <LanguageSwitcher />\n *\n * // Custom UI with render props\n * <LanguageSwitcher>\n * {({languages, currentLanguage, onLanguageChange}) => (\n * <div>\n * {languages.map(lang => (\n * <button\n * key={lang.code}\n * onClick={() => onLanguageChange(lang.code)}\n * style={{fontWeight: lang.code === currentLanguage ? 'bold' : 'normal'}}\n * >\n * {lang.emoji} {lang.displayName}\n * </button>\n * ))}\n * </div>\n * )}\n * </LanguageSwitcher>\n * ```\n */\nconst LanguageSwitcher: FC<LanguageSwitcherProps> = ({children, className}: LanguageSwitcherProps): ReactElement => {\n const {meta, switchLanguage, isLoading} = useFlowMeta();\n const {currentLanguage} = useTranslation();\n\n const availableLanguageCodes: string[] = meta?.i18n?.languages ?? [];\n // Only fall back to the detected browser language when the server returns no configured languages.\n // Do NOT inject currentLanguage unconditionally — a browser locale like \"en-GB\" must not appear\n // in the picker when the server only supports \"en-US\".\n const effectiveLanguageCodes: string[] = useMemo(\n () => (availableLanguageCodes.length > 0 ? availableLanguageCodes : [currentLanguage]),\n [availableLanguageCodes, currentLanguage],\n );\n\n const languages: LanguageOption[] = useMemo(\n () =>\n effectiveLanguageCodes.map((code: string) => ({\n code,\n // Resolve each label in its own locale so option names stay stable across UI language switches.\n displayName: resolveLocaleDisplayName(code, code) || code,\n emoji: resolveLocaleEmoji(code),\n })),\n [effectiveLanguageCodes],\n );\n\n // If the detected language isn't supported by the server, fall back to English (matched by base\n // language, e.g. browser \"en-US\" against server \"en\"), or the first available language if the\n // server doesn't offer English either.\n useEffect(() => {\n if (availableLanguageCodes.length === 0) {\n return;\n }\n const currentBase: string = getBaseLanguage(currentLanguage);\n const isSupported: boolean = availableLanguageCodes.some(\n (code: string): boolean => getBaseLanguage(code) === currentBase,\n );\n if (isSupported) {\n return;\n }\n const englishCode: string | undefined = availableLanguageCodes.find(\n (code: string): boolean => getBaseLanguage(code) === 'en',\n );\n switchLanguage(englishCode ?? availableLanguageCodes[0]);\n }, [availableLanguageCodes, currentLanguage, switchLanguage]);\n\n // Prefer an exact dialect match (e.g. \"en-IN\" against a supported \"en-IN\") over a base-language\n // one, so a specific regional variant isn't silently collapsed to \"en\" when it's actually offered.\n // Only fall back to a base-language match (e.g. \"en-US\" against a supported \"en\") when the exact\n // dialect isn't available, and to the raw code if neither is.\n const displayLanguage: string = useMemo(() => {\n const exactMatch: LanguageOption | undefined = languages.find(\n (option: LanguageOption): boolean => normalizeLocaleTag(option.code) === normalizeLocaleTag(currentLanguage),\n );\n if (exactMatch) {\n return exactMatch.code;\n }\n const baseMatch: LanguageOption | undefined = languages.find(\n (option: LanguageOption): boolean => getBaseLanguage(option.code) === getBaseLanguage(currentLanguage),\n );\n return baseMatch?.code ?? currentLanguage;\n }, [languages, currentLanguage]);\n\n const handleLanguageChange = (language: string): void => {\n if (language !== currentLanguage) {\n switchLanguage(language);\n }\n };\n\n return (\n <BaseLanguageSwitcher\n currentLanguage={displayLanguage}\n isLoading={isLoading}\n languages={languages}\n onLanguageChange={handleLanguageChange}\n className={className}\n >\n {children}\n </BaseLanguageSwitcher>\n );\n};\n\nexport default LanguageSwitcher;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmEA,MAAMA,oBAA+C,EAAC,UAAU,gBAAoD;CAClH,MAAM,EAAC,MAAM,gBAAgB,cAAaC,6BAAa;CACvD,MAAM,EAAC,oBAAmBC,gCAAgB;CAE1C,MAAMC,yBAAmC,MAAM,MAAM,aAAa,EAAE;CAIpE,MAAMC,kDACG,uBAAuB,SAAS,IAAI,yBAAyB,CAAC,gBAAgB,EACrF,CAAC,wBAAwB,gBAAgB,CAC1C;CAED,MAAMC,qCAEF,uBAAuB,KAAK,UAAkB;EAC5C;EAEA,+DAAsC,MAAM,KAAK,IAAI;EACrD,mDAA0B,KAAK;EAChC,EAAE,EACL,CAAC,uBAAuB,CACzB;AAKD,4BAAgB;AACd,MAAI,uBAAuB,WAAW,EACpC;EAEF,MAAMC,uDAAsC,gBAAgB;AAI5D,MAH6B,uBAAuB,MACjD,kDAA0C,KAAK,KAAK,YACtD,CAEC;AAKF,iBAHwC,uBAAuB,MAC5D,kDAA0C,KAAK,KAAK,KACtD,IAC6B,uBAAuB,GAAG;IACvD;EAAC;EAAwB;EAAiB;EAAe,CAAC;CAM7D,MAAMC,2CAAwC;EAC5C,MAAMC,aAAyC,UAAU,MACtD,uDAAuD,OAAO,KAAK,iDAAwB,gBAAgB,CAC7G;AACD,MAAI,WACF,QAAO,WAAW;AAKpB,SAH8C,UAAU,MACrD,oDAAoD,OAAO,KAAK,8CAAqB,gBAAgB,CACvG,EACiB,QAAQ;IACzB,CAAC,WAAW,gBAAgB,CAAC;CAEhC,MAAM,wBAAwB,aAA2B;AACvD,MAAI,aAAa,gBACf,gBAAe,SAAS;;AAI5B,QACE,2CAACC;EACC,iBAAiB;EACN;EACA;EACX,kBAAkB;EACP;EAEV;GACoB;;AAI3B,+BAAe"}
@@ -408,6 +408,7 @@ const createAuthComponentFromFlow = (component, formValues, touchedFields, formE
408
408
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("form", {
409
409
  id: component.id,
410
410
  className: require_emotion.cx(component.classes, formClass),
411
+ onSubmit: (event) => event.preventDefault(),
411
412
  children: blockComponents
412
413
  }, key);
413
414
  }
@@ -527,8 +528,6 @@ const createAuthComponentFromFlow = (component, formValues, touchedFields, formE
527
528
  consentData: consentPromptRawData,
528
529
  formValues,
529
530
  onInputChange,
530
- config: component.config,
531
- meta: options.meta,
532
531
  t: options.t
533
532
  }, key);
534
533
  }