Skip to content

Commit 4fca90b

Browse files
authored
Merge pull request #36 from toggle-corp/fix/differential-required-validation
Fix/differential required validation
2 parents fb18e55 + 9d4784f commit 4fca90b

File tree

15 files changed

+5904
-3323
lines changed

15 files changed

+5904
-3323
lines changed

lib/.babelrc

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
{
2-
'presets': [
3-
'@babel/preset-env',
4-
'@babel/preset-typescript',
5-
'@babel/preset-react',
6-
],
7-
8-
'plugins': [
9-
'@babel/plugin-transform-runtime',
10-
11-
['polyfill-corejs3', {
12-
"method": "usage-pure",
13-
}],
2+
"presets": [
3+
"@babel/preset-env",
4+
"@babel/preset-typescript",
5+
"@babel/preset-react"
146
],
7+
"plugins": [
8+
"@babel/plugin-transform-runtime",
9+
["polyfill-corejs3", {
10+
"method": "usage-pure"
11+
}]
12+
]
1513
}

lib/.browserslistrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
# Support all browsers with more than 1% market share
2-
>= 1%
2+
> 1%

lib/.eslintrc.js renamed to lib/.eslintrc.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ module.exports = {
3333
allowImportExportEverywhere: true,
3434
},
3535
rules: {
36+
'@typescript-eslint/no-empty-function': 'off',
3637
strict: 1,
3738
indent: ['error', 4, { SwitchCase: 1 }],
3839

File renamed without changes.

lib/package.json

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
"files": [
66
"/build"
77
],
8+
"type": "module",
89
"main": "build/cjs/index.js",
910
"module": "build/esm/index.js",
1011
"typings": "build/esm/index.d.ts",
1112
"scripts": {
1213
"prepare": "install-peers",
13-
"build": "tsc --project tsconfig-typings.json && rollup -c",
14+
"build": "rollup -c && tsc --project tsconfig-typings.json",
1415
"watch": "rollup -c -w",
1516
"prepack": "yarn build",
1617
"typecheck": "tsc",
@@ -29,44 +30,44 @@
2930
"url": "https://github.com/toggle-corp/toggle-form/issues"
3031
},
3132
"homepage": "https://github.com/toggle-corp/toggle-form#readme",
32-
"peerDependencies": {
33-
"react": "^17.0.2",
34-
"react-dom": "^17.0.2"
35-
},
3633
"dependencies": {
37-
"@babel/runtime": "^7.19.0",
34+
"@babel/runtime-corejs3": "^7.22.3",
3835
"@togglecorp/fujs": "^2.0.0"
3936
},
37+
"peerDependencies": {
38+
"react": "^18.2.0",
39+
"react-dom": "^18.2.0"
40+
},
4041
"devDependencies": {
41-
"@babel/core": "^7.19.1",
42-
"@babel/plugin-transform-runtime": "^7.19.1",
43-
"@babel/preset-env": "^7.19.1",
44-
"@babel/preset-react": "^7.18.6",
45-
"@babel/preset-typescript": "^7.18.6",
46-
"@rollup/plugin-babel": "^5.3.1",
47-
"@rollup/plugin-commonjs": "^22.0.2",
48-
"@rollup/plugin-eslint": "^8.0.1",
49-
"@rollup/plugin-node-resolve": "^14.1.0",
50-
"@types/jest": "^29.0.3",
51-
"@types/node": "^18.7.22",
52-
"@types/react": "^18.0.21",
53-
"@types/react-dom": "^18.0.6",
54-
"@typescript-eslint/eslint-plugin": "^5.59.8",
55-
"@typescript-eslint/parser": "^5.59.8",
56-
"babel-jest": "^29.0.3",
57-
"babel-plugin-polyfill-corejs3": "^0.6.0",
58-
"eslint": "^8.24.0",
42+
"@babel/core": "^7.22.8",
43+
"@babel/plugin-transform-runtime": "^7.22.7",
44+
"@babel/preset-env": "^7.22.7",
45+
"@babel/preset-react": "^7.22.5",
46+
"@babel/preset-typescript": "^7.22.5",
47+
"@rollup/plugin-babel": "^6.0.3",
48+
"@rollup/plugin-commonjs": "^25.0.2",
49+
"@rollup/plugin-eslint": "^9.0.4",
50+
"@rollup/plugin-node-resolve": "^15.1.0",
51+
"@types/jest": "^29.5.2",
52+
"@types/node": "^20.4.1",
53+
"@types/react": "^18.2.14",
54+
"@types/react-dom": "^18.2.6",
55+
"@typescript-eslint/eslint-plugin": "^5.61.0",
56+
"@typescript-eslint/parser": "^5.61.0",
57+
"babel-jest": "^29.6.1",
58+
"babel-plugin-polyfill-corejs3": "^0.8.2",
59+
"eslint": "^8.44.0",
5960
"eslint-config-airbnb": "^19.0.4",
60-
"eslint-plugin-import": "^2.26.0",
61-
"eslint-plugin-jsx-a11y": "^6.6.1",
62-
"eslint-plugin-react": "^7.31.8",
61+
"eslint-plugin-import": "^2.27.5",
62+
"eslint-plugin-jsx-a11y": "^6.7.1",
63+
"eslint-plugin-react": "^7.32.2",
6364
"eslint-plugin-react-hooks": "^4.6.0",
6465
"install-peers-cli": "^2.2.0",
65-
"jest": "^29.0.3",
66-
"rollup": "^2.79.1",
66+
"jest": "^29.6.1",
67+
"rollup": "^3.26.2",
6768
"rollup-plugin-copy": "^3.4.0",
68-
"rollup-plugin-filesize": "^9.1.2",
69-
"typescript": "^5.0.4",
70-
"unimported": "^1.22.0"
69+
"rollup-plugin-filesize": "^10.0.0",
70+
"typescript": "^5.1.6",
71+
"unimported": "^1.29.2"
7172
}
7273
}

lib/rollup.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import filesize from 'rollup-plugin-filesize';
55
import eslint from '@rollup/plugin-eslint';
66
import copy from 'rollup-plugin-copy';
77

8-
import pkg from './package.json';
8+
import pkg from './package.json' assert { type: 'json' };
99

1010
const INPUT_FILE_PATH = 'src/index.ts';
1111

lib/src/form.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,14 @@ export function useFormObject<K, T>(
454454
) {
455455
const setFieldValue = useCallback(
456456
(...entries: EntriesAsList<NonNullable<T>>) => {
457+
// NOTE: there was a weird issue when using isCallable after
458+
// typescript upgrade. So using a specific isNotCallable here
459+
function isNotCallable(
460+
value: SetValueArg<NonNullable<T>[keyof NonNullable<T>]>,
461+
): value is NonNullable<T>[keyof NonNullable<T>] {
462+
return typeof value !== 'function';
463+
}
464+
457465
// NOTE: may need to cast callableValue here
458466
const [callableValue, key] = entries;
459467
onChange(
@@ -463,11 +471,12 @@ export function useFormObject<K, T>(
463471
? defaultValue()
464472
: defaultValue
465473
);
474+
const val = baseValue[key];
466475
return {
467476
...baseValue,
468-
[key]: isCallable(callableValue)
469-
? callableValue(baseValue[key])
470-
: callableValue,
477+
[key]: isNotCallable(callableValue)
478+
? callableValue
479+
: callableValue(val),
471480
};
472481
},
473482
name,

lib/src/schema.d.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ export type ArraySchema<Value, TopValue = Value, Context = undefined> = {
4444
context: Context,
4545
) => Schema<Value, TopValue, Context>;
4646
keySelector: (value: Value) => string | number;
47+
48+
// for accumulateValues
49+
forceValue?: NonNullable<Value[]> | typeof undefinedValue | typeof nullValue,
50+
defaultValue?: NonNullable<Value[]> | typeof undefinedValue | typeof nullValue,
4751
}
4852

4953
export type ObjectSchema<Value, TopValue = Value, Context = undefined> = {
@@ -63,6 +67,10 @@ export type ObjectSchema<Value, TopValue = Value, Context = undefined> = {
6367
[fieldDependencies]?: { [K in keyof Value]: (keyof Value)[] };
6468
}
6569
);
70+
71+
// for accumulateValues
72+
forceValue?: NonNullable<Value> | typeof undefinedValue | typeof nullValue,
73+
defaultValue?: NonNullable<Value> | typeof undefinedValue | typeof nullValue,
6674
}
6775

6876
export type Error<Value> = (

lib/src/schema.js

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ export function accumulateValues(
4141
keySelector,
4242
} = schema;
4343

44+
if (isDefined(schema.forceValue)) {
45+
if (schema.forceValue === undefinedValue) {
46+
return undefined;
47+
}
48+
if (schema.forceValue === nullValue) {
49+
return null;
50+
}
51+
return schema.forceValue;
52+
}
53+
4454
const isSchemaForArray = (!!member && !!keySelector);
4555
const isSchemaForObject = !!fields;
4656

@@ -57,7 +67,16 @@ export function accumulateValues(
5767
return value;
5868
});
5969
if (hasNoValues(values)) {
60-
// FIXME: array will always be empty array
70+
if (isDefined(schema.defaultValue)) {
71+
if (schema.defaultValue === undefinedValue) {
72+
return undefined;
73+
}
74+
if (schema.defaultValue === nullValue) {
75+
return null;
76+
}
77+
return schema.defaultValue;
78+
}
79+
// FIXME: should we instead use (return nullable ? null : undefined)?
6180
return [];
6281
}
6382
return values;
@@ -84,21 +103,20 @@ export function accumulateValues(
84103
{},
85104
);
86105
if (hasNoKeys(values)) {
106+
if (isDefined(schema.defaultValue)) {
107+
if (schema.defaultValue === undefinedValue) {
108+
return undefined;
109+
}
110+
if (schema.defaultValue === nullValue) {
111+
return null;
112+
}
113+
return schema.defaultValue;
114+
}
87115
return nullable ? null : undefined;
88116
}
89117
return values;
90118
}
91119

92-
if (isDefined(schema.forceValue)) {
93-
if (schema.forceValue === undefinedValue) {
94-
return undefined;
95-
}
96-
if (schema.forceValue === nullValue) {
97-
return null;
98-
}
99-
return schema.forceValue;
100-
}
101-
102120
const requiredCondition = schema.requiredValidation ?? genericRequiredCondition;
103121

104122
if (!requiredCondition(obj, baseValue, context)) {
@@ -208,6 +226,10 @@ export function accumulateDifferentialErrors(
208226
context = undefined,
209227
depsChanged = false,
210228
) {
229+
// NOTE: schema can be undefined if the schema changed
230+
if (!schema) {
231+
return undefined;
232+
}
211233
if (!depsChanged && oldObj === newObj) {
212234
return oldError;
213235
}
@@ -322,12 +344,16 @@ export function accumulateDifferentialErrors(
322344
return hasNoKeys(errors) ? undefined : errors;
323345
}
324346

325-
// NOTE: we only run required validation when the actual field changes
326-
if (!depsChanged && schema.required) {
327-
const requiredCondition = schema.requiredValidation ?? genericRequiredCondition;
328-
const error = requiredCondition(newObj, baseValue, context);
329-
if (error) {
330-
return error;
347+
if (schema.required) {
348+
if (
349+
(depsChanged && oldObj === newObj && !!oldError)
350+
|| (oldObj !== newObj)
351+
) {
352+
const requiredCondition = schema.requiredValidation ?? genericRequiredCondition;
353+
const error = requiredCondition(newObj, baseValue, context);
354+
if (error) {
355+
return error;
356+
}
331357
}
332358
}
333359

0 commit comments

Comments
 (0)