@teamnovu/kit-vue-forms 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 (45) hide show
  1. package/PLAN.md +209 -0
  2. package/dist/composables/useField.d.ts +12 -0
  3. package/dist/composables/useFieldRegistry.d.ts +15 -0
  4. package/dist/composables/useForm.d.ts +10 -0
  5. package/dist/composables/useFormState.d.ts +7 -0
  6. package/dist/composables/useSubform.d.ts +5 -0
  7. package/dist/composables/useValidation.d.ts +30 -0
  8. package/dist/index.d.ts +6 -0
  9. package/dist/index.mjs +414 -0
  10. package/dist/types/form.d.ts +41 -0
  11. package/dist/types/util.d.ts +26 -0
  12. package/dist/types/validation.d.ts +16 -0
  13. package/dist/utils/general.d.ts +2 -0
  14. package/dist/utils/path.d.ts +11 -0
  15. package/dist/utils/type-helpers.d.ts +3 -0
  16. package/dist/utils/validation.d.ts +3 -0
  17. package/dist/utils/zod.d.ts +3 -0
  18. package/package.json +41 -0
  19. package/src/composables/useField.ts +74 -0
  20. package/src/composables/useFieldRegistry.ts +53 -0
  21. package/src/composables/useForm.ts +54 -0
  22. package/src/composables/useFormData.ts +16 -0
  23. package/src/composables/useFormState.ts +21 -0
  24. package/src/composables/useSubform.ts +173 -0
  25. package/src/composables/useValidation.ts +227 -0
  26. package/src/index.ts +11 -0
  27. package/src/types/form.ts +58 -0
  28. package/src/types/util.ts +73 -0
  29. package/src/types/validation.ts +22 -0
  30. package/src/utils/general.ts +7 -0
  31. package/src/utils/path.ts +87 -0
  32. package/src/utils/type-helpers.ts +3 -0
  33. package/src/utils/validation.ts +66 -0
  34. package/src/utils/zod.ts +24 -0
  35. package/tests/formState.test.ts +138 -0
  36. package/tests/integration.test.ts +200 -0
  37. package/tests/nestedPath.test.ts +651 -0
  38. package/tests/path-utils.test.ts +159 -0
  39. package/tests/subform.test.ts +1348 -0
  40. package/tests/useField.test.ts +147 -0
  41. package/tests/useForm.test.ts +178 -0
  42. package/tests/useValidation.test.ts +216 -0
  43. package/tsconfig.json +18 -0
  44. package/vite.config.js +39 -0
  45. package/vitest.config.ts +14 -0
package/PLAN.md ADDED
@@ -0,0 +1,209 @@
1
+ # Vue Forms Library - MVP Plan
2
+
3
+ ## Overview
4
+
5
+ A type-safe Vue 3 form library with immutable state management, validation, and subform support. The library uses a direct form instance pattern (no provide/inject) to maintain full type safety throughout the component tree.
6
+
7
+ ## Core Architecture
8
+
9
+ ### Direct Form Instance Pattern
10
+ - Forms are created with `createForm<T>()` and passed directly to components
11
+ - Full TypeScript type safety maintained throughout the component tree
12
+ - No context loss from provide/inject patterns
13
+
14
+ ### Subform Extraction Pattern
15
+ ```typescript
16
+ // Reusable components work with subforms
17
+ const addressSubform = form.getSubform('address')
18
+ // addressSubform has type FormInstance<Address>
19
+
20
+ <AddressForm :form="addressSubform" />
21
+ ```
22
+
23
+ This allows components to be reusable across different parent forms while maintaining type safety.
24
+
25
+ ## API Design
26
+
27
+ ### Form Creation
28
+ ```typescript
29
+ const form = createForm<UserData>({
30
+ initialData: { name: '', email: '', address: { street: '', city: '' } },
31
+ validationSchema: userSchema,
32
+ strategy: 'onTouch'
33
+ })
34
+ ```
35
+
36
+ ### Form Instance Interface
37
+ ```typescript
38
+ interface FormInstance<T> {
39
+ // Data access
40
+ getValue<K extends keyof T>(path: K): T[K]
41
+ setValue<K extends keyof T>(path: K, value: T[K]): void
42
+
43
+ // Field management
44
+ getField<K extends keyof T>(path: K): FieldInstance<T[K]>
45
+
46
+ // Subform extraction
47
+ getSubform<K extends keyof T>(path: K): FormInstance<T[K]>
48
+
49
+ // State queries
50
+ isDirty(): boolean
51
+ isTouched(): boolean
52
+ isValid(): boolean
53
+
54
+ // Operations
55
+ validate(): Promise<ValidationResult>
56
+ reset(): void
57
+ submit(): Promise<void>
58
+
59
+ // Error access
60
+ getErrors(path?: keyof T): ErrorMessage[]
61
+ hasErrors(path?: keyof T): boolean
62
+ }
63
+ ```
64
+
65
+ ### Field Instance Interface
66
+ ```typescript
67
+ interface FieldInstance<T> {
68
+ // Reactive value with getter/setter
69
+ value: Ref<T>
70
+
71
+ // State
72
+ touched: Ref<boolean>
73
+ dirty: Ref<boolean>
74
+ errors: Ref<ErrorMessage[]>
75
+
76
+ // Handlers
77
+ onBlur(): void
78
+ onFocus(): void
79
+
80
+ // Field-specific validation
81
+ validate(): Promise<ValidationResult>
82
+ }
83
+ ```
84
+
85
+ ## Directory Structure
86
+
87
+ ```
88
+ src/
89
+ ├── types/
90
+ │ ├── form.ts # Form instance types
91
+ │ ├── field.ts # Field instance types
92
+ │ ├── validation.ts # Validation types
93
+ │ └── index.ts
94
+ ├── core/
95
+ │ ├── form-instance.ts # Form instance implementation
96
+ │ ├── field-instance.ts # Field instance implementation
97
+ │ ├── subform-instance.ts # Subform implementation
98
+ │ └── validation-engine.ts # Validation logic
99
+ ├── factories/
100
+ │ └── create-form.ts # Main form factory
101
+ ├── utils/
102
+ │ ├── immutable.ts # Immutable helpers
103
+ │ ├── path.ts # Object path utilities
104
+ │ └── type-helpers.ts # TypeScript utility types
105
+ └── index.ts # Main exports
106
+ ```
107
+
108
+ ## Core Features
109
+
110
+ ### 1. Immutable State Management
111
+ - Store initial data as immutable
112
+ - Working copy is immutable from outside (readonly)
113
+ - Computed getter/setter on working copy
114
+ - Full clone on creation
115
+
116
+ ### 2. Form State Tracking
117
+ - **Touched**: Field has been interacted with at least once
118
+ - **Dirty**: Computed property checking if value ≠ initial state
119
+ - State propagation from subforms to parent forms
120
+
121
+ ### 3. Validation System
122
+ - **Strategies**: `onTouch`, `onFormOpen`, `none`, `preSubmit`
123
+ - **Zod Integration**: Primary validation with Zod schemas
124
+ - **Backend Validation**: API errors merged with Zod errors
125
+ - **Error Bag Structure**:
126
+ ```typescript
127
+ {
128
+ general: ErrorMessage[],
129
+ propertyErrors: Record<string, ErrorMessage[]>
130
+ }
131
+ ```
132
+
133
+ ### 4. Subform Support
134
+ - Extract subforms with `getSubform(path)`
135
+ - Type-safe subform instances
136
+ - Automatic value propagation from subforms to parent
137
+ - Reusable components across different parent forms
138
+
139
+ ### 5. Array Functionality (Future)
140
+ - `pushValue()`, `removeValue()`, `getKeys()`
141
+ - Similar to vee-validate's field array API
142
+
143
+ ## MVP Implementation Order
144
+
145
+ ### Phase 1: Core Infrastructure
146
+ 1. **Project Setup**
147
+ - Package.json with proper exports
148
+ - TypeScript configuration
149
+ - Vite build setup
150
+ - Basic documentation structure
151
+
152
+ 2. **Type System**
153
+ - Core interfaces and types
154
+ - Validation types
155
+ - Error handling types
156
+
157
+ 3. **Basic Form Instance**
158
+ - Form creation factory
159
+ - Basic field management
160
+ - Immutable state handling
161
+
162
+ ### Phase 2: Essential Features
163
+ 1. **Field Management**
164
+ - Field instance implementation
165
+ - Touch and dirty state tracking
166
+ - Basic event handlers
167
+
168
+ 2. **Validation Engine**
169
+ - Zod integration
170
+ - Error collection and formatting
171
+ - Basic validation strategies
172
+
173
+ 3. **Subform System**
174
+ - Subform extraction
175
+ - Type-safe subform instances
176
+ - Value propagation
177
+
178
+ ### Phase 3: Polish & Testing
179
+ 1. **Edge Cases**
180
+ - Error handling
181
+ - Reset functionality
182
+ - Validation edge cases
183
+
184
+ 2. **Documentation**
185
+ - API documentation
186
+ - Usage examples
187
+ - Migration guides
188
+
189
+ 3. **Testing**
190
+ - Unit tests
191
+ - Integration tests
192
+ - Type safety tests
193
+
194
+ ## Key Benefits
195
+
196
+ - **Type Safety**: Full TypeScript support with no type loss
197
+ - **Immutable State**: Predictable state management
198
+ - **Reusable Components**: Subforms enable component reuse
199
+ - **Validation Flexibility**: Multiple validation strategies
200
+ - **Performance**: Reactive updates only where needed
201
+ - **Developer Experience**: Excellent IDE support and debugging
202
+
203
+ ## Notes
204
+
205
+ - No provide/inject pattern to avoid type information loss
206
+ - Direct form instance passing maintains type safety
207
+ - Subform extraction enables component reusability
208
+ - Validation strategies can be overridden per field
209
+ - Backend validation seamlessly integrates with Zod
@@ -0,0 +1,12 @@
1
+ import { MaybeRef, MaybeRefOrGetter } from 'vue';
2
+ import { FormField } from '../types/form';
3
+ import { ValidationErrors } from '../types/validation';
4
+ export interface UseFieldOptions<T, K extends string> {
5
+ value?: MaybeRef<T>;
6
+ initialValue?: MaybeRefOrGetter<Readonly<T>>;
7
+ type?: MaybeRef<string>;
8
+ required?: MaybeRef<boolean>;
9
+ path: K;
10
+ errors?: MaybeRef<ValidationErrors>;
11
+ }
12
+ export declare function useField<T, K extends string>(options: UseFieldOptions<T, K>): FormField<T, K>;
@@ -0,0 +1,15 @@
1
+ import { FormDataDefault, FormField, FormState } from '../types/form';
2
+ import { Paths, PickProps } from '../types/util';
3
+ import { UseFieldOptions } from './useField';
4
+ type FieldRegistryCache<T> = Record<Paths<T>, FormField<any, string>>;
5
+ export type ResolvedFormField<T, K extends Paths<T>> = FormField<PickProps<T, K>, K>;
6
+ export type DefineFieldOptions<F, K extends string> = Pick<UseFieldOptions<F, K>, 'path' | 'type' | 'required'>;
7
+ export declare function useFieldRegistry<T extends FormDataDefault>(formState: FormState<T>): {
8
+ fields: FieldRegistryCache<T>;
9
+ getField: <K extends Paths<T>>(path: K) => ResolvedFormField<T, K> | undefined;
10
+ getFields: () => ResolvedFormField<T, Paths<T>>[];
11
+ registerField: <K extends Paths<T>>(field: ResolvedFormField<T, K>) => void;
12
+ defineField: <K extends Paths<T>>(options: DefineFieldOptions<PickProps<T, K>, K>) => FormField<PickProps<any, K>, K>;
13
+ };
14
+ export type FieldRegistry<T extends FormDataDefault> = ReturnType<typeof useFieldRegistry<T>>;
15
+ export {};
@@ -0,0 +1,10 @@
1
+ import { MaybeRef, MaybeRefOrGetter } from 'vue';
2
+ import { Form, FormDataDefault } from '../types/form';
3
+ import { ValidationStrategy } from '../types/validation';
4
+ import { ValidationOptions } from './useValidation';
5
+ export interface UseFormOptions<T extends FormDataDefault> extends ValidationOptions<T> {
6
+ initialData: MaybeRefOrGetter<T>;
7
+ validationStrategy?: MaybeRef<ValidationStrategy>;
8
+ keepValuesOnUnmount?: MaybeRef<boolean>;
9
+ }
10
+ export declare function useForm<T extends FormDataDefault>(options: UseFormOptions<T>): Form<T>;
@@ -0,0 +1,7 @@
1
+ import { FormDataDefault, FormState } from '../types/form';
2
+ import { FieldRegistry } from './useFieldRegistry';
3
+ import { ComputedRef } from 'vue';
4
+ export declare function useFormState<T extends FormDataDefault>(formState: FormState<T>, formFieldRegistry: FieldRegistry<T>): {
5
+ isDirty: ComputedRef<boolean>;
6
+ isTouched: ComputedRef<boolean>;
7
+ };
@@ -0,0 +1,5 @@
1
+ import { Form, FormDataDefault } from '../types/form';
2
+ import { EntityPaths, PickEntity } from '../types/util';
3
+ export interface SubformOptions<_T extends FormDataDefault> {
4
+ }
5
+ export declare function createSubformInterface<T extends FormDataDefault, K extends EntityPaths<T>>(mainForm: Form<T>, path: K, _options?: SubformOptions<PickEntity<T, K>>): Form<PickEntity<T, K>>;
@@ -0,0 +1,30 @@
1
+ import { MaybeRef, Ref, ComputedRef } from 'vue';
2
+ import { default as z } from 'zod';
3
+ import { FormDataDefault } from '../types/form';
4
+ import { ErrorBag, ValidationFunction, ValidationResult, Validator, ValidationErrors } from '../types/validation';
5
+ export interface ValidatorOptions<T> {
6
+ schema?: MaybeRef<z.ZodType>;
7
+ validateFn?: MaybeRef<ValidationFunction<T>>;
8
+ }
9
+ export interface ValidationOptions<T> extends ValidatorOptions<T> {
10
+ errors?: MaybeRef<ErrorBag>;
11
+ }
12
+ export declare const SuccessValidationResult: ValidationResult;
13
+ export declare function createValidator<T extends FormDataDefault>(options: ValidatorOptions<T>): Ref<Validator<T> | undefined>;
14
+ export declare function useValidation<T extends FormDataDefault>(formState: {
15
+ formData: T;
16
+ }, options: ValidationOptions<T>): {
17
+ validateForm: () => Promise<ValidationResult>;
18
+ defineValidator: (options: ValidatorOptions<T> | Ref<Validator<T>>) => Ref<Validator<T> | undefined, Validator<T> | undefined>;
19
+ isValid: ComputedRef<boolean>;
20
+ validators: Ref<Ref<Validator<T> | undefined, Validator<T> | undefined>[], Ref<Validator<T> | undefined, Validator<T> | undefined>[]>;
21
+ isValidated: Ref<boolean, boolean>;
22
+ errors: Ref<{
23
+ general: string[] | undefined;
24
+ propertyErrors: Record<string, ValidationErrors>;
25
+ }, {
26
+ general: string[] | undefined;
27
+ propertyErrors: Record<string, ValidationErrors>;
28
+ }>;
29
+ };
30
+ export type ValidationState<T extends FormDataDefault> = ReturnType<typeof useValidation<T>>;
@@ -0,0 +1,6 @@
1
+ export { useForm } from './composables/useForm';
2
+ export type { UseFormOptions } from './composables/useForm';
3
+ export { useField } from './composables/useField';
4
+ export type { UseFieldOptions } from './composables/useField';
5
+ export type { ValidationStrategy, ValidationErrorMessage as ErrorMessage, ValidationResult, ErrorBag } from './types/validation';
6
+ export type { DeepPartial, FormData } from './utils/type-helpers';