@tachui/forms 0.7.1-alpha → 0.8.0-alpha

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 (90) hide show
  1. package/README.md +87 -272
  2. package/dist/DatePicker-D5nRFTUm.js +475 -0
  3. package/dist/DatePicker-D5nRFTUm.js.map +1 -0
  4. package/dist/Select-yZyKooXk.js +945 -0
  5. package/dist/Select-yZyKooXk.js.map +1 -0
  6. package/dist/Slider-0-oal5YR.js +644 -0
  7. package/dist/Slider-0-oal5YR.js.map +1 -0
  8. package/dist/TextField-hX15dY3U.js +509 -0
  9. package/dist/TextField-hX15dY3U.js.map +1 -0
  10. package/dist/components/advanced/Slider.d.ts +190 -0
  11. package/dist/components/advanced/Slider.d.ts.map +1 -0
  12. package/dist/components/advanced/Stepper.d.ts +161 -0
  13. package/dist/components/advanced/Stepper.d.ts.map +1 -0
  14. package/dist/components/advanced/index.d.ts +15 -0
  15. package/dist/components/advanced/index.d.ts.map +1 -0
  16. package/dist/components/advanced/index.js +6 -0
  17. package/dist/components/advanced/index.js.map +1 -0
  18. package/dist/components/date-picker/DatePicker.d.ts +126 -0
  19. package/dist/components/date-picker/DatePicker.d.ts.map +1 -0
  20. package/dist/components/date-picker/index.d.ts +14 -0
  21. package/dist/components/date-picker/index.d.ts.map +1 -0
  22. package/dist/components/date-picker/index.js +5 -0
  23. package/dist/components/date-picker/index.js.map +1 -0
  24. package/dist/components/form-container/index.d.ts +58 -0
  25. package/dist/components/form-container/index.d.ts.map +1 -0
  26. package/dist/components/selection/Checkbox.d.ts.map +1 -0
  27. package/dist/components/selection/Radio.d.ts.map +1 -0
  28. package/dist/components/selection/Select.d.ts.map +1 -0
  29. package/dist/components/selection/index.d.ts +68 -0
  30. package/dist/components/selection/index.d.ts.map +1 -0
  31. package/dist/components/selection/index.js +12 -0
  32. package/dist/components/selection/index.js.map +1 -0
  33. package/dist/components/text-input/TextField.d.ts.map +1 -0
  34. package/dist/components/text-input/index.d.ts +8 -0
  35. package/dist/components/text-input/index.d.ts.map +1 -0
  36. package/dist/components/text-input/index.js +18 -0
  37. package/dist/components/text-input/index.js.map +1 -0
  38. package/dist/{state/index.js → index-D3WfkqVv.js} +15 -8
  39. package/dist/index-D3WfkqVv.js.map +1 -0
  40. package/dist/index.d.ts +10 -15
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +198 -376
  43. package/dist/index.js.map +1 -0
  44. package/dist/state/index.d.ts.map +1 -1
  45. package/dist/types/index.d.ts.map +1 -1
  46. package/dist/utils/index.d.ts +19 -0
  47. package/dist/utils/index.d.ts.map +1 -0
  48. package/dist/validation/component-validation.d.ts +11 -2
  49. package/dist/validation/component-validation.d.ts.map +1 -1
  50. package/dist/validation/index.d.ts.map +1 -1
  51. package/dist/validation/index.js +282 -191
  52. package/dist/validation/index.js.map +1 -0
  53. package/package.json +53 -39
  54. package/src/components/advanced/Slider.ts +722 -0
  55. package/src/components/advanced/Stepper.ts +715 -0
  56. package/src/components/advanced/index.ts +20 -0
  57. package/src/components/date-picker/DatePicker.ts +925 -0
  58. package/src/components/date-picker/index.ts +20 -0
  59. package/src/components/form-container/index.ts +266 -0
  60. package/src/components/selection/Checkbox.ts +478 -0
  61. package/src/components/selection/Radio.ts +470 -0
  62. package/src/components/selection/Select.ts +620 -0
  63. package/src/components/selection/index.ts +81 -0
  64. package/src/components/text-input/TextField.ts +728 -0
  65. package/src/components/text-input/index.ts +35 -0
  66. package/src/index.ts +48 -0
  67. package/src/state/index.ts +544 -0
  68. package/src/types/index.ts +579 -0
  69. package/src/utils/formatters.ts +184 -0
  70. package/src/utils/index.ts +57 -0
  71. package/src/validation/component-validation.ts +429 -0
  72. package/src/validation/index.ts +641 -0
  73. package/dist/TextField-CGBM3x7K.js +0 -1799
  74. package/dist/components/Form.d.ts +0 -76
  75. package/dist/components/Form.d.ts.map +0 -1
  76. package/dist/components/index.d.ts +0 -9
  77. package/dist/components/index.d.ts.map +0 -1
  78. package/dist/components/index.js +0 -28
  79. package/dist/components/input/Checkbox.d.ts.map +0 -1
  80. package/dist/components/input/Radio.d.ts.map +0 -1
  81. package/dist/components/input/Select.d.ts.map +0 -1
  82. package/dist/components/input/TextField.d.ts.map +0 -1
  83. package/dist/components/input/index.d.ts +0 -11
  84. package/dist/components/input/index.d.ts.map +0 -1
  85. package/dist/utils/validators.d.ts +0 -101
  86. package/dist/utils/validators.d.ts.map +0 -1
  87. /package/dist/components/{input → selection}/Checkbox.d.ts +0 -0
  88. /package/dist/components/{input → selection}/Radio.d.ts +0 -0
  89. /package/dist/components/{input → selection}/Select.d.ts +0 -0
  90. /package/dist/components/{input → text-input}/TextField.d.ts +0 -0
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Text Input Components
3
+ *
4
+ * All text-based input components with validation
5
+ */
6
+
7
+ // Import and re-export the complete TextField implementation
8
+ export {
9
+ TextField,
10
+ EmailField,
11
+ PasswordField,
12
+ SearchField,
13
+ URLField,
14
+ PhoneField,
15
+ NumberField,
16
+ CreditCardField,
17
+ SSNField,
18
+ PostalCodeField,
19
+ TextArea,
20
+ DateField,
21
+ TimeField,
22
+ ColorField,
23
+ } from './TextField'
24
+
25
+ // Export types from the main types file
26
+ export type {
27
+ TextFieldProps,
28
+ NumberFieldProps,
29
+ TextFieldType,
30
+ TextFieldFormatter,
31
+ TextFieldParser,
32
+ AutoCapitalization,
33
+ KeyboardType,
34
+ ReturnKeyType,
35
+ } from '../../types'
package/src/index.ts ADDED
@@ -0,0 +1,48 @@
1
+ /**
2
+ * TachUI Forms - Comprehensive Form Components and Validation
3
+ *
4
+ * Unified package combining all form functionality from @tachui/forms and @tachui/advanced-forms
5
+ * Provides 27 components with comprehensive validation and optimal tree-shaking
6
+ */
7
+
8
+ // Form Container Components
9
+ export * from './components/form-container'
10
+
11
+ // Text Input Components (TextField, TextArea, EmailField, etc.)
12
+ export * from './components/text-input'
13
+
14
+ // Selection Components (Checkbox, Radio, Select, etc.)
15
+ export * from './components/selection'
16
+
17
+ // Advanced Components (Stepper, Slider)
18
+ export * from './components/advanced'
19
+
20
+ // Date Components (DatePicker with rich calendar interface)
21
+ export * from './components/date-picker'
22
+
23
+ // State Management
24
+ export * from './state'
25
+
26
+ // Validation System
27
+ export * from './validation'
28
+
29
+ // Utilities and Helpers
30
+ export * from './utils'
31
+
32
+ // Export specific types to avoid conflicts
33
+ export type {
34
+ // Core form types
35
+ ValidationRule,
36
+ ValidationResult,
37
+ FieldValidation,
38
+ FieldState,
39
+
40
+ // Component prop types (using specific names to avoid conflicts)
41
+ TextFieldProps,
42
+ NumberFieldProps,
43
+ TextFieldFormatter,
44
+ TextFieldParser,
45
+ AutoCapitalization,
46
+ KeyboardType,
47
+ ReturnKeyType,
48
+ } from './types'
@@ -0,0 +1,544 @@
1
+ /**
2
+ * TachUI Forms State Management
3
+ *
4
+ * Reactive form state management with validation, field tracking,
5
+ * and form lifecycle management using TachUI's signal system.
6
+ */
7
+
8
+ import { createComputed, createEffect, createSignal } from '@tachui/core'
9
+ import type {
10
+ FieldState,
11
+ FieldValidation,
12
+ FormState,
13
+ FormSubmitHandler,
14
+ UseFormReturn,
15
+ ValidationResult,
16
+ } from '../types'
17
+ import { validateValueAsync } from '../validation'
18
+
19
+ /**
20
+ * Create a reactive field state
21
+ */
22
+ function createFieldState<T = any>(
23
+ initialValue?: T
24
+ ): {
25
+ state: () => FieldState<T>
26
+ setValue: (value: T) => void
27
+ setError: (error: string | undefined) => void
28
+ setTouched: (touched: boolean) => void
29
+ setFocused: (focused: boolean) => void
30
+ setValidating: (validating: boolean) => void
31
+ } {
32
+ const [value, setValue] = createSignal<T>(initialValue as T)
33
+ const [error, setError] = createSignal<string | undefined>(undefined)
34
+ const [touched, setTouched] = createSignal(false)
35
+ const [dirty, setDirty] = createSignal(false)
36
+ const [focused, setFocused] = createSignal(false)
37
+ const [validating, setValidating] = createSignal(false)
38
+
39
+ // Mark dirty when value changes from initial
40
+ createEffect(() => {
41
+ const currentValue = value()
42
+ if (currentValue !== initialValue) {
43
+ setDirty(true)
44
+ }
45
+ })
46
+
47
+ const valid = createComputed(() => !error())
48
+
49
+ const state = createComputed(
50
+ (): FieldState<T> => ({
51
+ value: value(),
52
+ error: error(),
53
+ touched: touched(),
54
+ dirty: dirty(),
55
+ valid: valid(),
56
+ validating: validating(),
57
+ focused: focused(),
58
+ })
59
+ )
60
+
61
+ return {
62
+ state,
63
+ setValue: (newValue: T) => {
64
+ setValue(newValue)
65
+ // Mark dirty if value changed from initial
66
+ if (newValue !== initialValue) {
67
+ setDirty(true)
68
+ } else {
69
+ setDirty(false)
70
+ }
71
+ if (touched()) {
72
+ // Trigger validation if field is touched
73
+ // This will be handled by the form's validation system
74
+ }
75
+ },
76
+ setError,
77
+ setTouched,
78
+ setFocused,
79
+ setValidating,
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Create a form state manager
85
+ */
86
+ export function createFormState(
87
+ initialValues: Record<string, any> = {}
88
+ ): UseFormReturn {
89
+ const fields = new Map<string, ReturnType<typeof createFieldState>>()
90
+ const validations = new Map<string, FieldValidation>()
91
+
92
+ const [submitting, setSubmitting] = createSignal(false)
93
+ const [submitted, setSubmitted] = createSignal(false)
94
+
95
+ // Auto-register fields from initial values
96
+ Object.keys(initialValues).forEach(name => {
97
+ const fieldManager = createFieldState(initialValues[name])
98
+ fields.set(name, fieldManager)
99
+ })
100
+
101
+ // Reactive form state
102
+ const formState = createComputed((): FormState => {
103
+ const fieldStates: Record<string, FieldState> = {}
104
+ const errors: Record<string, string> = {}
105
+ const touched: Record<string, boolean> = {}
106
+ let valid = true
107
+ let dirty = false
108
+
109
+ for (const [name, fieldManager] of fields) {
110
+ const fieldState = fieldManager.state()
111
+ fieldStates[name] = fieldState
112
+
113
+ if (fieldState.error) {
114
+ errors[name] = fieldState.error
115
+ valid = false
116
+ }
117
+
118
+ if (fieldState.touched) {
119
+ touched[name] = true
120
+ }
121
+
122
+ if (fieldState.dirty) {
123
+ dirty = true
124
+ }
125
+ }
126
+
127
+ return {
128
+ fields: fieldStates,
129
+ valid,
130
+ dirty,
131
+ submitting: submitting(),
132
+ submitted: submitted(),
133
+ errors,
134
+ touched,
135
+ }
136
+ })
137
+
138
+ // Register a field
139
+ const register = (name: string, validation?: FieldValidation) => {
140
+ if (fields.has(name)) {
141
+ // Field already exists, just update validation if provided
142
+ if (validation) {
143
+ validations.set(name, validation)
144
+ }
145
+ return
146
+ }
147
+
148
+ const fieldManager = createFieldState(initialValues[name])
149
+ fields.set(name, fieldManager)
150
+
151
+ if (validation) {
152
+ validations.set(name, validation)
153
+ }
154
+
155
+ // Set up validation effects
156
+ if (validation) {
157
+ const fieldState = fieldManager.state
158
+
159
+ createEffect(async () => {
160
+ const state = fieldState()
161
+ const shouldValidate =
162
+ validation.validateOn === 'change' ||
163
+ (validation.validateOn === 'blur' && state.touched) ||
164
+ (validation.validateOn === 'submit' && submitted())
165
+
166
+ if (shouldValidate && (state.dirty || state.touched)) {
167
+ fieldManager.setValidating(true)
168
+
169
+ try {
170
+ const result = await validateFieldAsync(state, validation)
171
+ fieldManager.setError(result.valid ? undefined : result.message)
172
+ } catch (_error) {
173
+ fieldManager.setError('Validation error occurred')
174
+ } finally {
175
+ fieldManager.setValidating(false)
176
+ }
177
+ }
178
+ })
179
+ }
180
+ }
181
+
182
+ // Unregister a field
183
+ const unregister = (name: string) => {
184
+ fields.delete(name)
185
+ validations.delete(name)
186
+ }
187
+
188
+ // Set field value
189
+ const setValue = (name: string, value: any) => {
190
+ const fieldManager = fields.get(name)
191
+ if (fieldManager) {
192
+ fieldManager.setValue(value)
193
+ }
194
+ }
195
+
196
+ // Get field value
197
+ const getValue = (name: string) => {
198
+ const fieldManager = fields.get(name)
199
+ return fieldManager?.state().value
200
+ }
201
+
202
+ // Get field error
203
+ const getError = (name: string) => {
204
+ const fieldManager = fields.get(name)
205
+ return fieldManager?.state().error
206
+ }
207
+
208
+ // Validate a specific field
209
+ const validateField = async (name: string): Promise<boolean> => {
210
+ const fieldManager = fields.get(name)
211
+ const validation = validations.get(name)
212
+
213
+ if (!fieldManager || !validation) {
214
+ return true
215
+ }
216
+
217
+ const fieldState = fieldManager.state()
218
+ fieldManager.setValidating(true)
219
+
220
+ try {
221
+ const result = await validateFieldAsync(fieldState, validation)
222
+ fieldManager.setError(result.valid ? undefined : result.message)
223
+ return result.valid
224
+ } catch (_error) {
225
+ fieldManager.setError('Validation error occurred')
226
+ return false
227
+ } finally {
228
+ fieldManager.setValidating(false)
229
+ }
230
+ }
231
+
232
+ // Validate entire form
233
+ const validateForm = async (): Promise<boolean> => {
234
+ const validationPromises = Array.from(fields.keys()).map(validateField)
235
+ const results = await Promise.all(validationPromises)
236
+ return results.every(result => result)
237
+ }
238
+
239
+ // Reset form to initial state
240
+ const resetForm = () => {
241
+ for (const [name, fieldManager] of fields) {
242
+ fieldManager.setValue(initialValues[name])
243
+ fieldManager.setError(undefined)
244
+ fieldManager.setTouched(false)
245
+ fieldManager.setFocused(false)
246
+ fieldManager.setValidating(false)
247
+ }
248
+ setSubmitting(false)
249
+ setSubmitted(false)
250
+ }
251
+
252
+ // Submit form
253
+ const submitForm = async (handler?: FormSubmitHandler) => {
254
+ setSubmitting(true)
255
+ setSubmitted(true)
256
+
257
+ try {
258
+ // Validate all fields
259
+ const isValid = await validateForm()
260
+
261
+ if (isValid && handler) {
262
+ // Collect form values
263
+ const values: Record<string, any> = {}
264
+ for (const [name, fieldManager] of fields) {
265
+ values[name] = fieldManager.state().value
266
+ }
267
+
268
+ await handler(values, formState())
269
+ }
270
+ } finally {
271
+ setSubmitting(false)
272
+ }
273
+ }
274
+
275
+ // Watch for changes in specific fields
276
+ const watch = (fieldNames?: string[]): Record<string, any> => {
277
+ const values: Record<string, any> = {}
278
+ const fieldsToWatch = fieldNames || Array.from(fields.keys())
279
+
280
+ for (const name of fieldsToWatch) {
281
+ if (fields.has(name)) {
282
+ values[name] = getValue(name)
283
+ }
284
+ }
285
+
286
+ return values
287
+ }
288
+
289
+ // Trigger validation for specific fields
290
+ const trigger = async (fieldNames?: string[]): Promise<boolean> => {
291
+ const fieldsToValidate = fieldNames || Array.from(fields.keys())
292
+ const validationPromises = fieldsToValidate.map(validateField)
293
+ const results = await Promise.all(validationPromises)
294
+ return results.every(result => result)
295
+ }
296
+
297
+ return {
298
+ fields: formState().fields,
299
+ state: formState(),
300
+ register,
301
+ unregister,
302
+ setValue,
303
+ getValue,
304
+ getError,
305
+ validateField,
306
+ validateForm,
307
+ resetForm,
308
+ submitForm,
309
+ watch,
310
+ trigger,
311
+ }
312
+ }
313
+
314
+ /**
315
+ * Async field validation helper
316
+ */
317
+ async function validateFieldAsync(
318
+ fieldState: FieldState,
319
+ validation: FieldValidation
320
+ ): Promise<ValidationResult> {
321
+ if (!validation.rules || validation.rules.length === 0) {
322
+ return { valid: true }
323
+ }
324
+
325
+ // Use debounced validation if specified
326
+ if (validation.debounceMs) {
327
+ return new Promise(resolve => {
328
+ setTimeout(async () => {
329
+ const result = await validateValueAsync(
330
+ fieldState.value,
331
+ validation.rules!
332
+ )
333
+ resolve(result)
334
+ }, validation.debounceMs)
335
+
336
+ // Store timeout ID for potential cleanup
337
+ // In a real implementation, you'd want to manage this better
338
+ })
339
+ }
340
+
341
+ return validateValueAsync(fieldState.value, validation.rules)
342
+ }
343
+
344
+ /**
345
+ * Form field hook for individual field management
346
+ */
347
+ export function createField<T = any>(
348
+ _name: string,
349
+ initialValue?: T,
350
+ validation?: FieldValidation
351
+ ): {
352
+ value: () => T
353
+ setValue: (value: T) => void
354
+ error: () => string | undefined
355
+ touched: () => boolean
356
+ dirty: () => boolean
357
+ valid: () => boolean
358
+ validating: () => boolean
359
+ focused: () => boolean
360
+ onFocus: () => void
361
+ onBlur: () => void
362
+ validate: () => Promise<boolean>
363
+ reset: () => void
364
+ } {
365
+ const fieldManager = createFieldState(initialValue)
366
+ const fieldState = fieldManager.state
367
+
368
+ // Validation effect
369
+ if (validation) {
370
+ createEffect(async () => {
371
+ const state = fieldState()
372
+ const shouldValidate =
373
+ validation.validateOn === 'change' ||
374
+ (validation.validateOn === 'blur' && state.touched)
375
+
376
+ if (shouldValidate && (state.dirty || state.touched)) {
377
+ fieldManager.setValidating(true)
378
+
379
+ try {
380
+ const result = await validateFieldAsync(state, validation)
381
+ fieldManager.setError(result.valid ? undefined : result.message)
382
+ } catch (_error) {
383
+ fieldManager.setError('Validation error occurred')
384
+ } finally {
385
+ fieldManager.setValidating(false)
386
+ }
387
+ }
388
+ })
389
+ }
390
+
391
+ const validate = async (): Promise<boolean> => {
392
+ if (!validation) return true
393
+
394
+ fieldManager.setValidating(true)
395
+ try {
396
+ const result = await validateFieldAsync(fieldState(), validation)
397
+ fieldManager.setError(result.valid ? undefined : result.message)
398
+ return result.valid
399
+ } catch (_error) {
400
+ fieldManager.setError('Validation error occurred')
401
+ return false
402
+ } finally {
403
+ fieldManager.setValidating(false)
404
+ }
405
+ }
406
+
407
+ const reset = () => {
408
+ fieldManager.setValue(initialValue as T)
409
+ fieldManager.setError(undefined)
410
+ fieldManager.setTouched(false)
411
+ fieldManager.setFocused(false)
412
+ fieldManager.setValidating(false)
413
+ }
414
+
415
+ return {
416
+ value: () => fieldState().value,
417
+ setValue: fieldManager.setValue,
418
+ error: () => fieldState().error,
419
+ touched: () => fieldState().touched,
420
+ dirty: () => fieldState().dirty,
421
+ valid: () => fieldState().valid,
422
+ validating: () => fieldState().validating,
423
+ focused: () => fieldState().focused,
424
+ onFocus: () => {
425
+ fieldManager.setFocused(true)
426
+ },
427
+ onBlur: () => {
428
+ fieldManager.setFocused(false)
429
+ fieldManager.setTouched(true)
430
+ },
431
+ validate,
432
+ reset,
433
+ }
434
+ }
435
+
436
+ /**
437
+ * Multi-step form state manager
438
+ */
439
+ export function createMultiStepFormState(
440
+ steps: string[],
441
+ initialValues: Record<string, any> = {}
442
+ ) {
443
+ const [currentStep, setCurrentStep] = createSignal(0)
444
+ const [completedSteps, setCompletedSteps] = createSignal<Set<number>>(
445
+ new Set()
446
+ )
447
+ const stepForms = new Map<number, UseFormReturn>()
448
+
449
+ // Create form state for each step
450
+ steps.forEach((_, index) => {
451
+ const stepValues = Object.keys(initialValues)
452
+ .filter(key => key.startsWith(`step_${index}_`))
453
+ .reduce(
454
+ (acc, key) => {
455
+ const fieldName = key.replace(`step_${index}_`, '')
456
+ acc[fieldName] = initialValues[key]
457
+ return acc
458
+ },
459
+ {} as Record<string, any>
460
+ )
461
+
462
+ stepForms.set(index, createFormState(stepValues))
463
+ })
464
+
465
+ const nextStep = async (validateCurrent = true): Promise<boolean> => {
466
+ const current = currentStep()
467
+ const currentForm = stepForms.get(current)
468
+
469
+ if (validateCurrent && currentForm) {
470
+ const isValid = await currentForm.validateForm()
471
+ if (!isValid) {
472
+ return false
473
+ }
474
+ }
475
+
476
+ if (current < steps.length - 1) {
477
+ setCompletedSteps(prev => new Set([...prev, current]))
478
+ setCurrentStep(current + 1)
479
+ return true
480
+ }
481
+
482
+ return false
483
+ }
484
+
485
+ const previousStep = (): boolean => {
486
+ const current = currentStep()
487
+ if (current > 0) {
488
+ setCurrentStep(current - 1)
489
+ return true
490
+ }
491
+ return false
492
+ }
493
+
494
+ const goToStep = (stepIndex: number): boolean => {
495
+ if (stepIndex >= 0 && stepIndex < steps.length) {
496
+ setCurrentStep(stepIndex)
497
+ return true
498
+ }
499
+ return false
500
+ }
501
+
502
+ const getCurrentForm = (): UseFormReturn | undefined => {
503
+ return stepForms.get(currentStep())
504
+ }
505
+
506
+ const getAllValues = (): Record<string, any> => {
507
+ const allValues: Record<string, any> = {}
508
+
509
+ stepForms.forEach((form, stepIndex) => {
510
+ const stepValues = form.watch()
511
+ Object.keys(stepValues).forEach(fieldName => {
512
+ allValues[`step_${stepIndex}_${fieldName}`] = stepValues[fieldName]
513
+ })
514
+ })
515
+
516
+ return allValues
517
+ }
518
+
519
+ const validateAllSteps = async (): Promise<boolean> => {
520
+ const validationPromises = Array.from(stepForms.values()).map(form =>
521
+ form.validateForm()
522
+ )
523
+ const results = await Promise.all(validationPromises)
524
+ return results.every(result => result)
525
+ }
526
+
527
+ return {
528
+ currentStep,
529
+ completedSteps,
530
+ nextStep,
531
+ previousStep,
532
+ goToStep,
533
+ getCurrentForm,
534
+ getAllValues,
535
+ validateAllSteps,
536
+ getStepForm: (stepIndex: number) => stepForms.get(stepIndex),
537
+ isStepCompleted: (stepIndex: number) => completedSteps().has(stepIndex),
538
+ canGoToStep: (stepIndex: number) =>
539
+ stepIndex <= currentStep() || completedSteps().has(stepIndex),
540
+ }
541
+ }
542
+
543
+ // Export validation function for internal use
544
+ export { validateValueAsync } from '../validation'