@thunderid/react 1.10.1 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/account/UserProfile/BaseUserProfile.cjs +1 -1
- package/dist/cjs/components/auth/AcceptInvite/BaseAcceptInvite.cjs +1 -1
- package/dist/cjs/components/auth/DeviceGrant/BaseDeviceGrant.cjs +61 -0
- package/dist/cjs/components/auth/DeviceGrant/BaseDeviceGrant.cjs.map +1 -0
- package/dist/cjs/components/auth/DeviceGrant/BaseDeviceGrant.styles.cjs +26 -0
- package/dist/cjs/components/auth/DeviceGrant/BaseDeviceGrant.styles.cjs.map +1 -0
- package/dist/cjs/components/auth/DeviceGrant/DeviceGrant.cjs +192 -0
- package/dist/cjs/components/auth/DeviceGrant/DeviceGrant.cjs.map +1 -0
- package/dist/cjs/components/auth/InviteUser/BaseInviteUser.cjs +1 -1
- package/dist/cjs/components/auth/Recovery/BaseRecovery.cjs +2 -2
- package/dist/cjs/components/auth/SignIn/BaseSignIn.cjs +15 -4
- package/dist/cjs/components/auth/SignIn/BaseSignIn.cjs.map +1 -1
- package/dist/cjs/components/auth/SignUp/BaseSignUp.cjs +2 -2
- package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs +17 -2
- package/dist/cjs/components/auth/flow/AuthOptionFactory.cjs.map +1 -1
- package/dist/cjs/components/auth/flow/Consent.cjs +1 -1
- package/dist/cjs/components/primitives/Alert/Alert.cjs +1 -1
- package/dist/cjs/components/primitives/Card/Card.cjs +1 -1
- package/dist/cjs/components/primitives/Typography/Typography.styles.cjs +3 -0
- package/dist/cjs/components/primitives/Typography/Typography.styles.cjs.map +1 -1
- package/dist/cjs/index.cjs +6 -2
- package/dist/components/account/UserProfile/BaseUserProfile.js +1 -1
- package/dist/components/auth/AcceptInvite/BaseAcceptInvite.js +1 -1
- package/dist/components/auth/DeviceGrant/BaseDeviceGrant.d.ts +17 -0
- package/dist/components/auth/DeviceGrant/BaseDeviceGrant.d.ts.map +1 -0
- package/dist/components/auth/DeviceGrant/BaseDeviceGrant.js +58 -0
- package/dist/components/auth/DeviceGrant/BaseDeviceGrant.js.map +1 -0
- package/dist/components/auth/DeviceGrant/BaseDeviceGrant.styles.d.ts +4 -0
- package/dist/components/auth/DeviceGrant/BaseDeviceGrant.styles.d.ts.map +1 -0
- package/dist/components/auth/DeviceGrant/BaseDeviceGrant.styles.js +24 -0
- package/dist/components/auth/DeviceGrant/BaseDeviceGrant.styles.js.map +1 -0
- package/dist/components/auth/DeviceGrant/DeviceGrant.d.ts +37 -0
- package/dist/components/auth/DeviceGrant/DeviceGrant.d.ts.map +1 -0
- package/dist/components/auth/DeviceGrant/DeviceGrant.js +188 -0
- package/dist/components/auth/DeviceGrant/DeviceGrant.js.map +1 -0
- package/dist/components/auth/InviteUser/BaseInviteUser.js +1 -1
- package/dist/components/auth/Recovery/BaseRecovery.js +2 -2
- package/dist/components/auth/SignIn/BaseSignIn.d.ts +4 -0
- package/dist/components/auth/SignIn/BaseSignIn.d.ts.map +1 -1
- package/dist/components/auth/SignIn/BaseSignIn.js +16 -5
- package/dist/components/auth/SignIn/BaseSignIn.js.map +1 -1
- package/dist/components/auth/SignUp/BaseSignUp.js +2 -2
- package/dist/components/auth/flow/AuthOptionFactory.d.ts.map +1 -1
- package/dist/components/auth/flow/AuthOptionFactory.js +17 -2
- package/dist/components/auth/flow/AuthOptionFactory.js.map +1 -1
- package/dist/components/auth/flow/Consent.js +1 -1
- package/dist/components/primitives/Alert/Alert.js +1 -1
- package/dist/components/primitives/Card/Card.js +1 -1
- package/dist/components/primitives/Typography/Typography.styles.d.ts.map +1 -1
- package/dist/components/primitives/Typography/Typography.styles.js +3 -0
- package/dist/components/primitives/Typography/Typography.styles.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -3
- package/package.json +2 -2
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import useTheme_default from "../../../contexts/Theme/useTheme.js";
|
|
2
|
+
import useTranslation_default from "../../../hooks/useTranslation.js";
|
|
3
|
+
import BaseDeviceGrant_styles_default from "./BaseDeviceGrant.styles.js";
|
|
4
|
+
import Typography_default from "../../primitives/Typography/Typography.js";
|
|
5
|
+
import Card_default from "../../primitives/Card/Card.js";
|
|
6
|
+
import BaseSignIn_default from "../SignIn/BaseSignIn.js";
|
|
7
|
+
import { createElement } from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
|
|
10
|
+
//#region src/components/auth/DeviceGrant/BaseDeviceGrant.tsx
|
|
11
|
+
/** Renders the server-described Device Grant prompt independently of SDK orchestration. */
|
|
12
|
+
const BaseDeviceGrant = ({ components, className = "", completeMessage = void 0, completeDescription = void 0, failedMessage = void 0, failedDescription = void 0, error, isLoading, preferences, result = null, variant = "default",...signInProps }) => {
|
|
13
|
+
const { theme } = useTheme_default();
|
|
14
|
+
const { t } = useTranslation_default(preferences?.i18n);
|
|
15
|
+
const styles = BaseDeviceGrant_styles_default(theme);
|
|
16
|
+
if ((error || result) && components.length === 0) {
|
|
17
|
+
const isSuccess = result === "success" && !error;
|
|
18
|
+
const resolvedCompleteMessage = completeMessage ?? t("deviceGrant.messages.complete");
|
|
19
|
+
const resolvedCompleteDescription = completeDescription ?? t("deviceGrant.messages.completeDescription");
|
|
20
|
+
const resolvedFailedMessage = failedMessage ?? t("deviceGrant.messages.failed");
|
|
21
|
+
const resolvedFailedDescription = failedDescription ?? t("deviceGrant.messages.failedDescription");
|
|
22
|
+
const title = isSuccess ? resolvedCompleteMessage : resolvedFailedMessage;
|
|
23
|
+
const description = isSuccess ? resolvedCompleteDescription : !error || error.message === resolvedFailedMessage ? resolvedFailedDescription : error.message;
|
|
24
|
+
return /* @__PURE__ */ jsxs(Card_default, {
|
|
25
|
+
className: `${styles["terminalCard"]} ${className}`,
|
|
26
|
+
"data-testid": "device-grant-result",
|
|
27
|
+
variant,
|
|
28
|
+
children: [/* @__PURE__ */ jsx(Typography_default, {
|
|
29
|
+
className: styles["terminalTitle"],
|
|
30
|
+
color: isSuccess ? "success" : "error",
|
|
31
|
+
component: "h2",
|
|
32
|
+
fontWeight: 600,
|
|
33
|
+
variant: "h6",
|
|
34
|
+
children: title
|
|
35
|
+
}), /* @__PURE__ */ jsx(Typography_default, {
|
|
36
|
+
className: styles["terminalDescription"],
|
|
37
|
+
color: "textSecondary",
|
|
38
|
+
component: "p",
|
|
39
|
+
variant: "caption",
|
|
40
|
+
children: description
|
|
41
|
+
})]
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return /* @__PURE__ */ createElement(BaseSignIn_default, {
|
|
45
|
+
...signInProps,
|
|
46
|
+
className,
|
|
47
|
+
key: components.map((component) => component.id).join("|"),
|
|
48
|
+
components,
|
|
49
|
+
error,
|
|
50
|
+
isLoading,
|
|
51
|
+
preferences
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
var BaseDeviceGrant_default = BaseDeviceGrant;
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { BaseDeviceGrant_default as default };
|
|
58
|
+
//# sourceMappingURL=BaseDeviceGrant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseDeviceGrant.js","names":["BaseDeviceGrant: FC<BaseDeviceGrantProps>","useTheme","useTranslation","useStyles","CardPrimitive","Typography","BaseSignIn"],"sources":["../../../../src/components/auth/DeviceGrant/BaseDeviceGrant.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport type {EmbeddedFlowComponent} from '@thunderid/browser';\nimport {FC, ReactElement} from 'react';\nimport useStyles from './BaseDeviceGrant.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport useTranslation from '../../../hooks/useTranslation';\nimport CardPrimitive from '../../primitives/Card/Card';\nimport Typography from '../../primitives/Typography/Typography';\nimport BaseSignIn, {type BaseSignInProps} from '../SignIn/BaseSignIn';\n\nexport type DeviceGrantResult = 'failure' | 'success' | null;\n\nexport interface BaseDeviceGrantProps extends Omit<BaseSignInProps, 'components' | 'onSubmit'> {\n components: EmbeddedFlowComponent[];\n completeMessage?: string;\n completeDescription?: string;\n failedMessage?: string;\n failedDescription?: string;\n onSubmit: NonNullable<BaseSignInProps['onSubmit']>;\n result?: DeviceGrantResult;\n}\n\n/** Renders the server-described Device Grant prompt independently of SDK orchestration. */\nconst BaseDeviceGrant: FC<BaseDeviceGrantProps> = ({\n components,\n className = '',\n completeMessage = undefined,\n completeDescription = undefined,\n failedMessage = undefined,\n failedDescription = undefined,\n error,\n isLoading,\n preferences,\n result = null,\n variant = 'default',\n ...signInProps\n}: BaseDeviceGrantProps): ReactElement => {\n const {theme} = useTheme();\n const {t} = useTranslation(preferences?.i18n);\n const styles = useStyles(theme);\n\n if ((error || result) && components.length === 0) {\n const isSuccess = result === 'success' && !error;\n const resolvedCompleteMessage = completeMessage ?? t('deviceGrant.messages.complete');\n const resolvedCompleteDescription = completeDescription ?? t('deviceGrant.messages.completeDescription');\n const resolvedFailedMessage = failedMessage ?? t('deviceGrant.messages.failed');\n const resolvedFailedDescription = failedDescription ?? t('deviceGrant.messages.failedDescription');\n const title = isSuccess ? resolvedCompleteMessage : resolvedFailedMessage;\n const description = isSuccess\n ? resolvedCompleteDescription\n : !error || error.message === resolvedFailedMessage\n ? resolvedFailedDescription\n : error.message;\n\n return (\n <CardPrimitive\n className={`${styles['terminalCard']} ${className}`}\n data-testid=\"device-grant-result\"\n variant={variant}\n >\n <Typography\n className={styles['terminalTitle']}\n color={isSuccess ? 'success' : 'error'}\n component=\"h2\"\n fontWeight={600}\n variant=\"h6\"\n >\n {title}\n </Typography>\n <Typography className={styles['terminalDescription']} color=\"textSecondary\" component=\"p\" variant=\"caption\">\n {description}\n </Typography>\n </CardPrimitive>\n );\n }\n\n return (\n <BaseSignIn\n {...signInProps}\n className={className}\n key={components.map((component: EmbeddedFlowComponent) => component.id).join('|')}\n components={components}\n error={error}\n isLoading={isLoading}\n preferences={preferences}\n />\n );\n};\n\nexport default BaseDeviceGrant;\n"],"mappings":";;;;;;;;;;;AAyBA,MAAMA,mBAA6C,EACjD,YACA,YAAY,IACZ,kBAAkB,QAClB,sBAAsB,QACtB,gBAAgB,QAChB,oBAAoB,QACpB,OACA,WACA,aACA,SAAS,MACT,UAAU,UACV,GAAG,kBACqC;CACxC,MAAM,EAAC,UAASC,kBAAU;CAC1B,MAAM,EAAC,MAAKC,uBAAe,aAAa,KAAK;CAC7C,MAAM,SAASC,+BAAU,MAAM;AAE/B,MAAK,SAAS,WAAW,WAAW,WAAW,GAAG;EAChD,MAAM,YAAY,WAAW,aAAa,CAAC;EAC3C,MAAM,0BAA0B,mBAAmB,EAAE,gCAAgC;EACrF,MAAM,8BAA8B,uBAAuB,EAAE,2CAA2C;EACxG,MAAM,wBAAwB,iBAAiB,EAAE,8BAA8B;EAC/E,MAAM,4BAA4B,qBAAqB,EAAE,yCAAyC;EAClG,MAAM,QAAQ,YAAY,0BAA0B;EACpD,MAAM,cAAc,YAChB,8BACA,CAAC,SAAS,MAAM,YAAY,wBAC1B,4BACA,MAAM;AAEZ,SACE,qBAACC;GACC,WAAW,GAAG,OAAO,gBAAgB,GAAG;GACxC,eAAY;GACH;cAET,oBAACC;IACC,WAAW,OAAO;IAClB,OAAO,YAAY,YAAY;IAC/B,WAAU;IACV,YAAY;IACZ,SAAQ;cAEP;KACU,EACb,oBAACA;IAAW,WAAW,OAAO;IAAwB,OAAM;IAAgB,WAAU;IAAI,SAAQ;cAC/F;KACU;IACC;;AAIpB,QACE,8BAACC;EACC,GAAI;EACO;EACX,KAAK,WAAW,KAAK,cAAqC,UAAU,GAAG,CAAC,KAAK,IAAI;EACrE;EACL;EACI;EACE;GACb;;AAIN,8BAAe"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseDeviceGrant.styles.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/DeviceGrant/BaseDeviceGrant.styles.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,EAAC,MAAM,oBAAoB,CAAC;AAIzC,QAAA,MAAM,SAAS,GAAI,OAAO,KAAK,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAkBpD,CAAC;AAEJ,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { css } from "../../../styles/emotion.js";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/components/auth/DeviceGrant/BaseDeviceGrant.styles.ts
|
|
5
|
+
const useStyles = (theme) => useMemo(() => ({
|
|
6
|
+
terminalCard: css`
|
|
7
|
+
box-sizing: border-box;
|
|
8
|
+
width: 100%;
|
|
9
|
+
max-width: calc(${theme.vars.spacing.unit} * 60);
|
|
10
|
+
margin: 0 auto;
|
|
11
|
+
gap: ${theme.vars.spacing.unit};
|
|
12
|
+
`,
|
|
13
|
+
terminalDescription: css`
|
|
14
|
+
margin: 0;
|
|
15
|
+
`,
|
|
16
|
+
terminalTitle: css`
|
|
17
|
+
margin: 0;
|
|
18
|
+
`
|
|
19
|
+
}), [theme]);
|
|
20
|
+
var BaseDeviceGrant_styles_default = useStyles;
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { BaseDeviceGrant_styles_default as default };
|
|
24
|
+
//# sourceMappingURL=BaseDeviceGrant.styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseDeviceGrant.styles.js","names":[],"sources":["../../../../src/components/auth/DeviceGrant/BaseDeviceGrant.styles.ts"],"sourcesContent":["// Copyright 2025-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\nconst useStyles = (theme: Theme): Record<string, string> =>\n useMemo(\n () => ({\n terminalCard: css`\n box-sizing: border-box;\n width: 100%;\n max-width: calc(${theme.vars.spacing.unit} * 60);\n margin: 0 auto;\n gap: ${theme.vars.spacing.unit};\n `,\n terminalDescription: css`\n margin: 0;\n `,\n terminalTitle: css`\n margin: 0;\n `,\n }),\n [theme],\n );\n\nexport default useStyles;\n"],"mappings":";;;;AAOA,MAAM,aAAa,UACjB,eACS;CACL,cAAc,GAAG;;;0BAGG,MAAM,KAAK,QAAQ,KAAK;;eAEnC,MAAM,KAAK,QAAQ,KAAK;;CAEjC,qBAAqB,GAAG;;;CAGxB,eAAe,GAAG;;;CAGnB,GACD,CAAC,MAAM,CACR;AAEH,qCAAe"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { executeEmbeddedDeviceGrantFlow } from '@thunderid/browser';
|
|
2
|
+
import type { EmbeddedFlowComponent, EmbeddedSignInFlowRequest, FlowMetadataResponse } from '@thunderid/browser';
|
|
3
|
+
import type { FC, ReactNode } from 'react';
|
|
4
|
+
import { type BaseDeviceGrantProps, type DeviceGrantResult } from './BaseDeviceGrant';
|
|
5
|
+
type EmbeddedDeviceGrantFlowResponse = Awaited<ReturnType<typeof executeEmbeddedDeviceGrantFlow>>;
|
|
6
|
+
/** Values exposed to consumers that provide custom Device Grant UI. */
|
|
7
|
+
export interface DeviceGrantRenderProps {
|
|
8
|
+
/** Additional values returned for the active flow step. */
|
|
9
|
+
additionalData: Record<string, unknown>;
|
|
10
|
+
/** Components returned by the configured flow. */
|
|
11
|
+
components: EmbeddedFlowComponent[];
|
|
12
|
+
/** Current flow error, when one needs to be shown. */
|
|
13
|
+
error: Error | null;
|
|
14
|
+
/** First server validation message for each field. */
|
|
15
|
+
fieldErrors: Record<string, string>;
|
|
16
|
+
/** Values prefilled from the verification URI. */
|
|
17
|
+
initialValues: Record<string, string>;
|
|
18
|
+
/** Whether a flow request is in progress. */
|
|
19
|
+
isLoading: boolean;
|
|
20
|
+
/** Flow metadata used to resolve application-specific template values. */
|
|
21
|
+
meta: FlowMetadataResponse | null;
|
|
22
|
+
/** Submits user-code input or continues the active flow. */
|
|
23
|
+
onSubmit: (payload: EmbeddedSignInFlowRequest) => Promise<void>;
|
|
24
|
+
/** Terminal flow result when the flow has no configured prompt to render. */
|
|
25
|
+
result: DeviceGrantResult;
|
|
26
|
+
}
|
|
27
|
+
export type DeviceGrantProps = Omit<BaseDeviceGrantProps, 'children' | 'components' | 'error' | 'initialValues' | 'isLoading' | 'onSubmit' | 'result' | 'serverFieldErrors'> & {
|
|
28
|
+
/** Render props for Gate or other consumers that provide their own flow UI. */
|
|
29
|
+
children?: (props: DeviceGrantRenderProps) => ReactNode;
|
|
30
|
+
onComplete?: (response: EmbeddedDeviceGrantFlowResponse) => void;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Runs the application's configured Device Grant flow and exposes its state for custom renderers.
|
|
34
|
+
*/
|
|
35
|
+
declare const DeviceGrant: FC<DeviceGrantProps>;
|
|
36
|
+
export default DeviceGrant;
|
|
37
|
+
//# sourceMappingURL=DeviceGrant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeviceGrant.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/DeviceGrant/DeviceGrant.tsx"],"names":[],"mappings":"AAGA,OAAO,EAA6C,8BAA8B,EAAC,MAAM,oBAAoB,CAAC;AAC9G,OAAO,KAAK,EAAC,qBAAqB,EAAE,yBAAyB,EAAE,oBAAoB,EAAC,MAAM,oBAAoB,CAAC;AAE/G,OAAO,KAAK,EAAC,EAAE,EAAgB,SAAS,EAAC,MAAM,OAAO,CAAC;AACvD,OAAwB,EAAC,KAAK,oBAAoB,EAAE,KAAK,iBAAiB,EAAC,MAAM,mBAAmB,CAAC;AAKrG,KAAK,+BAA+B,GAAG,OAAO,CAAC,UAAU,CAAC,OAAO,8BAA8B,CAAC,CAAC,CAAC;AAGlG,uEAAuE;AACvE,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,kDAAkD;IAClD,UAAU,EAAE,qBAAqB,EAAE,CAAC;IACpC,sDAAsD;IACtD,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,kDAAkD;IAClD,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,IAAI,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClC,4DAA4D;IAC5D,QAAQ,EAAE,CAAC,OAAO,EAAE,yBAAyB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,6EAA6E;IAC7E,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,oBAAoB,EACpB,UAAU,GAAG,YAAY,GAAG,OAAO,GAAG,eAAe,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,mBAAmB,CAClH,GAAG;IACF,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,SAAS,CAAC;IACxD,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,+BAA+B,KAAK,IAAI,CAAC;CAClE,CAAC;AAgBF;;GAEG;AACH,QAAA,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CA0MrC,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import useThunderID_default from "../../../contexts/ThunderID/useThunderID.js";
|
|
2
|
+
import useTranslation_default from "../../../hooks/useTranslation.js";
|
|
3
|
+
import { extractErrorMessage, normalizeFlowResponse } from "../../../utils/flowTransformer.js";
|
|
4
|
+
import BaseDeviceGrant_default from "./BaseDeviceGrant.js";
|
|
5
|
+
import { EmbeddedFlowType, EmbeddedSignInFlowStatus, executeEmbeddedDeviceGrantFlow } from "@thunderid/browser";
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { Fragment as Fragment$1, jsx } from "react/jsx-runtime";
|
|
8
|
+
|
|
9
|
+
//#region src/components/auth/DeviceGrant/DeviceGrant.tsx
|
|
10
|
+
const clearVerificationParameters = () => {
|
|
11
|
+
if (!window.location.href) return;
|
|
12
|
+
const url = new URL(window.location.href);
|
|
13
|
+
url.searchParams.delete("user_code");
|
|
14
|
+
url.searchParams.delete("applicationId");
|
|
15
|
+
window.history.replaceState(window.history.state, "", url.toString());
|
|
16
|
+
};
|
|
17
|
+
const hasUserCodeInput = (components) => components.some((component) => component.ref === "user_code" || Array.isArray(component.components) && hasUserCodeInput(component.components));
|
|
18
|
+
/**
|
|
19
|
+
* Runs the application's configured Device Grant flow and exposes its state for custom renderers.
|
|
20
|
+
*/
|
|
21
|
+
const DeviceGrant = ({ children = void 0, className = "", onComplete = void 0, onError = void 0, preferences = {}, size = "medium", variant = "default",...baseProps }) => {
|
|
22
|
+
const { applicationId, baseUrl, meta } = useThunderID_default();
|
|
23
|
+
const { t } = useTranslation_default(preferences?.i18n);
|
|
24
|
+
const [components, setComponents] = useState([]);
|
|
25
|
+
const [additionalData, setAdditionalData] = useState({});
|
|
26
|
+
const [initialValues, setInitialValues] = useState({});
|
|
27
|
+
const [serverFieldErrors, setServerFieldErrors] = useState(null);
|
|
28
|
+
const [executionId, setExecutionId] = useState("");
|
|
29
|
+
const [challengeToken, setChallengeToken] = useState("");
|
|
30
|
+
const [error, setError] = useState(null);
|
|
31
|
+
const [isLoading, setIsLoading] = useState(() => {
|
|
32
|
+
if (applicationId) return true;
|
|
33
|
+
return typeof window !== "undefined" && Boolean(new URL(window.location.href).searchParams.get("applicationId"));
|
|
34
|
+
});
|
|
35
|
+
const [result, setResult] = useState(null);
|
|
36
|
+
const flowStartAttempted = useRef(false);
|
|
37
|
+
const verificationParametersRead = useRef(false);
|
|
38
|
+
const handleError = useCallback((flowError) => {
|
|
39
|
+
setComponents([]);
|
|
40
|
+
setAdditionalData({});
|
|
41
|
+
setServerFieldErrors(null);
|
|
42
|
+
setError(flowError);
|
|
43
|
+
setResult("failure");
|
|
44
|
+
onError?.(flowError);
|
|
45
|
+
}, [onError]);
|
|
46
|
+
const applyResponse = useCallback((response) => {
|
|
47
|
+
const normalized = normalizeFlowResponse(response, t, {
|
|
48
|
+
throwOnError: false,
|
|
49
|
+
resolveTranslations: false
|
|
50
|
+
}, meta);
|
|
51
|
+
setExecutionId(response.executionId);
|
|
52
|
+
setChallengeToken(response.challengeToken ?? "");
|
|
53
|
+
setComponents(normalized.components);
|
|
54
|
+
setAdditionalData(normalized.additionalData);
|
|
55
|
+
setServerFieldErrors(response.data?.fieldErrors ?? null);
|
|
56
|
+
setError(response.error ? new Error(extractErrorMessage(response, t)) : null);
|
|
57
|
+
if (response.flowStatus === EmbeddedSignInFlowStatus.Complete) {
|
|
58
|
+
setResult("success");
|
|
59
|
+
onComplete?.(response);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (response.flowStatus === EmbeddedSignInFlowStatus.Error) {
|
|
63
|
+
const flowError = new Error(extractErrorMessage(response, t, "deviceGrant.messages.failed"));
|
|
64
|
+
setError(flowError);
|
|
65
|
+
setResult("failure");
|
|
66
|
+
onError?.(flowError);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
setResult(null);
|
|
70
|
+
}, [
|
|
71
|
+
meta,
|
|
72
|
+
onComplete,
|
|
73
|
+
onError,
|
|
74
|
+
t
|
|
75
|
+
]);
|
|
76
|
+
const startFlow = useCallback(async (appId) => {
|
|
77
|
+
setIsLoading(true);
|
|
78
|
+
setError(null);
|
|
79
|
+
try {
|
|
80
|
+
const response = await executeEmbeddedDeviceGrantFlow({
|
|
81
|
+
baseUrl,
|
|
82
|
+
payload: {
|
|
83
|
+
applicationId: appId,
|
|
84
|
+
flowType: EmbeddedFlowType.DeviceGrant,
|
|
85
|
+
inputs: {}
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
clearVerificationParameters();
|
|
89
|
+
applyResponse(response);
|
|
90
|
+
} catch (flowError) {
|
|
91
|
+
handleError(flowError instanceof Error ? flowError : new Error(t("deviceGrant.errors.continue")));
|
|
92
|
+
} finally {
|
|
93
|
+
setIsLoading(false);
|
|
94
|
+
}
|
|
95
|
+
}, [
|
|
96
|
+
applyResponse,
|
|
97
|
+
baseUrl,
|
|
98
|
+
handleError,
|
|
99
|
+
t
|
|
100
|
+
]);
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
const url = new URL(window.location.href);
|
|
103
|
+
if (!verificationParametersRead.current) {
|
|
104
|
+
verificationParametersRead.current = true;
|
|
105
|
+
const userCode = url.searchParams.get("user_code") ?? "";
|
|
106
|
+
if (userCode) setInitialValues({ user_code: userCode });
|
|
107
|
+
}
|
|
108
|
+
const applicationIdFromUrl = url.searchParams.get("applicationId");
|
|
109
|
+
const appId = applicationIdFromUrl?.trim() ? applicationIdFromUrl : applicationId;
|
|
110
|
+
if (flowStartAttempted.current) return;
|
|
111
|
+
if (!appId) {
|
|
112
|
+
flowStartAttempted.current = true;
|
|
113
|
+
handleError(new Error(t("deviceGrant.errors.start")));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
flowStartAttempted.current = true;
|
|
117
|
+
startFlow(appId);
|
|
118
|
+
}, [
|
|
119
|
+
applicationId,
|
|
120
|
+
handleError,
|
|
121
|
+
startFlow,
|
|
122
|
+
t
|
|
123
|
+
]);
|
|
124
|
+
const submit = async (payload, actionId) => {
|
|
125
|
+
setIsLoading(true);
|
|
126
|
+
setError(null);
|
|
127
|
+
setResult(null);
|
|
128
|
+
try {
|
|
129
|
+
if (!executionId) return;
|
|
130
|
+
applyResponse(await executeEmbeddedDeviceGrantFlow({
|
|
131
|
+
baseUrl,
|
|
132
|
+
payload: {
|
|
133
|
+
action: payload.action ?? actionId,
|
|
134
|
+
challengeToken,
|
|
135
|
+
executionId,
|
|
136
|
+
inputs: {
|
|
137
|
+
...Object.fromEntries(Object.entries(payload.inputs ?? {}).filter(([key]) => !key.startsWith("__consent_opt__"))),
|
|
138
|
+
...!hasUserCodeInput(components) ? { user_code: void 0 } : {}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}));
|
|
142
|
+
} catch (flowError) {
|
|
143
|
+
handleError(flowError instanceof Error ? flowError : new Error(t("deviceGrant.errors.continue")));
|
|
144
|
+
} finally {
|
|
145
|
+
setIsLoading(false);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const handleBaseSubmit = (payload, component) => submit(payload, component.id);
|
|
149
|
+
const fieldErrors = useMemo(() => {
|
|
150
|
+
const errors = {};
|
|
151
|
+
(serverFieldErrors ?? []).forEach((fieldError) => {
|
|
152
|
+
if (!(fieldError.identifier in errors)) errors[fieldError.identifier] = fieldError.message;
|
|
153
|
+
});
|
|
154
|
+
return errors;
|
|
155
|
+
}, [serverFieldErrors]);
|
|
156
|
+
if (children) return /* @__PURE__ */ jsx(Fragment$1, { children: children({
|
|
157
|
+
additionalData,
|
|
158
|
+
components,
|
|
159
|
+
error,
|
|
160
|
+
fieldErrors,
|
|
161
|
+
initialValues,
|
|
162
|
+
isLoading,
|
|
163
|
+
meta,
|
|
164
|
+
onSubmit: submit,
|
|
165
|
+
result
|
|
166
|
+
}) });
|
|
167
|
+
return /* @__PURE__ */ jsx(BaseDeviceGrant_default, {
|
|
168
|
+
...baseProps,
|
|
169
|
+
className,
|
|
170
|
+
components,
|
|
171
|
+
additionalData,
|
|
172
|
+
error,
|
|
173
|
+
initialValues,
|
|
174
|
+
isLoading,
|
|
175
|
+
onError: handleError,
|
|
176
|
+
onSubmit: handleBaseSubmit,
|
|
177
|
+
preferences,
|
|
178
|
+
result,
|
|
179
|
+
serverFieldErrors,
|
|
180
|
+
size,
|
|
181
|
+
variant
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
var DeviceGrant_default = DeviceGrant;
|
|
185
|
+
|
|
186
|
+
//#endregion
|
|
187
|
+
export { DeviceGrant_default as default };
|
|
188
|
+
//# sourceMappingURL=DeviceGrant.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DeviceGrant.js","names":["DeviceGrant: FC<DeviceGrantProps>","useThunderID","useTranslation","errors: Record<string, string>","BaseDeviceGrant"],"sources":["../../../../src/components/auth/DeviceGrant/DeviceGrant.tsx"],"sourcesContent":["// Copyright 2025-2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {EmbeddedFlowType, EmbeddedSignInFlowStatus, executeEmbeddedDeviceGrantFlow} from '@thunderid/browser';\nimport type {EmbeddedFlowComponent, EmbeddedSignInFlowRequest, FlowMetadataResponse} from '@thunderid/browser';\nimport {useCallback, useEffect, useMemo, useRef, useState} from 'react';\nimport type {FC, ReactElement, ReactNode} from 'react';\nimport BaseDeviceGrant, {type BaseDeviceGrantProps, type DeviceGrantResult} from './BaseDeviceGrant';\nimport useThunderID from '../../../contexts/ThunderID/useThunderID';\nimport useTranslation from '../../../hooks/useTranslation';\nimport {extractErrorMessage, normalizeFlowResponse} from '../../../utils/flowTransformer';\n\ntype EmbeddedDeviceGrantFlowResponse = Awaited<ReturnType<typeof executeEmbeddedDeviceGrantFlow>>;\ntype DeviceGrantFieldError = NonNullable<EmbeddedDeviceGrantFlowResponse['data']['fieldErrors']>[number];\n\n/** Values exposed to consumers that provide custom Device Grant UI. */\nexport interface DeviceGrantRenderProps {\n /** Additional values returned for the active flow step. */\n additionalData: Record<string, unknown>;\n /** Components returned by the configured flow. */\n components: EmbeddedFlowComponent[];\n /** Current flow error, when one needs to be shown. */\n error: Error | null;\n /** First server validation message for each field. */\n fieldErrors: Record<string, string>;\n /** Values prefilled from the verification URI. */\n initialValues: Record<string, string>;\n /** Whether a flow request is in progress. */\n isLoading: boolean;\n /** Flow metadata used to resolve application-specific template values. */\n meta: FlowMetadataResponse | null;\n /** Submits user-code input or continues the active flow. */\n onSubmit: (payload: EmbeddedSignInFlowRequest) => Promise<void>;\n /** Terminal flow result when the flow has no configured prompt to render. */\n result: DeviceGrantResult;\n}\n\nexport type DeviceGrantProps = Omit<\n BaseDeviceGrantProps,\n 'children' | 'components' | 'error' | 'initialValues' | 'isLoading' | 'onSubmit' | 'result' | 'serverFieldErrors'\n> & {\n /** Render props for Gate or other consumers that provide their own flow UI. */\n children?: (props: DeviceGrantRenderProps) => ReactNode;\n onComplete?: (response: EmbeddedDeviceGrantFlowResponse) => void;\n};\n\nconst clearVerificationParameters = (): void => {\n if (!window.location.href) return;\n const url = new URL(window.location.href);\n url.searchParams.delete('user_code');\n url.searchParams.delete('applicationId');\n window.history.replaceState(window.history.state, '', url.toString());\n};\n\nconst hasUserCodeInput = (components: EmbeddedFlowComponent[]): boolean =>\n components.some(\n (component: EmbeddedFlowComponent) =>\n component.ref === 'user_code' || (Array.isArray(component.components) && hasUserCodeInput(component.components)),\n );\n\n/**\n * Runs the application's configured Device Grant flow and exposes its state for custom renderers.\n */\nconst DeviceGrant: FC<DeviceGrantProps> = ({\n children = undefined,\n className = '',\n onComplete = undefined,\n onError = undefined,\n preferences = {},\n size = 'medium',\n variant = 'default',\n ...baseProps\n}: DeviceGrantProps): ReactElement => {\n const {applicationId, baseUrl, meta} = useThunderID();\n const {t} = useTranslation(preferences?.i18n);\n const [components, setComponents] = useState<EmbeddedFlowComponent[]>([]);\n const [additionalData, setAdditionalData] = useState<Record<string, unknown>>({});\n const [initialValues, setInitialValues] = useState<Record<string, string>>({});\n const [serverFieldErrors, setServerFieldErrors] = useState<\n EmbeddedDeviceGrantFlowResponse['data']['fieldErrors'] | null\n >(null);\n const [executionId, setExecutionId] = useState('');\n const [challengeToken, setChallengeToken] = useState('');\n const [error, setError] = useState<Error | null>(null);\n const [isLoading, setIsLoading] = useState(() => {\n if (applicationId) return true;\n return typeof window !== 'undefined' && Boolean(new URL(window.location.href).searchParams.get('applicationId'));\n });\n const [result, setResult] = useState<DeviceGrantResult>(null);\n const flowStartAttempted = useRef(false);\n const verificationParametersRead = useRef(false);\n\n const handleError = useCallback(\n (flowError: Error): void => {\n setComponents([]);\n setAdditionalData({});\n setServerFieldErrors(null);\n setError(flowError);\n setResult('failure');\n onError?.(flowError);\n },\n [onError],\n );\n\n const applyResponse = useCallback(\n (response: EmbeddedDeviceGrantFlowResponse): void => {\n const normalized = normalizeFlowResponse(\n response,\n t,\n {\n throwOnError: false,\n resolveTranslations: false,\n },\n meta,\n );\n setExecutionId(response.executionId);\n setChallengeToken(response.challengeToken ?? '');\n setComponents(normalized.components);\n setAdditionalData(normalized.additionalData);\n setServerFieldErrors(response.data?.fieldErrors ?? null);\n setError(response.error ? new Error(extractErrorMessage(response, t)) : null);\n\n if (response.flowStatus === EmbeddedSignInFlowStatus.Complete) {\n setResult('success');\n onComplete?.(response);\n return;\n }\n\n if (response.flowStatus === EmbeddedSignInFlowStatus.Error) {\n const flowError = new Error(extractErrorMessage(response, t, 'deviceGrant.messages.failed'));\n setError(flowError);\n setResult('failure');\n onError?.(flowError);\n return;\n }\n\n setResult(null);\n },\n [meta, onComplete, onError, t],\n );\n\n const startFlow = useCallback(\n async (appId: string): Promise<void> => {\n setIsLoading(true);\n setError(null);\n try {\n const response = await executeEmbeddedDeviceGrantFlow({\n baseUrl,\n payload: {\n applicationId: appId,\n flowType: EmbeddedFlowType.DeviceGrant,\n inputs: {},\n },\n });\n clearVerificationParameters();\n applyResponse(response);\n } catch (flowError) {\n handleError(flowError instanceof Error ? flowError : new Error(t('deviceGrant.errors.continue')));\n } finally {\n setIsLoading(false);\n }\n },\n [applyResponse, baseUrl, handleError, t],\n );\n\n useEffect(() => {\n const url = new URL(window.location.href);\n if (!verificationParametersRead.current) {\n verificationParametersRead.current = true;\n const userCode = url.searchParams.get('user_code') ?? '';\n if (userCode) setInitialValues({user_code: userCode});\n }\n\n const applicationIdFromUrl = url.searchParams.get('applicationId');\n const appId = applicationIdFromUrl?.trim() ? applicationIdFromUrl : applicationId;\n if (flowStartAttempted.current) return;\n if (!appId) {\n flowStartAttempted.current = true;\n handleError(new Error(t('deviceGrant.errors.start')));\n return;\n }\n\n flowStartAttempted.current = true;\n void startFlow(appId);\n }, [applicationId, handleError, startFlow, t]);\n\n const submit = async (payload: EmbeddedSignInFlowRequest, actionId?: string): Promise<void> => {\n setIsLoading(true);\n setError(null);\n setResult(null);\n try {\n if (!executionId) return;\n\n const response = await executeEmbeddedDeviceGrantFlow({\n baseUrl,\n payload: {\n action: payload.action ?? actionId,\n challengeToken,\n executionId,\n inputs: {\n ...Object.fromEntries(\n Object.entries(payload.inputs ?? {}).filter(\n ([key]: [string, unknown]) => !key.startsWith('__consent_opt__'),\n ),\n ),\n ...(!hasUserCodeInput(components) ? {user_code: undefined} : {}),\n },\n },\n });\n applyResponse(response);\n } catch (flowError) {\n handleError(flowError instanceof Error ? flowError : new Error(t('deviceGrant.errors.continue')));\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleBaseSubmit = (payload: EmbeddedSignInFlowRequest, component: EmbeddedFlowComponent): Promise<void> =>\n submit(payload, component.id);\n\n const fieldErrors = useMemo<Record<string, string>>(() => {\n const errors: Record<string, string> = {};\n (serverFieldErrors ?? []).forEach((fieldError: DeviceGrantFieldError) => {\n if (!(fieldError.identifier in errors)) errors[fieldError.identifier] = fieldError.message;\n });\n\n return errors;\n }, [serverFieldErrors]);\n\n if (children) {\n return (\n <>\n {children({\n additionalData,\n components,\n error,\n fieldErrors,\n initialValues,\n isLoading,\n meta,\n onSubmit: submit,\n result,\n })}\n </>\n );\n }\n\n return (\n <BaseDeviceGrant\n {...baseProps}\n className={className}\n components={components}\n additionalData={additionalData}\n error={error}\n initialValues={initialValues}\n isLoading={isLoading}\n onError={handleError}\n onSubmit={handleBaseSubmit}\n preferences={preferences}\n result={result}\n serverFieldErrors={serverFieldErrors}\n size={size}\n variant={variant}\n />\n );\n};\n\nexport default DeviceGrant;\n"],"mappings":"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"}
|
|
@@ -6,8 +6,8 @@ import useTranslation_default from "../../../hooks/useTranslation.js";
|
|
|
6
6
|
import { extractErrorMessage, normalizeFlowResponse } from "../../../utils/flowTransformer.js";
|
|
7
7
|
import Spinner_default from "../../primitives/Spinner/Spinner.js";
|
|
8
8
|
import Typography_default from "../../primitives/Typography/Typography.js";
|
|
9
|
-
import Alert_default from "../../primitives/Alert/Alert.js";
|
|
10
9
|
import Card_default from "../../primitives/Card/Card.js";
|
|
10
|
+
import Alert_default from "../../primitives/Alert/Alert.js";
|
|
11
11
|
import { renderInviteUserComponents } from "../flow/AuthOptionFactory.js";
|
|
12
12
|
import BaseInviteUser_styles_default from "./BaseInviteUser.styles.js";
|
|
13
13
|
import { EmbeddedFlowType, buildValidatorFromRules, logger, resolveFlowTemplateLiterals } from "@thunderid/browser";
|
|
@@ -9,10 +9,10 @@ import useTranslation_default from "../../../hooks/useTranslation.js";
|
|
|
9
9
|
import { extractErrorMessage, normalizeFlowResponse } from "../../../utils/flowTransformer.js";
|
|
10
10
|
import { useForm } from "../../../hooks/useForm.js";
|
|
11
11
|
import Spinner_default from "../../primitives/Spinner/Spinner.js";
|
|
12
|
-
import composeAffixedInputs_default from "../../../utils/composeAffixedInputs.js";
|
|
13
12
|
import Typography_default from "../../primitives/Typography/Typography.js";
|
|
14
|
-
import Alert_default from "../../primitives/Alert/Alert.js";
|
|
15
13
|
import Card_default from "../../primitives/Card/Card.js";
|
|
14
|
+
import composeAffixedInputs_default from "../../../utils/composeAffixedInputs.js";
|
|
15
|
+
import Alert_default from "../../primitives/Alert/Alert.js";
|
|
16
16
|
import { renderRecoveryComponents } from "../flow/AuthOptionFactory.js";
|
|
17
17
|
import BaseSignUp_styles_default from "../SignUp/BaseSignUp.styles.js";
|
|
18
18
|
import getAuthComponentHeadings_default from "../../../utils/getAuthComponentHeadings.js";
|
|
@@ -116,6 +116,10 @@ export interface BaseSignInProps {
|
|
|
116
116
|
* Flag to determine if the component is ready to be rendered.
|
|
117
117
|
*/
|
|
118
118
|
isLoading?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Values to seed form fields with, such as a value supplied by a verification URI.
|
|
121
|
+
*/
|
|
122
|
+
initialValues?: Record<string, string>;
|
|
119
123
|
/**
|
|
120
124
|
* Timer flag disabling actions
|
|
121
125
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseSignIn.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/SignIn/BaseSignIn.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,yBAAyB,EACzB,qBAAqB,EACrB,UAAU,EACV,oBAAoB,EACpB,WAAW,EAEZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"BaseSignIn.d.ts","sourceRoot":"","sources":["../../../../src/components/auth/SignIn/BaseSignIn.tsx"],"names":[],"mappings":"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"}
|
|
@@ -9,21 +9,21 @@ import useTranslation_default from "../../../hooks/useTranslation.js";
|
|
|
9
9
|
import { extractErrorMessage } from "../../../utils/flowTransformer.js";
|
|
10
10
|
import { useForm } from "../../../hooks/useForm.js";
|
|
11
11
|
import Spinner_default from "../../primitives/Spinner/Spinner.js";
|
|
12
|
+
import Typography_default from "../../primitives/Typography/Typography.js";
|
|
13
|
+
import Card_default from "../../primitives/Card/Card.js";
|
|
12
14
|
import BaseSignIn_styles_default from "./BaseSignIn.styles.js";
|
|
13
15
|
import composeAffixedInputs_default from "../../../utils/composeAffixedInputs.js";
|
|
14
|
-
import Typography_default from "../../primitives/Typography/Typography.js";
|
|
15
16
|
import Alert_default from "../../primitives/Alert/Alert.js";
|
|
16
|
-
import Card_default from "../../primitives/Card/Card.js";
|
|
17
17
|
import { renderSignInComponents } from "../flow/AuthOptionFactory.js";
|
|
18
18
|
import { buildValidatorFromRules, withVendorCSSClassPrefix } from "@thunderid/browser";
|
|
19
|
-
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
19
|
+
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
20
20
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
21
21
|
|
|
22
22
|
//#region src/components/auth/SignIn/BaseSignIn.tsx
|
|
23
23
|
/**
|
|
24
24
|
* Internal component that consumes FlowContext and renders the sign-in UI.
|
|
25
25
|
*/
|
|
26
|
-
const BaseSignInContent = ({ components = [], onSubmit, onError, error: externalError, id, className = "", inputClassName = "", buttonClassName = "", messageClassName = "", size = "medium", variant = "outlined", isLoading: externalIsLoading, children, additionalData = {}, isTimeoutDisabled = false, serverFieldErrors = null, revalidateOnChangeAfterBlur = false }) => {
|
|
26
|
+
const BaseSignInContent = ({ components = [], onSubmit, onError, error: externalError, id, className = "", inputClassName = "", buttonClassName = "", messageClassName = "", size = "medium", variant = "outlined", isLoading: externalIsLoading, initialValues, children, additionalData = {}, isTimeoutDisabled = false, serverFieldErrors = null, revalidateOnChangeAfterBlur = false }) => {
|
|
27
27
|
const { meta, vendor } = useThunderID_default();
|
|
28
28
|
const { theme } = useTheme_default();
|
|
29
29
|
const customRenderers = useContext(ComponentRendererContext_default);
|
|
@@ -94,7 +94,7 @@ const BaseSignInContent = ({ components = [], onSubmit, onError, error: external
|
|
|
94
94
|
processComponents(flowComponents);
|
|
95
95
|
return fields;
|
|
96
96
|
}, [t]);
|
|
97
|
-
const { values: formValues, touched: touchedFields, errors: formErrors, isValid: isFormValid, setValue: setFormValue, setTouched: setFormTouched, setTouchedFields, setErrors: setFormErrors, clearErrors: clearFormErrors, validateForm, touchAllFields, reset: resetForm, revalidateTouchedFields } = useForm({
|
|
97
|
+
const { values: formValues, touched: touchedFields, errors: formErrors, isValid: isFormValid, setValue: setFormValue, setValues: setFormValues, setTouched: setFormTouched, setTouchedFields, setErrors: setFormErrors, clearErrors: clearFormErrors, validateForm, touchAllFields, reset: resetForm, revalidateTouchedFields } = useForm({
|
|
98
98
|
fields: useMemo(() => components ? extractFormFields(components) : [], [components, extractFormFields]),
|
|
99
99
|
initialValues: {},
|
|
100
100
|
requiredMessage: t("validations.required.field.error"),
|
|
@@ -102,6 +102,17 @@ const BaseSignInContent = ({ components = [], onSubmit, onError, error: external
|
|
|
102
102
|
validateOnBlur: true,
|
|
103
103
|
validateOnChange: false
|
|
104
104
|
});
|
|
105
|
+
const initialValuesKey = useMemo(() => JSON.stringify(Object.entries(initialValues ?? {}).sort(([left], [right]) => left.localeCompare(right))), [initialValues]);
|
|
106
|
+
const appliedInitialValuesKeyRef = useRef(null);
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
if (!initialValues || Object.keys(initialValues).length === 0 || appliedInitialValuesKeyRef.current === initialValuesKey) return;
|
|
109
|
+
appliedInitialValuesKeyRef.current = initialValuesKey;
|
|
110
|
+
setFormValues(initialValues);
|
|
111
|
+
}, [
|
|
112
|
+
initialValues,
|
|
113
|
+
initialValuesKey,
|
|
114
|
+
setFormValues
|
|
115
|
+
]);
|
|
105
116
|
useEffect(() => {
|
|
106
117
|
clearFormErrors();
|
|
107
118
|
if (!serverFieldErrors || serverFieldErrors.length === 0) return;
|