@neovici/cosmoz-form 2.4.0 → 2.5.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 (82) hide show
  1. package/dist/async-rule.d.ts +21 -11
  2. package/dist/async-rule.d.ts.map +1 -1
  3. package/dist/inputs/autocomplete.d.ts +1 -1
  4. package/dist/inputs/autocomplete.d.ts.map +1 -1
  5. package/dist/inputs/base.d.ts +4 -4
  6. package/dist/inputs/base.d.ts.map +1 -1
  7. package/dist/inputs/base.js +15 -11
  8. package/dist/inputs/basic.d.ts +1 -1
  9. package/dist/inputs/basic.d.ts.map +1 -1
  10. package/dist/inputs/common.d.ts +8 -8
  11. package/dist/inputs/common.d.ts.map +1 -1
  12. package/dist/inputs/common.js +3 -3
  13. package/dist/inputs/date-range.d.ts +1 -1
  14. package/dist/inputs/date-range.d.ts.map +1 -1
  15. package/dist/inputs/file-drop.d.ts +1 -1
  16. package/dist/inputs/file-drop.d.ts.map +1 -1
  17. package/dist/inputs/file.d.ts +1 -1
  18. package/dist/inputs/file.d.ts.map +1 -1
  19. package/dist/inputs/inline-file.d.ts +1 -1
  20. package/dist/inputs/inline-file.d.ts.map +1 -1
  21. package/dist/inputs/inline-file.js +2 -1
  22. package/dist/inputs/read-only-number.d.ts +1 -1
  23. package/dist/inputs/read-only-number.d.ts.map +1 -1
  24. package/dist/inputs/read-only-number.js +3 -3
  25. package/dist/inputs/toggle.d.ts +1 -1
  26. package/dist/inputs/toggle.d.ts.map +1 -1
  27. package/dist/make-debounce-runner.d.ts +2 -2
  28. package/dist/make-debounce-runner.d.ts.map +1 -1
  29. package/dist/make-debounce-runner.js +10 -2
  30. package/dist/make-take-latest-runner.d.ts +2 -2
  31. package/dist/make-take-latest-runner.d.ts.map +1 -1
  32. package/dist/make-take-latest-runner.js +1 -0
  33. package/dist/render/fields.d.ts +11 -11
  34. package/dist/render/fields.d.ts.map +1 -1
  35. package/dist/render/fields.js +2 -3
  36. package/dist/render/items.d.ts +12 -8
  37. package/dist/render/items.d.ts.map +1 -1
  38. package/dist/render/items.js +5 -4
  39. package/dist/test/apply-rules.test.d.ts +2 -0
  40. package/dist/test/apply-rules.test.d.ts.map +1 -0
  41. package/dist/test/apply-rules.test.js +295 -0
  42. package/dist/test/use-items.test.js +69 -2
  43. package/dist/test/use-validated-form.test.js +120 -1
  44. package/dist/types/index.d.ts +27 -27
  45. package/dist/types/index.d.ts.map +1 -1
  46. package/dist/use-async-form-core.d.ts +6 -6
  47. package/dist/use-async-form-core.d.ts.map +1 -1
  48. package/dist/use-async-form-core.js +9 -7
  49. package/dist/use-form-core.d.ts +3 -2
  50. package/dist/use-form-core.d.ts.map +1 -1
  51. package/dist/use-form-core.js +30 -7
  52. package/dist/use-form.d.ts +1 -1
  53. package/dist/use-form.d.ts.map +1 -1
  54. package/dist/use-form.js +1 -1
  55. package/dist/use-items/apply-rules.d.ts +10 -5
  56. package/dist/use-items/apply-rules.d.ts.map +1 -1
  57. package/dist/use-items/apply-rules.js +3 -3
  58. package/dist/use-items/use-async-rules.d.ts +4 -3
  59. package/dist/use-items/use-async-rules.d.ts.map +1 -1
  60. package/dist/use-items/use-async-rules.js +6 -5
  61. package/dist/use-items/use-items.d.ts +6 -4
  62. package/dist/use-items/use-items.d.ts.map +1 -1
  63. package/dist/use-items/use-items.js +44 -11
  64. package/dist/use-items/use-validated-items.d.ts +6 -4
  65. package/dist/use-items/use-validated-items.d.ts.map +1 -1
  66. package/dist/use-items/use-validated-items.js +5 -3
  67. package/dist/use-validated-form$.d.ts +7 -6
  68. package/dist/use-validated-form$.d.ts.map +1 -1
  69. package/dist/use-validated-form$.js +2 -2
  70. package/dist/use-validated-form-core.d.ts +12 -10
  71. package/dist/use-validated-form-core.d.ts.map +1 -1
  72. package/dist/use-validated-form-core.js +5 -5
  73. package/dist/use-validated-form.d.ts +7 -5
  74. package/dist/use-validated-form.d.ts.map +1 -1
  75. package/dist/use-validated-form.js +3 -3
  76. package/dist/validation/index.d.ts +10 -10
  77. package/dist/validation/index.d.ts.map +1 -1
  78. package/dist/validation/index.js +12 -12
  79. package/dist/validation/rules.d.ts +6 -6
  80. package/dist/validation/rules.d.ts.map +1 -1
  81. package/dist/validation/rules.js +8 -6
  82. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  import type { AsyncItemRule } from './async-rule';
2
2
  import type { UseForm } from './use-form-core';
3
3
  /**
4
- * Composes with UseForm<T> to add async rules.
5
- * Returns UseForm<T> & { processing } where processing is true while any
4
+ * Composes with UseForm<T, C> to add async rules.
5
+ * Returns UseForm<T, C> & { processing } where processing is true while any
6
6
  * async rule is in flight.
7
7
  *
8
8
  * Async patches call onChange(patch, false) — they do not mark the form touched.
@@ -10,12 +10,12 @@ import type { UseForm } from './use-form-core';
10
10
  * patch — sync rules cascade on top of them, which is expected.
11
11
  *
12
12
  * Usage:
13
- * const form = useValidatedForm({ fields, initial, rules });
13
+ * const form = useValidatedForm({ fields, initial, rules, context });
14
14
  * const { processing } = useAsyncFormCore(form, asyncRules);
15
15
  */
16
- export declare const useAsyncFormCore: <T extends object>(form: UseForm<T>, asyncRules: readonly AsyncItemRule<T>[] | undefined, opts?: {
17
- onError?: (err: unknown, rule: AsyncItemRule<T>) => void;
18
- }) => UseForm<T> & {
16
+ export declare const useAsyncFormCore: <T extends object, C extends object = object>(form: UseForm<T, C>, asyncRules: readonly AsyncItemRule<T, C>[] | undefined, opts?: {
17
+ onError?: (err: unknown, rule: AsyncItemRule<T, C>) => void;
18
+ }) => UseForm<T, C> & {
19
19
  processing: boolean;
20
20
  };
21
21
  //# sourceMappingURL=use-async-form-core.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-async-form-core.d.ts","sourceRoot":"","sources":["../src/use-async-form-core.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,cAAc,CAAC;AAE/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAU/C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,MAAM,EAChD,MAAM,OAAO,CAAC,CAAC,CAAC,EAChB,YAAY,SAAS,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,EACnD,OAAO;IAAE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,IAAI,CAAA;CAAE,KACjE,OAAO,CAAC,CAAC,CAAC,GAAG;IAAE,UAAU,EAAE,OAAO,CAAA;CAkEpC,CAAC"}
1
+ {"version":3,"file":"use-async-form-core.d.ts","sourceRoot":"","sources":["../src/use-async-form-core.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,cAAc,CAAC;AAE/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAU/C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAC3E,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,EACnB,YAAY,SAAS,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,SAAS,EACtD,OAAO;IAAE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,CAAA;CAAE,KACpE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAAE,UAAU,EAAE,OAAO,CAAA;CAqEvC,CAAC"}
@@ -6,8 +6,8 @@ const DEFAULT_ON_ERROR = (err) => {
6
6
  console.error('[cosmoz-form] async rule error:', err);
7
7
  };
8
8
  /**
9
- * Composes with UseForm<T> to add async rules.
10
- * Returns UseForm<T> & { processing } where processing is true while any
9
+ * Composes with UseForm<T, C> to add async rules.
10
+ * Returns UseForm<T, C> & { processing } where processing is true while any
11
11
  * async rule is in flight.
12
12
  *
13
13
  * Async patches call onChange(patch, false) — they do not mark the form touched.
@@ -15,7 +15,7 @@ const DEFAULT_ON_ERROR = (err) => {
15
15
  * patch — sync rules cascade on top of them, which is expected.
16
16
  *
17
17
  * Usage:
18
- * const form = useValidatedForm({ fields, initial, rules });
18
+ * const form = useValidatedForm({ fields, initial, rules, context });
19
19
  * const { processing } = useAsyncFormCore(form, asyncRules);
20
20
  */
21
21
  export const useAsyncFormCore = (form, asyncRules, opts) => {
@@ -32,16 +32,17 @@ export const useAsyncFormCore = (form, asyncRules, opts) => {
32
32
  for (const runner of runnersRef.current.values())
33
33
  runner.cancel();
34
34
  }, []);
35
- // Dep-check + rule dispatch: runs after every values change
35
+ // Dep-check + rule dispatch: runs after every values or context change
36
36
  useEffect(() => {
37
37
  if (!asyncRules?.length)
38
38
  return;
39
+ const context = form.context;
39
40
  for (const rule of asyncRules) {
40
41
  const [ruleFn, depsFn, runnerFactory = makeTakeLatestRunner] = rule;
41
42
  if (!runnersRef.current.has(rule)) {
42
43
  runnersRef.current.set(rule, runnerFactory());
43
44
  }
44
- const deps = depsFn(form.values);
45
+ const deps = depsFn(form.values, undefined, context);
45
46
  const prev = prevDepsRef.current.get(rule);
46
47
  // Skip if deps unchanged (Object.is per element, same as applyRules)
47
48
  if (prev != null && !changed(deps, prev)) {
@@ -53,7 +54,8 @@ export const useAsyncFormCore = (form, asyncRules, opts) => {
53
54
  if (pendingCount.current === 1)
54
55
  setProcessing(true);
55
56
  runner
56
- .run(ruleFn, form.values, (patch) => form.onChange(patch, false))
57
+ .run(ruleFn, form.values, (patch) => form.onChange(patch, false), // intermediate: no touch
58
+ { context })
57
59
  .then((result) => {
58
60
  if (result !== null) {
59
61
  form.onChange(result, false); // final: no touch
@@ -66,6 +68,6 @@ export const useAsyncFormCore = (form, asyncRules, opts) => {
66
68
  setProcessing(false);
67
69
  });
68
70
  }
69
- }, [form.values]);
71
+ }, [form.values, form.context]);
70
72
  return { ...form, processing };
71
73
  };
@@ -1,7 +1,8 @@
1
1
  import { StateUpdater } from '@pionjs/pion';
2
2
  import { ItemRule } from './use-items/apply-rules';
3
- export interface UseForm<T extends object> {
3
+ export interface UseForm<T extends object, C extends object = object> {
4
4
  values: T;
5
+ context: C;
5
6
  onReset: () => void;
6
7
  onValues: (valueOrFn: T | ((values: T) => T), touched?: boolean) => void;
7
8
  onChange: (update: Partial<T> | ((values: T) => Partial<T>), touched?: boolean) => void;
@@ -9,5 +10,5 @@ export interface UseForm<T extends object> {
9
10
  touched: boolean;
10
11
  }
11
12
  export type FormValues<T extends object> = readonly [T, T];
12
- export declare const useFormCore: <T extends object>(state: FormValues<T>, setState: StateUpdater<FormValues<T>>, rules?: readonly ItemRule<T>[]) => UseForm<T>;
13
+ export declare const useFormCore: <T extends object, C extends object = object>(state: FormValues<T>, setState: StateUpdater<FormValues<T>>, rules?: readonly ItemRule<T, C>[], context?: C, externalTouched?: boolean) => UseForm<T, C>;
13
14
  //# sourceMappingURL=use-form-core.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-form-core.d.ts","sourceRoot":"","sources":["../src/use-form-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,YAAY,EAAE,MAAM,cAAc,CAAC;AAElE,OAAO,EAAc,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAG/D,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM;IACxC,MAAM,EAAE,CAAC,CAAC;IACV,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACzE,QAAQ,EAAE,CACT,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,EAChD,OAAO,CAAC,EAAE,OAAO,KACb,IAAI,CAAC;IACV,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;IACzD,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE3D,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAC3C,OAAO,UAAU,CAAC,CAAC,CAAC,EACpB,UAAU,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EACrC,QAAQ,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,KAC5B,OAAO,CAAC,CAAC,CA8DX,CAAC"}
1
+ {"version":3,"file":"use-form-core.d.ts","sourceRoot":"","sources":["../src/use-form-core.ts"],"names":[],"mappings":"AACA,OAAO,EACN,YAAY,EAKZ,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAc,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAE/D,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IACnE,MAAM,EAAE,CAAC,CAAC;IACV,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACzE,QAAQ,EAAE,CACT,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,EAChD,OAAO,CAAC,EAAE,OAAO,KACb,IAAI,CAAC;IACV,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;IACzD,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,IAAI,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE3D,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EACtE,OAAO,UAAU,CAAC,CAAC,CAAC,EACpB,UAAU,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EACrC,QAAQ,SAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EACjC,UAAU,CAAC,EACX,kBAAkB,OAAO,KACvB,OAAO,CAAC,CAAC,EAAE,CAAC,CA2Fd,CAAC"}
@@ -1,11 +1,31 @@
1
- import { useCallback, useMemo } from '@pionjs/pion';
2
1
  import { invoke } from '@neovici/cosmoz-utils/function';
2
+ import { useCallback, useEffect, useMemo, useRef, } from '@pionjs/pion';
3
+ import { touch, touched, untouch } from './touch';
3
4
  import { applyRules } from './use-items/apply-rules';
4
- import { touch, untouch, touched } from './touch';
5
- export const useFormCore = (state, setState, rules) => {
5
+ export const useFormCore = (state, setState, rules, context, externalTouched) => {
6
6
  const [, values] = state;
7
+ // Re-apply rules when context changes, passing oldContext so depsFn comparisons
8
+ // correctly detect the change (new context vs old context for the same values).
9
+ const prevContextRef = useRef(undefined);
10
+ useEffect(() => {
11
+ const oldContext = prevContextRef.current;
12
+ prevContextRef.current = context;
13
+ if (oldContext === undefined)
14
+ return; // skip mount
15
+ setState(([initial, values]) => [
16
+ initial,
17
+ touch(applyRules({
18
+ oldItem: values,
19
+ newItem: values,
20
+ rules,
21
+ context,
22
+ oldContext,
23
+ }), touched(values)),
24
+ ]);
25
+ }, [context]);
7
26
  return {
8
27
  values,
28
+ context: (context ?? {}),
9
29
  onReset: useCallback(() => setState(([initial]) => [initial, initial]), [setState]),
10
30
  onValues: useCallback((valuesOrFn, touched = true) => setState(([initial, prev]) => [
11
31
  initial,
@@ -13,8 +33,9 @@ export const useFormCore = (state, setState, rules) => {
13
33
  oldItem: prev,
14
34
  newItem: invoke(valuesOrFn, prev),
15
35
  rules,
36
+ context,
16
37
  }), touched),
17
- ]), [rules, setState]),
38
+ ]), [rules, setState, context]),
18
39
  onChange: useCallback((update, touched = true) => setState(([initial, values]) => [
19
40
  initial,
20
41
  touch(applyRules({
@@ -24,8 +45,9 @@ export const useFormCore = (state, setState, rules) => {
24
45
  ...invoke(update, values),
25
46
  },
26
47
  rules,
48
+ context,
27
49
  }), touched),
28
- ]), [rules, setState]),
50
+ ]), [rules, setState, context]),
29
51
  load: useCallback((values, rulesOverride) => {
30
52
  if (!values) {
31
53
  setState([values, values]);
@@ -35,9 +57,10 @@ export const useFormCore = (state, setState, rules) => {
35
57
  oldItem: undefined,
36
58
  newItem: values,
37
59
  rules: rulesOverride ?? rules,
60
+ context,
38
61
  }));
39
62
  setState([ini, ini]);
40
- }, [rules, setState]),
41
- touched: useMemo(() => touched(values), [values]),
63
+ }, [rules, setState, context]),
64
+ touched: useMemo(() => touched(values) || (externalTouched ?? false), [values, externalTouched]),
42
65
  };
43
66
  };
@@ -1,6 +1,6 @@
1
1
  import type { UseForm } from './use-form-core';
2
2
  import { ItemRule } from './use-items/apply-rules';
3
- export declare const processInitial: <T extends object>(initial: T, rules?: readonly ItemRule<T>[]) => T;
3
+ export declare const processInitial: <T extends object, C extends object = object>(initial: T, rules?: readonly ItemRule<T, C>[], context?: C) => T;
4
4
  export declare const useForm: <T extends object>(initial: T, rules?: readonly ItemRule<T>[]) => UseForm<T>;
5
5
  export { UseForm };
6
6
  //# sourceMappingURL=use-form.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-form.d.ts","sourceRoot":"","sources":["../src/use-form.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAc,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAc,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAE/D,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,MAAM,EAC9C,SAAS,CAAC,EACV,QAAQ,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,KAC5B,CAAyE,CAAC;AAE7E,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,EACvC,SAAS,CAAC,EACV,QAAQ,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,KAC5B,OAAO,CAAC,CAAC,CAOX,CAAC;AAEF,OAAO,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"use-form.d.ts","sourceRoot":"","sources":["../src/use-form.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAc,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAc,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAE/D,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EACzE,SAAS,CAAC,EACV,QAAQ,SAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EACjC,UAAU,CAAC,KACT,CAC2E,CAAC;AAE/E,eAAO,MAAM,OAAO,GAAI,CAAC,SAAS,MAAM,EACvC,SAAS,CAAC,EACV,QAAQ,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,KAC5B,OAAO,CAAC,CAAC,CAOX,CAAC;AAEF,OAAO,EAAE,OAAO,EAAE,CAAC"}
package/dist/use-form.js CHANGED
@@ -2,7 +2,7 @@ import { useState } from '@pionjs/pion';
2
2
  import { untouch } from './touch';
3
3
  import { useFormCore } from './use-form-core';
4
4
  import { applyRules } from './use-items/apply-rules';
5
- export const processInitial = (initial, rules) => untouch(applyRules({ oldItem: undefined, newItem: initial, rules }));
5
+ export const processInitial = (initial, rules, context) => untouch(applyRules({ oldItem: undefined, newItem: initial, rules, context }));
6
6
  export const useForm = (initial, rules) => {
7
7
  const [state, setState] = useState(() => {
8
8
  const ini = processInitial(initial, rules);
@@ -1,11 +1,16 @@
1
- export type Compute<T> = (current: T, item: T | undefined, index: number | undefined, oldIndex: number | undefined) => Partial<T>;
2
- export type Deps<T> = (current: T, index: number | undefined) => unknown[];
3
- export type ItemRule<T> = readonly [Compute<T>, Deps<T>?];
4
- export declare const applyRules: <T extends object>({ oldItem, newItem, rules, index, oldIndex, }: {
1
+ export type Compute<T, C extends object = object> = (current: T, item: T | undefined, index: number | undefined, oldIndex: number | undefined, context?: C) => Partial<T>;
2
+ export type Deps<T, C extends object = object> = (current: T, index: number | undefined, context?: C) => unknown[];
3
+ export type ItemRule<T, C extends object = object> = readonly [
4
+ Compute<T, C>,
5
+ Deps<T, C>?
6
+ ];
7
+ export declare const applyRules: <T extends object, C extends object = object>({ oldItem, newItem, rules, index, oldIndex, context, oldContext, }: {
5
8
  oldItem?: T | undefined;
6
9
  newItem: T;
7
- rules: readonly ItemRule<T>[] | undefined;
10
+ rules: readonly ItemRule<T, C>[] | undefined;
8
11
  index?: number;
9
12
  oldIndex?: number;
13
+ context?: C;
14
+ oldContext?: C;
10
15
  }) => T;
11
16
  //# sourceMappingURL=apply-rules.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"apply-rules.d.ts","sourceRoot":"","sources":["../../src/use-items/apply-rules.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CACxB,OAAO,EAAE,CAAC,EACV,IAAI,EAAE,CAAC,GAAG,SAAS,EACnB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,MAAM,GAAG,SAAS,KACxB,OAAO,CAAC,CAAC,CAAC,CAAC;AAChB,MAAM,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,OAAO,EAAE,CAAC;AAC3E,MAAM,MAAM,QAAQ,CAAC,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1D,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,+CAM1C;IACF,OAAO,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IACxB,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB,KAAG,CAcH,CAAC"}
1
+ {"version":3,"file":"apply-rules.d.ts","sourceRoot":"","sources":["../../src/use-items/apply-rules.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,CACnD,OAAO,EAAE,CAAC,EACV,IAAI,EAAE,CAAC,GAAG,SAAS,EACnB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,CAAC,EAAE,CAAC,KACP,OAAO,CAAC,CAAC,CAAC,CAAC;AAChB,MAAM,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,CAChD,OAAO,EAAE,CAAC,EACV,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,CAAC,EAAE,CAAC,KACP,OAAO,EAAE,CAAC;AACf,MAAM,MAAM,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,SAAS;IAC7D,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IACb,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CACX,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,oEAQrE;IACF,OAAO,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC;IACxB,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,EAAE,SAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,UAAU,CAAC,EAAE,CAAC,CAAC;CACf,KAAG,CAiBH,CAAC"}
@@ -1,13 +1,13 @@
1
1
  const changed = (values, lastValues) => !lastValues || values.some((value, i) => !Object.is(lastValues[i], value));
2
- export const applyRules = ({ oldItem, newItem, rules, index, oldIndex = index, }) => {
2
+ export const applyRules = ({ oldItem, newItem, rules, index, oldIndex = index, context, oldContext = context, }) => {
3
3
  if (!rules)
4
4
  return newItem;
5
5
  return rules.reduce((currentItem, [computeFn, depsFn]) => oldItem &&
6
6
  depsFn &&
7
- !changed(depsFn(currentItem, index), depsFn(oldItem, oldIndex))
7
+ !changed(depsFn(currentItem, index, context), depsFn(oldItem, oldIndex, oldContext))
8
8
  ? currentItem
9
9
  : {
10
10
  ...currentItem,
11
- ...computeFn(currentItem, oldItem, index, oldIndex),
11
+ ...computeFn(currentItem, oldItem, index, oldIndex, context),
12
12
  }, newItem);
13
13
  };
@@ -6,11 +6,12 @@ import type { UseItemsCore } from './use-items';
6
6
  *
7
7
  * Usage:
8
8
  * const core = useItems({ initial, rules });
9
- * useAsyncRules(core.items, asyncRules, core.update);
9
+ * useAsyncRules(core.items, asyncRules, core.update, { context });
10
10
  * return core;
11
11
  */
12
- export declare const useAsyncRules: <T extends object>(items: T[], asyncRules: readonly AsyncItemRule<T>[] | undefined, update: UseItemsCore<T>["update"], opts?: {
13
- onError?: (err: unknown, rule: AsyncItemRule<T>, index: number) => void;
12
+ export declare const useAsyncRules: <T extends object, C extends object = object>(items: T[], asyncRules: readonly AsyncItemRule<T, C>[] | undefined, update: UseItemsCore<T>["update"], opts?: {
13
+ context?: C;
14
+ onError?: (err: unknown, rule: AsyncItemRule<T, C>, index: number) => void;
14
15
  }) => {
15
16
  processing: boolean;
16
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"use-async-rules.d.ts","sourceRoot":"","sources":["../../src/use-items/use-async-rules.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,eAAe,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAuBhD;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,MAAM,EAC7C,OAAO,CAAC,EAAE,EACV,YAAY,SAAS,aAAa,CAAC,CAAC,CAAC,EAAE,GAAG,SAAS,EACnD,QAAQ,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EACjC,OAAO;IACN,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACxE,KACC;IAAE,UAAU,EAAE,OAAO,CAAA;CA0EvB,CAAC"}
1
+ {"version":3,"file":"use-async-rules.d.ts","sourceRoot":"","sources":["../../src/use-items/use-async-rules.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAe,MAAM,eAAe,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA6BhD;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EACxE,OAAO,CAAC,EAAE,EACV,YAAY,SAAS,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,SAAS,EACtD,QAAQ,YAAY,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EACjC,OAAO;IACN,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3E,KACC;IAAE,UAAU,EAAE,OAAO,CAAA;CA2EvB,CAAC"}
@@ -17,10 +17,11 @@ const ensureRuleTracking = (rule, runnersRef, prevDepsRef) => {
17
17
  *
18
18
  * Usage:
19
19
  * const core = useItems({ initial, rules });
20
- * useAsyncRules(core.items, asyncRules, core.update);
20
+ * useAsyncRules(core.items, asyncRules, core.update, { context });
21
21
  * return core;
22
22
  */
23
23
  export const useAsyncRules = (items, asyncRules, update, opts) => {
24
+ const context = opts?.context;
24
25
  const onError = opts?.onError ?? DEFAULT_ON_ERROR;
25
26
  const pendingCount = useRef(0);
26
27
  const [processing, setProcessing] = useState(false);
@@ -34,7 +35,7 @@ export const useAsyncRules = (items, asyncRules, update, opts) => {
34
35
  }
35
36
  }
36
37
  }, []);
37
- // Dep-check + rule dispatch: runs after every items change
38
+ // Dep-check + rule dispatch: runs after every items or context change
38
39
  useEffect(() => {
39
40
  if (!asyncRules?.length) {
40
41
  return;
@@ -47,7 +48,7 @@ export const useAsyncRules = (items, asyncRules, update, opts) => {
47
48
  if (!runnersForRule.has(idx)) {
48
49
  runnersForRule.set(idx, runnerFactory());
49
50
  }
50
- const deps = depsFn(item, idx);
51
+ const deps = depsFn(item, idx, context);
51
52
  const prev = prevDepsRef.current.get(rule).get(idx);
52
53
  if (prev != null && !changed(deps, prev)) {
53
54
  continue;
@@ -59,7 +60,7 @@ export const useAsyncRules = (items, asyncRules, update, opts) => {
59
60
  setProcessing(true);
60
61
  runner
61
62
  .run(ruleFn, item, (patch) => update(idx, patch), // intermediate: no touch
62
- { index: idx })
63
+ { index: idx, context })
63
64
  .then((result) => {
64
65
  if (result !== null) {
65
66
  update(idx, result);
@@ -73,6 +74,6 @@ export const useAsyncRules = (items, asyncRules, update, opts) => {
73
74
  });
74
75
  }
75
76
  }
76
- }, [items]);
77
+ }, [items, context]);
77
78
  return { processing };
78
79
  };
@@ -1,8 +1,10 @@
1
1
  import { StateUpdater } from '@pionjs/pion';
2
2
  import { ItemRule } from './apply-rules';
3
- interface Props<T extends object> {
3
+ interface Props<T extends object, C extends object = object> {
4
4
  initial: T[];
5
- rules?: ItemRule<T>[];
5
+ rules?: ItemRule<T, C>[];
6
+ context?: C;
7
+ touched?: boolean;
6
8
  }
7
9
  export type UseItemsCore<T extends object> = {
8
10
  items: T[];
@@ -16,10 +18,10 @@ export type UseItemsCore<T extends object> = {
16
18
  clear: () => void;
17
19
  load: (items: T[], rulesOverride?: ItemRule<T>[]) => void;
18
20
  };
19
- export declare const useItemsCore: <T extends object>({ items, setItems, initial, rules, }: Props<T> & {
21
+ export declare const useItemsCore: <T extends object, C extends object = object>({ items, setItems, initial, rules, context, touched: externalTouched, }: Props<T, C> & {
20
22
  items: T[];
21
23
  setItems: StateUpdater<T[]>;
22
24
  }) => UseItemsCore<T>;
23
- export declare const useItems: <T extends object>({ initial, rules }: Props<T>) => UseItemsCore<T>;
25
+ export declare const useItems: <T extends object, C extends object = object>({ initial, rules, context, touched, }: Props<T, C>) => UseItemsCore<T>;
24
26
  export {};
25
27
  //# sourceMappingURL=use-items.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-items.d.ts","sourceRoot":"","sources":["../../src/use-items/use-items.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAkC,MAAM,cAAc,CAAC;AAE5E,OAAO,EAAc,QAAQ,EAAE,MAAM,eAAe,CAAC;AAErD,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM;IAC/B,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;CACtB;AAYD,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI;IAC5C,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,CACP,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EACxD,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,KACd,IAAI,CAAC;IACV,SAAS,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACrE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,EAAE,sCAK5C,KAAK,CAAC,CAAC,CAAC,GAAG;IACb,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;CAC5B,KAAG,YAAY,CAAC,CAAC,CA+FjB,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,MAAM,EAAE,oBAAoB,KAAK,CAAC,CAAC,CAAC,oBAStE,CAAC"}
1
+ {"version":3,"file":"use-items.d.ts","sourceRoot":"","sources":["../../src/use-items/use-items.ts"],"names":[],"mappings":"AACA,OAAO,EACN,YAAY,EAMZ,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAc,QAAQ,EAAE,MAAM,eAAe,CAAC;AAErD,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IAC1D,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACzB,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAYD,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,MAAM,IAAI;IAC5C,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,CACP,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EACxD,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,KACd,IAAI,CAAC;IACV,SAAS,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACrE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAC7B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;CAC1D,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,yEAOvE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAChB,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,QAAQ,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;CAC5B,KAAG,YAAY,CAAC,CAAC,CAmIjB,CAAC;AAEF,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,uCAKnE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,oBAkBb,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { invoke } from '@neovici/cosmoz-utils/function';
2
- import { useCallback, useMemo, useState } from '@pionjs/pion';
2
+ import { useCallback, useEffect, useMemo, useRef, useState, } from '@pionjs/pion';
3
3
  import { touch, touched } from '../touch';
4
4
  import { applyRules } from './apply-rules';
5
5
  const changes = (indexOrChanges, update) => {
@@ -8,11 +8,28 @@ const changes = (indexOrChanges, update) => {
8
8
  }
9
9
  return [[indexOrChanges, update]];
10
10
  };
11
- export const useItemsCore = ({ items, setItems, initial, rules, }) => {
11
+ export const useItemsCore = ({ items, setItems, initial, rules, context, touched: externalTouched, }) => {
12
+ // Re-apply rules when context changes, passing oldContext so depsFn comparisons
13
+ // correctly detect the change (new context vs old context for the same item).
14
+ const prevContextRef = useRef(undefined);
15
+ useEffect(() => {
16
+ const oldContext = prevContextRef.current;
17
+ prevContextRef.current = context;
18
+ if (oldContext === undefined)
19
+ return; // skip mount
20
+ setItems((currentItems) => currentItems.map((oldItem, index) => touch(applyRules({
21
+ oldItem,
22
+ newItem: oldItem,
23
+ rules,
24
+ index,
25
+ context,
26
+ oldContext,
27
+ }), touched(oldItem))));
28
+ }, [context]);
12
29
  return {
13
30
  items,
14
31
  setItems,
15
- touched: touched(items),
32
+ touched: useMemo(() => touched(items) || (externalTouched ?? false), [items, externalTouched]),
16
33
  update: useCallback((indexOrChanges, update) => setItems((items = []) => touch(changes(indexOrChanges ?? items.length, update).reduce((acc, [index, update]) => [
17
34
  ...acc.slice(0, index),
18
35
  touch(applyRules({
@@ -20,9 +37,10 @@ export const useItemsCore = ({ items, setItems, initial, rules, }) => {
20
37
  newItem: { ...acc[index], ...update },
21
38
  rules,
22
39
  index,
40
+ context,
23
41
  })),
24
42
  ...acc.slice(index + 1),
25
- ], items))), [rules]),
43
+ ], items))), [rules, context]),
26
44
  updateAll: useCallback((updateOrFn) => setItems((items = []) => items.map((oldItem, index) => {
27
45
  const newItem = invoke(updateOrFn, oldItem);
28
46
  return touch(applyRules({
@@ -30,8 +48,9 @@ export const useItemsCore = ({ items, setItems, initial, rules, }) => {
30
48
  newItem: { ...oldItem, ...newItem },
31
49
  rules,
32
50
  index,
51
+ context,
33
52
  }));
34
- })), [rules]),
53
+ })), [rules, context]),
35
54
  remove: useCallback((rindex) => setItems((items = []) => touch([
36
55
  ...items.slice(0, rindex),
37
56
  ...items.slice(rindex + 1).map((item, index) => applyRules({
@@ -40,19 +59,33 @@ export const useItemsCore = ({ items, setItems, initial, rules, }) => {
40
59
  oldItem: item,
41
60
  index: index + rindex,
42
61
  oldIndex: index + rindex + 1,
62
+ context,
43
63
  })),
44
- ])), [rules]),
64
+ ])), [rules, context]),
45
65
  append: useCallback((appendedItems) => setItems((items = []) => touch(items.concat(appendedItems.map((item, index) => applyRules({
46
66
  rules,
47
67
  newItem: item,
48
68
  index: index + items.length,
49
- }))))), [rules]),
69
+ context,
70
+ }))))), [rules, context]),
50
71
  reset: useCallback(() => setItems(initial), [initial]),
51
72
  clear: useCallback(() => setItems(touch([])), []),
52
- load: useCallback((items, rulesOverride) => setItems(items.map((newItem, index) => applyRules({ newItem, index, rules: rulesOverride ?? rules }))), [rules]),
73
+ load: useCallback((items, rulesOverride) => setItems(items.map((newItem, index) => applyRules({
74
+ newItem,
75
+ index,
76
+ rules: rulesOverride ?? rules,
77
+ context,
78
+ }))), [rules, context]),
53
79
  };
54
80
  };
55
- export const useItems = ({ initial, rules }) => {
56
- const _initial = useMemo(() => initial.map((newItem, index) => applyRules({ rules, newItem, index })), [initial]), [items, setItems] = useState(_initial);
57
- return useItemsCore({ items, setItems, initial: _initial, rules });
81
+ export const useItems = ({ initial, rules, context, touched, }) => {
82
+ const _initial = useMemo(() => initial.map((newItem, index) => applyRules({ rules, newItem, index, context })), [initial]), [items, setItems] = useState(_initial);
83
+ return useItemsCore({
84
+ items,
85
+ setItems,
86
+ initial: _initial,
87
+ rules,
88
+ context,
89
+ touched,
90
+ });
58
91
  };
@@ -5,14 +5,16 @@ import { UseItemsCore } from './use-items';
5
5
  export type ValidatedItem = Partial<{
6
6
  [ERROR]: Errors | undefined;
7
7
  }>;
8
- interface Props<T extends ValidatedItem> {
8
+ interface Props<T extends ValidatedItem, C extends object = object> {
9
9
  initial: T[];
10
- rules?: ItemRule<T>[];
11
- fields: Fields<T>;
10
+ rules?: ItemRule<T, C>[];
11
+ fields: Fields<T, C>;
12
+ context?: C;
13
+ touched?: boolean;
12
14
  }
13
15
  export interface UseValidatedItems<T extends object> extends UseItemsCore<T & ValidatedItem> {
14
16
  invalid: boolean;
15
17
  }
16
- export declare const useValidatedItems: <T extends object>({ initial, rules, fields, }: Props<T>) => UseValidatedItems<T>;
18
+ export declare const useValidatedItems: <T extends object, C extends object = object>({ initial, rules, fields, context, touched, }: Props<T, C>) => UseValidatedItems<T>;
17
19
  export {};
18
20
  //# sourceMappingURL=use-validated-items.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-validated-items.d.ts","sourceRoot":"","sources":["../../src/use-items/use-validated-items.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAkB,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAY,YAAY,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;IAAE,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC,CAAC;AACrE,UAAU,KAAK,CAAC,CAAC,SAAS,aAAa;IACtC,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAClD,SAAQ,YAAY,CAAC,CAAC,GAAG,aAAa,CAAC;IACvC,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,EAAE,6BAIjD,KAAK,CAAC,CAAC,CAAC,KAAG,iBAAiB,CAAC,CAAC,CAsBhC,CAAC"}
1
+ {"version":3,"file":"use-validated-items.d.ts","sourceRoot":"","sources":["../../src/use-items/use-validated-items.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EAAE,KAAK,EAAkB,MAAM,eAAe,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAY,YAAY,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC;IAAE,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC,CAAC;AACrE,UAAU,KAAK,CAAC,CAAC,SAAS,aAAa,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IACjE,OAAO,EAAE,CAAC,EAAE,CAAC;IACb,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAE,SAAQ,YAAY,CACxE,CAAC,GAAG,aAAa,CACjB;IACA,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,+CAM5E,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAG,iBAAiB,CAAC,CAAC,CA4BnC,CAAC"}
@@ -2,12 +2,14 @@ import { useMeta } from '@neovici/cosmoz-utils/hooks/use-meta';
2
2
  import { useMemo } from '@pionjs/pion';
3
3
  import { ERROR, validateFields } from '../validation';
4
4
  import { useItems } from './use-items';
5
- export const useValidatedItems = ({ initial, rules, fields, }) => {
5
+ export const useValidatedItems = ({ initial, rules, fields, context, touched, }) => {
6
6
  const meta = useMeta({ fields }), validation = useMemo(() => [
7
- (item) => ({ [ERROR]: validateFields(meta.fields, item) }),
8
- ], [meta]), { items, ...rest } = useItems({
7
+ (item) => ({ [ERROR]: validateFields(meta.fields, item, context) }),
8
+ ], [meta, context]), { items, ...rest } = useItems({
9
9
  initial,
10
10
  rules: useMemo(() => [...(rules ?? []), validation], [rules, validation]),
11
+ context,
12
+ touched,
11
13
  }), invalid = useMemo(() => items.some((i) => i[ERROR]), [items]);
12
14
  return {
13
15
  ...rest,
@@ -4,11 +4,12 @@ import type { Fields } from './types';
4
4
  import { UseValidatedForm } from './use-validated-form';
5
5
  export type ProgressValue = string | number;
6
6
  export type Progress = [ProgressValue, ProgressValue];
7
- export interface Props<T extends object> {
8
- fields: Fields<T>;
7
+ export interface Props<T extends object, C extends object = object> {
8
+ fields: Fields<T, C>;
9
9
  initial: T;
10
- rules?: ItemRule<T>[];
11
- asyncRules?: readonly AsyncItemRule<T>[];
10
+ rules?: ItemRule<T, C>[];
11
+ asyncRules?: readonly AsyncItemRule<T, C>[];
12
+ context?: C;
12
13
  onSave?: (values: T, initial: T, setProgress?: (p: Progress) => void) => PromiseLike<unknown>;
13
14
  allowEmpty?: boolean;
14
15
  }
@@ -19,8 +20,8 @@ interface Opts {
19
20
  save$?: PromiseLike<unknown>;
20
21
  onSave: () => void;
21
22
  }
22
- export interface UseValidatedForm$<T extends object> extends UseValidatedForm<T>, Opts {
23
+ export interface UseValidatedForm$<T extends object, C extends object = object> extends UseValidatedForm<T, C>, Opts {
23
24
  }
24
- declare function useValidatedForm$<T extends object>({ fields, initial, rules, asyncRules, onSave, allowEmpty, }: Props<T>): UseValidatedForm$<T>;
25
+ declare function useValidatedForm$<T extends object, C extends object = object>({ fields, initial, rules, asyncRules, context, onSave, allowEmpty, }: Props<T, C>): UseValidatedForm$<T, C>;
25
26
  export { useValidatedForm$ };
26
27
  //# sourceMappingURL=use-validated-form$.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-validated-form$.d.ts","sourceRoot":"","sources":["../src/use-validated-form$.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,EAAE,gBAAgB,EAAoB,MAAM,sBAAsB,CAAC;AAE1E,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAEtD,MAAM,WAAW,KAAK,CAAC,CAAC,SAAS,MAAM;IACtC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,SAAS,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;IACzC,MAAM,CAAC,EAAE,CACR,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,CAAC,EACV,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,KAC/B,WAAW,CAAC,OAAO,CAAC,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,IAAI;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAClD,SAAQ,gBAAgB,CAAC,CAAC,CAAC,EAAE,IAAI;CAAG;AAErC,iBAAS,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,EAC5C,MAAM,EACN,OAAO,EACP,KAAK,EACL,UAAU,EACV,MAAM,EACN,UAAU,GACV,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAqBjC;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"use-validated-form$.d.ts","sourceRoot":"","sources":["../src/use-validated-form$.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC;AAC7B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtC,OAAO,EAAE,gBAAgB,EAAoB,MAAM,sBAAsB,CAAC;AAE1E,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAC5C,MAAM,MAAM,QAAQ,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAEtD,MAAM,WAAW,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IACjE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACrB,OAAO,EAAE,CAAC,CAAC;IACX,KAAK,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,SAAS,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC5C,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,MAAM,CAAC,EAAE,CACR,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,CAAC,EACV,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,KAC/B,WAAW,CAAC,OAAO,CAAC,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,IAAI;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAC7B,MAAM,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,CAC7E,SAAQ,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI;CAAG;AAExC,iBAAS,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EAAE,EACvE,MAAM,EACN,OAAO,EACP,KAAK,EACL,UAAU,EACV,OAAO,EACP,MAAM,EACN,UAAU,GACV,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,EAAE,CAAC,CAAC,CAqBvC;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import { useCallback, useState } from '@pionjs/pion';
2
2
  import { useAsyncFormCore } from './use-async-form-core';
3
3
  import { useValidatedForm } from './use-validated-form';
4
- function useValidatedForm$({ fields, initial, rules, asyncRules, onSave, allowEmpty, }) {
5
- const form = useValidatedForm({ fields, initial, rules });
4
+ function useValidatedForm$({ fields, initial, rules, asyncRules, context, onSave, allowEmpty, }) {
5
+ const form = useValidatedForm({ fields, initial, rules, context });
6
6
  const { processing } = useAsyncFormCore(form, asyncRules);
7
7
  const { values, invalid } = form;
8
8
  const [save$, setSave$] = useState();
@@ -1,17 +1,19 @@
1
1
  import { StateUpdater } from '@pionjs/pion';
2
- import { validate } from './validation';
3
- import { UseForm } from './use-form';
4
2
  import type { Fields } from './types';
5
- import type { ItemRule } from './use-items/apply-rules';
3
+ import { UseForm } from './use-form';
6
4
  import { FormValues } from './use-form-core';
7
- export declare const computeRules: <T extends object>(fields: Fields<T>, rules?: readonly ItemRule<T>[]) => ItemRule<T>[];
8
- type Validate<T extends object> = ReturnType<typeof validate<T>>;
9
- export interface UseValidatedForm<T extends object> extends UseForm<T>, Validate<T> {
5
+ import type { ItemRule } from './use-items/apply-rules';
6
+ import { validate } from './validation';
7
+ export declare const computeRules: <T extends object, C extends object = object>(fields: Fields<T, C>, rules?: readonly ItemRule<T, C>[]) => ItemRule<T, C>[];
8
+ type Validate<T extends object, C extends object = object> = ReturnType<typeof validate<T, C>>;
9
+ export interface UseValidatedForm<T extends object, C extends object = object> extends UseForm<T, C>, Validate<T, C> {
10
10
  }
11
- interface Props<T extends object> {
12
- fields?: Fields<T> | (() => Fields<T>);
13
- rules?: readonly ItemRule<T>[];
11
+ interface Props<T extends object, C extends object = object> {
12
+ fields?: Fields<T, C> | (() => Fields<T, C>);
13
+ rules?: readonly ItemRule<T, C>[];
14
+ context?: C;
15
+ touched?: boolean;
14
16
  }
15
- export declare const useValidatedFormCore: <T extends object>(state: FormValues<T>, setState: StateUpdater<FormValues<T>>, { fields: _fields, rules }: Readonly<Props<T>>) => UseValidatedForm<T>;
17
+ export declare const useValidatedFormCore: <T extends object, C extends object = object>(state: FormValues<T>, setState: StateUpdater<FormValues<T>>, { fields: _fields, rules, context, touched }: Readonly<Props<T, C>>) => UseValidatedForm<T, C>;
16
18
  export {};
17
19
  //# sourceMappingURL=use-validated-form-core.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-validated-form-core.d.ts","sourceRoot":"","sources":["../src/use-validated-form-core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAW,MAAM,cAAc,CAAC;AAErD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAe,MAAM,iBAAiB,CAAC;AAE1D,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,EAC5C,QAAQ,MAAM,CAAC,CAAC,CAAC,EACjB,QAAO,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAO,KAChC,QAAQ,CAAC,CAAC,CAAC,EAMb,CAAC;AAEF,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,IAAI,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAEjE,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,CACjD,SAAQ,OAAO,CAAC,CAAC,CAAC,EACjB,QAAQ,CAAC,CAAC,CAAC;CAAG;AAEhB,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACvC,KAAK,CAAC,EAAE,SAAS,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;CAC/B;AAED,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,MAAM,EACpD,OAAO,UAAU,CAAC,CAAC,CAAC,EACpB,UAAU,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EACrC,4BAA4B,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAC5C,gBAAgB,CAAC,CAAC,CAUpB,CAAC"}
1
+ {"version":3,"file":"use-validated-form-core.d.ts","sourceRoot":"","sources":["../src/use-validated-form-core.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAW,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AACrC,OAAO,EAAE,UAAU,EAAe,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,EACvE,QAAQ,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EACpB,QAAO,SAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAO,KACnC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAMhB,CAAC;AAEF,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,UAAU,CACtE,OAAO,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CACrB,CAAC;AAEF,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,CAC5E,SAAQ,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;CAAG;AAEzC,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,KAAK,CAAC,EAAE,SAAS,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAClC,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,oBAAoB,GAChC,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,MAAM,GAAG,MAAM,EAEzB,OAAO,UAAU,CAAC,CAAC,CAAC,EACpB,UAAU,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EACrC,8CAA8C,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KACjE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAavB,CAAC"}