remix-validated-form 3.3.1 → 3.4.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.
@@ -1,9 +1,9 @@
1
1
  $ npm run build:browser && npm run build:main
2
2
 
3
- > remix-validated-form@3.3.0 build:browser
3
+ > remix-validated-form@3.3.1 build:browser
4
4
  > tsc --module ESNext --outDir ./browser
5
5
 
6
6
 
7
- > remix-validated-form@3.3.0 build:main
7
+ > remix-validated-form@3.3.1 build:main
8
8
  > tsc --module CommonJS --outDir ./build
9
9
 
package/README.md CHANGED
@@ -50,6 +50,8 @@ see the [Validation library support](#validation-library-support) section below.
50
50
  npm install @remix-validated-form/with-zod
51
51
  ```
52
52
 
53
+ If you're using zod, you might also find `zod-form-data` helpful.
54
+
53
55
  ## Create an input component
54
56
 
55
57
  In order to display field errors or do field-by-field validation,
@@ -1,4 +1 @@
1
- import { GenericObject } from "..";
2
1
  export declare const objectFromPathEntries: (entries: [string, any][]) => {};
3
- /** Flatten an object so there are no nested objects or arrays */
4
- export declare function flatten(obj: GenericObject, preserveEmpty?: boolean): GenericObject;
@@ -1,40 +1,7 @@
1
- // `flatten` is taken from https://github.com/richie5um/FlattenJS. Decided to implement them here instead of using that package because this is a core functionality of the library and this will add more flexibility in case we need to change the implementation.
2
- import assign from "lodash/assign";
3
- import isArray from "lodash/isArray";
4
- import isObject from "lodash/isObject";
5
- import keys from "lodash/keys";
6
- import mapKeys from "lodash/mapKeys";
7
1
  import set from "lodash/set";
8
- import transform from "lodash/transform";
9
2
  import { MultiValueMap } from "./MultiValueMap";
10
3
  export const objectFromPathEntries = (entries) => {
11
4
  const map = new MultiValueMap();
12
5
  entries.forEach(([key, value]) => map.add(key, value));
13
6
  return [...map.entries()].reduce((acc, [key, value]) => set(acc, key, value.length === 1 ? value[0] : value), {});
14
7
  };
15
- /** Flatten an object so there are no nested objects or arrays */
16
- export function flatten(obj, preserveEmpty = false) {
17
- return transform(obj, function (result, value, key) {
18
- if (isObject(value)) {
19
- let flatMap = mapKeys(flatten(value, preserveEmpty), function (_mvalue, mkey) {
20
- if (isArray(value)) {
21
- let index = mkey.indexOf(".");
22
- if (-1 !== index) {
23
- return `${key}[${mkey.slice(0, index)}]${mkey.slice(index)}`;
24
- }
25
- return `${key}[${mkey}]`;
26
- }
27
- return `${key}.${mkey}`;
28
- });
29
- assign(result, flatMap);
30
- // Preverve Empty arrays and objects
31
- if (preserveEmpty && keys(flatMap).length === 0) {
32
- result[key] = value;
33
- }
34
- }
35
- else {
36
- result[key] = value;
37
- }
38
- return result;
39
- }, {});
40
- }
@@ -14,10 +14,16 @@ export declare type CreateGetInputPropsOptions = {
14
14
  validationBehavior?: Partial<ValidationBehaviorOptions>;
15
15
  name: string;
16
16
  };
17
- declare type OmitHandledProps = {
18
- name?: never;
19
- defaultValue?: never;
17
+ declare type HandledProps = "name" | "defaultValue" | "defaultChecked";
18
+ declare type Callbacks = "onChange" | "onBlur";
19
+ declare type MinimalInputProps = {
20
+ onChange?: (...args: any[]) => void;
21
+ onBlur?: (...args: any[]) => void;
22
+ defaultValue?: any;
23
+ defaultChecked?: boolean;
24
+ name?: string;
25
+ type?: string;
20
26
  };
21
- export declare type GetInputProps = <T extends Record<string, any>>(props?: T & OmitHandledProps) => T;
27
+ export declare type GetInputProps = <T extends MinimalInputProps>(props?: Omit<T, HandledProps | Callbacks> & Partial<Pick<T, Callbacks>>) => T;
22
28
  export declare const createGetInputProps: ({ clearError, validate, defaultValue, touched, setTouched, hasBeenSubmitted, validationBehavior, name, }: CreateGetInputPropsOptions) => GetInputProps;
23
29
  export {};
@@ -3,18 +3,28 @@ const defaultValidationBehavior = {
3
3
  whenTouched: "onChange",
4
4
  whenSubmitted: "onChange",
5
5
  };
6
+ const getCheckboxDefaultChecked = (value, defaultValue) => {
7
+ if (Array.isArray(defaultValue))
8
+ defaultValue.includes(value);
9
+ if (typeof defaultValue === "boolean")
10
+ return defaultValue;
11
+ if (typeof defaultValue === "string")
12
+ return defaultValue === value;
13
+ return undefined;
14
+ };
6
15
  export const createGetInputProps = ({ clearError, validate, defaultValue, touched, setTouched, hasBeenSubmitted, validationBehavior, name, }) => {
7
16
  const validationBehaviors = {
8
17
  ...defaultValidationBehavior,
9
18
  ...validationBehavior,
10
19
  };
11
20
  return (props = {}) => {
21
+ var _a, _b;
12
22
  const behavior = hasBeenSubmitted
13
23
  ? validationBehaviors.whenSubmitted
14
24
  : touched
15
25
  ? validationBehaviors.whenTouched
16
26
  : validationBehaviors.initial;
17
- const result = {
27
+ const inputProps = {
18
28
  ...props,
19
29
  onChange: (...args) => {
20
30
  var _a;
@@ -31,9 +41,19 @@ export const createGetInputProps = ({ clearError, validate, defaultValue, touche
31
41
  setTouched(true);
32
42
  return (_a = props === null || props === void 0 ? void 0 : props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, ...args);
33
43
  },
34
- defaultValue,
35
44
  name,
36
45
  };
37
- return result;
46
+ if (inputProps.type === "checkbox") {
47
+ const value = (_a = props.value) !== null && _a !== void 0 ? _a : "on";
48
+ inputProps.defaultChecked = getCheckboxDefaultChecked(value, defaultValue);
49
+ }
50
+ else if (inputProps.type === "radio") {
51
+ const value = (_b = props.value) !== null && _b !== void 0 ? _b : "on";
52
+ inputProps.defaultChecked = defaultValue === value;
53
+ }
54
+ else {
55
+ inputProps.defaultValue = defaultValue;
56
+ }
57
+ return inputProps;
38
58
  };
39
59
  };
@@ -1,4 +1 @@
1
- import { GenericObject } from "..";
2
1
  export declare const objectFromPathEntries: (entries: [string, any][]) => {};
3
- /** Flatten an object so there are no nested objects or arrays */
4
- export declare function flatten(obj: GenericObject, preserveEmpty?: boolean): GenericObject;
@@ -3,15 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.flatten = exports.objectFromPathEntries = void 0;
7
- // `flatten` is taken from https://github.com/richie5um/FlattenJS. Decided to implement them here instead of using that package because this is a core functionality of the library and this will add more flexibility in case we need to change the implementation.
8
- const assign_1 = __importDefault(require("lodash/assign"));
9
- const isArray_1 = __importDefault(require("lodash/isArray"));
10
- const isObject_1 = __importDefault(require("lodash/isObject"));
11
- const keys_1 = __importDefault(require("lodash/keys"));
12
- const mapKeys_1 = __importDefault(require("lodash/mapKeys"));
6
+ exports.objectFromPathEntries = void 0;
13
7
  const set_1 = __importDefault(require("lodash/set"));
14
- const transform_1 = __importDefault(require("lodash/transform"));
15
8
  const MultiValueMap_1 = require("./MultiValueMap");
16
9
  const objectFromPathEntries = (entries) => {
17
10
  const map = new MultiValueMap_1.MultiValueMap();
@@ -19,30 +12,3 @@ const objectFromPathEntries = (entries) => {
19
12
  return [...map.entries()].reduce((acc, [key, value]) => (0, set_1.default)(acc, key, value.length === 1 ? value[0] : value), {});
20
13
  };
21
14
  exports.objectFromPathEntries = objectFromPathEntries;
22
- /** Flatten an object so there are no nested objects or arrays */
23
- function flatten(obj, preserveEmpty = false) {
24
- return (0, transform_1.default)(obj, function (result, value, key) {
25
- if ((0, isObject_1.default)(value)) {
26
- let flatMap = (0, mapKeys_1.default)(flatten(value, preserveEmpty), function (_mvalue, mkey) {
27
- if ((0, isArray_1.default)(value)) {
28
- let index = mkey.indexOf(".");
29
- if (-1 !== index) {
30
- return `${key}[${mkey.slice(0, index)}]${mkey.slice(index)}`;
31
- }
32
- return `${key}[${mkey}]`;
33
- }
34
- return `${key}.${mkey}`;
35
- });
36
- (0, assign_1.default)(result, flatMap);
37
- // Preverve Empty arrays and objects
38
- if (preserveEmpty && (0, keys_1.default)(flatMap).length === 0) {
39
- result[key] = value;
40
- }
41
- }
42
- else {
43
- result[key] = value;
44
- }
45
- return result;
46
- }, {});
47
- }
48
- exports.flatten = flatten;
@@ -14,10 +14,16 @@ export declare type CreateGetInputPropsOptions = {
14
14
  validationBehavior?: Partial<ValidationBehaviorOptions>;
15
15
  name: string;
16
16
  };
17
- declare type OmitHandledProps = {
18
- name?: never;
19
- defaultValue?: never;
17
+ declare type HandledProps = "name" | "defaultValue" | "defaultChecked";
18
+ declare type Callbacks = "onChange" | "onBlur";
19
+ declare type MinimalInputProps = {
20
+ onChange?: (...args: any[]) => void;
21
+ onBlur?: (...args: any[]) => void;
22
+ defaultValue?: any;
23
+ defaultChecked?: boolean;
24
+ name?: string;
25
+ type?: string;
20
26
  };
21
- export declare type GetInputProps = <T extends Record<string, any>>(props?: T & OmitHandledProps) => T;
27
+ export declare type GetInputProps = <T extends MinimalInputProps>(props?: Omit<T, HandledProps | Callbacks> & Partial<Pick<T, Callbacks>>) => T;
22
28
  export declare const createGetInputProps: ({ clearError, validate, defaultValue, touched, setTouched, hasBeenSubmitted, validationBehavior, name, }: CreateGetInputPropsOptions) => GetInputProps;
23
29
  export {};
@@ -6,18 +6,28 @@ const defaultValidationBehavior = {
6
6
  whenTouched: "onChange",
7
7
  whenSubmitted: "onChange",
8
8
  };
9
+ const getCheckboxDefaultChecked = (value, defaultValue) => {
10
+ if (Array.isArray(defaultValue))
11
+ defaultValue.includes(value);
12
+ if (typeof defaultValue === "boolean")
13
+ return defaultValue;
14
+ if (typeof defaultValue === "string")
15
+ return defaultValue === value;
16
+ return undefined;
17
+ };
9
18
  const createGetInputProps = ({ clearError, validate, defaultValue, touched, setTouched, hasBeenSubmitted, validationBehavior, name, }) => {
10
19
  const validationBehaviors = {
11
20
  ...defaultValidationBehavior,
12
21
  ...validationBehavior,
13
22
  };
14
23
  return (props = {}) => {
24
+ var _a, _b;
15
25
  const behavior = hasBeenSubmitted
16
26
  ? validationBehaviors.whenSubmitted
17
27
  : touched
18
28
  ? validationBehaviors.whenTouched
19
29
  : validationBehaviors.initial;
20
- const result = {
30
+ const inputProps = {
21
31
  ...props,
22
32
  onChange: (...args) => {
23
33
  var _a;
@@ -34,10 +44,20 @@ const createGetInputProps = ({ clearError, validate, defaultValue, touched, setT
34
44
  setTouched(true);
35
45
  return (_a = props === null || props === void 0 ? void 0 : props.onBlur) === null || _a === void 0 ? void 0 : _a.call(props, ...args);
36
46
  },
37
- defaultValue,
38
47
  name,
39
48
  };
40
- return result;
49
+ if (inputProps.type === "checkbox") {
50
+ const value = (_a = props.value) !== null && _a !== void 0 ? _a : "on";
51
+ inputProps.defaultChecked = getCheckboxDefaultChecked(value, defaultValue);
52
+ }
53
+ else if (inputProps.type === "radio") {
54
+ const value = (_b = props.value) !== null && _b !== void 0 ? _b : "on";
55
+ inputProps.defaultChecked = defaultValue === value;
56
+ }
57
+ else {
58
+ inputProps.defaultValue = defaultValue;
59
+ }
60
+ return inputProps;
41
61
  };
42
62
  };
43
63
  exports.createGetInputProps = createGetInputProps;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "remix-validated-form",
3
- "version": "3.3.1",
3
+ "version": "3.4.0",
4
4
  "description": "Form component and utils for easy form validation in remix",
5
5
  "browser": "./browser/index.js",
6
6
  "main": "./build/index.js",
@@ -1,12 +1,4 @@
1
- // `flatten` is taken from https://github.com/richie5um/FlattenJS. Decided to implement them here instead of using that package because this is a core functionality of the library and this will add more flexibility in case we need to change the implementation.
2
- import assign from "lodash/assign";
3
- import isArray from "lodash/isArray";
4
- import isObject from "lodash/isObject";
5
- import keys from "lodash/keys";
6
- import mapKeys from "lodash/mapKeys";
7
1
  import set from "lodash/set";
8
- import transform from "lodash/transform";
9
- import { GenericObject } from "..";
10
2
  import { MultiValueMap } from "./MultiValueMap";
11
3
 
12
4
  export const objectFromPathEntries = (entries: [string, any][]) => {
@@ -17,39 +9,3 @@ export const objectFromPathEntries = (entries: [string, any][]) => {
17
9
  {}
18
10
  );
19
11
  };
20
-
21
- /** Flatten an object so there are no nested objects or arrays */
22
- export function flatten(obj: GenericObject, preserveEmpty = false) {
23
- return transform(
24
- obj,
25
- function (result: GenericObject, value, key) {
26
- if (isObject(value)) {
27
- let flatMap = mapKeys(
28
- flatten(value, preserveEmpty),
29
- function (_mvalue, mkey) {
30
- if (isArray(value)) {
31
- let index = mkey.indexOf(".");
32
- if (-1 !== index) {
33
- return `${key}[${mkey.slice(0, index)}]${mkey.slice(index)}`;
34
- }
35
- return `${key}[${mkey}]`;
36
- }
37
- return `${key}.${mkey}`;
38
- }
39
- );
40
-
41
- assign(result, flatMap);
42
-
43
- // Preverve Empty arrays and objects
44
- if (preserveEmpty && keys(flatMap).length === 0) {
45
- result[key] = value;
46
- }
47
- } else {
48
- result[key] = value;
49
- }
50
-
51
- return result;
52
- },
53
- {}
54
- );
55
- }
@@ -17,12 +17,20 @@ export type CreateGetInputPropsOptions = {
17
17
  name: string;
18
18
  };
19
19
 
20
- // Using Omit<T, HandledProps> breaks type inference sometimes for some reason.
21
- // Doing T & OmitHandledProps gives us the same behavior without breaking type inference.
22
- type OmitHandledProps = { name?: never; defaultValue?: never };
20
+ type HandledProps = "name" | "defaultValue" | "defaultChecked";
21
+ type Callbacks = "onChange" | "onBlur";
23
22
 
24
- export type GetInputProps = <T extends Record<string, any>>(
25
- props?: T & OmitHandledProps
23
+ type MinimalInputProps = {
24
+ onChange?: (...args: any[]) => void;
25
+ onBlur?: (...args: any[]) => void;
26
+ defaultValue?: any;
27
+ defaultChecked?: boolean;
28
+ name?: string;
29
+ type?: string;
30
+ };
31
+
32
+ export type GetInputProps = <T extends MinimalInputProps>(
33
+ props?: Omit<T, HandledProps | Callbacks> & Partial<Pick<T, Callbacks>>
26
34
  ) => T;
27
35
 
28
36
  const defaultValidationBehavior: ValidationBehaviorOptions = {
@@ -31,6 +39,13 @@ const defaultValidationBehavior: ValidationBehaviorOptions = {
31
39
  whenSubmitted: "onChange",
32
40
  };
33
41
 
42
+ const getCheckboxDefaultChecked = (value: string, defaultValue: any) => {
43
+ if (Array.isArray(defaultValue)) defaultValue.includes(value);
44
+ if (typeof defaultValue === "boolean") return defaultValue;
45
+ if (typeof defaultValue === "string") return defaultValue === value;
46
+ return undefined;
47
+ };
48
+
34
49
  export const createGetInputProps = ({
35
50
  clearError,
36
51
  validate,
@@ -46,14 +61,14 @@ export const createGetInputProps = ({
46
61
  ...validationBehavior,
47
62
  };
48
63
 
49
- return <T extends Record<string, any>>(props = {} as any) => {
64
+ return <T extends MinimalInputProps>(props = {} as any) => {
50
65
  const behavior = hasBeenSubmitted
51
66
  ? validationBehaviors.whenSubmitted
52
67
  : touched
53
68
  ? validationBehaviors.whenTouched
54
69
  : validationBehaviors.initial;
55
70
 
56
- const result: T = {
71
+ const inputProps: T = {
57
72
  ...props,
58
73
  onChange: (...args: unknown[]) => {
59
74
  if (behavior === "onChange") validate();
@@ -65,10 +80,22 @@ export const createGetInputProps = ({
65
80
  setTouched(true);
66
81
  return props?.onBlur?.(...args);
67
82
  },
68
- defaultValue,
69
83
  name,
70
84
  };
71
85
 
72
- return result;
86
+ if (inputProps.type === "checkbox") {
87
+ const value = props.value ?? "on";
88
+ inputProps.defaultChecked = getCheckboxDefaultChecked(
89
+ value,
90
+ defaultValue
91
+ );
92
+ } else if (inputProps.type === "radio") {
93
+ const value = props.value ?? "on";
94
+ inputProps.defaultChecked = defaultValue === value;
95
+ } else {
96
+ inputProps.defaultValue = defaultValue;
97
+ }
98
+
99
+ return inputProps;
73
100
  };
74
101
  };