@formisch/svelte 0.3.0 → 0.4.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.
@@ -2,10 +2,27 @@ import * as v from "valibot";
2
2
  import { untrack } from "svelte";
3
3
 
4
4
  //#region src/framework/index.svelte.ts
5
+ /**
6
+ * The current framework being used.
7
+ */
5
8
  const framework = "svelte";
9
+ /**
10
+ * Creates a unique identifier string.
11
+ *
12
+ * @returns The unique identifier.
13
+ */
14
+ /* @__NO_SIDE_EFFECTS__ */
6
15
  function createId() {
7
16
  return Math.random().toString(36).slice(2);
8
17
  }
18
+ /**
19
+ * Creates a reactive signal with an initial value.
20
+ *
21
+ * @param initialValue The initial value.
22
+ *
23
+ * @returns The created signal.
24
+ */
25
+ /* @__NO_SIDE_EFFECTS__ */
9
26
  function createSignal(initialValue) {
10
27
  let signal = $state.raw(initialValue);
11
28
  return {
@@ -17,6 +34,14 @@ function createSignal(initialValue) {
17
34
  }
18
35
  };
19
36
  }
37
+ /**
38
+ * Batches multiple signal updates into a single update cycle. This is a
39
+ * no-op in Svelte as batching is handled automatically.
40
+ *
41
+ * @param fn The function to execute.
42
+ *
43
+ * @returns The return value of the function.
44
+ */
20
45
  function batch(fn) {
21
46
  return fn();
22
47
  }
@@ -24,8 +49,15 @@ function batch(fn) {
24
49
  //#endregion
25
50
  //#region src/field/initializeFieldStore/initializeFieldStore.ts
26
51
  /**
27
- * TODO: Add comment
28
- * TODO: Should this stay in /primitives or move to /utils?
52
+ * Initializes a field store recursively based on the schema structure. Handles
53
+ * array, object, and value schemas, setting up all necessary signals and
54
+ * children. Supports wrapped schemas and schema options.
55
+ *
56
+ * @param internalFieldStore The partial field store to initialize.
57
+ * @param schema The Valibot schema defining the field structure.
58
+ * @param initialInput The initial input value.
59
+ * @param path The path to the field in the form.
60
+ * @param nullish Whether the schema is wrapped in a nullish schema.
29
61
  */
30
62
  function initializeFieldStore(internalFieldStore, schema, initialInput, path, nullish = false) {
31
63
  if (framework === "qwik" && schema.type === "lazy" || schema.type === "object_with_rest" || schema.type === "record" || schema.type === "tuple_with_rest" || schema.type === "promise") throw new Error(`"${schema.type}" schema is not supported`);
@@ -99,13 +131,13 @@ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nu
99
131
  //#endregion
100
132
  //#region src/array/copyItemState/copyItemState.ts
101
133
  /**
102
- * Copies the deeply nested state (signal values) from one array item to another.
103
- * This includes the `isTouched`, `isDirty`, `startInput`, `input`, `startItems`, and `items` properties.
134
+ * Copies the deeply nested state (signal values) from one field store to
135
+ * another. This includes the `elements`, `errors`, `startInput`, `input`,
136
+ * `isTouched`, `isDirty`, and for arrays `startItems` and `items` properties.
104
137
  * Recursively walks through the field stores and copies all signal values.
105
138
  *
106
- * @param internalArrayStore - The field store of the array (not the array item)
107
- * @param fromIndex - The source index to copy from
108
- * @param toIndex - The destination index to copy to
139
+ * @param fromInternalFieldStore The source field store to copy from.
140
+ * @param toInternalFieldStore The destination field store to copy to.
109
141
  */
110
142
  function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
111
143
  batch(() => {
@@ -139,13 +171,14 @@ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
139
171
  //#endregion
140
172
  //#region src/array/resetItemState/resetItemState.ts
141
173
  /**
142
- * Resets the state of an array item (signal values) deeply nested.
143
- * Sets `isTouched` and `isDirty` to `false` and `startInput`, `input`,
144
- * `startItems` and `items` to the new input.
145
- * Keeps the `initialInput` and `initialItems` state unchanged for form reset functionality.
174
+ * Resets the state of a field store (signal values) deeply nested. Sets
175
+ * `elements` to empty array, `errors` to `null`, `isTouched` and `isDirty` to
176
+ * `false`, and `startInput`, `input`, `startItems`, and `items` to the new
177
+ * input value. Keeps the `initialInput` and `initialItems` state unchanged for
178
+ * form reset functionality.
146
179
  *
147
- * @param internalFieldStore - The field store of the array item
148
- * @param initialInput - The new input value (can be any type including array or object)
180
+ * @param internalFieldStore The field store to reset.
181
+ * @param initialInput The new input value (can be any type including array or object).
149
182
  */
150
183
  function resetItemState(internalFieldStore, initialInput) {
151
184
  batch(() => {
@@ -177,12 +210,13 @@ function resetItemState(internalFieldStore, initialInput) {
177
210
  //#endregion
178
211
  //#region src/array/swapItemState/swapItemState.ts
179
212
  /**
180
- * Swaps the deeply nested state (signal values) between two field stores.
181
- * This includes the `isTouched`, `isDirty`, `startInput`, `input`, `startItems`, and `items` properties.
182
- * Recursively walks through the field stores and swaps all signal values.
213
+ * Swaps the deeply nested state (signal values) between two field stores. This
214
+ * includes the `elements`, `errors`, `startInput`, `input`, `isTouched`,
215
+ * `isDirty`, and for arrays `startItems` and `items` properties. Recursively
216
+ * walks through the field stores and swaps all signal values.
183
217
  *
184
- * @param firstInternalFieldStore - The first field store to swap
185
- * @param secondInternalFieldStore - The second field store to swap
218
+ * @param firstInternalFieldStore The first field store to swap.
219
+ * @param secondInternalFieldStore The second field store to swap.
186
220
  */
187
221
  function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
188
222
  batch(() => {
@@ -240,11 +274,21 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
240
274
 
241
275
  //#endregion
242
276
  //#region src/field/getFieldInput/getFieldInput.ts
277
+ /**
278
+ * Returns the current input of the field store. For arrays and objects,
279
+ * recursively collects input from all children. Returns `null` or `undefined`
280
+ * for nullish array/object inputs, or the primitive value for value fields.
281
+ *
282
+ * @param internalFieldStore The field store to get input from.
283
+ *
284
+ * @returns The field input.
285
+ */
286
+ /* @__NO_SIDE_EFFECTS__ */
243
287
  function getFieldInput(internalFieldStore) {
244
288
  if (internalFieldStore.kind === "array") {
245
289
  if (internalFieldStore.input.value) {
246
290
  const value = [];
247
- for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = getFieldInput(internalFieldStore.children[index]);
291
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = /* @__PURE__ */ getFieldInput(internalFieldStore.children[index]);
248
292
  return value;
249
293
  }
250
294
  return internalFieldStore.input.value;
@@ -252,7 +296,7 @@ function getFieldInput(internalFieldStore) {
252
296
  if (internalFieldStore.kind === "object") {
253
297
  if (internalFieldStore.input.value) {
254
298
  const value = {};
255
- for (const key in internalFieldStore.children) value[key] = getFieldInput(internalFieldStore.children[key]);
299
+ for (const key in internalFieldStore.children) value[key] = /* @__PURE__ */ getFieldInput(internalFieldStore.children[key]);
256
300
  return value;
257
301
  }
258
302
  return internalFieldStore.input.value;
@@ -263,13 +307,15 @@ function getFieldInput(internalFieldStore) {
263
307
  //#endregion
264
308
  //#region src/field/getElementInput/getElementInput.ts
265
309
  /**
266
- * Returns the current input of the element.
310
+ * Returns the current input of the element. Handles special cases for select
311
+ * multiple, checkbox groups, radio groups, and file inputs.
267
312
  *
268
313
  * @param element The field element.
269
- * @param interalFieldStore The interal field store.
314
+ * @param internalFieldStore The internal field store.
270
315
  *
271
316
  * @returns The element input.
272
317
  */
318
+ /* @__NO_SIDE_EFFECTS__ */
273
319
  function getElementInput(element, internalFieldStore) {
274
320
  if (element.options && element.multiple) return [...element.options].filter((option) => option.selected && !option.disabled).map((option) => option.value);
275
321
  if (element.type === "checkbox") {
@@ -291,14 +337,24 @@ function getElementInput(element, internalFieldStore) {
291
337
 
292
338
  //#endregion
293
339
  //#region src/field/getFieldBool/getFieldBool.ts
340
+ /**
341
+ * Returns whether the specified boolean property is true for the field store
342
+ * or any of its nested children. Recursively checks arrays and objects.
343
+ *
344
+ * @param internalFieldStore The field store to check.
345
+ * @param type The boolean property type to check.
346
+ *
347
+ * @returns Whether the property is true.
348
+ */
349
+ /* @__NO_SIDE_EFFECTS__ */
294
350
  function getFieldBool(internalFieldStore, type) {
295
351
  if (internalFieldStore[type].value) return true;
296
352
  if (internalFieldStore.kind === "array") {
297
- for (let index = 0; index < internalFieldStore.items.value.length; index++) if (getFieldBool(internalFieldStore.children[index], type)) return true;
353
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[index], type)) return true;
298
354
  return false;
299
355
  }
300
356
  if (internalFieldStore.kind == "object") {
301
- for (const key in internalFieldStore.children) if (getFieldBool(internalFieldStore.children[key], type)) return true;
357
+ for (const key in internalFieldStore.children) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[key], type)) return true;
302
358
  return false;
303
359
  }
304
360
  return false;
@@ -306,6 +362,16 @@ function getFieldBool(internalFieldStore, type) {
306
362
 
307
363
  //#endregion
308
364
  //#region src/field/getFieldStore/getFieldStore.ts
365
+ /**
366
+ * Returns the field store at the specified path by traversing the form store's
367
+ * children hierarchy.
368
+ *
369
+ * @param internalFormStore The form store to traverse.
370
+ * @param path The path to the field store.
371
+ *
372
+ * @returns The field store.
373
+ */
374
+ /* @__NO_SIDE_EFFECTS__ */
309
375
  function getFieldStore(internalFormStore, path) {
310
376
  let internalFieldStore = internalFormStore;
311
377
  for (const key of path) internalFieldStore = internalFieldStore.children[key];
@@ -314,6 +380,14 @@ function getFieldStore(internalFormStore, path) {
314
380
 
315
381
  //#endregion
316
382
  //#region src/field/setFieldBool/setFieldBool.ts
383
+ /**
384
+ * Sets the specified boolean property for the field store and all nested
385
+ * children. Recursively updates arrays and objects.
386
+ *
387
+ * @param internalFieldStore The field store to update.
388
+ * @param type The boolean property type to set.
389
+ * @param bool The boolean value to set.
390
+ */
317
391
  function setFieldBool(internalFieldStore, type, bool) {
318
392
  batch(() => {
319
393
  if (internalFieldStore.kind === "array") {
@@ -326,6 +400,13 @@ function setFieldBool(internalFieldStore, type, bool) {
326
400
 
327
401
  //#endregion
328
402
  //#region src/field/setFieldInput/setFieldInput.ts
403
+ /**
404
+ * Sets the input for a nested field store and all its children, updating
405
+ * touched and dirty states accordingly. Handles dynamic array resizing.
406
+ *
407
+ * @param internalFieldStore The field store to update.
408
+ * @param input The new input value.
409
+ */
329
410
  function setNestedInput(internalFieldStore, input) {
330
411
  internalFieldStore.isTouched.value = true;
331
412
  if (internalFieldStore.kind === "array") {
@@ -344,7 +425,7 @@ function setNestedInput(internalFieldStore, input) {
344
425
  }
345
426
  internalFieldStore.items.value = [...items, ...arrayInput.slice(items.length).map(createId)];
346
427
  }
347
- for (let index = 0; index < items.length; index++) setNestedInput(internalFieldStore.children[index], arrayInput[index]);
428
+ for (let index = 0; index < arrayInput.length; index++) setNestedInput(internalFieldStore.children[index], arrayInput[index]);
348
429
  internalFieldStore.input.value = input == null ? input : true;
349
430
  internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value || internalFieldStore.startItems.value.length !== items.length;
350
431
  } else if (internalFieldStore.kind === "object") {
@@ -357,6 +438,14 @@ function setNestedInput(internalFieldStore, input) {
357
438
  internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
358
439
  }
359
440
  }
441
+ /**
442
+ * Sets the input for a field at the specified path in the form store,
443
+ * traversing the path and updating all parent fields along the way.
444
+ *
445
+ * @param internalFormStore The form store containing the field.
446
+ * @param path The path to the field.
447
+ * @param input The new input value.
448
+ */
360
449
  function setFieldInput(internalFormStore, path, input) {
361
450
  batch(() => {
362
451
  untrack(() => {
@@ -372,6 +461,14 @@ function setFieldInput(internalFormStore, path, input) {
372
461
 
373
462
  //#endregion
374
463
  //#region src/field/setInitialFieldInput/setInitialFieldInput.ts
464
+ /**
465
+ * Sets the initial input for a field store and all its children recursively.
466
+ * For arrays, initializes missing children if needed. Updates `initialInput`
467
+ * and `initialItems` properties.
468
+ *
469
+ * @param internalFieldStore The field store to update.
470
+ * @param initialInput The initial input value.
471
+ */
375
472
  function setInitialFieldInput(internalFieldStore, initialInput) {
376
473
  batch(() => {
377
474
  if (internalFieldStore.kind === "array") {
@@ -397,6 +494,13 @@ function setInitialFieldInput(internalFieldStore, initialInput) {
397
494
 
398
495
  //#endregion
399
496
  //#region src/field/walkFieldStore/walkFieldStore.ts
497
+ /**
498
+ * Walks through the field store and all nested children, calling the callback
499
+ * for each field store in depth-first order.
500
+ *
501
+ * @param internalFieldStore The field store to walk.
502
+ * @param callback The callback to invoke for each field store.
503
+ */
400
504
  function walkFieldStore(internalFieldStore, callback) {
401
505
  callback(internalFieldStore);
402
506
  if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
@@ -405,9 +509,20 @@ function walkFieldStore(internalFieldStore, callback) {
405
509
 
406
510
  //#endregion
407
511
  //#region src/form/createFormStore/createFormStore.ts
512
+ /**
513
+ * Creates a new internal form store from the provided configuration.
514
+ * Initializes the field store hierarchy, sets validation modes, and
515
+ * creates form state signals.
516
+ *
517
+ * @param config The form configuration.
518
+ * @param parse The schema parse function.
519
+ *
520
+ * @returns The internal form store.
521
+ */
408
522
  function createFormStore(config, parse) {
409
523
  const store = {};
410
524
  initializeFieldStore(store, config.schema, config.initialInput, []);
525
+ store.validators = 0;
411
526
  store.validate = config.validate ?? "submit";
412
527
  store.revalidate = config.revalidate ?? "input";
413
528
  store.parse = parse;
@@ -419,6 +534,16 @@ function createFormStore(config, parse) {
419
534
 
420
535
  //#endregion
421
536
  //#region src/form/validateFormInput/validateFormInput.ts
537
+ /**
538
+ * Validates the form input using the configured Valibot schema. Parses the
539
+ * current form input, processes validation issues, assigns errors to fields,
540
+ * and optionally focuses the first field with an error.
541
+ *
542
+ * @param internalFormStore The form store to validate.
543
+ * @param config The validation configuration.
544
+ *
545
+ * @returns The Valibot validation result.
546
+ */
422
547
  async function validateFormInput(internalFormStore, config) {
423
548
  internalFormStore.validators++;
424
549
  internalFormStore.isValidating.value = true;
@@ -464,12 +589,24 @@ async function validateFormInput(internalFormStore, config) {
464
589
 
465
590
  //#endregion
466
591
  //#region src/form/validateIfRequired/validateIfRequired.ts
592
+ /**
593
+ * Validates the form input if required based on the validation mode and form
594
+ * state. Determines whether to use initial validation mode, revalidation mode,
595
+ * or skip validation entirely.
596
+ *
597
+ * @param internalFormStore The form store to validate.
598
+ * @param internalFieldStore The field store that triggered validation.
599
+ * @param validationMode The validation mode that triggered this check.
600
+ */
467
601
  function validateIfRequired(internalFormStore, internalFieldStore, validationMode) {
468
602
  if (validationMode === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
469
603
  }
470
604
 
471
605
  //#endregion
472
606
  //#region src/values.ts
607
+ /**
608
+ * Internal symbol constant.
609
+ */
473
610
  const INTERNAL = "~internal";
474
611
 
475
612
  //#endregion