@aws-amplify/ui-react-native 2.4.4 → 2.5.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 (63) hide show
  1. package/dist/Authenticator/Authenticator.d.ts +33 -0
  2. package/dist/Authenticator/Authenticator.js +5 -1
  3. package/dist/Authenticator/Defaults/SelectMfaType/SelectMfaType.d.ts +14 -0
  4. package/dist/Authenticator/Defaults/SelectMfaType/SelectMfaType.js +39 -0
  5. package/dist/Authenticator/Defaults/SelectMfaType/index.d.ts +1 -0
  6. package/dist/Authenticator/Defaults/SelectMfaType/index.js +1 -0
  7. package/dist/Authenticator/Defaults/SetupEmail/SetupEmail.d.ts +14 -0
  8. package/dist/Authenticator/Defaults/SetupEmail/SetupEmail.js +39 -0
  9. package/dist/Authenticator/Defaults/SetupEmail/index.d.ts +1 -0
  10. package/dist/Authenticator/Defaults/SetupEmail/index.js +1 -0
  11. package/dist/Authenticator/Defaults/VerifyUser/VerifyUser.js +2 -2
  12. package/dist/Authenticator/Defaults/index.d.ts +3 -1
  13. package/dist/Authenticator/Defaults/index.js +2 -0
  14. package/dist/Authenticator/Defaults/types.d.ts +42 -0
  15. package/dist/Authenticator/common/DefaultContainer/index.d.ts +1 -1
  16. package/dist/Authenticator/common/DefaultFormFields/DefaultSelectMfaTypeFormFields.d.ts +7 -0
  17. package/dist/Authenticator/common/DefaultFormFields/DefaultSelectMfaTypeFormFields.js +12 -0
  18. package/dist/Authenticator/common/DefaultFormFields/{DefaultRadioFormFields.d.ts → DefaultVerifyUserFormFields.d.ts} +2 -2
  19. package/dist/Authenticator/common/DefaultFormFields/{DefaultRadioFormFields.js → DefaultVerifyUserFormFields.js} +7 -5
  20. package/dist/Authenticator/common/DefaultFormFields/index.d.ts +2 -1
  21. package/dist/Authenticator/common/DefaultFormFields/index.js +2 -1
  22. package/dist/Authenticator/hooks/useFieldValues/useFieldValues.js +52 -19
  23. package/dist/Authenticator/hooks/useFieldValues/utils.d.ts +2 -1
  24. package/dist/Authenticator/hooks/useFieldValues/utils.js +26 -3
  25. package/dist/Authenticator/index.d.ts +2 -0
  26. package/dist/index.d.ts +1 -1
  27. package/dist/primitives/RadioGroup/RadioGroup.d.ts +1 -0
  28. package/dist/primitives/RadioGroup/RadioGroup.js +2 -1
  29. package/dist/version.d.ts +1 -1
  30. package/dist/version.js +1 -1
  31. package/lib/Authenticator/Authenticator.js +4 -0
  32. package/lib/Authenticator/Defaults/SelectMfaType/SelectMfaType.js +42 -0
  33. package/lib/Authenticator/Defaults/SelectMfaType/index.js +8 -0
  34. package/lib/Authenticator/Defaults/SetupEmail/SetupEmail.js +42 -0
  35. package/lib/Authenticator/Defaults/SetupEmail/index.js +8 -0
  36. package/lib/Authenticator/Defaults/VerifyUser/VerifyUser.js +1 -1
  37. package/lib/Authenticator/Defaults/index.js +5 -1
  38. package/lib/Authenticator/common/DefaultFormFields/DefaultSelectMfaTypeFormFields.js +15 -0
  39. package/lib/Authenticator/common/DefaultFormFields/{DefaultRadioFormFields.js → DefaultVerifyUserFormFields.js} +7 -5
  40. package/lib/Authenticator/common/DefaultFormFields/index.js +5 -3
  41. package/lib/Authenticator/hooks/useFieldValues/useFieldValues.js +51 -18
  42. package/lib/Authenticator/hooks/useFieldValues/utils.js +29 -5
  43. package/lib/primitives/RadioGroup/RadioGroup.js +3 -1
  44. package/lib/version.js +1 -1
  45. package/package.json +4 -4
  46. package/src/Authenticator/Authenticator.tsx +6 -0
  47. package/src/Authenticator/Defaults/SelectMfaType/SelectMfaType.tsx +87 -0
  48. package/src/Authenticator/Defaults/SelectMfaType/index.ts +1 -0
  49. package/src/Authenticator/Defaults/SetupEmail/SetupEmail.tsx +86 -0
  50. package/src/Authenticator/Defaults/SetupEmail/index.ts +1 -0
  51. package/src/Authenticator/Defaults/VerifyUser/VerifyUser.tsx +2 -2
  52. package/src/Authenticator/Defaults/index.ts +18 -1
  53. package/src/Authenticator/Defaults/types.ts +42 -0
  54. package/src/Authenticator/common/DefaultContainer/index.ts +1 -1
  55. package/src/Authenticator/common/DefaultFormFields/DefaultSelectMfaTypeFormFields.tsx +35 -0
  56. package/src/Authenticator/common/DefaultFormFields/{DefaultRadioFormFields.tsx → DefaultVerifyUserFormFields.tsx} +8 -7
  57. package/src/Authenticator/common/DefaultFormFields/index.ts +2 -1
  58. package/src/Authenticator/hooks/useFieldValues/useFieldValues.ts +65 -21
  59. package/src/Authenticator/hooks/useFieldValues/utils.ts +40 -5
  60. package/src/Authenticator/index.ts +15 -0
  61. package/src/index.ts +12 -0
  62. package/src/primitives/RadioGroup/RadioGroup.tsx +7 -1
  63. package/src/version.ts +1 -1
@@ -15,6 +15,8 @@ export interface SetupTotpStyle {}
15
15
  export interface SignInStyle {}
16
16
  export interface SignUpStyle {}
17
17
  export interface VerifyUserStyle {}
18
+ export interface SetupEmailStyle {}
19
+ export interface SelectMfaTypeStyle {}
18
20
 
19
21
  export type DefaultComponents<
20
22
  FieldType = {},
@@ -85,6 +87,20 @@ export type DefaultVerifyUserProps = React.ComponentPropsWithoutRef<
85
87
  >['VerifyUser']
86
88
  >;
87
89
 
90
+ export type DefaultSetupEmailProps = React.ComponentPropsWithoutRef<
91
+ DefaultComponents<
92
+ TextFieldOptionsType,
93
+ { style?: SetupEmailStyle }
94
+ >['SetupEmail']
95
+ >;
96
+
97
+ export type DefaultSelectMfaTypeProps = React.ComponentPropsWithoutRef<
98
+ DefaultComponents<
99
+ RadioFieldOptions,
100
+ { style?: SelectMfaTypeStyle }
101
+ >['SelectMfaType']
102
+ >;
103
+
88
104
  /**
89
105
  * Custom Authenticator components
90
106
  */
@@ -143,6 +159,16 @@ type VerifyUserComponent<P = {}> = OverrideComponents<
143
159
  { style?: VerifyUserStyle } & P
144
160
  >['VerifyUser'];
145
161
 
162
+ type SetupEmailComponent<P = {}> = OverrideComponents<
163
+ TextFieldOptionsType,
164
+ { style?: SetupEmailStyle } & P
165
+ >['SetupEmail'];
166
+
167
+ type SelectMfaTypeComponent<P = {}> = OverrideComponents<
168
+ RadioFieldOptions,
169
+ { style?: SelectMfaTypeStyle } & P
170
+ >['SelectMfaType'];
171
+
146
172
  /**
147
173
  * Override `Authenticator` components param
148
174
  */
@@ -153,8 +179,24 @@ export interface Components {
153
179
  ConfirmVerifyUser?: ConfirmVerifyUserComponent;
154
180
  ForceNewPassword?: ForceNewPasswordComponent;
155
181
  ForgotPassword?: ForgotPasswordComponent;
182
+ SelectMfaType?: SelectMfaTypeComponent;
183
+ SetupEmail?: SetupEmailComponent;
156
184
  SetupTotp?: SetupTotpComponent;
157
185
  SignIn?: SignInComponent;
158
186
  SignUp?: SignUpComponent;
159
187
  VerifyUser?: VerifyUserComponent;
160
188
  }
189
+
190
+ export interface ConfirmResetPasswordProps
191
+ extends DefaultConfirmResetPasswordProps {}
192
+ export interface ConfirmSignInProps extends DefaultConfirmSignInProps {}
193
+ export interface ConfirmSignUpProps extends DefaultConfirmSignUpProps {}
194
+ export interface ConfirmVerifyUserProps extends DefaultConfirmVerifyUserProps {}
195
+ export interface ForceNewPasswordProps extends DefaultForceNewPasswordProps {}
196
+ export interface ForgotPasswordProps extends DefaultForgotPasswordProps {}
197
+ export interface SelectMfaTypeProps extends DefaultSelectMfaTypeProps {}
198
+ export interface SetupEmailProps extends DefaultSetupEmailProps {}
199
+ export interface SetupTotpProps extends DefaultSetupTotpProps {}
200
+ export interface SignInProps extends DefaultSignInProps {}
201
+ export interface SignUpProps extends DefaultSignUpProps {}
202
+ export interface VerifyUserProps extends DefaultVerifyUserProps {}
@@ -1,3 +1,3 @@
1
1
  export { default as DefaultContainer } from './DefaultContainer';
2
2
  export { default as InnerContainer } from './InnerContainer';
3
- export { DefaultContainerComponent } from './types';
3
+ export { ContainerProps, DefaultContainerComponent } from './types';
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+
3
+ import { DefaultRadioFormFieldsProps } from './types';
4
+
5
+ import { RadioGroup } from '../../../primitives/RadioGroup';
6
+ import { Radio } from '../../../primitives/Radio';
7
+
8
+ const DefaultSelectMfaTypeFormFields = ({
9
+ fields = [],
10
+ fieldContainerStyle,
11
+ fieldLabelStyle,
12
+ isPending,
13
+ style,
14
+ }: DefaultRadioFormFieldsProps): React.JSX.Element => {
15
+ // set initial value for radio field based on selected bool
16
+ const initialValue = fields.find((field) => !!field.selected)?.value;
17
+ return (
18
+ <RadioGroup disabled={isPending} style={style} initialValue={initialValue}>
19
+ {fields.map(({ value, label, ...props }) => (
20
+ <Radio
21
+ {...props}
22
+ key={value}
23
+ value={value}
24
+ label={label}
25
+ labelStyle={fieldLabelStyle}
26
+ style={fieldContainerStyle}
27
+ />
28
+ ))}
29
+ </RadioGroup>
30
+ );
31
+ };
32
+
33
+ DefaultSelectMfaTypeFormFields.displayName = 'FormFields';
34
+
35
+ export default DefaultSelectMfaTypeFormFields;
@@ -14,18 +14,19 @@ const attributeMap: AttributeMap = {
14
14
  phone_number: 'Phone Number',
15
15
  };
16
16
 
17
- const DefaultRadioFormFields = ({
18
- fields,
17
+ const DefaultVerifyUserFormFields = ({
18
+ fields = [],
19
19
  fieldContainerStyle,
20
20
  fieldLabelStyle,
21
21
  isPending,
22
22
  style,
23
23
  }: DefaultRadioFormFieldsProps): React.JSX.Element => {
24
+ // set initial value for radio field based on selected bool
25
+ const initialValue = fields.find((field) => !!field.selected)?.name;
24
26
  return (
25
- <RadioGroup disabled={isPending} style={style}>
26
- {(fields ?? []).map(({ name, value, ...props }) => {
27
+ <RadioGroup disabled={isPending} style={style} initialValue={initialValue}>
28
+ {fields.map(({ name, value, ...props }) => {
27
29
  const attributeType = attributeMap[name as keyof AttributeMap];
28
-
29
30
  return (
30
31
  <Radio
31
32
  {...props}
@@ -43,6 +44,6 @@ const DefaultRadioFormFields = ({
43
44
  );
44
45
  };
45
46
 
46
- DefaultRadioFormFields.displayName = 'FormFields';
47
+ DefaultVerifyUserFormFields.displayName = 'FormFields';
47
48
 
48
- export default DefaultRadioFormFields;
49
+ export default DefaultVerifyUserFormFields;
@@ -1,3 +1,4 @@
1
- export { default as DefaultRadioFormFields } from './DefaultRadioFormFields';
2
1
  export { default as DefaultTextFormFields } from './DefaultTextFormFields';
2
+ export { default as DefaultVerifyUserFormFields } from './DefaultVerifyUserFormFields';
3
+ export { default as DefaultSelectMfaTypeFormFields } from './DefaultSelectMfaTypeFormFields';
3
4
  export { DefaultFormFieldsComponent, DefaultFormFieldsStyle } from './types';
@@ -2,14 +2,20 @@ import { useMemo, useState } from 'react';
2
2
  import { ConsoleLogger as Logger } from 'aws-amplify/utils';
3
3
  import { ValidationError } from '@aws-amplify/ui';
4
4
 
5
- import { OnChangeText, TextFieldOnBlur, TypedField } from '../types';
5
+ import {
6
+ OnChangeText,
7
+ RadioFieldOptions,
8
+ TextFieldOnBlur,
9
+ TypedField,
10
+ } from '../types';
6
11
 
7
12
  import { UseFieldValues, UseFieldValuesParams } from './types';
8
13
  import {
9
14
  getSanitizedTextFields,
10
- getSanitizedRadioFields,
11
15
  isRadioFieldOptions,
12
16
  runFieldValidation,
17
+ getSanitizedVerifyUserFields,
18
+ getSanitizedSelectMfaTypeFields,
13
19
  } from './utils';
14
20
 
15
21
  const logger = new Logger('Authenticator');
@@ -22,11 +28,32 @@ export default function useFieldValues<FieldType extends TypedField>({
22
28
  handleSubmit,
23
29
  validationErrors,
24
30
  }: UseFieldValuesParams<FieldType>): UseFieldValues<FieldType> {
25
- const [values, setValues] = useState<Record<string, string>>({});
26
31
  const [touched, setTouched] = useState<Record<string, boolean>>({});
27
32
  const [fieldValidationErrors, setFieldValidationErrors] =
28
33
  useState<ValidationError>({});
29
- const isRadioFieldComponent = componentName === 'VerifyUser';
34
+ const isVerifyUserRoute = componentName === 'VerifyUser';
35
+ const isSelectMfaTypeRoute = componentName === 'SelectMfaType';
36
+ const isRadioFieldComponent = isVerifyUserRoute || isSelectMfaTypeRoute;
37
+
38
+ // initialize values based on route
39
+ // select mfa type screen should auto select first radio option
40
+ const [values, setValues] = useState(() => {
41
+ const result: Record<string, string> = {};
42
+ if (isSelectMfaTypeRoute) {
43
+ const initialValue = fields[0]?.value;
44
+ if (initialValue) {
45
+ result.mfa_type = initialValue;
46
+ }
47
+ }
48
+ if (isVerifyUserRoute) {
49
+ const initialValue = fields[0]?.name;
50
+ if (initialValue) {
51
+ result.unverifiedAttr = initialValue;
52
+ }
53
+ }
54
+
55
+ return result;
56
+ });
30
57
 
31
58
  const sanitizedFields = useMemo(() => {
32
59
  if (!Array.isArray(fields)) {
@@ -36,12 +63,16 @@ export default function useFieldValues<FieldType extends TypedField>({
36
63
  return [];
37
64
  }
38
65
 
39
- if (isRadioFieldComponent) {
40
- return getSanitizedRadioFields(fields, componentName);
66
+ if (isVerifyUserRoute) {
67
+ return getSanitizedVerifyUserFields(fields);
68
+ }
69
+
70
+ if (isSelectMfaTypeRoute) {
71
+ return getSanitizedSelectMfaTypeFields(fields);
41
72
  }
42
73
 
43
74
  return getSanitizedTextFields(fields, componentName);
44
- }, [componentName, fields, isRadioFieldComponent]);
75
+ }, [componentName, fields, isVerifyUserRoute, isSelectMfaTypeRoute]);
45
76
 
46
77
  const fieldsWithHandlers = sanitizedFields.map((field) => {
47
78
  if (isRadioFieldOptions(field)) {
@@ -49,11 +80,31 @@ export default function useFieldValues<FieldType extends TypedField>({
49
80
  // call `onChange` passed as radio `field` option
50
81
  field.onChange?.(value);
51
82
 
52
- // set `name` as value of 'unverifiedAttr'
53
- setValues({ unverifiedAttr: value });
83
+ // on VerifyUser route, set `name` as value of 'unverifiedAttr'
84
+ // on SelectMfaTYpe route, set `name` as value of 'mfa_type'
85
+ const fieldName = isVerifyUserRoute
86
+ ? 'unverifiedAttr'
87
+ : isSelectMfaTypeRoute
88
+ ? 'mfa_type'
89
+ : field.name;
90
+
91
+ setValues((prev) => ({ ...prev, [fieldName]: value }));
92
+ };
93
+
94
+ const result: RadioFieldOptions = {
95
+ ...field,
96
+ onChange,
54
97
  };
55
98
 
56
- return { ...field, onChange };
99
+ // bind selected boolean attribute for radio field
100
+ if (isSelectMfaTypeRoute) {
101
+ result.selected = values.mfa_type === field.value;
102
+ }
103
+ if (isVerifyUserRoute) {
104
+ result.selected = values.unverifiedAttr === field.name;
105
+ }
106
+
107
+ return result;
57
108
  }
58
109
 
59
110
  const { name, label, labelHidden, ...rest } = field;
@@ -100,18 +151,11 @@ export default function useFieldValues<FieldType extends TypedField>({
100
151
  };
101
152
  }) as FieldType[];
102
153
 
103
- const disableFormSubmit = isRadioFieldComponent
154
+ const disableFormSubmit = isVerifyUserRoute
104
155
  ? !values.unverifiedAttr
105
- : fieldsWithHandlers.some(({ required, value }) => {
106
- if (!required) {
107
- return false;
108
- }
109
-
110
- if (value) {
111
- return false;
112
- }
113
- return true;
114
- });
156
+ : isSelectMfaTypeRoute
157
+ ? !values.mfa_type
158
+ : fieldsWithHandlers.some(({ required, value }) => required && !value);
115
159
 
116
160
  const handleFormSubmit = () => {
117
161
  const submitValue = isRadioFieldComponent
@@ -31,16 +31,15 @@ export const isRadioFieldOptions = (
31
31
  field: TypedField
32
32
  ): field is RadioFieldOptions => field?.type === 'radio';
33
33
 
34
- export const getSanitizedRadioFields = (
35
- fields: TypedField[],
36
- componentName: AuthenticatorRouteComponentName
34
+ export const getSanitizedVerifyUserFields = (
35
+ fields: TypedField[]
37
36
  ): TypedField[] => {
38
37
  const values: Record<string, boolean> = {};
39
38
 
40
39
  return fields.filter((field) => {
41
40
  if (!isRadioFieldOptions(field)) {
42
41
  logger.warn(
43
- `${componentName} component does not support text fields. field with type ${field.type} has been ignored.`
42
+ `VerifyUser component does not support text fields. field with type ${field.type} has been ignored.`
44
43
  );
45
44
  return false;
46
45
  }
@@ -77,6 +76,39 @@ export const getSanitizedRadioFields = (
77
76
  });
78
77
  };
79
78
 
79
+ export const getSanitizedSelectMfaTypeFields = (
80
+ fields: TypedField[]
81
+ ): TypedField[] => {
82
+ const values: Record<string, boolean> = {};
83
+
84
+ return fields.filter((field) => {
85
+ const { value } = field;
86
+
87
+ if (!isRadioFieldOptions(field)) {
88
+ logger.warn(
89
+ `SelectMfaType component does not support non-radio fields; field with type "${field.type}" has been ignored.`
90
+ );
91
+ return false;
92
+ }
93
+
94
+ if (!value) {
95
+ logger.warn('Each field must have a value; field has been ignored.');
96
+ return false;
97
+ }
98
+
99
+ if (values[value]) {
100
+ logger.warn(
101
+ `Each field value must be unique; field with duplicate value of "${value}" has been ignored.`
102
+ );
103
+ return false;
104
+ }
105
+
106
+ values[value] = true;
107
+
108
+ return true;
109
+ });
110
+ };
111
+
80
112
  export const getSanitizedTextFields = (
81
113
  fields: TypedField[],
82
114
  componentName: AuthenticatorRouteComponentName
@@ -180,9 +212,12 @@ export function getRouteTypedFields({
180
212
 
181
213
  // `VerifyUser` does not require additional updates to the shape of `fields`
182
214
  const isVerifyUserRoute = route === 'verifyUser';
215
+ const isSelectMfaTypeRoute = route === 'selectMfaType';
183
216
  const radioFields = fields as TypedField[];
184
217
 
185
- return isVerifyUserRoute ? radioFields : getTypedFields(fields);
218
+ return isVerifyUserRoute || isSelectMfaTypeRoute
219
+ ? radioFields
220
+ : getTypedFields(fields);
186
221
  }
187
222
 
188
223
  /**
@@ -1,4 +1,19 @@
1
1
  export { default as Authenticator } from './Authenticator';
2
+ export { ContainerProps } from './common';
3
+ export {
4
+ ConfirmResetPasswordProps,
5
+ ConfirmSignInProps,
6
+ ConfirmSignUpProps,
7
+ ConfirmVerifyUserProps,
8
+ ForceNewPasswordProps,
9
+ ForgotPasswordProps,
10
+ SelectMfaTypeProps,
11
+ SetupEmailProps,
12
+ SetupTotpProps,
13
+ SignInProps,
14
+ SignUpProps,
15
+ VerifyUserProps,
16
+ } from './Defaults';
2
17
  export { AuthenticatorProps, WithAuthenticatorOptions } from './types';
3
18
  export { useAuthenticator, UseAuthenticator } from './useAuthenticator';
4
19
  export { default as withAuthenticator } from './withAuthenticator';
package/src/index.ts CHANGED
@@ -5,6 +5,18 @@ export {
5
5
  UseAuthenticator,
6
6
  withAuthenticator,
7
7
  WithAuthenticatorOptions,
8
+ ConfirmResetPasswordProps,
9
+ ConfirmSignInProps,
10
+ ConfirmSignUpProps,
11
+ ConfirmVerifyUserProps,
12
+ ForceNewPasswordProps,
13
+ ForgotPasswordProps,
14
+ SelectMfaTypeProps,
15
+ SetupEmailProps,
16
+ SetupTotpProps,
17
+ SignInProps,
18
+ SignUpProps,
19
+ VerifyUserProps,
8
20
  } from './Authenticator';
9
21
  export * from './InAppMessaging';
10
22
  export {
@@ -19,6 +19,8 @@ import { RadioProps } from '../Radio';
19
19
  import { getThemedStyles } from './styles';
20
20
  import { RadioGroupProps } from './types';
21
21
 
22
+ export const RADIO_GROUP_CONTAINER_TEST_ID = 'amplify__radio-group__container';
23
+
22
24
  export default function RadioGroup<T>({
23
25
  accessible = true,
24
26
  accessibilityRole = 'radiogroup',
@@ -73,7 +75,11 @@ export default function RadioGroup<T>({
73
75
  );
74
76
 
75
77
  return (
76
- <View {...rest} style={[themedStyle.container, containerStyle, style]}>
78
+ <View
79
+ {...rest}
80
+ style={[themedStyle.container, containerStyle, style]}
81
+ testID={RADIO_GROUP_CONTAINER_TEST_ID}
82
+ >
77
83
  <View
78
84
  accessible={accessible}
79
85
  accessibilityRole={accessibilityRole}
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const VERSION = '2.4.4';
1
+ export const VERSION = '2.5.0';