@aws-amplify/ui-react-native 2.4.5 → 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 (61) 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 +22 -0
  15. package/dist/Authenticator/common/DefaultFormFields/DefaultSelectMfaTypeFormFields.d.ts +7 -0
  16. package/dist/Authenticator/common/DefaultFormFields/DefaultSelectMfaTypeFormFields.js +12 -0
  17. package/dist/Authenticator/common/DefaultFormFields/{DefaultRadioFormFields.d.ts → DefaultVerifyUserFormFields.d.ts} +2 -2
  18. package/dist/Authenticator/common/DefaultFormFields/{DefaultRadioFormFields.js → DefaultVerifyUserFormFields.js} +7 -5
  19. package/dist/Authenticator/common/DefaultFormFields/index.d.ts +2 -1
  20. package/dist/Authenticator/common/DefaultFormFields/index.js +2 -1
  21. package/dist/Authenticator/hooks/useFieldValues/useFieldValues.js +52 -19
  22. package/dist/Authenticator/hooks/useFieldValues/utils.d.ts +2 -1
  23. package/dist/Authenticator/hooks/useFieldValues/utils.js +26 -3
  24. package/dist/Authenticator/index.d.ts +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/primitives/RadioGroup/RadioGroup.d.ts +1 -0
  27. package/dist/primitives/RadioGroup/RadioGroup.js +2 -1
  28. package/dist/version.d.ts +1 -1
  29. package/dist/version.js +1 -1
  30. package/lib/Authenticator/Authenticator.js +4 -0
  31. package/lib/Authenticator/Defaults/SelectMfaType/SelectMfaType.js +42 -0
  32. package/lib/Authenticator/Defaults/SelectMfaType/index.js +8 -0
  33. package/lib/Authenticator/Defaults/SetupEmail/SetupEmail.js +42 -0
  34. package/lib/Authenticator/Defaults/SetupEmail/index.js +8 -0
  35. package/lib/Authenticator/Defaults/VerifyUser/VerifyUser.js +1 -1
  36. package/lib/Authenticator/Defaults/index.js +5 -1
  37. package/lib/Authenticator/common/DefaultFormFields/DefaultSelectMfaTypeFormFields.js +15 -0
  38. package/lib/Authenticator/common/DefaultFormFields/{DefaultRadioFormFields.js → DefaultVerifyUserFormFields.js} +7 -5
  39. package/lib/Authenticator/common/DefaultFormFields/index.js +5 -3
  40. package/lib/Authenticator/hooks/useFieldValues/useFieldValues.js +51 -18
  41. package/lib/Authenticator/hooks/useFieldValues/utils.js +29 -5
  42. package/lib/primitives/RadioGroup/RadioGroup.js +3 -1
  43. package/lib/version.js +1 -1
  44. package/package.json +4 -4
  45. package/src/Authenticator/Authenticator.tsx +6 -0
  46. package/src/Authenticator/Defaults/SelectMfaType/SelectMfaType.tsx +87 -0
  47. package/src/Authenticator/Defaults/SelectMfaType/index.ts +1 -0
  48. package/src/Authenticator/Defaults/SetupEmail/SetupEmail.tsx +86 -0
  49. package/src/Authenticator/Defaults/SetupEmail/index.ts +1 -0
  50. package/src/Authenticator/Defaults/VerifyUser/VerifyUser.tsx +2 -2
  51. package/src/Authenticator/Defaults/index.ts +4 -0
  52. package/src/Authenticator/Defaults/types.ts +30 -0
  53. package/src/Authenticator/common/DefaultFormFields/DefaultSelectMfaTypeFormFields.tsx +35 -0
  54. package/src/Authenticator/common/DefaultFormFields/{DefaultRadioFormFields.tsx → DefaultVerifyUserFormFields.tsx} +8 -7
  55. package/src/Authenticator/common/DefaultFormFields/index.ts +2 -1
  56. package/src/Authenticator/hooks/useFieldValues/useFieldValues.ts +65 -21
  57. package/src/Authenticator/hooks/useFieldValues/utils.ts +40 -5
  58. package/src/Authenticator/index.ts +2 -0
  59. package/src/index.ts +2 -0
  60. package/src/primitives/RadioGroup/RadioGroup.tsx +7 -1
  61. package/src/version.ts +1 -1
@@ -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
  /**
@@ -7,6 +7,8 @@ export {
7
7
  ConfirmVerifyUserProps,
8
8
  ForceNewPasswordProps,
9
9
  ForgotPasswordProps,
10
+ SelectMfaTypeProps,
11
+ SetupEmailProps,
10
12
  SetupTotpProps,
11
13
  SignInProps,
12
14
  SignUpProps,
package/src/index.ts CHANGED
@@ -11,6 +11,8 @@ export {
11
11
  ConfirmVerifyUserProps,
12
12
  ForceNewPasswordProps,
13
13
  ForgotPasswordProps,
14
+ SelectMfaTypeProps,
15
+ SetupEmailProps,
14
16
  SetupTotpProps,
15
17
  SignInProps,
16
18
  SignUpProps,
@@ -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.5';
1
+ export const VERSION = '2.5.0';