remix-validated-form 5.1.5 → 5.1.6

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 (75) hide show
  1. package/.turbo/turbo-build.log +18 -18
  2. package/dist/index.cjs.js +3 -0
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.esm.js +3 -0
  5. package/dist/index.esm.js.map +1 -1
  6. package/package.json +1 -1
  7. package/.turbo/turbo-dev.log +0 -0
  8. package/.turbo/turbo-typecheck.log +0 -1
  9. package/browser/ValidatedForm.d.ts +0 -50
  10. package/browser/ValidatedForm.js +0 -210
  11. package/browser/hooks.d.ts +0 -67
  12. package/browser/hooks.js +0 -84
  13. package/browser/index.d.ts +0 -7
  14. package/browser/index.js +0 -7
  15. package/browser/internal/MultiValueMap.d.ts +0 -11
  16. package/browser/internal/MultiValueMap.js +0 -43
  17. package/browser/internal/constants.d.ts +0 -3
  18. package/browser/internal/constants.js +0 -3
  19. package/browser/internal/flatten.d.ts +0 -1
  20. package/browser/internal/flatten.js +0 -7
  21. package/browser/internal/formContext.d.ts +0 -12
  22. package/browser/internal/formContext.js +0 -2
  23. package/browser/internal/getInputProps.d.ts +0 -29
  24. package/browser/internal/getInputProps.js +0 -51
  25. package/browser/internal/hooks.d.ts +0 -35
  26. package/browser/internal/hooks.js +0 -118
  27. package/browser/internal/hydratable.d.ts +0 -14
  28. package/browser/internal/hydratable.js +0 -14
  29. package/browser/internal/logic/getCheckboxChecked.d.ts +0 -1
  30. package/browser/internal/logic/getCheckboxChecked.js +0 -9
  31. package/browser/internal/logic/getRadioChecked.d.ts +0 -1
  32. package/browser/internal/logic/getRadioChecked.js +0 -15
  33. package/browser/internal/logic/nestedObjectToPathObject.d.ts +0 -1
  34. package/browser/internal/logic/nestedObjectToPathObject.js +0 -47
  35. package/browser/internal/logic/requestSubmit.d.ts +0 -5
  36. package/browser/internal/logic/requestSubmit.js +0 -66
  37. package/browser/internal/reset.d.ts +0 -28
  38. package/browser/internal/reset.js +0 -13
  39. package/browser/internal/state/arrayUtil.d.ts +0 -12
  40. package/browser/internal/state/arrayUtil.js +0 -350
  41. package/browser/internal/state/atomUtils.d.ts +0 -38
  42. package/browser/internal/state/atomUtils.js +0 -5
  43. package/browser/internal/state/cleanup.d.ts +0 -2
  44. package/browser/internal/state/cleanup.js +0 -6
  45. package/browser/internal/state/controlledFieldStore.d.ts +0 -26
  46. package/browser/internal/state/controlledFieldStore.js +0 -70
  47. package/browser/internal/state/controlledFields.d.ts +0 -7
  48. package/browser/internal/state/controlledFields.js +0 -36
  49. package/browser/internal/state/createFormStore.d.ts +0 -79
  50. package/browser/internal/state/createFormStore.js +0 -306
  51. package/browser/internal/state/fieldArray.d.ts +0 -28
  52. package/browser/internal/state/fieldArray.js +0 -74
  53. package/browser/internal/state/storeFamily.d.ts +0 -9
  54. package/browser/internal/state/storeFamily.js +0 -18
  55. package/browser/internal/state/storeHooks.d.ts +0 -3
  56. package/browser/internal/state/storeHooks.js +0 -4
  57. package/browser/internal/state/types.d.ts +0 -1
  58. package/browser/internal/state/types.js +0 -1
  59. package/browser/internal/state.d.ts +0 -343
  60. package/browser/internal/state.js +0 -64
  61. package/browser/internal/submissionCallbacks.d.ts +0 -1
  62. package/browser/internal/submissionCallbacks.js +0 -13
  63. package/browser/internal/util.d.ts +0 -5
  64. package/browser/internal/util.js +0 -32
  65. package/browser/server.d.ts +0 -21
  66. package/browser/server.js +0 -27
  67. package/browser/unreleased/formStateHooks.d.ts +0 -64
  68. package/browser/unreleased/formStateHooks.js +0 -76
  69. package/browser/userFacingFormContext.d.ts +0 -85
  70. package/browser/userFacingFormContext.js +0 -41
  71. package/browser/validation/createValidator.d.ts +0 -7
  72. package/browser/validation/createValidator.js +0 -43
  73. package/browser/validation/types.d.ts +0 -58
  74. package/browser/validation/types.js +0 -1
  75. package/stats.html +0 -4044
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remix-validated-form",
3
- "version": "5.1.5",
3
+ "version": "5.1.6",
4
4
  "description": "Form component and utils for easy form validation in remix",
5
5
  "main": "./dist/index.cjs.js",
6
6
  "module": "./dist/index.esm.js",
File without changes
@@ -1 +0,0 @@
1
- $ tsc --noEmit
@@ -1,50 +0,0 @@
1
- import { FetcherWithComponents, Form as RemixForm } from "@remix-run/react";
2
- import React, { ComponentProps } from "react";
3
- import { Validator } from "./validation/types";
4
- export type FormProps<DataType> = {
5
- /**
6
- * A `Validator` object that describes how to validate the form.
7
- */
8
- validator: Validator<DataType>;
9
- /**
10
- * A submit callback that gets called when the form is submitted
11
- * after all validations have been run.
12
- */
13
- onSubmit?: (data: DataType, event: React.FormEvent<HTMLFormElement>) => void | Promise<void>;
14
- /**
15
- * Allows you to provide a `fetcher` from remix's `useFetcher` hook.
16
- * The form will use the fetcher for loading states, action data, etc
17
- * instead of the default form action.
18
- */
19
- fetcher?: FetcherWithComponents<any>;
20
- /**
21
- * Accepts an object of default values for the form
22
- * that will automatically be propagated to the form fields via `useField`.
23
- */
24
- defaultValues?: Partial<DataType>;
25
- /**
26
- * A ref to the form element.
27
- */
28
- formRef?: React.RefObject<HTMLFormElement>;
29
- /**
30
- * An optional sub-action to use for the form.
31
- * Setting a value here will cause the form to be submitted with an extra `subaction` value.
32
- * This can be useful when there are multiple forms on the screen handled by the same action.
33
- */
34
- subaction?: string;
35
- /**
36
- * Reset the form to the default values after the form has been successfully submitted.
37
- * This is useful if you want to submit the same form multiple times,
38
- * and don't redirect in-between submissions.
39
- */
40
- resetAfterSubmit?: boolean;
41
- /**
42
- * Normally, the first invalid input will be focused when the validation fails on form submit.
43
- * Set this to `false` to disable this behavior.
44
- */
45
- disableFocusOnError?: boolean;
46
- } & Omit<ComponentProps<typeof RemixForm>, "onSubmit">;
47
- /**
48
- * The primary form component of `remix-validated-form`.
49
- */
50
- export declare function ValidatedForm<DataType>({ validator, onSubmit, children, fetcher, action, defaultValues: unMemoizedDefaults, formRef: formRefProp, onReset, subaction, resetAfterSubmit, disableFocusOnError, method, replace, id, ...rest }: FormProps<DataType>): JSX.Element;
@@ -1,210 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Form as RemixForm, useSubmit, } from "@remix-run/react";
3
- import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
4
- import * as R from "remeda";
5
- import { useIsSubmitting, useIsValid } from "./hooks";
6
- import { FORM_ID_FIELD } from "./internal/constants";
7
- import { InternalFormContext, } from "./internal/formContext";
8
- import { useDefaultValuesFromLoader, useErrorResponseForForm, useHasActiveFormSubmit, useSetFieldErrors, } from "./internal/hooks";
9
- import { useMultiValueMap } from "./internal/MultiValueMap";
10
- import { useRootFormStore, } from "./internal/state/createFormStore";
11
- import { useFormStore } from "./internal/state/storeHooks";
12
- import { useSubmitComplete } from "./internal/submissionCallbacks";
13
- import { mergeRefs, useDeepEqualsMemo, useIsomorphicLayoutEffect as useLayoutEffect, } from "./internal/util";
14
- const getDataFromForm = (el) => new FormData(el);
15
- function nonNull(value) {
16
- return value !== null;
17
- }
18
- const focusFirstInvalidInput = (fieldErrors, customFocusHandlers, formElement) => {
19
- var _a;
20
- const namesInOrder = [...formElement.elements]
21
- .map((el) => {
22
- const input = el instanceof RadioNodeList ? el[0] : el;
23
- if (input instanceof HTMLElement && "name" in input)
24
- return input.name;
25
- return null;
26
- })
27
- .filter(nonNull)
28
- .filter((name) => name in fieldErrors);
29
- const uniqueNamesInOrder = R.uniq(namesInOrder);
30
- for (const fieldName of uniqueNamesInOrder) {
31
- if (customFocusHandlers.has(fieldName)) {
32
- customFocusHandlers.getAll(fieldName).forEach((handler) => {
33
- handler();
34
- });
35
- break;
36
- }
37
- const elem = formElement.elements.namedItem(fieldName);
38
- if (!elem)
39
- continue;
40
- if (elem instanceof RadioNodeList) {
41
- const selectedRadio = (_a = [...elem]
42
- .filter((item) => item instanceof HTMLInputElement)
43
- .find((item) => item.value === elem.value)) !== null && _a !== void 0 ? _a : elem[0];
44
- if (selectedRadio && selectedRadio instanceof HTMLInputElement) {
45
- selectedRadio.focus();
46
- break;
47
- }
48
- }
49
- if (elem instanceof HTMLElement) {
50
- if (elem instanceof HTMLInputElement && elem.type === "hidden") {
51
- continue;
52
- }
53
- elem.focus();
54
- break;
55
- }
56
- }
57
- };
58
- const useFormId = (providedId) => {
59
- // We can use a `Symbol` here because we only use it after hydration
60
- const [symbolId] = useState(() => Symbol("remix-validated-form-id"));
61
- return providedId !== null && providedId !== void 0 ? providedId : symbolId;
62
- };
63
- /**
64
- * Use a component to access the state so we don't cause
65
- * any extra rerenders of the whole form.
66
- */
67
- const FormResetter = ({ resetAfterSubmit, formRef, }) => {
68
- const isSubmitting = useIsSubmitting();
69
- const isValid = useIsValid();
70
- useSubmitComplete(isSubmitting, () => {
71
- var _a;
72
- if (isValid && resetAfterSubmit) {
73
- (_a = formRef.current) === null || _a === void 0 ? void 0 : _a.reset();
74
- }
75
- });
76
- return null;
77
- };
78
- function formEventProxy(event) {
79
- let defaultPrevented = false;
80
- return new Proxy(event, {
81
- get: (target, prop) => {
82
- if (prop === "preventDefault") {
83
- return () => {
84
- defaultPrevented = true;
85
- };
86
- }
87
- if (prop === "defaultPrevented") {
88
- return defaultPrevented;
89
- }
90
- return target[prop];
91
- },
92
- });
93
- }
94
- /**
95
- * The primary form component of `remix-validated-form`.
96
- */
97
- export function ValidatedForm({ validator, onSubmit, children, fetcher, action, defaultValues: unMemoizedDefaults, formRef: formRefProp, onReset, subaction, resetAfterSubmit = false, disableFocusOnError, method, replace, id, ...rest }) {
98
- var _a;
99
- const formId = useFormId(id);
100
- const providedDefaultValues = useDeepEqualsMemo(unMemoizedDefaults);
101
- const contextValue = useMemo(() => ({
102
- formId,
103
- action,
104
- subaction,
105
- defaultValuesProp: providedDefaultValues,
106
- fetcher,
107
- }), [action, fetcher, formId, providedDefaultValues, subaction]);
108
- const backendError = useErrorResponseForForm(contextValue);
109
- const backendDefaultValues = useDefaultValuesFromLoader(contextValue);
110
- const hasActiveSubmission = useHasActiveFormSubmit(contextValue);
111
- const formRef = useRef(null);
112
- const Form = (_a = fetcher === null || fetcher === void 0 ? void 0 : fetcher.Form) !== null && _a !== void 0 ? _a : RemixForm;
113
- const submit = useSubmit();
114
- const setFieldErrors = useSetFieldErrors(formId);
115
- const setFieldError = useFormStore(formId, (state) => state.setFieldError);
116
- const reset = useFormStore(formId, (state) => state.reset);
117
- const startSubmit = useFormStore(formId, (state) => state.startSubmit);
118
- const endSubmit = useFormStore(formId, (state) => state.endSubmit);
119
- const syncFormProps = useFormStore(formId, (state) => state.syncFormProps);
120
- const setFormElementInState = useFormStore(formId, (state) => state.setFormElement);
121
- const cleanupForm = useRootFormStore((state) => state.cleanupForm);
122
- const registerForm = useRootFormStore((state) => state.registerForm);
123
- const customFocusHandlers = useMultiValueMap();
124
- const registerReceiveFocus = useCallback((fieldName, handler) => {
125
- customFocusHandlers().add(fieldName, handler);
126
- return () => {
127
- customFocusHandlers().remove(fieldName, handler);
128
- };
129
- }, [customFocusHandlers]);
130
- // TODO: all these hooks running at startup cause extra, unnecessary renders
131
- // There must be a nice way to avoid this.
132
- useLayoutEffect(() => {
133
- registerForm(formId);
134
- return () => cleanupForm(formId);
135
- }, [cleanupForm, formId, registerForm]);
136
- useLayoutEffect(() => {
137
- var _a;
138
- syncFormProps({
139
- action,
140
- defaultValues: (_a = providedDefaultValues !== null && providedDefaultValues !== void 0 ? providedDefaultValues : backendDefaultValues) !== null && _a !== void 0 ? _a : {},
141
- subaction,
142
- registerReceiveFocus,
143
- validator,
144
- });
145
- }, [
146
- action,
147
- providedDefaultValues,
148
- registerReceiveFocus,
149
- subaction,
150
- syncFormProps,
151
- backendDefaultValues,
152
- validator,
153
- ]);
154
- useLayoutEffect(() => {
155
- setFormElementInState(formRef.current);
156
- }, [setFormElementInState]);
157
- useEffect(() => {
158
- var _a;
159
- setFieldErrors((_a = backendError === null || backendError === void 0 ? void 0 : backendError.fieldErrors) !== null && _a !== void 0 ? _a : {});
160
- }, [backendError === null || backendError === void 0 ? void 0 : backendError.fieldErrors, setFieldErrors, setFieldError]);
161
- useSubmitComplete(hasActiveSubmission, () => {
162
- endSubmit();
163
- });
164
- const handleSubmit = async (e, target, nativeEvent) => {
165
- startSubmit();
166
- const submitter = nativeEvent.submitter;
167
- const formDataToValidate = getDataFromForm(e.currentTarget);
168
- if (submitter === null || submitter === void 0 ? void 0 : submitter.name) {
169
- formDataToValidate.append(submitter.name, submitter.value);
170
- }
171
- const result = await validator.validate(formDataToValidate);
172
- if (result.error) {
173
- setFieldErrors(result.error.fieldErrors);
174
- endSubmit();
175
- if (!disableFocusOnError) {
176
- focusFirstInvalidInput(result.error.fieldErrors, customFocusHandlers(), formRef.current);
177
- }
178
- }
179
- else {
180
- setFieldErrors({});
181
- const eventProxy = formEventProxy(e);
182
- await (onSubmit === null || onSubmit === void 0 ? void 0 : onSubmit(result.data, eventProxy));
183
- if (eventProxy.defaultPrevented) {
184
- endSubmit();
185
- return;
186
- }
187
- // We deviate from the remix code here a bit because of our async submit.
188
- // In remix's `FormImpl`, they use `event.currentTarget` to get the form,
189
- // but we already have the form in `formRef.current` so we can just use that.
190
- // If we use `event.currentTarget` here, it will break because `currentTarget`
191
- // will have changed since the start of the submission.
192
- if (fetcher)
193
- fetcher.submit(submitter || e.currentTarget);
194
- else
195
- submit(submitter || target, {
196
- replace,
197
- method: (submitter === null || submitter === void 0 ? void 0 : submitter.formMethod) || method,
198
- });
199
- }
200
- };
201
- return (_jsx(Form, { ref: mergeRefs([formRef, formRefProp]), ...rest, id: id, action: action, method: method, replace: replace, onSubmit: (e) => {
202
- e.preventDefault();
203
- handleSubmit(e, e.currentTarget, e.nativeEvent);
204
- }, onReset: (event) => {
205
- onReset === null || onReset === void 0 ? void 0 : onReset(event);
206
- if (event.defaultPrevented)
207
- return;
208
- reset();
209
- }, children: _jsx(InternalFormContext.Provider, { value: contextValue, children: _jsxs(_Fragment, { children: [_jsx(FormResetter, { formRef: formRef, resetAfterSubmit: resetAfterSubmit }), subaction && (_jsx("input", { type: "hidden", value: subaction, name: "subaction" })), id && _jsx("input", { type: "hidden", value: id, name: FORM_ID_FIELD }), children] }) }) }));
210
- }
@@ -1,67 +0,0 @@
1
- import { GetInputProps, ValidationBehaviorOptions } from "./internal/getInputProps";
2
- /**
3
- * Returns whether or not the parent form is currently being submitted.
4
- * This is different from remix's `useTransition().submission` in that it
5
- * is aware of what form it's in and when _that_ form is being submitted.
6
- *
7
- * @param formId
8
- */
9
- export declare const useIsSubmitting: (formId?: string) => boolean;
10
- /**
11
- * Returns whether or not the current form is valid.
12
- *
13
- * @param formId the id of the form. Only necessary if being used outside a ValidatedForm.
14
- */
15
- export declare const useIsValid: (formId?: string) => boolean;
16
- export type FieldProps = {
17
- /**
18
- * The validation error message if there is one.
19
- */
20
- error?: string;
21
- /**
22
- * Clears the error message.
23
- */
24
- clearError: () => void;
25
- /**
26
- * Validates the field.
27
- */
28
- validate: () => void;
29
- /**
30
- * The default value of the field, if there is one.
31
- */
32
- defaultValue?: any;
33
- /**
34
- * Whether or not the field has been touched.
35
- */
36
- touched: boolean;
37
- /**
38
- * Helper to set the touched state of the field.
39
- */
40
- setTouched: (touched: boolean) => void;
41
- /**
42
- * Helper to get all the props necessary for a regular input.
43
- */
44
- getInputProps: GetInputProps;
45
- };
46
- /**
47
- * Provides the data and helpers necessary to set up a field.
48
- */
49
- export declare const useField: (name: string, options?: {
50
- /**
51
- * Allows you to configure a custom function that will be called
52
- * when the input needs to receive focus due to a validation error.
53
- * This is useful for custom components that use a hidden input.
54
- */
55
- handleReceiveFocus?: () => void;
56
- /**
57
- * Allows you to specify when a field gets validated (when using getInputProps)
58
- */
59
- validationBehavior?: Partial<ValidationBehaviorOptions>;
60
- /**
61
- * The formId of the form you want to use.
62
- * This is not necesary if the input is used inside a form.
63
- */
64
- formId?: string;
65
- }) => FieldProps;
66
- export declare const useControlField: <T>(name: string, formId?: string) => readonly [T, (value: T) => void];
67
- export declare const useUpdateControlledField: (formId?: string) => (field: string, value: unknown) => void;
package/browser/hooks.js DELETED
@@ -1,84 +0,0 @@
1
- import { useEffect, useMemo } from "react";
2
- import { createGetInputProps, } from "./internal/getInputProps";
3
- import { useInternalFormContext, useFieldTouched, useFieldError, useFieldDefaultValue, useClearError, useInternalIsSubmitting, useInternalIsValid, useInternalHasBeenSubmitted, useValidateField, useRegisterReceiveFocus, } from "./internal/hooks";
4
- import { useControllableValue, useUpdateControllableValue, } from "./internal/state/controlledFields";
5
- /**
6
- * Returns whether or not the parent form is currently being submitted.
7
- * This is different from remix's `useTransition().submission` in that it
8
- * is aware of what form it's in and when _that_ form is being submitted.
9
- *
10
- * @param formId
11
- */
12
- export const useIsSubmitting = (formId) => {
13
- const formContext = useInternalFormContext(formId, "useIsSubmitting");
14
- return useInternalIsSubmitting(formContext.formId);
15
- };
16
- /**
17
- * Returns whether or not the current form is valid.
18
- *
19
- * @param formId the id of the form. Only necessary if being used outside a ValidatedForm.
20
- */
21
- export const useIsValid = (formId) => {
22
- const formContext = useInternalFormContext(formId, "useIsValid");
23
- return useInternalIsValid(formContext.formId);
24
- };
25
- /**
26
- * Provides the data and helpers necessary to set up a field.
27
- */
28
- export const useField = (name, options) => {
29
- const { formId: providedFormId, handleReceiveFocus } = options !== null && options !== void 0 ? options : {};
30
- const formContext = useInternalFormContext(providedFormId, "useField");
31
- const defaultValue = useFieldDefaultValue(name, formContext);
32
- const [touched, setTouched] = useFieldTouched(name, formContext);
33
- const error = useFieldError(name, formContext);
34
- const clearError = useClearError(formContext);
35
- const hasBeenSubmitted = useInternalHasBeenSubmitted(formContext.formId);
36
- const validateField = useValidateField(formContext.formId);
37
- const registerReceiveFocus = useRegisterReceiveFocus(formContext.formId);
38
- useEffect(() => {
39
- if (handleReceiveFocus)
40
- return registerReceiveFocus(name, handleReceiveFocus);
41
- }, [handleReceiveFocus, name, registerReceiveFocus]);
42
- const field = useMemo(() => {
43
- const helpers = {
44
- error,
45
- clearError: () => clearError(name),
46
- validate: () => {
47
- validateField(name);
48
- },
49
- defaultValue,
50
- touched,
51
- setTouched,
52
- };
53
- const getInputProps = createGetInputProps({
54
- ...helpers,
55
- name,
56
- hasBeenSubmitted,
57
- validationBehavior: options === null || options === void 0 ? void 0 : options.validationBehavior,
58
- });
59
- return {
60
- ...helpers,
61
- getInputProps,
62
- };
63
- }, [
64
- error,
65
- clearError,
66
- defaultValue,
67
- touched,
68
- setTouched,
69
- name,
70
- hasBeenSubmitted,
71
- options === null || options === void 0 ? void 0 : options.validationBehavior,
72
- validateField,
73
- ]);
74
- return field;
75
- };
76
- export const useControlField = (name, formId) => {
77
- const context = useInternalFormContext(formId, "useControlField");
78
- const [value, setValue] = useControllableValue(context, name);
79
- return [value, setValue];
80
- };
81
- export const useUpdateControlledField = (formId) => {
82
- const context = useInternalFormContext(formId, "useControlField");
83
- return useUpdateControllableValue(context.formId);
84
- };
@@ -1,7 +0,0 @@
1
- export * from "./hooks";
2
- export * from "./server";
3
- export * from "./ValidatedForm";
4
- export * from "./validation/types";
5
- export * from "./validation/createValidator";
6
- export * from "./userFacingFormContext";
7
- export { FieldArray, useFieldArray, type FieldArrayProps, type FieldArrayHelpers, } from "./internal/state/fieldArray";
package/browser/index.js DELETED
@@ -1,7 +0,0 @@
1
- export * from "./hooks";
2
- export * from "./server";
3
- export * from "./ValidatedForm";
4
- export * from "./validation/types";
5
- export * from "./validation/createValidator";
6
- export * from "./userFacingFormContext";
7
- export { FieldArray, useFieldArray, } from "./internal/state/fieldArray";
@@ -1,11 +0,0 @@
1
- export declare class MultiValueMap<Key, Value> {
2
- private dict;
3
- add: (key: Key, value: Value) => void;
4
- delete: (key: Key) => void;
5
- remove: (key: Key, value: Value) => void;
6
- getAll: (key: Key) => Value[];
7
- entries: () => IterableIterator<[Key, Value[]]>;
8
- values: () => IterableIterator<Value[]>;
9
- has: (key: Key) => boolean;
10
- }
11
- export declare const useMultiValueMap: <Key, Value>() => () => MultiValueMap<Key, Value>;
@@ -1,43 +0,0 @@
1
- import { useCallback, useRef } from "react";
2
- export class MultiValueMap {
3
- constructor() {
4
- this.dict = new Map();
5
- this.add = (key, value) => {
6
- if (this.dict.has(key)) {
7
- this.dict.get(key).push(value);
8
- }
9
- else {
10
- this.dict.set(key, [value]);
11
- }
12
- };
13
- this.delete = (key) => {
14
- this.dict.delete(key);
15
- };
16
- this.remove = (key, value) => {
17
- if (!this.dict.has(key))
18
- return;
19
- const array = this.dict.get(key);
20
- const index = array.indexOf(value);
21
- if (index !== -1)
22
- array.splice(index, 1);
23
- if (array.length === 0)
24
- this.dict.delete(key);
25
- };
26
- this.getAll = (key) => {
27
- var _a;
28
- return (_a = this.dict.get(key)) !== null && _a !== void 0 ? _a : [];
29
- };
30
- this.entries = () => this.dict.entries();
31
- this.values = () => this.dict.values();
32
- this.has = (key) => this.dict.has(key);
33
- }
34
- }
35
- export const useMultiValueMap = () => {
36
- const ref = useRef(null);
37
- return useCallback(() => {
38
- if (ref.current)
39
- return ref.current;
40
- ref.current = new MultiValueMap();
41
- return ref.current;
42
- }, []);
43
- };
@@ -1,3 +0,0 @@
1
- export declare const FORM_ID_FIELD: "__rvfInternalFormId";
2
- export declare const FORM_DEFAULTS_FIELD: "__rvfInternalFormDefaults";
3
- export declare const formDefaultValuesKey: (formId: string) => string;
@@ -1,3 +0,0 @@
1
- export const FORM_ID_FIELD = "__rvfInternalFormId";
2
- export const FORM_DEFAULTS_FIELD = "__rvfInternalFormDefaults";
3
- export const formDefaultValuesKey = (formId) => `${FORM_DEFAULTS_FIELD}_${formId}`;
@@ -1 +0,0 @@
1
- export declare const objectFromPathEntries: (entries: [string, any][]) => Record<string, any>;
@@ -1,7 +0,0 @@
1
- import { setPath } from "set-get";
2
- import { MultiValueMap } from "./MultiValueMap";
3
- export const objectFromPathEntries = (entries) => {
4
- const map = new MultiValueMap();
5
- entries.forEach(([key, value]) => map.add(key, value));
6
- return [...map.entries()].reduce((acc, [key, value]) => setPath(acc, key, value.length === 1 ? value[0] : value), {});
7
- };
@@ -1,12 +0,0 @@
1
- /// <reference types="react" />
2
- import { FetcherWithComponents } from "@remix-run/react";
3
- export type InternalFormContextValue = {
4
- formId: string | symbol;
5
- action?: string;
6
- subaction?: string;
7
- defaultValuesProp?: {
8
- [fieldName: string]: any;
9
- };
10
- fetcher?: FetcherWithComponents<unknown>;
11
- };
12
- export declare const InternalFormContext: import("react").Context<InternalFormContextValue | null>;
@@ -1,2 +0,0 @@
1
- import { createContext } from "react";
2
- export const InternalFormContext = createContext(null);
@@ -1,29 +0,0 @@
1
- export type ValidationBehavior = "onBlur" | "onChange" | "onSubmit";
2
- export type ValidationBehaviorOptions = {
3
- initial: ValidationBehavior;
4
- whenTouched: ValidationBehavior;
5
- whenSubmitted: ValidationBehavior;
6
- };
7
- export type CreateGetInputPropsOptions = {
8
- clearError: () => void;
9
- validate: () => void;
10
- defaultValue?: any;
11
- touched: boolean;
12
- setTouched: (touched: boolean) => void;
13
- hasBeenSubmitted: boolean;
14
- validationBehavior?: Partial<ValidationBehaviorOptions>;
15
- name: string;
16
- };
17
- type HandledProps = "name" | "defaultValue" | "defaultChecked";
18
- type Callbacks = "onChange" | "onBlur";
19
- type MinimalInputProps = {
20
- onChange?: (...args: any[]) => void;
21
- onBlur?: (...args: any[]) => void;
22
- defaultValue?: any;
23
- defaultChecked?: boolean;
24
- name?: string;
25
- type?: string;
26
- };
27
- export type GetInputProps = <T extends MinimalInputProps>(props?: Omit<T, HandledProps | Callbacks> & Partial<Pick<T, Callbacks>>) => T;
28
- export declare const createGetInputProps: ({ clearError, validate, defaultValue, touched, setTouched, hasBeenSubmitted, validationBehavior, name, }: CreateGetInputPropsOptions) => GetInputProps;
29
- export {};
@@ -1,51 +0,0 @@
1
- import * as R from "remeda";
2
- import { getCheckboxChecked } from "./logic/getCheckboxChecked";
3
- import { getRadioChecked } from "./logic/getRadioChecked";
4
- const defaultValidationBehavior = {
5
- initial: "onBlur",
6
- whenTouched: "onChange",
7
- whenSubmitted: "onChange",
8
- };
9
- export const createGetInputProps = ({ clearError, validate, defaultValue, touched, setTouched, hasBeenSubmitted, validationBehavior, name, }) => {
10
- const validationBehaviors = {
11
- ...defaultValidationBehavior,
12
- ...validationBehavior,
13
- };
14
- return (props = {}) => {
15
- const behavior = hasBeenSubmitted
16
- ? validationBehaviors.whenSubmitted
17
- : touched
18
- ? validationBehaviors.whenTouched
19
- : validationBehaviors.initial;
20
- const inputProps = {
21
- ...props,
22
- onChange: (...args) => {
23
- var _a;
24
- if (behavior === "onChange")
25
- validate();
26
- else
27
- clearError();
28
- return (_a = props === null || props === void 0 ? void 0 : props.onChange) === null || _a === void 0 ? void 0 : _a.call(props, ...args);
29
- },
30
- onBlur: (...args) => {
31
- var _a;
32
- if (behavior === "onBlur")
33
- validate();
34
- setTouched(true);
35
- return (_a = props === null || props === void 0 ? void 0 : props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, ...args);
36
- },
37
- name,
38
- };
39
- if (props.type === "checkbox") {
40
- inputProps.defaultChecked = getCheckboxChecked(props.value, defaultValue);
41
- }
42
- else if (props.type === "radio") {
43
- inputProps.defaultChecked = getRadioChecked(props.value, defaultValue);
44
- }
45
- else if (props.value === undefined) {
46
- // We should only set the defaultValue if the input is uncontrolled.
47
- inputProps.defaultValue = defaultValue;
48
- }
49
- return R.omitBy(inputProps, (value) => value === undefined);
50
- };
51
- };
@@ -1,35 +0,0 @@
1
- import { FieldErrors, ValidationErrorResponseData } from "..";
2
- import { InternalFormContextValue } from "./formContext";
3
- import { Hydratable } from "./hydratable";
4
- import { InternalFormId } from "./state/types";
5
- export declare const useInternalFormContext: (formId?: string | symbol, hookName?: string) => InternalFormContextValue;
6
- export declare function useErrorResponseForForm({ fetcher, subaction, formId, }: InternalFormContextValue): ValidationErrorResponseData | null;
7
- export declare const useFieldErrorsForForm: (context: InternalFormContextValue) => Hydratable<FieldErrors | undefined>;
8
- export declare const useDefaultValuesFromLoader: ({ formId, }: InternalFormContextValue) => any;
9
- export declare const useDefaultValuesForForm: (context: InternalFormContextValue) => Hydratable<{
10
- [fieldName: string]: any;
11
- }>;
12
- export declare const useHasActiveFormSubmit: ({ fetcher, }: InternalFormContextValue) => boolean;
13
- export declare const useFieldTouched: (field: string, { formId }: InternalFormContextValue) => readonly [boolean, (touched: boolean) => void];
14
- export declare const useFieldError: (name: string, context: InternalFormContextValue) => string | undefined;
15
- export declare const useClearError: (context: InternalFormContextValue) => (field: string) => void;
16
- export declare const useCurrentDefaultValueForField: (formId: InternalFormId, field: string) => any;
17
- export declare const useFieldDefaultValue: (name: string, context: InternalFormContextValue) => any;
18
- export declare const useInternalIsSubmitting: (formId: InternalFormId) => boolean;
19
- export declare const useInternalIsValid: (formId: InternalFormId) => boolean;
20
- export declare const useInternalHasBeenSubmitted: (formId: InternalFormId) => boolean;
21
- export declare const useValidateField: (formId: InternalFormId) => (fieldName: string) => Promise<string | null>;
22
- export declare const useValidate: (formId: InternalFormId) => () => Promise<import("..").ValidationResult<unknown>>;
23
- export declare const useRegisterReceiveFocus: (formId: InternalFormId) => (fieldName: string, handler: () => void) => () => void;
24
- export declare const useSyncedDefaultValues: (formId: InternalFormId) => {
25
- [fieldName: string]: any;
26
- };
27
- export declare const useSetTouched: ({ formId }: InternalFormContextValue) => (field: string, touched: boolean) => void;
28
- export declare const useTouchedFields: (formId: InternalFormId) => import("..").TouchedFields;
29
- export declare const useFieldErrors: (formId: InternalFormId) => FieldErrors;
30
- export declare const useSetFieldErrors: (formId: InternalFormId) => (errors: FieldErrors) => void;
31
- export declare const useResetFormElement: (formId: InternalFormId) => () => void;
32
- export declare const useSubmitForm: (formId: InternalFormId) => () => void;
33
- export declare const useFormActionProp: (formId: InternalFormId) => string | undefined;
34
- export declare const useFormSubactionProp: (formId: InternalFormId) => string | undefined;
35
- export declare const useFormValues: (formId: InternalFormId) => () => FormData;