oxform-core 0.1.0 → 0.1.1

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 (39) hide show
  1. package/dist/index.cjs +751 -0
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.d.cts +443 -0
  4. package/dist/index.d.ts +443 -0
  5. package/dist/index.js +747 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +20 -15
  8. package/export/index.ts +0 -7
  9. package/export/schema.ts +0 -1
  10. package/src/field-api.constants.ts +0 -15
  11. package/src/field-api.ts +0 -139
  12. package/src/form-api.ts +0 -84
  13. package/src/form-api.types.ts +0 -148
  14. package/src/form-array-field-api.ts +0 -233
  15. package/src/form-context-api.ts +0 -232
  16. package/src/form-field-api.ts +0 -174
  17. package/src/more-types.ts +0 -178
  18. package/src/tests/array/append.spec.ts +0 -138
  19. package/src/tests/array/insert.spec.ts +0 -182
  20. package/src/tests/array/move.spec.ts +0 -175
  21. package/src/tests/array/prepend.spec.ts +0 -138
  22. package/src/tests/array/remove.spec.ts +0 -174
  23. package/src/tests/array/swap.spec.ts +0 -152
  24. package/src/tests/array/update.spec.ts +0 -148
  25. package/src/tests/field/change.spec.ts +0 -226
  26. package/src/tests/field/reset.spec.ts +0 -617
  27. package/src/tests/field/set-errors.spec.ts +0 -254
  28. package/src/tests/field-api/field-api.spec.ts +0 -341
  29. package/src/tests/form-api/reset.spec.ts +0 -535
  30. package/src/tests/form-api/submit.spec.ts +0 -409
  31. package/src/types.ts +0 -5
  32. package/src/utils/get.ts +0 -5
  33. package/src/utils/testing/sleep.ts +0 -1
  34. package/src/utils/testing/tests.ts +0 -18
  35. package/src/utils/update.ts +0 -6
  36. package/src/utils/validate.ts +0 -8
  37. package/tsconfig.json +0 -3
  38. package/tsdown.config.ts +0 -10
  39. package/vitest.config.ts +0 -3
@@ -1,617 +0,0 @@
1
- import { FormApi } from '#form-api';
2
- import { describe, expect, it } from 'vitest';
3
- import z from 'zod';
4
-
5
- const schema = z.object({
6
- name: z.string(),
7
- email: z.string().email('Invalid email format'),
8
- age: z.number().min(0, 'Age must be non-negative'),
9
- nested: z.object({
10
- deep: z.object({
11
- value: z.string(),
12
- array: z.string().array(),
13
- }),
14
- }),
15
- });
16
-
17
- const defaultValues = {
18
- name: 'Default Name',
19
- email: 'default@example.com',
20
- age: 25,
21
- nested: {
22
- deep: {
23
- value: 'default value',
24
- array: ['default1', 'default2'],
25
- },
26
- },
27
- };
28
-
29
- const setup = async () => {
30
- const form = new FormApi({
31
- schema,
32
- defaultValues,
33
- });
34
-
35
- form['~mount']();
36
-
37
- return { form };
38
- };
39
-
40
- describe('basic field reset', () => {
41
- it('should reset field value to default', async () => {
42
- const { form } = await setup();
43
-
44
- form.field.change('name', 'Changed Name');
45
-
46
- expect(form.field.get('name')).toBe('Changed Name');
47
-
48
- form.field.reset('name');
49
-
50
- expect(form.field.get('name')).toBe('Default Name');
51
- });
52
-
53
- it('should reset nested field value to default', async () => {
54
- const { form } = await setup();
55
-
56
- form.field.change('nested.deep.value', 'changed nested');
57
-
58
- expect(form.field.get('nested.deep.value')).toBe('changed nested');
59
-
60
- form.field.reset('nested.deep.value');
61
-
62
- expect(form.field.get('nested.deep.value')).toBe('default value');
63
- });
64
-
65
- it('should reset array field value to default', async () => {
66
- const { form } = await setup();
67
-
68
- form.field.change('nested.deep.array', ['changed1', 'changed2', 'changed3']);
69
-
70
- expect(form.field.get('nested.deep.array')).toEqual(['changed1', 'changed2', 'changed3']);
71
-
72
- form.field.reset('nested.deep.array');
73
-
74
- expect(form.field.get('nested.deep.array')).toEqual(['default1', 'default2']);
75
- });
76
-
77
- it('should not affect other fields when resetting single field', async () => {
78
- const { form } = await setup();
79
-
80
- form.field.change('name', 'Changed Name');
81
- form.field.change('email', 'changed@example.com');
82
- form.field.change('age', 30);
83
-
84
- form.field.reset('name');
85
-
86
- expect(form.field.get('name')).toBe('Default Name');
87
- expect(form.field.get('email')).toBe('changed@example.com');
88
- expect(form.field.get('age')).toBe(30);
89
- });
90
- });
91
-
92
- describe('field metadata reset', () => {
93
- it('should reset field metadata to defaults', async () => {
94
- const { form } = await setup();
95
-
96
- form.field.change('name', 'Changed Name');
97
- form.field.focus('name');
98
- form.field.blur('name');
99
-
100
- expect(form.field.meta('name').dirty).toBe(true);
101
- expect(form.field.meta('name').touched).toBe(true);
102
- expect(form.field.meta('name').blurred).toBe(true);
103
-
104
- form.field.reset('name');
105
-
106
- expect(form.field.meta('name').dirty).toBe(false);
107
- expect(form.field.meta('name').touched).toBe(false);
108
- expect(form.field.meta('name').blurred).toBe(false);
109
- });
110
-
111
- it('should reset computed metadata properties', async () => {
112
- const { form } = await setup();
113
-
114
- form.field.change('name', 'Changed Name');
115
-
116
- expect(form.field.meta('name').pristine).toBe(false);
117
- expect(form.field.meta('name').default).toBe(false);
118
-
119
- form.field.reset('name');
120
-
121
- expect(form.field.meta('name').pristine).toBe(true);
122
- expect(form.field.meta('name').default).toBe(true);
123
- });
124
-
125
- it('should not affect metadata of other fields', async () => {
126
- const { form } = await setup();
127
-
128
- form.field.change('name', 'Changed Name');
129
- form.field.change('email', 'changed@example.com');
130
- form.field.focus('email');
131
-
132
- form.field.reset('name');
133
-
134
- expect(form.field.meta('name').dirty).toBe(false);
135
- expect(form.field.meta('email').dirty).toBe(true);
136
- expect(form.field.meta('email').touched).toBe(true);
137
- });
138
- });
139
-
140
- describe('field errors reset', () => {
141
- it('should clear field errors', async () => {
142
- const { form } = await setup();
143
-
144
- form.field.change('email', 'invalid-email');
145
- await form.validate();
146
-
147
- expect(form.field.errors('email')).not.toHaveLength(0);
148
-
149
- form.field.reset('email');
150
-
151
- expect(form.field.errors('email')).toHaveLength(0);
152
- });
153
-
154
- it('should not affect errors of other fields', async () => {
155
- const { form } = await setup();
156
-
157
- form.field.change('email', 'invalid-email');
158
- form.field.change('age', -5);
159
- await form.validate();
160
-
161
- expect(form.field.errors('email')).not.toHaveLength(0);
162
- expect(form.field.errors('age')).not.toHaveLength(0);
163
-
164
- form.field.reset('email');
165
-
166
- expect(form.field.errors('email')).toHaveLength(0);
167
- expect(form.field.errors('age')).not.toHaveLength(0);
168
- });
169
- });
170
-
171
- describe('field refs reset', () => {
172
- it('should clear field ref', async () => {
173
- const { form } = await setup();
174
-
175
- const nameElement = document.createElement('input');
176
- const emailElement = document.createElement('input');
177
-
178
- form.field.register('name')(nameElement);
179
- form.field.register('email')(emailElement);
180
-
181
- expect(form.store.state.refs.name).toBe(nameElement);
182
- expect(form.store.state.refs.email).toBe(emailElement);
183
-
184
- form.field.reset('name');
185
-
186
- expect(form.store.state.refs.name).toBeUndefined();
187
- expect(form.store.state.refs.email).toBe(emailElement);
188
- });
189
- });
190
-
191
- describe('reset with options', () => {
192
- describe('custom value option', () => {
193
- it('should reset field to custom value instead of default', async () => {
194
- const { form } = await setup();
195
-
196
- form.field.change('name', 'Changed Name');
197
-
198
- form.field.reset('name', { value: 'Custom Reset Value' });
199
-
200
- expect(form.field.get('name')).toBe('Custom Reset Value');
201
- });
202
-
203
- it('should reset nested field to custom value', async () => {
204
- const { form } = await setup();
205
-
206
- form.field.change('nested.deep.value', 'changed');
207
-
208
- form.field.reset('nested.deep.value', { value: 'custom nested' });
209
-
210
- expect(form.field.get('nested.deep.value')).toBe('custom nested');
211
- });
212
-
213
- it('should reset array field to custom value', async () => {
214
- const { form } = await setup();
215
-
216
- form.field.change('nested.deep.array', ['changed']);
217
-
218
- form.field.reset('nested.deep.array', { value: ['custom1', 'custom2'] });
219
-
220
- expect(form.field.get('nested.deep.array')).toEqual(['custom1', 'custom2']);
221
- });
222
- });
223
-
224
- describe('keep options', () => {
225
- it('should keep field metadata when keep.meta is true', async () => {
226
- const { form } = await setup();
227
-
228
- form.field.change('name', 'Changed Name');
229
- form.field.focus('name');
230
- form.field.blur('name');
231
-
232
- expect(form.field.meta('name').dirty).toBe(true);
233
- expect(form.field.meta('name').touched).toBe(true);
234
- expect(form.field.meta('name').blurred).toBe(true);
235
-
236
- form.field.reset('name', { keep: { meta: true } });
237
-
238
- expect(form.field.get('name')).toBe('Default Name');
239
- expect(form.field.meta('name').dirty).toBe(true);
240
- expect(form.field.meta('name').touched).toBe(true);
241
- expect(form.field.meta('name').blurred).toBe(true);
242
- });
243
-
244
- it('should keep field errors when keep.errors is true', async () => {
245
- const { form } = await setup();
246
-
247
- form.field.change('email', 'invalid-email');
248
- await form.validate();
249
-
250
- expect(form.field.errors('email')).not.toHaveLength(0);
251
-
252
- form.field.reset('email', { keep: { errors: true } });
253
-
254
- expect(form.field.get('email')).toBe('default@example.com');
255
- expect(form.field.errors('email')).not.toHaveLength(0);
256
- });
257
-
258
- it('should keep field refs when keep.refs is true', async () => {
259
- const { form } = await setup();
260
-
261
- const nameElement = document.createElement('input');
262
- form.field.register('name')(nameElement);
263
-
264
- form.field.change('name', 'Changed Name');
265
-
266
- form.field.reset('name', { keep: { refs: true } });
267
-
268
- expect(form.field.get('name')).toBe('Default Name');
269
- expect(form.store.state.refs.name).toBe(nameElement);
270
- });
271
-
272
- it('should keep multiple things when multiple keep options are true', async () => {
273
- const { form } = await setup();
274
-
275
- const nameElement = document.createElement('input');
276
- form.field.register('name')(nameElement);
277
-
278
- form.field.change('name', 'invalid-name-that-would-cause-error');
279
- form.field.focus('name');
280
- form.field.blur('name');
281
-
282
- const mockErrors = [{ code: 'test', message: 'Test error', path: ['name'] }];
283
- form.field.setErrors('name', mockErrors);
284
-
285
- expect(form.field.meta('name').dirty).toBe(true);
286
- expect(form.field.meta('name').touched).toBe(true);
287
- expect(form.field.errors('name')).toEqual(mockErrors);
288
- expect(form.store.state.refs.name).toBe(nameElement);
289
-
290
- form.field.reset('name', {
291
- keep: {
292
- meta: true,
293
- errors: true,
294
- refs: true,
295
- },
296
- });
297
-
298
- expect(form.field.get('name')).toBe('Default Name');
299
- expect(form.field.meta('name').dirty).toBe(true);
300
- expect(form.field.meta('name').touched).toBe(true);
301
- expect(form.field.errors('name')).toEqual(mockErrors);
302
- expect(form.store.state.refs.name).toBe(nameElement);
303
- });
304
- });
305
-
306
- describe('combined options', () => {
307
- it('should handle custom value and keep options together', async () => {
308
- const { form } = await setup();
309
-
310
- form.field.change('name', 'Changed Name');
311
- form.field.focus('name');
312
-
313
- form.field.reset('name', {
314
- value: 'Custom Reset Value',
315
- keep: { meta: true },
316
- });
317
-
318
- expect(form.field.get('name')).toBe('Custom Reset Value');
319
- expect(form.field.meta('name').dirty).toBe(true);
320
- expect(form.field.meta('name').touched).toBe(true);
321
- });
322
- });
323
-
324
- describe('meta overrides', () => {
325
- it('should set specific meta values when provided', async () => {
326
- const { form } = await setup();
327
-
328
- form.field.change('name', 'Changed Name');
329
-
330
- expect(form.field.meta('name').dirty).toBe(true);
331
- expect(form.field.meta('name').touched).toBe(true);
332
- expect(form.field.meta('name').blurred).toBe(false);
333
-
334
- form.field.reset('name', {
335
- meta: {
336
- dirty: false,
337
- touched: false,
338
- blurred: true,
339
- },
340
- });
341
-
342
- expect(form.field.get('name')).toBe('Default Name');
343
- expect(form.field.meta('name').dirty).toBe(false);
344
- expect(form.field.meta('name').touched).toBe(false);
345
- expect(form.field.meta('name').blurred).toBe(true);
346
- });
347
-
348
- it('should partially override meta values if keep.meta is true', async () => {
349
- const { form } = await setup();
350
-
351
- form.field.change('name', 'Changed Name');
352
- form.field.focus('name');
353
- form.field.blur('name');
354
-
355
- expect(form.field.meta('name').dirty).toBe(true);
356
- expect(form.field.meta('name').touched).toBe(true);
357
- expect(form.field.meta('name').blurred).toBe(true);
358
-
359
- form.field.reset('name', {
360
- meta: {
361
- dirty: false,
362
- },
363
- keep: {
364
- meta: true,
365
- },
366
- });
367
-
368
- expect(form.field.get('name')).toBe('Default Name');
369
- expect(form.field.meta('name').dirty).toBe(false);
370
- expect(form.field.meta('name').touched).toBe(true);
371
- expect(form.field.meta('name').blurred).toBe(true);
372
- });
373
-
374
- it('should fully override meta values if keep.meta is undefined', async () => {
375
- const { form } = await setup();
376
-
377
- form.field.change('name', 'Changed Name');
378
- form.field.focus('name');
379
- form.field.blur('name');
380
-
381
- expect(form.field.meta('name').dirty).toBe(true);
382
- expect(form.field.meta('name').touched).toBe(true);
383
- expect(form.field.meta('name').blurred).toBe(true);
384
-
385
- form.field.reset('name', {
386
- meta: {
387
- blurred: true,
388
- },
389
- });
390
-
391
- expect(form.field.get('name')).toBe('Default Name');
392
- expect(form.field.meta('name').dirty).toBe(false);
393
- expect(form.field.meta('name').touched).toBe(false);
394
- expect(form.field.meta('name').blurred).toBe(true);
395
- });
396
-
397
- it('should work with custom value and meta overrides', async () => {
398
- const { form } = await setup();
399
-
400
- form.field.reset('name', {
401
- value: 'Custom Value',
402
- meta: {
403
- dirty: true,
404
- touched: true,
405
- blurred: false,
406
- },
407
- });
408
-
409
- expect(form.field.get('name')).toBe('Custom Value');
410
- expect(form.field.meta('name').dirty).toBe(true);
411
- expect(form.field.meta('name').touched).toBe(true);
412
- expect(form.field.meta('name').blurred).toBe(false);
413
- });
414
-
415
- it('should work with keep.meta true and meta overrides', async () => {
416
- const { form } = await setup();
417
-
418
- form.field.change('name', 'Changed Name');
419
- form.field.focus('name');
420
- form.field.blur('name');
421
-
422
- expect(form.field.meta('name').dirty).toBe(true);
423
- expect(form.field.meta('name').touched).toBe(true);
424
- expect(form.field.meta('name').blurred).toBe(true);
425
-
426
- form.field.reset('name', {
427
- keep: { meta: true },
428
- meta: {
429
- blurred: false,
430
- },
431
- });
432
-
433
- expect(form.field.get('name')).toBe('Default Name');
434
- expect(form.field.meta('name').dirty).toBe(true);
435
- expect(form.field.meta('name').touched).toBe(true);
436
- expect(form.field.meta('name').blurred).toBe(false);
437
- });
438
-
439
- it('should create meta when field has no existing meta', async () => {
440
- const { form } = await setup();
441
-
442
- expect(form.field.meta('name').dirty).toBe(false);
443
- expect(form.field.meta('name').touched).toBe(false);
444
- expect(form.field.meta('name').blurred).toBe(false);
445
-
446
- form.field.reset('name', {
447
- meta: {
448
- dirty: true,
449
- touched: true,
450
- blurred: true,
451
- },
452
- });
453
-
454
- expect(form.field.get('name')).toBe('Default Name');
455
- expect(form.field.meta('name').dirty).toBe(true);
456
- expect(form.field.meta('name').touched).toBe(true);
457
- expect(form.field.meta('name').blurred).toBe(true);
458
- });
459
-
460
- it('should handle meta overrides with nested fields', async () => {
461
- const { form } = await setup();
462
-
463
- form.field.change('nested.deep.value', 'changed value');
464
- form.field.focus('nested.deep.value');
465
-
466
- expect(form.field.meta('nested.deep.value').dirty).toBe(true);
467
- expect(form.field.meta('nested.deep.value').touched).toBe(true);
468
- expect(form.field.meta('nested.deep.value').blurred).toBe(false);
469
-
470
- form.field.reset('nested.deep.value', {
471
- meta: {
472
- dirty: false,
473
- blurred: true,
474
- },
475
- });
476
-
477
- expect(form.field.get('nested.deep.value')).toBe('default value');
478
- expect(form.field.meta('nested.deep.value').dirty).toBe(false);
479
- expect(form.field.meta('nested.deep.value').touched).toBe(false);
480
- expect(form.field.meta('nested.deep.value').blurred).toBe(true);
481
- });
482
-
483
- it('should handle meta overrides with all options combined', async () => {
484
- const { form } = await setup();
485
-
486
- const nameElement = document.createElement('input');
487
- form.field.register('name')(nameElement);
488
-
489
- form.field.change('name', 'invalid-name');
490
-
491
- const mockErrors = [{ code: 'test', message: 'Test error', path: ['name'] }];
492
- form.field.setErrors('name', mockErrors);
493
-
494
- form.field.reset('name', {
495
- value: 'Custom Reset Value',
496
- meta: {
497
- dirty: true,
498
- touched: true,
499
- blurred: false,
500
- },
501
- keep: {
502
- errors: true,
503
- refs: true,
504
- },
505
- });
506
-
507
- expect(form.field.get('name')).toBe('Custom Reset Value');
508
- expect(form.field.meta('name').dirty).toBe(true);
509
- expect(form.field.meta('name').touched).toBe(true);
510
- expect(form.field.meta('name').blurred).toBe(false);
511
- expect(form.field.errors('name')).toEqual(mockErrors);
512
- expect(form.store.state.refs.name).toBe(nameElement);
513
- });
514
- });
515
- });
516
-
517
- describe('edge cases', () => {
518
- it('should handle resetting non-existent field gracefully', async () => {
519
- const { form } = await setup();
520
-
521
- expect(() => {
522
- form.field.reset('nonExistent' as any);
523
- }).not.toThrow();
524
- });
525
-
526
- it('should handle undefined custom value gracefully', async () => {
527
- const { form } = await setup();
528
-
529
- form.field.change('name', 'Changed Name');
530
-
531
- form.field.reset('name', { value: undefined });
532
-
533
- expect(form.field.get('name')).toBe('Default Name');
534
- });
535
-
536
- it('should work after form reset', async () => {
537
- const { form } = await setup();
538
-
539
- form.field.change('name', 'Changed Name');
540
- form.field.change('email', 'changed@example.com');
541
-
542
- form.reset();
543
-
544
- expect(form.field.get('name')).toBe('Default Name');
545
- expect(form.field.get('email')).toBe('default@example.com');
546
-
547
- form.field.change('name', 'New Change');
548
-
549
- form.field.reset('name');
550
-
551
- expect(form.field.get('name')).toBe('Default Name');
552
- expect(form.field.get('email')).toBe('default@example.com');
553
- });
554
-
555
- it('should not affect form-level status', async () => {
556
- const { form } = await setup();
557
-
558
- const onSuccess = () => {};
559
- await form.submit(onSuccess)();
560
-
561
- expect(form.status.submits).toBe(1);
562
- expect(form.status.submitted).toBe(true);
563
-
564
- form.field.change('name', 'Changed Name');
565
- form.field.reset('name');
566
-
567
- expect(form.status.submits).toBe(1);
568
- expect(form.status.submitted).toBe(true);
569
- });
570
- });
571
-
572
- describe('integration with other form methods', () => {
573
- it('should work correctly with validation', async () => {
574
- const { form } = await setup();
575
-
576
- form.field.change('email', 'invalid-email');
577
- await form.validate();
578
-
579
- expect(form.field.errors('email')).not.toHaveLength(0);
580
- expect(form.status.valid).toBe(false);
581
-
582
- form.field.reset('email');
583
-
584
- expect(form.field.errors('email')).toHaveLength(0);
585
- await form.validate();
586
- expect(form.status.valid).toBe(true);
587
- });
588
-
589
- it('should work correctly after field interactions', async () => {
590
- const { form } = await setup();
591
-
592
- form.field.change('name', 'Changed Name');
593
- form.field.focus('name');
594
- form.field.blur('name');
595
-
596
- const nameElement = document.createElement('input');
597
- form.field.register('name')(nameElement);
598
-
599
- expect(form.field.get('name')).toBe('Changed Name');
600
- expect(form.field.meta('name').dirty).toBe(true);
601
- expect(form.field.meta('name').touched).toBe(true);
602
- expect(form.field.meta('name').blurred).toBe(true);
603
- expect(form.store.state.refs.name).toBe(nameElement);
604
-
605
- form.field.reset('name');
606
-
607
- expect(form.field.get('name')).toBe('Default Name');
608
- expect(form.field.meta('name').dirty).toBe(false);
609
- expect(form.field.meta('name').touched).toBe(false);
610
- expect(form.field.meta('name').blurred).toBe(false);
611
- expect(form.store.state.refs.name).toBeUndefined();
612
-
613
- form.field.change('name', 'New Value After Reset');
614
- expect(form.field.get('name')).toBe('New Value After Reset');
615
- expect(form.field.meta('name').dirty).toBe(true);
616
- });
617
- });