-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtypes.ts
356 lines (303 loc) · 15.8 KB
/
types.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
// BROWSER FORM HOOK TYPES
// --------------------------------------------------------------------------------
/** An options object to configure how you use this form.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
*/
export interface BrowserFormOptionsInput<Schema> {
/**
* Form DOM name attribute - **must be unique**. Used to access inputs through `document.forms`, to read all events and hydrate the form data and the DOM inputs.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
*/
name: string;
/**
* Default values need to match your schema. **Do not change these - it will result in incorrect behavior.**
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
*/
defaultValues: Schema & { [key: string]: any };
/**
* A callback for when the form is submitted. **Will not trigger if there are errors during validation!**
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
*/
onSubmit?: (data: Schema) => void;
/**
* This method is useful when using `onChange` mode, live fields, setting or resetting values, etc.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
*/
onChange?: (data: Schema) => void;
/**
* A dead-simple validation with a validator schema that has access to single field and all form data. Throw `ValidationError` with an error message if field validation fails.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
* - [Documentation](https://deniskabana.github.io/react-browser-form/documentation/validation-and-transformation)
* - [Examples](https://deniskabana.github.io/react-browser-form/examples/validation)
*/
validationSchema?: ValidationSchema<Schema>;
/**
* A dead-simple type and value transformation schema. Useful when you need easy data processing, input masking or just recast types.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
* - [Documentation](https://deniskabana.github.io/react-browser-form/documentation/validation-and-transformation)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/advanced/value-transformation)
*/
transformationSchema?: TransformationSchema<Schema>;
/**
* Whether to perform validation right after mounting the form - before the first render.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
*/
validateAfterInit?: boolean;
/**
* Options:
* - `onSubmitUnlessError`: Hydrate and validate upon form submit event. Inputs with errors re-validate on input change until the error is resolved.
* - `onSubmit`: Hydrate and validate upon form submit event. The fastest option if not validating, reliant on browser handling and keeping inputs mounted.
* - `onBlurUnlessError`: Hydrate and validate the form on every input blur. Inputs with errors re-validate on input change until the error is resolved.
* - `onBlur`: Hydrate and validate the form on every input blur. Recommended for forms with more complex validation logic.
* - `onChange`: The React way of handling forms. - the slowest method. Only good for live data handling. It is recommended to use live fields instead.
*
* Further reading:
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/basic/form-modes)
*
* @default "onSubmitUnlessError"
*/
mode?: "onSubmitUnlessError" | "onSubmit" | "onBlurUnlessError" | "onBlur" | "onChange";
/**
* A revalidation strategy for inputs with errors. To be used with any *unlessError mode. Choose `onBlur` if your validation is demanding.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/validation/revalidation-strategies)
*
* @default "onChange"
*/
revalidationStrategy?: "onChange" | "onBlur";
/**
* A subset of fields that will trigger update and validation of specified fields on every input change. Useful for conditional operations within forms, dependent fields, etc.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/advanced/live-fields)
*/
liveFields?: (keyof Schema)[];
/** **DO NOT USE IN PRODUCTION**. UNDOCUMENTED ON PURPOSE. This is meant for tests, library development and docs. */
debug?: boolean;
}
export type BrowserFormOptions<Schema> = Required<BrowserFormOptionsInput<Schema>>;
/** An object returned after initialization.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
*/
export interface BrowserFormReturnType<Schema> {
// REQUIRED TO USE
// --------------------------------------------------------------------------------
/**
* Props that will attach to DOM form node - `<form {...formProps} />`. This is necessary for React Browser Form to function as it uses the built-in browser form management mechanisms an React events.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
*/
formProps: FormComponentProps<Schema>;
// OPTIONAL TO USE
// --------------------------------------------------------------------------------
/**
* **Optional but recommended.** Names object prevents errors during development. You can pass name as a string to inputs optionally, but you will lose out on compile-time errors.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
*/
names: Record<keyof Schema, string>;
/**
* Errors object that keeps tracks of errors and their count.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
*
* @example { count: 1, errors: { password: "Error message" } }
*/
errorData: ErrorsObject<Schema>;
/**
* Whether the form has been touched by the user. No deep comparisons happen internally. Reset will clear this value.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
*/
isDirty: boolean;
/**
* An array of strings referencing the names of inputs considered "dirty". Reset will clear this value.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
*/
dirtyFields: Array<keyof Schema>;
// METHODS
// --------------------------------------------------------------------------------
/**
* Lets you programatically submit the form. Useful when using non-standard or controlled inputs.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/basic/form-methods)
*/
submit: SubmitMethod;
/**
* Programatically reset the form. If no values are provided, `defaultValues` are used. If values are provided, they need to cover the entire Schema. Triggers the `onChange` event and validation and reset dirty fields.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/basic/form-methods)
*/
reset: ResetMethod<Schema>;
/**
* Allows to set a subset of values programmatically (this gets merged with the current form state). It will trigger an `onChange` event and validation.
* **Setting the values programatically does change the dirty status of both the fields and the whole form.**
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/basic/form-methods)
*/
setValues: SetValuesMethod<Schema>;
}
// EXPOSED METHODS
// --------------------------------------------------------------------------------
/**
* Lets you programatically submit the form. Useful when using non-standard or controlled inputs.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/basic/form-methods)
*/
export type SubmitMethod = VoidFunction;
/**
* Programatically reset the form. If no values are provided, `defaultValues` are used. If values are provided, they need to cover the entire Schema. Triggers the `onChange` event and validation.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/basic/form-methods)
*/
export type ResetMethod<Schema> = (values?: Schema) => void;
/**
* Allows to set a subset of values programmatically (this gets merged with the current form state). It will trigger an `onChange` event and validation.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/basic/form-methods)
*/
export type SetValuesMethod<Schema> = (values: Partial<Schema>) => void;
// VALUE TRANSFORMATION
// --------------------------------------------------------------------------------
export type TransformationFn<Schema, Key extends keyof Schema> = (
fieldData: unknown,
formState?: Schema,
) => Schema[Key];
/**
* A dead-simple type and value transformation schema. Useful when you need easy data processing, input masking or just recast types.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
* - [Documentation](https://deniskabana.github.io/react-browser-form/documentation/validation-and-transformation)
* - [Example](https://deniskabana.github.io/react-browser-form/examples/advanced/value-transformation)
*/
export interface TransformationSchema<Schema> {
/** By default a transformation based on input[type] is applied, managing the correct types for primitive types. */
disableDefaultTransformation?: boolean;
/** Singular fields to transform. Can not use `transformAllData` if `fields` is used. Provide the name of the primitive type or your own transform function. */
fields?: {
[Field in keyof Schema]?: TransformationFn<Schema, Field> | "number" | "string" | "boolean";
};
}
// DIRTY FIELDS
// --------------------------------------------------------------------------------
export interface DirtyFieldsManager<Schema> {
isDirty: boolean;
setIsDirty: React.Dispatch<React.SetStateAction<boolean>>;
dirtyFields: Array<keyof Schema>;
setDirtyFields: (fields: Array<keyof Schema>) => void;
resetDirtyState: () => void;
}
// VALIDATION AND ERROR HANDLING
// --------------------------------------------------------------------------------
export interface ErrorManager<Schema> {
errorData: ErrorsObject<Schema>;
setErrors: (errors: Partial<Record<keyof Schema, string>>) => void;
}
/**
* Errors object that keeps tracks of errors and their count.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
*
* @example { count: 1, errors: { password: "Error message" } }
*/
export interface ErrorsObject<Schema> {
count: number;
/** Contains an object that ties field name to a custom error message (if any). */
errors: Partial<Record<keyof Schema, string>>;
}
/**
* A validation function that receives all the latest form data.
* @param fieldData Data of the field that the validation function is tied to.
* @param formState **Optional.** The whole form state object. Use if any of your data are tied together.
* @throws `ValidationError` if the validation failed.
*/
export type ValidationFn<Schema, Key extends keyof Schema> = (fieldData: Schema[Key], formState: Schema) => void;
export type ValidationValidatorsFields<Schema> = {
[Field in keyof Schema]?: ValidationFn<Schema, Field> | Array<ValidationFn<Schema, Field>>;
};
export type ValidationRequiredFields<Schema> = { fields: (keyof Schema)[]; message?: string };
/**
* A dead-simple validation with a validator schema that has access to single field and all form data. Throw `ValidationError` with an error message if field validation fails.
* - [Options API](https://deniskabana.github.io/react-browser-form/documentation/options-api)
* - [Documentation](https://deniskabana.github.io/react-browser-form/documentation/validation-and-transformation)
* - [Examples](https://deniskabana.github.io/react-browser-form/examples/validation)
*/
export type ValidationSchema<Schema> =
| {
validators?: ValidationValidatorsFields<Schema>;
required: ValidationRequiredFields<Schema>;
}
| {
validators: ValidationValidatorsFields<Schema>;
required?: ValidationRequiredFields<Schema>;
};
// INTERNAL DATA
// --------------------------------------------------------------------------------
export interface FieldsData<Schema> {
names: Record<keyof Schema, string>;
required: (keyof Schema)[];
validated: (keyof Schema)[];
}
/**
* Props that will attach to DOM form node - `<form {...formProps} />`. This is necessary for React Browser Form to function as it uses the built-in browser form management mechanisms an React events.
* - [Return types API](https://deniskabana.github.io/react-browser-form/documentation/return-types-api)
*/
export type FormComponentProps<Schema> = FormEventHandlers<Schema>[EventSource.Form] & {
name: BrowserFormOptions<Schema>["name"];
};
export interface UserCallbacks<Schema> {
onSubmit: (data: Schema) => void;
onChange: (data: Schema) => void;
}
// DATA FLOW
// --------------------------------------------------------------------------------
export enum EventSource {
User = "User",
Form = "Form",
}
export enum EventType {
/** Submit event */
Submit = "Submit",
/** Any type of reset or clear action */
Reset = "Reset",
/** `EventType.Change` gets called for all listeners - `onChange`, `onBlur` and `onSubmit` */
Change = "Change",
/** `EventType.Blur` when a form input is blurred (loses focus) */
Blur = "Blur",
/** A special type of event triggered programmatically during init phase. Under the hood it just calls `reset()` without calling `onChange()` or hydrating */
FormInit = "FormInit",
}
export type FormEventHandler = (event: React.FormEvent<HTMLFormElement>) => void;
export type UserEventHandler<Schema> = (value?: Partial<Schema>) => void;
export interface FormEventHandlers<Schema> {
[EventSource.User]: {
setValues: UserEventHandler<Schema>;
submit: UserEventHandler<Schema>;
reset: UserEventHandler<Schema>;
};
[EventSource.Form]: {
onChange: FormEventHandler;
onSubmit: FormEventHandler;
onBlur: FormEventHandler;
onReset: FormEventHandler;
};
}
export interface DataFlowEvent<Schema> {
source: EventSource;
type: EventType;
value?: Partial<Schema>;
nativeEvent?: React.FormEvent<HTMLFormElement>;
}
export interface DataFlowState<Schema> {
hasErrors: boolean;
event: DataFlowEvent<Schema>;
options: BrowserFormOptions<Schema>;
changedData: Partial<Schema>;
changeReason: string;
formState: Schema;
fieldsData: FieldsData<Schema>;
callbacks: UserCallbacks<Schema>;
errorData: ErrorsObject<Schema>;
setErrors: ErrorManager<Schema>["setErrors"];
isDirty: boolean;
setIsDirty: React.Dispatch<React.SetStateAction<boolean>>;
setDirtyFields: DirtyFieldsManager<Schema>["setDirtyFields"];
resetDirtyState: DirtyFieldsManager<Schema>["resetDirtyState"];
}
export type DataFlowFn<Schema> = (dataFlowState: DataFlowState<Schema>) => void;
// Function used in browser-form wrapper
export type HandleDataFlow<Schema> = (event: DataFlowEvent<Schema>) => void;