@lucas-barake/effect-form 0.1.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 (64) hide show
  1. package/Form/package.json +6 -0
  2. package/FormAtoms/package.json +6 -0
  3. package/LICENSE +21 -0
  4. package/Mode/package.json +6 -0
  5. package/README.md +5 -0
  6. package/Validation/package.json +6 -0
  7. package/dist/cjs/Form.js +299 -0
  8. package/dist/cjs/Form.js.map +1 -0
  9. package/dist/cjs/FormAtoms.js +266 -0
  10. package/dist/cjs/FormAtoms.js.map +1 -0
  11. package/dist/cjs/Mode.js +64 -0
  12. package/dist/cjs/Mode.js.map +1 -0
  13. package/dist/cjs/Validation.js +69 -0
  14. package/dist/cjs/Validation.js.map +1 -0
  15. package/dist/cjs/index.js +35 -0
  16. package/dist/cjs/index.js.map +1 -0
  17. package/dist/cjs/internal/dirty.js +101 -0
  18. package/dist/cjs/internal/dirty.js.map +1 -0
  19. package/dist/cjs/internal/path.js +96 -0
  20. package/dist/cjs/internal/path.js.map +1 -0
  21. package/dist/cjs/internal/weak-registry.js +52 -0
  22. package/dist/cjs/internal/weak-registry.js.map +1 -0
  23. package/dist/dts/Form.d.ts +317 -0
  24. package/dist/dts/Form.d.ts.map +1 -0
  25. package/dist/dts/FormAtoms.d.ts +145 -0
  26. package/dist/dts/FormAtoms.d.ts.map +1 -0
  27. package/dist/dts/Mode.d.ts +55 -0
  28. package/dist/dts/Mode.d.ts.map +1 -0
  29. package/dist/dts/Validation.d.ts +23 -0
  30. package/dist/dts/Validation.d.ts.map +1 -0
  31. package/dist/dts/index.d.ts +26 -0
  32. package/dist/dts/index.d.ts.map +1 -0
  33. package/dist/dts/internal/dirty.d.ts +13 -0
  34. package/dist/dts/internal/dirty.d.ts.map +1 -0
  35. package/dist/dts/internal/path.d.ts +32 -0
  36. package/dist/dts/internal/path.d.ts.map +1 -0
  37. package/dist/dts/internal/weak-registry.d.ts +7 -0
  38. package/dist/dts/internal/weak-registry.d.ts.map +1 -0
  39. package/dist/esm/Form.js +263 -0
  40. package/dist/esm/Form.js.map +1 -0
  41. package/dist/esm/FormAtoms.js +238 -0
  42. package/dist/esm/FormAtoms.js.map +1 -0
  43. package/dist/esm/Mode.js +36 -0
  44. package/dist/esm/Mode.js.map +1 -0
  45. package/dist/esm/Validation.js +40 -0
  46. package/dist/esm/Validation.js.map +1 -0
  47. package/dist/esm/index.js +26 -0
  48. package/dist/esm/index.js.map +1 -0
  49. package/dist/esm/internal/dirty.js +72 -0
  50. package/dist/esm/internal/dirty.js.map +1 -0
  51. package/dist/esm/internal/path.js +86 -0
  52. package/dist/esm/internal/path.js.map +1 -0
  53. package/dist/esm/internal/weak-registry.js +45 -0
  54. package/dist/esm/internal/weak-registry.js.map +1 -0
  55. package/dist/esm/package.json +4 -0
  56. package/package.json +64 -0
  57. package/src/Form.ts +522 -0
  58. package/src/FormAtoms.ts +485 -0
  59. package/src/Mode.ts +59 -0
  60. package/src/Validation.ts +43 -0
  61. package/src/index.ts +28 -0
  62. package/src/internal/dirty.ts +96 -0
  63. package/src/internal/path.ts +93 -0
  64. package/src/internal/weak-registry.ts +60 -0
@@ -0,0 +1,263 @@
1
+ import * as Predicate from "effect/Predicate";
2
+ import * as Schema from "effect/Schema";
3
+ /**
4
+ * Unique identifier for FormBuilder instances.
5
+ *
6
+ * @since 1.0.0
7
+ * @category Symbols
8
+ */
9
+ export const TypeId = /*#__PURE__*/Symbol.for("@lucas-barake/effect-form/Form");
10
+ /**
11
+ * Unique identifier for Field references.
12
+ *
13
+ * @since 1.0.0
14
+ * @category Symbols
15
+ * @internal
16
+ */
17
+ export const FieldTypeId = /*#__PURE__*/Symbol.for("@lucas-barake/effect-form/Field");
18
+ /**
19
+ * Creates a field reference for type-safe setValue operations.
20
+ *
21
+ * @since 1.0.0
22
+ * @category Constructors
23
+ * @internal
24
+ */
25
+ export const makeFieldRef = key => ({
26
+ [FieldTypeId]: FieldTypeId,
27
+ _S: undefined,
28
+ key
29
+ });
30
+ /**
31
+ * Creates a scalar field definition.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const NameField = Form.makeField("name", Schema.String)
36
+ * const form = Form.empty.addField(NameField)
37
+ * ```
38
+ *
39
+ * @since 1.0.0
40
+ * @category Constructors
41
+ */
42
+ export const makeField = (key, schema) => ({
43
+ _tag: "field",
44
+ key,
45
+ schema
46
+ });
47
+ /**
48
+ * Creates an array field definition.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * // Array of primitives
53
+ * const TagsField = Form.makeArrayField("tags", Schema.String)
54
+ *
55
+ * // Array of objects
56
+ * const ItemsField = Form.makeArrayField("items", Schema.Struct({
57
+ * name: Schema.String,
58
+ * quantity: Schema.Number
59
+ * }))
60
+ * ```
61
+ *
62
+ * @since 1.0.0
63
+ * @category Constructors
64
+ */
65
+ export const makeArrayField = (key, itemSchema) => ({
66
+ _tag: "array",
67
+ key,
68
+ itemSchema
69
+ });
70
+ const FormBuilderProto = {
71
+ [TypeId]: TypeId,
72
+ addField(field) {
73
+ const newSelf = Object.create(FormBuilderProto);
74
+ newSelf.fields = {
75
+ ...this.fields,
76
+ [field.key]: field
77
+ };
78
+ newSelf.refinements = this.refinements;
79
+ return newSelf;
80
+ },
81
+ merge(other) {
82
+ const newSelf = Object.create(FormBuilderProto);
83
+ newSelf.fields = {
84
+ ...this.fields,
85
+ ...other.fields
86
+ };
87
+ newSelf.refinements = [...this.refinements, ...other.refinements];
88
+ return newSelf;
89
+ },
90
+ refine(predicate) {
91
+ const newSelf = Object.create(FormBuilderProto);
92
+ newSelf.fields = this.fields;
93
+ newSelf.refinements = [...this.refinements, {
94
+ _tag: "sync",
95
+ fn: values => predicate(values)
96
+ }];
97
+ return newSelf;
98
+ },
99
+ refineEffect(predicate) {
100
+ const newSelf = Object.create(FormBuilderProto);
101
+ newSelf.fields = this.fields;
102
+ newSelf.refinements = [...this.refinements, {
103
+ _tag: "async",
104
+ fn: values => predicate(values)
105
+ }];
106
+ return newSelf;
107
+ }
108
+ };
109
+ /**
110
+ * Checks if a value is a `FormBuilder`.
111
+ *
112
+ * @example
113
+ * ```ts
114
+ * import * as Form from "@lucas-barake/effect-form"
115
+ *
116
+ * const builder = Form.empty
117
+ *
118
+ * console.log(Form.isFormBuilder(builder))
119
+ * // Output: true
120
+ *
121
+ * console.log(Form.isFormBuilder({}))
122
+ * // Output: false
123
+ * ```
124
+ *
125
+ * @since 1.0.0
126
+ * @category Guards
127
+ */
128
+ export const isFormBuilder = u => Predicate.hasProperty(u, TypeId);
129
+ /**
130
+ * Checks if a field definition is an array field.
131
+ *
132
+ * @since 1.0.0
133
+ * @category Guards
134
+ */
135
+ export const isArrayFieldDef = def => def._tag === "array";
136
+ /**
137
+ * Checks if a field definition is a simple field.
138
+ *
139
+ * @since 1.0.0
140
+ * @category Guards
141
+ */
142
+ export const isFieldDef = def => def._tag === "field";
143
+ /**
144
+ * Gets a default encoded value from a schema.
145
+ *
146
+ * @since 1.0.0
147
+ * @category Helpers
148
+ */
149
+ export const getDefaultFromSchema = schema => {
150
+ const ast = schema.ast;
151
+ switch (ast._tag) {
152
+ case "StringKeyword":
153
+ case "TemplateLiteral":
154
+ return "";
155
+ case "NumberKeyword":
156
+ return 0;
157
+ case "BooleanKeyword":
158
+ return false;
159
+ case "TypeLiteral":
160
+ {
161
+ const result = {};
162
+ for (const prop of ast.propertySignatures) {
163
+ result[prop.name] = getDefaultFromSchema(Schema.make(prop.type));
164
+ }
165
+ return result;
166
+ }
167
+ case "Transformation":
168
+ return getDefaultFromSchema(Schema.make(ast.from));
169
+ case "Refinement":
170
+ return getDefaultFromSchema(Schema.make(ast.from));
171
+ case "Suspend":
172
+ return getDefaultFromSchema(Schema.make(ast.f()));
173
+ default:
174
+ return "";
175
+ }
176
+ };
177
+ /**
178
+ * An empty `FormBuilder` to start building a form.
179
+ *
180
+ * **Details**
181
+ *
182
+ * This is the entry point for building a form. Use method chaining to add
183
+ * fields and then build the form with a React adapter.
184
+ *
185
+ * @example
186
+ * ```ts
187
+ * import * as Form from "@lucas-barake/effect-form"
188
+ * import * as Schema from "effect/Schema"
189
+ *
190
+ * const EmailField = Form.makeField("email", Schema.String)
191
+ * const PasswordField = Form.makeField("password", Schema.String)
192
+ *
193
+ * const loginForm = Form.empty
194
+ * .addField(EmailField)
195
+ * .addField(PasswordField)
196
+ * ```
197
+ *
198
+ * @since 1.0.0
199
+ * @category Constructors
200
+ */
201
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
202
+ export const empty = /*#__PURE__*/(() => {
203
+ const self = /*#__PURE__*/Object.create(FormBuilderProto);
204
+ self.fields = {};
205
+ self.refinements = [];
206
+ return self;
207
+ })();
208
+ /**
209
+ * Builds a combined Schema from a FormBuilder's field definitions.
210
+ *
211
+ * @since 1.0.0
212
+ * @category Schema
213
+ */
214
+ export const buildSchema = self => {
215
+ const schemaFields = {};
216
+ for (const [key, def] of Object.entries(self.fields)) {
217
+ if (isArrayFieldDef(def)) {
218
+ schemaFields[key] = Schema.Array(def.itemSchema);
219
+ } else if (isFieldDef(def)) {
220
+ schemaFields[key] = def.schema;
221
+ }
222
+ }
223
+ let schema = Schema.Struct(schemaFields);
224
+ for (const refinement of self.refinements) {
225
+ if (refinement._tag === "sync") {
226
+ schema = schema.pipe(Schema.filter(refinement.fn));
227
+ } else {
228
+ schema = schema.pipe(Schema.filterEffect(refinement.fn));
229
+ }
230
+ }
231
+ return schema;
232
+ };
233
+ /**
234
+ * Gets default encoded values for a fields record.
235
+ *
236
+ * @since 1.0.0
237
+ * @category Helpers
238
+ */
239
+ export const getDefaultEncodedValues = fields => {
240
+ const result = {};
241
+ for (const [key, def] of Object.entries(fields)) {
242
+ if (isArrayFieldDef(def)) {
243
+ result[key] = [];
244
+ } else {
245
+ result[key] = "";
246
+ }
247
+ }
248
+ return result;
249
+ };
250
+ /**
251
+ * Creates a touched record with all fields set to the given value.
252
+ *
253
+ * @since 1.0.0
254
+ * @category Helpers
255
+ */
256
+ export const createTouchedRecord = (fields, value) => {
257
+ const result = {};
258
+ for (const key of Object.keys(fields)) {
259
+ result[key] = value;
260
+ }
261
+ return result;
262
+ };
263
+ //# sourceMappingURL=Form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Form.js","names":["Predicate","Schema","TypeId","Symbol","for","FieldTypeId","makeFieldRef","key","_S","undefined","makeField","schema","_tag","makeArrayField","itemSchema","FormBuilderProto","addField","field","newSelf","Object","create","fields","refinements","merge","other","refine","predicate","fn","values","refineEffect","isFormBuilder","u","hasProperty","isArrayFieldDef","def","isFieldDef","getDefaultFromSchema","ast","result","prop","propertySignatures","name","make","type","from","f","empty","self","buildSchema","schemaFields","entries","Array","Struct","refinement","pipe","filter","filterEffect","getDefaultEncodedValues","createTouchedRecord","value","keys"],"sources":["../../src/Form.ts"],"sourcesContent":[null],"mappings":"AAIA,OAAO,KAAKA,SAAS,MAAM,kBAAkB;AAC7C,OAAO,KAAKC,MAAM,MAAM,eAAe;AAEvC;;;;;;AAMA,OAAO,MAAMC,MAAM,gBAAkBC,MAAM,CAACC,GAAG,CAAC,gCAAgC,CAAC;AAQjF;;;;;;;AAOA,OAAO,MAAMC,WAAW,gBAAkBF,MAAM,CAACC,GAAG,CAAC,iCAAiC,CAAC;AAqBvF;;;;;;;AAOA,OAAO,MAAME,YAAY,GAAOC,GAAW,KAAgB;EACzD,CAACF,WAAW,GAAGA,WAAW;EAC1BG,EAAE,EAAEC,SAAgB;EACpBF;CACD,CAAC;AAkCF;;;;;;;;;;;;AAYA,OAAO,MAAMG,SAAS,GAAGA,CACvBH,GAAM,EACNI,MAAS,MACW;EACpBC,IAAI,EAAE,OAAO;EACbL,GAAG;EACHI;CACD,CAAC;AAEF;;;;;;;;;;;;;;;;;;AAkBA,OAAO,MAAME,cAAc,GAAGA,CAC5BN,GAAM,EACNO,UAAa,MACY;EACzBF,IAAI,EAAE,OAAO;EACbL,GAAG;EACHO;CACD,CAAC;AAuKF,MAAMC,gBAAgB,GAAG;EACvB,CAACb,MAAM,GAAGA,MAAM;EAChBc,QAAQA,CAENC,KAAkB;IAElB,MAAMC,OAAO,GAAGC,MAAM,CAACC,MAAM,CAACL,gBAAgB,CAAC;IAC/CG,OAAO,CAACG,MAAM,GAAG;MAAE,GAAG,IAAI,CAACA,MAAM;MAAE,CAACJ,KAAK,CAACV,GAAG,GAAGU;IAAK,CAAE;IACvDC,OAAO,CAACI,WAAW,GAAG,IAAI,CAACA,WAAW;IACtC,OAAOJ,OAAO;EAChB,CAAC;EACDK,KAAKA,CAEHC,KAAgC;IAEhC,MAAMN,OAAO,GAAGC,MAAM,CAACC,MAAM,CAACL,gBAAgB,CAAC;IAC/CG,OAAO,CAACG,MAAM,GAAG;MAAE,GAAG,IAAI,CAACA,MAAM;MAAE,GAAGG,KAAK,CAACH;IAAM,CAAE;IACpDH,OAAO,CAACI,WAAW,GAAG,CAAC,GAAG,IAAI,CAACA,WAAW,EAAE,GAAGE,KAAK,CAACF,WAAW,CAAC;IACjE,OAAOJ,OAAO;EAChB,CAAC;EACDO,MAAMA,CAEJC,SAAsE;IAEtE,MAAMR,OAAO,GAAGC,MAAM,CAACC,MAAM,CAACL,gBAAgB,CAAC;IAC/CG,OAAO,CAACG,MAAM,GAAG,IAAI,CAACA,MAAM;IAC5BH,OAAO,CAACI,WAAW,GAAG,CACpB,GAAG,IAAI,CAACA,WAAW,EACnB;MAAEV,IAAI,EAAE,MAAe;MAAEe,EAAE,EAAGC,MAAe,IAAKF,SAAS,CAACE,MAAoC;IAAC,CAAE,CACpG;IACD,OAAOV,OAAO;EAChB,CAAC;EACDW,YAAYA,CAEVH,SAAgG;IAEhG,MAAMR,OAAO,GAAGC,MAAM,CAACC,MAAM,CAACL,gBAAgB,CAAC;IAC/CG,OAAO,CAACG,MAAM,GAAG,IAAI,CAACA,MAAM;IAC5BH,OAAO,CAACI,WAAW,GAAG,CACpB,GAAG,IAAI,CAACA,WAAW,EACnB;MAAEV,IAAI,EAAE,OAAgB;MAAEe,EAAE,EAAGC,MAAe,IAAKF,SAAS,CAACE,MAAoC;IAAC,CAAE,CACrG;IACD,OAAOV,OAAO;EAChB;CACD;AAED;;;;;;;;;;;;;;;;;;;AAmBA,OAAO,MAAMY,aAAa,GAAIC,CAAU,IAAiC/B,SAAS,CAACgC,WAAW,CAACD,CAAC,EAAE7B,MAAM,CAAC;AAEzG;;;;;;AAMA,OAAO,MAAM+B,eAAe,GAAIC,GAAgB,IAAwCA,GAAG,CAACtB,IAAI,KAAK,OAAO;AAE5G;;;;;;AAMA,OAAO,MAAMuB,UAAU,GAAID,GAAgB,IAAiDA,GAAG,CAACtB,IAAI,KAAK,OAAO;AAEhH;;;;;;AAMA,OAAO,MAAMwB,oBAAoB,GAAIzB,MAAyB,IAAa;EACzE,MAAM0B,GAAG,GAAG1B,MAAM,CAAC0B,GAAG;EACtB,QAAQA,GAAG,CAACzB,IAAI;IACd,KAAK,eAAe;IACpB,KAAK,iBAAiB;MACpB,OAAO,EAAE;IACX,KAAK,eAAe;MAClB,OAAO,CAAC;IACV,KAAK,gBAAgB;MACnB,OAAO,KAAK;IACd,KAAK,aAAa;MAAE;QAClB,MAAM0B,MAAM,GAA4B,EAAE;QAC1C,KAAK,MAAMC,IAAI,IAAIF,GAAG,CAACG,kBAAkB,EAAE;UACzCF,MAAM,CAACC,IAAI,CAACE,IAAc,CAAC,GAAGL,oBAAoB,CAACnC,MAAM,CAACyC,IAAI,CAACH,IAAI,CAACI,IAAI,CAAC,CAAC;QAC5E;QACA,OAAOL,MAAM;MACf;IACA,KAAK,gBAAgB;MACnB,OAAOF,oBAAoB,CAACnC,MAAM,CAACyC,IAAI,CAACL,GAAG,CAACO,IAAI,CAAC,CAAC;IACpD,KAAK,YAAY;MACf,OAAOR,oBAAoB,CAACnC,MAAM,CAACyC,IAAI,CAACL,GAAG,CAACO,IAAI,CAAC,CAAC;IACpD,KAAK,SAAS;MACZ,OAAOR,oBAAoB,CAACnC,MAAM,CAACyC,IAAI,CAACL,GAAG,CAACQ,CAAC,EAAE,CAAC,CAAC;IACnD;MACE,OAAO,EAAE;EACb;AACF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;AAwBA;AACA,OAAO,MAAMC,KAAK,gBAA2B,CAAC,MAAK;EACjD,MAAMC,IAAI,gBAAG5B,MAAM,CAACC,MAAM,CAACL,gBAAgB,CAAC;EAC5CgC,IAAI,CAAC1B,MAAM,GAAG,EAAE;EAChB0B,IAAI,CAACzB,WAAW,GAAG,EAAE;EACrB,OAAOyB,IAAI;AACb,CAAC,EAAC,CAAE;AAEJ;;;;;;AAMA,OAAO,MAAMC,WAAW,GACtBD,IAA6B,IAC+C;EAC5E,MAAME,YAAY,GAAsC,EAAE;EAC1D,KAAK,MAAM,CAAC1C,GAAG,EAAE2B,GAAG,CAAC,IAAIf,MAAM,CAAC+B,OAAO,CAACH,IAAI,CAAC1B,MAAM,CAAC,EAAE;IACpD,IAAIY,eAAe,CAACC,GAAG,CAAC,EAAE;MACxBe,YAAY,CAAC1C,GAAG,CAAC,GAAGN,MAAM,CAACkD,KAAK,CAACjB,GAAG,CAACpB,UAAU,CAAC;IAClD,CAAC,MAAM,IAAIqB,UAAU,CAACD,GAAG,CAAC,EAAE;MAC1Be,YAAY,CAAC1C,GAAG,CAAC,GAAG2B,GAAG,CAACvB,MAAM;IAChC;EACF;EAEA,IAAIA,MAAM,GAAiCV,MAAM,CAACmD,MAAM,CAACH,YAAY,CAAC;EAEtE,KAAK,MAAMI,UAAU,IAAIN,IAAI,CAACzB,WAAW,EAAE;IACzC,IAAI+B,UAAU,CAACzC,IAAI,KAAK,MAAM,EAAE;MAC9BD,MAAM,GAAGA,MAAM,CAAC2C,IAAI,CAACrD,MAAM,CAACsD,MAAM,CAACF,UAAU,CAAC1B,EAAE,CAAC,CAAC;IACpD,CAAC,MAAM;MACLhB,MAAM,GAAGA,MAAM,CAAC2C,IAAI,CAACrD,MAAM,CAACuD,YAAY,CAACH,UAAU,CAAC1B,EAAE,CAAC,CAAC;IAC1D;EACF;EAEA,OAAOhB,MAIN;AACH,CAAC;AAED;;;;;;AAMA,OAAO,MAAM8C,uBAAuB,GAAIpC,MAAoB,IAA6B;EACvF,MAAMiB,MAAM,GAA4B,EAAE;EAC1C,KAAK,MAAM,CAAC/B,GAAG,EAAE2B,GAAG,CAAC,IAAIf,MAAM,CAAC+B,OAAO,CAAC7B,MAAM,CAAC,EAAE;IAC/C,IAAIY,eAAe,CAACC,GAAG,CAAC,EAAE;MACxBI,MAAM,CAAC/B,GAAG,CAAC,GAAG,EAAE;IAClB,CAAC,MAAM;MACL+B,MAAM,CAAC/B,GAAG,CAAC,GAAG,EAAE;IAClB;EACF;EACA,OAAO+B,MAAM;AACf,CAAC;AAED;;;;;;AAMA,OAAO,MAAMoB,mBAAmB,GAAGA,CAACrC,MAAoB,EAAEsC,KAAc,KAA6B;EACnG,MAAMrB,MAAM,GAA4B,EAAE;EAC1C,KAAK,MAAM/B,GAAG,IAAIY,MAAM,CAACyC,IAAI,CAACvC,MAAM,CAAC,EAAE;IACrCiB,MAAM,CAAC/B,GAAG,CAAC,GAAGoD,KAAK;EACrB;EACA,OAAOrB,MAAM;AACf,CAAC","ignoreList":[]}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Atom infrastructure for form state management.
3
+ *
4
+ * This module provides the core atom infrastructure that framework adapters
5
+ * (React, Vue, Svelte, Solid) can use to build reactive form components.
6
+ *
7
+ * @since 1.0.0
8
+ */
9
+ import * as Atom from "@effect-atom/atom/Atom";
10
+ import * as Effect from "effect/Effect";
11
+ import * as Equal from "effect/Equal";
12
+ import { pipe } from "effect/Function";
13
+ import * as Option from "effect/Option";
14
+ import * as Schema from "effect/Schema";
15
+ import * as Utils from "effect/Utils";
16
+ import { buildSchema, createTouchedRecord, getDefaultFromSchema, makeFieldRef } from "./Form.js";
17
+ import { recalculateDirtyFieldsForArray, recalculateDirtySubtree } from "./internal/dirty.js";
18
+ import { getNestedValue, setNestedValue } from "./internal/path.js";
19
+ import { createWeakRegistry } from "./internal/weak-registry.js";
20
+ /**
21
+ * Creates the complete form atoms infrastructure.
22
+ *
23
+ * @example
24
+ * ```ts
25
+ * import * as FormAtoms from "@lucas-barake/effect-form/FormAtoms"
26
+ * import * as Form from "@lucas-barake/effect-form"
27
+ * import * as Atom from "@effect-atom/atom/Atom"
28
+ * import * as Layer from "effect/Layer"
29
+ *
30
+ * const runtime = Atom.runtime(Layer.empty)
31
+ *
32
+ * const loginForm = Form.empty
33
+ * .addField(Form.makeField("email", Schema.String))
34
+ * .addField(Form.makeField("password", Schema.String))
35
+ *
36
+ * const atoms = FormAtoms.make({
37
+ * runtime,
38
+ * formBuilder: loginForm,
39
+ * parsedMode: { validation: "onChange", debounce: 300, autoSubmit: false }
40
+ * })
41
+ * ```
42
+ *
43
+ * @since 1.0.0
44
+ * @category Constructors
45
+ */
46
+ export const make = config => {
47
+ const {
48
+ formBuilder,
49
+ runtime
50
+ } = config;
51
+ const {
52
+ fields
53
+ } = formBuilder;
54
+ const combinedSchema = buildSchema(formBuilder);
55
+ const stateAtom = Atom.make(Option.none()).pipe(Atom.setIdleTTL(0));
56
+ const crossFieldErrorsAtom = Atom.make(new Map()).pipe(Atom.setIdleTTL(0));
57
+ const dirtyFieldsAtom = Atom.readable(get => Option.getOrThrow(get(stateAtom)).dirtyFields).pipe(Atom.setIdleTTL(0));
58
+ const isDirtyAtom = Atom.readable(get => Option.getOrThrow(get(stateAtom)).dirtyFields.size > 0).pipe(Atom.setIdleTTL(0));
59
+ const submitCountAtom = Atom.readable(get => Option.getOrThrow(get(stateAtom)).submitCount).pipe(Atom.setIdleTTL(0));
60
+ const onSubmitAtom = Atom.make(null).pipe(Atom.setIdleTTL(0));
61
+ const updateDirtyFields = (state, fieldPath, newValue) => {
62
+ const initialValue = getNestedValue(state.initialValues, fieldPath);
63
+ const isEqual = Utils.structuralRegion(() => Equal.equals(newValue, initialValue));
64
+ const newDirtyFields = new Set(state.dirtyFields);
65
+ if (!isEqual) {
66
+ newDirtyFields.add(fieldPath);
67
+ } else {
68
+ newDirtyFields.delete(fieldPath);
69
+ }
70
+ return newDirtyFields;
71
+ };
72
+ const validationAtomsRegistry = createWeakRegistry();
73
+ const fieldAtomsRegistry = createWeakRegistry();
74
+ const getOrCreateValidationAtom = (fieldPath, schema) => {
75
+ const existing = validationAtomsRegistry.get(fieldPath);
76
+ if (existing) return existing;
77
+ const validationAtom = runtime.fn()(value => pipe(Schema.decodeUnknown(schema)(value), Effect.asVoid)).pipe(Atom.setIdleTTL(0));
78
+ validationAtomsRegistry.set(fieldPath, validationAtom);
79
+ return validationAtom;
80
+ };
81
+ const getOrCreateFieldAtoms = fieldPath => {
82
+ const existing = fieldAtomsRegistry.get(fieldPath);
83
+ if (existing) return existing;
84
+ const valueAtom = Atom.writable(get => getNestedValue(Option.getOrThrow(get(stateAtom)).values, fieldPath), (ctx, value) => {
85
+ const currentState = Option.getOrThrow(ctx.get(stateAtom));
86
+ ctx.set(stateAtom, Option.some({
87
+ ...currentState,
88
+ values: setNestedValue(currentState.values, fieldPath, value),
89
+ dirtyFields: updateDirtyFields(currentState, fieldPath, value)
90
+ }));
91
+ }).pipe(Atom.setIdleTTL(0));
92
+ const initialValueAtom = Atom.readable(get => getNestedValue(Option.getOrThrow(get(stateAtom)).initialValues, fieldPath)).pipe(Atom.setIdleTTL(0));
93
+ const touchedAtom = Atom.writable(get => getNestedValue(Option.getOrThrow(get(stateAtom)).touched, fieldPath) ?? false, (ctx, value) => {
94
+ const currentState = Option.getOrThrow(ctx.get(stateAtom));
95
+ ctx.set(stateAtom, Option.some({
96
+ ...currentState,
97
+ touched: setNestedValue(currentState.touched, fieldPath, value)
98
+ }));
99
+ }).pipe(Atom.setIdleTTL(0));
100
+ const crossFieldErrorAtom = Atom.readable(get => {
101
+ const errors = get(crossFieldErrorsAtom);
102
+ const error = errors.get(fieldPath);
103
+ return error !== undefined ? Option.some(error) : Option.none();
104
+ }).pipe(Atom.setIdleTTL(0));
105
+ const atoms = {
106
+ valueAtom,
107
+ initialValueAtom,
108
+ touchedAtom,
109
+ crossFieldErrorAtom
110
+ };
111
+ fieldAtomsRegistry.set(fieldPath, atoms);
112
+ return atoms;
113
+ };
114
+ const resetValidationAtoms = registry => {
115
+ for (const validationAtom of validationAtomsRegistry.values()) {
116
+ registry.set(validationAtom, Atom.Reset);
117
+ }
118
+ validationAtomsRegistry.clear();
119
+ fieldAtomsRegistry.clear();
120
+ };
121
+ const decodeAndSubmit = runtime.fn()((values, get) => Effect.gen(function* () {
122
+ const decoded = yield* Schema.decodeUnknown(combinedSchema)(values);
123
+ const onSubmit = get(onSubmitAtom);
124
+ get.set(onSubmit, decoded);
125
+ return yield* get.result(onSubmit, {
126
+ suspendOnWaiting: true
127
+ });
128
+ })).pipe(Atom.setIdleTTL(0));
129
+ const fieldRefs = Object.fromEntries(Object.keys(fields).map(key => [key, makeFieldRef(key)]));
130
+ const operations = {
131
+ createInitialState: defaultValues => ({
132
+ values: defaultValues,
133
+ initialValues: defaultValues,
134
+ touched: createTouchedRecord(fields, false),
135
+ submitCount: 0,
136
+ dirtyFields: new Set()
137
+ }),
138
+ createResetState: state => ({
139
+ values: state.initialValues,
140
+ initialValues: state.initialValues,
141
+ touched: createTouchedRecord(fields, false),
142
+ submitCount: 0,
143
+ dirtyFields: new Set()
144
+ }),
145
+ createSubmitState: state => ({
146
+ ...state,
147
+ touched: createTouchedRecord(fields, true),
148
+ submitCount: state.submitCount + 1
149
+ }),
150
+ setFieldValue: (state, fieldPath, value) => {
151
+ const newValues = setNestedValue(state.values, fieldPath, value);
152
+ const newDirtyFields = recalculateDirtySubtree(state.dirtyFields, state.initialValues, newValues, fieldPath);
153
+ return {
154
+ ...state,
155
+ values: newValues,
156
+ dirtyFields: newDirtyFields
157
+ };
158
+ },
159
+ setFormValues: (state, values) => {
160
+ const newDirtyFields = recalculateDirtySubtree(state.dirtyFields, state.initialValues, values, "");
161
+ return {
162
+ ...state,
163
+ values,
164
+ dirtyFields: newDirtyFields
165
+ };
166
+ },
167
+ setFieldTouched: (state, fieldPath, touched) => ({
168
+ ...state,
169
+ touched: setNestedValue(state.touched, fieldPath, touched)
170
+ }),
171
+ appendArrayItem: (state, arrayPath, itemSchema, value) => {
172
+ const newItem = value ?? getDefaultFromSchema(itemSchema);
173
+ const currentItems = getNestedValue(state.values, arrayPath) ?? [];
174
+ const newItems = [...currentItems, newItem];
175
+ return {
176
+ ...state,
177
+ values: setNestedValue(state.values, arrayPath, newItems),
178
+ dirtyFields: recalculateDirtyFieldsForArray(state.dirtyFields, state.initialValues, arrayPath, newItems)
179
+ };
180
+ },
181
+ removeArrayItem: (state, arrayPath, index) => {
182
+ const currentItems = getNestedValue(state.values, arrayPath) ?? [];
183
+ const newItems = currentItems.filter((_, i) => i !== index);
184
+ return {
185
+ ...state,
186
+ values: setNestedValue(state.values, arrayPath, newItems),
187
+ dirtyFields: recalculateDirtyFieldsForArray(state.dirtyFields, state.initialValues, arrayPath, newItems)
188
+ };
189
+ },
190
+ swapArrayItems: (state, arrayPath, indexA, indexB) => {
191
+ const currentItems = getNestedValue(state.values, arrayPath) ?? [];
192
+ if (indexA < 0 || indexA >= currentItems.length || indexB < 0 || indexB >= currentItems.length || indexA === indexB) {
193
+ return state;
194
+ }
195
+ const newItems = [...currentItems];
196
+ const temp = newItems[indexA];
197
+ newItems[indexA] = newItems[indexB];
198
+ newItems[indexB] = temp;
199
+ return {
200
+ ...state,
201
+ values: setNestedValue(state.values, arrayPath, newItems),
202
+ dirtyFields: recalculateDirtyFieldsForArray(state.dirtyFields, state.initialValues, arrayPath, newItems)
203
+ };
204
+ },
205
+ moveArrayItem: (state, arrayPath, fromIndex, toIndex) => {
206
+ const currentItems = getNestedValue(state.values, arrayPath) ?? [];
207
+ if (fromIndex < 0 || fromIndex >= currentItems.length || toIndex < 0 || toIndex > currentItems.length || fromIndex === toIndex) {
208
+ return state;
209
+ }
210
+ const newItems = [...currentItems];
211
+ const [item] = newItems.splice(fromIndex, 1);
212
+ newItems.splice(toIndex, 0, item);
213
+ return {
214
+ ...state,
215
+ values: setNestedValue(state.values, arrayPath, newItems),
216
+ dirtyFields: recalculateDirtyFieldsForArray(state.dirtyFields, state.initialValues, arrayPath, newItems)
217
+ };
218
+ }
219
+ };
220
+ return {
221
+ stateAtom,
222
+ crossFieldErrorsAtom,
223
+ dirtyFieldsAtom,
224
+ isDirtyAtom,
225
+ submitCountAtom,
226
+ onSubmitAtom,
227
+ decodeAndSubmit,
228
+ combinedSchema,
229
+ fieldRefs,
230
+ validationAtomsRegistry,
231
+ fieldAtomsRegistry,
232
+ getOrCreateValidationAtom,
233
+ getOrCreateFieldAtoms,
234
+ resetValidationAtoms,
235
+ operations
236
+ };
237
+ };
238
+ //# sourceMappingURL=FormAtoms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FormAtoms.js","names":["Atom","Effect","Equal","pipe","Option","Schema","Utils","buildSchema","createTouchedRecord","getDefaultFromSchema","makeFieldRef","recalculateDirtyFieldsForArray","recalculateDirtySubtree","getNestedValue","setNestedValue","createWeakRegistry","make","config","formBuilder","runtime","fields","combinedSchema","stateAtom","none","setIdleTTL","crossFieldErrorsAtom","Map","dirtyFieldsAtom","readable","get","getOrThrow","dirtyFields","isDirtyAtom","size","submitCountAtom","submitCount","onSubmitAtom","updateDirtyFields","state","fieldPath","newValue","initialValue","initialValues","isEqual","structuralRegion","equals","newDirtyFields","Set","add","delete","validationAtomsRegistry","fieldAtomsRegistry","getOrCreateValidationAtom","schema","existing","validationAtom","fn","value","decodeUnknown","asVoid","set","getOrCreateFieldAtoms","valueAtom","writable","values","ctx","currentState","some","initialValueAtom","touchedAtom","touched","crossFieldErrorAtom","errors","error","undefined","atoms","resetValidationAtoms","registry","Reset","clear","decodeAndSubmit","gen","decoded","onSubmit","result","suspendOnWaiting","fieldRefs","Object","fromEntries","keys","map","key","operations","createInitialState","defaultValues","createResetState","createSubmitState","setFieldValue","newValues","setFormValues","setFieldTouched","appendArrayItem","arrayPath","itemSchema","newItem","currentItems","newItems","removeArrayItem","index","filter","_","i","swapArrayItems","indexA","indexB","length","temp","moveArrayItem","fromIndex","toIndex","item","splice"],"sources":["../../src/FormAtoms.ts"],"sourcesContent":[null],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Form validation mode configuration.
3
+ *
4
+ * @since 1.0.0
5
+ */
6
+ import * as Duration from "effect/Duration";
7
+ /**
8
+ * Parses a FormMode into a normalized ParsedMode.
9
+ *
10
+ * @since 1.0.0
11
+ * @category Parsing
12
+ */
13
+ export const parse = (mode = "onSubmit") => {
14
+ if (typeof mode === "string") {
15
+ return {
16
+ validation: mode,
17
+ debounce: null,
18
+ autoSubmit: false
19
+ };
20
+ }
21
+ if ("onBlur" in mode) {
22
+ return {
23
+ validation: "onBlur",
24
+ debounce: null,
25
+ autoSubmit: true
26
+ };
27
+ }
28
+ const debounceMs = Duration.toMillis(mode.onChange.debounce);
29
+ const autoSubmit = mode.onChange.autoSubmit === true;
30
+ return {
31
+ validation: "onChange",
32
+ debounce: debounceMs,
33
+ autoSubmit
34
+ };
35
+ };
36
+ //# sourceMappingURL=Mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Mode.js","names":["Duration","parse","mode","validation","debounce","autoSubmit","debounceMs","toMillis","onChange"],"sources":["../../src/Mode.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,OAAO,KAAKA,QAAQ,MAAM,iBAAiB;AAqC3C;;;;;;AAMA,OAAO,MAAMC,KAAK,GAAGA,CAACC,IAAA,GAAiB,UAAU,KAAgB;EAC/D,IAAI,OAAOA,IAAI,KAAK,QAAQ,EAAE;IAC5B,OAAO;MAAEC,UAAU,EAAED,IAAI;MAAEE,QAAQ,EAAE,IAAI;MAAEC,UAAU,EAAE;IAAK,CAAE;EAChE;EACA,IAAI,QAAQ,IAAIH,IAAI,EAAE;IACpB,OAAO;MAAEC,UAAU,EAAE,QAAQ;MAAEC,QAAQ,EAAE,IAAI;MAAEC,UAAU,EAAE;IAAI,CAAE;EACnE;EACA,MAAMC,UAAU,GAAGN,QAAQ,CAACO,QAAQ,CAACL,IAAI,CAACM,QAAQ,CAACJ,QAAQ,CAAC;EAC5D,MAAMC,UAAU,GAAGH,IAAI,CAACM,QAAQ,CAACH,UAAU,KAAK,IAAI;EACpD,OAAO;IAAEF,UAAU,EAAE,UAAU;IAAEC,QAAQ,EAAEE,UAAU;IAAED;EAAU,CAAE;AACrE,CAAC","ignoreList":[]}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Validation utilities for form error handling.
3
+ *
4
+ * @since 1.0.0
5
+ */
6
+ import * as Option from "effect/Option";
7
+ import * as ParseResult from "effect/ParseResult";
8
+ import { schemaPathToFieldPath } from "./internal/path.js";
9
+ /**
10
+ * Extracts the first error message from a ParseError.
11
+ *
12
+ * @since 1.0.0
13
+ * @category Error Handling
14
+ */
15
+ export const extractFirstError = error => {
16
+ const issues = ParseResult.ArrayFormatter.formatErrorSync(error);
17
+ if (issues.length === 0) {
18
+ return Option.none();
19
+ }
20
+ return Option.some(issues[0].message);
21
+ };
22
+ /**
23
+ * Routes validation errors from a ParseError to a map of field paths to error messages.
24
+ * Used for cross-field validation where schema errors need to be displayed on specific fields.
25
+ *
26
+ * @since 1.0.0
27
+ * @category Error Handling
28
+ */
29
+ export const routeErrors = error => {
30
+ const result = new Map();
31
+ const issues = ParseResult.ArrayFormatter.formatErrorSync(error);
32
+ for (const issue of issues) {
33
+ const fieldPath = schemaPathToFieldPath(issue.path);
34
+ if (fieldPath && !result.has(fieldPath)) {
35
+ result.set(fieldPath, issue.message);
36
+ }
37
+ }
38
+ return result;
39
+ };
40
+ //# sourceMappingURL=Validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Validation.js","names":["Option","ParseResult","schemaPathToFieldPath","extractFirstError","error","issues","ArrayFormatter","formatErrorSync","length","none","some","message","routeErrors","result","Map","issue","fieldPath","path","has","set"],"sources":["../../src/Validation.ts"],"sourcesContent":[null],"mappings":"AAAA;;;;;AAKA,OAAO,KAAKA,MAAM,MAAM,eAAe;AACvC,OAAO,KAAKC,WAAW,MAAM,oBAAoB;AACjD,SAASC,qBAAqB,QAAQ,oBAAoB;AAE1D;;;;;;AAMA,OAAO,MAAMC,iBAAiB,GAAIC,KAA6B,IAA2B;EACxF,MAAMC,MAAM,GAAGJ,WAAW,CAACK,cAAc,CAACC,eAAe,CAACH,KAAK,CAAC;EAChE,IAAIC,MAAM,CAACG,MAAM,KAAK,CAAC,EAAE;IACvB,OAAOR,MAAM,CAACS,IAAI,EAAE;EACtB;EACA,OAAOT,MAAM,CAACU,IAAI,CAACL,MAAM,CAAC,CAAC,CAAC,CAACM,OAAO,CAAC;AACvC,CAAC;AAED;;;;;;;AAOA,OAAO,MAAMC,WAAW,GAAIR,KAA6B,IAAyB;EAChF,MAAMS,MAAM,GAAG,IAAIC,GAAG,EAAkB;EACxC,MAAMT,MAAM,GAAGJ,WAAW,CAACK,cAAc,CAACC,eAAe,CAACH,KAAK,CAAC;EAEhE,KAAK,MAAMW,KAAK,IAAIV,MAAM,EAAE;IAC1B,MAAMW,SAAS,GAAGd,qBAAqB,CAACa,KAAK,CAACE,IAAI,CAAC;IACnD,IAAID,SAAS,IAAI,CAACH,MAAM,CAACK,GAAG,CAACF,SAAS,CAAC,EAAE;MACvCH,MAAM,CAACM,GAAG,CAACH,SAAS,EAAED,KAAK,CAACJ,OAAO,CAAC;IACtC;EACF;EAEA,OAAOE,MAAM;AACf,CAAC","ignoreList":[]}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ export * as Form from "./Form.js";
5
+ /**
6
+ * Atom infrastructure for form state management.
7
+ *
8
+ * This module provides the core atom infrastructure that framework adapters
9
+ * (React, Vue, Svelte, Solid) can use to build reactive form components.
10
+ *
11
+ * @since 1.0.0
12
+ */
13
+ export * as FormAtoms from "./FormAtoms.js";
14
+ /**
15
+ * Form validation mode configuration.
16
+ *
17
+ * @since 1.0.0
18
+ */
19
+ export * as Mode from "./Mode.js";
20
+ /**
21
+ * Validation utilities for form error handling.
22
+ *
23
+ * @since 1.0.0
24
+ */
25
+ export * as Validation from "./Validation.js";
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["Form","FormAtoms","Mode","Validation"],"sources":["../../src/index.ts"],"sourcesContent":[null],"mappings":"AAAA;;;AAGA,OAAO,KAAKA,IAAI,MAAM,WAAW;AAEjC;;;;;;;;AAQA,OAAO,KAAKC,SAAS,MAAM,gBAAgB;AAE3C;;;;;AAKA,OAAO,KAAKC,IAAI,MAAM,WAAW;AAEjC;;;;;AAKA,OAAO,KAAKC,UAAU,MAAM,iBAAiB","ignoreList":[]}