@shivaedev/form 0.13.1 → 0.15.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 (54) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +83 -10
  3. package/dist/adapters/browserDraftStorage.d.ts.map +1 -1
  4. package/dist/adapters/browserDraftStorage.js +27 -2
  5. package/dist/adapters/browserDraftStorage.js.map +1 -1
  6. package/dist/adapters/draftCodec.d.ts +7 -0
  7. package/dist/adapters/draftCodec.d.ts.map +1 -0
  8. package/dist/adapters/draftCodec.js +40 -0
  9. package/dist/adapters/draftCodec.js.map +1 -0
  10. package/dist/adapters/numberInput.d.ts +15 -0
  11. package/dist/adapters/numberInput.d.ts.map +1 -0
  12. package/dist/adapters/numberInput.js +11 -0
  13. package/dist/adapters/numberInput.js.map +1 -0
  14. package/dist/adapters/persistence.d.ts +1 -1
  15. package/dist/adapters/persistence.d.ts.map +1 -1
  16. package/dist/adapters/persistence.js +91 -61
  17. package/dist/adapters/persistence.js.map +1 -1
  18. package/dist/adapters/react.d.ts.map +1 -1
  19. package/dist/adapters/react.js +3 -1
  20. package/dist/adapters/react.js.map +1 -1
  21. package/dist/adapters/useList.d.ts +23 -0
  22. package/dist/adapters/useList.d.ts.map +1 -0
  23. package/dist/adapters/useList.js +27 -0
  24. package/dist/adapters/useList.js.map +1 -0
  25. package/dist/draft.d.ts +2 -2
  26. package/dist/draft.d.ts.map +1 -1
  27. package/dist/draft.js +67 -45
  28. package/dist/draft.js.map +1 -1
  29. package/dist/draftValues.d.ts +13 -0
  30. package/dist/draftValues.d.ts.map +1 -0
  31. package/dist/draftValues.js +47 -0
  32. package/dist/draftValues.js.map +1 -0
  33. package/dist/field.d.ts +17 -0
  34. package/dist/field.d.ts.map +1 -0
  35. package/dist/field.js +20 -0
  36. package/dist/field.js.map +1 -0
  37. package/dist/form.d.ts.map +1 -1
  38. package/dist/form.js +17 -9
  39. package/dist/form.js.map +1 -1
  40. package/dist/persistence.d.ts +15 -11
  41. package/dist/persistence.d.ts.map +1 -1
  42. package/dist/persistence.js.map +1 -1
  43. package/package.json +4 -4
  44. package/src/adapters/browserDraftStorage.ts +30 -2
  45. package/src/adapters/draftCodec.ts +43 -0
  46. package/src/adapters/numberInput.ts +17 -0
  47. package/src/adapters/persistence.ts +97 -63
  48. package/src/adapters/react.ts +3 -1
  49. package/src/adapters/useList.ts +39 -0
  50. package/src/draft.ts +70 -62
  51. package/src/draftValues.ts +65 -0
  52. package/src/field.ts +34 -0
  53. package/src/form.ts +12 -6
  54. package/src/persistence.ts +17 -7
@@ -0,0 +1,27 @@
1
+ import { useAtomMount, useAtomRef, useAtomValue } from "@effect/atom-react";
2
+ import * as Atom from "effect/reactivity/Atom";
3
+ import { useMemo } from "react";
4
+ export function useList(form, name) {
5
+ useAtomMount(form.dirty);
6
+ const values = useAtomRef(form.field(name));
7
+ const error = useAtomValue(form.error(name));
8
+ const errors = useAtomValue(useMemo(() => Atom.readable((get) => values.map((_, index) => get(form.errorAt([name, index])))), [form, name, values]));
9
+ function change(next) {
10
+ form.change(name, next);
11
+ }
12
+ function current() {
13
+ return form.field(name).value;
14
+ }
15
+ return {
16
+ add: (value) => change([...current(), value]),
17
+ error,
18
+ items: values.map((value, index) => ({
19
+ error: errors[index],
20
+ onChange: (next) => change(current().map((item, at) => (at === index ? next : item))),
21
+ onRemove: () => change(current().filter((_, at) => at !== index)),
22
+ value,
23
+ })),
24
+ onBlur: () => form.blur(name),
25
+ };
26
+ }
27
+ //# sourceMappingURL=useList.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useList.js","sourceRoot":"","sources":["../../src/adapters/useList.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAE/C,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAWhC,MAAM,UAAU,OAAO,CAA6B,IAAoC,EAAE,IAAU;IACnG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,YAAY,CAC1B,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CACvH,CAAC;IACF,SAAS,MAAM,CAAC,IAAsB;QACrC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACzB,CAAC;IACD,SAAS,OAAO;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC;IAC/B,CAAC;IACD,OAAO;QACN,GAAG,EAAE,CAAC,KAAY,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;QACpD,KAAK;QACL,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YACpC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC;YACpB,QAAQ,EAAE,CAAC,IAAW,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5F,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC;YACjE,KAAK;SACL,CAAC,CAAC;QACH,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;KAC7B,CAAC;AACH,CAAC"}
package/dist/draft.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import * as Atom from "effect/reactivity/Atom";
2
2
  import * as AtomRef from "effect/reactivity/AtomRef";
3
+ import { type Entries } from "./draftValues.ts";
3
4
  import type { Persistence } from "./persistence.ts";
4
- type Entries = Readonly<Record<string, unknown>>;
5
5
  export declare function draft<TValues extends Entries>(initial: TValues, persistence?: Persistence<TValues>): {
6
6
  dirty: Atom.Atom<boolean>;
7
+ mounted: Atom.Atom<void>;
7
8
  receive: (incoming: TValues) => void;
8
9
  revert: () => void;
9
10
  submission: () => {
@@ -12,5 +13,4 @@ export declare function draft<TValues extends Entries>(initial: TValues, persist
12
13
  };
13
14
  values: AtomRef.AtomRef<TValues>;
14
15
  };
15
- export {};
16
16
  //# sourceMappingURL=draft.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../src/draft.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAC/C,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,KAAK,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAsCjD,wBAAgB,KAAK,CAAC,OAAO,SAAS,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC;IAuBjG,KAAK;IAIL,OAAO,aAAa,OAAO,KAAG,IAAI;IAOlC,MAAM,QAAM,IAAI;IAOhB,UAAU;QAGR,MAAM,cAAc,OAAO,KAAG,IAAI;QAalC,MAAM;;IAGR,MAAM;EAEP"}
1
+ {"version":3,"file":"draft.d.ts","sourceRoot":"","sources":["../src/draft.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAC/C,OAAO,KAAK,OAAO,MAAM,2BAA2B,CAAC;AACrD,OAAO,EAAgD,KAAK,OAAO,EAAoC,MAAM,kBAAkB,CAAC;AAChI,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,kBAAkB,CAAC;AAElE,wBAAgB,KAAK,CAAC,OAAO,SAAS,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC;;;wBAsE7E,OAAO,KAAG,IAAI;kBAUtB,IAAI;;QAWd,MAAM,cAAc,OAAO,KAAG,IAAI;QAYlC,MAAM;;;EAKT"}
package/dist/draft.js CHANGED
@@ -1,45 +1,61 @@
1
- import { Equal } from "effect";
2
1
  import * as Atom from "effect/reactivity/Atom";
3
2
  import * as AtomRef from "effect/reactivity/AtomRef";
4
- const none = {};
5
- function untouched({ baseline, current, settled }, name) {
6
- return Equal.equals(current[name], baseline[name]) || (Object.hasOwn(settled, name) && Equal.equals(current[name], settled[name]));
7
- }
8
- function changed(held) {
9
- return Object.keys({ ...held.baseline, ...held.current }).some((name) => !untouched(held, name));
10
- }
11
- function merged(held, incoming) {
12
- const result = {};
13
- for (const name of Object.keys({ ...held.current, ...incoming })) {
14
- const source = untouched(held, name) ? incoming : held.current;
15
- if (Object.hasOwn(source, name)) {
16
- result[name] = source[name];
17
- }
18
- }
19
- return result;
20
- }
21
- function matching(current, submitted) {
22
- return Object.fromEntries(Object.keys({ ...current, ...submitted })
23
- .filter((name) => Equal.equals(current[name], submitted[name]))
24
- .map((name) => [name, submitted[name]]));
25
- }
3
+ import { accepted, changed, changedFields, merged, mergeObserved, untouched } from "./draftValues.js";
26
4
  export function draft(initial, persistence) {
27
- const restored = persistence?.read();
28
- const loaded = {
29
- baseline: restored?.baseline ?? initial,
30
- current: restored?.values ?? initial,
31
- settled: restored ? Object.fromEntries(Object.entries(restored.values).filter(([name]) => !restored.edited.includes(name))) : none,
32
- };
33
- const state = AtomRef.make({
34
- baseline: initial,
35
- current: restored ? merged(loaded, initial) : initial,
36
- settled: none,
5
+ const none = {};
6
+ const state = AtomRef.make({ baseline: initial, current: initial, settled: none });
7
+ const local = new Set();
8
+ let previous = initial;
9
+ let receiving = false;
10
+ let refreshing = false;
11
+ function withoutWriting(run) {
12
+ receiving = true;
13
+ run();
14
+ receiving = false;
15
+ }
16
+ function restore(restored) {
17
+ const held = state.value;
18
+ const incoming = restored
19
+ ? merged({
20
+ baseline: restored.baseline,
21
+ current: restored.values,
22
+ settled: Object.fromEntries(Object.entries(restored.values).filter(([name]) => !restored.edited.includes(name))),
23
+ }, held.baseline)
24
+ : held.baseline;
25
+ withoutWriting(() => state.update((value) => ({ ...value, current: mergeObserved(value.current, incoming, local) })));
26
+ return local.size === 0;
27
+ }
28
+ const mounted = Atom.readable((get) => {
29
+ if (persistence) {
30
+ get.addFinalizer(persistence.observe(restore));
31
+ }
37
32
  });
33
+ function releaseCleanFields() {
34
+ for (const name of local) {
35
+ if (untouched(state.value, name)) {
36
+ local.delete(name);
37
+ }
38
+ }
39
+ }
40
+ function store(value, sameInput = refreshing) {
41
+ const edited = Object.keys({ ...value.baseline, ...value.current }).filter((name) => !untouched(value, name));
42
+ persistence?.write({ ...value.baseline, ...value.settled }, value.current, edited, sameInput);
43
+ }
38
44
  if (persistence) {
39
45
  state.subscribe((value) => {
46
+ const before = previous;
47
+ previous = value.current;
48
+ if (receiving) {
49
+ return;
50
+ }
51
+ if (!refreshing) {
52
+ for (const name of changedFields(before, value.current)) {
53
+ local.add(name);
54
+ }
55
+ }
56
+ releaseCleanFields();
40
57
  if (changed(value)) {
41
- const edited = Object.keys({ ...value.baseline, ...value.current }).filter((name) => !untouched(value, name));
42
- persistence.write({ ...value.baseline, ...value.settled }, value.current, edited);
58
+ store(value);
43
59
  }
44
60
  else {
45
61
  persistence.clear();
@@ -48,15 +64,20 @@ export function draft(initial, persistence) {
48
64
  }
49
65
  return {
50
66
  dirty: Atom.readable((get) => {
67
+ get(mounted);
51
68
  get.addFinalizer(state.subscribe((value) => get.setSelf(changed(value))));
52
69
  return changed(state.value);
53
70
  }),
71
+ mounted,
54
72
  receive: (incoming) => {
73
+ refreshing = true;
55
74
  state.update((held) => ({
56
75
  baseline: incoming,
57
76
  current: changed(held) ? merged(held, incoming) : incoming,
58
77
  settled: none,
59
78
  }));
79
+ refreshing = false;
80
+ releaseCleanFields();
60
81
  },
61
82
  revert: () => {
62
83
  state.update((held) => ({
@@ -67,19 +88,20 @@ export function draft(initial, persistence) {
67
88
  },
68
89
  submission: () => {
69
90
  const { baseline, current: submitted } = state.value;
91
+ const revision = persistence?.revision();
70
92
  return {
71
93
  accept: (incoming) => {
72
- state.update((held) => {
73
- if (held.baseline !== baseline) {
74
- return { ...held, settled: matching(held.current, submitted) };
94
+ withoutWriting(() => state.update((held) => accepted(held, baseline, submitted, incoming)));
95
+ releaseCleanFields();
96
+ if (changed(state.value)) {
97
+ store(state.value, true);
98
+ }
99
+ else {
100
+ const expected = revision?.();
101
+ if (expected !== undefined) {
102
+ persistence?.clear(expected);
75
103
  }
76
- return {
77
- ...held,
78
- baseline: incoming ?? submitted,
79
- current: incoming === undefined ? held.current : merged({ ...held, baseline: submitted, settled: none }, incoming),
80
- settled: none,
81
- };
82
- });
104
+ }
83
105
  },
84
106
  values: submitted,
85
107
  };
package/dist/draft.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"draft.js","sourceRoot":"","sources":["../src/draft.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"draft.js","sourceRoot":"","sources":["../src/draft.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export type Entries = Readonly<Record<string, unknown>>;
2
+ export interface Draft<TValues> {
3
+ readonly baseline: TValues;
4
+ readonly current: TValues;
5
+ readonly settled: Entries;
6
+ }
7
+ export declare function untouched({ baseline, current, settled }: Draft<Entries>, name: string): boolean;
8
+ export declare function changed(held: Draft<Entries>): boolean;
9
+ export declare function merged<TValues>(held: Draft<TValues>, incoming: TValues): TValues;
10
+ export declare function mergeObserved<TValues>(current: TValues, incoming: TValues, local: ReadonlySet<string>): TValues;
11
+ export declare function changedFields(previous: Entries, current: Entries): readonly string[];
12
+ export declare function accepted<TValues extends Entries>(held: Draft<TValues>, baseline: TValues, submitted: TValues, incoming?: TValues): Draft<TValues>;
13
+ //# sourceMappingURL=draftValues.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draftValues.d.ts","sourceRoot":"","sources":["../src/draftValues.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAExD,MAAM,WAAW,KAAK,CAAC,OAAO;IAC7B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE/F;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,OAAO,CAErD;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC;AAoBlF,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC;AAYjH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,SAAS,MAAM,EAAE,CAEpF;AAED,wBAAgB,QAAQ,CAAC,OAAO,SAAS,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAUjJ"}
@@ -0,0 +1,47 @@
1
+ import { Equal } from "effect";
2
+ export function untouched({ baseline, current, settled }, name) {
3
+ return Equal.equals(current[name], baseline[name]) || (Object.hasOwn(settled, name) && Equal.equals(current[name], settled[name]));
4
+ }
5
+ export function changed(held) {
6
+ return Object.keys({ ...held.baseline, ...held.current }).some((name) => !untouched(held, name));
7
+ }
8
+ export function merged(held, incoming) {
9
+ const result = {};
10
+ for (const name of Object.keys({ ...held.current, ...incoming })) {
11
+ const source = untouched(held, name) ? incoming : held.current;
12
+ if (Object.hasOwn(source, name)) {
13
+ result[name] = source[name];
14
+ }
15
+ }
16
+ return result;
17
+ }
18
+ function matching(current, submitted) {
19
+ return Object.fromEntries(Object.keys({ ...current, ...submitted })
20
+ .filter((name) => Equal.equals(current[name], submitted[name]))
21
+ .map((name) => [name, submitted[name]]));
22
+ }
23
+ export function mergeObserved(current, incoming, local) {
24
+ const result = {};
25
+ for (const name of Object.keys({ ...current, ...incoming })) {
26
+ const source = local.has(name) ? current : incoming;
27
+ if (Object.hasOwn(source, name)) {
28
+ result[name] = source[name];
29
+ }
30
+ }
31
+ return result;
32
+ }
33
+ export function changedFields(previous, current) {
34
+ return Object.keys({ ...previous, ...current }).filter((name) => !Equal.equals(previous[name], current[name]));
35
+ }
36
+ export function accepted(held, baseline, submitted, incoming) {
37
+ if (held.baseline !== baseline) {
38
+ return { ...held, settled: matching(held.current, submitted) };
39
+ }
40
+ return {
41
+ ...held,
42
+ baseline: incoming ?? submitted,
43
+ current: incoming === undefined ? held.current : merged({ ...held, baseline: submitted, settled: {} }, incoming),
44
+ settled: {},
45
+ };
46
+ }
47
+ //# sourceMappingURL=draftValues.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draftValues.js","sourceRoot":"","sources":["../src/draftValues.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Schema } from "effect";
2
+ export interface NumberOptions {
3
+ readonly integer?: boolean;
4
+ readonly max?: number;
5
+ readonly min?: number;
6
+ readonly optional?: boolean;
7
+ }
8
+ export declare function number(options?: NumberOptions & {
9
+ readonly optional?: false;
10
+ }): Schema.Codec<number, string>;
11
+ export declare function number(options: NumberOptions): Schema.Codec<number | null, string>;
12
+ export interface ListOptions {
13
+ readonly max: number;
14
+ readonly min?: number;
15
+ }
16
+ export declare function list<TItem extends Schema.Constraint>(item: TItem, options: ListOptions): Schema.$Array<TItem>;
17
+ //# sourceMappingURL=field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../src/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC5B;AACD,wBAAgB,MAAM,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG;IAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC9G,wBAAgB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC;AAepF,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,IAAI,CAAC,KAAK,SAAS,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,wBAGtF"}
package/dist/field.js ADDED
@@ -0,0 +1,20 @@
1
+ import { Schema } from "effect";
2
+ import { emptyAsNull } from "./emptyAsNull.js";
3
+ export function number(options = {}) {
4
+ let populated = Schema.NonEmptyString.pipe(Schema.decodeTo(Schema.FiniteFromString));
5
+ if (options.min !== undefined) {
6
+ populated = populated.check(Schema.isGreaterThanOrEqualTo(options.min));
7
+ }
8
+ if (options.max !== undefined) {
9
+ populated = populated.check(Schema.isLessThanOrEqualTo(options.max));
10
+ }
11
+ if (options.integer) {
12
+ populated = populated.check(Schema.isInt());
13
+ }
14
+ return Schema.Trim.pipe(Schema.decodeTo(options.optional ? emptyAsNull(populated) : populated));
15
+ }
16
+ export function list(item, options) {
17
+ const values = Schema.Array(item).check(Schema.isMaxLength(options.max));
18
+ return options.min === undefined ? values : values.check(Schema.isMinLength(options.min));
19
+ }
20
+ //# sourceMappingURL=field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field.js","sourceRoot":"","sources":["../src/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAU/C,MAAM,UAAU,MAAM,CAAC,OAAO,GAAkB,EAAE;IACjD,IAAI,SAAS,GAAG,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACrF,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC/B,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,sBAAsB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,KAAK,SAAS,EAAE,CAAC;QAC/B,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,mBAAmB,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACrB,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACjG,CAAC;AAOD,MAAM,UAAU,IAAI,CAAkC,IAAW,EAAE,OAAoB;IACtF,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACzE,OAAO,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AAC3F,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,MAAM,EAAkC,MAAM,QAAQ,CAAC;AAUvF,OAAO,EAAE,KAAK,MAAM,EAA4C,KAAK,MAAM,EAAE,KAAK,IAAI,EAA4C,MAAM,YAAY,CAAC;AAcrJ,wBAAgB,IAAI,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,KAAK,EAAE,aAAa,GAAG,KAAK,EACpG,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAC9B,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC,GAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CAqG9C"}
1
+ {"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,MAAM,EAAkC,MAAM,QAAQ,CAAC;AAUvF,OAAO,EAAE,KAAK,MAAM,EAA4C,KAAK,MAAM,EAAE,KAAK,IAAI,EAA4C,MAAM,YAAY,CAAC;AAcrJ,wBAAgB,IAAI,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,KAAK,EAAE,aAAa,GAAG,KAAK,EACpG,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAC9B,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,CAAC,GAC/D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CA2G9C"}
package/dist/form.js CHANGED
@@ -35,7 +35,11 @@ export function form(schema, config) {
35
35
  held[name] = made;
36
36
  return made;
37
37
  }
38
- const valuesAtom = fromRef(values);
38
+ const fromValues = fromRef(values);
39
+ const valuesAtom = Atom.readable((get) => {
40
+ get(editing.mounted);
41
+ return get(fromValues);
42
+ });
39
43
  const decoded = runtime.atom((get) => decode(get(valuesAtom)).pipe(Effect.match({
40
44
  onFailure: (issue) => Result.fail(issue),
41
45
  onSuccess: (value) => Result.succeed(value),
@@ -51,17 +55,21 @@ export function form(schema, config) {
51
55
  const submitter = {
52
56
  fail: (path, message) => Effect.fail(new FieldFailure(typeof path === "string" ? { message, path } : { message, path: path[0], segments: path })),
53
57
  };
54
- const validate = runtime.fn()(() => {
58
+ const validate = runtime.fn()((_, get) => {
59
+ get.mount(editing.mounted);
55
60
  status.attempt();
56
61
  return snapshot(values.value);
57
62
  });
58
- const submit = runtime.fn()(() => Effect.gen(function* () {
59
- status.attempt();
60
- const submission = editing.submission();
61
- const submitted = submission.values;
62
- const { decoded: value } = yield* snapshot(submitted);
63
- return yield* onSubmit(value, submitter, submitted).pipe(Effect.tapError(noted(submitted)), Effect.tap((saved) => Effect.sync(() => submission.accept(config.savedValues?.(saved)))));
64
- }));
63
+ const submit = runtime.fn()((_, get) => {
64
+ get.mount(editing.mounted);
65
+ return Effect.gen(function* () {
66
+ status.attempt();
67
+ const submission = editing.submission();
68
+ const submitted = submission.values;
69
+ const { decoded: value } = yield* snapshot(submitted);
70
+ return yield* onSubmit(value, submitter, submitted).pipe(Effect.tapError(noted(submitted)), Effect.tap((saved) => Effect.sync(() => submission.accept(config.savedValues?.(saved)))));
71
+ });
72
+ });
65
73
  return {
66
74
  blur: status.touch,
67
75
  change: (name, value) => {
package/dist/form.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"form.js","sourceRoot":"","sources":["../src/form.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,11 @@
1
- import { Context } from "effect";
1
+ import { Context, type Effect } from "effect";
2
2
  import type { DraftSession } from "./draftSession.ts";
3
+ export type DraftOperation<A> = A | Effect.Effect<A, unknown>;
3
4
  export interface DraftStorage {
4
- readonly getItem: (key: string) => string | null;
5
- readonly removeItem: (key: string) => void;
6
- readonly setItem: (key: string, value: string) => void;
5
+ readonly getItem: (key: string) => DraftOperation<string | null>;
6
+ readonly removeItem: (key: string, expected: string) => DraftOperation<void>;
7
+ readonly setItem: (key: string, value: string, expected?: string) => DraftOperation<void>;
8
+ readonly subscribe?: (key: string, listener: (value: string | null) => void) => () => void;
7
9
  }
8
10
  declare const DraftStorageProvider_base: Context.ServiceClass<DraftStorageProvider, "@shivaedev/form/DraftStorageProvider", () => DraftStorage>;
9
11
  export declare class DraftStorageProvider extends DraftStorageProvider_base {
@@ -16,14 +18,16 @@ export interface PersistedDraftConfig {
16
18
  readonly session?: DraftSession | undefined;
17
19
  readonly storage: () => DraftStorage;
18
20
  }
21
+ export interface StoredValues<TValues> {
22
+ readonly baseline: TValues;
23
+ readonly edited: readonly string[];
24
+ readonly values: TValues;
25
+ }
19
26
  export interface Persistence<TValues> {
20
- readonly clear: () => void;
21
- readonly read: () => {
22
- readonly baseline: TValues;
23
- readonly edited: readonly string[];
24
- readonly values: TValues;
25
- } | undefined;
26
- readonly write: (baseline: TValues, values: TValues, edited: readonly string[]) => void;
27
+ readonly clear: (revision?: string) => void;
28
+ readonly observe: (receive: (values: StoredValues<TValues> | undefined) => boolean) => () => void;
29
+ readonly revision: () => () => string | undefined;
30
+ readonly write: (baseline: TValues, values: TValues, edited: readonly string[], sameInput?: boolean) => void;
27
31
  }
28
32
  export {};
29
33
  //# sourceMappingURL=persistence.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;IACjD,QAAQ,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvD;kIAEqF,YAAY;AAAlG,qBAAa,oBAAqB,SAAQ,yBAAmG;CAAG;AAEhJ,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,YAAY,CAAC;CACrC;AAED,MAAM,WAAW,WAAW,CAAC,OAAO;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM;QAAE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;IAC9H,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;CACxF"}
1
+ {"version":3,"file":"persistence.d.ts","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACjE,QAAQ,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,cAAc,CAAC,IAAI,CAAC,CAAC;IAC7E,QAAQ,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,KAAK,cAAc,CAAC,IAAI,CAAC,CAAC;IAC1F,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;CAC3F;kIAEqF,YAAY;AAAlG,qBAAa,oBAAqB,SAAQ,yBAAmG;CAAG;AAEhJ,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,YAAY,CAAC;CACrC;AAED,MAAM,WAAW,YAAY,CAAC,OAAO;IACpC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,WAAW,CAAC,OAAO;IACnC,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,YAAY,CAAC,OAAO,CAAC,GAAG,SAAS,KAAK,OAAO,KAAK,MAAM,IAAI,CAAC;IAClG,QAAQ,CAAC,QAAQ,EAAE,MAAM,MAAM,MAAM,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CAC7G"}
@@ -1 +1 @@
1
- {"version":3,"file":"persistence.js","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AASjC,MAAM,OAAO,oBAAqB,SAAQ,OAAO,CAAC,OAAO,EAA4C,CAAC,sCAAsC,CAAC;CAAG"}
1
+ {"version":3,"file":"persistence.js","sourceRoot":"","sources":["../src/persistence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAe,MAAM,QAAQ,CAAC;AAY9C,MAAM,OAAO,oBAAqB,SAAQ,OAAO,CAAC,OAAO,EAA4C,CAAC,sCAAsC,CAAC;CAAG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/form",
3
- "version": "0.13.1",
3
+ "version": "0.15.0",
4
4
  "description": "Schema-derived Effect atom forms with optional React hooks",
5
5
  "keywords": [
6
6
  "effect"
@@ -43,14 +43,14 @@
43
43
  "README.md"
44
44
  ],
45
45
  "dependencies": {
46
- "@shivaedev/errors": "0.7.0"
46
+ "@shivaedev/errors": "0.8.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@effect/atom-react": "4.0.6",
50
50
  "@effect/vitest": "4.0.6",
51
- "@shivaedev/quality": "0.57.1",
51
+ "@shivaedev/quality": "0.58.0",
52
52
  "@shivaedev/test": "0.14.0",
53
- "@shivaedev/test-story": "0.36.0",
53
+ "@shivaedev/test-story": "0.37.0",
54
54
  "@types/node": "24.19.2",
55
55
  "@types/react": "19.3.0",
56
56
  "effect": "4.0.6",
@@ -1,4 +1,32 @@
1
- import { Layer } from "effect";
1
+ import { Effect, Layer } from "effect";
2
2
  import { DraftStorageProvider } from "#persistence.ts";
3
3
 
4
- export const browserDraftStorage = Layer.succeed(DraftStorageProvider, () => globalThis.localStorage);
4
+ function mutate(key: string, run: () => void) {
5
+ const locks = globalThis.navigator?.locks;
6
+ return locks ? Effect.promise(() => locks.request(`@shivaedev/form/${key}`, run)) : run();
7
+ }
8
+
9
+ export const browserDraftStorage = Layer.succeed(DraftStorageProvider, () => ({
10
+ getItem: (key) => globalThis.localStorage.getItem(key),
11
+ removeItem: (key, expected) =>
12
+ mutate(key, () => {
13
+ if (globalThis.localStorage.getItem(key) === expected) {
14
+ globalThis.localStorage.removeItem(key);
15
+ }
16
+ }),
17
+ setItem: (key, value, expected) =>
18
+ mutate(key, () => {
19
+ if (expected === undefined || globalThis.localStorage.getItem(key) === expected) {
20
+ globalThis.localStorage.setItem(key, value);
21
+ }
22
+ }),
23
+ subscribe: (key, listener) => {
24
+ function changed(event: StorageEvent) {
25
+ if (event.storageArea === globalThis.localStorage && (event.key === key || event.key === null)) {
26
+ listener(event.newValue);
27
+ }
28
+ }
29
+ globalThis.addEventListener("storage", changed);
30
+ return () => globalThis.removeEventListener("storage", changed);
31
+ },
32
+ }));
@@ -0,0 +1,43 @@
1
+ import { Schema, SchemaParser } from "effect";
2
+ import type { PersistedDraftConfig, StoredValues } from "#persistence.ts";
3
+
4
+ export function draftCodec<TSchema extends Schema.Constraint>(schema: TSchema, config: PersistedDraftConfig) {
5
+ const StoredDraft = Schema.Struct({
6
+ baseline: Schema.Unknown,
7
+ edited: Schema.Array(Schema.String),
8
+ session: Schema.String,
9
+ updatedAt: Schema.Number,
10
+ values: Schema.Unknown,
11
+ version: Schema.Literal(1),
12
+ });
13
+ const valid = Schema.is(StoredDraft);
14
+ const decode = SchemaParser.decodeUnknownSync(Schema.toEncoded(schema), { disableChecks: true });
15
+ const maxAgeMs = config.maxAgeMs ?? 7 * 24 * 60 * 60 * 1000;
16
+ const maxBytes = config.maxBytes ?? 256 * 1024;
17
+ const session = config.session?.id ?? "";
18
+ function read(raw: string): StoredValues<TSchema["Encoded"]> {
19
+ const value: unknown = new TextEncoder().encode(raw).byteLength <= maxBytes ? JSON.parse(raw) : undefined;
20
+ const now = config.now();
21
+ if (
22
+ !valid(value)
23
+ || value.session !== session
24
+ || !Number.isFinite(maxAgeMs)
25
+ || !Number.isFinite(maxBytes)
26
+ || maxAgeMs <= 0
27
+ || maxBytes <= 0
28
+ || now - value.updatedAt > maxAgeMs
29
+ || value.updatedAt > now
30
+ ) {
31
+ throw new Error("Invalid stored draft");
32
+ }
33
+ return { baseline: decode(value.baseline), edited: value.edited, values: decode(value.values) };
34
+ }
35
+ return {
36
+ read,
37
+ write: (baseline: TSchema["Encoded"], values: TSchema["Encoded"], edited: readonly string[]) => {
38
+ const raw = JSON.stringify({ baseline, edited, revision: crypto.randomUUID(), session, updatedAt: config.now(), values, version: 1 });
39
+ read(raw);
40
+ return raw;
41
+ },
42
+ };
43
+ }
@@ -0,0 +1,17 @@
1
+ import type { InputEvent } from "react";
2
+
3
+ export function numberInput(field: {
4
+ readonly name: string;
5
+ readonly value: string;
6
+ readonly onChange: (value: string) => void;
7
+ readonly onBlur: () => void;
8
+ }) {
9
+ return {
10
+ inputMode: "decimal" as const,
11
+ name: field.name,
12
+ onBlur: field.onBlur,
13
+ onInput: (event: InputEvent<HTMLInputElement>) => field.onChange(event.currentTarget.value),
14
+ type: "text" as const,
15
+ value: field.value,
16
+ };
17
+ }