@aws-amplify/ui-react-native 1.2.20 → 1.2.22

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 (113) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/Authenticator/Authenticator.d.ts +101 -148
  3. package/dist/Authenticator/Authenticator.js +2 -3
  4. package/dist/Authenticator/Defaults/ConfirmResetPassword/ConfirmResetPassword.d.ts +13 -2
  5. package/dist/Authenticator/Defaults/ConfirmResetPassword/ConfirmResetPassword.js +4 -3
  6. package/dist/Authenticator/Defaults/ConfirmSignIn/ConfirmSignIn.d.ts +13 -2
  7. package/dist/Authenticator/Defaults/ConfirmSignIn/ConfirmSignIn.js +4 -3
  8. package/dist/Authenticator/Defaults/ConfirmSignUp/ConfirmSignUp.d.ts +13 -2
  9. package/dist/Authenticator/Defaults/ConfirmSignUp/ConfirmSignUp.js +4 -3
  10. package/dist/Authenticator/Defaults/ConfirmVerifyUser/ConfirmVerifyUser.d.ts +13 -2
  11. package/dist/Authenticator/Defaults/ConfirmVerifyUser/ConfirmVerifyUser.js +4 -3
  12. package/dist/Authenticator/Defaults/ForceNewPassword/ForceNewPassword.d.ts +13 -2
  13. package/dist/Authenticator/Defaults/ForceNewPassword/ForceNewPassword.js +4 -3
  14. package/dist/Authenticator/Defaults/ResetPassword/ResetPassword.d.ts +13 -2
  15. package/dist/Authenticator/Defaults/ResetPassword/ResetPassword.js +4 -3
  16. package/dist/Authenticator/Defaults/SetupTOTP/SetupTOTP.d.ts +13 -2
  17. package/dist/Authenticator/Defaults/SetupTOTP/SetupTOTP.js +4 -3
  18. package/dist/Authenticator/Defaults/SignIn/SignIn.d.ts +13 -2
  19. package/dist/Authenticator/Defaults/SignIn/SignIn.js +4 -3
  20. package/dist/Authenticator/Defaults/SignUp/SignUp.d.ts +13 -2
  21. package/dist/Authenticator/Defaults/SignUp/SignUp.js +4 -3
  22. package/dist/Authenticator/Defaults/VerifyUser/VerifyUser.d.ts +13 -2
  23. package/dist/Authenticator/Defaults/VerifyUser/VerifyUser.js +4 -3
  24. package/dist/Authenticator/Defaults/types.d.ts +21 -20
  25. package/dist/Authenticator/common/DefaultContent/styles.js +1 -2
  26. package/dist/Authenticator/common/DefaultContent/types.d.ts +1 -1
  27. package/dist/Authenticator/common/DefaultFormFields/DefaultRadioFormFields.d.ts +7 -3
  28. package/dist/Authenticator/common/DefaultFormFields/DefaultRadioFormFields.js +4 -3
  29. package/dist/Authenticator/common/DefaultFormFields/DefaultTextFormFields.d.ts +6 -2
  30. package/dist/Authenticator/common/DefaultFormFields/DefaultTextFormFields.js +3 -3
  31. package/dist/Authenticator/common/DefaultFormFields/types.d.ts +12 -3
  32. package/dist/Authenticator/hooks/types.d.ts +3 -2
  33. package/dist/Authenticator/hooks/useFieldValues/types.d.ts +4 -1
  34. package/dist/Authenticator/hooks/useFieldValues/useFieldValues.d.ts +1 -1
  35. package/dist/Authenticator/hooks/useFieldValues/useFieldValues.js +21 -3
  36. package/dist/Authenticator/hooks/useFieldValues/utils.d.ts +10 -1
  37. package/dist/Authenticator/hooks/useFieldValues/utils.js +32 -2
  38. package/dist/primitives/Heading/styles.js +5 -5
  39. package/dist/primitives/Label/styles.js +2 -2
  40. package/dist/primitives/TextField/TextField.js +2 -1
  41. package/dist/primitives/TextField/styles.js +6 -3
  42. package/dist/primitives/TextField/types.d.ts +1 -0
  43. package/dist/theme/createTheme.js +24 -18
  44. package/dist/theme/types.d.ts +1 -1
  45. package/dist/version.d.ts +1 -1
  46. package/dist/version.js +1 -1
  47. package/jest.config.js +1 -0
  48. package/package.json +5 -5
  49. package/src/Authenticator/Authenticator.tsx +2 -6
  50. package/src/Authenticator/Defaults/ConfirmResetPassword/ConfirmResetPassword.tsx +7 -3
  51. package/src/Authenticator/Defaults/ConfirmResetPassword/__tests__/__snapshots__/ConfirmResetPassword.spec.tsx.snap +34 -30
  52. package/src/Authenticator/Defaults/ConfirmSignIn/ConfirmSignIn.tsx +7 -3
  53. package/src/Authenticator/Defaults/ConfirmSignIn/__tests__/ConfirmSignIn.spec.tsx +1 -0
  54. package/src/Authenticator/Defaults/ConfirmSignIn/__tests__/__snapshots__/ConfirmSignIn.spec.tsx.snap +14 -14
  55. package/src/Authenticator/Defaults/ConfirmSignUp/ConfirmSignUp.tsx +7 -3
  56. package/src/Authenticator/Defaults/ConfirmSignUp/__tests__/ConfirmSignUp.spec.tsx +1 -0
  57. package/src/Authenticator/Defaults/ConfirmSignUp/__tests__/__snapshots__/ConfirmSignUp.spec.tsx.snap +12 -15
  58. package/src/Authenticator/Defaults/ConfirmVerifyUser/ConfirmVerifyUser.tsx +7 -3
  59. package/src/Authenticator/Defaults/ConfirmVerifyUser/__tests__/ConfirmVerifyUser.spec.tsx +1 -0
  60. package/src/Authenticator/Defaults/ConfirmVerifyUser/__tests__/__snapshots__/ConfirmVerifyUser.spec.tsx.snap +6 -9
  61. package/src/Authenticator/Defaults/ForceNewPassword/ForceNewPassword.tsx +7 -3
  62. package/src/Authenticator/Defaults/ForceNewPassword/__tests__/__snapshots__/ForceNewPassword.spec.tsx.snap +13 -10
  63. package/src/Authenticator/Defaults/ResetPassword/ResetPassword.tsx +7 -3
  64. package/src/Authenticator/Defaults/ResetPassword/__tests__/ResetPassword.spec.tsx +1 -0
  65. package/src/Authenticator/Defaults/ResetPassword/__tests__/__snapshots__/ResetPassword.spec.tsx.snap +14 -14
  66. package/src/Authenticator/Defaults/SetupTOTP/SetupTOTP.tsx +7 -3
  67. package/src/Authenticator/Defaults/SetupTOTP/__tests__/SetupTOTP.spec.tsx +1 -0
  68. package/src/Authenticator/Defaults/SetupTOTP/__tests__/__snapshots__/SetupTOTP.spec.tsx.snap +22 -22
  69. package/src/Authenticator/Defaults/SignIn/SignIn.tsx +7 -3
  70. package/src/Authenticator/Defaults/SignIn/__tests__/SignIn.spec.tsx +1 -0
  71. package/src/Authenticator/Defaults/SignIn/__tests__/__snapshots__/SignIn.spec.tsx.snap +36 -33
  72. package/src/Authenticator/Defaults/SignUp/SignUp.tsx +7 -3
  73. package/src/Authenticator/Defaults/SignUp/__tests__/__snapshots__/SignUp.spec.tsx.snap +111 -96
  74. package/src/Authenticator/Defaults/VerifyUser/VerifyUser.tsx +7 -3
  75. package/src/Authenticator/Defaults/VerifyUser/__tests__/VerifyUser.spec.tsx +1 -0
  76. package/src/Authenticator/Defaults/VerifyUser/__tests__/__snapshots__/VerifyUser.spec.tsx.snap +16 -18
  77. package/src/Authenticator/Defaults/types.ts +63 -49
  78. package/src/Authenticator/__tests__/Authenticator.spec.tsx +16 -19
  79. package/src/Authenticator/__tests__/__snapshots__/Authenticator.spec.tsx.snap +1 -9
  80. package/src/Authenticator/__tests__/withAuthenticator.spec.tsx +1 -1
  81. package/src/Authenticator/common/DefaultContent/styles.ts +1 -2
  82. package/src/Authenticator/common/DefaultContent/types.ts +1 -4
  83. package/src/Authenticator/common/DefaultFormFields/DefaultRadioFormFields.tsx +8 -6
  84. package/src/Authenticator/common/DefaultFormFields/DefaultTextFormFields.tsx +10 -7
  85. package/src/Authenticator/common/DefaultFormFields/types.ts +15 -5
  86. package/src/Authenticator/common/DefaultHeader/__tests__/__snapshots__/DefaultHeader.spec.tsx.snap +1 -1
  87. package/src/Authenticator/common/FederatedProviderButton/__tests__/__snapshots__/FederatedProviderButton.spec.tsx.snap +4 -4
  88. package/src/Authenticator/common/FederatedProviderButtons/__tests__/__snapshots__/FederatedProviderButtons.spec.tsx.snap +4 -4
  89. package/src/Authenticator/hooks/types.ts +3 -0
  90. package/src/Authenticator/hooks/useFieldValues/__tests__/useFieldValues.spec.ts +75 -2
  91. package/src/Authenticator/hooks/useFieldValues/__tests__/utils.spec.ts +67 -1
  92. package/src/Authenticator/hooks/useFieldValues/types.ts +5 -0
  93. package/src/Authenticator/hooks/useFieldValues/useFieldValues.ts +26 -1
  94. package/src/Authenticator/hooks/useFieldValues/utils.ts +44 -1
  95. package/src/primitives/Checkbox/__tests__/__snapshots__/Checkbox.spec.tsx.snap +14 -14
  96. package/src/primitives/Divider/__tests__/__snapshots__/Divider.spec.tsx.snap +4 -4
  97. package/src/primitives/Heading/__tests__/__snapshots__/Heading.spec.tsx.snap +7 -7
  98. package/src/primitives/Heading/styles.ts +5 -5
  99. package/src/primitives/Label/__tests__/__snapshots__/Label.spec.tsx.snap +8 -8
  100. package/src/primitives/Label/styles.ts +2 -2
  101. package/src/primitives/PasswordField/__tests__/__snapshots__/PasswordField.spec.tsx.snap +25 -20
  102. package/src/primitives/PhoneNumberField/__tests__/__snapshots__/PhoneNumberField.spec.tsx.snap +6 -0
  103. package/src/primitives/Radio/__tests__/__snapshots__/Radio.spec.tsx.snap +14 -14
  104. package/src/primitives/RadioGroup/__tests__/__snapshots__/RadioGroup.spec.tsx.snap +48 -48
  105. package/src/primitives/TextField/TextField.tsx +2 -1
  106. package/src/primitives/TextField/__tests__/TextField.spec.tsx +57 -8
  107. package/src/primitives/TextField/__tests__/__snapshots__/TextField.spec.tsx.snap +61 -55
  108. package/src/primitives/TextField/styles.ts +6 -3
  109. package/src/primitives/TextField/types.ts +1 -0
  110. package/src/theme/__tests__/createTheme.spec.ts +48 -0
  111. package/src/theme/createTheme.ts +44 -21
  112. package/src/theme/types.ts +17 -16
  113. package/src/version.ts +1 -1
@@ -2,7 +2,10 @@ import { act, renderHook } from '@testing-library/react-hooks';
2
2
  import { NativeSyntheticEvent, TextInputFocusEventData } from 'react-native';
3
3
 
4
4
  import { Logger } from 'aws-amplify';
5
- import { UnverifiedContactMethodType } from '@aws-amplify/ui';
5
+ import {
6
+ UnverifiedContactMethodType,
7
+ authenticatorTextUtil,
8
+ } from '@aws-amplify/ui';
6
9
  import {
7
10
  RadioFieldOptions,
8
11
  TextFieldOptionsType,
@@ -58,6 +61,7 @@ describe('useFieldValues', () => {
58
61
  value: undefined,
59
62
  },
60
63
  ],
64
+ fieldValidationErrors: {},
61
65
  handleFormSubmit: expect.any(Function),
62
66
  });
63
67
  });
@@ -80,6 +84,7 @@ describe('useFieldValues', () => {
80
84
  value: undefined,
81
85
  },
82
86
  ],
87
+ fieldValidationErrors: {},
83
88
  handleFormSubmit: expect.any(Function),
84
89
  });
85
90
  });
@@ -95,6 +100,7 @@ describe('useFieldValues', () => {
95
100
  expect(result.current).toStrictEqual({
96
101
  disableFormSubmit: true,
97
102
  fields: [{ ...radioField, onChange: expect.any(Function) }],
103
+ fieldValidationErrors: {},
98
104
  handleFormSubmit: expect.any(Function),
99
105
  });
100
106
  });
@@ -105,6 +111,7 @@ describe('useFieldValues', () => {
105
111
  expect(result.current).toStrictEqual({
106
112
  disableFormSubmit: false,
107
113
  fields: mockfields,
114
+ fieldValidationErrors: {},
108
115
  handleFormSubmit: expect.any(Function),
109
116
  });
110
117
  });
@@ -129,7 +136,9 @@ describe('useFieldValues', () => {
129
136
  const mockEvent = {
130
137
  nativeEvent: { target: 1 },
131
138
  } as NativeSyntheticEvent<TextInputFocusEventData>;
132
- result.current.fields[0].onBlur?.(mockEvent);
139
+ act(() => {
140
+ result.current.fields[0].onBlur?.(mockEvent);
141
+ });
133
142
  expect(props.handleBlur).toHaveBeenCalledTimes(1);
134
143
  expect(props.handleBlur).toHaveBeenCalledWith({
135
144
  name: textField.name,
@@ -153,6 +162,68 @@ describe('useFieldValues', () => {
153
162
  });
154
163
  });
155
164
 
165
+ it('runs validations for email fields', () => {
166
+ const emailField = {
167
+ label: 'test',
168
+ type: 'email',
169
+ name: 'invalid_email',
170
+ value: 'test@',
171
+ } as TextFieldOptionsType;
172
+ const phoneTextField = {
173
+ type: 'phone',
174
+ name: 'testPhone',
175
+ } as TextFieldOptionsType;
176
+ const { result } = renderHook(() =>
177
+ useFieldValues({
178
+ ...props,
179
+ fields: [emailField, phoneTextField],
180
+ })
181
+ );
182
+ const mockEvent = {
183
+ nativeEvent: { target: 1 },
184
+ } as NativeSyntheticEvent<TextInputFocusEventData>;
185
+ act(() => {
186
+ result.current.fields[0].onBlur?.(mockEvent);
187
+ });
188
+ expect(props.handleBlur).toHaveBeenCalledTimes(1);
189
+ expect(props.handleBlur).toHaveBeenCalledWith({
190
+ name: emailField.name,
191
+ value: undefined,
192
+ });
193
+ expect(result.current.fieldValidationErrors).toStrictEqual({
194
+ [emailField.name]: [authenticatorTextUtil.getInvalidEmailText()],
195
+ });
196
+ });
197
+
198
+ it('runs validations for required fields', () => {
199
+ const requiredField = {
200
+ label: 'test',
201
+ type: 'password',
202
+ name: 'required',
203
+ required: true,
204
+ } as TextFieldOptionsType;
205
+ const { result } = renderHook(() =>
206
+ useFieldValues({
207
+ ...props,
208
+ fields: [requiredField],
209
+ })
210
+ );
211
+ const mockEvent = {
212
+ nativeEvent: { target: 1 },
213
+ } as NativeSyntheticEvent<TextInputFocusEventData>;
214
+ act(() => {
215
+ result.current.fields[0].onBlur?.(mockEvent);
216
+ });
217
+ expect(props.handleBlur).toHaveBeenCalledTimes(1);
218
+ expect(props.handleBlur).toHaveBeenCalledWith({
219
+ name: requiredField.name,
220
+ value: undefined,
221
+ });
222
+ expect(result.current.fieldValidationErrors).toStrictEqual({
223
+ [requiredField.name]: [authenticatorTextUtil.getRequiredFieldText()],
224
+ });
225
+ });
226
+
156
227
  it('calls expected handlers for radios', () => {
157
228
  const { result } = renderHook(() =>
158
229
  useFieldValues({
@@ -234,6 +305,7 @@ describe('useFieldValues', () => {
234
305
  value: undefined,
235
306
  },
236
307
  ],
308
+ fieldValidationErrors: {},
237
309
  handleFormSubmit: expect.any(Function),
238
310
  });
239
311
  });
@@ -267,6 +339,7 @@ describe('useFieldValues', () => {
267
339
  value: mockValue,
268
340
  },
269
341
  ],
342
+ fieldValidationErrors: {},
270
343
  handleFormSubmit: expect.any(Function),
271
344
  });
272
345
  });
@@ -1,10 +1,12 @@
1
1
  import { Logger } from 'aws-amplify';
2
- import { TypedField } from '../../types';
2
+ import { authenticatorTextUtil } from '@aws-amplify/ui';
3
3
 
4
+ import { TextFieldOptionsType, TypedField } from '../../types';
4
5
  import {
5
6
  getRouteTypedFields,
6
7
  getSanitizedRadioFields,
7
8
  getSanitizedTextFields,
9
+ runFieldValidation,
8
10
  } from '../utils';
9
11
 
10
12
  const warnSpy = jest.spyOn(Logger.prototype, 'warn');
@@ -214,3 +216,67 @@ describe('getRouteTypedFields', () => {
214
216
  expect(fields).toStrictEqual(expected);
215
217
  });
216
218
  });
219
+
220
+ describe('runFieldValidation', () => {
221
+ const { getInvalidEmailText, getRequiredFieldText } = authenticatorTextUtil;
222
+ const field: TextFieldOptionsType = {
223
+ required: true,
224
+ type: 'email',
225
+ name: 'email',
226
+ };
227
+
228
+ it('should return an empty array when no errors are found', () => {
229
+ const value = 'test@example.com';
230
+ const stateValidations = {};
231
+
232
+ const result = runFieldValidation(field, value, stateValidations);
233
+
234
+ expect(result).toEqual([]);
235
+ });
236
+
237
+ it('should return an array with the required field error when value is missing', () => {
238
+ const value = undefined;
239
+ const stateValidations = {};
240
+
241
+ const result = runFieldValidation(field, value, stateValidations);
242
+
243
+ expect(result).toEqual([getRequiredFieldText(), getInvalidEmailText()]);
244
+ });
245
+
246
+ it('should return an array with the invalid email error when email value is invalid', () => {
247
+ const value = 'invalid-email';
248
+ const stateValidations = {};
249
+
250
+ const result = runFieldValidation(field, value, stateValidations);
251
+
252
+ expect(result).toEqual([getInvalidEmailText()]);
253
+ });
254
+
255
+ it('should include state machine validation errors in the result', () => {
256
+ const value = 'test@example.com';
257
+ const errorMessage = 'Email already exists.';
258
+ const stateValidations = {
259
+ email: errorMessage,
260
+ };
261
+
262
+ const result = runFieldValidation(field, value, stateValidations);
263
+
264
+ expect(result).toEqual([errorMessage]);
265
+ });
266
+
267
+ it('should concatenate state machine validation errors with other errors', () => {
268
+ const value = undefined;
269
+ const errorMessage = 'Email already exists.';
270
+ const stateValidations = {
271
+ email: errorMessage,
272
+ };
273
+
274
+ const result = runFieldValidation(field, value, stateValidations);
275
+
276
+ expect(result).toEqual([
277
+ getRequiredFieldText(),
278
+ getInvalidEmailText(),
279
+ errorMessage,
280
+ ]);
281
+ });
282
+ });
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  AuthenticatorComponentDefaultProps,
3
3
  AuthenticatorRouteComponentName,
4
+ AuthenticatorMachineContext,
4
5
  } from '@aws-amplify/ui-react-core';
6
+ import { ValidationError } from '@aws-amplify/ui';
5
7
 
6
8
  import { TypedField } from '../types';
7
9
 
@@ -26,10 +28,13 @@ export interface UseFieldValuesParams<FieldType extends TypedField> {
26
28
  * machine "SUBMIT"" event handler, validates `field` value against machine validation rules
27
29
  */
28
30
  handleSubmit: MachineEventHandlers['handleSubmit'];
31
+
32
+ validationErrors?: AuthenticatorMachineContext['validationErrors'];
29
33
  }
30
34
 
31
35
  export interface UseFieldValues<FieldType extends TypedField> {
32
36
  fields: FieldType[]; // return either radio or text
37
+ fieldValidationErrors: ValidationError | undefined;
33
38
  disableFormSubmit: boolean;
34
39
  handleFormSubmit: () => void;
35
40
  }
@@ -1,5 +1,6 @@
1
1
  import { useMemo, useState } from 'react';
2
2
  import { Logger } from 'aws-amplify';
3
+ import { ValidationError } from '@aws-amplify/ui';
3
4
 
4
5
  import { OnChangeText, TextFieldOnBlur, TypedField } from '../types';
5
6
 
@@ -8,6 +9,7 @@ import {
8
9
  getSanitizedTextFields,
9
10
  getSanitizedRadioFields,
10
11
  isRadioFieldOptions,
12
+ runFieldValidation,
11
13
  } from './utils';
12
14
 
13
15
  const logger = new Logger('Authenticator');
@@ -18,8 +20,12 @@ export default function useFieldValues<FieldType extends TypedField>({
18
20
  handleBlur,
19
21
  handleChange,
20
22
  handleSubmit,
23
+ validationErrors,
21
24
  }: UseFieldValuesParams<FieldType>): UseFieldValues<FieldType> {
22
25
  const [values, setValues] = useState<Record<string, string>>({});
26
+ const [touched, setTouched] = useState<Record<string, boolean>>({});
27
+ const [fieldValidationErrors, setFieldValidationErrors] =
28
+ useState<ValidationError>({});
23
29
  const isRadioFieldComponent = componentName === 'VerifyUser';
24
30
 
25
31
  const sanitizedFields = useMemo(() => {
@@ -53,11 +59,18 @@ export default function useFieldValues<FieldType extends TypedField>({
53
59
  const { name, label, labelHidden, ...rest } = field;
54
60
 
55
61
  const onBlur: TextFieldOnBlur = (event) => {
62
+ setTouched({ ...touched, [name]: true });
63
+
56
64
  // call `onBlur` passed as text `field` option
57
65
  field.onBlur?.(event);
58
66
 
59
67
  // call machine blur handler
60
68
  handleBlur({ name, value: values[name] });
69
+
70
+ setFieldValidationErrors({
71
+ ...fieldValidationErrors,
72
+ [name]: runFieldValidation(field, values[name], validationErrors),
73
+ });
61
74
  };
62
75
 
63
76
  const onChangeText: OnChangeText = (value) => {
@@ -67,6 +80,13 @@ export default function useFieldValues<FieldType extends TypedField>({
67
80
  // call machine change handler
68
81
  handleChange({ name, value });
69
82
 
83
+ if (touched[name]) {
84
+ setFieldValidationErrors({
85
+ ...fieldValidationErrors,
86
+ [name]: runFieldValidation(field, value, validationErrors),
87
+ });
88
+ }
89
+
70
90
  setValues({ ...values, [name]: value });
71
91
  };
72
92
 
@@ -112,5 +132,10 @@ export default function useFieldValues<FieldType extends TypedField>({
112
132
  handleSubmit?.(submitValue);
113
133
  };
114
134
 
115
- return { fields: fieldsWithHandlers, disableFormSubmit, handleFormSubmit };
135
+ return {
136
+ fields: fieldsWithHandlers,
137
+ disableFormSubmit,
138
+ fieldValidationErrors: { ...fieldValidationErrors, ...validationErrors },
139
+ handleFormSubmit,
140
+ };
116
141
  }
@@ -1,7 +1,11 @@
1
1
  import { Logger } from 'aws-amplify';
2
2
  import {
3
+ authenticatorTextUtil,
4
+ isString,
3
5
  isUnverifiedContactMethodType,
6
+ isValidEmail,
4
7
  UnverifiedContactMethodType,
8
+ ValidationError,
5
9
  } from '@aws-amplify/ui';
6
10
  import {
7
11
  AuthenticatorLegacyField,
@@ -14,12 +18,15 @@ import {
14
18
  AuthenticatorFieldTypeKey,
15
19
  MachineFieldTypeKey,
16
20
  RadioFieldOptions,
21
+ TextFieldOptionsType,
17
22
  TypedField,
18
23
  } from '../types';
19
24
  import { KEY_ALLOW_LIST } from './constants';
20
25
 
21
26
  const logger = new Logger('Authenticator');
22
27
 
28
+ const { getInvalidEmailText, getRequiredFieldText } = authenticatorTextUtil;
29
+
23
30
  export const isRadioFieldOptions = (
24
31
  field: TypedField
25
32
  ): field is RadioFieldOptions => field?.type === 'radio';
@@ -109,7 +116,8 @@ const isKeyAllowed = (key: string) =>
109
116
 
110
117
  const isValidMachineFieldType = (
111
118
  type: string | undefined
112
- ): type is MachineFieldTypeKey => type === 'password' || type === 'tel';
119
+ ): type is MachineFieldTypeKey =>
120
+ type === 'password' || type === 'tel' || type == 'email';
113
121
 
114
122
  const getFieldType = (type: string | undefined): AuthenticatorFieldTypeKey => {
115
123
  if (isValidMachineFieldType(type)) {
@@ -176,3 +184,38 @@ export function getRouteTypedFields({
176
184
 
177
185
  return isVerifyUserRoute ? radioFields : getTypedFields(fields);
178
186
  }
187
+
188
+ /**
189
+ *
190
+ * @param {TextFieldOptionsType} field text field type
191
+ * @param {string | undefined} value text field value
192
+ * @param {string[]} stateValidations validation errors array from state machine
193
+ * @returns {string[]} field errors array
194
+ */
195
+ export const runFieldValidation = (
196
+ field: TextFieldOptionsType,
197
+ value: string | undefined,
198
+ stateValidations: ValidationError | undefined
199
+ ): string[] => {
200
+ const fieldErrors: string[] = [];
201
+ if (field.required && !value) {
202
+ fieldErrors.push(getRequiredFieldText());
203
+ }
204
+ if (field.type === 'email') {
205
+ if (!isValidEmail(value)) {
206
+ fieldErrors.push(getInvalidEmailText());
207
+ }
208
+ }
209
+
210
+ // add state machine validation errors, if any
211
+ const stateFieldValidation = stateValidations?.[field.name];
212
+ if (stateFieldValidation) {
213
+ if (isString(stateFieldValidation)) {
214
+ fieldErrors.push(stateFieldValidation);
215
+ } else {
216
+ return fieldErrors.concat(stateFieldValidation);
217
+ }
218
+ }
219
+
220
+ return fieldErrors;
221
+ };
@@ -51,9 +51,9 @@ exports[`Checkbox applies label position prop 1`] = `
51
51
  style={
52
52
  Array [
53
53
  Object {
54
- "fontSize": 14,
54
+ "fontSize": 16,
55
55
  "fontWeight": "400",
56
- "lineHeight": 21,
56
+ "lineHeight": 24,
57
57
  },
58
58
  Object {
59
59
  "color": "hsl(210, 50%, 10%)",
@@ -120,9 +120,9 @@ exports[`Checkbox applies theme and style props 1`] = `
120
120
  style={
121
121
  Array [
122
122
  Object {
123
- "fontSize": 14,
123
+ "fontSize": 16,
124
124
  "fontWeight": "400",
125
- "lineHeight": 21,
125
+ "lineHeight": 24,
126
126
  },
127
127
  Object {
128
128
  "color": "hsl(210, 50%, 10%)",
@@ -193,9 +193,9 @@ exports[`Checkbox renders as expected when disabled 1`] = `
193
193
  style={
194
194
  Array [
195
195
  Object {
196
- "fontSize": 14,
196
+ "fontSize": 16,
197
197
  "fontWeight": "400",
198
- "lineHeight": 21,
198
+ "lineHeight": 24,
199
199
  },
200
200
  Object {
201
201
  "color": "hsl(210, 50%, 10%)",
@@ -260,9 +260,9 @@ exports[`Checkbox renders as expected when passing a number to the size prop 1`]
260
260
  style={
261
261
  Array [
262
262
  Object {
263
- "fontSize": 14,
263
+ "fontSize": 16,
264
264
  "fontWeight": "400",
265
- "lineHeight": 21,
265
+ "lineHeight": 24,
266
266
  },
267
267
  Object {
268
268
  "color": "hsl(210, 50%, 10%)",
@@ -327,9 +327,9 @@ exports[`Checkbox renders as expected when selected is false 1`] = `
327
327
  style={
328
328
  Array [
329
329
  Object {
330
- "fontSize": 14,
330
+ "fontSize": 16,
331
331
  "fontWeight": "400",
332
- "lineHeight": 21,
332
+ "lineHeight": 24,
333
333
  },
334
334
  Object {
335
335
  "color": "hsl(210, 50%, 10%)",
@@ -394,9 +394,9 @@ exports[`Checkbox renders as expected when selected is true 1`] = `
394
394
  style={
395
395
  Array [
396
396
  Object {
397
- "fontSize": 14,
397
+ "fontSize": 16,
398
398
  "fontWeight": "400",
399
- "lineHeight": 21,
399
+ "lineHeight": 24,
400
400
  },
401
401
  Object {
402
402
  "color": "hsl(210, 50%, 10%)",
@@ -461,9 +461,9 @@ exports[`Checkbox renders as expected with custom accessibilityRole 1`] = `
461
461
  style={
462
462
  Array [
463
463
  Object {
464
- "fontSize": 14,
464
+ "fontSize": 16,
465
465
  "fontWeight": "400",
466
- "lineHeight": 21,
466
+ "lineHeight": 24,
467
467
  },
468
468
  Object {
469
469
  "color": "hsl(210, 50%, 10%)",
@@ -32,9 +32,9 @@ exports[`Divider applies theme and style props 1`] = `
32
32
  style={
33
33
  Array [
34
34
  Object {
35
- "fontSize": 14,
35
+ "fontSize": 16,
36
36
  "fontWeight": "400",
37
- "lineHeight": 21,
37
+ "lineHeight": 24,
38
38
  },
39
39
  Object {
40
40
  "color": "hsl(210, 50%, 10%)",
@@ -101,9 +101,9 @@ exports[`Divider renders as expected with label 1`] = `
101
101
  style={
102
102
  Array [
103
103
  Object {
104
- "fontSize": 14,
104
+ "fontSize": 16,
105
105
  "fontWeight": "400",
106
- "lineHeight": 21,
106
+ "lineHeight": 24,
107
107
  },
108
108
  Object {
109
109
  "color": "hsl(210, 50%, 10%)",
@@ -10,7 +10,7 @@ exports[`Heading applies theme and style props 1`] = `
10
10
  },
11
11
  Object {
12
12
  "fontSize": 14,
13
- "fontWeight": "900",
13
+ "fontWeight": "700",
14
14
  "lineHeight": 21,
15
15
  },
16
16
  Object {
@@ -33,7 +33,7 @@ exports[`Heading renders a level 1 Heading as expected 1`] = `
33
33
  },
34
34
  Object {
35
35
  "fontSize": 40,
36
- "fontWeight": "100",
36
+ "fontWeight": "300",
37
37
  "lineHeight": 60,
38
38
  },
39
39
  undefined,
@@ -54,7 +54,7 @@ exports[`Heading renders a level 2 Heading as expected 1`] = `
54
54
  },
55
55
  Object {
56
56
  "fontSize": 32,
57
- "fontWeight": "200",
57
+ "fontWeight": "400",
58
58
  "lineHeight": 48,
59
59
  },
60
60
  undefined,
@@ -75,7 +75,7 @@ exports[`Heading renders a level 3 Heading as expected 1`] = `
75
75
  },
76
76
  Object {
77
77
  "fontSize": 24,
78
- "fontWeight": "300",
78
+ "fontWeight": "500",
79
79
  "lineHeight": 36,
80
80
  },
81
81
  undefined,
@@ -117,7 +117,7 @@ exports[`Heading renders a level 5 Heading as expected 1`] = `
117
117
  },
118
118
  Object {
119
119
  "fontSize": 16,
120
- "fontWeight": "700",
120
+ "fontWeight": "600",
121
121
  "lineHeight": 24,
122
122
  },
123
123
  undefined,
@@ -138,7 +138,7 @@ exports[`Heading renders a level 6 Heading as expected 1`] = `
138
138
  },
139
139
  Object {
140
140
  "fontSize": 14,
141
- "fontWeight": "900",
141
+ "fontWeight": "700",
142
142
  "lineHeight": 21,
143
143
  },
144
144
  undefined,
@@ -159,7 +159,7 @@ exports[`Heading renders a level 6 Heading by default 1`] = `
159
159
  },
160
160
  Object {
161
161
  "fontSize": 14,
162
- "fontWeight": "900",
162
+ "fontWeight": "700",
163
163
  "lineHeight": 21,
164
164
  },
165
165
  undefined,
@@ -17,19 +17,19 @@ export const getThemedStyles = (theme: StrictTheme): HeadingStyles => {
17
17
  },
18
18
  1: {
19
19
  fontSize: fontSizes.xxxl,
20
- fontWeight: fontWeights.hairline,
20
+ fontWeight: fontWeights.light,
21
21
  lineHeight: getLineHeight(fontSizes.xxxl),
22
22
  ...components?.heading?.[1],
23
23
  },
24
24
  2: {
25
25
  fontSize: fontSizes.xxl,
26
- fontWeight: fontWeights.thin,
26
+ fontWeight: fontWeights.normal,
27
27
  lineHeight: getLineHeight(fontSizes.xxl),
28
28
  ...components?.heading?.[2],
29
29
  },
30
30
  3: {
31
31
  fontSize: fontSizes.xl,
32
- fontWeight: fontWeights.light,
32
+ fontWeight: fontWeights.medium,
33
33
  lineHeight: getLineHeight(fontSizes.xl),
34
34
  ...components?.heading?.[3],
35
35
  },
@@ -41,13 +41,13 @@ export const getThemedStyles = (theme: StrictTheme): HeadingStyles => {
41
41
  },
42
42
  5: {
43
43
  fontSize: fontSizes.medium,
44
- fontWeight: fontWeights.bold,
44
+ fontWeight: fontWeights.semibold,
45
45
  lineHeight: getLineHeight(fontSizes.medium),
46
46
  ...components?.heading?.[5],
47
47
  },
48
48
  6: {
49
49
  fontSize: fontSizes.small,
50
- fontWeight: fontWeights.black,
50
+ fontWeight: fontWeights.bold,
51
51
  lineHeight: getLineHeight(fontSizes.small),
52
52
  ...components?.heading?.[6],
53
53
  },
@@ -6,9 +6,9 @@ exports[`Label applies accessibility role 1`] = `
6
6
  style={
7
7
  Array [
8
8
  Object {
9
- "fontSize": 14,
9
+ "fontSize": 16,
10
10
  "fontWeight": "400",
11
- "lineHeight": 21,
11
+ "lineHeight": 24,
12
12
  },
13
13
  Object {
14
14
  "color": "hsl(210, 50%, 10%)",
@@ -28,9 +28,9 @@ exports[`Label renders a default Label 1`] = `
28
28
  style={
29
29
  Array [
30
30
  Object {
31
- "fontSize": 14,
31
+ "fontSize": 16,
32
32
  "fontWeight": "400",
33
- "lineHeight": 21,
33
+ "lineHeight": 24,
34
34
  },
35
35
  Object {
36
36
  "color": "hsl(210, 50%, 10%)",
@@ -50,9 +50,9 @@ exports[`Label should apply theme and style props 1`] = `
50
50
  style={
51
51
  Array [
52
52
  Object {
53
- "fontSize": 14,
53
+ "fontSize": 16,
54
54
  "fontWeight": "400",
55
- "lineHeight": 21,
55
+ "lineHeight": 24,
56
56
  },
57
57
  Object {
58
58
  "color": "hsl(210, 50%, 10%)",
@@ -74,9 +74,9 @@ exports[`Label should apply variant styles 1`] = `
74
74
  style={
75
75
  Array [
76
76
  Object {
77
- "fontSize": 14,
77
+ "fontSize": 16,
78
78
  "fontWeight": "400",
79
- "lineHeight": 21,
79
+ "lineHeight": 24,
80
80
  },
81
81
  Object {
82
82
  "color": "hsl(130, 27%, 29%)",
@@ -12,9 +12,9 @@ export const getThemedStyles = (theme: StrictTheme): LabelStyles => {
12
12
 
13
13
  return StyleSheet.create({
14
14
  text: {
15
- fontSize: fontSizes.small,
15
+ fontSize: fontSizes.medium,
16
16
  fontWeight: fontWeights.normal,
17
- lineHeight: getLineHeight(fontSizes.small),
17
+ lineHeight: getLineHeight(fontSizes.medium),
18
18
  ...components?.label?.text,
19
19
  },
20
20
  primary: {