@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.
- package/README.md +87 -272
- package/dist/DatePicker-D5nRFTUm.js +475 -0
- package/dist/DatePicker-D5nRFTUm.js.map +1 -0
- package/dist/Select-yZyKooXk.js +945 -0
- package/dist/Select-yZyKooXk.js.map +1 -0
- package/dist/Slider-0-oal5YR.js +644 -0
- package/dist/Slider-0-oal5YR.js.map +1 -0
- package/dist/TextField-hX15dY3U.js +509 -0
- package/dist/TextField-hX15dY3U.js.map +1 -0
- package/dist/components/advanced/Slider.d.ts +190 -0
- package/dist/components/advanced/Slider.d.ts.map +1 -0
- package/dist/components/advanced/Stepper.d.ts +161 -0
- package/dist/components/advanced/Stepper.d.ts.map +1 -0
- package/dist/components/advanced/index.d.ts +15 -0
- package/dist/components/advanced/index.d.ts.map +1 -0
- package/dist/components/advanced/index.js +6 -0
- package/dist/components/advanced/index.js.map +1 -0
- package/dist/components/date-picker/DatePicker.d.ts +126 -0
- package/dist/components/date-picker/DatePicker.d.ts.map +1 -0
- package/dist/components/date-picker/index.d.ts +14 -0
- package/dist/components/date-picker/index.d.ts.map +1 -0
- package/dist/components/date-picker/index.js +5 -0
- package/dist/components/date-picker/index.js.map +1 -0
- package/dist/components/form-container/index.d.ts +58 -0
- package/dist/components/form-container/index.d.ts.map +1 -0
- package/dist/components/selection/Checkbox.d.ts.map +1 -0
- package/dist/components/selection/Radio.d.ts.map +1 -0
- package/dist/components/selection/Select.d.ts.map +1 -0
- package/dist/components/selection/index.d.ts +68 -0
- package/dist/components/selection/index.d.ts.map +1 -0
- package/dist/components/selection/index.js +12 -0
- package/dist/components/selection/index.js.map +1 -0
- package/dist/components/text-input/TextField.d.ts.map +1 -0
- package/dist/components/text-input/index.d.ts +8 -0
- package/dist/components/text-input/index.d.ts.map +1 -0
- package/dist/components/text-input/index.js +18 -0
- package/dist/components/text-input/index.js.map +1 -0
- package/dist/{state/index.js → index-D3WfkqVv.js} +15 -8
- package/dist/index-D3WfkqVv.js.map +1 -0
- package/dist/index.d.ts +10 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +198 -376
- package/dist/index.js.map +1 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/index.d.ts +19 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/validation/component-validation.d.ts +11 -2
- package/dist/validation/component-validation.d.ts.map +1 -1
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +282 -191
- package/dist/validation/index.js.map +1 -0
- package/package.json +53 -39
- package/src/components/advanced/Slider.ts +722 -0
- package/src/components/advanced/Stepper.ts +715 -0
- package/src/components/advanced/index.ts +20 -0
- package/src/components/date-picker/DatePicker.ts +925 -0
- package/src/components/date-picker/index.ts +20 -0
- package/src/components/form-container/index.ts +266 -0
- package/src/components/selection/Checkbox.ts +478 -0
- package/src/components/selection/Radio.ts +470 -0
- package/src/components/selection/Select.ts +620 -0
- package/src/components/selection/index.ts +81 -0
- package/src/components/text-input/TextField.ts +728 -0
- package/src/components/text-input/index.ts +35 -0
- package/src/index.ts +48 -0
- package/src/state/index.ts +544 -0
- package/src/types/index.ts +579 -0
- package/src/utils/formatters.ts +184 -0
- package/src/utils/index.ts +57 -0
- package/src/validation/component-validation.ts +429 -0
- package/src/validation/index.ts +641 -0
- package/dist/TextField-CGBM3x7K.js +0 -1799
- package/dist/components/Form.d.ts +0 -76
- package/dist/components/Form.d.ts.map +0 -1
- package/dist/components/index.d.ts +0 -9
- package/dist/components/index.d.ts.map +0 -1
- package/dist/components/index.js +0 -28
- package/dist/components/input/Checkbox.d.ts.map +0 -1
- package/dist/components/input/Radio.d.ts.map +0 -1
- package/dist/components/input/Select.d.ts.map +0 -1
- package/dist/components/input/TextField.d.ts.map +0 -1
- package/dist/components/input/index.d.ts +0 -11
- package/dist/components/input/index.d.ts.map +0 -1
- package/dist/utils/validators.d.ts +0 -101
- package/dist/utils/validators.d.ts.map +0 -1
- /package/dist/components/{input → selection}/Checkbox.d.ts +0 -0
- /package/dist/components/{input → selection}/Radio.d.ts +0 -0
- /package/dist/components/{input → selection}/Select.d.ts +0 -0
- /package/dist/components/{input → text-input}/TextField.d.ts +0 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TextField Formatters
|
|
3
|
+
*
|
|
4
|
+
* Pre-built formatting functions for common input types.
|
|
5
|
+
* Migrated from core TextField to forms plugin.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { TextFieldFormatter } from '../types'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Common text formatters
|
|
12
|
+
*/
|
|
13
|
+
export const TextFieldFormatters = {
|
|
14
|
+
/**
|
|
15
|
+
* Phone number formatter (US format)
|
|
16
|
+
*/
|
|
17
|
+
phone: (value: string): string => {
|
|
18
|
+
const digits = value.replace(/\D/g, '')
|
|
19
|
+
if (digits.length <= 3) {
|
|
20
|
+
return digits
|
|
21
|
+
} else if (digits.length <= 6) {
|
|
22
|
+
return `(${digits.slice(0, 3)}) ${digits.slice(3)}`
|
|
23
|
+
} else {
|
|
24
|
+
return `(${digits.slice(0, 3)}) ${digits.slice(3, 6)}-${digits.slice(6, 10)}`
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Credit card formatter
|
|
30
|
+
*/
|
|
31
|
+
creditCard: (value: string): string => {
|
|
32
|
+
const digits = value.replace(/\D/g, '')
|
|
33
|
+
return digits.replace(/(\d{4})(?=\d)/g, '$1 ')
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Currency formatter
|
|
38
|
+
*/
|
|
39
|
+
currency: (value: string): string => {
|
|
40
|
+
const number = parseFloat(value.replace(/[^\d.]/g, ''))
|
|
41
|
+
if (Number.isNaN(number)) return ''
|
|
42
|
+
return new Intl.NumberFormat('en-US', {
|
|
43
|
+
style: 'currency',
|
|
44
|
+
currency: 'USD',
|
|
45
|
+
}).format(number)
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Uppercase formatter
|
|
50
|
+
*/
|
|
51
|
+
uppercase: (value: string): string => value.toUpperCase(),
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Lowercase formatter
|
|
55
|
+
*/
|
|
56
|
+
lowercase: (value: string): string => value.toLowerCase(),
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Title case formatter
|
|
60
|
+
*/
|
|
61
|
+
titleCase: (value: string): string => {
|
|
62
|
+
return value.replace(
|
|
63
|
+
/\w\S*/g,
|
|
64
|
+
txt => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
|
|
65
|
+
)
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Social Security Number formatter
|
|
70
|
+
*/
|
|
71
|
+
ssn: (value: string): string => {
|
|
72
|
+
const digits = value.replace(/\D/g, '')
|
|
73
|
+
if (digits.length <= 3) {
|
|
74
|
+
return digits
|
|
75
|
+
} else if (digits.length <= 5) {
|
|
76
|
+
return `${digits.slice(0, 3)}-${digits.slice(3)}`
|
|
77
|
+
} else {
|
|
78
|
+
return `${digits.slice(0, 3)}-${digits.slice(3, 5)}-${digits.slice(5, 9)}`
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Postal code formatter (US ZIP)
|
|
84
|
+
*/
|
|
85
|
+
postalCode: (value: string): string => {
|
|
86
|
+
const digits = value.replace(/\D/g, '')
|
|
87
|
+
if (digits.length <= 5) {
|
|
88
|
+
return digits
|
|
89
|
+
} else {
|
|
90
|
+
return `${digits.slice(0, 5)}-${digits.slice(5, 9)}`
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Decimal number formatter
|
|
96
|
+
*/
|
|
97
|
+
decimal:
|
|
98
|
+
(places: number = 2) =>
|
|
99
|
+
(value: string): string => {
|
|
100
|
+
const number = parseFloat(value.replace(/[^\d.-]/g, ''))
|
|
101
|
+
if (Number.isNaN(number)) return ''
|
|
102
|
+
return number.toFixed(places)
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Percentage formatter
|
|
107
|
+
*/
|
|
108
|
+
percentage: (value: string): string => {
|
|
109
|
+
const number = parseFloat(value.replace(/[^\d.-]/g, ''))
|
|
110
|
+
if (Number.isNaN(number)) return ''
|
|
111
|
+
return `${number}%`
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Custom formatter factory
|
|
116
|
+
*/
|
|
117
|
+
custom: (formatFn: (value: string) => string): TextFieldFormatter => formatFn,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Common text parsers (reverse of formatters)
|
|
122
|
+
*/
|
|
123
|
+
export const TextFieldParsers = {
|
|
124
|
+
/**
|
|
125
|
+
* Phone number parser - extracts digits only
|
|
126
|
+
*/
|
|
127
|
+
phone: (value: string): string => {
|
|
128
|
+
return value.replace(/\D/g, '')
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Credit card parser - extracts digits only
|
|
133
|
+
*/
|
|
134
|
+
creditCard: (value: string): string => {
|
|
135
|
+
return value.replace(/\D/g, '')
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Currency parser - extracts numeric value
|
|
140
|
+
*/
|
|
141
|
+
currency: (value: string): string => {
|
|
142
|
+
const matches = value.match(/[\d.-]+/)
|
|
143
|
+
return matches ? matches[0] : ''
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* SSN parser - extracts digits only
|
|
148
|
+
*/
|
|
149
|
+
ssn: (value: string): string => {
|
|
150
|
+
return value.replace(/\D/g, '')
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Postal code parser - extracts digits only
|
|
155
|
+
*/
|
|
156
|
+
postalCode: (value: string): string => {
|
|
157
|
+
return value.replace(/\D/g, '')
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Decimal parser - extracts number
|
|
162
|
+
*/
|
|
163
|
+
decimal: (value: string): string => {
|
|
164
|
+
const matches = value.match(/^-?\d*\.?\d*/)
|
|
165
|
+
return matches ? matches[0] : ''
|
|
166
|
+
},
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Percentage parser - extracts number without %
|
|
170
|
+
*/
|
|
171
|
+
percentage: (value: string): string => {
|
|
172
|
+
return value.replace(/[^\d.-]/g, '')
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* No-op parser (returns value unchanged)
|
|
177
|
+
*/
|
|
178
|
+
none: (value: string): string => value,
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Custom parser factory
|
|
182
|
+
*/
|
|
183
|
+
custom: (parseFn: (value: string) => string) => parseFn,
|
|
184
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form Utilities
|
|
3
|
+
*
|
|
4
|
+
* Shared utilities for form handling, formatting, and validation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// TODO: Migrate actual utilities from @tachui/forms
|
|
8
|
+
// Placeholder implementation for unified package structure
|
|
9
|
+
|
|
10
|
+
// Form state utilities (stubs)
|
|
11
|
+
export function useFormState() {
|
|
12
|
+
return {
|
|
13
|
+
/* TODO: Implement form state hook */
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function useFormValidation() {
|
|
18
|
+
return {
|
|
19
|
+
/* TODO: Implement form validation hook */
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Formatting utilities (stubs)
|
|
24
|
+
export function formatCreditCard(value: string): string {
|
|
25
|
+
return value.replace(/\D/g, '').replace(/(\d{4})(?=\d)/g, '$1 ')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function formatPhoneNumber(value: string): string {
|
|
29
|
+
return value.replace(/\D/g, '').replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function formatSSN(value: string): string {
|
|
33
|
+
return value.replace(/\D/g, '').replace(/(\d{3})(\d{2})(\d{4})/, '$1-$2-$3')
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function formatPostalCode(value: string): string {
|
|
37
|
+
return value.toUpperCase().replace(/[^A-Z0-9]/g, '')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Date utilities (stubs)
|
|
41
|
+
export function formatDate(date: Date, _format: string = 'yyyy-MM-dd'): string {
|
|
42
|
+
return date.toISOString().split('T')[0]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function parseDate(value: string): Date {
|
|
46
|
+
return new Date(value)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function isValidDate(date: Date): boolean {
|
|
50
|
+
return date instanceof Date && !isNaN(date.getTime())
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Type aliases
|
|
54
|
+
export type FormStateManager = any
|
|
55
|
+
export type FormatterFunction = (value: string) => string
|
|
56
|
+
export type DateFormat = string
|
|
57
|
+
export type FormUtilOptions = any
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forms Package Component Validation
|
|
3
|
+
*
|
|
4
|
+
* Validation for @tachui/advanced-forms components that registers with the Core
|
|
5
|
+
* validation system, following proper plugin architecture.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Import from core to register with the validation system
|
|
9
|
+
// ComponentValidator type is defined locally since it's not exported from core
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Component validator interface (matches core's internal interface)
|
|
13
|
+
*/
|
|
14
|
+
interface ComponentValidator {
|
|
15
|
+
packageName: string
|
|
16
|
+
componentName: string
|
|
17
|
+
validate: (args: unknown[]) => void
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* TachUI Forms validation error class
|
|
22
|
+
*/
|
|
23
|
+
export class FormsValidationError extends Error {
|
|
24
|
+
constructor(
|
|
25
|
+
message: string,
|
|
26
|
+
public context: {
|
|
27
|
+
component: string
|
|
28
|
+
property?: string
|
|
29
|
+
suggestion?: string
|
|
30
|
+
documentation?: string
|
|
31
|
+
example?: {
|
|
32
|
+
wrong: string
|
|
33
|
+
correct: string
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
) {
|
|
37
|
+
super(message)
|
|
38
|
+
this.name = 'FormsValidationError'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getFormattedMessage(): string {
|
|
42
|
+
const { component, suggestion, example, documentation } = this.context
|
|
43
|
+
|
|
44
|
+
let formatted = `❌ [@tachui/advanced-forms] ${component} Component Error: ${this.message}\n`
|
|
45
|
+
|
|
46
|
+
if (suggestion) {
|
|
47
|
+
formatted += `\n💡 Suggestion: ${suggestion}\n`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (example) {
|
|
51
|
+
formatted += `\n❌ Wrong: ${example.wrong}`
|
|
52
|
+
formatted += `\n✅ Correct: ${example.correct}\n`
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (documentation) {
|
|
56
|
+
formatted += `\n📚 Documentation: ${documentation}`
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return formatted
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Forms Components Validation
|
|
65
|
+
*/
|
|
66
|
+
export const FormsComponentValidation = {
|
|
67
|
+
// TextField Component
|
|
68
|
+
validateTextField(args: unknown[]): void {
|
|
69
|
+
if (args.length === 0) {
|
|
70
|
+
throw new FormsValidationError(
|
|
71
|
+
'TextField component requires a props object with name',
|
|
72
|
+
{
|
|
73
|
+
component: 'TextField',
|
|
74
|
+
suggestion: 'Add name property: TextField({ name: "fieldName" })',
|
|
75
|
+
documentation:
|
|
76
|
+
'https://docs.tachui.dev/advanced-forms/components/textfield',
|
|
77
|
+
example: {
|
|
78
|
+
wrong: 'TextField()',
|
|
79
|
+
correct: 'TextField({ name: "email", value: emailSignal })',
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const [props] = args
|
|
86
|
+
if (!props || typeof props !== 'object') {
|
|
87
|
+
throw new FormsValidationError('TextField requires a props object', {
|
|
88
|
+
component: 'TextField',
|
|
89
|
+
suggestion: 'Pass a props object with name property',
|
|
90
|
+
example: {
|
|
91
|
+
wrong: 'TextField("email")',
|
|
92
|
+
correct: 'TextField({ name: "email" })',
|
|
93
|
+
},
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const propsObj = props as any
|
|
98
|
+
if (!propsObj.name || typeof propsObj.name !== 'string') {
|
|
99
|
+
throw new FormsValidationError(
|
|
100
|
+
'TextField name property is required and must be a string',
|
|
101
|
+
{
|
|
102
|
+
component: 'TextField',
|
|
103
|
+
suggestion: 'Provide a unique name for the field',
|
|
104
|
+
example: {
|
|
105
|
+
wrong: 'TextField({ placeholder: "Email" })',
|
|
106
|
+
correct: 'TextField({ name: "email", placeholder: "Email" })',
|
|
107
|
+
},
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
// EmailField Component
|
|
114
|
+
validateEmailField(args: unknown[]): void {
|
|
115
|
+
if (args.length === 0) {
|
|
116
|
+
throw new FormsValidationError(
|
|
117
|
+
'EmailField component requires a props object with name',
|
|
118
|
+
{
|
|
119
|
+
component: 'EmailField',
|
|
120
|
+
suggestion: 'Add name property: EmailField({ name: "email" })',
|
|
121
|
+
documentation:
|
|
122
|
+
'https://docs.tachui.dev/advanced-forms/components/emailfield',
|
|
123
|
+
example: {
|
|
124
|
+
wrong: 'EmailField()',
|
|
125
|
+
correct: 'EmailField({ name: "email", value: emailSignal })',
|
|
126
|
+
},
|
|
127
|
+
}
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const [props] = args
|
|
132
|
+
if (!props || typeof props !== 'object') {
|
|
133
|
+
throw new FormsValidationError('EmailField requires a props object', {
|
|
134
|
+
component: 'EmailField',
|
|
135
|
+
suggestion: 'Pass a props object with name property',
|
|
136
|
+
example: {
|
|
137
|
+
wrong: 'EmailField("email@example.com")',
|
|
138
|
+
correct: 'EmailField({ name: "email", value: "email@example.com" })',
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const propsObj = props as any
|
|
144
|
+
if (!propsObj.name || typeof propsObj.name !== 'string') {
|
|
145
|
+
throw new FormsValidationError(
|
|
146
|
+
'EmailField name property is required and must be a string',
|
|
147
|
+
{
|
|
148
|
+
component: 'EmailField',
|
|
149
|
+
suggestion: 'Provide a unique name for the email field',
|
|
150
|
+
example: {
|
|
151
|
+
wrong: 'EmailField({ placeholder: "Email" })',
|
|
152
|
+
correct: 'EmailField({ name: "email", placeholder: "Email" })',
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
// PasswordField Component
|
|
160
|
+
validatePasswordField(args: unknown[]): void {
|
|
161
|
+
if (args.length === 0) {
|
|
162
|
+
throw new FormsValidationError(
|
|
163
|
+
'PasswordField component requires a props object with name',
|
|
164
|
+
{
|
|
165
|
+
component: 'PasswordField',
|
|
166
|
+
suggestion: 'Add name property: PasswordField({ name: "password" })',
|
|
167
|
+
documentation:
|
|
168
|
+
'https://docs.tachui.dev/advanced-forms/components/passwordfield',
|
|
169
|
+
example: {
|
|
170
|
+
wrong: 'PasswordField()',
|
|
171
|
+
correct:
|
|
172
|
+
'PasswordField({ name: "password", value: passwordSignal })',
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const [props] = args
|
|
179
|
+
if (!props || typeof props !== 'object') {
|
|
180
|
+
throw new FormsValidationError('PasswordField requires a props object', {
|
|
181
|
+
component: 'PasswordField',
|
|
182
|
+
suggestion: 'Pass a props object with name property',
|
|
183
|
+
example: {
|
|
184
|
+
wrong: 'PasswordField("password")',
|
|
185
|
+
correct: 'PasswordField({ name: "password", value: passwordSignal })',
|
|
186
|
+
},
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const propsObj = props as any
|
|
191
|
+
if (!propsObj.name || typeof propsObj.name !== 'string') {
|
|
192
|
+
throw new FormsValidationError(
|
|
193
|
+
'PasswordField name property is required and must be a string',
|
|
194
|
+
{
|
|
195
|
+
component: 'PasswordField',
|
|
196
|
+
suggestion: 'Provide a unique name for the password field',
|
|
197
|
+
example: {
|
|
198
|
+
wrong: 'PasswordField({ placeholder: "Password" })',
|
|
199
|
+
correct:
|
|
200
|
+
'PasswordField({ name: "password", placeholder: "Password" })',
|
|
201
|
+
},
|
|
202
|
+
}
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
// PhoneField Component
|
|
208
|
+
validatePhoneField(args: unknown[]): void {
|
|
209
|
+
if (args.length === 0) {
|
|
210
|
+
throw new FormsValidationError(
|
|
211
|
+
'PhoneField component requires a props object with name',
|
|
212
|
+
{
|
|
213
|
+
component: 'PhoneField',
|
|
214
|
+
suggestion: 'Add name property: PhoneField({ name: "phone" })',
|
|
215
|
+
documentation:
|
|
216
|
+
'https://docs.tachui.dev/advanced-forms/components/phonefield',
|
|
217
|
+
example: {
|
|
218
|
+
wrong: 'PhoneField()',
|
|
219
|
+
correct: 'PhoneField({ name: "phone", format: "US" })',
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const [props] = args
|
|
226
|
+
if (!props || typeof props !== 'object') {
|
|
227
|
+
throw new FormsValidationError('PhoneField requires a props object', {
|
|
228
|
+
component: 'PhoneField',
|
|
229
|
+
suggestion: 'Pass a props object with name property',
|
|
230
|
+
example: {
|
|
231
|
+
wrong: 'PhoneField("(555) 123-4567")',
|
|
232
|
+
correct: 'PhoneField({ name: "phone", value: phoneSignal })',
|
|
233
|
+
},
|
|
234
|
+
})
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const propsObj = props as any
|
|
238
|
+
if (!propsObj.name || typeof propsObj.name !== 'string') {
|
|
239
|
+
throw new FormsValidationError(
|
|
240
|
+
'PhoneField name property is required and must be a string',
|
|
241
|
+
{
|
|
242
|
+
component: 'PhoneField',
|
|
243
|
+
suggestion: 'Provide a unique name for the phone field',
|
|
244
|
+
example: {
|
|
245
|
+
wrong: 'PhoneField({ format: "US" })',
|
|
246
|
+
correct: 'PhoneField({ name: "phone", format: "US" })',
|
|
247
|
+
},
|
|
248
|
+
}
|
|
249
|
+
)
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
// NumberField Component
|
|
254
|
+
validateNumberField(args: unknown[]): void {
|
|
255
|
+
if (args.length === 0) {
|
|
256
|
+
throw new FormsValidationError(
|
|
257
|
+
'NumberField component requires a props object with name',
|
|
258
|
+
{
|
|
259
|
+
component: 'NumberField',
|
|
260
|
+
suggestion: 'Add name property: NumberField({ name: "amount" })',
|
|
261
|
+
documentation:
|
|
262
|
+
'https://docs.tachui.dev/advanced-forms/components/numberfield',
|
|
263
|
+
example: {
|
|
264
|
+
wrong: 'NumberField()',
|
|
265
|
+
correct: 'NumberField({ name: "amount", min: 0, max: 100 })',
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const [props] = args
|
|
272
|
+
if (!props || typeof props !== 'object') {
|
|
273
|
+
throw new FormsValidationError('NumberField requires a props object', {
|
|
274
|
+
component: 'NumberField',
|
|
275
|
+
suggestion: 'Pass a props object with name property',
|
|
276
|
+
example: {
|
|
277
|
+
wrong: 'NumberField(42)',
|
|
278
|
+
correct: 'NumberField({ name: "amount", value: 42 })',
|
|
279
|
+
},
|
|
280
|
+
})
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const propsObj = props as any
|
|
284
|
+
if (!propsObj.name || typeof propsObj.name !== 'string') {
|
|
285
|
+
throw new FormsValidationError(
|
|
286
|
+
'NumberField name property is required and must be a string',
|
|
287
|
+
{
|
|
288
|
+
component: 'NumberField',
|
|
289
|
+
suggestion: 'Provide a unique name for the number field',
|
|
290
|
+
example: {
|
|
291
|
+
wrong: 'NumberField({ min: 0, max: 100 })',
|
|
292
|
+
correct: 'NumberField({ name: "amount", min: 0, max: 100 })',
|
|
293
|
+
},
|
|
294
|
+
}
|
|
295
|
+
)
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
// CreditCardField Component
|
|
300
|
+
validateCreditCardField(args: unknown[]): void {
|
|
301
|
+
if (args.length === 0) {
|
|
302
|
+
throw new FormsValidationError(
|
|
303
|
+
'CreditCardField component requires a props object with name',
|
|
304
|
+
{
|
|
305
|
+
component: 'CreditCardField',
|
|
306
|
+
suggestion:
|
|
307
|
+
'Add name property: CreditCardField({ name: "cardNumber" })',
|
|
308
|
+
documentation:
|
|
309
|
+
'https://docs.tachui.dev/advanced-forms/components/creditcardfield',
|
|
310
|
+
example: {
|
|
311
|
+
wrong: 'CreditCardField()',
|
|
312
|
+
correct:
|
|
313
|
+
'CreditCardField({ name: "cardNumber", onChange: handleChange })',
|
|
314
|
+
},
|
|
315
|
+
}
|
|
316
|
+
)
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const [props] = args
|
|
320
|
+
if (!props || typeof props !== 'object') {
|
|
321
|
+
throw new FormsValidationError(
|
|
322
|
+
'CreditCardField requires a props object',
|
|
323
|
+
{
|
|
324
|
+
component: 'CreditCardField',
|
|
325
|
+
suggestion: 'Pass a props object with name property',
|
|
326
|
+
example: {
|
|
327
|
+
wrong: 'CreditCardField("4111111111111111")',
|
|
328
|
+
correct:
|
|
329
|
+
'CreditCardField({ name: "cardNumber", value: cardSignal })',
|
|
330
|
+
},
|
|
331
|
+
}
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const propsObj = props as any
|
|
336
|
+
if (!propsObj.name || typeof propsObj.name !== 'string') {
|
|
337
|
+
throw new FormsValidationError(
|
|
338
|
+
'CreditCardField name property is required and must be a string',
|
|
339
|
+
{
|
|
340
|
+
component: 'CreditCardField',
|
|
341
|
+
suggestion: 'Provide a unique name for the credit card field',
|
|
342
|
+
example: {
|
|
343
|
+
wrong: 'CreditCardField({ placeholder: "Card Number" })',
|
|
344
|
+
correct:
|
|
345
|
+
'CreditCardField({ name: "cardNumber", placeholder: "Card Number" })',
|
|
346
|
+
},
|
|
347
|
+
}
|
|
348
|
+
)
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
// Additional Forms components would go here...
|
|
353
|
+
// (SearchField, URLField, TextArea, ColorField, etc.)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Create Forms component validators for registration
|
|
358
|
+
*/
|
|
359
|
+
export function createFormsValidators(): ComponentValidator[] {
|
|
360
|
+
return [
|
|
361
|
+
{
|
|
362
|
+
packageName: 'advanced-forms',
|
|
363
|
+
componentName: 'TextField',
|
|
364
|
+
validate: FormsComponentValidation.validateTextField,
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
packageName: 'advanced-forms',
|
|
368
|
+
componentName: 'EmailField',
|
|
369
|
+
validate: FormsComponentValidation.validateEmailField,
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
packageName: 'advanced-forms',
|
|
373
|
+
componentName: 'PasswordField',
|
|
374
|
+
validate: FormsComponentValidation.validatePasswordField,
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
packageName: 'advanced-forms',
|
|
378
|
+
componentName: 'PhoneField',
|
|
379
|
+
validate: FormsComponentValidation.validatePhoneField,
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
packageName: 'advanced-forms',
|
|
383
|
+
componentName: 'NumberField',
|
|
384
|
+
validate: FormsComponentValidation.validateNumberField,
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
packageName: 'advanced-forms',
|
|
388
|
+
componentName: 'CreditCardField',
|
|
389
|
+
validate: FormsComponentValidation.validateCreditCardField,
|
|
390
|
+
},
|
|
391
|
+
// Additional validators would be added here for remaining Forms components
|
|
392
|
+
]
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Register Forms validators with Core validation system
|
|
397
|
+
*/
|
|
398
|
+
export async function registerFormsValidators(): Promise<void> {
|
|
399
|
+
try {
|
|
400
|
+
// Dynamic import to avoid circular dependency
|
|
401
|
+
const { registerComponentValidator } = await import(
|
|
402
|
+
'@tachui/core/validation'
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
const validators = createFormsValidators()
|
|
406
|
+
|
|
407
|
+
for (const validator of validators) {
|
|
408
|
+
registerComponentValidator(validator)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
412
|
+
console.info(
|
|
413
|
+
`🔍 [@tachui/advanced-forms] Registered ${validators.length} component validators`
|
|
414
|
+
)
|
|
415
|
+
}
|
|
416
|
+
} catch (error) {
|
|
417
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
418
|
+
console.warn(
|
|
419
|
+
'⚠️ [@tachui/advanced-forms] Could not register validators with Core:',
|
|
420
|
+
error
|
|
421
|
+
)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Auto-register when Forms package loads
|
|
427
|
+
if (typeof window !== 'undefined' && process.env.NODE_ENV !== 'production') {
|
|
428
|
+
setTimeout(registerFormsValidators, 10)
|
|
429
|
+
}
|