@formisch/solid 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Formisch is a schema-based, headless form library for SolidJS. It manages form state and validation. It is type-safe, fast by default and its bundle size is small due to its modular design. Try it out in our [playground](https://stackblitz.com/edit/formisch-playground-solid)!
4
4
 
5
+ Formisch is also available for [Preact][formisch-preact], [Qwik][formisch-qwik], and [Vue][formisch-vue]. Svelte will follow soon.
6
+
5
7
  ## Highlights
6
8
 
7
9
  - Small bundle size starting at 2.5 kB
@@ -55,6 +57,16 @@ export default function LoginPage() {
55
57
 
56
58
  In addition, Formisch offers several functions (we call them "methods") that can be used to read and manipulate the form state. These include `focus`, `getErrors`, `getAllErrors`, `getInput`, `insert`, `move`, `remove`, `replace`, `reset`, `setErrors`, `setInput`, `submit`, `swap` and `validate`. These methods allow you to control the form programmatically.
57
59
 
60
+ ## Comparison
61
+
62
+ What makes Formisch unique is its framework-agnostic core, which is fully native to the framework you are using. It works by inserting framework-specific reactivity blocks when the core package is built. The result is a small bundle size and native performance for any UI update. This feature, along with a few others, distinguishes Formisch from other form libraries. My vision for Formisch is to create a framework-agnostic platform similar to [Vite](https://vite.dev/), but for forms.
63
+
64
+ ## Partners
65
+
66
+ Thanks to our partners who support the development! [Join them](https://github.com/sponsors/fabian-hiller) and contribute to the sustainability of open source software!
67
+
68
+ ![Partners of Formisch](https://github.com/fabian-hiller/formisch/blob/main/partners.webp?raw=true)
69
+
58
70
  ## Feedback
59
71
 
60
72
  Find a bug or have an idea how to improve the library? Please fill out an [issue](https://github.com/fabian-hiller/formisch/issues/new). Together we can make forms even better!
@@ -62,3 +74,7 @@ Find a bug or have an idea how to improve the library? Please fill out an [issue
62
74
  ## License
63
75
 
64
76
  This project is available free of charge and licensed under the [MIT license](https://github.com/fabian-hiller/formisch/blob/main/LICENSE.md).
77
+
78
+ [formisch-preact]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/preact
79
+ [formisch-qwik]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/qwik
80
+ [formisch-vue]: https://github.com/fabian-hiller/formisch/tree/main/frameworks/vue
package/dist/dev.js CHANGED
@@ -263,6 +263,7 @@ function setFieldInput(internalFieldStore, input) {
263
263
  } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
264
264
  else {
265
265
  internalFieldStore.input.value = input;
266
+ internalFieldStore.isTouched.value = true;
266
267
  const startInput = untrack(() => internalFieldStore.startInput.value);
267
268
  internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
268
269
  }
@@ -487,7 +488,6 @@ function setInput(form, config) {
487
488
  batch(() => {
488
489
  const internalFormStore = form[INTERNAL];
489
490
  const internalFieldStore = config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
490
- setFieldBool(internalFieldStore, "isTouched", true);
491
491
  setFieldInput(internalFieldStore, config.input);
492
492
  validateIfRequired(internalFormStore, internalFieldStore, "input");
493
493
  });
package/dist/dev.jsx CHANGED
@@ -261,6 +261,7 @@ function setFieldInput(internalFieldStore, input) {
261
261
  } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
262
262
  else {
263
263
  internalFieldStore.input.value = input;
264
+ internalFieldStore.isTouched.value = true;
264
265
  const startInput = untrack(() => internalFieldStore.startInput.value);
265
266
  internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
266
267
  }
@@ -485,7 +486,6 @@ function setInput(form, config) {
485
486
  batch(() => {
486
487
  const internalFormStore = form[INTERNAL];
487
488
  const internalFieldStore = config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
488
- setFieldBool(internalFieldStore, "isTouched", true);
489
489
  setFieldInput(internalFieldStore, config.input);
490
490
  validateIfRequired(internalFormStore, internalFieldStore, "input");
491
491
  });
package/dist/index.d.ts CHANGED
@@ -94,7 +94,7 @@ interface InternalFormStore<TSchema extends Schema = Schema> extends InternalObj
94
94
  interface BaseFormStore<TSchema extends Schema = Schema> {
95
95
  [INTERNAL]: InternalFormStore<TSchema>;
96
96
  }
97
- type SubmitHandler<TSchema extends Schema> = (output: v.InferOutput<TSchema>, event: SubmitEvent) => MaybePromise<void>;
97
+ type SubmitHandler<TSchema extends Schema> = (output: v.InferOutput<TSchema>, event: SubmitEvent) => MaybePromise<unknown>;
98
98
  //#endregion
99
99
  //#region src/types/path.d.ts
100
100
  /**
@@ -124,16 +124,16 @@ type MergeUnion<T> = { [K in KeyOf<T>]: T extends Record<K, infer V> ? V : never
124
124
  /**
125
125
  * Lazily evaluate only the first valid path segment based on the given value.
126
126
  */
127
- type LazyPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValidPath : TPathToCheck extends readonly [infer TFirstKey extends KeyOf<TValue>, ...infer TPathRest extends Path] ? LazyPath<MergeUnion<TValue>[TFirstKey], TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<KeyOf<TValue>> extends false ? readonly [...TValidPath, KeyOf<TValue>] : TValidPath;
127
+ type LazyPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValidPath : TPathToCheck extends readonly [infer TFirstKey extends KeyOf<TValue>, ...infer TPathRest extends Path] ? LazyPath<Required<MergeUnion<TValue>[TFirstKey]>, TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<KeyOf<TValue>> extends false ? readonly [...TValidPath, KeyOf<TValue>] : TValidPath;
128
128
  /**
129
129
  * Returns the path if valid, otherwise the first possible valid path based on
130
130
  * the given value.
131
131
  */
132
- type ValidPath<TValue, TPath extends RequiredPath> = TPath extends LazyPath<TValue, TPath> ? TPath : LazyPath<TValue, TPath>;
132
+ type ValidPath<TValue, TPath extends RequiredPath> = TPath extends LazyPath<Required<TValue>, TPath> ? TPath : LazyPath<Required<TValue>, TPath>;
133
133
  /**
134
134
  * Extracts the value type at the given path.
135
135
  */
136
- type PathValue<TValue, TPath extends Path> = TPath extends readonly [infer TKey, ...infer TRest extends Path] ? TKey extends KeyOf<TValue> ? PathValue<MergeUnion<TValue>[TKey], TRest> : unknown : TValue;
136
+ type PathValue<TValue, TPath extends Path> = TPath extends readonly [infer TKey, ...infer TRest extends Path] ? TKey extends KeyOf<Required<TValue>> ? PathValue<MergeUnion<Required<TValue>>[TKey], TRest> : unknown : TValue;
137
137
  /**
138
138
  * Checks if a value is an array or contains one.
139
139
  */
@@ -141,16 +141,16 @@ type IsOrHasArray<TValue> = IsAny<TValue> extends true ? false : TValue extends
141
141
  /**
142
142
  * Extracts the exact keys of a tuple, array or object that contain arrays.
143
143
  */
144
- type KeyOfArrayPath<TValue> = IsAny<TValue> extends true ? never : TValue extends readonly (infer TItem)[] ? number extends TValue["length"] ? IsOrHasArray<TItem> extends true ? number : never : { [TKey in keyof TValue]: TKey extends `${infer TIndex extends number}` ? IsOrHasArray<TValue[TKey]> extends true ? TIndex : never : never }[number] : TValue extends Record<string, unknown> ? { [TKey in keyof TValue]: IsOrHasArray<TValue[TKey]> extends true ? TKey : never }[keyof TValue] & PathKey : never;
144
+ type KeyOfArrayPath<TValue> = IsAny<TValue> extends true ? never : TValue extends readonly (infer TItem)[] ? number extends TValue["length"] ? IsOrHasArray<TItem> extends true ? number : never : { [TKey in keyof TValue]: TKey extends `${infer TIndex extends number}` ? IsOrHasArray<NonNullable<TValue[TKey]>> extends true ? TIndex : never : never }[number] : TValue extends Record<string, unknown> ? { [TKey in keyof TValue]: IsOrHasArray<NonNullable<TValue[TKey]>> extends true ? TKey : never }[keyof TValue] & PathKey : never;
145
145
  /**
146
146
  * Lazily evaluate only the first valid array path segment based on the given value.
147
147
  */
148
- type LazyArrayPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValue extends readonly unknown[] ? TValidPath : readonly [...TValidPath, KeyOfArrayPath<TValue>] : TPathToCheck extends readonly [infer TFirstKey extends KeyOfArrayPath<TValue>, ...infer TPathRest extends Path] ? LazyArrayPath<MergeUnion<TValue>[TFirstKey], TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<KeyOfArrayPath<TValue>> extends false ? readonly [...TValidPath, KeyOfArrayPath<TValue>] : never;
148
+ type LazyArrayPath<TValue, TPathToCheck extends Path, TValidPath extends Path = readonly []> = TPathToCheck extends readonly [] ? TValue extends readonly unknown[] ? TValidPath : readonly [...TValidPath, KeyOfArrayPath<TValue>] : TPathToCheck extends readonly [infer TFirstKey extends KeyOfArrayPath<TValue>, ...infer TPathRest extends Path] ? LazyArrayPath<Required<MergeUnion<TValue>[TFirstKey]>, TPathRest, readonly [...TValidPath, TFirstKey]> : IsNever<KeyOfArrayPath<TValue>> extends false ? readonly [...TValidPath, KeyOfArrayPath<TValue>] : never;
149
149
  /**
150
150
  * Returns the path if valid, otherwise the first possible valid array path based on
151
151
  * the given value.
152
152
  */
153
- type ValidArrayPath<TValue, TPath extends RequiredPath> = TPath extends LazyArrayPath<TValue, TPath> ? TPath : LazyArrayPath<TValue, TPath>;
153
+ type ValidArrayPath<TValue, TPath extends RequiredPath> = TPath extends LazyArrayPath<Required<TValue>, TPath> ? TPath : LazyArrayPath<Required<TValue>, TPath>;
154
154
  //#endregion
155
155
  //#region src/array/copyItemState/copyItemState.d.ts
156
156
  /**
package/dist/index.js CHANGED
@@ -263,6 +263,7 @@ function setFieldInput(internalFieldStore, input) {
263
263
  } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
264
264
  else {
265
265
  internalFieldStore.input.value = input;
266
+ internalFieldStore.isTouched.value = true;
266
267
  const startInput = untrack(() => internalFieldStore.startInput.value);
267
268
  internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
268
269
  }
@@ -487,7 +488,6 @@ function setInput(form, config) {
487
488
  batch(() => {
488
489
  const internalFormStore = form[INTERNAL];
489
490
  const internalFieldStore = config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
490
- setFieldBool(internalFieldStore, "isTouched", true);
491
491
  setFieldInput(internalFieldStore, config.input);
492
492
  validateIfRequired(internalFormStore, internalFieldStore, "input");
493
493
  });
package/dist/index.jsx CHANGED
@@ -261,6 +261,7 @@ function setFieldInput(internalFieldStore, input) {
261
261
  } else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) setFieldInput(internalFieldStore.children[key], input[key]);
262
262
  else {
263
263
  internalFieldStore.input.value = input;
264
+ internalFieldStore.isTouched.value = true;
264
265
  const startInput = untrack(() => internalFieldStore.startInput.value);
265
266
  internalFieldStore.isDirty.value = startInput !== input && (startInput !== void 0 || input !== "" && !Number.isNaN(input));
266
267
  }
@@ -485,7 +486,6 @@ function setInput(form, config) {
485
486
  batch(() => {
486
487
  const internalFormStore = form[INTERNAL];
487
488
  const internalFieldStore = config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
488
- setFieldBool(internalFieldStore, "isTouched", true);
489
489
  setFieldInput(internalFieldStore, config.input);
490
490
  validateIfRequired(internalFormStore, internalFieldStore, "input");
491
491
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formisch/solid",
3
3
  "description": "The modular and type-safe form library for SolidJS",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "license": "MIT",
6
6
  "author": "Fabian Hiller",
7
7
  "homepage": "https://formisch.dev",