@octanejs/formisch 0.0.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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/UPSTREAM.md +95 -0
  4. package/package.json +65 -0
  5. package/src/components/Field/Field.tsrx +22 -0
  6. package/src/components/Field/Field.tsrx.d.ts +17 -0
  7. package/src/components/Field/index.ts +1 -0
  8. package/src/components/FieldArray/FieldArray.tsrx +22 -0
  9. package/src/components/FieldArray/FieldArray.tsrx.d.ts +18 -0
  10. package/src/components/FieldArray/index.ts +1 -0
  11. package/src/components/Form/Form.tsrx +28 -0
  12. package/src/components/Form/Form.tsrx.d.ts +15 -0
  13. package/src/components/Form/index.ts +1 -0
  14. package/src/components/index.ts +3 -0
  15. package/src/core/array/copyItemState/copyItemState.ts +101 -0
  16. package/src/core/array/copyItemState/index.ts +1 -0
  17. package/src/core/array/index.ts +3 -0
  18. package/src/core/array/resetItemState/index.ts +1 -0
  19. package/src/core/array/resetItemState/resetItemState.ts +172 -0
  20. package/src/core/array/swapItemState/index.ts +1 -0
  21. package/src/core/array/swapItemState/swapItemState.ts +138 -0
  22. package/src/core/field/focusFieldElement/focusFieldElement.ts +32 -0
  23. package/src/core/field/focusFieldElement/index.ts +1 -0
  24. package/src/core/field/getDirtyFieldInput/getDirtyFieldInput.ts +66 -0
  25. package/src/core/field/getDirtyFieldInput/index.ts +1 -0
  26. package/src/core/field/getElementInput/getElementInput.ts +78 -0
  27. package/src/core/field/getElementInput/index.ts +1 -0
  28. package/src/core/field/getFieldBool/getFieldBool.ts +22 -0
  29. package/src/core/field/getFieldBool/index.ts +1 -0
  30. package/src/core/field/getFieldInput/getFieldInput.ts +52 -0
  31. package/src/core/field/getFieldInput/index.ts +1 -0
  32. package/src/core/field/getFieldStore/getFieldStore.ts +34 -0
  33. package/src/core/field/getFieldStore/index.ts +1 -0
  34. package/src/core/field/index.ts +11 -0
  35. package/src/core/field/initializeFieldStore/index.ts +1 -0
  36. package/src/core/field/initializeFieldStore/initializeFieldStore.ts +325 -0
  37. package/src/core/field/setFieldBool/index.ts +1 -0
  38. package/src/core/field/setFieldBool/setFieldBool.ts +29 -0
  39. package/src/core/field/setFieldInput/index.ts +1 -0
  40. package/src/core/field/setFieldInput/setFieldInput.ts +180 -0
  41. package/src/core/field/setInitialFieldInput/index.ts +1 -0
  42. package/src/core/field/setInitialFieldInput/setInitialFieldInput.ts +99 -0
  43. package/src/core/field/walkFieldStore/index.ts +1 -0
  44. package/src/core/field/walkFieldStore/walkFieldStore.ts +49 -0
  45. package/src/core/form/createFormStore/createFormStore.ts +56 -0
  46. package/src/core/form/createFormStore/index.ts +1 -0
  47. package/src/core/form/decodeFormData/decodeFormData.ts +436 -0
  48. package/src/core/form/decodeFormData/index.ts +1 -0
  49. package/src/core/form/index.ts +4 -0
  50. package/src/core/form/validateFormInput/index.ts +1 -0
  51. package/src/core/form/validateFormInput/validateFormInput.ts +138 -0
  52. package/src/core/form/validateIfRequired/index.ts +1 -0
  53. package/src/core/form/validateIfRequired/validateIfRequired.ts +31 -0
  54. package/src/core/framework/index.ts +80 -0
  55. package/src/core/index.ts +6 -0
  56. package/src/core/types/field/field.ts +201 -0
  57. package/src/core/types/field/index.ts +1 -0
  58. package/src/core/types/form/form.ts +140 -0
  59. package/src/core/types/form/index.ts +1 -0
  60. package/src/core/types/index.ts +6 -0
  61. package/src/core/types/path/index.ts +10 -0
  62. package/src/core/types/path/path.ts +301 -0
  63. package/src/core/types/schema/index.ts +1 -0
  64. package/src/core/types/schema/schema.ts +18 -0
  65. package/src/core/types/signal/index.ts +1 -0
  66. package/src/core/types/signal/signal.ts +23 -0
  67. package/src/core/types/utils/index.ts +1 -0
  68. package/src/core/types/utils/utils.ts +46 -0
  69. package/src/core/values.ts +4 -0
  70. package/src/hooks/index.ts +3 -0
  71. package/src/hooks/useField/index.ts +1 -0
  72. package/src/hooks/useField/useField.ts +114 -0
  73. package/src/hooks/useFieldArray/index.ts +1 -0
  74. package/src/hooks/useFieldArray/useFieldArray.ts +63 -0
  75. package/src/hooks/useForm/index.ts +1 -0
  76. package/src/hooks/useForm/useForm.ts +68 -0
  77. package/src/hooks/useSignals/index.ts +1 -0
  78. package/src/hooks/useSignals/useSignals.ts +31 -0
  79. package/src/index.ts +19 -0
  80. package/src/internal.ts +32 -0
  81. package/src/methods/focus/focus.ts +35 -0
  82. package/src/methods/focus/index.ts +1 -0
  83. package/src/methods/getDeepErrorEntries/getDeepErrorEntries.ts +108 -0
  84. package/src/methods/getDeepErrorEntries/index.ts +1 -0
  85. package/src/methods/getDeepErrors/getDeepErrors.ts +90 -0
  86. package/src/methods/getDeepErrors/index.ts +1 -0
  87. package/src/methods/getDirtyInput/getDirtyInput.ts +87 -0
  88. package/src/methods/getDirtyInput/index.ts +1 -0
  89. package/src/methods/getDirtyPaths/getDirtyPaths.ts +123 -0
  90. package/src/methods/getDirtyPaths/index.ts +1 -0
  91. package/src/methods/getErrors/getErrors.ts +70 -0
  92. package/src/methods/getErrors/index.ts +1 -0
  93. package/src/methods/getInput/getInput.ts +75 -0
  94. package/src/methods/getInput/index.ts +1 -0
  95. package/src/methods/handleSubmit/handleSubmit.ts +83 -0
  96. package/src/methods/handleSubmit/index.ts +1 -0
  97. package/src/methods/index.ts +23 -0
  98. package/src/methods/insert/index.ts +1 -0
  99. package/src/methods/insert/insert.ts +134 -0
  100. package/src/methods/isDirty/index.ts +1 -0
  101. package/src/methods/isDirty/isDirty.ts +72 -0
  102. package/src/methods/isEdited/index.ts +1 -0
  103. package/src/methods/isEdited/isEdited.ts +72 -0
  104. package/src/methods/isTouched/index.ts +1 -0
  105. package/src/methods/isTouched/isTouched.ts +72 -0
  106. package/src/methods/isValid/index.ts +1 -0
  107. package/src/methods/isValid/isValid.ts +74 -0
  108. package/src/methods/move/index.ts +1 -0
  109. package/src/methods/move/move.ts +124 -0
  110. package/src/methods/pickDirty/index.ts +1 -0
  111. package/src/methods/pickDirty/pickDirty.ts +87 -0
  112. package/src/methods/remove/index.ts +1 -0
  113. package/src/methods/remove/remove.ts +76 -0
  114. package/src/methods/replace/index.ts +1 -0
  115. package/src/methods/replace/replace.ts +80 -0
  116. package/src/methods/reset/index.ts +1 -0
  117. package/src/methods/reset/reset.ts +216 -0
  118. package/src/methods/setErrors/index.ts +1 -0
  119. package/src/methods/setErrors/setErrors.ts +63 -0
  120. package/src/methods/setInput/index.ts +1 -0
  121. package/src/methods/setInput/setInput.ts +87 -0
  122. package/src/methods/submit/index.ts +1 -0
  123. package/src/methods/submit/submit.ts +11 -0
  124. package/src/methods/swap/index.ts +1 -0
  125. package/src/methods/swap/swap.ts +85 -0
  126. package/src/methods/validate/index.ts +1 -0
  127. package/src/methods/validate/validate.ts +34 -0
  128. package/src/types/field.ts +48 -0
  129. package/src/types/form.ts +12 -0
  130. package/src/types/index.ts +2 -0
@@ -0,0 +1,80 @@
1
+ /*
2
+ * Vendored from Formisch 1.0.0-rc.0, commit
3
+ * 4c494fd8cf105efd04a4b179e9c090595a0bf041.
4
+ * This is the React-generated signal protocol with an Octane framework tag.
5
+ */
6
+ import type { Signal } from '../types/signal/index.ts';
7
+
8
+ export type Framework =
9
+ 'angular' | 'octane' | 'preact' | 'qwik' | 'react' | 'solid' | 'svelte' | 'vue';
10
+
11
+ export const framework: Framework = 'octane';
12
+
13
+ // @__NO_SIDE_EFFECTS__
14
+ export function createId(): string {
15
+ return Math.random().toString(36).slice(2);
16
+ }
17
+
18
+ export type Listener = [() => void, Set<Set<Listener>>];
19
+
20
+ let listener: Listener | undefined;
21
+
22
+ export function setListener(newListener: Listener | undefined): void {
23
+ listener = newListener;
24
+ }
25
+
26
+ let batchSubscribers: Set<Listener> | undefined;
27
+
28
+ // @__NO_SIDE_EFFECTS__
29
+ export function createSignal<T>(value: T): Signal<T> {
30
+ const subscribers = new Set<Listener>();
31
+ return {
32
+ get value() {
33
+ if (listener) {
34
+ subscribers.add(listener);
35
+ listener[1].add(subscribers);
36
+ }
37
+ return value;
38
+ },
39
+ set value(newValue: T) {
40
+ if (newValue !== value) {
41
+ value = newValue;
42
+ const localSubscribers: Listener[] = [];
43
+ for (const subscriber of subscribers) {
44
+ if (batchSubscribers) batchSubscribers.add(subscriber);
45
+ else localSubscribers.push(subscriber);
46
+ subscriber[1].delete(subscribers);
47
+ }
48
+ subscribers.clear();
49
+ for (const subscriber of localSubscribers) subscriber[0]();
50
+ }
51
+ },
52
+ };
53
+ }
54
+
55
+ let batchDepth = 0;
56
+
57
+ export function batch<T>(fn: () => T): T {
58
+ batchDepth++;
59
+ batchSubscribers ??= new Set();
60
+ try {
61
+ return fn();
62
+ } finally {
63
+ batchDepth--;
64
+ if (batchDepth === 0) {
65
+ const subscribers = batchSubscribers;
66
+ batchSubscribers = undefined;
67
+ for (const subscriber of subscribers) subscriber[0]();
68
+ }
69
+ }
70
+ }
71
+
72
+ export function untrack<T>(fn: () => T): T {
73
+ const previousListener = listener;
74
+ listener = undefined;
75
+ try {
76
+ return fn();
77
+ } finally {
78
+ listener = previousListener;
79
+ }
80
+ }
@@ -0,0 +1,6 @@
1
+ export * from './array/index.ts';
2
+ export * from './field/index.ts';
3
+ export * from './form/index.ts';
4
+ export * from './framework/index.ts';
5
+ export * from './types/index.ts';
6
+ export * from './values.ts';
@@ -0,0 +1,201 @@
1
+ import type { Path } from '../path/index.ts';
2
+ import type { Schema } from '../schema/index.ts';
3
+ import type { Signal } from '../signal/index.ts';
4
+
5
+ /**
6
+ * Field element type.
7
+ */
8
+ export type FieldElement = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
9
+
10
+ /**
11
+ * Internal base store interface.
12
+ */
13
+ export interface InternalBaseStore {
14
+ /**
15
+ * The kind of field store.
16
+ */
17
+ kind: 'array' | 'object' | 'value';
18
+ /**
19
+ * The name of the field.
20
+ */
21
+ name: string;
22
+ /**
23
+ * The path to the field.
24
+ */
25
+ path: Path;
26
+ /**
27
+ * The schema of the field.
28
+ */
29
+ schema: Schema;
30
+ /**
31
+ * Whether the schema is wrapped in a nullish schema.
32
+ *
33
+ * Hint: This indicates whether a missing input should be represented as the
34
+ * nullish value (`null`/`undefined`) instead of a present empty fallback
35
+ * (`true` for arrays and objects, or the empty input for values). It keeps
36
+ * resetting consistent with the initial state.
37
+ */
38
+ isNullish: boolean;
39
+ /**
40
+ * The initial elements of the field.
41
+ *
42
+ * Hint: This may look unused, but do not remove it. `copyItemState` and
43
+ * `swapItemState` move the `elements` reference between field stores when
44
+ * array items are inserted, moved, removed or swapped, and `reset` restores
45
+ * each field's original element via `elements = initialElements`. Without it,
46
+ * focus and file reset target the wrong element after a reorder followed by a
47
+ * reset.
48
+ */
49
+ initialElements: FieldElement[];
50
+ /**
51
+ * The elements of the field.
52
+ */
53
+ elements: FieldElement[];
54
+ /**
55
+ * The errors of the field.
56
+ */
57
+ errors: Signal<[string, ...string[]] | null>;
58
+ /**
59
+ * The touched state of the field.
60
+ */
61
+ isTouched: Signal<boolean>;
62
+ /**
63
+ * The edited state of the field.
64
+ *
65
+ * Hint: Unlike `isTouched`, which is also set when a field is focused, this
66
+ * is only set when the field's value is changed. Unlike `isDirty`, it stays
67
+ * `true` even if the value is changed back to its initial value. It is only
68
+ * reset when the field is reset.
69
+ */
70
+ isEdited: Signal<boolean>;
71
+ /**
72
+ * The dirty state of the field.
73
+ */
74
+ isDirty: Signal<boolean>;
75
+ }
76
+
77
+ /**
78
+ * Internal array store interface.
79
+ */
80
+ export interface InternalArrayStore extends InternalBaseStore {
81
+ /**
82
+ * The kind of field store.
83
+ */
84
+ kind: 'array';
85
+
86
+ /**
87
+ * The children of the array field.
88
+ */
89
+ children: InternalFieldStore[];
90
+
91
+ /**
92
+ * The initial input of the array field.
93
+ *
94
+ * Hint: The initial input is used for resetting and may only be changed
95
+ * during this process. It does not move when a field is moved.
96
+ */
97
+ initialInput: Signal<true | null | undefined>;
98
+ /**
99
+ * The start input of the array field.
100
+ *
101
+ * Hint: The start input is used to determine whether the field is dirty
102
+ * and moves with it.
103
+ */
104
+ startInput: Signal<true | null | undefined>;
105
+ /**
106
+ * The input of the array field.
107
+ *
108
+ * Hint: The input indicates whether it is `null`, `undefined`, or found in
109
+ * the children.
110
+ */
111
+ input: Signal<true | null | undefined>;
112
+
113
+ /**
114
+ * The initial items of the array field.
115
+ *
116
+ * Hint: The initial items are used for resetting and may only be changed
117
+ * during this process. It does not move when a field is moved.
118
+ */
119
+ initialItems: Signal<string[]>;
120
+ /**
121
+ * The start items of the array field.
122
+ *
123
+ * Hint: The start items are used to determine whether the field is dirty
124
+ * and moves with it.
125
+ */
126
+ startItems: Signal<string[]>;
127
+ /**
128
+ * The items of the array field.
129
+ */
130
+ items: Signal<string[]>;
131
+ }
132
+
133
+ /**
134
+ * Internal object store interface.
135
+ */
136
+ export interface InternalObjectStore extends InternalBaseStore {
137
+ /**
138
+ * The kind of field store.
139
+ */
140
+ kind: 'object';
141
+ /**
142
+ * The children of the object field.
143
+ */
144
+ children: Record<string, InternalFieldStore>;
145
+
146
+ /**
147
+ * The initial input of the object field.
148
+ *
149
+ * Hint: The initial input is used for resetting and may only be changed
150
+ * during this process. It does not move when a field is moved.
151
+ */
152
+ initialInput: Signal<true | null | undefined>;
153
+ /**
154
+ * The start input of the object field.
155
+ *
156
+ * Hint: The start input is used to determine whether the field is dirty
157
+ * and moves with it.
158
+ */
159
+ startInput: Signal<true | null | undefined>;
160
+ /**
161
+ * The input of the object field.
162
+ *
163
+ * Hint: The input indicates whether it is `null`, `undefined`, or found in
164
+ * the children.
165
+ */
166
+ input: Signal<true | null | undefined>;
167
+ }
168
+
169
+ /**
170
+ * Internal value store interface.
171
+ */
172
+ export interface InternalValueStore extends InternalBaseStore {
173
+ /**
174
+ * The kind of field store.
175
+ */
176
+ kind: 'value';
177
+
178
+ /**
179
+ * The initial input of the value field.
180
+ *
181
+ * Hint: The initial input is used for resetting and may only be changed
182
+ * during this process. It does not move when a field is moved.
183
+ */
184
+ initialInput: Signal<unknown>;
185
+ /**
186
+ * The start input of the value field.
187
+ *
188
+ * Hint: The start input is used to determine whether the field is dirty
189
+ * and moves with it.
190
+ */
191
+ startInput: Signal<unknown>;
192
+ /**
193
+ * The input of the value field.
194
+ */
195
+ input: Signal<unknown>;
196
+ }
197
+
198
+ /**
199
+ * Internal field store type.
200
+ */
201
+ export type InternalFieldStore = InternalArrayStore | InternalObjectStore | InternalValueStore;
@@ -0,0 +1 @@
1
+ export * from './field.ts';
@@ -0,0 +1,140 @@
1
+ import type * as v from 'valibot';
2
+ import type { INTERNAL } from '../../values.ts';
3
+ import type { InternalObjectStore } from '../field/index.ts';
4
+ import type { FormSchema } from '../schema/index.ts';
5
+ import type { Signal } from '../signal/index.ts';
6
+ import type { DeepPartial, MaybePromise } from '../utils/index.ts';
7
+
8
+ /**
9
+ * Validation mode type.
10
+ */
11
+ export type ValidationMode = 'initial' | 'touch' | 'input' | 'change' | 'blur' | 'submit';
12
+
13
+ /**
14
+ * Empty input interface.
15
+ *
16
+ * Defines the value a required field of a given type starts at when no initial
17
+ * input is provided. Optional and nullable fields are not affected, as they
18
+ * accept `undefined`. Only required fields whose input is `undefined` fall back
19
+ * to these values.
20
+ */
21
+ export interface EmptyInput {
22
+ /**
23
+ * The empty input of a string field. Defaults to an empty string so that an
24
+ * untouched field matches the DOM and validates with its own message instead
25
+ * of a type mismatch. Set to `undefined` to opt out.
26
+ */
27
+ readonly string?: string | undefined;
28
+ /**
29
+ * The empty input of a number field. Defaults to `undefined`.
30
+ */
31
+ readonly number?: number | undefined;
32
+ /**
33
+ * The empty input of a boolean field. Defaults to `undefined`.
34
+ */
35
+ readonly boolean?: boolean | undefined;
36
+ /**
37
+ * The empty input of a date field. Defaults to `undefined`.
38
+ */
39
+ readonly date?: Date | undefined;
40
+ }
41
+
42
+ /**
43
+ * Form config interface.
44
+ */
45
+ export interface FormConfig<TSchema extends FormSchema = FormSchema> {
46
+ /**
47
+ * The schema of the form.
48
+ */
49
+ readonly schema: TSchema;
50
+ /**
51
+ * The initial input of the form.
52
+ */
53
+ readonly initialInput?: DeepPartial<v.InferInput<TSchema>> | undefined;
54
+ /**
55
+ * The empty input of the form, keyed by field type. Merged on top of the
56
+ * defaults, so `{ string: '' }` stays in effect unless overridden.
57
+ */
58
+ readonly emptyInput?: EmptyInput | undefined;
59
+ /**
60
+ * The validation mode of the form.
61
+ */
62
+ readonly validate?: ValidationMode | undefined;
63
+ /**
64
+ * The revalidation mode of the form.
65
+ */
66
+ readonly revalidate?: Exclude<ValidationMode, 'initial'> | undefined;
67
+ }
68
+
69
+ /**
70
+ * Internal form store interface.
71
+ */
72
+ export interface InternalFormStore<
73
+ TSchema extends FormSchema = FormSchema,
74
+ > extends InternalObjectStore {
75
+ /**
76
+ * The element of the form.
77
+ */
78
+ element?: HTMLFormElement | undefined;
79
+
80
+ /**
81
+ * The number of active validators.
82
+ */
83
+ validators: number;
84
+ /**
85
+ * The resolved empty input of the form, keyed by field type.
86
+ */
87
+ emptyInput: EmptyInput;
88
+ /**
89
+ * The validation mode of the form.
90
+ */
91
+ validate: ValidationMode;
92
+ /**
93
+ * The revalidation mode of the form.
94
+ */
95
+ revalidate: Exclude<ValidationMode, 'initial'>;
96
+ /**
97
+ * The parse function of the form.
98
+ */
99
+ parse: (input: unknown) => Promise<v.SafeParseResult<TSchema>>;
100
+
101
+ /**
102
+ * The submitting state of the form.
103
+ */
104
+ isSubmitting: Signal<boolean>;
105
+ /**
106
+ * The submitted state of the form.
107
+ */
108
+ isSubmitted: Signal<boolean>;
109
+ /**
110
+ * The validating state of the form.
111
+ */
112
+ isValidating: Signal<boolean>;
113
+ }
114
+
115
+ /**
116
+ * Base form store interface.
117
+ */
118
+ export interface BaseFormStore<TSchema extends FormSchema = FormSchema> {
119
+ /**
120
+ * The internal form store.
121
+ *
122
+ * @internal
123
+ */
124
+ readonly [INTERNAL]: InternalFormStore<TSchema>;
125
+ }
126
+
127
+ /**
128
+ * Submit handler type.
129
+ */
130
+ export type SubmitHandler<TSchema extends FormSchema> = (
131
+ output: v.InferOutput<TSchema>,
132
+ ) => MaybePromise<unknown>;
133
+
134
+ /**
135
+ * Submit event handler type.
136
+ */
137
+ export type SubmitEventHandler<TSchema extends FormSchema> = (
138
+ output: v.InferOutput<TSchema>,
139
+ event: SubmitEvent,
140
+ ) => MaybePromise<unknown>;
@@ -0,0 +1 @@
1
+ export * from './form.ts';
@@ -0,0 +1,6 @@
1
+ export * from './field/index.ts';
2
+ export * from './form/index.ts';
3
+ export * from './path/index.ts';
4
+ export * from './schema/index.ts';
5
+ export * from './signal/index.ts';
6
+ export * from './utils/index.ts';
@@ -0,0 +1,10 @@
1
+ export type {
2
+ DirtyPath,
3
+ FieldPath,
4
+ Path,
5
+ PathValue,
6
+ PathKey,
7
+ RequiredPath,
8
+ ValidArrayPath,
9
+ ValidPath,
10
+ } from './path.ts';