@thunderid/react 1.0.8 → 1.1.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/api/updateMeCredentials.d.ts +33 -0
- package/dist/api/updateMeCredentials.d.ts.map +1 -0
- package/dist/api/updateMeCredentials.js +29 -0
- package/dist/api/updateMeCredentials.js.map +1 -0
- package/dist/cjs/api/updateMeCredentials.cjs +31 -0
- package/dist/cjs/api/updateMeCredentials.cjs.map +1 -0
- package/dist/cjs/components/presentation/ChangeCredential/BaseChangeCredential.cjs +187 -0
- package/dist/cjs/components/presentation/ChangeCredential/BaseChangeCredential.cjs.map +1 -0
- package/dist/cjs/components/presentation/ChangeCredential/BaseChangeCredential.styles.cjs +108 -0
- package/dist/cjs/components/presentation/ChangeCredential/BaseChangeCredential.styles.cjs.map +1 -0
- package/dist/cjs/components/presentation/ChangeCredential/ChangeCredential.cjs +123 -0
- package/dist/cjs/components/presentation/ChangeCredential/ChangeCredential.cjs.map +1 -0
- package/dist/cjs/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.cjs +1 -1
- package/dist/cjs/components/presentation/UserDropdown/BaseUserDropdown.cjs +2 -2
- package/dist/cjs/components/presentation/UserDropdown/BaseUserDropdown.cjs.map +1 -1
- package/dist/cjs/components/presentation/UserDropdown/UserDropdown.cjs +8 -4
- package/dist/cjs/components/presentation/UserDropdown/UserDropdown.cjs.map +1 -1
- package/dist/cjs/components/presentation/UserProfile/BaseUserProfile.styles.cjs +2 -0
- package/dist/cjs/components/presentation/UserProfile/BaseUserProfile.styles.cjs.map +1 -1
- package/dist/cjs/components/primitives/PasswordField/PasswordField.cjs +2 -2
- package/dist/cjs/components/primitives/PasswordField/PasswordField.cjs.map +1 -1
- package/dist/cjs/contexts/Theme/ThemeProvider.cjs +26 -4
- package/dist/cjs/contexts/Theme/ThemeProvider.cjs.map +1 -1
- package/dist/cjs/contexts/ThunderID/ThunderIDContext.cjs +2 -0
- package/dist/cjs/contexts/ThunderID/ThunderIDContext.cjs.map +1 -1
- package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs +7 -1
- package/dist/cjs/contexts/ThunderID/ThunderIDProvider.cjs.map +1 -1
- package/dist/cjs/hooks/agents/useCreateAgent.cjs +26 -0
- package/dist/cjs/hooks/agents/useCreateAgent.cjs.map +1 -0
- package/dist/cjs/hooks/agents/useDeleteAgent.cjs +26 -0
- package/dist/cjs/hooks/agents/useDeleteAgent.cjs.map +1 -0
- package/dist/cjs/hooks/agents/useGetAgent.cjs +30 -0
- package/dist/cjs/hooks/agents/useGetAgent.cjs.map +1 -0
- package/dist/cjs/hooks/agents/useGetAgents.cjs +31 -0
- package/dist/cjs/hooks/agents/useGetAgents.cjs.map +1 -0
- package/dist/cjs/hooks/agents/useUpdateAgent.cjs +27 -0
- package/dist/cjs/hooks/agents/useUpdateAgent.cjs.map +1 -0
- package/dist/cjs/hooks/applications/useCreateApplication.cjs +31 -0
- package/dist/cjs/hooks/applications/useCreateApplication.cjs.map +1 -0
- package/dist/cjs/hooks/applications/useDeleteApplication.cjs +26 -0
- package/dist/cjs/hooks/applications/useDeleteApplication.cjs.map +1 -0
- package/dist/cjs/hooks/applications/useGetApplication.cjs +35 -0
- package/dist/cjs/hooks/applications/useGetApplication.cjs.map +1 -0
- package/dist/cjs/hooks/applications/useGetApplications.cjs +36 -0
- package/dist/cjs/hooks/applications/useGetApplications.cjs.map +1 -0
- package/dist/cjs/hooks/applications/useUpdateApplication.cjs +27 -0
- package/dist/cjs/hooks/applications/useUpdateApplication.cjs.map +1 -0
- package/dist/cjs/hooks/useManagementEndpoint.cjs +25 -0
- package/dist/cjs/hooks/useManagementEndpoint.cjs.map +1 -0
- package/dist/cjs/hooks/useResourceMutation.cjs +72 -0
- package/dist/cjs/hooks/useResourceMutation.cjs.map +1 -0
- package/dist/cjs/hooks/useResourceQuery.cjs +86 -0
- package/dist/cjs/hooks/useResourceQuery.cjs.map +1 -0
- package/dist/cjs/hooks/users/useCreateUser.cjs +26 -0
- package/dist/cjs/hooks/users/useCreateUser.cjs.map +1 -0
- package/dist/cjs/hooks/users/useDeleteUser.cjs +26 -0
- package/dist/cjs/hooks/users/useDeleteUser.cjs.map +1 -0
- package/dist/cjs/hooks/users/useGetUser.cjs +30 -0
- package/dist/cjs/hooks/users/useGetUser.cjs.map +1 -0
- package/dist/cjs/hooks/users/useGetUsers.cjs +38 -0
- package/dist/cjs/hooks/users/useGetUsers.cjs.map +1 -0
- package/dist/cjs/hooks/users/useUpdateUser.cjs +27 -0
- package/dist/cjs/hooks/users/useUpdateUser.cjs.map +1 -0
- package/dist/cjs/index.cjs +144 -0
- package/dist/cjs/utils/createAuthenticatedFetcher.cjs +43 -0
- package/dist/cjs/utils/createAuthenticatedFetcher.cjs.map +1 -0
- package/dist/cjs/utils/createResourceInvalidator.cjs +38 -0
- package/dist/cjs/utils/createResourceInvalidator.cjs.map +1 -0
- package/dist/components/presentation/ChangeCredential/BaseChangeCredential.d.ts +100 -0
- package/dist/components/presentation/ChangeCredential/BaseChangeCredential.d.ts.map +1 -0
- package/dist/components/presentation/ChangeCredential/BaseChangeCredential.js +183 -0
- package/dist/components/presentation/ChangeCredential/BaseChangeCredential.js.map +1 -0
- package/dist/components/presentation/ChangeCredential/BaseChangeCredential.styles.d.ts +10 -0
- package/dist/components/presentation/ChangeCredential/BaseChangeCredential.styles.d.ts.map +1 -0
- package/dist/components/presentation/ChangeCredential/BaseChangeCredential.styles.js +108 -0
- package/dist/components/presentation/ChangeCredential/BaseChangeCredential.styles.js.map +1 -0
- package/dist/components/presentation/ChangeCredential/ChangeCredential.d.ts +55 -0
- package/dist/components/presentation/ChangeCredential/ChangeCredential.d.ts.map +1 -0
- package/dist/components/presentation/ChangeCredential/ChangeCredential.js +119 -0
- package/dist/components/presentation/ChangeCredential/ChangeCredential.js.map +1 -0
- package/dist/components/presentation/LanguageSwitcher/BaseLanguageSwitcher.js +1 -1
- package/dist/components/presentation/UserDropdown/BaseUserDropdown.d.ts +5 -0
- package/dist/components/presentation/UserDropdown/BaseUserDropdown.d.ts.map +1 -1
- package/dist/components/presentation/UserDropdown/BaseUserDropdown.js +2 -2
- package/dist/components/presentation/UserDropdown/BaseUserDropdown.js.map +1 -1
- package/dist/components/presentation/UserDropdown/UserDropdown.d.ts +12 -0
- package/dist/components/presentation/UserDropdown/UserDropdown.d.ts.map +1 -1
- package/dist/components/presentation/UserDropdown/UserDropdown.js +8 -4
- package/dist/components/presentation/UserDropdown/UserDropdown.js.map +1 -1
- package/dist/components/presentation/UserProfile/BaseUserProfile.styles.d.ts.map +1 -1
- package/dist/components/presentation/UserProfile/BaseUserProfile.styles.js +2 -0
- package/dist/components/presentation/UserProfile/BaseUserProfile.styles.js.map +1 -1
- package/dist/components/primitives/PasswordField/PasswordField.d.ts +6 -0
- package/dist/components/primitives/PasswordField/PasswordField.d.ts.map +1 -1
- package/dist/components/primitives/PasswordField/PasswordField.js +2 -2
- package/dist/components/primitives/PasswordField/PasswordField.js.map +1 -1
- package/dist/contexts/Theme/ThemeProvider.d.ts +1 -1
- package/dist/contexts/Theme/ThemeProvider.d.ts.map +1 -1
- package/dist/contexts/Theme/ThemeProvider.js +27 -5
- package/dist/contexts/Theme/ThemeProvider.js.map +1 -1
- package/dist/contexts/ThunderID/ThunderIDContext.d.ts +12 -1
- package/dist/contexts/ThunderID/ThunderIDContext.d.ts.map +1 -1
- package/dist/contexts/ThunderID/ThunderIDContext.js +2 -0
- package/dist/contexts/ThunderID/ThunderIDContext.js.map +1 -1
- package/dist/contexts/ThunderID/ThunderIDProvider.d.ts.map +1 -1
- package/dist/contexts/ThunderID/ThunderIDProvider.js +7 -1
- package/dist/contexts/ThunderID/ThunderIDProvider.js.map +1 -1
- package/dist/hooks/agents/useCreateAgent.d.ts +11 -0
- package/dist/hooks/agents/useCreateAgent.d.ts.map +1 -0
- package/dist/hooks/agents/useCreateAgent.js +24 -0
- package/dist/hooks/agents/useCreateAgent.js.map +1 -0
- package/dist/hooks/agents/useDeleteAgent.d.ts +10 -0
- package/dist/hooks/agents/useDeleteAgent.d.ts.map +1 -0
- package/dist/hooks/agents/useDeleteAgent.js +24 -0
- package/dist/hooks/agents/useDeleteAgent.js.map +1 -0
- package/dist/hooks/agents/useGetAgent.d.ts +12 -0
- package/dist/hooks/agents/useGetAgent.d.ts.map +1 -0
- package/dist/hooks/agents/useGetAgent.js +28 -0
- package/dist/hooks/agents/useGetAgent.js.map +1 -0
- package/dist/hooks/agents/useGetAgents.d.ts +19 -0
- package/dist/hooks/agents/useGetAgents.d.ts.map +1 -0
- package/dist/hooks/agents/useGetAgents.js +29 -0
- package/dist/hooks/agents/useGetAgents.js.map +1 -0
- package/dist/hooks/agents/useUpdateAgent.d.ts +18 -0
- package/dist/hooks/agents/useUpdateAgent.d.ts.map +1 -0
- package/dist/hooks/agents/useUpdateAgent.js +25 -0
- package/dist/hooks/agents/useUpdateAgent.js.map +1 -0
- package/dist/hooks/applications/useCreateApplication.d.ts +16 -0
- package/dist/hooks/applications/useCreateApplication.d.ts.map +1 -0
- package/dist/hooks/applications/useCreateApplication.js +29 -0
- package/dist/hooks/applications/useCreateApplication.js.map +1 -0
- package/dist/hooks/applications/useDeleteApplication.d.ts +10 -0
- package/dist/hooks/applications/useDeleteApplication.d.ts.map +1 -0
- package/dist/hooks/applications/useDeleteApplication.js +24 -0
- package/dist/hooks/applications/useDeleteApplication.js.map +1 -0
- package/dist/hooks/applications/useGetApplication.d.ts +17 -0
- package/dist/hooks/applications/useGetApplication.d.ts.map +1 -0
- package/dist/hooks/applications/useGetApplication.js +33 -0
- package/dist/hooks/applications/useGetApplication.js.map +1 -0
- package/dist/hooks/applications/useGetApplications.d.ts +24 -0
- package/dist/hooks/applications/useGetApplications.d.ts.map +1 -0
- package/dist/hooks/applications/useGetApplications.js +34 -0
- package/dist/hooks/applications/useGetApplications.js.map +1 -0
- package/dist/hooks/applications/useUpdateApplication.d.ts +18 -0
- package/dist/hooks/applications/useUpdateApplication.d.ts.map +1 -0
- package/dist/hooks/applications/useUpdateApplication.js +25 -0
- package/dist/hooks/applications/useUpdateApplication.js.map +1 -0
- package/dist/hooks/useManagementEndpoint.d.ts +22 -0
- package/dist/hooks/useManagementEndpoint.d.ts.map +1 -0
- package/dist/hooks/useManagementEndpoint.js +23 -0
- package/dist/hooks/useManagementEndpoint.js.map +1 -0
- package/dist/hooks/useResourceMutation.d.ts +51 -0
- package/dist/hooks/useResourceMutation.d.ts.map +1 -0
- package/dist/hooks/useResourceMutation.js +70 -0
- package/dist/hooks/useResourceMutation.js.map +1 -0
- package/dist/hooks/useResourceQuery.d.ts +45 -0
- package/dist/hooks/useResourceQuery.d.ts.map +1 -0
- package/dist/hooks/useResourceQuery.js +83 -0
- package/dist/hooks/useResourceQuery.js.map +1 -0
- package/dist/hooks/users/useCreateUser.d.ts +11 -0
- package/dist/hooks/users/useCreateUser.d.ts.map +1 -0
- package/dist/hooks/users/useCreateUser.js +24 -0
- package/dist/hooks/users/useCreateUser.js.map +1 -0
- package/dist/hooks/users/useDeleteUser.d.ts +10 -0
- package/dist/hooks/users/useDeleteUser.d.ts.map +1 -0
- package/dist/hooks/users/useDeleteUser.js +24 -0
- package/dist/hooks/users/useDeleteUser.js.map +1 -0
- package/dist/hooks/users/useGetUser.d.ts +12 -0
- package/dist/hooks/users/useGetUser.d.ts.map +1 -0
- package/dist/hooks/users/useGetUser.js +28 -0
- package/dist/hooks/users/useGetUser.js.map +1 -0
- package/dist/hooks/users/useGetUsers.d.ts +17 -0
- package/dist/hooks/users/useGetUsers.d.ts.map +1 -0
- package/dist/hooks/users/useGetUsers.js +36 -0
- package/dist/hooks/users/useGetUsers.js.map +1 -0
- package/dist/hooks/users/useUpdateUser.d.ts +18 -0
- package/dist/hooks/users/useUpdateUser.d.ts.map +1 -0
- package/dist/hooks/users/useUpdateUser.js +25 -0
- package/dist/hooks/users/useUpdateUser.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -2
- package/dist/models/config.d.ts +13 -1
- package/dist/models/config.d.ts.map +1 -1
- package/dist/utils/createAuthenticatedFetcher.d.ts +14 -0
- package/dist/utils/createAuthenticatedFetcher.d.ts.map +1 -0
- package/dist/utils/createAuthenticatedFetcher.js +41 -0
- package/dist/utils/createAuthenticatedFetcher.js.map +1 -0
- package/dist/utils/createResourceInvalidator.d.ts +29 -0
- package/dist/utils/createResourceInvalidator.d.ts.map +1 -0
- package/dist/utils/createResourceInvalidator.js +36 -0
- package/dist/utils/createResourceInvalidator.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { PasswordPolicy, Preferences } from '@thunderid/browser';
|
|
2
|
+
import { FC } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* The values collected by the form and handed to `onSubmit`.
|
|
5
|
+
*
|
|
6
|
+
* There is deliberately no current-value field here. The self-service credential write
|
|
7
|
+
* endpoint does not verify the account's existing value today, so a field the server
|
|
8
|
+
* ignores would only teach the user a false sense of security.
|
|
9
|
+
*/
|
|
10
|
+
export interface ChangePasswordValues {
|
|
11
|
+
/**
|
|
12
|
+
* The value to set.
|
|
13
|
+
*/
|
|
14
|
+
newPassword: string;
|
|
15
|
+
}
|
|
16
|
+
export interface BaseChangeCredentialProps {
|
|
17
|
+
/**
|
|
18
|
+
* Whether to wrap the form in a bordered card.
|
|
19
|
+
*/
|
|
20
|
+
cardLayout?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Additional CSS class names
|
|
23
|
+
*/
|
|
24
|
+
className?: string;
|
|
25
|
+
/**
|
|
26
|
+
* The human-readable name of the credential, substituted into every default label,
|
|
27
|
+
* placeholder and message (for example "Change {credential}", "New {credential}").
|
|
28
|
+
* Defaults to `Password`. {@link ChangeCredential} resolves this from the attribute's own
|
|
29
|
+
* `displayName` in the user schema; set it directly here when using this presentational
|
|
30
|
+
* component without that context.
|
|
31
|
+
*/
|
|
32
|
+
credentialDisplayName?: string;
|
|
33
|
+
/**
|
|
34
|
+
* A form-level error, typically a server failure that maps to no single field.
|
|
35
|
+
*/
|
|
36
|
+
error?: string | null;
|
|
37
|
+
/**
|
|
38
|
+
* Server-supplied errors keyed by field name (`newPassword`).
|
|
39
|
+
*/
|
|
40
|
+
fieldErrors?: Record<string, string>;
|
|
41
|
+
/**
|
|
42
|
+
* Whether a submission is in flight.
|
|
43
|
+
*/
|
|
44
|
+
loading?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Called with the collected values once client-side validation passes.
|
|
47
|
+
*/
|
|
48
|
+
onSubmit?: (values: ChangePasswordValues) => void;
|
|
49
|
+
/**
|
|
50
|
+
* The rules the new value must satisfy. Defaults to no rules, in which case the checklist
|
|
51
|
+
* is empty and the only submit gate is a non-empty value; the caller is expected to source
|
|
52
|
+
* this from the user type schema (see {@link ChangeCredential}) or supply its own.
|
|
53
|
+
*/
|
|
54
|
+
policy?: PasswordPolicy;
|
|
55
|
+
/**
|
|
56
|
+
* Component-level preference overrides, including i18n.
|
|
57
|
+
*/
|
|
58
|
+
preferences?: Preferences;
|
|
59
|
+
/**
|
|
60
|
+
* Whether to render the live requirement checklist. Defaults to `true`.
|
|
61
|
+
*/
|
|
62
|
+
showRequirements?: boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Whether the last submission succeeded.
|
|
65
|
+
*/
|
|
66
|
+
success?: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Overrides the default "Change {credential}" heading. Pass an empty string to omit the
|
|
69
|
+
* heading entirely, for example when an app's own surrounding layout (a card header, a
|
|
70
|
+
* dialog title) already names the credential and a second heading would be redundant.
|
|
71
|
+
* Defaults to the translated `user.change_password.heading` string.
|
|
72
|
+
*/
|
|
73
|
+
title?: string;
|
|
74
|
+
/**
|
|
75
|
+
* Whether the account cannot have this credential changed at all, because the user type's
|
|
76
|
+
* schema defines no attribute of this name. The form is rendered inert behind an
|
|
77
|
+
* explanatory message rather than hidden, so an integrator who placed the component can see
|
|
78
|
+
* why it is not usable instead of finding an empty space.
|
|
79
|
+
*/
|
|
80
|
+
unavailable?: boolean;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Presentational change-credential form with just the two fields a first-time or
|
|
84
|
+
* unverified credential change needs: new value and confirmation.
|
|
85
|
+
*
|
|
86
|
+
* Holds no context and performs no network calls: it renders the fields, evaluates the
|
|
87
|
+
* policy for the checklist and the submit gate, and hands validated values to `onSubmit`.
|
|
88
|
+
* Use {@link ChangeCredential} for the context-wired variant.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```tsx
|
|
92
|
+
* <BaseChangeCredential
|
|
93
|
+
* policy={{regex: '^.{12,}$'}}
|
|
94
|
+
* onSubmit={({newPassword}) => save(newPassword)}
|
|
95
|
+
* />
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
declare const BaseChangeCredential: FC<BaseChangeCredentialProps>;
|
|
99
|
+
export default BaseChangeCredential;
|
|
100
|
+
//# sourceMappingURL=BaseChangeCredential.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseChangeCredential.d.ts","sourceRoot":"","sources":["../../../../src/components/presentation/ChangeCredential/BaseChangeCredential.tsx"],"names":[],"mappings":"AAGA,OAAO,EAEL,cAAc,EAEd,WAAW,EAIZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,EAAE,EAA6C,MAAM,OAAO,CAAC;AAYrE;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACxC;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAClD;;;;OAIG;IACH,MAAM,CAAC,EAAE,cAAc,CAAC;IACxB;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;OAEG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAsOvD,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { cx } from "../../../styles/emotion.js";
|
|
2
|
+
import useTheme_default from "../../../contexts/Theme/useTheme.js";
|
|
3
|
+
import useTranslation_default from "../../../hooks/useTranslation.js";
|
|
4
|
+
import Button_default from "../../primitives/Button/Button.js";
|
|
5
|
+
import Typography_default from "../../primitives/Typography/Typography.js";
|
|
6
|
+
import Alert_default from "../../primitives/Alert/Alert.js";
|
|
7
|
+
import X_default from "../../primitives/Icons/X.js";
|
|
8
|
+
import PasswordField_default from "../../primitives/PasswordField/PasswordField.js";
|
|
9
|
+
import BaseChangeCredential_styles_default from "./BaseChangeCredential.styles.js";
|
|
10
|
+
import Check_default from "../../primitives/Icons/Check.js";
|
|
11
|
+
import { bem, evaluateChangePasswordForm, withVendorCSSClassPrefix } from "@thunderid/browser";
|
|
12
|
+
import { useMemo, useState } from "react";
|
|
13
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
+
|
|
15
|
+
//#region src/components/presentation/ChangeCredential/BaseChangeCredential.tsx
|
|
16
|
+
/**
|
|
17
|
+
* Presentational change-credential form with just the two fields a first-time or
|
|
18
|
+
* unverified credential change needs: new value and confirmation.
|
|
19
|
+
*
|
|
20
|
+
* Holds no context and performs no network calls: it renders the fields, evaluates the
|
|
21
|
+
* policy for the checklist and the submit gate, and hands validated values to `onSubmit`.
|
|
22
|
+
* Use {@link ChangeCredential} for the context-wired variant.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <BaseChangeCredential
|
|
27
|
+
* policy={{regex: '^.{12,}$'}}
|
|
28
|
+
* onSubmit={({newPassword}) => save(newPassword)}
|
|
29
|
+
* />
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
const BaseChangeCredential = ({ cardLayout = false, className = "", credentialDisplayName = "Password", error = null, fieldErrors = {}, loading = false, onSubmit = void 0, policy = {}, preferences = void 0, showRequirements = true, success = false, title = void 0, unavailable = false }) => {
|
|
33
|
+
const { theme, colorScheme } = useTheme_default();
|
|
34
|
+
const styles = BaseChangeCredential_styles_default(theme, colorScheme);
|
|
35
|
+
const { t } = useTranslation_default(preferences?.i18n);
|
|
36
|
+
const labelParams = {
|
|
37
|
+
credential: credentialDisplayName,
|
|
38
|
+
credentialLower: credentialDisplayName.toLowerCase()
|
|
39
|
+
};
|
|
40
|
+
const resolvedTitle = title ?? t("user.change_password.heading", labelParams);
|
|
41
|
+
const [newPassword, setNewPassword] = useState("");
|
|
42
|
+
const [confirmPassword, setConfirmPassword] = useState("");
|
|
43
|
+
const [submitted, setSubmitted] = useState(false);
|
|
44
|
+
const [prevSuccess, setPrevSuccess] = useState(success);
|
|
45
|
+
if (success !== prevSuccess) {
|
|
46
|
+
setPrevSuccess(success);
|
|
47
|
+
if (success) {
|
|
48
|
+
setNewPassword("");
|
|
49
|
+
setConfirmPassword("");
|
|
50
|
+
setSubmitted(false);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const { confirmMatches, isValid, ruleResults } = useMemo(() => evaluateChangePasswordForm({
|
|
54
|
+
confirmPassword,
|
|
55
|
+
newPassword
|
|
56
|
+
}, policy), [
|
|
57
|
+
confirmPassword,
|
|
58
|
+
newPassword,
|
|
59
|
+
policy
|
|
60
|
+
]);
|
|
61
|
+
const interactionDisabled = loading || unavailable;
|
|
62
|
+
const canSubmit = !interactionDisabled && isValid;
|
|
63
|
+
const handleSubmit = (event) => {
|
|
64
|
+
event.preventDefault();
|
|
65
|
+
setSubmitted(true);
|
|
66
|
+
if (!canSubmit) return;
|
|
67
|
+
onSubmit?.({ newPassword });
|
|
68
|
+
};
|
|
69
|
+
const renderRequirement = (rule) => /* @__PURE__ */ jsxs("li", {
|
|
70
|
+
"data-passed": rule.passed,
|
|
71
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "requirement")), styles["requirement"], rule.passed ? styles["requirementPassed"] : styles["requirementPending"]),
|
|
72
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
73
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "requirement-icon")), styles["requirementIcon"]),
|
|
74
|
+
children: rule.passed ? /* @__PURE__ */ jsx(Check_default, {
|
|
75
|
+
width: 14,
|
|
76
|
+
height: 14
|
|
77
|
+
}) : /* @__PURE__ */ jsx(X_default, {
|
|
78
|
+
width: 14,
|
|
79
|
+
height: 14
|
|
80
|
+
})
|
|
81
|
+
}), /* @__PURE__ */ jsx(Typography_default, {
|
|
82
|
+
variant: "body2",
|
|
83
|
+
component: "span",
|
|
84
|
+
children: t(rule.messageKey, rule.params)
|
|
85
|
+
})]
|
|
86
|
+
}, rule.key);
|
|
87
|
+
const confirmError = submitted && !confirmMatches ? t("user.change_password.mismatch.error", labelParams) : void 0;
|
|
88
|
+
const newPasswordError = fieldErrors["newPassword"];
|
|
89
|
+
const form = /* @__PURE__ */ jsxs("form", {
|
|
90
|
+
noValidate: true,
|
|
91
|
+
onSubmit: handleSubmit,
|
|
92
|
+
className: cx(withVendorCSSClassPrefix("change-credential"), styles["root"], cardLayout ? styles["card"] : "", className),
|
|
93
|
+
children: [
|
|
94
|
+
resolvedTitle && /* @__PURE__ */ jsx(Typography_default, {
|
|
95
|
+
variant: "h5",
|
|
96
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "heading")), styles["heading"]),
|
|
97
|
+
children: resolvedTitle
|
|
98
|
+
}),
|
|
99
|
+
error && /* @__PURE__ */ jsxs(Alert_default, {
|
|
100
|
+
variant: "error",
|
|
101
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "alert")), styles["alert"]),
|
|
102
|
+
children: [/* @__PURE__ */ jsx(Alert_default.Title, { children: t("errors.heading") || "Error" }), /* @__PURE__ */ jsx(Alert_default.Description, { children: error })]
|
|
103
|
+
}),
|
|
104
|
+
success && /* @__PURE__ */ jsx(Alert_default, {
|
|
105
|
+
variant: "success",
|
|
106
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "alert")), styles["alert"]),
|
|
107
|
+
children: /* @__PURE__ */ jsx(Alert_default.Description, { children: t("user.change_password.success", labelParams) })
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ jsxs("div", {
|
|
110
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "fields")), styles["fields"]),
|
|
111
|
+
children: [
|
|
112
|
+
/* @__PURE__ */ jsx(PasswordField_default, {
|
|
113
|
+
name: "newPassword",
|
|
114
|
+
autoComplete: "new-password",
|
|
115
|
+
label: t("user.change_password.new.label", labelParams),
|
|
116
|
+
placeholder: t("user.change_password.new.placeholder", labelParams),
|
|
117
|
+
value: newPassword,
|
|
118
|
+
onChange: setNewPassword,
|
|
119
|
+
disabled: interactionDisabled,
|
|
120
|
+
error: newPasswordError,
|
|
121
|
+
required: true
|
|
122
|
+
}),
|
|
123
|
+
showRequirements && ruleResults.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
124
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "requirements"))),
|
|
125
|
+
children: [/* @__PURE__ */ jsx(Typography_default, {
|
|
126
|
+
variant: "body2",
|
|
127
|
+
component: "p",
|
|
128
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "requirements-heading")), styles["requirementsHeading"]),
|
|
129
|
+
children: t("user.change_password.requirements.heading", labelParams)
|
|
130
|
+
}), /* @__PURE__ */ jsx("ul", {
|
|
131
|
+
className: styles["requirements"],
|
|
132
|
+
children: ruleResults.map(renderRequirement)
|
|
133
|
+
})]
|
|
134
|
+
}),
|
|
135
|
+
/* @__PURE__ */ jsx(PasswordField_default, {
|
|
136
|
+
name: "confirmPassword",
|
|
137
|
+
autoComplete: "new-password",
|
|
138
|
+
label: t("user.change_password.confirm.label", labelParams),
|
|
139
|
+
placeholder: t("user.change_password.confirm.placeholder", labelParams),
|
|
140
|
+
value: confirmPassword,
|
|
141
|
+
onChange: setConfirmPassword,
|
|
142
|
+
disabled: interactionDisabled,
|
|
143
|
+
error: confirmError,
|
|
144
|
+
required: true
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
}),
|
|
148
|
+
/* @__PURE__ */ jsx("div", {
|
|
149
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "actions")), styles["actions"]),
|
|
150
|
+
children: /* @__PURE__ */ jsx(Button_default, {
|
|
151
|
+
type: "submit",
|
|
152
|
+
color: "primary",
|
|
153
|
+
variant: "solid",
|
|
154
|
+
loading,
|
|
155
|
+
disabled: !canSubmit,
|
|
156
|
+
children: t("user.change_password.submit", labelParams)
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
]
|
|
160
|
+
});
|
|
161
|
+
if (!unavailable) return form;
|
|
162
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
163
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "unavailable")), styles["unavailableRoot"], className),
|
|
164
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
165
|
+
"aria-hidden": "true",
|
|
166
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "unavailable-content")), styles["unavailableContent"]),
|
|
167
|
+
children: form
|
|
168
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
169
|
+
role: "status",
|
|
170
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "unavailable-overlay")), styles["unavailableOverlay"]),
|
|
171
|
+
children: /* @__PURE__ */ jsxs(Alert_default, {
|
|
172
|
+
variant: "warning",
|
|
173
|
+
className: cx(withVendorCSSClassPrefix(bem("change-credential", "alert")), styles["alert"]),
|
|
174
|
+
children: [/* @__PURE__ */ jsx(Alert_default.Title, { children: t("user.change_password.unavailable.heading", labelParams) }), /* @__PURE__ */ jsx(Alert_default.Description, { children: t("user.change_password.unavailable.description", labelParams) })]
|
|
175
|
+
})
|
|
176
|
+
})]
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
var BaseChangeCredential_default = BaseChangeCredential;
|
|
180
|
+
|
|
181
|
+
//#endregion
|
|
182
|
+
export { BaseChangeCredential_default as default };
|
|
183
|
+
//# sourceMappingURL=BaseChangeCredential.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseChangeCredential.js","names":["BaseChangeCredential: FC<BaseChangeCredentialProps>","useTheme","styles: Record<string, string>","useStyles","useTranslation","labelParams: Record<string, string>","resolvedTitle: string","interactionDisabled: boolean","canSubmit: boolean","Check","X","Typography","confirmError: string | undefined","newPasswordError: string | undefined","form: ReactElement","AlertPrimitive","PasswordField","Button"],"sources":["../../../../src/components/presentation/ChangeCredential/BaseChangeCredential.tsx"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {\n ChangePasswordFormEvaluation,\n PasswordPolicy,\n PasswordRuleResult,\n Preferences,\n bem,\n evaluateChangePasswordForm,\n withVendorCSSClassPrefix,\n} from '@thunderid/browser';\nimport {FC, FormEvent, ReactElement, useMemo, useState} from 'react';\nimport useStyles from './BaseChangeCredential.styles';\nimport useTheme from '../../../contexts/Theme/useTheme';\nimport useTranslation from '../../../hooks/useTranslation';\nimport {cx} from '../../../styles/emotion';\nimport AlertPrimitive from '../../primitives/Alert/Alert';\nimport Button from '../../primitives/Button/Button';\nimport Check from '../../primitives/Icons/Check';\nimport X from '../../primitives/Icons/X';\nimport PasswordField from '../../primitives/PasswordField/PasswordField';\nimport Typography from '../../primitives/Typography/Typography';\n\n/**\n * The values collected by the form and handed to `onSubmit`.\n *\n * There is deliberately no current-value field here. The self-service credential write\n * endpoint does not verify the account's existing value today, so a field the server\n * ignores would only teach the user a false sense of security.\n */\nexport interface ChangePasswordValues {\n /**\n * The value to set.\n */\n newPassword: string;\n}\n\nexport interface BaseChangeCredentialProps {\n /**\n * Whether to wrap the form in a bordered card.\n */\n cardLayout?: boolean;\n /**\n * Additional CSS class names\n */\n className?: string;\n /**\n * The human-readable name of the credential, substituted into every default label,\n * placeholder and message (for example \"Change {credential}\", \"New {credential}\").\n * Defaults to `Password`. {@link ChangeCredential} resolves this from the attribute's own\n * `displayName` in the user schema; set it directly here when using this presentational\n * component without that context.\n */\n credentialDisplayName?: string;\n /**\n * A form-level error, typically a server failure that maps to no single field.\n */\n error?: string | null;\n /**\n * Server-supplied errors keyed by field name (`newPassword`).\n */\n fieldErrors?: Record<string, string>;\n /**\n * Whether a submission is in flight.\n */\n loading?: boolean;\n /**\n * Called with the collected values once client-side validation passes.\n */\n onSubmit?: (values: ChangePasswordValues) => void;\n /**\n * The rules the new value must satisfy. Defaults to no rules, in which case the checklist\n * is empty and the only submit gate is a non-empty value; the caller is expected to source\n * this from the user type schema (see {@link ChangeCredential}) or supply its own.\n */\n policy?: PasswordPolicy;\n /**\n * Component-level preference overrides, including i18n.\n */\n preferences?: Preferences;\n /**\n * Whether to render the live requirement checklist. Defaults to `true`.\n */\n showRequirements?: boolean;\n /**\n * Whether the last submission succeeded.\n */\n success?: boolean;\n /**\n * Overrides the default \"Change {credential}\" heading. Pass an empty string to omit the\n * heading entirely, for example when an app's own surrounding layout (a card header, a\n * dialog title) already names the credential and a second heading would be redundant.\n * Defaults to the translated `user.change_password.heading` string.\n */\n title?: string;\n /**\n * Whether the account cannot have this credential changed at all, because the user type's\n * schema defines no attribute of this name. The form is rendered inert behind an\n * explanatory message rather than hidden, so an integrator who placed the component can see\n * why it is not usable instead of finding an empty space.\n */\n unavailable?: boolean;\n}\n\n/**\n * Presentational change-credential form with just the two fields a first-time or\n * unverified credential change needs: new value and confirmation.\n *\n * Holds no context and performs no network calls: it renders the fields, evaluates the\n * policy for the checklist and the submit gate, and hands validated values to `onSubmit`.\n * Use {@link ChangeCredential} for the context-wired variant.\n *\n * @example\n * ```tsx\n * <BaseChangeCredential\n * policy={{regex: '^.{12,}$'}}\n * onSubmit={({newPassword}) => save(newPassword)}\n * />\n * ```\n */\nconst BaseChangeCredential: FC<BaseChangeCredentialProps> = ({\n cardLayout = false,\n className = '',\n credentialDisplayName = 'Password',\n error = null,\n fieldErrors = {},\n loading = false,\n onSubmit = undefined,\n policy = {},\n preferences = undefined,\n showRequirements = true,\n success = false,\n title = undefined,\n unavailable = false,\n}: BaseChangeCredentialProps) => {\n const {theme, colorScheme}: ReturnType<typeof useTheme> = useTheme();\n const styles: Record<string, string> = useStyles(theme, colorScheme);\n const {t} = useTranslation(preferences?.i18n);\n\n // Substituted into every default label, placeholder and message. A caller-supplied\n // translation that carries no `{credential}`/`{credentialLower}` placeholder is unaffected.\n const labelParams: Record<string, string> = {\n credential: credentialDisplayName,\n credentialLower: credentialDisplayName.toLowerCase(),\n };\n\n // `title` overrides the default heading; an explicit empty string omits it entirely.\n const resolvedTitle: string = title ?? t('user.change_password.heading', labelParams);\n\n const [newPassword, setNewPassword] = useState<string>('');\n const [confirmPassword, setConfirmPassword] = useState<string>('');\n const [submitted, setSubmitted] = useState<boolean>(false);\n\n // Clear the entered values once the container reports the write succeeded, so a shared\n // machine is not left with the new credential sitting in the form. Adjusting state during\n // render (rather than in an effect) is React's documented way to reset on a prop change and\n // avoids the extra commit an effect would cause.\n const [prevSuccess, setPrevSuccess] = useState<boolean>(success);\n\n if (success !== prevSuccess) {\n setPrevSuccess(success);\n\n if (success) {\n setNewPassword('');\n setConfirmPassword('');\n setSubmitted(false);\n }\n }\n\n const {confirmMatches, isValid, ruleResults}: ChangePasswordFormEvaluation = useMemo(\n () => evaluateChangePasswordForm({confirmPassword, newPassword}, policy),\n [confirmPassword, newPassword, policy],\n );\n\n // A schema with no attribute of this name makes every control pointless, so they are\n // disabled outright rather than left focusable behind the overlay.\n const interactionDisabled: boolean = loading || unavailable;\n const canSubmit: boolean = !interactionDisabled && isValid;\n\n const handleSubmit = (event: FormEvent<HTMLFormElement>): void => {\n event.preventDefault();\n setSubmitted(true);\n\n if (!canSubmit) {\n return;\n }\n\n onSubmit?.({newPassword});\n };\n\n const renderRequirement = (rule: PasswordRuleResult): ReactElement => (\n <li\n key={rule.key}\n data-passed={rule.passed}\n className={cx(\n withVendorCSSClassPrefix(bem('change-credential', 'requirement')),\n styles['requirement'],\n rule.passed ? styles['requirementPassed'] : styles['requirementPending'],\n )}\n >\n <span\n className={cx(\n withVendorCSSClassPrefix(bem('change-credential', 'requirement-icon')),\n styles['requirementIcon'],\n )}\n >\n {rule.passed ? <Check width={14} height={14} /> : <X width={14} height={14} />}\n </span>\n <Typography variant=\"body2\" component=\"span\">\n {t(rule.messageKey, rule.params)}\n </Typography>\n </li>\n );\n\n // Only surface the local error once the user has attempted a submit, so the form does\n // not flag fields the user has not finished filling in.\n const confirmError: string | undefined =\n submitted && !confirmMatches ? t('user.change_password.mismatch.error', labelParams) : undefined;\n const newPasswordError: string | undefined = fieldErrors['newPassword'];\n\n const form: ReactElement = (\n <form\n noValidate\n onSubmit={handleSubmit}\n className={cx(\n withVendorCSSClassPrefix('change-credential'),\n styles['root'],\n cardLayout ? styles['card'] : '',\n className,\n )}\n >\n {resolvedTitle && (\n <Typography\n variant=\"h5\"\n className={cx(withVendorCSSClassPrefix(bem('change-credential', 'heading')), styles['heading'])}\n >\n {resolvedTitle}\n </Typography>\n )}\n\n {error && (\n <AlertPrimitive\n variant=\"error\"\n className={cx(withVendorCSSClassPrefix(bem('change-credential', 'alert')), styles['alert'])}\n >\n <AlertPrimitive.Title>{t('errors.heading') || 'Error'}</AlertPrimitive.Title>\n <AlertPrimitive.Description>{error}</AlertPrimitive.Description>\n </AlertPrimitive>\n )}\n\n {success && (\n <AlertPrimitive\n variant=\"success\"\n className={cx(withVendorCSSClassPrefix(bem('change-credential', 'alert')), styles['alert'])}\n >\n <AlertPrimitive.Description>{t('user.change_password.success', labelParams)}</AlertPrimitive.Description>\n </AlertPrimitive>\n )}\n\n <div className={cx(withVendorCSSClassPrefix(bem('change-credential', 'fields')), styles['fields'])}>\n <PasswordField\n name=\"newPassword\"\n autoComplete=\"new-password\"\n label={t('user.change_password.new.label', labelParams)}\n placeholder={t('user.change_password.new.placeholder', labelParams)}\n value={newPassword}\n onChange={setNewPassword}\n disabled={interactionDisabled}\n error={newPasswordError}\n required\n />\n\n {showRequirements && ruleResults.length > 0 && (\n <div className={cx(withVendorCSSClassPrefix(bem('change-credential', 'requirements')))}>\n <Typography\n variant=\"body2\"\n component=\"p\"\n className={cx(\n withVendorCSSClassPrefix(bem('change-credential', 'requirements-heading')),\n styles['requirementsHeading'],\n )}\n >\n {t('user.change_password.requirements.heading', labelParams)}\n </Typography>\n <ul className={styles['requirements']}>{ruleResults.map(renderRequirement)}</ul>\n </div>\n )}\n\n <PasswordField\n name=\"confirmPassword\"\n autoComplete=\"new-password\"\n label={t('user.change_password.confirm.label', labelParams)}\n placeholder={t('user.change_password.confirm.placeholder', labelParams)}\n value={confirmPassword}\n onChange={setConfirmPassword}\n disabled={interactionDisabled}\n error={confirmError}\n required\n />\n </div>\n\n <div className={cx(withVendorCSSClassPrefix(bem('change-credential', 'actions')), styles['actions'])}>\n <Button type=\"submit\" color=\"primary\" variant=\"solid\" loading={loading} disabled={!canSubmit}>\n {t('user.change_password.submit', labelParams)}\n </Button>\n </div>\n </form>\n );\n\n if (!unavailable) {\n return form;\n }\n\n return (\n <div\n className={cx(\n withVendorCSSClassPrefix(bem('change-credential', 'unavailable')),\n styles['unavailableRoot'],\n className,\n )}\n >\n <div\n aria-hidden=\"true\"\n className={cx(\n withVendorCSSClassPrefix(bem('change-credential', 'unavailable-content')),\n styles['unavailableContent'],\n )}\n >\n {form}\n </div>\n\n <div\n role=\"status\"\n className={cx(\n withVendorCSSClassPrefix(bem('change-credential', 'unavailable-overlay')),\n styles['unavailableOverlay'],\n )}\n >\n <AlertPrimitive\n variant=\"warning\"\n className={cx(withVendorCSSClassPrefix(bem('change-credential', 'alert')), styles['alert'])}\n >\n <AlertPrimitive.Title>{t('user.change_password.unavailable.heading', labelParams)}</AlertPrimitive.Title>\n <AlertPrimitive.Description>\n {t('user.change_password.unavailable.description', labelParams)}\n </AlertPrimitive.Description>\n </AlertPrimitive>\n </div>\n </div>\n );\n};\n\nexport default BaseChangeCredential;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Theme } from '@thunderid/browser';
|
|
2
|
+
/**
|
|
3
|
+
* Creates styles for the BaseChangeCredential 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
|
+
declare const useStyles: (theme: Theme, colorScheme: string) => Record<string, string>;
|
|
9
|
+
export default useStyles;
|
|
10
|
+
//# sourceMappingURL=BaseChangeCredential.styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseChangeCredential.styles.d.ts","sourceRoot":"","sources":["../../../../src/components/presentation/ChangeCredential/BaseChangeCredential.styles.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,KAAK,EAAC,MAAM,oBAAoB,CAAC;AAGzC;;;;;GAKG;AACH,QAAA,MAAM,SAAS,GAAI,OAAO,KAAK,EAAE,aAAa,MAAM,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CA8G3E,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { css } from "../../../styles/emotion.js";
|
|
2
|
+
|
|
3
|
+
//#region src/components/presentation/ChangeCredential/BaseChangeCredential.styles.ts
|
|
4
|
+
/**
|
|
5
|
+
* Creates styles for the BaseChangeCredential component
|
|
6
|
+
* @param theme - The theme object containing design tokens
|
|
7
|
+
* @param colorScheme - The current color scheme (used for memoization)
|
|
8
|
+
* @returns Object containing CSS class names for component styling
|
|
9
|
+
*/
|
|
10
|
+
const useStyles = (theme, colorScheme) => {
|
|
11
|
+
const root = css`
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
gap: calc(${theme.vars.spacing.unit} * 2);
|
|
15
|
+
width: 100%;
|
|
16
|
+
`;
|
|
17
|
+
const card = css`
|
|
18
|
+
padding: calc(${theme.vars.spacing.unit} * 3);
|
|
19
|
+
border: 1px solid ${theme.vars.colors.border};
|
|
20
|
+
border-radius: ${theme.vars.borderRadius.large};
|
|
21
|
+
`;
|
|
22
|
+
const heading = css`
|
|
23
|
+
margin: 0;
|
|
24
|
+
`;
|
|
25
|
+
const fields = css`
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
gap: calc(${theme.vars.spacing.unit} * 2);
|
|
29
|
+
`;
|
|
30
|
+
const requirements = css`
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
gap: calc(${theme.vars.spacing.unit} / 2);
|
|
34
|
+
margin: 0;
|
|
35
|
+
padding: 0;
|
|
36
|
+
list-style: none;
|
|
37
|
+
`;
|
|
38
|
+
const requirementsHeading = css`
|
|
39
|
+
margin: 0 0 calc(${theme.vars.spacing.unit} / 2) 0;
|
|
40
|
+
opacity: 0.8;
|
|
41
|
+
`;
|
|
42
|
+
const requirement = css`
|
|
43
|
+
display: flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
gap: ${theme.vars.spacing.unit};
|
|
46
|
+
`;
|
|
47
|
+
const requirementPassed = css`
|
|
48
|
+
color: ${theme.vars.colors.success.main};
|
|
49
|
+
`;
|
|
50
|
+
const requirementPending = css`
|
|
51
|
+
opacity: 0.7;
|
|
52
|
+
`;
|
|
53
|
+
const requirementIcon = css`
|
|
54
|
+
flex-shrink: 0;
|
|
55
|
+
width: 14px;
|
|
56
|
+
height: 14px;
|
|
57
|
+
`;
|
|
58
|
+
const alert = css`
|
|
59
|
+
width: 100%;
|
|
60
|
+
`;
|
|
61
|
+
const actions = css`
|
|
62
|
+
display: flex;
|
|
63
|
+
gap: ${theme.vars.spacing.unit};
|
|
64
|
+
align-items: center;
|
|
65
|
+
justify-content: flex-end;
|
|
66
|
+
`;
|
|
67
|
+
const unavailableRoot = css`
|
|
68
|
+
position: relative;
|
|
69
|
+
display: flex;
|
|
70
|
+
width: 100%;
|
|
71
|
+
`;
|
|
72
|
+
return {
|
|
73
|
+
actions,
|
|
74
|
+
alert,
|
|
75
|
+
card,
|
|
76
|
+
colorScheme,
|
|
77
|
+
fields,
|
|
78
|
+
heading,
|
|
79
|
+
requirement,
|
|
80
|
+
requirementIcon,
|
|
81
|
+
requirementPassed,
|
|
82
|
+
requirementPending,
|
|
83
|
+
requirements,
|
|
84
|
+
requirementsHeading,
|
|
85
|
+
root,
|
|
86
|
+
unavailableContent: css`
|
|
87
|
+
width: 100%;
|
|
88
|
+
filter: blur(3px);
|
|
89
|
+
opacity: 0.55;
|
|
90
|
+
pointer-events: none;
|
|
91
|
+
user-select: none;
|
|
92
|
+
`,
|
|
93
|
+
unavailableOverlay: css`
|
|
94
|
+
position: absolute;
|
|
95
|
+
inset: 0;
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
padding: calc(${theme.vars.spacing.unit} * 2);
|
|
100
|
+
`,
|
|
101
|
+
unavailableRoot
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
var BaseChangeCredential_styles_default = useStyles;
|
|
105
|
+
|
|
106
|
+
//#endregion
|
|
107
|
+
export { BaseChangeCredential_styles_default as default };
|
|
108
|
+
//# sourceMappingURL=BaseChangeCredential.styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BaseChangeCredential.styles.js","names":["root: string","card: string","heading: string","fields: string","requirements: string","requirementsHeading: string","requirement: string","requirementPassed: string","requirementPending: string","requirementIcon: string","alert: string","actions: string","unavailableRoot: string"],"sources":["../../../../src/components/presentation/ChangeCredential/BaseChangeCredential.styles.ts"],"sourcesContent":["// Copyright 2026 The ThunderID Authors\n// SPDX-License-Identifier: Apache-2.0\n\nimport {Theme} from '@thunderid/browser';\nimport {css} from '../../../styles/emotion';\n\n/**\n * Creates styles for the BaseChangeCredential 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 */\nconst useStyles = (theme: Theme, colorScheme: string): Record<string, string> => {\n const root: string = css`\n display: flex;\n flex-direction: column;\n gap: calc(${theme.vars.spacing.unit} * 2);\n width: 100%;\n `;\n\n const card: string = css`\n padding: calc(${theme.vars.spacing.unit} * 3);\n border: 1px solid ${theme.vars.colors.border};\n border-radius: ${theme.vars.borderRadius.large};\n `;\n\n const heading: string = css`\n margin: 0;\n `;\n\n const fields: string = css`\n display: flex;\n flex-direction: column;\n gap: calc(${theme.vars.spacing.unit} * 2);\n `;\n\n const requirements: string = css`\n display: flex;\n flex-direction: column;\n gap: calc(${theme.vars.spacing.unit} / 2);\n margin: 0;\n padding: 0;\n list-style: none;\n `;\n\n const requirementsHeading: string = css`\n margin: 0 0 calc(${theme.vars.spacing.unit} / 2) 0;\n opacity: 0.8;\n `;\n\n const requirement: string = css`\n display: flex;\n align-items: center;\n gap: ${theme.vars.spacing.unit};\n `;\n\n const requirementPassed: string = css`\n color: ${theme.vars.colors.success.main};\n `;\n\n const requirementPending: string = css`\n opacity: 0.7;\n `;\n\n const requirementIcon: string = css`\n flex-shrink: 0;\n width: 14px;\n height: 14px;\n `;\n\n const alert: string = css`\n width: 100%;\n `;\n\n const actions: string = css`\n display: flex;\n gap: ${theme.vars.spacing.unit};\n align-items: center;\n justify-content: flex-end;\n `;\n\n const unavailableRoot: string = css`\n position: relative;\n display: flex;\n width: 100%;\n `;\n\n const unavailableContent: string = css`\n width: 100%;\n filter: blur(3px);\n opacity: 0.55;\n pointer-events: none;\n user-select: none;\n `;\n\n const unavailableOverlay: string = css`\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: calc(${theme.vars.spacing.unit} * 2);\n `;\n\n return {\n actions,\n alert,\n card,\n colorScheme,\n fields,\n heading,\n requirement,\n requirementIcon,\n requirementPassed,\n requirementPending,\n requirements,\n requirementsHeading,\n root,\n unavailableContent,\n unavailableOverlay,\n unavailableRoot,\n };\n};\n\nexport default useStyles;\n"],"mappings":";;;;;;;;;AAYA,MAAM,aAAa,OAAc,gBAAgD;CAC/E,MAAMA,OAAe,GAAG;;;gBAGV,MAAM,KAAK,QAAQ,KAAK;;;CAItC,MAAMC,OAAe,GAAG;oBACN,MAAM,KAAK,QAAQ,KAAK;wBACpB,MAAM,KAAK,OAAO,OAAO;qBAC5B,MAAM,KAAK,aAAa,MAAM;;CAGjD,MAAMC,UAAkB,GAAG;;;CAI3B,MAAMC,SAAiB,GAAG;;;gBAGZ,MAAM,KAAK,QAAQ,KAAK;;CAGtC,MAAMC,eAAuB,GAAG;;;gBAGlB,MAAM,KAAK,QAAQ,KAAK;;;;;CAMtC,MAAMC,sBAA8B,GAAG;uBAClB,MAAM,KAAK,QAAQ,KAAK;;;CAI7C,MAAMC,cAAsB,GAAG;;;WAGtB,MAAM,KAAK,QAAQ,KAAK;;CAGjC,MAAMC,oBAA4B,GAAG;aAC1B,MAAM,KAAK,OAAO,QAAQ,KAAK;;CAG1C,MAAMC,qBAA6B,GAAG;;;CAItC,MAAMC,kBAA0B,GAAG;;;;;CAMnC,MAAMC,QAAgB,GAAG;;;CAIzB,MAAMC,UAAkB,GAAG;;WAElB,MAAM,KAAK,QAAQ,KAAK;;;;CAKjC,MAAMC,kBAA0B,GAAG;;;;;AAuBnC,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,oBA/BiC,GAAG;;;;;;;EAgCpC,oBAxBiC,GAAG;;;;;;oBAMpB,MAAM,KAAK,QAAQ,KAAK;;EAmBxC;EACD;;AAGH,0CAAe"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
import { BaseChangeCredentialProps } from './BaseChangeCredential';
|
|
3
|
+
export interface ChangeCredentialProps extends Omit<BaseChangeCredentialProps, 'credentialDisplayName' | 'error' | 'fieldErrors' | 'loading' | 'onSubmit' | 'success'> {
|
|
4
|
+
/**
|
|
5
|
+
* The credential attribute this instance manages, any attribute the user's entity type
|
|
6
|
+
* schema declares `credential: true` (for example `password` or `pin`). Defaults to
|
|
7
|
+
* `password`. Render the component once per credential to let a user manage more than one,
|
|
8
|
+
* for example `<ChangeCredential />` for the password and
|
|
9
|
+
* `<ChangeCredential attribute="pin" />` for a PIN.
|
|
10
|
+
*/
|
|
11
|
+
attribute?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Called after the credential has been changed successfully.
|
|
14
|
+
*/
|
|
15
|
+
onSuccess?: () => void;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* ChangeCredential lets the signed-in user set a new value for one of their own credentials.
|
|
19
|
+
*
|
|
20
|
+
* It collects only a new value and its confirmation. The self-service credential write path
|
|
21
|
+
* does not verify the account's existing value today, so this component does not ask for one;
|
|
22
|
+
* once server-side current-value verification ships, that field returns without a breaking
|
|
23
|
+
* change to this component's public props.
|
|
24
|
+
*
|
|
25
|
+
* It reads the applicable rules from the user schema already resolved by the ThunderID
|
|
26
|
+
* provider, so it adds no network request beyond the write itself, and posts to
|
|
27
|
+
* `/users/me/update-credentials` with the access token attached by the SDK's HTTP client.
|
|
28
|
+
*
|
|
29
|
+
* Defaults to managing the `password` credential. To manage a different one (for example a
|
|
30
|
+
* PIN declared on the user type schema), set `attribute`; render the component once per
|
|
31
|
+
* credential to let a user manage several. Every default label, placeholder and message is
|
|
32
|
+
* built from the attribute's own `displayName` in the schema (`GET /users/me/meta`), so it
|
|
33
|
+
* always matches whatever an admin named the attribute there; when the schema carries no
|
|
34
|
+
* `displayName` for it, it falls back to the attribute name title-cased (`pin` -> `Pin`).
|
|
35
|
+
* Override individual strings via `preferences.i18n` for full control (including other
|
|
36
|
+
* languages) if the schema-derived name isn't the right fit.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* // Basic usage, manages the password
|
|
41
|
+
* <ChangeCredential onSuccess={() => toast('Password updated')} />
|
|
42
|
+
*
|
|
43
|
+
* // With an explicit rule instead of the schema-derived policy
|
|
44
|
+
* <ChangeCredential
|
|
45
|
+
* policy={{regex: '^.{12,}$'}}
|
|
46
|
+
* />
|
|
47
|
+
*
|
|
48
|
+
* // Managing a different credential declared on the schema; labels use the schema's own
|
|
49
|
+
* // displayName for it automatically
|
|
50
|
+
* <ChangeCredential attribute="pin" />
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
declare const ChangeCredential: FC<ChangeCredentialProps>;
|
|
54
|
+
export default ChangeCredential;
|
|
55
|
+
//# sourceMappingURL=ChangeCredential.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChangeCredential.d.ts","sourceRoot":"","sources":["../../../../src/components/presentation/ChangeCredential/ChangeCredential.tsx"],"names":[],"mappings":"AAYA,OAAO,EAAC,EAAE,EAAoB,MAAM,OAAO,CAAC;AAC5C,OAA6B,EAAC,yBAAyB,EAAuB,MAAM,wBAAwB,CAAC;AAY7G,MAAM,WAAW,qBACf,SAAQ,IAAI,CACV,yBAAyB,EACzB,uBAAuB,GAAG,OAAO,GAAG,aAAa,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CACvF;IACD;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,QAAA,MAAM,gBAAgB,EAAE,EAAE,CAAC,qBAAqB,CA8E/C,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import useThunderID_default from "../../../contexts/ThunderID/useThunderID.js";
|
|
2
|
+
import useUser_default from "../../../contexts/User/useUser.js";
|
|
3
|
+
import useTranslation_default from "../../../hooks/useTranslation.js";
|
|
4
|
+
import BaseChangeCredential_default from "./BaseChangeCredential.js";
|
|
5
|
+
import updateMeCredentials_default from "../../../api/updateMeCredentials.js";
|
|
6
|
+
import { CredentialConstants, mapCredentialUpdateError, resolveChangeCredentialPolicy, resolveResourceEndpoint, supportsCredential } from "@thunderid/browser";
|
|
7
|
+
import { useMemo, useState } from "react";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
|
|
10
|
+
//#region src/components/presentation/ChangeCredential/ChangeCredential.tsx
|
|
11
|
+
/**
|
|
12
|
+
* Title-cases a credential attribute name for use as a display-name fallback when the schema
|
|
13
|
+
* declares no `displayName` for it, e.g. `pin` -> `Pin`.
|
|
14
|
+
*/
|
|
15
|
+
const defaultDisplayName = (attribute) => attribute.charAt(0).toUpperCase() + attribute.slice(1);
|
|
16
|
+
/**
|
|
17
|
+
* ChangeCredential lets the signed-in user set a new value for one of their own credentials.
|
|
18
|
+
*
|
|
19
|
+
* It collects only a new value and its confirmation. The self-service credential write path
|
|
20
|
+
* does not verify the account's existing value today, so this component does not ask for one;
|
|
21
|
+
* once server-side current-value verification ships, that field returns without a breaking
|
|
22
|
+
* change to this component's public props.
|
|
23
|
+
*
|
|
24
|
+
* It reads the applicable rules from the user schema already resolved by the ThunderID
|
|
25
|
+
* provider, so it adds no network request beyond the write itself, and posts to
|
|
26
|
+
* `/users/me/update-credentials` with the access token attached by the SDK's HTTP client.
|
|
27
|
+
*
|
|
28
|
+
* Defaults to managing the `password` credential. To manage a different one (for example a
|
|
29
|
+
* PIN declared on the user type schema), set `attribute`; render the component once per
|
|
30
|
+
* credential to let a user manage several. Every default label, placeholder and message is
|
|
31
|
+
* built from the attribute's own `displayName` in the schema (`GET /users/me/meta`), so it
|
|
32
|
+
* always matches whatever an admin named the attribute there; when the schema carries no
|
|
33
|
+
* `displayName` for it, it falls back to the attribute name title-cased (`pin` -> `Pin`).
|
|
34
|
+
* Override individual strings via `preferences.i18n` for full control (including other
|
|
35
|
+
* languages) if the schema-derived name isn't the right fit.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* // Basic usage, manages the password
|
|
40
|
+
* <ChangeCredential onSuccess={() => toast('Password updated')} />
|
|
41
|
+
*
|
|
42
|
+
* // With an explicit rule instead of the schema-derived policy
|
|
43
|
+
* <ChangeCredential
|
|
44
|
+
* policy={{regex: '^.{12,}$'}}
|
|
45
|
+
* />
|
|
46
|
+
*
|
|
47
|
+
* // Managing a different credential declared on the schema; labels use the schema's own
|
|
48
|
+
* // displayName for it automatically
|
|
49
|
+
* <ChangeCredential attribute="pin" />
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
const ChangeCredential = ({ attribute = CredentialConstants.PASSWORD, onSuccess = void 0, policy = void 0, preferences = void 0,...rest }) => {
|
|
53
|
+
const { baseUrl, endpoints, instanceId, preferences: contextPreferences } = useThunderID_default();
|
|
54
|
+
const { userSchema } = useUser_default();
|
|
55
|
+
const resolvedDisplayName = userSchema?.[attribute]?.displayName ?? defaultDisplayName(attribute);
|
|
56
|
+
const resolvedPreferences = useMemo(() => ({
|
|
57
|
+
...contextPreferences,
|
|
58
|
+
...preferences,
|
|
59
|
+
user: {
|
|
60
|
+
...contextPreferences?.user,
|
|
61
|
+
...preferences?.user
|
|
62
|
+
}
|
|
63
|
+
}), [contextPreferences, preferences]);
|
|
64
|
+
const { t } = useTranslation_default(resolvedPreferences?.i18n);
|
|
65
|
+
const [error, setError] = useState(null);
|
|
66
|
+
const [fieldErrors, setFieldErrors] = useState({});
|
|
67
|
+
const [loading, setLoading] = useState(false);
|
|
68
|
+
const [success, setSuccess] = useState(false);
|
|
69
|
+
const resolvedPolicy = useMemo(() => resolveChangeCredentialPolicy(userSchema, attribute, policy), [
|
|
70
|
+
userSchema,
|
|
71
|
+
attribute,
|
|
72
|
+
policy
|
|
73
|
+
]);
|
|
74
|
+
const handleSubmit = async ({ newPassword }) => {
|
|
75
|
+
setError(null);
|
|
76
|
+
setFieldErrors({});
|
|
77
|
+
setSuccess(false);
|
|
78
|
+
setLoading(true);
|
|
79
|
+
try {
|
|
80
|
+
await updateMeCredentials_default({
|
|
81
|
+
baseUrl,
|
|
82
|
+
instanceId,
|
|
83
|
+
payload: { [attribute]: newPassword },
|
|
84
|
+
url: resolveResourceEndpoint("usersMeCredentials", { endpoints })
|
|
85
|
+
});
|
|
86
|
+
setSuccess(true);
|
|
87
|
+
onSuccess?.();
|
|
88
|
+
} catch (caughtError) {
|
|
89
|
+
const { field, message, messageKey } = mapCredentialUpdateError(caughtError);
|
|
90
|
+
const text = message ?? t(messageKey, {
|
|
91
|
+
credential: resolvedDisplayName,
|
|
92
|
+
credentialLower: resolvedDisplayName.toLowerCase()
|
|
93
|
+
});
|
|
94
|
+
if (field) setFieldErrors({ [field]: text });
|
|
95
|
+
else setError(text);
|
|
96
|
+
} finally {
|
|
97
|
+
setLoading(false);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
return /* @__PURE__ */ jsx(BaseChangeCredential_default, {
|
|
101
|
+
...rest,
|
|
102
|
+
credentialDisplayName: resolvedDisplayName,
|
|
103
|
+
error,
|
|
104
|
+
fieldErrors,
|
|
105
|
+
loading,
|
|
106
|
+
policy: resolvedPolicy,
|
|
107
|
+
preferences: resolvedPreferences,
|
|
108
|
+
success,
|
|
109
|
+
unavailable: !supportsCredential(userSchema, attribute),
|
|
110
|
+
onSubmit: (values) => {
|
|
111
|
+
handleSubmit(values);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
var ChangeCredential_default = ChangeCredential;
|
|
116
|
+
|
|
117
|
+
//#endregion
|
|
118
|
+
export { ChangeCredential_default as default };
|
|
119
|
+
//# sourceMappingURL=ChangeCredential.js.map
|