@prototyp/skeletor 1.0.5 → 1.0.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.
package/README.md CHANGED
@@ -252,6 +252,12 @@ Flexible in its function, supports multiple validation approaches through callba
252
252
  2. To trigger standalone validation, use `validate("prop")`
253
253
  3. Validate entire form with `validateForm()`
254
254
 
255
+ The order of importance when it comes to validating fields is:
256
+
257
+ 1. Custom validation rule - will get the value as-is for your rule to validate it fully. The configuration rule receives the current value, state and optional flag values for you to validate against.
258
+ 2. If there is no custom validation rule and the primitive value check returns false (there is no value), check if the field is optional. If optional, the validation result is `true`, otherwise it is `false`;
259
+ 3. If all previous checks have not been triggered, return the primitive "has value" check result. This will return `false` for values such as: `null | undefined | NaN | "" | Invalid Date`. This will return `true` if you have a complex value type such as `object | Array`, <b>so in case you have a complex value type use a custom validation rule to get what you need</b>.
260
+
255
261
  #### Example 1: Simple use case with standalone validation on blur:
256
262
 
257
263
  ```javascript
@@ -321,7 +327,7 @@ const { state, validation, update, validate } = useForm(
321
327
  optional: ["middleName"],
322
328
  // validation.lastName is invalid if lastName is <3 characters long
323
329
  // state can be used to compare with other values (ie repeat password)
324
- rules: { lastName: (value, state) => value.length >= 3,
330
+ rules: { lastName: (value, state, optional) => value.length >= 3,
325
331
  }
326
332
  ```
327
333
 
@@ -108,32 +108,47 @@ export function useForm(values, config) {
108
108
  /** Helper hook to validate form state outside of the scope of useForm. */
109
109
  export function useFormUtils(config) {
110
110
  function doesValueExist(value) {
111
- if (value === null || value === undefined || value === "" || value < 0) {
111
+ if (value === undefined || value === null) {
112
112
  return false;
113
113
  }
114
- return true;
115
- }
116
- function validateByRule(key, value, state) {
117
- // If rule exists, validate with rule
118
- if (config !== null && config !== void 0 && config.rules && config.rules[key]) {
119
- var _config$rules$key, _config$rules;
120
- return (_config$rules$key = (_config$rules = config.rules)[key]) === null || _config$rules$key === void 0 ? void 0 : _config$rules$key.call(_config$rules, value, state);
114
+ if (typeof value === "string") {
115
+ return value !== "";
116
+ }
117
+ if (typeof value === "number") {
118
+ return value >= 0 || value < 0 || !isNaN(value);
119
+ }
120
+ if (value instanceof Date) {
121
+ return !isNaN(value.valueOf());
121
122
  }
122
- // else return true because we know the value exists already.
123
123
  return true;
124
124
  }
125
125
  function isOptional(key) {
126
126
  var _config$optional;
127
- return config === null || config === void 0 ? void 0 : (_config$optional = config.optional) === null || _config$optional === void 0 ? void 0 : _config$optional.includes(key);
127
+ return (config === null || config === void 0 ? void 0 : (_config$optional = config.optional) === null || _config$optional === void 0 ? void 0 : _config$optional.includes(key)) || false;
128
128
  }
129
+
130
+ /** Validate by custom validation rule. If the rule does not exist, returns undefined. */
131
+ function validateByRule(key, value, state) {
132
+ var _config$rules, _config$rules$key;
133
+ return config === null || config === void 0 ? void 0 : (_config$rules = config.rules) === null || _config$rules === void 0 ? void 0 : (_config$rules$key = _config$rules[key]) === null || _config$rules$key === void 0 ? void 0 : _config$rules$key.call(_config$rules, value, state, isOptional(key));
134
+ }
135
+
136
+ /** Handles validation for a specific form field.
137
+ * Order of priority:
138
+ * 1. If there is a custom validation rule, always use that to preserve all possible type values
139
+ * 2. If there is no value (is a falsy value), check if the field is optional
140
+ * 3. Fallback to simple truthy value check if all other checks are not triggered. */
129
141
  function fieldValidation(key, value, state) {
142
+ var _config$rules2;
130
143
  const hasValue = doesValueExist(value);
131
144
  const optional = isOptional(key);
132
- if (!hasValue) {
133
- return !!optional;
134
- } else {
135
- return validateByRule(key, value, state);
136
- }
145
+
146
+ // If form has custom validation rule, always trigger only that.
147
+ if (!!(config !== null && config !== void 0 && (_config$rules2 = config.rules) !== null && _config$rules2 !== void 0 && _config$rules2[key])) return validateByRule(key, value, state);
148
+ // If value does not exist (is null, undefined or other falsy value), check if field is optional.
149
+ if (!hasValue) return !!optional;
150
+ // Fallback, simple check if value exists
151
+ return hasValue;
137
152
  }
138
153
  function stateValidation(state) {
139
154
  const keys = Object.keys(state).map(key => key);
@@ -1 +1 @@
1
- {"version":3,"names":["useEffect","useState","useForm","values","config","keys","Object","validation","setValidation","initialState","setInitialState","state","setState","fieldValidation","stateValidation","isOptional","useFormUtils","changed","filter","key","length","updatedState","forEach","update","value","shouldValidate","s","undefined","validate","validateForm","formValidationState","valid","isFormValid","some","resetState","resetInitialValues","resetValidation","clearForm","doesValueExist","validateByRule","rules","optional","includes","hasValue","map"],"sourceRoot":"../../src","sources":["useForm.ts"],"mappings":"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"}
1
+ {"version":3,"names":["useEffect","useState","useForm","values","config","keys","Object","validation","setValidation","initialState","setInitialState","state","setState","fieldValidation","stateValidation","isOptional","useFormUtils","changed","filter","key","length","updatedState","forEach","update","value","shouldValidate","s","undefined","validate","validateForm","formValidationState","valid","isFormValid","some","resetState","resetInitialValues","resetValidation","clearForm","doesValueExist","isNaN","Date","valueOf","optional","includes","validateByRule","rules","hasValue","map"],"sourceRoot":"../../src","sources":["useForm.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../module/hooks/useForm.js"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AACH;;;;;;;;;;;EA+FC;AAED,0EAA0E;AAC1E;;;;;;;;;EAiDC"}
1
+ {"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../module/hooks/useForm.js"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AACH;;;;;;;;;;;EA+FC;AAED,0EAA0E;AAC1E;;;;;;;;;EAgEC"}
@@ -1,16 +1,16 @@
1
- declare type Validation<T> = {
1
+ export declare type Validation<T> = {
2
2
  [K in keyof Partial<T>]?: boolean;
3
3
  };
4
4
  declare type Rules<T> = {
5
- [K in keyof T]?: (value: T[K], state: T) => boolean | undefined;
5
+ [K in keyof T]?: (value: T[K], state: T, optional: boolean) => boolean | undefined;
6
6
  };
7
- declare type Values<T> = {
7
+ export declare type Values<T> = {
8
8
  [K in keyof T]: T[K];
9
9
  };
10
10
  export declare type FormConfig<R> = {
11
11
  /** List of optional properties. Optional properties will be marked as valid if left empty. */
12
12
  optional?: Array<keyof R>;
13
- /** Validation rules by specified property name. If you define a validation rule function here, the field will be validated against it. If no rule is set, a crude value check will be used instead (Boolean(value)) */
13
+ /** Validation rules by specified property name. If you define a validation rule function here, the field will be validated against it. If no rule is set, a crude value check will be used instead (optional || Boolean(value)). Note: For complex value types (objects, arrays, dates etc) it is best to use a custom validation rule. */
14
14
  rules?: Rules<R>;
15
15
  /** Will compare key/value pairs instead of just top level JSON.stringify on complex objects/arrays */
16
16
  deepCompare?: boolean;
@@ -39,10 +39,10 @@ export declare function useForm<T>(values: Values<T>, config?: FormConfig<T>): {
39
39
  };
40
40
  /** Helper hook to validate form state outside of the scope of useForm. */
41
41
  export declare function useFormUtils<T>(config?: FormConfig<T>): {
42
- doesValueExist: (value: T[keyof T] | undefined) => value is T[keyof T];
42
+ doesValueExist: (value: T[keyof T]) => value is Exclude<T[keyof T], null | undefined>;
43
43
  validateByRule: <K extends keyof T>(key: K, value: T[K], state: Values<T>) => boolean | undefined;
44
- isOptional: (key: keyof T) => boolean | undefined;
45
- fieldValidation: (key: keyof T, value: T[keyof T] | undefined, state: Values<T>) => boolean | undefined;
44
+ isOptional: (key: keyof T) => boolean;
45
+ fieldValidation: (key: keyof T, value: T[keyof T], state: Values<T>) => boolean | undefined;
46
46
  stateValidation: (state: Values<T>) => {
47
47
  valid: boolean;
48
48
  validation: Validation<T>;
@@ -1 +1 @@
1
- {"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useForm.ts"],"names":[],"mappings":"AAEA,aAAK,UAAU,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO;CAAE,CAAC;AAC3D,aAAK,KAAK,CAAC,CAAC,IAAI;KACb,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,GAAG,SAAS;CAChE,CAAC;AAEF,aAAK,MAAM,CAAC,CAAC,IAAI;KACd,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACrB,CAAC;AAEF,oBAAY,UAAU,CAAC,CAAC,IAAI;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1B,uNAAuN;IACvN,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,sGAAsG;IACtG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;;;8EA2B/C,OAAO;;wBAmBD,OAAO;;;;;;EAgDjC;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;4BACrB,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS;oEAU5C,OAAO,CAAC,CAAC;sBAUO,MAAM,CAAC;2BAKzB,MAAM,CAAC,SACL,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,SACtB,OAAO,CAAC,CAAC;6BAWc,OAAO,CAAC,CAAC;;;;EAuB1C"}
1
+ {"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useForm.ts"],"names":[],"mappings":"AAEA,oBAAY,UAAU,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO;CAAE,CAAC;AAClE,aAAK,KAAK,CAAC,CAAC,IAAI;KACb,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CACf,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EACX,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,OAAO,KACd,OAAO,GAAG,SAAS;CACzB,CAAC;AAEF,oBAAY,MAAM,CAAC,CAAC,IAAI;KACrB,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CACrB,CAAC;AAEF,oBAAY,UAAU,CAAC,CAAC,IAAI;IAC1B,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1B,2UAA2U;IAC3U,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IACjB,sGAAsG;IACtG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;;;8EA2B/C,OAAO;;wBAmBD,OAAO;;;;;;EAgDjC;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC;4BAE3C,CAAC,CAAC,MAAM,CAAC,CAAC;oEA6BV,OAAO,CAAC,CAAC;sBARO,MAAM,CAAC;2BAkBF,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,SAAS,OAAO,CAAC,CAAC;6BAY1C,OAAO,CAAC,CAAC;;;;EAuB1C"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@prototyp/skeletor",
3
3
  "description": "React-Native UI and functional toolkit",
4
4
  "author": "Luka Buljan <luka@prototyp.digital>",
5
- "version": "1.0.5",
5
+ "version": "1.0.6",
6
6
  "types": "lib/typescript/src/index.d.ts",
7
7
  "main": "lib/module/index.js",
8
8
  "react-native": "src/index.ts",
@@ -1,18 +1,22 @@
1
1
  import { useEffect, useState } from "react";
2
2
 
3
- type Validation<T> = { [K in keyof Partial<T>]?: boolean };
3
+ export type Validation<T> = { [K in keyof Partial<T>]?: boolean };
4
4
  type Rules<T> = {
5
- [K in keyof T]?: (value: T[K], state: T) => boolean | undefined;
5
+ [K in keyof T]?: (
6
+ value: T[K],
7
+ state: T,
8
+ optional: boolean
9
+ ) => boolean | undefined;
6
10
  };
7
11
 
8
- type Values<T> = {
12
+ export type Values<T> = {
9
13
  [K in keyof T]: T[K];
10
14
  };
11
15
 
12
16
  export type FormConfig<R> = {
13
17
  /** List of optional properties. Optional properties will be marked as valid if left empty. */
14
18
  optional?: Array<keyof R>;
15
- /** Validation rules by specified property name. If you define a validation rule function here, the field will be validated against it. If no rule is set, a crude value check will be used instead (Boolean(value)) */
19
+ /** Validation rules by specified property name. If you define a validation rule function here, the field will be validated against it. If no rule is set, a crude value check will be used instead (optional || Boolean(value)). Note: For complex value types (objects, arrays, dates etc) it is best to use a custom validation rule. */
16
20
  rules?: Rules<R>;
17
21
  /** Will compare key/value pairs instead of just top level JSON.stringify on complex objects/arrays */
18
22
  deepCompare?: boolean;
@@ -55,7 +59,7 @@ export function useForm<T>(values: Values<T>, config?: FormConfig<T>) {
55
59
  function update<K extends keyof T>(
56
60
  key: K,
57
61
  value: Values<T>[K],
58
- shouldValidate?: boolean,
62
+ shouldValidate?: boolean
59
63
  ) {
60
64
  setState((s) => ({ ...s, [key]: value }));
61
65
  setValidation((s) => ({
@@ -84,7 +88,7 @@ export function useForm<T>(values: Values<T>, config?: FormConfig<T>) {
84
88
  * Only use when validating fields separately, has no value when valiating on form submit. */
85
89
  function isFormValid() {
86
90
  return !keys.some((key) =>
87
- isOptional(key) ? validation[key] === false : !validation[key],
91
+ isOptional(key) ? validation[key] === false : !validation[key]
88
92
  );
89
93
  }
90
94
 
@@ -126,42 +130,56 @@ export function useForm<T>(values: Values<T>, config?: FormConfig<T>) {
126
130
 
127
131
  /** Helper hook to validate form state outside of the scope of useForm. */
128
132
  export function useFormUtils<T>(config?: FormConfig<T>) {
129
- function doesValueExist(value: T[keyof T] | undefined): value is T[keyof T] {
130
- if (value === null || value === undefined || value === "" || value < 0) {
133
+ function doesValueExist(
134
+ value: T[keyof T]
135
+ ): value is Exclude<T[keyof T], null | undefined> {
136
+ if (value === undefined || value === null) {
131
137
  return false;
132
138
  }
133
- return true;
134
- }
135
139
 
136
- function validateByRule<K extends keyof T>(
137
- key: K,
138
- value: T[K],
139
- state: Values<T>,
140
- ) {
141
- // If rule exists, validate with rule
142
- if (config?.rules && config.rules[key]) {
143
- return config.rules[key]?.(value, state);
140
+ if (typeof value === "string") {
141
+ return value !== "";
144
142
  }
145
- // else return true because we know the value exists already.
143
+
144
+ if (typeof value === "number") {
145
+ return value >= 0 || value < 0 || !isNaN(value);
146
+ }
147
+
148
+ if (value instanceof Date) {
149
+ return !isNaN(value.valueOf());
150
+ }
151
+
146
152
  return true;
147
153
  }
148
154
 
149
155
  function isOptional(key: keyof T) {
150
- return config?.optional?.includes(key);
156
+ return config?.optional?.includes(key) || false;
151
157
  }
152
158
 
153
- function fieldValidation(
154
- key: keyof T,
155
- value: T[keyof T] | undefined,
156
- state: Values<T>,
159
+ /** Validate by custom validation rule. If the rule does not exist, returns undefined. */
160
+ function validateByRule<K extends keyof T>(
161
+ key: K,
162
+ value: T[K],
163
+ state: Values<T>
157
164
  ) {
165
+ return config?.rules?.[key]?.(value, state, isOptional(key));
166
+ }
167
+
168
+ /** Handles validation for a specific form field.
169
+ * Order of priority:
170
+ * 1. If there is a custom validation rule, always use that to preserve all possible type values
171
+ * 2. If there is no value (is a falsy value), check if the field is optional
172
+ * 3. Fallback to simple truthy value check if all other checks are not triggered. */
173
+ function fieldValidation(key: keyof T, value: T[keyof T], state: Values<T>) {
158
174
  const hasValue = doesValueExist(value);
159
175
  const optional = isOptional(key);
160
- if (!hasValue) {
161
- return !!optional;
162
- } else {
163
- return validateByRule(key, value, state);
164
- }
176
+
177
+ // If form has custom validation rule, always trigger only that.
178
+ if (!!config?.rules?.[key]) return validateByRule(key, value, state);
179
+ // If value does not exist (is null, undefined or other falsy value), check if field is optional.
180
+ if (!hasValue) return !!optional;
181
+ // Fallback, simple check if value exists
182
+ return hasValue;
165
183
  }
166
184
 
167
185
  function stateValidation(state: Values<T>) {