remix-validated-form 5.0.2 → 5.1.1-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.turbo/turbo-build.log +152 -8
  2. package/dist/index.cjs.js +898 -63
  3. package/dist/index.cjs.js.map +1 -1
  4. package/dist/index.d.ts +7 -2
  5. package/dist/index.esm.js +876 -15
  6. package/dist/index.esm.js.map +1 -1
  7. package/package.json +4 -4
  8. package/src/ValidatedForm.tsx +0 -427
  9. package/src/hooks.ts +0 -160
  10. package/src/index.ts +0 -12
  11. package/src/internal/MultiValueMap.ts +0 -44
  12. package/src/internal/constants.ts +0 -4
  13. package/src/internal/flatten.ts +0 -12
  14. package/src/internal/formContext.ts +0 -13
  15. package/src/internal/getInputProps.test.ts +0 -251
  16. package/src/internal/getInputProps.ts +0 -94
  17. package/src/internal/hooks.ts +0 -217
  18. package/src/internal/hydratable.ts +0 -28
  19. package/src/internal/logic/getCheckboxChecked.ts +0 -10
  20. package/src/internal/logic/getRadioChecked.ts +0 -18
  21. package/src/internal/logic/nestedObjectToPathObject.ts +0 -63
  22. package/src/internal/logic/requestSubmit.test.tsx +0 -24
  23. package/src/internal/logic/requestSubmit.ts +0 -103
  24. package/src/internal/state/arrayUtil.ts +0 -451
  25. package/src/internal/state/controlledFields.ts +0 -86
  26. package/src/internal/state/createFormStore.ts +0 -591
  27. package/src/internal/state/fieldArray.tsx +0 -197
  28. package/src/internal/state/storeHooks.ts +0 -9
  29. package/src/internal/state/types.ts +0 -1
  30. package/src/internal/submissionCallbacks.ts +0 -15
  31. package/src/internal/util.ts +0 -39
  32. package/src/server.ts +0 -53
  33. package/src/unreleased/formStateHooks.ts +0 -170
  34. package/src/userFacingFormContext.ts +0 -147
  35. package/src/validation/createValidator.ts +0 -53
  36. package/src/validation/types.ts +0 -72
  37. package/tsconfig.json +0 -8
@@ -1,251 +0,0 @@
1
- import { describe, it, expect, vi } from "vitest";
2
- import {
3
- createGetInputProps,
4
- CreateGetInputPropsOptions,
5
- } from "./getInputProps";
6
-
7
- const fakeEvent = { fake: "event" } as any;
8
-
9
- describe("getInputProps", () => {
10
- describe("initial", () => {
11
- it("should validate on blur by default", () => {
12
- const options: CreateGetInputPropsOptions = {
13
- name: "some-field",
14
- defaultValue: "test default value",
15
- touched: false,
16
- hasBeenSubmitted: false,
17
- setTouched: vi.fn(),
18
- clearError: vi.fn(),
19
- validate: vi.fn(),
20
- };
21
- const getInputProps = createGetInputProps(options);
22
-
23
- const provided = {
24
- onBlur: vi.fn(),
25
- onChange: vi.fn(),
26
- };
27
- const { onChange, onBlur } = getInputProps(provided);
28
-
29
- onChange!(fakeEvent);
30
- expect(provided.onChange).toBeCalledTimes(1);
31
- expect(provided.onChange).toBeCalledWith(fakeEvent);
32
- expect(options.setTouched).not.toBeCalled();
33
- expect(options.validate).not.toBeCalled();
34
-
35
- onBlur!(fakeEvent);
36
- expect(provided.onBlur).toBeCalledTimes(1);
37
- expect(provided.onBlur).toBeCalledWith(fakeEvent);
38
- expect(options.setTouched).toBeCalledTimes(1);
39
- expect(options.setTouched).toBeCalledWith(true);
40
- expect(options.validate).toBeCalledTimes(1);
41
- });
42
-
43
- it("should respect provided validation behavior", () => {
44
- const options: CreateGetInputPropsOptions = {
45
- name: "some-field",
46
- defaultValue: "test default value",
47
- touched: false,
48
- hasBeenSubmitted: false,
49
- setTouched: vi.fn(),
50
- clearError: vi.fn(),
51
- validate: vi.fn(),
52
- validationBehavior: {
53
- initial: "onChange",
54
- },
55
- };
56
- const getInputProps = createGetInputProps(options);
57
-
58
- const provided = {
59
- onBlur: vi.fn(),
60
- onChange: vi.fn(),
61
- };
62
- const { onChange, onBlur } = getInputProps(provided);
63
-
64
- onChange!(fakeEvent);
65
- expect(provided.onChange).toBeCalledTimes(1);
66
- expect(provided.onChange).toBeCalledWith(fakeEvent);
67
- expect(options.setTouched).not.toBeCalled();
68
- expect(options.validate).toBeCalledTimes(1);
69
-
70
- onBlur!(fakeEvent);
71
- expect(provided.onBlur).toBeCalledTimes(1);
72
- expect(provided.onBlur).toBeCalledWith(fakeEvent);
73
- expect(options.setTouched).toBeCalledTimes(1);
74
- expect(options.setTouched).toBeCalledWith(true);
75
- expect(options.validate).toBeCalledTimes(1);
76
- });
77
-
78
- it("should not validate when behavior is onSubmit", () => {
79
- const options: CreateGetInputPropsOptions = {
80
- name: "some-field",
81
- defaultValue: "test default value",
82
- touched: false,
83
- hasBeenSubmitted: false,
84
- setTouched: vi.fn(),
85
- clearError: vi.fn(),
86
- validate: vi.fn(),
87
- validationBehavior: {
88
- initial: "onSubmit",
89
- },
90
- };
91
- const getInputProps = createGetInputProps(options);
92
-
93
- const provided = {
94
- onBlur: vi.fn(),
95
- onChange: vi.fn(),
96
- };
97
- const { onChange, onBlur } = getInputProps(provided);
98
-
99
- onChange!(fakeEvent);
100
- expect(provided.onChange).toBeCalledTimes(1);
101
- expect(provided.onChange).toBeCalledWith(fakeEvent);
102
- expect(options.setTouched).not.toBeCalled();
103
- expect(options.validate).not.toBeCalled();
104
-
105
- onBlur!(fakeEvent);
106
- expect(provided.onBlur).toBeCalledTimes(1);
107
- expect(provided.onBlur).toBeCalledWith(fakeEvent);
108
- expect(options.setTouched).toBeCalledTimes(1);
109
- expect(options.setTouched).toBeCalledWith(true);
110
- expect(options.validate).not.toBeCalled();
111
- });
112
- });
113
-
114
- describe("whenTouched", () => {
115
- it("should validate on change by default", () => {
116
- const options: CreateGetInputPropsOptions = {
117
- name: "some-field",
118
- defaultValue: "test default value",
119
- touched: true,
120
- hasBeenSubmitted: false,
121
- setTouched: vi.fn(),
122
- clearError: vi.fn(),
123
- validate: vi.fn(),
124
- };
125
- const getInputProps = createGetInputProps(options);
126
-
127
- const provided = {
128
- onBlur: vi.fn(),
129
- onChange: vi.fn(),
130
- };
131
- const { onChange, onBlur } = getInputProps(provided);
132
-
133
- onChange!(fakeEvent);
134
- expect(provided.onChange).toBeCalledTimes(1);
135
- expect(provided.onChange).toBeCalledWith(fakeEvent);
136
- expect(options.setTouched).not.toBeCalled();
137
- expect(options.validate).toBeCalledTimes(1);
138
-
139
- onBlur!(fakeEvent);
140
- expect(provided.onBlur).toBeCalledTimes(1);
141
- expect(provided.onBlur).toBeCalledWith(fakeEvent);
142
- expect(options.setTouched).toBeCalledTimes(1);
143
- expect(options.setTouched).toBeCalledWith(true);
144
- expect(options.validate).toBeCalledTimes(1);
145
- });
146
-
147
- it("should respect provided validation behavior", () => {
148
- const options: CreateGetInputPropsOptions = {
149
- name: "some-field",
150
- defaultValue: "test default value",
151
- touched: true,
152
- hasBeenSubmitted: false,
153
- setTouched: vi.fn(),
154
- clearError: vi.fn(),
155
- validate: vi.fn(),
156
- validationBehavior: {
157
- whenTouched: "onBlur",
158
- },
159
- };
160
- const getInputProps = createGetInputProps(options);
161
-
162
- const provided = {
163
- onBlur: vi.fn(),
164
- onChange: vi.fn(),
165
- };
166
- const { onChange, onBlur } = getInputProps(provided);
167
-
168
- onChange!(fakeEvent);
169
- expect(provided.onChange).toBeCalledTimes(1);
170
- expect(provided.onChange).toBeCalledWith(fakeEvent);
171
- expect(options.setTouched).not.toBeCalled();
172
- expect(options.validate).not.toBeCalled();
173
-
174
- onBlur!(fakeEvent);
175
- expect(provided.onBlur).toBeCalledTimes(1);
176
- expect(provided.onBlur).toBeCalledWith(fakeEvent);
177
- expect(options.setTouched).toBeCalledTimes(1);
178
- expect(options.setTouched).toBeCalledWith(true);
179
- expect(options.validate).toBeCalledTimes(1);
180
- });
181
- });
182
-
183
- describe("whenSubmitted", () => {
184
- it("should validate on change by default", () => {
185
- const options: CreateGetInputPropsOptions = {
186
- name: "some-field",
187
- defaultValue: "test default value",
188
- touched: true,
189
- hasBeenSubmitted: true,
190
- setTouched: vi.fn(),
191
- clearError: vi.fn(),
192
- validate: vi.fn(),
193
- };
194
- const getInputProps = createGetInputProps(options);
195
-
196
- const provided = {
197
- onBlur: vi.fn(),
198
- onChange: vi.fn(),
199
- };
200
- const { onChange, onBlur } = getInputProps(provided);
201
-
202
- onChange!(fakeEvent);
203
- expect(provided.onChange).toBeCalledTimes(1);
204
- expect(provided.onChange).toBeCalledWith(fakeEvent);
205
- expect(options.setTouched).not.toBeCalled();
206
- expect(options.validate).toBeCalledTimes(1);
207
-
208
- onBlur!(fakeEvent);
209
- expect(provided.onBlur).toBeCalledTimes(1);
210
- expect(provided.onBlur).toBeCalledWith(fakeEvent);
211
- expect(options.setTouched).toBeCalledTimes(1);
212
- expect(options.setTouched).toBeCalledWith(true);
213
- expect(options.validate).toBeCalledTimes(1);
214
- });
215
-
216
- it("should respect provided validation behavior", () => {
217
- const options: CreateGetInputPropsOptions = {
218
- name: "some-field",
219
- defaultValue: "test default value",
220
- touched: true,
221
- hasBeenSubmitted: true,
222
- setTouched: vi.fn(),
223
- clearError: vi.fn(),
224
- validate: vi.fn(),
225
- validationBehavior: {
226
- whenSubmitted: "onBlur",
227
- },
228
- };
229
- const getInputProps = createGetInputProps(options);
230
-
231
- const provided = {
232
- onBlur: vi.fn(),
233
- onChange: vi.fn(),
234
- };
235
- const { onChange, onBlur } = getInputProps(provided);
236
-
237
- onChange!(fakeEvent);
238
- expect(provided.onChange).toBeCalledTimes(1);
239
- expect(provided.onChange).toBeCalledWith(fakeEvent);
240
- expect(options.setTouched).not.toBeCalled();
241
- expect(options.validate).not.toBeCalled();
242
-
243
- onBlur!(fakeEvent);
244
- expect(provided.onBlur).toBeCalledTimes(1);
245
- expect(provided.onBlur).toBeCalledWith(fakeEvent);
246
- expect(options.setTouched).toBeCalledTimes(1);
247
- expect(options.setTouched).toBeCalledWith(true);
248
- expect(options.validate).toBeCalledTimes(1);
249
- });
250
- });
251
- });
@@ -1,94 +0,0 @@
1
- import * as R from "remeda";
2
- import { getCheckboxChecked } from "./logic/getCheckboxChecked";
3
- import { getRadioChecked } from "./logic/getRadioChecked";
4
-
5
- export type ValidationBehavior = "onBlur" | "onChange" | "onSubmit";
6
-
7
- export type ValidationBehaviorOptions = {
8
- initial: ValidationBehavior;
9
- whenTouched: ValidationBehavior;
10
- whenSubmitted: ValidationBehavior;
11
- };
12
-
13
- export type CreateGetInputPropsOptions = {
14
- clearError: () => void;
15
- validate: () => void;
16
- defaultValue?: any;
17
- touched: boolean;
18
- setTouched: (touched: boolean) => void;
19
- hasBeenSubmitted: boolean;
20
- validationBehavior?: Partial<ValidationBehaviorOptions>;
21
- name: string;
22
- };
23
-
24
- type HandledProps = "name" | "defaultValue" | "defaultChecked";
25
- type Callbacks = "onChange" | "onBlur";
26
-
27
- type MinimalInputProps = {
28
- onChange?: ((...args: any[]) => void) | undefined;
29
- onBlur?: ((...args: any[]) => void) | undefined;
30
- defaultValue?: any;
31
- defaultChecked?: boolean | undefined;
32
- name?: string | undefined;
33
- type?: string | undefined;
34
- };
35
-
36
- export type GetInputProps = <T extends MinimalInputProps>(
37
- props?: Omit<T, HandledProps | Callbacks> & Partial<Pick<T, Callbacks>>
38
- ) => T;
39
-
40
- const defaultValidationBehavior: ValidationBehaviorOptions = {
41
- initial: "onBlur",
42
- whenTouched: "onChange",
43
- whenSubmitted: "onChange",
44
- };
45
-
46
- export const createGetInputProps = ({
47
- clearError,
48
- validate,
49
- defaultValue,
50
- touched,
51
- setTouched,
52
- hasBeenSubmitted,
53
- validationBehavior,
54
- name,
55
- }: CreateGetInputPropsOptions): GetInputProps => {
56
- const validationBehaviors = {
57
- ...defaultValidationBehavior,
58
- ...validationBehavior,
59
- };
60
-
61
- return <T extends MinimalInputProps>(props = {} as any) => {
62
- const behavior = hasBeenSubmitted
63
- ? validationBehaviors.whenSubmitted
64
- : touched
65
- ? validationBehaviors.whenTouched
66
- : validationBehaviors.initial;
67
-
68
- const inputProps: MinimalInputProps = {
69
- ...props,
70
- onChange: (...args: unknown[]) => {
71
- if (behavior === "onChange") validate();
72
- else clearError();
73
- return props?.onChange?.(...args);
74
- },
75
- onBlur: (...args: unknown[]) => {
76
- if (behavior === "onBlur") validate();
77
- setTouched(true);
78
- return props?.onBlur?.(...args);
79
- },
80
- name,
81
- };
82
-
83
- if (props.type === "checkbox") {
84
- inputProps.defaultChecked = getCheckboxChecked(props.value, defaultValue);
85
- } else if (props.type === "radio") {
86
- inputProps.defaultChecked = getRadioChecked(props.value, defaultValue);
87
- } else if (props.value === undefined) {
88
- // We should only set the defaultValue if the input is uncontrolled.
89
- inputProps.defaultValue = defaultValue;
90
- }
91
-
92
- return R.omitBy(inputProps, (value) => value === undefined) as T;
93
- };
94
- };
@@ -1,217 +0,0 @@
1
- import { useActionData, useMatches, useNavigation } from "@remix-run/react";
2
- import { useCallback, useContext } from "react";
3
- import { getPath } from "set-get";
4
- import invariant from "tiny-invariant";
5
- import { FieldErrors, ValidationErrorResponseData } from "..";
6
- import { formDefaultValuesKey } from "./constants";
7
- import { InternalFormContext, InternalFormContextValue } from "./formContext";
8
- import { Hydratable, hydratable } from "./hydratable";
9
- import { useFormStore } from "./state/storeHooks";
10
- import { InternalFormId } from "./state/types";
11
-
12
- export const useInternalFormContext = (
13
- formId?: string | symbol,
14
- hookName?: string
15
- ) => {
16
- const formContext = useContext(InternalFormContext);
17
-
18
- if (formId) return { formId };
19
- if (formContext) return formContext;
20
-
21
- throw new Error(
22
- `Unable to determine form for ${hookName}. Please use it inside a ValidatedForm or pass a 'formId'.`
23
- );
24
- };
25
-
26
- export function useErrorResponseForForm({
27
- fetcher,
28
- subaction,
29
- formId,
30
- }: InternalFormContextValue): ValidationErrorResponseData | null {
31
- const actionData = useActionData<any>();
32
- if (fetcher) {
33
- if ((fetcher.data as any)?.fieldErrors) return fetcher.data as any;
34
- return null;
35
- }
36
-
37
- if (!actionData?.fieldErrors) return null;
38
-
39
- // If there's an explicit id, we should ignore data that has the wrong id
40
- if (typeof formId === "string" && actionData.formId)
41
- return actionData.formId === formId ? actionData : null;
42
-
43
- if (
44
- (!subaction && !actionData.subaction) ||
45
- actionData.subaction === subaction
46
- )
47
- return actionData;
48
-
49
- return null;
50
- }
51
-
52
- export const useFieldErrorsForForm = (
53
- context: InternalFormContextValue
54
- ): Hydratable<FieldErrors | undefined> => {
55
- const response = useErrorResponseForForm(context);
56
- const hydrated = useFormStore(context.formId, (state) => state.isHydrated);
57
- return hydratable.from(response?.fieldErrors, hydrated);
58
- };
59
-
60
- export const useDefaultValuesFromLoader = ({
61
- formId,
62
- }: InternalFormContextValue) => {
63
- const matches = useMatches();
64
- if (typeof formId === "string") {
65
- const dataKey = formDefaultValuesKey(formId);
66
- // If multiple loaders declare the same default values,
67
- // we should use the data from the deepest route.
68
- const match = matches
69
- .reverse()
70
- .find(
71
- (match) =>
72
- match.data && typeof match.data === "object" && dataKey in match.data
73
- );
74
- return match?.data[dataKey];
75
- }
76
-
77
- return null;
78
- };
79
-
80
- export const useDefaultValuesForForm = (
81
- context: InternalFormContextValue
82
- ): Hydratable<{ [fieldName: string]: any }> => {
83
- const { formId, defaultValuesProp } = context;
84
- const hydrated = useFormStore(formId, (state) => state.isHydrated);
85
- const errorResponse = useErrorResponseForForm(context);
86
- const defaultValuesFromLoader = useDefaultValuesFromLoader(context);
87
-
88
- // Typical flow is:
89
- // - Default values only available from props or server
90
- // - Props have a higher priority than server
91
- // - State gets hydrated with default values
92
- // - After submit, we may need to use values from the error
93
-
94
- if (hydrated) return hydratable.hydratedData();
95
- if (errorResponse?.repopulateFields) {
96
- invariant(
97
- typeof errorResponse.repopulateFields === "object",
98
- "repopulateFields returned something other than an object"
99
- );
100
- return hydratable.serverData(errorResponse.repopulateFields);
101
- }
102
- if (defaultValuesProp) return hydratable.serverData(defaultValuesProp);
103
-
104
- return hydratable.serverData(defaultValuesFromLoader);
105
- };
106
-
107
- export const useHasActiveFormSubmit = ({
108
- fetcher,
109
- }: InternalFormContextValue): boolean => {
110
- let navigation = useNavigation();
111
- const hasActiveSubmission = fetcher
112
- ? fetcher.state === "submitting"
113
- : navigation.state === "submitting" || navigation.state === "loading";
114
- return hasActiveSubmission;
115
- };
116
-
117
- export const useFieldTouched = (
118
- field: string,
119
- { formId }: InternalFormContextValue
120
- ) => {
121
- const touched = useFormStore(formId, (state) => state.touchedFields[field]);
122
- const setFieldTouched = useFormStore(formId, (state) => state.setTouched);
123
- const setTouched = useCallback(
124
- (touched: boolean) => setFieldTouched(field, touched),
125
- [field, setFieldTouched]
126
- );
127
- return [touched, setTouched] as const;
128
- };
129
-
130
- export const useFieldError = (
131
- name: string,
132
- context: InternalFormContextValue
133
- ) => {
134
- const fieldErrors = useFieldErrorsForForm(context);
135
- const state = useFormStore(
136
- context.formId,
137
- (state) => state.fieldErrors[name]
138
- );
139
- return fieldErrors.map((fieldErrors) => fieldErrors?.[name]).hydrateTo(state);
140
- };
141
-
142
- export const useClearError = (context: InternalFormContextValue) => {
143
- const { formId } = context;
144
- return useFormStore(formId, (state) => state.clearFieldError);
145
- };
146
-
147
- export const useCurrentDefaultValueForField = (
148
- formId: InternalFormId,
149
- field: string
150
- ) =>
151
- useFormStore(formId, (state) => getPath(state.currentDefaultValues, field));
152
-
153
- export const useFieldDefaultValue = (
154
- name: string,
155
- context: InternalFormContextValue
156
- ) => {
157
- const defaultValues = useDefaultValuesForForm(context);
158
- const state = useCurrentDefaultValueForField(context.formId, name);
159
-
160
- return defaultValues.map((val) => getPath(val, name)).hydrateTo(state);
161
- };
162
-
163
- export const useInternalIsSubmitting = (formId: InternalFormId) =>
164
- useFormStore(formId, (state) => state.isSubmitting);
165
-
166
- export const useInternalIsValid = (formId: InternalFormId) =>
167
- useFormStore(formId, (state) => state.isValid());
168
-
169
- export const useInternalHasBeenSubmitted = (formId: InternalFormId) =>
170
- useFormStore(formId, (state) => state.hasBeenSubmitted);
171
-
172
- export const useSmartValidate = (formId: InternalFormId) =>
173
- useFormStore(formId, (state) => state.smartValidate);
174
-
175
- export const useValidate = (formId: InternalFormId) =>
176
- useFormStore(formId, (state) => state.validate);
177
-
178
- const noOpReceiver = () => () => {};
179
- export const useRegisterReceiveFocus = (formId: InternalFormId) =>
180
- useFormStore(
181
- formId,
182
- (state) => state.formProps?.registerReceiveFocus ?? noOpReceiver
183
- );
184
-
185
- const defaultDefaultValues = {};
186
- export const useSyncedDefaultValues = (formId: InternalFormId) =>
187
- useFormStore(
188
- formId,
189
- (state) => state.formProps?.defaultValues ?? defaultDefaultValues
190
- );
191
-
192
- export const useSetTouched = ({ formId }: InternalFormContextValue) =>
193
- useFormStore(formId, (state) => state.setTouched);
194
-
195
- export const useTouchedFields = (formId: InternalFormId) =>
196
- useFormStore(formId, (state) => state.touchedFields);
197
-
198
- export const useFieldErrors = (formId: InternalFormId) =>
199
- useFormStore(formId, (state) => state.fieldErrors);
200
-
201
- export const useSetFieldErrors = (formId: InternalFormId) =>
202
- useFormStore(formId, (state) => state.setFieldErrors);
203
-
204
- export const useResetFormElement = (formId: InternalFormId) =>
205
- useFormStore(formId, (state) => state.resetFormElement);
206
-
207
- export const useSubmitForm = (formId: InternalFormId) =>
208
- useFormStore(formId, (state) => state.submit);
209
-
210
- export const useFormActionProp = (formId: InternalFormId) =>
211
- useFormStore(formId, (state) => state.formProps?.action);
212
-
213
- export const useFormSubactionProp = (formId: InternalFormId) =>
214
- useFormStore(formId, (state) => state.formProps?.subaction);
215
-
216
- export const useFormValues = (formId: InternalFormId) =>
217
- useFormStore(formId, (state) => state.getValues);
@@ -1,28 +0,0 @@
1
- /**
2
- * The purpose of this type is to simplify the logic
3
- * around data that needs to come from the server initially,
4
- * but from the internal state after hydration.
5
- */
6
- export type Hydratable<T> = {
7
- hydrateTo: (data: T) => T;
8
- map: <U>(fn: (data: T) => U) => Hydratable<U>;
9
- };
10
-
11
- const serverData = <T>(data: T): Hydratable<T> => ({
12
- hydrateTo: () => data,
13
- map: (fn) => serverData(fn(data)),
14
- });
15
-
16
- const hydratedData = <T>(): Hydratable<T> => ({
17
- hydrateTo: (hydratedData: T) => hydratedData,
18
- map: <U>() => hydratedData<U>(),
19
- });
20
-
21
- const from = <T>(data: T, hydrated: boolean): Hydratable<T> =>
22
- hydrated ? hydratedData<T>() : serverData<T>(data);
23
-
24
- export const hydratable = {
25
- serverData,
26
- hydratedData,
27
- from,
28
- };
@@ -1,10 +0,0 @@
1
- export const getCheckboxChecked = (
2
- checkboxValue: string | undefined = "on",
3
- newValue: unknown
4
- ): boolean | undefined => {
5
- if (Array.isArray(newValue))
6
- return newValue.some((val) => val === true || val === checkboxValue);
7
- if (typeof newValue === "boolean") return newValue;
8
- if (typeof newValue === "string") return newValue === checkboxValue;
9
- return undefined;
10
- };
@@ -1,18 +0,0 @@
1
- export const getRadioChecked = (
2
- radioValue: string | undefined = "on",
3
- newValue: unknown
4
- ) => {
5
- if (typeof newValue === "string") return newValue === radioValue;
6
- return undefined;
7
- };
8
-
9
- if (import.meta.vitest) {
10
- const { it, expect } = import.meta.vitest;
11
- it("getRadioChecked", () => {
12
- expect(getRadioChecked("on", "on")).toBe(true);
13
- expect(getRadioChecked("on", undefined)).toBe(undefined);
14
- expect(getRadioChecked("trueValue", undefined)).toBe(undefined);
15
- expect(getRadioChecked("trueValue", "bob")).toBe(false);
16
- expect(getRadioChecked("trueValue", "trueValue")).toBe(true);
17
- });
18
- }
@@ -1,63 +0,0 @@
1
- export const nestedObjectToPathObject = (
2
- val: any,
3
- acc: Record<string, any>,
4
- path: string
5
- ): any => {
6
- if (Array.isArray(val)) {
7
- val.forEach((v, index) =>
8
- nestedObjectToPathObject(v, acc, `${path}[${index}]`)
9
- );
10
- return acc;
11
- }
12
-
13
- if (typeof val === "object") {
14
- Object.entries(val).forEach(([key, value]) => {
15
- const nextPath = path ? `${path}.${key}` : key;
16
- nestedObjectToPathObject(value, acc, nextPath);
17
- });
18
- return acc;
19
- }
20
-
21
- if (val !== undefined) {
22
- acc[path] = val;
23
- }
24
-
25
- return acc;
26
- };
27
-
28
- if (import.meta.vitest) {
29
- const { describe, expect, it } = import.meta.vitest;
30
-
31
- describe("nestedObjectToPathObject", () => {
32
- it("should return an object with the correct path", () => {
33
- const result = nestedObjectToPathObject(
34
- {
35
- a: 1,
36
- b: 2,
37
- c: { foo: "bar", baz: [true, false] },
38
- d: [
39
- { foo: "bar", baz: [true, false] },
40
- { e: true, f: "hi" },
41
- ],
42
- g: undefined,
43
- },
44
- {},
45
- ""
46
- );
47
-
48
- expect(result).toEqual({
49
- a: 1,
50
- b: 2,
51
- "c.foo": "bar",
52
- "c.baz[0]": true,
53
- "c.baz[1]": false,
54
- "d[0].foo": "bar",
55
- "d[0].baz[0]": true,
56
- "d[0].baz[1]": false,
57
- "d[1].e": true,
58
- "d[1].f": "hi",
59
- });
60
- expect(Object.keys(result)).toHaveLength(10);
61
- });
62
- });
63
- }