@aws-amplify/ui-react-core 2.1.32 → 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.
- package/dist/esm/Authenticator/context/AuthenticatorProvider.mjs +5 -6
- package/dist/esm/Authenticator/hooks/constants.mjs +4 -4
- package/dist/esm/Authenticator/hooks/useAuthenticator/useAuthenticator.mjs +14 -11
- package/dist/esm/Authenticator/hooks/useAuthenticator/utils.mjs +10 -18
- package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/constants.mjs +7 -4
- package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.mjs +6 -6
- package/dist/esm/Authenticator/hooks/useAuthenticatorRoute/utils.mjs +47 -18
- package/dist/esm/Authenticator/hooks/utils.mjs +2 -2
- package/dist/esm/components/FormCore/FormProvider.mjs +15 -0
- package/dist/esm/components/FormCore/useField.mjs +20 -0
- package/dist/esm/components/FormCore/useForm.mjs +51 -0
- package/dist/esm/components/FormCore/withFormProvider.mjs +15 -0
- package/dist/esm/hooks/useSetUserAgent.mjs +15 -0
- package/dist/esm/hooks/useTimeout.mjs +22 -0
- package/dist/esm/index.mjs +7 -0
- package/dist/esm/utils/createContextUtilities.mjs +80 -0
- package/dist/index.js +284 -96
- package/dist/types/Authenticator/hooks/types.d.ts +10 -7
- package/dist/types/Authenticator/hooks/useAuthenticator/types.d.ts +1 -3
- package/dist/types/Authenticator/hooks/useAuthenticator/utils.d.ts +2 -3
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/types.d.ts +3 -3
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.d.ts +2 -2
- package/dist/types/Authenticator/hooks/useAuthenticatorRoute/utils.d.ts +2 -2
- package/dist/types/components/FormCore/FormProvider.d.ts +4 -0
- package/dist/types/components/FormCore/index.d.ts +5 -0
- package/dist/types/components/FormCore/types.d.ts +217 -0
- package/dist/types/components/FormCore/useControlledField.d.ts +9 -0
- package/dist/types/components/FormCore/useField.d.ts +9 -0
- package/dist/types/components/FormCore/useForm.d.ts +12 -0
- package/dist/types/components/FormCore/withFormProvider.d.ts +8 -0
- package/dist/types/components/index.d.ts +1 -0
- package/dist/types/hooks/index.d.ts +2 -0
- package/dist/types/hooks/useSetUserAgent.d.ts +2 -0
- package/dist/types/hooks/useTimeout.d.ts +4 -0
- package/dist/types/index.d.ts +3 -2
- package/dist/types/types/index.d.ts +1 -1
- package/dist/types/types/types.d.ts +2 -0
- package/dist/types/utils/createContextUtilities.d.ts +26 -18
- package/package.json +11 -29
- package/src/Authenticator/context/AuthenticatorContext.tsx +17 -0
- package/src/Authenticator/context/AuthenticatorProvider.tsx +82 -0
- package/src/Authenticator/context/index.ts +2 -0
- package/src/Authenticator/hooks/constants.ts +30 -0
- package/src/Authenticator/hooks/index.ts +5 -0
- package/src/Authenticator/hooks/types.ts +218 -0
- package/src/Authenticator/hooks/useAuthenticator/__mock__/useAuthenticator.ts +66 -0
- package/src/Authenticator/hooks/useAuthenticator/constants.ts +2 -0
- package/src/Authenticator/hooks/useAuthenticator/index.ts +2 -0
- package/src/Authenticator/hooks/useAuthenticator/types.ts +48 -0
- package/src/Authenticator/hooks/useAuthenticator/useAuthenticator.ts +72 -0
- package/src/Authenticator/hooks/useAuthenticator/utils.ts +97 -0
- package/src/Authenticator/hooks/useAuthenticatorInitMachine/index.ts +1 -0
- package/src/Authenticator/hooks/useAuthenticatorInitMachine/useAuthenticatorInitMachine.tsx +25 -0
- package/src/Authenticator/hooks/useAuthenticatorRoute/constants.ts +107 -0
- package/src/Authenticator/hooks/useAuthenticatorRoute/index.ts +2 -0
- package/src/Authenticator/hooks/useAuthenticatorRoute/types.ts +111 -0
- package/src/Authenticator/hooks/useAuthenticatorRoute/useAuthenticatorRoute.ts +126 -0
- package/src/Authenticator/hooks/useAuthenticatorRoute/utils.ts +204 -0
- package/src/Authenticator/hooks/utils.ts +38 -0
- package/src/Authenticator/index.ts +23 -0
- package/src/components/FormCore/FormProvider.tsx +37 -0
- package/src/components/FormCore/index.ts +13 -0
- package/src/components/FormCore/types.ts +277 -0
- package/src/components/FormCore/useControlledField.ts +73 -0
- package/src/components/FormCore/useField.ts +25 -0
- package/src/components/FormCore/useForm.ts +84 -0
- package/src/components/FormCore/withFormProvider.tsx +31 -0
- package/src/components/RenderNothing/RenderNothing.tsx +6 -0
- package/src/components/RenderNothing/index.ts +1 -0
- package/src/components/index.ts +15 -0
- package/src/hooks/index.ts +8 -0
- package/src/hooks/useDeprecationWarning.ts +27 -0
- package/src/hooks/useHasValueUpdated.ts +28 -0
- package/src/hooks/usePreviousValue.ts +15 -0
- package/src/hooks/useSetUserAgent.ts +18 -0
- package/src/hooks/useTimeout.ts +30 -0
- package/src/index.ts +48 -0
- package/src/types/index.ts +1 -0
- package/src/types/types.ts +3 -0
- package/src/utils/createContextUtilities.tsx +131 -0
- package/src/utils/index.ts +1 -0
- package/dist/esm/node_modules/tslib/tslib.es6.mjs +0 -38
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { DefaultValues } from 'react-hook-form';
|
|
3
|
+
|
|
4
|
+
export interface FormValues {
|
|
5
|
+
[k: string]: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type FocusHandler = (event?: any) => void;
|
|
9
|
+
export type ChangeHandler = (event?: any) => void;
|
|
10
|
+
|
|
11
|
+
export type SubmitHandler<Values extends FormValues = FormValues> = (
|
|
12
|
+
values: Values,
|
|
13
|
+
event?: React.BaseSyntheticEvent
|
|
14
|
+
) => void;
|
|
15
|
+
|
|
16
|
+
type RefCallback = (node: any) => void;
|
|
17
|
+
|
|
18
|
+
export interface SetFormValueParams<Name extends string = string> {
|
|
19
|
+
/**
|
|
20
|
+
* `Form` value `name`
|
|
21
|
+
*/
|
|
22
|
+
name: Name;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* `value` to be applied
|
|
26
|
+
*/
|
|
27
|
+
value: string;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Whether validation should be ran
|
|
31
|
+
*/
|
|
32
|
+
shouldValidate?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type SetFormValue<Name extends string = string> = (
|
|
36
|
+
params: SetFormValueParams<Name>
|
|
37
|
+
) => void;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* `Field` validator callback
|
|
41
|
+
*
|
|
42
|
+
* @param value current `Field` value`
|
|
43
|
+
* @param values current `Form` values
|
|
44
|
+
* @returns `string` message on invalid `Field`, `undefined` on valid
|
|
45
|
+
*/
|
|
46
|
+
export type Validator<Values extends FormValues = FormValues> = (
|
|
47
|
+
value: string,
|
|
48
|
+
values: Values
|
|
49
|
+
) => string | undefined;
|
|
50
|
+
|
|
51
|
+
export type Validate<Values extends FormValues = FormValues> =
|
|
52
|
+
| Validator<Values>
|
|
53
|
+
| Record<string, Validator<Values>>;
|
|
54
|
+
|
|
55
|
+
export interface RegisterFieldParams<Values extends FormValues = FormValues> {
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
name: string;
|
|
58
|
+
onBlur?: FocusHandler;
|
|
59
|
+
onChange?: ChangeHandler;
|
|
60
|
+
validate?: Validate<Values>;
|
|
61
|
+
value?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface UseFormParams<
|
|
65
|
+
Values extends FormValues = FormValues,
|
|
66
|
+
OnSubmit extends SubmitHandler<Values> = SubmitHandler<Values>
|
|
67
|
+
> {
|
|
68
|
+
/**
|
|
69
|
+
* Custom error message provided to `Error` on call to `useForm` outside `FormProvider`
|
|
70
|
+
*/
|
|
71
|
+
errorMessage?: string;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Submit event handler
|
|
75
|
+
*/
|
|
76
|
+
onSubmit?: OnSubmit;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* `Form` aware `Field` props to be provided to UI components
|
|
81
|
+
*/
|
|
82
|
+
interface RegisterProps<Name extends string = string> {
|
|
83
|
+
disabled?: boolean;
|
|
84
|
+
name: Name;
|
|
85
|
+
onBlur: FocusHandler;
|
|
86
|
+
onChange: ChangeHandler;
|
|
87
|
+
ref: RefCallback;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
interface FieldState {
|
|
91
|
+
errorMessage: string | undefined;
|
|
92
|
+
hasError: boolean;
|
|
93
|
+
invalid: boolean;
|
|
94
|
+
isDirty: boolean;
|
|
95
|
+
isTouched: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export type UseForm<Values extends FormValues = FormValues> = {
|
|
99
|
+
/**
|
|
100
|
+
* Get `Field` state of `name`
|
|
101
|
+
*/
|
|
102
|
+
getFieldState: (name: string) => FieldState;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get current `Form` values
|
|
106
|
+
*/
|
|
107
|
+
getValues: () => FormValues;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* `Form` validity state
|
|
111
|
+
*/
|
|
112
|
+
isValid: boolean;
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Registers `name` to `Form` values, returns `Form` aware `Field` handlers and `ref`
|
|
116
|
+
*/
|
|
117
|
+
registerField: (params: RegisterFieldParams) => RegisterProps;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Reset `Form` values
|
|
121
|
+
*/
|
|
122
|
+
reset: (values: Values) => void;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Sets `Form` value of `name` param to provided `value`
|
|
126
|
+
*/
|
|
127
|
+
setFormValue: SetFormValue;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* `Form` submit callback prop
|
|
131
|
+
*
|
|
132
|
+
* @usage
|
|
133
|
+
* ```tsx
|
|
134
|
+
* const { onSubmit } = useForm();
|
|
135
|
+
*
|
|
136
|
+
* <form onSubmit={onSubmit} />
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
onSubmit: (e?: React.BaseSyntheticEvent) => void;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export type FormHandle<Values extends FormValues = FormValues> = {
|
|
143
|
+
/**
|
|
144
|
+
* Get current `Form` values
|
|
145
|
+
*/
|
|
146
|
+
getValues: () => Values;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Reset `Form` values to default values
|
|
150
|
+
*/
|
|
151
|
+
reset: () => void;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
type ValidationMode = 'onBlur' | 'onChange' | 'onSubmit' | 'onTouched' | 'all';
|
|
155
|
+
|
|
156
|
+
export interface FormProviderProps<Values extends FormValues = FormValues> {
|
|
157
|
+
/**
|
|
158
|
+
* `Form` children
|
|
159
|
+
*/
|
|
160
|
+
children?: React.ReactNode;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* `Form` default values
|
|
164
|
+
*/
|
|
165
|
+
defaultValues?: DefaultValues<Values>;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Validation mode applied to `Field` components:
|
|
169
|
+
*
|
|
170
|
+
* - `onTouched`: Validate on first blur event and every subsequent change event
|
|
171
|
+
* - `onBlur`: validate on blur events only
|
|
172
|
+
* - `onChange`: validate on change events, non-performant
|
|
173
|
+
* - `all`: validate on blur and change events
|
|
174
|
+
*
|
|
175
|
+
* @default
|
|
176
|
+
* "onTouched"
|
|
177
|
+
*/
|
|
178
|
+
mode?: ValidationMode;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* For use with React only.
|
|
183
|
+
*/
|
|
184
|
+
export interface UseField<Name extends string = string>
|
|
185
|
+
extends FieldState,
|
|
186
|
+
RegisterProps {
|
|
187
|
+
name: Name;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* For use with React only.
|
|
192
|
+
*/
|
|
193
|
+
export interface UseFieldParams<
|
|
194
|
+
OnBlur extends FocusHandler | undefined,
|
|
195
|
+
OnChange extends ChangeHandler | undefined,
|
|
196
|
+
Values extends FormValues = FormValues
|
|
197
|
+
> {
|
|
198
|
+
/**
|
|
199
|
+
* Controlled `disabled` state
|
|
200
|
+
*/
|
|
201
|
+
disabled?: boolean;
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Controlled blur event handler
|
|
205
|
+
*/
|
|
206
|
+
onBlur?: OnBlur;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Controlled change event handler
|
|
210
|
+
*/
|
|
211
|
+
onChange?: OnChange;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* `Field` name, must be unique
|
|
215
|
+
*/
|
|
216
|
+
name: string;
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* `Field` validation handler. Accepts a callback function or an
|
|
220
|
+
* object of callback functions to validate against
|
|
221
|
+
*
|
|
222
|
+
* @usage
|
|
223
|
+
* ```tsx
|
|
224
|
+
*
|
|
225
|
+
* // validate `password` and `confim_pasword` values match
|
|
226
|
+
* const validate = (value: string, values: Values) =>
|
|
227
|
+
* value === values['confirm_password']
|
|
228
|
+
* ? undefined
|
|
229
|
+
* : 'Passwords must match!';
|
|
230
|
+
*
|
|
231
|
+
*
|
|
232
|
+
* const passwordProps = useField({ name: 'password' });
|
|
233
|
+
*
|
|
234
|
+
* const confirmPasswordProps = useField({
|
|
235
|
+
* name: 'confirm_password',
|
|
236
|
+
* validate
|
|
237
|
+
* });
|
|
238
|
+
*
|
|
239
|
+
* return (
|
|
240
|
+
* <>
|
|
241
|
+
* <TextField {...passwordProps} />
|
|
242
|
+
* <TextField {...confirmPasswordProps} />
|
|
243
|
+
* </>
|
|
244
|
+
* )
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
validate?: Validate<Values>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* For use with React Native only.
|
|
252
|
+
*/
|
|
253
|
+
export interface UseControlledFieldParams<
|
|
254
|
+
OnBlur extends FocusHandler | undefined,
|
|
255
|
+
Values extends FormValues = FormValues
|
|
256
|
+
> extends Omit<UseFieldParams<OnBlur, undefined, Values>, 'onChange'> {
|
|
257
|
+
/**
|
|
258
|
+
* Controlled text change event handler
|
|
259
|
+
*/
|
|
260
|
+
onChangeText?: (value: string) => void;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* For use with React Native only.
|
|
265
|
+
*/
|
|
266
|
+
export interface UseControlledField<Name extends string = string>
|
|
267
|
+
extends Omit<UseField<Name>, 'onChange'> {
|
|
268
|
+
name: Name;
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* React Native only.
|
|
272
|
+
* Controlled text change event handler
|
|
273
|
+
*/
|
|
274
|
+
onChangeText: (value: string) => void;
|
|
275
|
+
|
|
276
|
+
value: string;
|
|
277
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useController } from 'react-hook-form';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
FormValues,
|
|
5
|
+
FocusHandler,
|
|
6
|
+
UseControlledField,
|
|
7
|
+
UseControlledFieldParams,
|
|
8
|
+
} from './types';
|
|
9
|
+
import { isTypedFunction } from '@aws-amplify/ui';
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_ERROR_MESSAGE =
|
|
12
|
+
'`useControlledField` must be used within a `FormProvider`';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* `Field` integration hook for usage with React Native `Field` components
|
|
16
|
+
*
|
|
17
|
+
* @param params Requires `name`, all additional params optional
|
|
18
|
+
* @returns `Form` aware `Field` handlers and state values
|
|
19
|
+
*/
|
|
20
|
+
export default function useControlledField<OnBlur extends FocusHandler>({
|
|
21
|
+
onBlur: _onBlur,
|
|
22
|
+
onChangeText: _onChangeText,
|
|
23
|
+
...rest
|
|
24
|
+
}: UseControlledFieldParams<OnBlur>): UseControlledField {
|
|
25
|
+
// If called outside a `FormProvider`, `useController` throws a `TypeError` instead
|
|
26
|
+
// of failing gracefully (for example returning `undefined` or `null`).
|
|
27
|
+
// Wrap call to `useController` in a `try`/`catch` for graceful failure
|
|
28
|
+
let controller;
|
|
29
|
+
try {
|
|
30
|
+
controller = useController<FormValues>(rest);
|
|
31
|
+
} catch {
|
|
32
|
+
throw new Error(DEFAULT_ERROR_MESSAGE);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const {
|
|
36
|
+
// `useController.onChange` handles `string` values passed directly to `onChange`
|
|
37
|
+
// for RN support, map to `onChangeText`
|
|
38
|
+
field: { name, onBlur, onChange: onChangeText, ref, value },
|
|
39
|
+
fieldState: { error, isDirty, isTouched },
|
|
40
|
+
formState: { isValid: invalid },
|
|
41
|
+
} = controller;
|
|
42
|
+
|
|
43
|
+
const errorMessage = error?.message;
|
|
44
|
+
const hasError = !!errorMessage;
|
|
45
|
+
|
|
46
|
+
const handleBlur = (event: Parameters<OnBlur>[0]) => {
|
|
47
|
+
if (isTypedFunction(_onBlur)) {
|
|
48
|
+
_onBlur(event);
|
|
49
|
+
}
|
|
50
|
+
// `useController.onBlur` does not receive params
|
|
51
|
+
onBlur();
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const handleChangeText = (event: string) => {
|
|
55
|
+
if (isTypedFunction(_onChangeText)) {
|
|
56
|
+
_onChangeText(event);
|
|
57
|
+
}
|
|
58
|
+
onChangeText(event);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
errorMessage,
|
|
63
|
+
hasError,
|
|
64
|
+
invalid,
|
|
65
|
+
isDirty,
|
|
66
|
+
isTouched,
|
|
67
|
+
name,
|
|
68
|
+
onBlur: handleBlur,
|
|
69
|
+
onChangeText: handleChangeText,
|
|
70
|
+
ref,
|
|
71
|
+
value,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import useForm from './useForm';
|
|
2
|
+
import { ChangeHandler, FocusHandler, UseField, UseFieldParams } from './types';
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_ERROR_MESSAGE =
|
|
5
|
+
'`useField` must be used within a `FormProvider`';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* `Field` integration hook for usage with React `Field` components.
|
|
9
|
+
*
|
|
10
|
+
* @param params Requires `name`, all additional params optional
|
|
11
|
+
* @returns `Form` aware `Field` event handlers and state values
|
|
12
|
+
*/
|
|
13
|
+
export default function useField<
|
|
14
|
+
OnBlur extends FocusHandler,
|
|
15
|
+
OnChange extends ChangeHandler
|
|
16
|
+
>(params: UseFieldParams<OnBlur, OnChange>): UseField {
|
|
17
|
+
const { getFieldState, registerField } = useForm({
|
|
18
|
+
errorMessage: DEFAULT_ERROR_MESSAGE,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
...registerField(params),
|
|
23
|
+
...getFieldState(params.name),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useFormContext } from 'react-hook-form';
|
|
3
|
+
import { noop } from '@aws-amplify/ui';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
FormValues,
|
|
7
|
+
RegisterFieldParams,
|
|
8
|
+
SetFormValueParams,
|
|
9
|
+
SubmitHandler,
|
|
10
|
+
UseForm,
|
|
11
|
+
UseFormParams,
|
|
12
|
+
} from './types';
|
|
13
|
+
|
|
14
|
+
export const DEFAULT_ERROR_MESSAGE =
|
|
15
|
+
'`useForm` must be called inside a `FormProvider`';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Utility hook corresponding to `FormProvider`, must be used within a `FormProvider`
|
|
19
|
+
*
|
|
20
|
+
* @internal Extend for public export. `useForm` and `UseForm` are an abstraction layer
|
|
21
|
+
* on top of `useFormContext` and `UseFormReturn`, imported from `react-hook-form`
|
|
22
|
+
*
|
|
23
|
+
* @param options optional parameters
|
|
24
|
+
* @returns `Form` utilities
|
|
25
|
+
*/
|
|
26
|
+
export default function useForm<
|
|
27
|
+
Values extends FormValues = FormValues,
|
|
28
|
+
OnSubmit extends SubmitHandler = SubmitHandler
|
|
29
|
+
>(options: UseFormParams<Values, OnSubmit> = {}): UseForm<Values> {
|
|
30
|
+
const formContext = useFormContext();
|
|
31
|
+
const { errorMessage, onSubmit: _onSubmit } = options;
|
|
32
|
+
|
|
33
|
+
if (!formContext) {
|
|
34
|
+
throw new Error(errorMessage ?? DEFAULT_ERROR_MESSAGE);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const {
|
|
38
|
+
formState,
|
|
39
|
+
getFieldState: _getFieldState,
|
|
40
|
+
getValues,
|
|
41
|
+
handleSubmit,
|
|
42
|
+
register,
|
|
43
|
+
reset,
|
|
44
|
+
setValue,
|
|
45
|
+
} = formContext;
|
|
46
|
+
|
|
47
|
+
// Do not memoize, `formState` updates on all events
|
|
48
|
+
const getFieldState = (name: string) => {
|
|
49
|
+
const { error, ...fieldState } = _getFieldState(name, formState);
|
|
50
|
+
|
|
51
|
+
const { message: errorMessage } = error ?? {};
|
|
52
|
+
return { ...fieldState, errorMessage, hasError: !!errorMessage };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// memoize `registerField` and `setFormValue` together,
|
|
56
|
+
// `register` and `setValue` maintain stable references
|
|
57
|
+
const { registerField, setFormValue } = React.useMemo(() => {
|
|
58
|
+
return {
|
|
59
|
+
registerField: ({ name, ...options }: RegisterFieldParams) =>
|
|
60
|
+
register(name, options),
|
|
61
|
+
setFormValue: ({ name, value, ...options }: SetFormValueParams) =>
|
|
62
|
+
setValue(name, value, options),
|
|
63
|
+
};
|
|
64
|
+
}, [register, setValue]);
|
|
65
|
+
|
|
66
|
+
const onSubmit = React.useCallback(
|
|
67
|
+
(event?: React.BaseSyntheticEvent) => {
|
|
68
|
+
const handler = _onSubmit ? handleSubmit(_onSubmit) : noop;
|
|
69
|
+
|
|
70
|
+
handler(event);
|
|
71
|
+
},
|
|
72
|
+
[_onSubmit, handleSubmit]
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
getFieldState,
|
|
77
|
+
getValues,
|
|
78
|
+
isValid: formState.isValid,
|
|
79
|
+
onSubmit,
|
|
80
|
+
registerField,
|
|
81
|
+
reset,
|
|
82
|
+
setFormValue,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { AnyComponent, MergeProps } from '../../types';
|
|
4
|
+
|
|
5
|
+
import FormProvider from './FormProvider';
|
|
6
|
+
import { FormHandle, FormProviderProps } from './types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param Child `Form` base component wrapped inside `FormProvider`
|
|
10
|
+
* @returns Composed `Form` component exposing `FormContext` values to descendents
|
|
11
|
+
*/
|
|
12
|
+
export default function withFormProvider<
|
|
13
|
+
ChildComp extends AnyComponent,
|
|
14
|
+
ChildProps extends React.ComponentPropsWithRef<ChildComp>,
|
|
15
|
+
Props extends MergeProps<FormProviderProps, ChildProps>
|
|
16
|
+
>(
|
|
17
|
+
Child: ChildComp
|
|
18
|
+
): React.ForwardRefExoticComponent<
|
|
19
|
+
React.PropsWithoutRef<Props> & React.RefAttributes<FormHandle>
|
|
20
|
+
> {
|
|
21
|
+
return React.forwardRef<FormHandle, Props>(function Form(
|
|
22
|
+
{ defaultValues, mode, ...props },
|
|
23
|
+
ref
|
|
24
|
+
) {
|
|
25
|
+
return (
|
|
26
|
+
<FormProvider defaultValues={defaultValues} mode={mode} ref={ref}>
|
|
27
|
+
<Child {...(props as ChildProps)} />
|
|
28
|
+
</FormProvider>
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as RenderNothing } from './RenderNothing';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export {
|
|
2
|
+
FormProvider,
|
|
3
|
+
FormProviderProps,
|
|
4
|
+
FormValues,
|
|
5
|
+
FormHandle,
|
|
6
|
+
SubmitHandler,
|
|
7
|
+
useField,
|
|
8
|
+
useForm,
|
|
9
|
+
UseForm,
|
|
10
|
+
Validate,
|
|
11
|
+
Validator,
|
|
12
|
+
withFormProvider,
|
|
13
|
+
} from './FormCore';
|
|
14
|
+
|
|
15
|
+
export { RenderNothing } from './RenderNothing';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export {
|
|
2
|
+
default as useDeprecationWarning,
|
|
3
|
+
UseDeprecationWarning,
|
|
4
|
+
} from './useDeprecationWarning';
|
|
5
|
+
export { default as useHasValueUpdated } from './useHasValueUpdated';
|
|
6
|
+
export { default as usePreviousValue } from './usePreviousValue';
|
|
7
|
+
export { default as useSetUserAgent } from './useSetUserAgent';
|
|
8
|
+
export { default as useTimeout } from './useTimeout';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
export type UseDeprecationWarning = (params: {
|
|
4
|
+
shouldWarn: boolean;
|
|
5
|
+
message: string;
|
|
6
|
+
}) => void;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Logs a deprecation warning message.
|
|
10
|
+
*
|
|
11
|
+
* @important Please use the React/React Native specific platform implementations.
|
|
12
|
+
* This version of the hook is a base implementation that the others extend from due
|
|
13
|
+
* to env differences between running in RN or the browser
|
|
14
|
+
*/
|
|
15
|
+
const useDeprecationWarning: UseDeprecationWarning = ({
|
|
16
|
+
shouldWarn,
|
|
17
|
+
message,
|
|
18
|
+
}) => {
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
if (shouldWarn) {
|
|
21
|
+
// eslint-disable-next-line no-console
|
|
22
|
+
console.warn(message);
|
|
23
|
+
}
|
|
24
|
+
}, [shouldWarn, message]);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default useDeprecationWarning;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { isUndefined } from '@aws-amplify/ui';
|
|
2
|
+
|
|
3
|
+
import usePreviousValue from './usePreviousValue';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param value `value` to track for updates
|
|
7
|
+
* @param ignoreFirstRender whether to ignore initial render. defaults to `false`
|
|
8
|
+
* @returns a boolean representing whether the tracked `value` has updated between renders
|
|
9
|
+
*
|
|
10
|
+
* Returns `false`:
|
|
11
|
+
* - on initial render when ignoring first render
|
|
12
|
+
* - current and previous `value` are equal
|
|
13
|
+
*
|
|
14
|
+
* Returns `true`:
|
|
15
|
+
* - on initial render when not ignoring first render (default behavior)
|
|
16
|
+
* - current and previous `value` are not equal
|
|
17
|
+
*/
|
|
18
|
+
export default function useHasValueUpdated<Value>(
|
|
19
|
+
value: Value,
|
|
20
|
+
ignoreFirstRender = false
|
|
21
|
+
): boolean {
|
|
22
|
+
const previous = usePreviousValue<Value>(value);
|
|
23
|
+
const shouldIgnoreChange = isUndefined(previous) && ignoreFirstRender;
|
|
24
|
+
if (shouldIgnoreChange) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return previous !== value;
|
|
28
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
export default function usePreviousValue<Value>(
|
|
4
|
+
value: Value
|
|
5
|
+
): Value | undefined {
|
|
6
|
+
const previous = useRef<Value>();
|
|
7
|
+
|
|
8
|
+
// update ref post render
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
previous.current = value;
|
|
11
|
+
}, [value]);
|
|
12
|
+
|
|
13
|
+
// return previous ref
|
|
14
|
+
return previous.current;
|
|
15
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
import { setUserAgent, SetUserAgentOptions } from '@aws-amplify/ui';
|
|
3
|
+
|
|
4
|
+
export default function useSetUserAgent({
|
|
5
|
+
componentName,
|
|
6
|
+
packageName,
|
|
7
|
+
version,
|
|
8
|
+
}: SetUserAgentOptions): void {
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const clearUserAgent = setUserAgent({
|
|
11
|
+
componentName,
|
|
12
|
+
packageName,
|
|
13
|
+
version,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
return clearUserAgent;
|
|
17
|
+
}, [componentName, packageName, version]);
|
|
18
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { isTypedFunction } from '@aws-amplify/ui';
|
|
3
|
+
|
|
4
|
+
export default function useTimeout({
|
|
5
|
+
callback,
|
|
6
|
+
delay,
|
|
7
|
+
}: {
|
|
8
|
+
callback?: () => void;
|
|
9
|
+
delay?: number;
|
|
10
|
+
}): void {
|
|
11
|
+
const storedCallback = React.useRef(callback);
|
|
12
|
+
|
|
13
|
+
React.useLayoutEffect(() => {
|
|
14
|
+
storedCallback.current = callback;
|
|
15
|
+
}, [callback]);
|
|
16
|
+
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
if (!isTypedFunction(storedCallback.current) || !delay) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const timeoutId = setTimeout(() => {
|
|
23
|
+
storedCallback.current?.();
|
|
24
|
+
}, delay);
|
|
25
|
+
|
|
26
|
+
return () => {
|
|
27
|
+
clearTimeout(timeoutId);
|
|
28
|
+
};
|
|
29
|
+
}, [delay]);
|
|
30
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// features
|
|
2
|
+
export {
|
|
3
|
+
AuthenticatorComponentDefaults,
|
|
4
|
+
AuthenticatorComponentDefaultProps,
|
|
5
|
+
AuthenticatorComponentOverrides,
|
|
6
|
+
AuthenticatorFooterComponent,
|
|
7
|
+
AuthenticatorFormFieldsComponent,
|
|
8
|
+
AuthenticatorHeaderComponent,
|
|
9
|
+
AuthenticatorLegacyField,
|
|
10
|
+
AuthenticatorMachineContext,
|
|
11
|
+
AuthenticatorProvider,
|
|
12
|
+
AuthenticatorRouteComponentKey,
|
|
13
|
+
AuthenticatorRouteComponentName,
|
|
14
|
+
isAuthenticatorComponentRouteKey,
|
|
15
|
+
resolveAuthenticatorComponents,
|
|
16
|
+
useAuthenticator,
|
|
17
|
+
useAuthenticatorRoute,
|
|
18
|
+
UseAuthenticator,
|
|
19
|
+
useAuthenticatorInitMachine,
|
|
20
|
+
UseAuthenticatorRoute,
|
|
21
|
+
} from './Authenticator';
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
FormProvider,
|
|
25
|
+
FormProviderProps,
|
|
26
|
+
RenderNothing,
|
|
27
|
+
FormValues,
|
|
28
|
+
FormHandle,
|
|
29
|
+
useField,
|
|
30
|
+
useForm,
|
|
31
|
+
UseForm,
|
|
32
|
+
Validate,
|
|
33
|
+
Validator,
|
|
34
|
+
withFormProvider,
|
|
35
|
+
} from './components';
|
|
36
|
+
|
|
37
|
+
export {
|
|
38
|
+
useDeprecationWarning,
|
|
39
|
+
UseDeprecationWarning,
|
|
40
|
+
useHasValueUpdated,
|
|
41
|
+
usePreviousValue,
|
|
42
|
+
useSetUserAgent,
|
|
43
|
+
useTimeout,
|
|
44
|
+
} from './hooks';
|
|
45
|
+
|
|
46
|
+
export { MergeProps } from './types';
|
|
47
|
+
|
|
48
|
+
export { createContextUtilities } from './utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AnyComponent, MergeProps } from './types';
|