@thunderid/react 1.8.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/account/UserProfile/BaseUserProfile.cjs +1 -1
- package/dist/cjs/components/admin/AgentDetails/AgentDetails.cjs +13 -2
- package/dist/cjs/components/admin/AgentDetails/AgentDetails.cjs.map +1 -1
- package/dist/cjs/components/admin/AgentDetails/BaseAgentDetails.cjs +25 -7
- package/dist/cjs/components/admin/AgentDetails/BaseAgentDetails.cjs.map +1 -1
- package/dist/cjs/components/admin/ApplicationDetails/ApplicationDetails.cjs +15 -2
- package/dist/cjs/components/admin/ApplicationDetails/ApplicationDetails.cjs.map +1 -1
- package/dist/cjs/components/admin/ApplicationDetails/BaseApplicationDetails.cjs +24 -7
- package/dist/cjs/components/admin/ApplicationDetails/BaseApplicationDetails.cjs.map +1 -1
- package/dist/cjs/components/admin/GroupMembers/GroupMembers.cjs +2 -1
- package/dist/cjs/components/admin/GroupMembers/GroupMembers.cjs.map +1 -1
- package/dist/cjs/components/admin/RoleAssignments/RoleAssignments.cjs +2 -1
- package/dist/cjs/components/admin/RoleAssignments/RoleAssignments.cjs.map +1 -1
- package/dist/cjs/components/admin/UserDetails/BaseUserDetails.cjs +32 -14
- package/dist/cjs/components/admin/UserDetails/BaseUserDetails.cjs.map +1 -1
- package/dist/cjs/components/admin/UserDetails/UserDetails.cjs +14 -2
- package/dist/cjs/components/admin/UserDetails/UserDetails.cjs.map +1 -1
- package/dist/cjs/components/admin/shared/AccountLifecycleParts.cjs +105 -0
- package/dist/cjs/components/admin/shared/AccountLifecycleParts.cjs.map +1 -0
- package/dist/cjs/components/admin/shared/ApplicationFormFields.cjs +1 -1
- package/dist/cjs/components/auth/AcceptInvite/BaseAcceptInvite.cjs +4 -5
- package/dist/cjs/components/auth/AcceptInvite/BaseAcceptInvite.cjs.map +1 -1
- package/dist/cjs/components/auth/SignIn/SignIn.cjs +5 -5
- package/dist/cjs/components/auth/SignIn/SignIn.cjs.map +1 -1
- package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs +4 -5
- package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs.map +1 -1
- package/dist/cjs/components/auth/flow/Consent.cjs +53 -28
- package/dist/cjs/components/auth/flow/Consent.cjs.map +1 -1
- package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.cjs +104 -0
- package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.cjs.map +1 -0
- package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.styles.cjs +59 -0
- package/dist/cjs/components/auth/flow/ConsentAuthorizationDetail.styles.cjs.map +1 -0
- package/dist/cjs/components/auth/flow/ConsentDetailField.cjs +171 -0
- package/dist/cjs/components/auth/flow/ConsentDetailField.cjs.map +1 -0
- package/dist/cjs/components/auth/flow/ConsentDetailField.styles.cjs +85 -0
- package/dist/cjs/components/auth/flow/ConsentDetailField.styles.cjs.map +1 -0
- package/dist/cjs/components/auth/flow/ConsentDetailText.cjs +63 -0
- package/dist/cjs/components/auth/flow/ConsentDetailText.cjs.map +1 -0
- package/dist/cjs/components/auth/flow/ConsentDetailText.styles.cjs +83 -0
- package/dist/cjs/components/auth/flow/ConsentDetailText.styles.cjs.map +1 -0
- package/dist/cjs/components/auth/flow/FieldFactory.cjs +1 -1
- package/dist/cjs/components/auth/flow/resolveConsentText.cjs +25 -0
- package/dist/cjs/components/auth/flow/resolveConsentText.cjs.map +1 -0
- package/dist/cjs/components/primitives/KeyValueInput/KeyValueInput.cjs +1 -1
- package/dist/cjs/components/primitives/MultiInput/MultiInput.cjs +1 -1
- package/dist/cjs/components/primitives/PasswordField/PasswordField.cjs +1 -1
- package/dist/cjs/contexts/Theme/ThemeProvider.cjs +36 -6
- package/dist/cjs/contexts/Theme/ThemeProvider.cjs.map +1 -1
- package/dist/cjs/contexts/Theme/ThemeRootContext.cjs +12 -0
- package/dist/cjs/contexts/Theme/ThemeRootContext.cjs.map +1 -0
- package/dist/cjs/hooks/auth/useConsentDetailField.cjs +357 -0
- package/dist/cjs/hooks/auth/useConsentDetailField.cjs.map +1 -0
- package/dist/cjs/hooks/management/useAccountLifecycle.cjs +59 -0
- package/dist/cjs/hooks/management/useAccountLifecycle.cjs.map +1 -0
- package/dist/cjs/index.cjs +66 -1
- package/dist/cjs/utils/formatConsentDetailValue.cjs +26 -0
- package/dist/cjs/utils/formatConsentDetailValue.cjs.map +1 -0
- package/dist/cjs/utils/getConsentDetailLayout.cjs +44 -0
- package/dist/cjs/utils/getConsentDetailLayout.cjs.map +1 -0
- package/dist/cjs/utils/getConsentDetailListDisplay.cjs +30 -0
- package/dist/cjs/utils/getConsentDetailListDisplay.cjs.map +1 -0
- package/dist/cjs/utils/isConsentApprovalBlocked.cjs +41 -0
- package/dist/cjs/utils/isConsentApprovalBlocked.cjs.map +1 -0
- package/dist/cjs/utils/isConsentDetailPlainList.cjs +24 -0
- package/dist/cjs/utils/isConsentDetailPlainList.cjs.map +1 -0
- package/dist/cjs/utils/isConsentDetailStructured.cjs +15 -0
- package/dist/cjs/utils/isConsentDetailStructured.cjs.map +1 -0
- package/dist/cjs/utils/isConsentDetailTextClamped.cjs +25 -0
- package/dist/cjs/utils/isConsentDetailTextClamped.cjs.map +1 -0
- package/dist/components/account/UserProfile/BaseUserProfile.js +1 -1
- package/dist/components/admin/AgentDetails/AgentDetails.d.ts +8 -1
- package/dist/components/admin/AgentDetails/AgentDetails.d.ts.map +1 -1
- package/dist/components/admin/AgentDetails/AgentDetails.js +13 -2
- package/dist/components/admin/AgentDetails/AgentDetails.js.map +1 -1
- package/dist/components/admin/AgentDetails/BaseAgentDetails.d.ts +21 -1
- package/dist/components/admin/AgentDetails/BaseAgentDetails.d.ts.map +1 -1
- package/dist/components/admin/AgentDetails/BaseAgentDetails.js +25 -7
- package/dist/components/admin/AgentDetails/BaseAgentDetails.js.map +1 -1
- package/dist/components/admin/ApplicationDetails/ApplicationDetails.d.ts +15 -1
- package/dist/components/admin/ApplicationDetails/ApplicationDetails.d.ts.map +1 -1
- package/dist/components/admin/ApplicationDetails/ApplicationDetails.js +15 -2
- package/dist/components/admin/ApplicationDetails/ApplicationDetails.js.map +1 -1
- package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.d.ts +20 -1
- package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.d.ts.map +1 -1
- package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.js +24 -7
- package/dist/components/admin/ApplicationDetails/BaseApplicationDetails.js.map +1 -1
- package/dist/components/admin/GroupMembers/GroupMembers.d.ts +7 -0
- package/dist/components/admin/GroupMembers/GroupMembers.d.ts.map +1 -1
- package/dist/components/admin/GroupMembers/GroupMembers.js +2 -1
- package/dist/components/admin/GroupMembers/GroupMembers.js.map +1 -1
- package/dist/components/admin/RoleAssignments/RoleAssignments.d.ts +7 -0
- package/dist/components/admin/RoleAssignments/RoleAssignments.d.ts.map +1 -1
- package/dist/components/admin/RoleAssignments/RoleAssignments.js +2 -1
- package/dist/components/admin/RoleAssignments/RoleAssignments.js.map +1 -1
- package/dist/components/admin/UserDetails/BaseUserDetails.d.ts +22 -1
- package/dist/components/admin/UserDetails/BaseUserDetails.d.ts.map +1 -1
- package/dist/components/admin/UserDetails/BaseUserDetails.js +32 -14
- package/dist/components/admin/UserDetails/BaseUserDetails.js.map +1 -1
- package/dist/components/admin/UserDetails/UserDetails.d.ts +15 -1
- package/dist/components/admin/UserDetails/UserDetails.d.ts.map +1 -1
- package/dist/components/admin/UserDetails/UserDetails.js +14 -2
- package/dist/components/admin/UserDetails/UserDetails.js.map +1 -1
- package/dist/components/admin/shared/AccountLifecycleParts.d.ts +32 -0
- package/dist/components/admin/shared/AccountLifecycleParts.d.ts.map +1 -0
- package/dist/components/admin/shared/AccountLifecycleParts.js +101 -0
- package/dist/components/admin/shared/AccountLifecycleParts.js.map +1 -0
- package/dist/components/admin/shared/ApplicationFormFields.js +1 -1
- package/dist/components/auth/AcceptInvite/BaseAcceptInvite.d.ts.map +1 -1
- package/dist/components/auth/AcceptInvite/BaseAcceptInvite.js +5 -6
- package/dist/components/auth/AcceptInvite/BaseAcceptInvite.js.map +1 -1
- package/dist/components/auth/SignIn/SignIn.d.ts.map +1 -1
- package/dist/components/auth/SignIn/SignIn.js +6 -6
- package/dist/components/auth/SignIn/SignIn.js.map +1 -1
- package/dist/components/auth/flow/AuthOptionFactory.d.ts.map +1 -1
- package/dist/components/auth/flow/AuthOptionFactory.js +5 -6
- package/dist/components/auth/flow/AuthOptionFactory.js.map +1 -1
- package/dist/components/auth/flow/Consent.d.ts +6 -0
- package/dist/components/auth/flow/Consent.d.ts.map +1 -1
- package/dist/components/auth/flow/Consent.js +54 -29
- package/dist/components/auth/flow/Consent.js.map +1 -1
- package/dist/components/auth/flow/ConsentAuthorizationDetail.d.ts +68 -0
- package/dist/components/auth/flow/ConsentAuthorizationDetail.d.ts.map +1 -0
- package/dist/components/auth/flow/ConsentAuthorizationDetail.js +100 -0
- package/dist/components/auth/flow/ConsentAuthorizationDetail.js.map +1 -0
- package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.d.ts +10 -0
- package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.d.ts.map +1 -0
- package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.js +57 -0
- package/dist/components/auth/flow/ConsentAuthorizationDetail.styles.js.map +1 -0
- package/dist/components/auth/flow/ConsentDetailField.d.ts +39 -0
- package/dist/components/auth/flow/ConsentDetailField.d.ts.map +1 -0
- package/dist/components/auth/flow/ConsentDetailField.js +168 -0
- package/dist/components/auth/flow/ConsentDetailField.js.map +1 -0
- package/dist/components/auth/flow/ConsentDetailField.styles.d.ts +11 -0
- package/dist/components/auth/flow/ConsentDetailField.styles.d.ts.map +1 -0
- package/dist/components/auth/flow/ConsentDetailField.styles.js +83 -0
- package/dist/components/auth/flow/ConsentDetailField.styles.js.map +1 -0
- package/dist/components/auth/flow/ConsentDetailText.d.ts +53 -0
- package/dist/components/auth/flow/ConsentDetailText.d.ts.map +1 -0
- package/dist/components/auth/flow/ConsentDetailText.js +58 -0
- package/dist/components/auth/flow/ConsentDetailText.js.map +1 -0
- package/dist/components/auth/flow/ConsentDetailText.styles.d.ts +20 -0
- package/dist/components/auth/flow/ConsentDetailText.styles.d.ts.map +1 -0
- package/dist/components/auth/flow/ConsentDetailText.styles.js +80 -0
- package/dist/components/auth/flow/ConsentDetailText.styles.js.map +1 -0
- package/dist/components/auth/flow/FieldFactory.js +1 -1
- package/dist/components/auth/flow/resolveConsentText.d.ts +13 -0
- package/dist/components/auth/flow/resolveConsentText.d.ts.map +1 -0
- package/dist/components/auth/flow/resolveConsentText.js +23 -0
- package/dist/components/auth/flow/resolveConsentText.js.map +1 -0
- package/dist/components/primitives/KeyValueInput/KeyValueInput.js +1 -1
- package/dist/components/primitives/MultiInput/MultiInput.js +1 -1
- package/dist/components/primitives/PasswordField/PasswordField.js +1 -1
- package/dist/contexts/Theme/ThemeProvider.d.ts +2 -1
- package/dist/contexts/Theme/ThemeProvider.d.ts.map +1 -1
- package/dist/contexts/Theme/ThemeProvider.js +37 -7
- package/dist/contexts/Theme/ThemeProvider.js.map +1 -1
- package/dist/contexts/Theme/ThemeRootContext.d.ts +11 -0
- package/dist/contexts/Theme/ThemeRootContext.d.ts.map +1 -0
- package/dist/contexts/Theme/ThemeRootContext.js +10 -0
- package/dist/contexts/Theme/ThemeRootContext.js.map +1 -0
- package/dist/hooks/auth/useConsentDetailField.d.ts +130 -0
- package/dist/hooks/auth/useConsentDetailField.d.ts.map +1 -0
- package/dist/hooks/auth/useConsentDetailField.js +354 -0
- package/dist/hooks/auth/useConsentDetailField.js.map +1 -0
- package/dist/hooks/management/useAccountLifecycle.d.ts +49 -0
- package/dist/hooks/management/useAccountLifecycle.d.ts.map +1 -0
- package/dist/hooks/management/useAccountLifecycle.js +56 -0
- package/dist/hooks/management/useAccountLifecycle.js.map +1 -0
- package/dist/index.d.ts +16 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -3
- package/dist/utils/formatConsentDetailValue.d.ts +16 -0
- package/dist/utils/formatConsentDetailValue.d.ts.map +1 -0
- package/dist/utils/formatConsentDetailValue.js +25 -0
- package/dist/utils/formatConsentDetailValue.js.map +1 -0
- package/dist/utils/getConsentDetailLayout.d.ts +32 -0
- package/dist/utils/getConsentDetailLayout.d.ts.map +1 -0
- package/dist/utils/getConsentDetailLayout.js +43 -0
- package/dist/utils/getConsentDetailLayout.js.map +1 -0
- package/dist/utils/getConsentDetailListDisplay.d.ts +30 -0
- package/dist/utils/getConsentDetailListDisplay.d.ts.map +1 -0
- package/dist/utils/getConsentDetailListDisplay.js +30 -0
- package/dist/utils/getConsentDetailListDisplay.js.map +1 -0
- package/dist/utils/isConsentApprovalBlocked.d.ts +17 -0
- package/dist/utils/isConsentApprovalBlocked.d.ts.map +1 -0
- package/dist/utils/isConsentApprovalBlocked.js +39 -0
- package/dist/utils/isConsentApprovalBlocked.js.map +1 -0
- package/dist/utils/isConsentDetailPlainList.d.ts +15 -0
- package/dist/utils/isConsentDetailPlainList.d.ts.map +1 -0
- package/dist/utils/isConsentDetailPlainList.js +23 -0
- package/dist/utils/isConsentDetailPlainList.js.map +1 -0
- package/dist/utils/isConsentDetailStructured.d.ts +10 -0
- package/dist/utils/isConsentDetailStructured.d.ts.map +1 -0
- package/dist/utils/isConsentDetailStructured.js +14 -0
- package/dist/utils/isConsentDetailStructured.js.map +1 -0
- package/dist/utils/isConsentDetailTextClamped.d.ts +20 -0
- package/dist/utils/isConsentDetailTextClamped.d.ts.map +1 -0
- package/dist/utils/isConsentDetailTextClamped.js +24 -0
- package/dist/utils/isConsentDetailTextClamped.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { cx } from "../../../styles/emotion.js";
|
|
2
|
+
import useTheme_default from "../../../contexts/Theme/useTheme.js";
|
|
3
|
+
import Typography_default from "../../primitives/Typography/Typography.js";
|
|
4
|
+
import ConsentDetailText_styles_default, { useToggleStyles } from "./ConsentDetailText.styles.js";
|
|
5
|
+
import resolveConsentText_default from "./resolveConsentText.js";
|
|
6
|
+
import isConsentDetailTextClamped_default from "../../../utils/isConsentDetailTextClamped.js";
|
|
7
|
+
import { bem, withVendorCSSClassPrefix } from "@thunderid/browser";
|
|
8
|
+
import { useState } from "react";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
|
|
11
|
+
//#region src/components/auth/flow/ConsentDetailText.tsx
|
|
12
|
+
/**
|
|
13
|
+
* Button that expands or collapses long authorization detail content.
|
|
14
|
+
*/
|
|
15
|
+
const ConsentDetailToggle = ({ controls = void 0, expanded, hiddenCount = void 0, onToggle, t = void 0 }) => {
|
|
16
|
+
const { theme, colorScheme } = useTheme_default();
|
|
17
|
+
const styles = useToggleStyles(theme, colorScheme);
|
|
18
|
+
let label = resolveConsentText_default(t, "consent.authorization_details.show_less");
|
|
19
|
+
if (!expanded) label = hiddenCount === void 0 ? resolveConsentText_default(t, "consent.authorization_details.show_more") : resolveConsentText_default(t, "consent.authorization_details.more_items", { count: hiddenCount });
|
|
20
|
+
return /* @__PURE__ */ jsx("button", {
|
|
21
|
+
type: "button",
|
|
22
|
+
className: cx(withVendorCSSClassPrefix(bem("consent-detail-text", "toggle")), styles["toggle"]),
|
|
23
|
+
"aria-controls": controls,
|
|
24
|
+
"aria-expanded": expanded,
|
|
25
|
+
onClick: () => onToggle(!expanded),
|
|
26
|
+
children: label
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Shows authorization detail text that wraps anywhere, so a long unbroken token such as an IBAN or a
|
|
31
|
+
* URL never overflows. Text longer than its limit is clamped behind a toggle.
|
|
32
|
+
*/
|
|
33
|
+
const ConsentDetailText = ({ align = "left", className = void 0, fontWeight = void 0, id = void 0, maxChars, maxLines, monospace = false, t = void 0, text, variant = "body2" }) => {
|
|
34
|
+
const [expanded, setExpanded] = useState(false);
|
|
35
|
+
const { theme, colorScheme } = useTheme_default();
|
|
36
|
+
const styles = ConsentDetailText_styles_default(theme, colorScheme, align, monospace, maxLines);
|
|
37
|
+
const long = isConsentDetailTextClamped_default(text, maxChars, maxLines);
|
|
38
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
39
|
+
className: cx(withVendorCSSClassPrefix(bem("consent-detail-text")), styles["container"]),
|
|
40
|
+
children: [/* @__PURE__ */ jsx(Typography_default, {
|
|
41
|
+
id,
|
|
42
|
+
variant,
|
|
43
|
+
fontWeight,
|
|
44
|
+
className: cx(withVendorCSSClassPrefix(bem("consent-detail-text", "text")), styles["text"], monospace && withVendorCSSClassPrefix(bem("consent-detail-text", "text", "monospace")), monospace && styles["monospace"], long && !expanded && styles["clamp"], className),
|
|
45
|
+
children: text
|
|
46
|
+
}), long && /* @__PURE__ */ jsx(ConsentDetailToggle, {
|
|
47
|
+
controls: id,
|
|
48
|
+
expanded,
|
|
49
|
+
onToggle: setExpanded,
|
|
50
|
+
t
|
|
51
|
+
})]
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
var ConsentDetailText_default = ConsentDetailText;
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { ConsentDetailToggle, ConsentDetailText_default as default };
|
|
58
|
+
//# sourceMappingURL=ConsentDetailText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConsentDetailText.js","names":["ConsentDetailToggle: FC<ConsentDetailToggleProps>","useTheme","styles: Record<string, string>","label: string","resolveConsentText","ConsentDetailText: FC<ConsentDetailTextProps>","useStyles","long: boolean","isConsentDetailTextClamped","Typography"],"sources":["../../../../src/components/auth/flow/ConsentDetailText.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {bem, withVendorCSSClassPrefix} from '@thunderid/browser';\nimport {FC, ReactElement, useState} from 'react';\nimport useStyles, {useToggleStyles} from './ConsentDetailText.styles';\nimport resolveConsentText from './resolveConsentText';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport {UseTranslation} from '../../../hooks/useTranslation';\nimport {cx} from '../../../styles/emotion';\nimport isConsentDetailTextClamped from '../../../utils/isConsentDetailTextClamped';\nimport Typography from '../../primitives/Typography/Typography';\n\n/**\n * Props for the ConsentDetailToggle component.\n */\nexport interface ConsentDetailToggleProps {\n /** Id of the element the toggle shows more or less of. */\n controls?: string;\n /** Whether everything is shown. */\n expanded: boolean;\n /** Number of items hidden while collapsed. When given, the collapsed label counts them. */\n hiddenCount?: number;\n /** Callback invoked with the next expanded state. */\n onToggle: (expanded: boolean) => void;\n /** translation data */\n t?: UseTranslation['t'];\n}\n\n/**\n * Button that expands or collapses long authorization detail content.\n */\nexport const ConsentDetailToggle: FC<ConsentDetailToggleProps> = ({\n controls = undefined,\n expanded,\n hiddenCount = undefined,\n onToggle,\n t = undefined,\n}: ConsentDetailToggleProps): ReactElement => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const styles: Record<string, string> = useToggleStyles(theme, colorScheme);\n\n let label: string = resolveConsentText(t, 'consent.authorization_details.show_less');\n if (!expanded) {\n label =\n hiddenCount === undefined\n ? resolveConsentText(t, 'consent.authorization_details.show_more')\n : resolveConsentText(t, 'consent.authorization_details.more_items', {count: hiddenCount});\n }\n\n return (\n <button\n type=\"button\"\n className={cx(withVendorCSSClassPrefix(bem('consent-detail-text', 'toggle')), styles['toggle'])}\n aria-controls={controls}\n aria-expanded={expanded}\n onClick={(): void => onToggle(!expanded)}\n >\n {label}\n </button>\n );\n};\n\n/**\n * Props for the ConsentDetailText component.\n */\nexport interface ConsentDetailTextProps {\n /** Alignment of the text. */\n align?: 'left' | 'right';\n /** Class name applied to the text. */\n className?: string;\n /** Weight of the text. */\n fontWeight?: 'normal' | 'medium' | 'semibold' | 'bold';\n /** Id of the text element. */\n id?: string;\n /** Number of characters above which the text is clamped. */\n maxChars: number;\n /** Number of lines the text is clamped to. */\n maxLines: number;\n /** Shows the text as a preformatted monospace block, for structured JSON. */\n monospace?: boolean;\n /** translation data */\n t?: UseTranslation['t'];\n /** Text to show. */\n text: string;\n /** Typography variant of the text. */\n variant?: 'body2' | 'subtitle2';\n}\n\n/**\n * Shows authorization detail text that wraps anywhere, so a long unbroken token such as an IBAN or a\n * URL never overflows. Text longer than its limit is clamped behind a toggle.\n */\nconst ConsentDetailText: FC<ConsentDetailTextProps> = ({\n align = 'left',\n className = undefined,\n fontWeight = undefined,\n id = undefined,\n maxChars,\n maxLines,\n monospace = false,\n t = undefined,\n text,\n variant = 'body2',\n}: ConsentDetailTextProps): ReactElement => {\n const [expanded, setExpanded] = useState<boolean>(false);\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme, align, monospace, maxLines);\n const long: boolean = isConsentDetailTextClamped(text, maxChars, maxLines);\n\n return (\n <div className={cx(withVendorCSSClassPrefix(bem('consent-detail-text')), styles['container'])}>\n <Typography\n id={id}\n variant={variant}\n fontWeight={fontWeight}\n className={cx(\n withVendorCSSClassPrefix(bem('consent-detail-text', 'text')),\n styles['text'],\n monospace && withVendorCSSClassPrefix(bem('consent-detail-text', 'text', 'monospace')),\n monospace && styles['monospace'],\n long && !expanded && styles['clamp'],\n className,\n )}\n >\n {text}\n </Typography>\n {long && <ConsentDetailToggle controls={id} expanded={expanded} onToggle={setExpanded} t={t} />}\n </div>\n );\n};\n\nexport default ConsentDetailText;\n"],"mappings":";;;;;;;;;;;;;;AAgCA,MAAaA,uBAAqD,EAChE,WAAW,QACX,UACA,cAAc,QACd,UACA,IAAI,aACwC;CAC5C,MAAM,EAAC,OAAO,gBAA4CC,kBAAU;CACpE,MAAMC,SAAiC,gBAAgB,OAAO,YAAY;CAE1E,IAAIC,QAAgBC,2BAAmB,GAAG,0CAA0C;AACpF,KAAI,CAAC,SACH,SACE,gBAAgB,SACZA,2BAAmB,GAAG,0CAA0C,GAChEA,2BAAmB,GAAG,4CAA4C,EAAC,OAAO,aAAY,CAAC;AAG/F,QACE,oBAAC;EACC,MAAK;EACL,WAAW,GAAG,yBAAyB,IAAI,uBAAuB,SAAS,CAAC,EAAE,OAAO,UAAU;EAC/F,iBAAe;EACf,iBAAe;EACf,eAAqB,SAAS,CAAC,SAAS;YAEvC;GACM;;;;;;AAkCb,MAAMC,qBAAiD,EACrD,QAAQ,QACR,YAAY,QACZ,aAAa,QACb,KAAK,QACL,UACA,UACA,YAAY,OACZ,IAAI,QACJ,MACA,UAAU,cACgC;CAC1C,MAAM,CAAC,UAAU,eAAe,SAAkB,MAAM;CACxD,MAAM,EAAC,OAAO,gBAA4CJ,kBAAU;CACpE,MAAMC,SAAiCI,iCAAU,OAAO,aAAa,OAAO,WAAW,SAAS;CAChG,MAAMC,OAAgBC,mCAA2B,MAAM,UAAU,SAAS;AAE1E,QACE,qBAAC;EAAI,WAAW,GAAG,yBAAyB,IAAI,sBAAsB,CAAC,EAAE,OAAO,aAAa;aAC3F,oBAACC;GACK;GACK;GACG;GACZ,WAAW,GACT,yBAAyB,IAAI,uBAAuB,OAAO,CAAC,EAC5D,OAAO,SACP,aAAa,yBAAyB,IAAI,uBAAuB,QAAQ,YAAY,CAAC,EACtF,aAAa,OAAO,cACpB,QAAQ,CAAC,YAAY,OAAO,UAC5B,UACD;aAEA;IACU,EACZ,QAAQ,oBAAC;GAAoB,UAAU;GAAc;GAAU,UAAU;GAAgB;IAAK;GAC3F;;AAIV,gCAAe"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Theme } from '@thunderid/browser';
|
|
2
|
+
/**
|
|
3
|
+
* Creates styles for the ConsentDetailToggle component.
|
|
4
|
+
* @param theme - The theme object containing design tokens
|
|
5
|
+
* @param colorScheme - The current color scheme (used for memoization)
|
|
6
|
+
* @returns Object containing CSS class names for component styling
|
|
7
|
+
*/
|
|
8
|
+
export declare const useToggleStyles: (theme: Theme, colorScheme: string) => Record<string, string>;
|
|
9
|
+
/**
|
|
10
|
+
* Creates styles for the ConsentDetailText component.
|
|
11
|
+
* @param theme - The theme object containing design tokens
|
|
12
|
+
* @param colorScheme - The current color scheme (used for memoization)
|
|
13
|
+
* @param align - Alignment of the text
|
|
14
|
+
* @param monospace - Whether the text is shown as a preformatted monospace block
|
|
15
|
+
* @param maxLines - Number of lines the text is clamped to
|
|
16
|
+
* @returns Object containing CSS class names for component styling
|
|
17
|
+
*/
|
|
18
|
+
declare const useStyles: (theme: Theme, colorScheme: string, align: "left" | "right", monospace: boolean, maxLines: number) => Record<string, string>;
|
|
19
|
+
export default useStyles;
|
|
20
|
+
//# sourceMappingURL=ConsentDetailText.styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConsentDetailText.styles.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/flow/ConsentDetailText.styles.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,EAAC,MAAM,oBAAoB,CAAC;AAIzC;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,KAAK,EAAE,aAAa,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAiBtF,CAAC;AAEJ;;;;;;;;GAQG;AACH,QAAA,MAAM,SAAS,GACb,OAAO,KAAK,EACZ,aAAa,MAAM,EACnB,OAAO,MAAM,GAAG,OAAO,EACvB,WAAW,OAAO,EAClB,UAAU,MAAM,KACf,MAAM,CAAC,MAAM,EAAE,MAAM,CAsCrB,CAAC;AAEJ,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { css } from "../../../styles/emotion.js";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/components/auth/flow/ConsentDetailText.styles.ts
|
|
5
|
+
/**
|
|
6
|
+
* Creates styles for the ConsentDetailToggle component.
|
|
7
|
+
* @param theme - The theme object containing design tokens
|
|
8
|
+
* @param colorScheme - The current color scheme (used for memoization)
|
|
9
|
+
* @returns Object containing CSS class names for component styling
|
|
10
|
+
*/
|
|
11
|
+
const useToggleStyles = (theme, colorScheme) => useMemo(() => ({ toggle: css({
|
|
12
|
+
background: "transparent",
|
|
13
|
+
border: "none",
|
|
14
|
+
borderRadius: "4px",
|
|
15
|
+
color: theme.vars.colors.primary.main,
|
|
16
|
+
cursor: "pointer",
|
|
17
|
+
font: "inherit",
|
|
18
|
+
fontSize: "0.8125rem",
|
|
19
|
+
padding: "2px 4px",
|
|
20
|
+
"&:hover": { textDecoration: "underline" },
|
|
21
|
+
"&:focus-visible": {
|
|
22
|
+
outline: `2px solid ${theme.vars.colors.primary.main}`,
|
|
23
|
+
outlineOffset: "1px"
|
|
24
|
+
}
|
|
25
|
+
}) }), [theme, colorScheme]);
|
|
26
|
+
/**
|
|
27
|
+
* Creates styles for the ConsentDetailText component.
|
|
28
|
+
* @param theme - The theme object containing design tokens
|
|
29
|
+
* @param colorScheme - The current color scheme (used for memoization)
|
|
30
|
+
* @param align - Alignment of the text
|
|
31
|
+
* @param monospace - Whether the text is shown as a preformatted monospace block
|
|
32
|
+
* @param maxLines - Number of lines the text is clamped to
|
|
33
|
+
* @returns Object containing CSS class names for component styling
|
|
34
|
+
*/
|
|
35
|
+
const useStyles = (theme, colorScheme, align, monospace, maxLines) => useMemo(() => ({
|
|
36
|
+
clamp: css({
|
|
37
|
+
display: "-webkit-box",
|
|
38
|
+
overflow: "hidden",
|
|
39
|
+
WebkitBoxOrient: "vertical",
|
|
40
|
+
WebkitLineClamp: maxLines
|
|
41
|
+
}),
|
|
42
|
+
container: css({
|
|
43
|
+
alignItems: align === "right" ? "flex-end" : "flex-start",
|
|
44
|
+
display: "flex",
|
|
45
|
+
flexDirection: "column",
|
|
46
|
+
gap: "2px",
|
|
47
|
+
maxWidth: "100%",
|
|
48
|
+
minWidth: 0
|
|
49
|
+
}),
|
|
50
|
+
monospace: css({
|
|
51
|
+
background: theme.vars.colors.action.hover,
|
|
52
|
+
border: `1px solid ${theme.vars.colors.border}`,
|
|
53
|
+
borderRadius: "4px",
|
|
54
|
+
boxSizing: "border-box",
|
|
55
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
56
|
+
fontSize: "0.75rem",
|
|
57
|
+
padding: "6px 8px",
|
|
58
|
+
width: "100%"
|
|
59
|
+
}),
|
|
60
|
+
text: css({
|
|
61
|
+
lineHeight: 1.45,
|
|
62
|
+
margin: 0,
|
|
63
|
+
maxWidth: "100%",
|
|
64
|
+
overflowWrap: "anywhere",
|
|
65
|
+
textAlign: align,
|
|
66
|
+
whiteSpace: monospace ? "pre-wrap" : "normal",
|
|
67
|
+
wordBreak: "normal"
|
|
68
|
+
})
|
|
69
|
+
}), [
|
|
70
|
+
theme,
|
|
71
|
+
colorScheme,
|
|
72
|
+
align,
|
|
73
|
+
monospace,
|
|
74
|
+
maxLines
|
|
75
|
+
]);
|
|
76
|
+
var ConsentDetailText_styles_default = useStyles;
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
export { ConsentDetailText_styles_default as default, useToggleStyles };
|
|
80
|
+
//# sourceMappingURL=ConsentDetailText.styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConsentDetailText.styles.js","names":[],"sources":["../../../../src/components/auth/flow/ConsentDetailText.styles.ts"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {Theme} from '@thunderid/browser';\nimport {useMemo} from 'react';\nimport {css} from '../../../styles/emotion';\n\n/**\n * Creates styles for the ConsentDetailToggle component.\n * @param theme - The theme object containing design tokens\n * @param colorScheme - The current color scheme (used for memoization)\n * @returns Object containing CSS class names for component styling\n */\nexport const useToggleStyles = (theme: Theme, colorScheme: string): Record<string, string> =>\n useMemo(\n () => ({\n toggle: css({\n background: 'transparent',\n border: 'none',\n borderRadius: '4px',\n color: theme.vars.colors.primary.main,\n cursor: 'pointer',\n font: 'inherit',\n fontSize: '0.8125rem',\n padding: '2px 4px',\n '&:hover': {textDecoration: 'underline'},\n '&:focus-visible': {outline: `2px solid ${theme.vars.colors.primary.main}`, outlineOffset: '1px'},\n }),\n }),\n [theme, colorScheme],\n );\n\n/**\n * Creates styles for the ConsentDetailText component.\n * @param theme - The theme object containing design tokens\n * @param colorScheme - The current color scheme (used for memoization)\n * @param align - Alignment of the text\n * @param monospace - Whether the text is shown as a preformatted monospace block\n * @param maxLines - Number of lines the text is clamped to\n * @returns Object containing CSS class names for component styling\n */\nconst useStyles = (\n theme: Theme,\n colorScheme: string,\n align: 'left' | 'right',\n monospace: boolean,\n maxLines: number,\n): Record<string, string> =>\n useMemo(\n () => ({\n clamp: css({\n display: '-webkit-box',\n overflow: 'hidden',\n WebkitBoxOrient: 'vertical',\n WebkitLineClamp: maxLines,\n }),\n container: css({\n alignItems: align === 'right' ? 'flex-end' : 'flex-start',\n display: 'flex',\n flexDirection: 'column',\n gap: '2px',\n maxWidth: '100%',\n minWidth: 0,\n }),\n monospace: css({\n background: theme.vars.colors.action.hover,\n border: `1px solid ${theme.vars.colors.border}`,\n borderRadius: '4px',\n boxSizing: 'border-box',\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',\n fontSize: '0.75rem',\n padding: '6px 8px',\n width: '100%',\n }),\n text: css({\n lineHeight: 1.45,\n margin: 0,\n maxWidth: '100%',\n overflowWrap: 'anywhere',\n textAlign: align,\n whiteSpace: monospace ? 'pre-wrap' : 'normal',\n wordBreak: 'normal',\n }),\n }),\n [theme, colorScheme, align, monospace, maxLines],\n );\n\nexport default useStyles;\n"],"mappings":";;;;;;;;;;AAaA,MAAa,mBAAmB,OAAc,gBAC5C,eACS,EACL,QAAQ,IAAI;CACV,YAAY;CACZ,QAAQ;CACR,cAAc;CACd,OAAO,MAAM,KAAK,OAAO,QAAQ;CACjC,QAAQ;CACR,MAAM;CACN,UAAU;CACV,SAAS;CACT,WAAW,EAAC,gBAAgB,aAAY;CACxC,mBAAmB;EAAC,SAAS,aAAa,MAAM,KAAK,OAAO,QAAQ;EAAQ,eAAe;EAAM;CAClG,CAAC,EACH,GACD,CAAC,OAAO,YAAY,CACrB;;;;;;;;;;AAWH,MAAM,aACJ,OACA,aACA,OACA,WACA,aAEA,eACS;CACL,OAAO,IAAI;EACT,SAAS;EACT,UAAU;EACV,iBAAiB;EACjB,iBAAiB;EAClB,CAAC;CACF,WAAW,IAAI;EACb,YAAY,UAAU,UAAU,aAAa;EAC7C,SAAS;EACT,eAAe;EACf,KAAK;EACL,UAAU;EACV,UAAU;EACX,CAAC;CACF,WAAW,IAAI;EACb,YAAY,MAAM,KAAK,OAAO,OAAO;EACrC,QAAQ,aAAa,MAAM,KAAK,OAAO;EACvC,cAAc;EACd,WAAW;EACX,YAAY;EACZ,UAAU;EACV,SAAS;EACT,OAAO;EACR,CAAC;CACF,MAAM,IAAI;EACR,YAAY;EACZ,QAAQ;EACR,UAAU;EACV,cAAc;EACd,WAAW;EACX,YAAY,YAAY,aAAa;EACrC,WAAW;EACZ,CAAC;CACH,GACD;CAAC;CAAO;CAAa;CAAO;CAAW;CAAS,CACjD;AAEH,uCAAe"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import TextField_default from "../../primitives/TextField/TextField.js";
|
|
1
2
|
import Checkbox_default from "../../primitives/Checkbox/Checkbox.js";
|
|
2
3
|
import DatePicker_default from "../../primitives/DatePicker/DatePicker.js";
|
|
3
4
|
import OtpField_default from "../../primitives/OtpField/OtpField.js";
|
|
4
|
-
import TextField_default from "../../primitives/TextField/TextField.js";
|
|
5
5
|
import PasswordField_default from "../../primitives/PasswordField/PasswordField.js";
|
|
6
6
|
import Select_default from "../../primitives/Select/Select.js";
|
|
7
7
|
import { FieldType } from "@thunderid/browser";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { UseTranslation } from '../../../hooks/useTranslation';
|
|
2
|
+
/**
|
|
3
|
+
* Resolves a consent screen string through the given translator, falling back to the SDK's default
|
|
4
|
+
* bundle when there is no translator or it has no entry for the key.
|
|
5
|
+
*
|
|
6
|
+
* @param t - Translator, when the screen has one.
|
|
7
|
+
* @param key - Translation key.
|
|
8
|
+
* @param params - Values to substitute into the text.
|
|
9
|
+
* @returns The resolved text.
|
|
10
|
+
*/
|
|
11
|
+
declare const resolveConsentText: (t: UseTranslation["t"] | undefined, key: string, params?: Record<string, string | number>) => string;
|
|
12
|
+
export default resolveConsentText;
|
|
13
|
+
//# sourceMappingURL=resolveConsentText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveConsentText.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/flow/resolveConsentText.ts"],"names":[],"mappings":"AASA,OAAO,EAAC,cAAc,EAAC,MAAM,+BAA+B,CAAC;AAE7D;;;;;;;;GAQG;AACH,QAAA,MAAM,kBAAkB,GACtB,GAAG,cAAc,CAAC,GAAG,CAAC,GAAG,SAAS,EAClC,KAAK,MAAM,EACX,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACvC,MASF,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TranslationBundleConstants, getDefaultI18nBundles, substituteTranslationParams } from "@thunderid/browser";
|
|
2
|
+
|
|
3
|
+
//#region src/components/auth/flow/resolveConsentText.ts
|
|
4
|
+
/**
|
|
5
|
+
* Resolves a consent screen string through the given translator, falling back to the SDK's default
|
|
6
|
+
* bundle when there is no translator or it has no entry for the key.
|
|
7
|
+
*
|
|
8
|
+
* @param t - Translator, when the screen has one.
|
|
9
|
+
* @param key - Translation key.
|
|
10
|
+
* @param params - Values to substitute into the text.
|
|
11
|
+
* @returns The resolved text.
|
|
12
|
+
*/
|
|
13
|
+
const resolveConsentText = (t, key, params) => {
|
|
14
|
+
const translated = t?.(key, params);
|
|
15
|
+
if (translated && translated !== key) return translated;
|
|
16
|
+
const fallback = getDefaultI18nBundles()[TranslationBundleConstants.FALLBACK_LOCALE]?.translations[key];
|
|
17
|
+
return substituteTranslationParams(fallback ?? key, params);
|
|
18
|
+
};
|
|
19
|
+
var resolveConsentText_default = resolveConsentText;
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { resolveConsentText_default as default };
|
|
23
|
+
//# sourceMappingURL=resolveConsentText.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveConsentText.js","names":["translated: string | undefined","fallback: string | undefined"],"sources":["../../../../src/components/auth/flow/resolveConsentText.ts"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n getDefaultI18nBundles,\n I18nBundle,\n substituteTranslationParams,\n TranslationBundleConstants,\n} from '@thunderid/browser';\nimport {UseTranslation} from '../../../hooks/useTranslation';\n\n/**\n * Resolves a consent screen string through the given translator, falling back to the SDK's default\n * bundle when there is no translator or it has no entry for the key.\n *\n * @param t - Translator, when the screen has one.\n * @param key - Translation key.\n * @param params - Values to substitute into the text.\n * @returns The resolved text.\n */\nconst resolveConsentText = (\n t: UseTranslation['t'] | undefined,\n key: string,\n params?: Record<string, string | number>,\n): string => {\n const translated: string | undefined = t?.(key, params);\n if (translated && translated !== key) {\n return translated;\n }\n const bundle: I18nBundle | undefined = getDefaultI18nBundles()[TranslationBundleConstants.FALLBACK_LOCALE];\n const fallback: string | undefined = bundle?.translations[key as keyof I18nBundle['translations']];\n\n return substituteTranslationParams(fallback ?? key, params);\n};\n\nexport default resolveConsentText;\n"],"mappings":";;;;;;;;;;;;AAoBA,MAAM,sBACJ,GACA,KACA,WACW;CACX,MAAMA,aAAiC,IAAI,KAAK,OAAO;AACvD,KAAI,cAAc,eAAe,IAC/B,QAAO;CAGT,MAAMC,WADiC,uBAAuB,CAAC,2BAA2B,kBAC7C,aAAa;AAE1D,QAAO,4BAA4B,YAAY,KAAK,OAAO;;AAG7D,iCAAe"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { cx } from "../../../styles/emotion.js";
|
|
2
2
|
import useTheme_default from "../../../contexts/Theme/useTheme.js";
|
|
3
|
+
import TextField_default from "../TextField/TextField.js";
|
|
3
4
|
import Plus_default from "../Icons/Plus.js";
|
|
4
5
|
import X_default from "../Icons/X.js";
|
|
5
|
-
import TextField_default from "../TextField/TextField.js";
|
|
6
6
|
import KeyValueInput_styles_default from "./KeyValueInput.styles.js";
|
|
7
7
|
import { bem, withVendorCSSClassPrefix } from "@thunderid/browser";
|
|
8
8
|
import { useCallback, useState } from "react";
|
|
@@ -2,9 +2,9 @@ import { cx } from "../../../styles/emotion.js";
|
|
|
2
2
|
import useTheme_default from "../../../contexts/Theme/useTheme.js";
|
|
3
3
|
import FormControl_default from "../FormControl/FormControl.js";
|
|
4
4
|
import InputLabel_default from "../InputLabel/InputLabel.js";
|
|
5
|
+
import TextField_default from "../TextField/TextField.js";
|
|
5
6
|
import Checkbox_default from "../Checkbox/Checkbox.js";
|
|
6
7
|
import DatePicker_default from "../DatePicker/DatePicker.js";
|
|
7
|
-
import TextField_default from "../TextField/TextField.js";
|
|
8
8
|
import MultiInput_styles_default from "./MultiInput.styles.js";
|
|
9
9
|
import { bem, withVendorCSSClassPrefix } from "@thunderid/browser";
|
|
10
10
|
import { useCallback, useId, useState } from "react";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { cx } from "../../../styles/emotion.js";
|
|
2
2
|
import useTheme_default from "../../../contexts/Theme/useTheme.js";
|
|
3
|
+
import TextField_default from "../TextField/TextField.js";
|
|
3
4
|
import Eye_default from "../Icons/Eye.js";
|
|
4
5
|
import EyeOff_default from "../Icons/EyeOff.js";
|
|
5
6
|
import PasswordField_styles_default from "./PasswordField.styles.js";
|
|
6
|
-
import TextField_default from "../TextField/TextField.js";
|
|
7
7
|
import { bem, withVendorCSSClassPrefix } from "@thunderid/browser";
|
|
8
8
|
import { useState } from "react";
|
|
9
9
|
import { jsx } from "react/jsx-runtime";
|
|
@@ -7,7 +7,8 @@ export interface ThemeProviderProps {
|
|
|
7
7
|
*/
|
|
8
8
|
designTheme?: FlowMetaTheme | null;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* Color scheme override. Overrides the server default when provided, and the color scheme follows it
|
|
11
|
+
* when it changes.
|
|
11
12
|
*/
|
|
12
13
|
mode?: ThemeMode;
|
|
13
14
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../../src/contexts/Theme/ThemeProvider.tsx"],"names":[],"mappings":"AAGA,OAAO,EAKL,aAAa,EACb,gBAAgB,EAEhB,WAAW,EACX,SAAS,EACV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,
|
|
1
|
+
{"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../../src/contexts/Theme/ThemeProvider.tsx"],"names":[],"mappings":"AAGA,OAAO,EAKL,aAAa,EACb,gBAAgB,EAEhB,WAAW,EACX,SAAS,EACV,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,EAAE,EAEF,iBAAiB,EAQlB,MAAM,OAAO,CAAC;AAQf,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,WAAW,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACnC;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB;;;OAGG;IACH,KAAK,CAAC,EAAE,gBAAgB,CAAC,WAAW,CAAC,CAAC;CACvC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,QAAA,MAAM,aAAa,EAAE,EAAE,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAwJ5D,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import FlowMetaContext_default from "../FlowMeta/FlowMetaContext.js";
|
|
2
2
|
import ThemeContext_default from "./ThemeContext.js";
|
|
3
|
+
import ThemeRootContext_default from "./ThemeRootContext.js";
|
|
3
4
|
import applyThemeToDOM_default from "../../utils/applyThemeToDOM.js";
|
|
4
5
|
import buildThemeConfigFromFlowMeta_default from "../../utils/buildThemeConfigFromFlowMeta.js";
|
|
5
6
|
import normalizeThemeConfig_default from "../../utils/normalizeThemeConfig.js";
|
|
6
7
|
import { createClassObserver, createMediaQueryListener, createTheme, detectThemeMode } from "@thunderid/browser";
|
|
7
|
-
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
8
|
+
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
8
9
|
import { jsx } from "react/jsx-runtime";
|
|
9
10
|
|
|
10
11
|
//#region src/contexts/Theme/ThemeProvider.tsx
|
|
@@ -49,6 +50,11 @@ const ThemeProvider = ({ children, designTheme = void 0, mode, theme: themeOverr
|
|
|
49
50
|
return flowMetaTheme?.defaultColorScheme ?? "light";
|
|
50
51
|
};
|
|
51
52
|
const [colorScheme, setColorScheme] = useState(getInitialColorScheme);
|
|
53
|
+
const [seededMode, setSeededMode] = useState(mode);
|
|
54
|
+
if (mode !== seededMode) {
|
|
55
|
+
setSeededMode(mode);
|
|
56
|
+
if (mode !== void 0) setColorScheme(getInitialColorScheme());
|
|
57
|
+
}
|
|
52
58
|
useEffect(() => {
|
|
53
59
|
if (mode === void 0 && flowMetaTheme?.defaultColorScheme) setColorScheme(flowMetaTheme.defaultColorScheme);
|
|
54
60
|
}, [mode, flowMetaTheme?.defaultColorScheme]);
|
|
@@ -99,12 +105,33 @@ const ThemeProvider = ({ children, designTheme = void 0, mode, theme: themeOverr
|
|
|
99
105
|
]);
|
|
100
106
|
const theme = useMemo(() => createTheme(finalThemeConfig, colorScheme === "dark"), [finalThemeConfig, colorScheme]);
|
|
101
107
|
const direction = flowMetaTheme?.direction ?? "ltr";
|
|
108
|
+
const parentRoot = useContext(ThemeRootContext_default);
|
|
109
|
+
const claims = useRef(0);
|
|
110
|
+
const applied = useRef(null);
|
|
111
|
+
const applyToRoot = useCallback(() => {
|
|
112
|
+
if (!applied.current || typeof document === "undefined") return;
|
|
113
|
+
applyThemeToDOM_default(applied.current.theme);
|
|
114
|
+
document.documentElement.dir = applied.current.direction;
|
|
115
|
+
}, []);
|
|
116
|
+
const root = useMemo(() => ({ claim: () => {
|
|
117
|
+
claims.current += 1;
|
|
118
|
+
return () => {
|
|
119
|
+
claims.current -= 1;
|
|
120
|
+
if (claims.current === 0) applyToRoot();
|
|
121
|
+
};
|
|
122
|
+
} }), [applyToRoot]);
|
|
123
|
+
useEffect(() => parentRoot?.claim(), [parentRoot]);
|
|
102
124
|
useEffect(() => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
125
|
+
applied.current = {
|
|
126
|
+
direction,
|
|
127
|
+
theme
|
|
128
|
+
};
|
|
129
|
+
if (claims.current === 0) applyToRoot();
|
|
130
|
+
}, [
|
|
131
|
+
applyToRoot,
|
|
132
|
+
direction,
|
|
133
|
+
theme
|
|
134
|
+
]);
|
|
108
135
|
const value = {
|
|
109
136
|
colorScheme,
|
|
110
137
|
direction,
|
|
@@ -113,7 +140,10 @@ const ThemeProvider = ({ children, designTheme = void 0, mode, theme: themeOverr
|
|
|
113
140
|
};
|
|
114
141
|
return /* @__PURE__ */ jsx(ThemeContext_default.Provider, {
|
|
115
142
|
value,
|
|
116
|
-
children
|
|
143
|
+
children: /* @__PURE__ */ jsx(ThemeRootContext_default.Provider, {
|
|
144
|
+
value: root,
|
|
145
|
+
children
|
|
146
|
+
})
|
|
117
147
|
});
|
|
118
148
|
};
|
|
119
149
|
var ThemeProvider_default = ThemeProvider;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ThemeProvider.js","names":["ThemeProvider: FC<PropsWithChildren<ThemeProviderProps>>","themeOverride: RecursivePartial<ThemeConfig> | undefined","normalizeThemeConfig","flowMetaContext: FlowMetaContextValue | null","FlowMetaContext","flowMetaTheme: FlowMetaTheme | null","toggleTheme: () => void","finalThemeConfig: RecursivePartial<ThemeConfig> | undefined","metaConfig: RecursivePartial<ThemeConfig>","buildThemeConfigFromFlowMeta","theme: Theme","direction: 'ltr' | 'rtl'","value: any","ThemeContext"],"sources":["../../../src/contexts/Theme/ThemeProvider.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n createClassObserver,\n createMediaQueryListener,\n createTheme,\n detectThemeMode,\n FlowMetaTheme,\n RecursivePartial,\n Theme,\n ThemeConfig,\n ThemeMode,\n} from '@thunderid/browser';\nimport {FC, PropsWithChildren, ReactElement, useCallback, useContext, useEffect, useMemo, useState} from 'react';\nimport ThemeContext from './ThemeContext';\nimport applyThemeToDOM from '../../utils/applyThemeToDOM';\nimport buildThemeConfigFromFlowMeta from '../../utils/buildThemeConfigFromFlowMeta';\nimport normalizeThemeConfig from '../../utils/normalizeThemeConfig';\nimport FlowMetaContext, {FlowMetaContextValue} from '../FlowMeta/FlowMetaContext';\n\nexport interface ThemeProviderProps {\n /**\n * A Design theme to use instead of the one the server returns in flow meta, for example the theme an\n * app configuration names. `theme` overrides are still applied on top.\n */\n designTheme?: FlowMetaTheme | null;\n /**\n * Initial color scheme override. Overrides the server default when provided.\n */\n mode?: ThemeMode;\n\n /**\n * Optional theme overrides merged on top of the server-side flow meta theme.\n * User-supplied values take highest precedence.\n */\n theme?: RecursivePartial<ThemeConfig>;\n}\n\n/**\n * ThemeProvider is the v2 drop-in replacement for `ThemeProvider`.\n *\n * It reads the design theme from the nearest `FlowMetaContext` (provided by\n * `FlowMetaProvider`) and publishes a resolved `Theme` object through the\n * **same** `ThemeContext` that `useTheme` consumes. This means all existing\n * components that call `useTheme` continue to work without any changes.\n *\n * The `defaultColorScheme` field returned by the server is used to seed the\n * active color scheme; the user can still toggle it locally via the\n * `toggleTheme` value exposed in the context.\n *\n * @example\n * ```tsx\n * <FlowMetaProvider config={{ baseUrl, type: FlowMetaType.App, id: appId }}>\n * <ThemeProvider>\n * <App /> {/* useTheme() works here as usual *\\/}\n * </ThemeProvider>\n * </FlowMetaProvider>\n * ```\n *\n * @example\n * With user theme overrides (user values win over server values):\n * ```tsx\n * <ThemeProvider theme={{ colors: { primary: { main: '#ff0000' } } }}>\n * <App />\n * </ThemeProvider>\n * ```\n */\nconst ThemeProvider: FC<PropsWithChildren<ThemeProviderProps>> = ({\n children,\n designTheme = undefined,\n mode,\n theme: themeOverrideProp,\n}: PropsWithChildren<ThemeProviderProps>): ReactElement => {\n const themeOverride: RecursivePartial<ThemeConfig> | undefined = normalizeThemeConfig(themeOverrideProp);\n const flowMetaContext: FlowMetaContextValue | null = useContext(FlowMetaContext);\n\n const flowMetaTheme: FlowMetaTheme | null = designTheme ?? flowMetaContext?.meta?.design?.theme ?? null;\n const isLoading: boolean = flowMetaContext?.isLoading ?? false;\n const error: Error | null = flowMetaContext?.error ?? null;\n\n // Seed the color scheme: a fixed mode wins outright, 'system'/'class' detect it from the\n // environment via the same shared utilities Vue's ThemeProvider uses, and no mode falls back\n // to the server's default (unchanged pre-`mode` behavior).\n const getInitialColorScheme = (): 'light' | 'dark' => {\n if (mode === 'light' || mode === 'dark') return mode;\n if (mode === 'system' || mode === 'class') return detectThemeMode(mode);\n return flowMetaTheme?.defaultColorScheme ?? 'light';\n };\n\n const [colorScheme, setColorScheme] = useState<'light' | 'dark'>(getInitialColorScheme);\n\n // When mode is unset, sync the color scheme with the server default once flow meta loads.\n useEffect(() => {\n if (mode === undefined && flowMetaTheme?.defaultColorScheme) {\n setColorScheme(flowMetaTheme.defaultColorScheme);\n }\n }, [mode, flowMetaTheme?.defaultColorScheme]);\n\n // Set up automatic detection listeners for 'system'/'class' modes.\n useEffect(() => {\n if (mode !== 'system' && mode !== 'class') return undefined;\n\n const handleThemeChange = (isDark: boolean): void => {\n setColorScheme(isDark ? 'dark' : 'light');\n };\n\n if (mode === 'class') {\n if (typeof document === 'undefined') return undefined;\n const observer = createClassObserver(document.documentElement, handleThemeChange);\n return () => {\n observer.disconnect();\n };\n }\n\n const mediaQuery = createMediaQueryListener(handleThemeChange);\n return () => {\n mediaQuery?.disconnect();\n };\n }, [mode]);\n\n const toggleTheme: () => void = useCallback(() => {\n setColorScheme((prev: 'light' | 'dark') => (prev === 'light' ? 'dark' : 'light'));\n }, []);\n\n // Build the resolved ThemeConfig: flow meta base → user overrides on top.\n const finalThemeConfig: RecursivePartial<ThemeConfig> | undefined = useMemo(() => {\n if (!flowMetaTheme) {\n return themeOverride;\n }\n\n const metaConfig: RecursivePartial<ThemeConfig> = buildThemeConfigFromFlowMeta(flowMetaTheme, colorScheme);\n\n if (!themeOverride) {\n return metaConfig;\n }\n\n return {\n ...metaConfig,\n ...themeOverride,\n borderRadius: {\n ...metaConfig.borderRadius,\n ...themeOverride.borderRadius,\n },\n colors: {\n ...metaConfig.colors,\n ...themeOverride.colors,\n },\n ...(metaConfig.typography || themeOverride.typography\n ? {\n typography: {\n ...(metaConfig as any).typography,\n ...themeOverride.typography,\n },\n }\n : {}),\n };\n }, [flowMetaTheme, colorScheme, themeOverride]);\n\n const theme: Theme = useMemo(\n () => createTheme(finalThemeConfig, colorScheme === 'dark'),\n [finalThemeConfig, colorScheme],\n );\n\n const direction: 'ltr' | 'rtl' = flowMetaTheme?.direction ?? 'ltr';\n\n // Apply CSS variables to the document root.\n useEffect(() => {\n applyThemeToDOM(theme);\n }, [theme]);\n\n // Apply text direction to the document root.\n useEffect(() => {\n if (typeof document !== 'undefined') {\n document.documentElement.dir = direction;\n }\n }, [direction]);\n\n const value: any = {\n colorScheme,\n direction,\n theme,\n toggleTheme,\n };\n\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n};\n\nexport default ThemeProvider;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,MAAMA,iBAA4D,EAChE,UACA,cAAc,QACd,MACA,OAAO,wBACkD;CACzD,MAAMC,gBAA2DC,6BAAqB,kBAAkB;CACxG,MAAMC,kBAA+C,WAAWC,wBAAgB;CAEhF,MAAMC,gBAAsC,eAAe,iBAAiB,MAAM,QAAQ,SAAS;AACxE,kBAAiB;AAChB,kBAAiB;CAK7C,MAAM,8BAAgD;AACpD,MAAI,SAAS,WAAW,SAAS,OAAQ,QAAO;AAChD,MAAI,SAAS,YAAY,SAAS,QAAS,QAAO,gBAAgB,KAAK;AACvE,SAAO,eAAe,sBAAsB;;CAG9C,MAAM,CAAC,aAAa,kBAAkB,SAA2B,sBAAsB;AAGvF,iBAAgB;AACd,MAAI,SAAS,UAAa,eAAe,mBACvC,gBAAe,cAAc,mBAAmB;IAEjD,CAAC,MAAM,eAAe,mBAAmB,CAAC;AAG7C,iBAAgB;AACd,MAAI,SAAS,YAAY,SAAS,QAAS,QAAO;EAElD,MAAM,qBAAqB,WAA0B;AACnD,kBAAe,SAAS,SAAS,QAAQ;;AAG3C,MAAI,SAAS,SAAS;AACpB,OAAI,OAAO,aAAa,YAAa,QAAO;GAC5C,MAAM,WAAW,oBAAoB,SAAS,iBAAiB,kBAAkB;AACjF,gBAAa;AACX,aAAS,YAAY;;;EAIzB,MAAM,aAAa,yBAAyB,kBAAkB;AAC9D,eAAa;AACX,eAAY,YAAY;;IAEzB,CAAC,KAAK,CAAC;CAEV,MAAMC,cAA0B,kBAAkB;AAChD,kBAAgB,SAA4B,SAAS,UAAU,SAAS,QAAS;IAChF,EAAE,CAAC;CAGN,MAAMC,mBAA8D,cAAc;AAChF,MAAI,CAAC,cACH,QAAO;EAGT,MAAMC,aAA4CC,qCAA6B,eAAe,YAAY;AAE1G,MAAI,CAAC,cACH,QAAO;AAGT,SAAO;GACL,GAAG;GACH,GAAG;GACH,cAAc;IACZ,GAAG,WAAW;IACd,GAAG,cAAc;IAClB;GACD,QAAQ;IACN,GAAG,WAAW;IACd,GAAG,cAAc;IAClB;GACD,GAAI,WAAW,cAAc,cAAc,aACvC,EACE,YAAY;IACV,GAAI,WAAmB;IACvB,GAAG,cAAc;IAClB,EACF,GACD,EAAE;GACP;IACA;EAAC;EAAe;EAAa;EAAc,CAAC;CAE/C,MAAMC,QAAe,cACb,YAAY,kBAAkB,gBAAgB,OAAO,EAC3D,CAAC,kBAAkB,YAAY,CAChC;CAED,MAAMC,YAA2B,eAAe,aAAa;AAG7D,iBAAgB;AACd,0BAAgB,MAAM;IACrB,CAAC,MAAM,CAAC;AAGX,iBAAgB;AACd,MAAI,OAAO,aAAa,YACtB,UAAS,gBAAgB,MAAM;IAEhC,CAAC,UAAU,CAAC;CAEf,MAAMC,QAAa;EACjB;EACA;EACA;EACA;EACD;AAED,QAAO,oBAACC,qBAAa;EAAgB;EAAQ;GAAiC;;AAGhF,4BAAe"}
|
|
1
|
+
{"version":3,"file":"ThemeProvider.js","names":["ThemeProvider: FC<PropsWithChildren<ThemeProviderProps>>","themeOverride: RecursivePartial<ThemeConfig> | undefined","normalizeThemeConfig","flowMetaContext: FlowMetaContextValue | null","FlowMetaContext","flowMetaTheme: FlowMetaTheme | null","toggleTheme: () => void","finalThemeConfig: RecursivePartial<ThemeConfig> | undefined","metaConfig: RecursivePartial<ThemeConfig>","buildThemeConfigFromFlowMeta","theme: Theme","direction: 'ltr' | 'rtl'","parentRoot: ThemeRootContextValue | null","ThemeRootContext","claims: MutableRefObject<number>","applied: MutableRefObject<{direction: 'ltr' | 'rtl'; theme: Theme} | null>","applyToRoot: () => void","root: ThemeRootContextValue","value: any","ThemeContext"],"sources":["../../../src/contexts/Theme/ThemeProvider.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n createClassObserver,\n createMediaQueryListener,\n createTheme,\n detectThemeMode,\n FlowMetaTheme,\n RecursivePartial,\n Theme,\n ThemeConfig,\n ThemeMode,\n} from '@thunderid/browser';\nimport {\n FC,\n MutableRefObject,\n PropsWithChildren,\n ReactElement,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport ThemeContext from './ThemeContext';\nimport ThemeRootContext, {ThemeRootContextValue} from './ThemeRootContext';\nimport applyThemeToDOM from '../../utils/applyThemeToDOM';\nimport buildThemeConfigFromFlowMeta from '../../utils/buildThemeConfigFromFlowMeta';\nimport normalizeThemeConfig from '../../utils/normalizeThemeConfig';\nimport FlowMetaContext, {FlowMetaContextValue} from '../FlowMeta/FlowMetaContext';\n\nexport interface ThemeProviderProps {\n /**\n * A Design theme to use instead of the one the server returns in flow meta, for example the theme an\n * app configuration names. `theme` overrides are still applied on top.\n */\n designTheme?: FlowMetaTheme | null;\n /**\n * Color scheme override. Overrides the server default when provided, and the color scheme follows it\n * when it changes.\n */\n mode?: ThemeMode;\n\n /**\n * Optional theme overrides merged on top of the server-side flow meta theme.\n * User-supplied values take highest precedence.\n */\n theme?: RecursivePartial<ThemeConfig>;\n}\n\n/**\n * ThemeProvider is the v2 drop-in replacement for `ThemeProvider`.\n *\n * It reads the design theme from the nearest `FlowMetaContext` (provided by\n * `FlowMetaProvider`) and publishes a resolved `Theme` object through the\n * **same** `ThemeContext` that `useTheme` consumes. This means all existing\n * components that call `useTheme` continue to work without any changes.\n *\n * The `defaultColorScheme` field returned by the server is used to seed the\n * active color scheme; the user can still toggle it locally via the\n * `toggleTheme` value exposed in the context.\n *\n * @example\n * ```tsx\n * <FlowMetaProvider config={{ baseUrl, type: FlowMetaType.App, id: appId }}>\n * <ThemeProvider>\n * <App /> {/* useTheme() works here as usual *\\/}\n * </ThemeProvider>\n * </FlowMetaProvider>\n * ```\n *\n * @example\n * With user theme overrides (user values win over server values):\n * ```tsx\n * <ThemeProvider theme={{ colors: { primary: { main: '#ff0000' } } }}>\n * <App />\n * </ThemeProvider>\n * ```\n */\nconst ThemeProvider: FC<PropsWithChildren<ThemeProviderProps>> = ({\n children,\n designTheme = undefined,\n mode,\n theme: themeOverrideProp,\n}: PropsWithChildren<ThemeProviderProps>): ReactElement => {\n const themeOverride: RecursivePartial<ThemeConfig> | undefined = normalizeThemeConfig(themeOverrideProp);\n const flowMetaContext: FlowMetaContextValue | null = useContext(FlowMetaContext);\n\n const flowMetaTheme: FlowMetaTheme | null = designTheme ?? flowMetaContext?.meta?.design?.theme ?? null;\n const isLoading: boolean = flowMetaContext?.isLoading ?? false;\n const error: Error | null = flowMetaContext?.error ?? null;\n\n // Seed the color scheme: a fixed mode wins outright, 'system'/'class' detect it from the\n // environment via the same shared utilities Vue's ThemeProvider uses, and no mode falls back\n // to the server's default (unchanged pre-`mode` behavior).\n const getInitialColorScheme = (): 'light' | 'dark' => {\n if (mode === 'light' || mode === 'dark') return mode;\n if (mode === 'system' || mode === 'class') return detectThemeMode(mode);\n return flowMetaTheme?.defaultColorScheme ?? 'light';\n };\n\n const [colorScheme, setColorScheme] = useState<'light' | 'dark'>(getInitialColorScheme);\n\n // Follow a change of mode after mount, such as a host app's own color scheme toggle.\n const [seededMode, setSeededMode] = useState<ThemeMode | undefined>(mode);\n\n if (mode !== seededMode) {\n setSeededMode(mode);\n if (mode !== undefined) {\n setColorScheme(getInitialColorScheme());\n }\n }\n\n // When mode is unset, sync the color scheme with the server default once flow meta loads.\n useEffect(() => {\n if (mode === undefined && flowMetaTheme?.defaultColorScheme) {\n setColorScheme(flowMetaTheme.defaultColorScheme);\n }\n }, [mode, flowMetaTheme?.defaultColorScheme]);\n\n // Set up automatic detection listeners for 'system'/'class' modes.\n useEffect(() => {\n if (mode !== 'system' && mode !== 'class') return undefined;\n\n const handleThemeChange = (isDark: boolean): void => {\n setColorScheme(isDark ? 'dark' : 'light');\n };\n\n if (mode === 'class') {\n if (typeof document === 'undefined') return undefined;\n const observer = createClassObserver(document.documentElement, handleThemeChange);\n return () => {\n observer.disconnect();\n };\n }\n\n const mediaQuery = createMediaQueryListener(handleThemeChange);\n return () => {\n mediaQuery?.disconnect();\n };\n }, [mode]);\n\n const toggleTheme: () => void = useCallback(() => {\n setColorScheme((prev: 'light' | 'dark') => (prev === 'light' ? 'dark' : 'light'));\n }, []);\n\n // Build the resolved ThemeConfig: flow meta base → user overrides on top.\n const finalThemeConfig: RecursivePartial<ThemeConfig> | undefined = useMemo(() => {\n if (!flowMetaTheme) {\n return themeOverride;\n }\n\n const metaConfig: RecursivePartial<ThemeConfig> = buildThemeConfigFromFlowMeta(flowMetaTheme, colorScheme);\n\n if (!themeOverride) {\n return metaConfig;\n }\n\n return {\n ...metaConfig,\n ...themeOverride,\n borderRadius: {\n ...metaConfig.borderRadius,\n ...themeOverride.borderRadius,\n },\n colors: {\n ...metaConfig.colors,\n ...themeOverride.colors,\n },\n ...(metaConfig.typography || themeOverride.typography\n ? {\n typography: {\n ...(metaConfig as any).typography,\n ...themeOverride.typography,\n },\n }\n : {}),\n };\n }, [flowMetaTheme, colorScheme, themeOverride]);\n\n const theme: Theme = useMemo(\n () => createTheme(finalThemeConfig, colorScheme === 'dark'),\n [finalThemeConfig, colorScheme],\n );\n\n const direction: 'ltr' | 'rtl' = flowMetaTheme?.direction ?? 'ltr';\n\n // The innermost ThemeProvider owns the document root: an outer one stops writing its CSS variables\n // and text direction while a nested one is mounted, and writes them again once it unmounts.\n const parentRoot: ThemeRootContextValue | null = useContext(ThemeRootContext);\n const claims: MutableRefObject<number> = useRef<number>(0);\n const applied: MutableRefObject<{direction: 'ltr' | 'rtl'; theme: Theme} | null> = useRef(null);\n\n const applyToRoot: () => void = useCallback(() => {\n if (!applied.current || typeof document === 'undefined') return;\n applyThemeToDOM(applied.current.theme);\n document.documentElement.dir = applied.current.direction;\n }, []);\n\n const root: ThemeRootContextValue = useMemo(\n () => ({\n claim: (): (() => void) => {\n claims.current += 1;\n return (): void => {\n claims.current -= 1;\n if (claims.current === 0) applyToRoot();\n };\n },\n }),\n [applyToRoot],\n );\n\n useEffect(() => parentRoot?.claim(), [parentRoot]);\n\n useEffect(() => {\n applied.current = {direction, theme};\n if (claims.current === 0) applyToRoot();\n }, [applyToRoot, direction, theme]);\n\n const value: any = {\n colorScheme,\n direction,\n theme,\n toggleTheme,\n };\n\n return (\n <ThemeContext.Provider value={value}>\n <ThemeRootContext.Provider value={root}>{children}</ThemeRootContext.Provider>\n </ThemeContext.Provider>\n );\n};\n\nexport default ThemeProvider;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Context } from 'react';
|
|
2
|
+
export interface ThemeRootContextValue {
|
|
3
|
+
/**
|
|
4
|
+
* Hands the document root to a nested `ThemeProvider` until the returned release is called, so the
|
|
5
|
+
* innermost provider's CSS variables and text direction are the ones on the page.
|
|
6
|
+
*/
|
|
7
|
+
claim: () => () => void;
|
|
8
|
+
}
|
|
9
|
+
declare const ThemeRootContext: Context<ThemeRootContextValue | null>;
|
|
10
|
+
export default ThemeRootContext;
|
|
11
|
+
//# sourceMappingURL=ThemeRootContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemeRootContext.d.ts","sourceRoot":"","sources":["../../../src/contexts/Theme/ThemeRootContext.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,EAAgB,MAAM,OAAO,CAAC;AAE7C,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,KAAK,EAAE,MAAM,MAAM,IAAI,CAAC;CACzB;AAED,QAAA,MAAM,gBAAgB,EAAE,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAqD,CAAC;AAIlH,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createContext } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/contexts/Theme/ThemeRootContext.ts
|
|
4
|
+
const ThemeRootContext = createContext(null);
|
|
5
|
+
ThemeRootContext.displayName = "ThemeRootContext";
|
|
6
|
+
var ThemeRootContext_default = ThemeRootContext;
|
|
7
|
+
|
|
8
|
+
//#endregion
|
|
9
|
+
export { ThemeRootContext_default as default };
|
|
10
|
+
//# sourceMappingURL=ThemeRootContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemeRootContext.js","names":["ThemeRootContext: Context<ThemeRootContextValue | null>"],"sources":["../../../src/contexts/Theme/ThemeRootContext.ts"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {Context, createContext} from 'react';\n\nexport interface ThemeRootContextValue {\n /**\n * Hands the document root to a nested `ThemeProvider` until the returned release is called, so the\n * innermost provider's CSS variables and text direction are the ones on the page.\n */\n claim: () => () => void;\n}\n\nconst ThemeRootContext: Context<ThemeRootContextValue | null> = createContext<ThemeRootContextValue | null>(null);\n\nThemeRootContext.displayName = 'ThemeRootContext';\n\nexport default ThemeRootContext;\n"],"mappings":";;;AAaA,MAAMA,mBAA0D,cAA4C,KAAK;AAEjH,iBAAiB,cAAc;AAE/B,+BAAe"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { type ConsentDetailRow } from '@thunderid/browser';
|
|
2
|
+
import { type ConsentDetailListDisplay } from '../../utils/getConsentDetailListDisplay';
|
|
3
|
+
import { UseTranslation } from '../useTranslation';
|
|
4
|
+
/**
|
|
5
|
+
* How the user may change one field of an authorization detail on the consent screen: type a lower or
|
|
6
|
+
* higher `number` or `date`, or toggle items of a list whose rule is `removeItems` or `addItems`.
|
|
7
|
+
*
|
|
8
|
+
* @experimental This type may change in future versions
|
|
9
|
+
*/
|
|
10
|
+
export type ConsentDetailInputKind = 'number' | 'date' | 'removeItems' | 'addItems';
|
|
11
|
+
/**
|
|
12
|
+
* Error shown for text a user entered into an authorization detail field, as a translation key and the
|
|
13
|
+
* values to substitute into its text.
|
|
14
|
+
*
|
|
15
|
+
* @experimental This interface may change in future versions
|
|
16
|
+
*/
|
|
17
|
+
export interface ConsentDetailInputError {
|
|
18
|
+
/** Translation key of the message. */
|
|
19
|
+
key: string;
|
|
20
|
+
/** Values to substitute into the message: `value` is the value that was shown. */
|
|
21
|
+
params: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* One item of a list field of an authorization detail, as the consent screen offers it.
|
|
25
|
+
*
|
|
26
|
+
* @experimental This interface may change in future versions
|
|
27
|
+
*/
|
|
28
|
+
export interface ConsentDetailListItem {
|
|
29
|
+
/**
|
|
30
|
+
* Where the item comes from: `shown` in the requested detail, `added` by the user, or `offered` by the
|
|
31
|
+
* type for the user to add.
|
|
32
|
+
*/
|
|
33
|
+
origin: 'shown' | 'added' | 'offered';
|
|
34
|
+
/** Whether the item is part of the value that would be granted. */
|
|
35
|
+
selected: boolean;
|
|
36
|
+
/** Whether the user may toggle the item. */
|
|
37
|
+
toggleable: boolean;
|
|
38
|
+
/** The item. */
|
|
39
|
+
value: string | number | boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Props for the useConsentDetailField hook.
|
|
43
|
+
*/
|
|
44
|
+
export interface UseConsentDetailFieldProps {
|
|
45
|
+
/** The identifier of the consent purpose the authorization detail belongs to. */
|
|
46
|
+
purposeId: string;
|
|
47
|
+
/** The identifier of the authorization detail the field belongs to, its consent element name. */
|
|
48
|
+
detailId: string;
|
|
49
|
+
/** Current consent form values. */
|
|
50
|
+
formValues: Record<string, string>;
|
|
51
|
+
/** Callback that writes one consent form value. */
|
|
52
|
+
onInputChange: (name: string, value: string) => void;
|
|
53
|
+
/** The field. */
|
|
54
|
+
row: ConsentDetailRow;
|
|
55
|
+
/** Translator for the error message; the SDK's default bundle is used without one. */
|
|
56
|
+
t?: UseTranslation['t'];
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Error of a field, with its message resolved.
|
|
60
|
+
*/
|
|
61
|
+
export interface ConsentDetailFieldError extends ConsentDetailInputError {
|
|
62
|
+
/** Translated message. */
|
|
63
|
+
message: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* State and handlers of one authorization detail field, for drawing it in any UI.
|
|
67
|
+
*/
|
|
68
|
+
export interface UseConsentDetailFieldResult {
|
|
69
|
+
/** Why the text shown cannot be submitted, absent when it can. */
|
|
70
|
+
error?: ConsentDetailFieldError;
|
|
71
|
+
/** Adds a typed item to an `addItems` list that takes typed values; returns whether it was added. */
|
|
72
|
+
handleAdd: (text: string) => boolean;
|
|
73
|
+
/** Call when the field loses focus: an empty field returns to the value that was shown. */
|
|
74
|
+
handleBlur: () => void;
|
|
75
|
+
/** Call with the text the user entered into a `number` or `date` field, or the item typed into a list. */
|
|
76
|
+
handleChange: (text: string) => void;
|
|
77
|
+
/** Expands or collapses the field's list. */
|
|
78
|
+
handleListToggle: (expanded: boolean) => void;
|
|
79
|
+
/** Toggles an item of a list field, within what its rule allows. */
|
|
80
|
+
handleToggle: (item: string | number | boolean) => void;
|
|
81
|
+
/** Identifier for the field's input element. */
|
|
82
|
+
inputId: string;
|
|
83
|
+
/** Whether the user expanded the field's list past `CONSENT_DETAIL_DISPLAY_LIMITS.listItems`. */
|
|
84
|
+
isListExpanded: boolean;
|
|
85
|
+
/** Whether the field's value is a list of plain values, shown as a list rather than as structured JSON. */
|
|
86
|
+
isPlainList: boolean;
|
|
87
|
+
/** Whether an item of a list field is part of the value that would be granted. */
|
|
88
|
+
isSelected: (item: string | number | boolean) => boolean;
|
|
89
|
+
/** Whether the user may toggle an item of a list field. */
|
|
90
|
+
isToggleable: (item: string | number | boolean) => boolean;
|
|
91
|
+
/** Whether the field takes typed items: an `addItems` list whose type offers no fixed values. */
|
|
92
|
+
isTypedItemAllowed: boolean;
|
|
93
|
+
/** Whether the field's text may be submitted. Always true for a list or a read-only field. */
|
|
94
|
+
isValid: boolean;
|
|
95
|
+
/** Items of a list field, in display order; empty for any other field. */
|
|
96
|
+
items: ConsentDetailListItem[];
|
|
97
|
+
/** How the user may change the field, or `undefined` when it is read-only. */
|
|
98
|
+
kind?: ConsentDetailInputKind;
|
|
99
|
+
/** Label of the field. */
|
|
100
|
+
label: string;
|
|
101
|
+
/**
|
|
102
|
+
* How many items of the field's list to show and hide: the items of a list the user may change, or the
|
|
103
|
+
* values of a read-only plain list. Nothing is hidden for any other field.
|
|
104
|
+
*/
|
|
105
|
+
listDisplay: ConsentDetailListDisplay;
|
|
106
|
+
/** Upper bound of a `number` or `date` field that may be decreased. */
|
|
107
|
+
max?: string;
|
|
108
|
+
/** Lower bound of a `number` or `date` field that may be increased. */
|
|
109
|
+
min?: string;
|
|
110
|
+
/** Text to show: the typed text of a `number` or `date` field, or the item being typed into a list. */
|
|
111
|
+
text: string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Headless state of one authorization detail field on the consent screen. A `number` or `date` field keeps
|
|
115
|
+
* the text the user typed, writes it to the decision only while it stays within the field's bound, and
|
|
116
|
+
* otherwise clears the field's modification and marks the field invalid, which blocks approval (see
|
|
117
|
+
* `isConsentApprovalBlocked`). A list field exposes its items and toggles them as its rule allows.
|
|
118
|
+
*
|
|
119
|
+
* @param props - The field and the consent form state.
|
|
120
|
+
* @returns The field's state and handlers.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```tsx
|
|
124
|
+
* const field = useConsentDetailField({purposeId, detailId, row, formValues, onInputChange});
|
|
125
|
+
* <input value={field.text} onChange={(e) => field.handleChange(e.target.value)} onBlur={field.handleBlur} />
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
declare const useConsentDetailField: ({ detailId, formValues, onInputChange, purposeId, row, t, }: UseConsentDetailFieldProps) => UseConsentDetailFieldResult;
|
|
129
|
+
export default useConsentDetailField;
|
|
130
|
+
//# sourceMappingURL=useConsentDetailField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useConsentDetailField.d.ts","sourceRoot":"","sources":["../../../src/hooks/auth/useConsentDetailField.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,gBAAgB,EAA8C,MAAM,oBAAoB,CAAC;AAGtG,OAAoC,EAAC,KAAK,wBAAwB,EAAC,MAAM,yCAAyC,CAAC;AAEnH,OAAO,EAAC,cAAc,EAAC,MAAM,mBAAmB,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,CAAC;AAEpF;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,sCAAsC;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAmBD;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,CAAC;IACtC,mEAAmE;IACnE,QAAQ,EAAE,OAAO,CAAC;IAClB,4CAA4C;IAC5C,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB;IAChB,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;CAClC;AAwUD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,iGAAiG;IACjG,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,mDAAmD;IACnD,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,iBAAiB;IACjB,GAAG,EAAE,gBAAgB,CAAC;IACtB,sFAAsF;IACtF,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,uBAAuB;IACtE,0BAA0B;IAC1B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,kEAAkE;IAClE,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAChC,qGAAqG;IACrG,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IACrC,2FAA2F;IAC3F,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,0GAA0G;IAC1G,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,6CAA6C;IAC7C,gBAAgB,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,oEAAoE;IACpE,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,KAAK,IAAI,CAAC;IACxD,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,cAAc,EAAE,OAAO,CAAC;IACxB,2GAA2G;IAC3G,WAAW,EAAE,OAAO,CAAC;IACrB,kFAAkF;IAClF,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,KAAK,OAAO,CAAC;IACzD,2DAA2D;IAC3D,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,KAAK,OAAO,CAAC;IAC3D,iGAAiG;IACjG,kBAAkB,EAAE,OAAO,CAAC;IAC5B,8FAA8F;IAC9F,OAAO,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,8EAA8E;IAC9E,IAAI,CAAC,EAAE,sBAAsB,CAAC;IAC9B,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,WAAW,EAAE,wBAAwB,CAAC;IACtC,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,uGAAuG;IACvG,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;GAcG;AACH,QAAA,MAAM,qBAAqB,GAAI,6DAO5B,0BAA0B,KAAG,2BAuE/B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|