@aws-amplify/ui-react-core 2.1.33 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/esm/Authenticator/context/AuthenticatorProvider.mjs +5 -6
  2. package/dist/esm/Authenticator/hooks/constants.mjs +4 -4
  3. package/dist/esm/Authenticator/hooks/useAuthenticator/useAuthenticator.mjs +14 -11
  4. package/dist/esm/Authenticator/hooks/useAuthenticator/utils.mjs +10 -18
  5. package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/constants.mjs +7 -4
  6. package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.mjs +6 -6
  7. package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/utils.mjs +47 -18
  8. package/dist/esm/Authenticator/hooks/utils.mjs +2 -2
  9. package/dist/esm/components/FormCore/FormProvider.mjs +15 -0
  10. package/dist/esm/components/FormCore/useField.mjs +20 -0
  11. package/dist/esm/components/FormCore/useForm.mjs +51 -0
  12. package/dist/esm/components/FormCore/withFormProvider.mjs +15 -0
  13. package/dist/esm/hooks/useSetUserAgent.mjs +15 -0
  14. package/dist/esm/hooks/useTimeout.mjs +22 -0
  15. package/dist/esm/index.mjs +7 -0
  16. package/dist/esm/utils/createContextUtilities.mjs +80 -0
  17. package/dist/index.js +284 -96
  18. package/dist/types/Authenticator/hooks/types.d.ts +10 -7
  19. package/dist/types/Authenticator/hooks/useAuthenticator/types.d.ts +1 -3
  20. package/dist/types/Authenticator/hooks/useAuthenticator/utils.d.ts +2 -3
  21. package/dist/types/Authenticator/hooks/useAuthenticatorRoute/types.d.ts +3 -3
  22. package/dist/types/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.d.ts +2 -2
  23. package/dist/types/Authenticator/hooks/useAuthenticatorRoute/utils.d.ts +2 -2
  24. package/dist/types/components/FormCore/FormProvider.d.ts +4 -0
  25. package/dist/types/components/FormCore/index.d.ts +5 -0
  26. package/dist/types/components/FormCore/types.d.ts +217 -0
  27. package/dist/types/components/FormCore/useControlledField.d.ts +9 -0
  28. package/dist/types/components/FormCore/useField.d.ts +9 -0
  29. package/dist/types/components/FormCore/useForm.d.ts +12 -0
  30. package/dist/types/components/FormCore/withFormProvider.d.ts +8 -0
  31. package/dist/types/components/index.d.ts +1 -0
  32. package/dist/types/hooks/index.d.ts +2 -0
  33. package/dist/types/hooks/useSetUserAgent.d.ts +2 -0
  34. package/dist/types/hooks/useTimeout.d.ts +4 -0
  35. package/dist/types/index.d.ts +3 -2
  36. package/dist/types/types/index.d.ts +1 -1
  37. package/dist/types/types/types.d.ts +2 -0
  38. package/dist/types/utils/createContextUtilities.d.ts +26 -18
  39. package/package.json +11 -29
  40. package/src/Authenticator/context/AuthenticatorContext.tsx +17 -0
  41. package/src/Authenticator/context/AuthenticatorProvider.tsx +82 -0
  42. package/src/Authenticator/context/index.ts +2 -0
  43. package/src/Authenticator/hooks/constants.ts +30 -0
  44. package/src/Authenticator/hooks/index.ts +5 -0
  45. package/src/Authenticator/hooks/types.ts +218 -0
  46. package/src/Authenticator/hooks/useAuthenticator/__mock__/useAuthenticator.ts +66 -0
  47. package/src/Authenticator/hooks/useAuthenticator/constants.ts +2 -0
  48. package/src/Authenticator/hooks/useAuthenticator/index.ts +2 -0
  49. package/src/Authenticator/hooks/useAuthenticator/types.ts +48 -0
  50. package/src/Authenticator/hooks/useAuthenticator/useAuthenticator.ts +72 -0
  51. package/src/Authenticator/hooks/useAuthenticator/utils.ts +97 -0
  52. package/src/Authenticator/hooks/useAuthenticatorInitMachine/index.ts +1 -0
  53. package/src/Authenticator/hooks/useAuthenticatorInitMachine/useAuthenticatorInitMachine.tsx +25 -0
  54. package/src/Authenticator/hooks/useAuthenticatorRoute/constants.ts +107 -0
  55. package/src/Authenticator/hooks/useAuthenticatorRoute/index.ts +2 -0
  56. package/src/Authenticator/hooks/useAuthenticatorRoute/types.ts +111 -0
  57. package/src/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.ts +126 -0
  58. package/src/Authenticator/hooks/useAuthenticatorRoute/utils.ts +204 -0
  59. package/src/Authenticator/hooks/utils.ts +38 -0
  60. package/src/Authenticator/index.ts +23 -0
  61. package/src/components/FormCore/FormProvider.tsx +37 -0
  62. package/src/components/FormCore/index.ts +13 -0
  63. package/src/components/FormCore/types.ts +277 -0
  64. package/src/components/FormCore/useControlledField.ts +73 -0
  65. package/src/components/FormCore/useField.ts +25 -0
  66. package/src/components/FormCore/useForm.ts +84 -0
  67. package/src/components/FormCore/withFormProvider.tsx +31 -0
  68. package/src/components/RenderNothing/RenderNothing.tsx +6 -0
  69. package/src/components/RenderNothing/index.ts +1 -0
  70. package/src/components/index.ts +15 -0
  71. package/src/hooks/index.ts +8 -0
  72. package/src/hooks/useDeprecationWarning.ts +27 -0
  73. package/src/hooks/useHasValueUpdated.ts +28 -0
  74. package/src/hooks/usePreviousValue.ts +15 -0
  75. package/src/hooks/useSetUserAgent.ts +18 -0
  76. package/src/hooks/useTimeout.ts +30 -0
  77. package/src/index.ts +48 -0
  78. package/src/types/index.ts +1 -0
  79. package/src/types/types.ts +3 -0
  80. package/src/utils/createContextUtilities.tsx +131 -0
  81. package/src/utils/index.ts +1 -0
  82. package/dist/esm/node_modules/tslib/tslib.es6.mjs +0 -38
@@ -0,0 +1,218 @@
1
+ import React from 'react';
2
+
3
+ import {
4
+ ChallengeName,
5
+ AuthenticatorServiceFacade,
6
+ LegacyFormFieldOptions,
7
+ } from '@aws-amplify/ui';
8
+
9
+ import { UseAuthenticator } from './useAuthenticator';
10
+
11
+ export type AuthenticatorRouteComponentKey =
12
+ | 'confirmResetPassword'
13
+ | 'confirmSignIn'
14
+ | 'confirmSignUp'
15
+ | 'confirmVerifyUser'
16
+ | 'forceNewPassword'
17
+ | 'forgotPassword'
18
+ | 'setupTotp'
19
+ | 'signIn'
20
+ | 'signUp'
21
+ | 'verifyUser';
22
+
23
+ export type AuthenticatorLegacyField = LegacyFormFieldOptions;
24
+ export type AuthenticatorLegacyFields = AuthenticatorLegacyField[];
25
+
26
+ /**
27
+ * These are the "facades" that we provide, which contains contexts respective
28
+ * to current authenticator state.
29
+ */
30
+ export type AuthenticatorMachineContext = AuthenticatorServiceFacade;
31
+ export type AuthenticatorMachineContextKey = keyof AuthenticatorMachineContext;
32
+
33
+ export type AuthenticatorRouteComponentName =
34
+ Capitalize<AuthenticatorRouteComponentKey>;
35
+
36
+ interface HeaderProps {
37
+ children?: React.ReactNode;
38
+ }
39
+
40
+ interface FooterProps {
41
+ children?: React.ReactNode;
42
+ }
43
+
44
+ type FormFieldsProps = {
45
+ isPending: UseAuthenticator['isPending'];
46
+ validationErrors?: UseAuthenticator['validationErrors'];
47
+ };
48
+
49
+ export type FooterComponent<Props = {}> = React.ComponentType<
50
+ FooterProps & Props
51
+ >;
52
+
53
+ export type FormFieldsComponent<FieldType, Props = {}> = React.ComponentType<
54
+ FormFieldsProps & { fields: FieldType[] } & Props
55
+ >;
56
+
57
+ export type HeaderComponent<Props = {}> = React.ComponentType<
58
+ HeaderProps & Props
59
+ >;
60
+
61
+ export interface ComponentSlots<FieldType = {}> {
62
+ Footer: FooterComponent;
63
+ Header: HeaderComponent;
64
+
65
+ // `FormFieldsComponent` requires `FieldType`
66
+ FormFields: FormFieldsComponent<FieldType>;
67
+ }
68
+
69
+ /**
70
+ * Common component prop types used for both RWA and RNA implementations
71
+ */
72
+ export type CommonRouteProps = {
73
+ error?: UseAuthenticator['error'];
74
+ isPending: UseAuthenticator['isPending'];
75
+ handleBlur: UseAuthenticator['updateBlur'];
76
+ handleChange: UseAuthenticator['updateForm'];
77
+ handleSubmit: UseAuthenticator['submitForm'];
78
+ };
79
+
80
+ export interface ValidationProps {
81
+ hasValidationErrors: UseAuthenticator['hasValidationErrors'];
82
+ validationErrors?: UseAuthenticator['validationErrors'];
83
+ }
84
+
85
+ /**
86
+ * Base Route component props
87
+ */
88
+ export type ConfirmResetPasswordBaseProps<FieldType = {}> = {
89
+ resendCode: UseAuthenticator['resendCode'];
90
+ } & CommonRouteProps &
91
+ ComponentSlots<FieldType> &
92
+ ValidationProps;
93
+
94
+ export type ConfirmSignInBaseProps<FieldType = {}> = {
95
+ challengeName: ChallengeName | undefined;
96
+ toSignIn: UseAuthenticator['toSignIn'];
97
+ } & CommonRouteProps &
98
+ ComponentSlots<FieldType> &
99
+ ValidationProps;
100
+
101
+ export type ConfirmSignUpBaseProps<FieldType = {}> = {
102
+ codeDeliveryDetails: UseAuthenticator['codeDeliveryDetails'];
103
+ resendCode: UseAuthenticator['resendCode'];
104
+ } & CommonRouteProps &
105
+ ComponentSlots<FieldType> &
106
+ ValidationProps;
107
+
108
+ export type ConfirmVerifyUserProps<FieldType = {}> = {
109
+ skipVerification: UseAuthenticator['skipVerification'];
110
+ } & CommonRouteProps &
111
+ ComponentSlots<FieldType> &
112
+ ValidationProps;
113
+
114
+ export type ForceResetPasswordBaseProps<FieldType = {}> = {
115
+ toSignIn: UseAuthenticator['toSignIn'];
116
+ } & CommonRouteProps &
117
+ ComponentSlots<FieldType> &
118
+ ValidationProps;
119
+
120
+ export type ResetPasswordBaseProps<FieldType = {}> = {
121
+ toSignIn: UseAuthenticator['toSignIn'];
122
+ } & CommonRouteProps &
123
+ ComponentSlots<FieldType> &
124
+ ValidationProps;
125
+
126
+ export type SetupTotpBaseProps<FieldType = {}> = {
127
+ toSignIn: UseAuthenticator['toSignIn'];
128
+ totpSecretCode: UseAuthenticator['totpSecretCode'];
129
+ username: UseAuthenticator['username'];
130
+ } & CommonRouteProps &
131
+ ComponentSlots<FieldType> &
132
+ ValidationProps;
133
+
134
+ export type SignInBaseProps<FieldType = {}> = {
135
+ hideSignUp?: boolean;
136
+ socialProviders?: UseAuthenticator['socialProviders'];
137
+ toFederatedSignIn: UseAuthenticator['toFederatedSignIn'];
138
+ toForgotPassword: UseAuthenticator['toForgotPassword'];
139
+ toSignUp: UseAuthenticator['toSignUp'];
140
+ } & CommonRouteProps &
141
+ ComponentSlots<FieldType> &
142
+ ValidationProps;
143
+
144
+ export type SignUpBaseProps<FieldType = {}> = {
145
+ hideSignIn?: boolean;
146
+ socialProviders?: UseAuthenticator['socialProviders'];
147
+ toFederatedSignIn: UseAuthenticator['toFederatedSignIn'];
148
+ toSignIn: UseAuthenticator['toSignIn'];
149
+ } & CommonRouteProps &
150
+ ComponentSlots<FieldType> &
151
+ ValidationProps;
152
+
153
+ export type VerifyUserProps<FieldType = {}> = {
154
+ skipVerification: UseAuthenticator['skipVerification'];
155
+ } & CommonRouteProps &
156
+ ComponentSlots<FieldType> &
157
+ ValidationProps;
158
+
159
+ export interface DefaultProps<FieldType = {}> {
160
+ ConfirmSignIn: ConfirmSignInBaseProps<FieldType>;
161
+ ConfirmSignUp: ConfirmSignUpBaseProps<FieldType>;
162
+ ConfirmResetPassword: ConfirmResetPasswordBaseProps<FieldType>;
163
+ ConfirmVerifyUser: ConfirmVerifyUserProps<FieldType>;
164
+ ForceNewPassword: ForceResetPasswordBaseProps<FieldType>;
165
+ ForgotPassword: ResetPasswordBaseProps<FieldType>;
166
+ SetupTotp: SetupTotpBaseProps<FieldType>;
167
+ SignIn: SignInBaseProps<FieldType>;
168
+ SignUp: SignUpBaseProps<FieldType>;
169
+ VerifyUser: VerifyUserProps<FieldType>;
170
+ }
171
+
172
+ /**
173
+ * common types extended for default component types/implementations and override component types
174
+ */
175
+ type BaseComponent<
176
+ // Route specifc props
177
+ ComponentRouteProps = {},
178
+ // Route specific `FieldType`
179
+ FieldType = {},
180
+ // additional props assigned in the UI layer
181
+ Props = {},
182
+ > = React.ComponentType<
183
+ ComponentSlots<FieldType> &
184
+ ComponentRouteProps & { fields: FieldType[] } & Props
185
+ >;
186
+
187
+ /**
188
+ * Authenticator Route Component Default types
189
+ */
190
+ export type Defaults<FieldType = {}, PlatformProps = {}> = {
191
+ [Key in AuthenticatorRouteComponentName]: BaseComponent<
192
+ DefaultProps<FieldType>[Key],
193
+ FieldType,
194
+ PlatformProps
195
+ > &
196
+ // add component slots for Defaults
197
+ ComponentSlots<FieldType>;
198
+ };
199
+
200
+ export type Overrides<FieldType = {}, PlatformProps = {}> = {
201
+ [Key in AuthenticatorRouteComponentName]?: BaseComponent<
202
+ DefaultProps<FieldType>[Key],
203
+ FieldType,
204
+ PlatformProps
205
+ >;
206
+ };
207
+
208
+ /**
209
+ * Default Route Component union type
210
+ */
211
+ export type DefaultComponentType<FieldType = {}> =
212
+ Defaults<FieldType>[keyof Defaults<FieldType>];
213
+
214
+ /**
215
+ * Default Route Component union type
216
+ */
217
+ export type DefaultPropsType<FieldType = {}> =
218
+ DefaultProps<FieldType>[keyof DefaultProps<FieldType>];
@@ -0,0 +1,66 @@
1
+ import {
2
+ AuthenticatorLegacyFields,
3
+ AuthenticatorMachineContext,
4
+ } from '../../types';
5
+ import { UseAuthenticator } from '../types';
6
+
7
+ const authStatus = 'unauthenticated';
8
+ const challengeName = 'CUSTOM_CHALLENGE';
9
+ const codeDeliveryDetails =
10
+ {} as AuthenticatorMachineContext['codeDeliveryDetails'];
11
+ const error = 'error';
12
+ const fields = [] as AuthenticatorLegacyFields;
13
+ const hasValidationErrors = false;
14
+ const initializeMachine = jest.fn();
15
+ const isPending = false;
16
+ const QRFields = null;
17
+ const resendCode = jest.fn();
18
+ const route = 'idle';
19
+ const skipVerification = jest.fn();
20
+ const signOut = jest.fn();
21
+ const socialProviders = [] as AuthenticatorMachineContext['socialProviders'];
22
+ const submitForm = jest.fn();
23
+ const toFederatedSignIn = jest.fn();
24
+ const toForgotPassword = jest.fn();
25
+ const toSignIn = jest.fn();
26
+ const toSignUp = jest.fn();
27
+ const totpSecretCode = null;
28
+ const unverifiedUserAttributes = {};
29
+ const updateBlur = jest.fn();
30
+ const updateForm = jest.fn();
31
+ const user = { username: 'username', userId: 'userId' };
32
+ const validationErrors = {};
33
+
34
+ export const mockMachineContext: AuthenticatorMachineContext = {
35
+ authStatus,
36
+ challengeName,
37
+ codeDeliveryDetails,
38
+ error,
39
+ hasValidationErrors,
40
+ initializeMachine,
41
+ isPending,
42
+ resendCode,
43
+ route,
44
+ signOut,
45
+ submitForm,
46
+ updateForm,
47
+ toSignIn,
48
+ toSignUp,
49
+ updateBlur,
50
+ user,
51
+ skipVerification,
52
+ socialProviders,
53
+ toFederatedSignIn,
54
+ toForgotPassword,
55
+ totpSecretCode,
56
+
57
+ unverifiedUserAttributes,
58
+ username: 'george',
59
+ validationErrors,
60
+ };
61
+
62
+ export const mockUseAuthenticatorOutput: UseAuthenticator = {
63
+ ...mockMachineContext,
64
+ fields,
65
+ QRFields,
66
+ };
@@ -0,0 +1,2 @@
1
+ export const USE_AUTHENTICATOR_ERROR =
2
+ '`useAuthenticator` must be used inside an `Authenticator.Provider`.';
@@ -0,0 +1,2 @@
1
+ export { default as useAuthenticator } from './useAuthenticator';
2
+ export { UseAuthenticator, UseAuthenticatorSelector } from './types';
@@ -0,0 +1,48 @@
1
+ import {
2
+ AuthenticatorServiceFacade,
3
+ LegacyFormFieldOptions,
4
+ } from '@aws-amplify/ui';
5
+
6
+ /**
7
+ * These are the "facades" that we provide, which contains contexts respective
8
+ * to current authenticator state.
9
+ */
10
+ type AuthenticatorMachineContext = AuthenticatorServiceFacade;
11
+ type AuthenticatorMachineContextKey = keyof AuthenticatorMachineContext;
12
+
13
+ export type AuthenticatorRouteComponentKey =
14
+ | 'signIn'
15
+ | 'signUp'
16
+ | 'forceNewPassword'
17
+ | 'confirmResetPassword'
18
+ | 'confirmSignIn'
19
+ | 'confirmSignUp'
20
+ | 'confirmVerifyUser'
21
+ | 'forgotPassword'
22
+ | 'setupTotp'
23
+ | 'verifyUser';
24
+
25
+ export type AuthenticatorLegacyFields = LegacyFormFieldOptions[];
26
+
27
+ /**
28
+ * Inspired from https://xstate.js.org/docs/packages/xstate-react/#useselector-actor-selector-compare-getsnapshot.
29
+ *
30
+ * Selector accepts current facade values and returns an array of
31
+ * desired value(s) that should trigger re-render.
32
+ */
33
+ export type UseAuthenticatorSelector = (
34
+ context: AuthenticatorMachineContext
35
+ ) => AuthenticatorMachineContext[AuthenticatorMachineContextKey][];
36
+
37
+ export interface UseAuthenticator extends AuthenticatorServiceFacade {
38
+ /** @deprecated For internal use only */
39
+ fields: AuthenticatorLegacyFields;
40
+
41
+ /** @deprecated For internal use only */
42
+ QRFields: { totpIssuer?: string; totpUsername?: string } | null;
43
+ }
44
+
45
+ export type Comparator = (
46
+ currentMachineContext: AuthenticatorMachineContext,
47
+ nextMachineContext: AuthenticatorMachineContext
48
+ ) => boolean;
@@ -0,0 +1,72 @@
1
+ import React, { useCallback } from 'react';
2
+ import { useSelector } from '@xstate/react';
3
+ import { AuthMachineState, getServiceFacade } from '@aws-amplify/ui';
4
+
5
+ import { AuthenticatorContext } from '../../context';
6
+
7
+ import { USE_AUTHENTICATOR_ERROR } from './constants';
8
+ import { UseAuthenticatorSelector, UseAuthenticator } from './types';
9
+ import {
10
+ defaultComparator,
11
+ getComparator,
12
+ getMachineFields,
13
+ // getTotpSecretCodeCallback,
14
+ getQRFields,
15
+ } from './utils';
16
+
17
+ /**
18
+ * [📖 Docs](https://ui.docs.amplify.aws/react/connected-components/authenticator/headless#useauthenticator-hook)
19
+ */
20
+ export default function useAuthenticator(
21
+ selector?: UseAuthenticatorSelector
22
+ ): UseAuthenticator {
23
+ const context = React.useContext(AuthenticatorContext);
24
+
25
+ if (!context) {
26
+ throw new Error(USE_AUTHENTICATOR_ERROR);
27
+ }
28
+
29
+ const { service } = context;
30
+ const { send } = service;
31
+
32
+ const xstateSelector = useCallback(
33
+ (state: AuthMachineState) => ({ ...getServiceFacade({ send, state }) }),
34
+ [send]
35
+ );
36
+
37
+ const comparator = selector ? getComparator(selector) : defaultComparator;
38
+
39
+ // the purpose of `context.authStatus`is to intentionally override `facade.authStatus`. `facade.authStatus` does
40
+ // not update on external sign in events (for example when a user is not using the `Authenticator`).
41
+ const { authStatus } = context;
42
+ const facade = useSelector(service, xstateSelector, comparator);
43
+
44
+ const { route, totpSecretCode, unverifiedUserAttributes, user, ...rest } =
45
+ facade;
46
+
47
+ // do not memoize output. `service.getSnapshot` reference remains stable preventing
48
+ // `fields` from updating with current form state on value changes
49
+ const serviceSnapshot = service.getSnapshot() as AuthMachineState;
50
+
51
+ // legacy `QRFields` values only used for SetupTotp page to retrieve issuer information, will be removed in future
52
+ const QRFields = route === 'setupTotp' ? getQRFields(serviceSnapshot) : null;
53
+
54
+ // legacy `formFields` values required until form state is removed from state machine
55
+ const fields = getMachineFields(
56
+ route,
57
+ serviceSnapshot,
58
+ unverifiedUserAttributes
59
+ );
60
+
61
+ return {
62
+ ...rest,
63
+ authStatus,
64
+ route,
65
+ totpSecretCode,
66
+ unverifiedUserAttributes,
67
+ user,
68
+ /** @deprecated For internal use only */
69
+ fields,
70
+ QRFields,
71
+ };
72
+ }
@@ -0,0 +1,97 @@
1
+ import {
2
+ areEmptyArrays,
3
+ areEmptyObjects,
4
+ AuthenticatorRoute,
5
+ AuthMachineState,
6
+ FormFieldsArray,
7
+ getSortedFormFields,
8
+ UnverifiedUserAttributes,
9
+ getActorContext,
10
+ isString,
11
+ } from '@aws-amplify/ui';
12
+
13
+ import { AuthenticatorLegacyField, AuthenticatorLegacyFields } from '../types';
14
+ import { isComponentRouteKey } from '../utils';
15
+
16
+ import { Comparator, UseAuthenticatorSelector } from './types';
17
+
18
+ export const defaultComparator = (): false => false;
19
+
20
+ /**
21
+ * Does an ordering and shallow comparison of each array value,
22
+ * plus a value equality check for empty objects and arrays.
23
+ */
24
+ export function areSelectorDepsEqual<T>(
25
+ currentDeps: T[],
26
+ nextDeps: T[]
27
+ ): boolean {
28
+ if (currentDeps.length !== nextDeps.length) {
29
+ return false;
30
+ }
31
+ return currentDeps.every((currentDep, index) => {
32
+ const nextDep = nextDeps[index];
33
+
34
+ if (
35
+ areEmptyArrays(currentDep, nextDep) ||
36
+ areEmptyObjects(currentDep, nextDep)
37
+ ) {
38
+ return true;
39
+ }
40
+
41
+ return currentDep === nextDep;
42
+ });
43
+ }
44
+
45
+ export const getComparator =
46
+ (selector: UseAuthenticatorSelector): Comparator =>
47
+ (currentFacade, nextFacade) => {
48
+ const currentSelectorDeps = selector(currentFacade);
49
+ const nextSelectorDeps = selector(nextFacade);
50
+
51
+ // Shallow compare the array values
52
+ return areSelectorDepsEqual(currentSelectorDeps, nextSelectorDeps);
53
+ };
54
+
55
+ export const getQRFields = (
56
+ state: AuthMachineState
57
+ ): { totpIssuer?: string; totpUsername?: string } => ({
58
+ ...getActorContext(state)?.formFields?.setupTotp?.QR,
59
+ });
60
+
61
+ const flattenFormFields = (
62
+ fields: FormFieldsArray
63
+ ): AuthenticatorLegacyFields =>
64
+ fields.flatMap(([name, options]) => ({ name, ...options }));
65
+
66
+ const convertContactMethodsToFields = (
67
+ unverifiedUserAttributes: UnverifiedUserAttributes
68
+ ): AuthenticatorLegacyFields => {
69
+ return (
70
+ unverifiedUserAttributes &&
71
+ Object.entries(unverifiedUserAttributes).map(([name, value]) => {
72
+ const valueIsString = isString(value);
73
+ if (!valueIsString || !name) {
74
+ return {} as AuthenticatorLegacyField;
75
+ }
76
+ return { name, label: value, type: 'radio', value };
77
+ })
78
+ );
79
+ };
80
+
81
+ /**
82
+ * Retrieves default and custom (RWA only, to be updated) form field values from state machine
83
+ * for subcomponent routes that render fields
84
+ */
85
+ export const getMachineFields = (
86
+ route: AuthenticatorRoute,
87
+ state: AuthMachineState,
88
+ unverifiedUserAttributes: UnverifiedUserAttributes
89
+ ): AuthenticatorLegacyFields => {
90
+ if (isComponentRouteKey(route)) {
91
+ return route === 'verifyUser'
92
+ ? convertContactMethodsToFields(unverifiedUserAttributes)
93
+ : flattenFormFields(getSortedFormFields(route, state));
94
+ }
95
+
96
+ return [];
97
+ };
@@ -0,0 +1 @@
1
+ export { default as useAuthenticatorInitMachine } from './useAuthenticatorInitMachine';
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { AuthenticatorMachineOptions } from '@aws-amplify/ui';
3
+
4
+ import {
5
+ useAuthenticator,
6
+ UseAuthenticatorSelector,
7
+ } from '../useAuthenticator';
8
+
9
+ // only select `route` from machine context
10
+ export const routeSelector: UseAuthenticatorSelector = ({ route }) => [route];
11
+
12
+ export default function useAuthenticatorInitMachine(
13
+ data: AuthenticatorMachineOptions
14
+ ): void {
15
+ const { route, initializeMachine } = useAuthenticator(routeSelector);
16
+
17
+ const hasInitialized = React.useRef(false);
18
+ React.useEffect(() => {
19
+ if (!hasInitialized.current && route === 'setup') {
20
+ initializeMachine(data);
21
+
22
+ hasInitialized.current = true;
23
+ }
24
+ }, [initializeMachine, route, data]);
25
+ }
@@ -0,0 +1,107 @@
1
+ import {
2
+ AuthenticatorMachineContextKey,
3
+ AuthenticatorRouteComponentKey,
4
+ } from '../types';
5
+ import {
6
+ CommonRouteMachineKey,
7
+ ConfirmResetPasswordMachineKey,
8
+ ConfirmSignInMachineKey,
9
+ ConfirmSignUpMachineKey,
10
+ ConfirmVerifyUserMachineKey,
11
+ ForceNewPasswordMachineKey,
12
+ FormEventHandlerMachineKey,
13
+ FormEventHandlerPropKey,
14
+ ResetPasswordMachineKey,
15
+ SignInMachineKey,
16
+ SignUpMachineKey,
17
+ SetupTotpMachineKey,
18
+ VerifyUserMachineKey,
19
+ } from './types';
20
+
21
+ export const EVENT_HANDLER_KEY_MAP: Record<
22
+ FormEventHandlerMachineKey,
23
+ FormEventHandlerPropKey
24
+ > = {
25
+ updateBlur: 'handleBlur',
26
+ updateForm: 'handleChange',
27
+ submitForm: 'handleSubmit',
28
+ };
29
+
30
+ const COMMON_ROUTE_MACHINE_KEYS: CommonRouteMachineKey[] = [
31
+ 'error',
32
+ 'isPending',
33
+ 'submitForm',
34
+ 'updateBlur',
35
+ 'updateForm',
36
+ ];
37
+
38
+ const CONFIRM_RESET_PASSWORD_MACHINE_KEYS: ConfirmResetPasswordMachineKey[] = [
39
+ ...COMMON_ROUTE_MACHINE_KEYS,
40
+ 'hasValidationErrors',
41
+ 'resendCode',
42
+ 'validationErrors',
43
+ ];
44
+ const CONFIRM_SIGN_IN_MACHINE_KEYS: ConfirmSignInMachineKey[] = [
45
+ ...COMMON_ROUTE_MACHINE_KEYS,
46
+ 'challengeName',
47
+ 'toSignIn',
48
+ ];
49
+ const CONFIRM_SIGN_UP_MACHINE_KEYS: ConfirmSignUpMachineKey[] = [
50
+ ...COMMON_ROUTE_MACHINE_KEYS,
51
+ 'codeDeliveryDetails',
52
+ 'resendCode',
53
+ ];
54
+ const CONFIRM_VERIFY_USER_MACHINE_KEYS: ConfirmVerifyUserMachineKey[] = [
55
+ ...COMMON_ROUTE_MACHINE_KEYS,
56
+ 'skipVerification',
57
+ ];
58
+ const FORCE_NEW_PASSWORD_MACHINE_KEYS: ForceNewPasswordMachineKey[] = [
59
+ ...COMMON_ROUTE_MACHINE_KEYS,
60
+ 'hasValidationErrors',
61
+ 'toSignIn',
62
+ 'validationErrors',
63
+ ];
64
+ const RESET_PASSWORD_MACHINE_KEYS: ResetPasswordMachineKey[] = [
65
+ ...COMMON_ROUTE_MACHINE_KEYS,
66
+ 'toSignIn',
67
+ ];
68
+ const SIGN_IN_MACHINE_KEYS: SignInMachineKey[] = [
69
+ ...COMMON_ROUTE_MACHINE_KEYS,
70
+ 'socialProviders',
71
+ 'toFederatedSignIn',
72
+ 'toForgotPassword',
73
+ 'toSignUp',
74
+ ];
75
+ const SIGN_UP_MACHINE_KEYS: SignUpMachineKey[] = [
76
+ ...COMMON_ROUTE_MACHINE_KEYS,
77
+ 'hasValidationErrors',
78
+ 'socialProviders',
79
+ 'toSignIn',
80
+ 'validationErrors',
81
+ ];
82
+ const SETUP_TOTP_MACHINE_KEYS: SetupTotpMachineKey[] = [
83
+ ...COMMON_ROUTE_MACHINE_KEYS,
84
+ 'toSignIn',
85
+ 'totpSecretCode',
86
+ 'username',
87
+ ];
88
+ const VERIFY_USER_MACHINE_KEYS: VerifyUserMachineKey[] = [
89
+ ...COMMON_ROUTE_MACHINE_KEYS,
90
+ 'skipVerification',
91
+ ];
92
+
93
+ export const MACHINE_PROP_KEYS: Record<
94
+ AuthenticatorRouteComponentKey,
95
+ AuthenticatorMachineContextKey[]
96
+ > = {
97
+ confirmResetPassword: CONFIRM_RESET_PASSWORD_MACHINE_KEYS,
98
+ confirmSignIn: CONFIRM_SIGN_IN_MACHINE_KEYS,
99
+ confirmSignUp: CONFIRM_SIGN_UP_MACHINE_KEYS,
100
+ confirmVerifyUser: CONFIRM_VERIFY_USER_MACHINE_KEYS,
101
+ forceNewPassword: FORCE_NEW_PASSWORD_MACHINE_KEYS,
102
+ signIn: SIGN_IN_MACHINE_KEYS,
103
+ signUp: SIGN_UP_MACHINE_KEYS,
104
+ forgotPassword: RESET_PASSWORD_MACHINE_KEYS,
105
+ setupTotp: SETUP_TOTP_MACHINE_KEYS,
106
+ verifyUser: VERIFY_USER_MACHINE_KEYS,
107
+ };
@@ -0,0 +1,2 @@
1
+ export { default as useAuthenticatorRoute } from './useAuthenticatorRoute';
2
+ export * from './types';