@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.1.3 → 0.1.5
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/CHANGELOG.md +1 -1
- package/dist/index.d.ts +131 -131
- package/dist/index.esm.js +148 -148
- package/dist/index.js +148 -148
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/components/ui/accessibility-demo.tsx +271 -0
- package/src/components/ui/advanced-component-architecture-demo.tsx +916 -0
- package/src/components/ui/advanced-transition-system-demo.tsx +670 -0
- package/src/components/ui/advanced-transition-system.tsx +395 -0
- package/src/components/ui/animation/animated-container.tsx +166 -0
- package/src/components/ui/animation/index.ts +19 -0
- package/src/components/ui/animation/staggered-container.tsx +68 -0
- package/src/components/ui/animation-demo.tsx +250 -0
- package/src/components/ui/badge.tsx +33 -0
- package/src/components/ui/battery-conscious-animation-demo.tsx +568 -0
- package/src/components/ui/border-radius-shadow-demo.tsx +187 -0
- package/src/components/ui/button.tsx +36 -0
- package/src/components/ui/card.tsx +207 -0
- package/src/components/ui/checkbox.tsx +30 -0
- package/src/components/ui/color-preview.tsx +411 -0
- package/src/components/ui/data-display/chart.tsx +653 -0
- package/src/components/ui/data-display/data-grid-simple.tsx +76 -0
- package/src/components/ui/data-display/data-grid.tsx +680 -0
- package/src/components/ui/data-display/list.tsx +456 -0
- package/src/components/ui/data-display/table.tsx +482 -0
- package/src/components/ui/data-display/timeline.tsx +441 -0
- package/src/components/ui/data-display/tree.tsx +602 -0
- package/src/components/ui/data-display/types.ts +536 -0
- package/src/components/ui/enterprise-mobile-experience-demo.tsx +749 -0
- package/src/components/ui/enterprise-mobile-experience.tsx +464 -0
- package/src/components/ui/feedback/alert.tsx +157 -0
- package/src/components/ui/feedback/progress.tsx +292 -0
- package/src/components/ui/feedback/skeleton.tsx +185 -0
- package/src/components/ui/feedback/toast.tsx +280 -0
- package/src/components/ui/feedback/types.ts +125 -0
- package/src/components/ui/font-preview.tsx +288 -0
- package/src/components/ui/form-demo.tsx +553 -0
- package/src/components/ui/hardware-acceleration-demo.tsx +547 -0
- package/src/components/ui/input.tsx +35 -0
- package/src/components/ui/label.tsx +16 -0
- package/src/components/ui/layout-demo.tsx +367 -0
- package/src/components/ui/layouts/adaptive-layout.tsx +139 -0
- package/src/components/ui/layouts/desktop-layout.tsx +224 -0
- package/src/components/ui/layouts/index.ts +10 -0
- package/src/components/ui/layouts/mobile-layout.tsx +162 -0
- package/src/components/ui/layouts/tablet-layout.tsx +197 -0
- package/src/components/ui/mobile-form-validation.tsx +451 -0
- package/src/components/ui/mobile-input-demo.tsx +201 -0
- package/src/components/ui/mobile-input.tsx +281 -0
- package/src/components/ui/mobile-skeleton-loading-demo.tsx +638 -0
- package/src/components/ui/navigation/breadcrumb.tsx +158 -0
- package/src/components/ui/navigation/index.ts +36 -0
- package/src/components/ui/navigation/menu.tsx +374 -0
- package/src/components/ui/navigation/navigation-demo.tsx +324 -0
- package/src/components/ui/navigation/pagination.tsx +272 -0
- package/src/components/ui/navigation/sidebar.tsx +383 -0
- package/src/components/ui/navigation/stepper.tsx +303 -0
- package/src/components/ui/navigation/tabs.tsx +205 -0
- package/src/components/ui/navigation/types.ts +299 -0
- package/src/components/ui/overlay/backdrop.tsx +81 -0
- package/src/components/ui/overlay/focus-manager.tsx +143 -0
- package/src/components/ui/overlay/index.ts +36 -0
- package/src/components/ui/overlay/modal.tsx +270 -0
- package/src/components/ui/overlay/overlay-manager.tsx +110 -0
- package/src/components/ui/overlay/popover.tsx +462 -0
- package/src/components/ui/overlay/portal.tsx +79 -0
- package/src/components/ui/overlay/tooltip.tsx +303 -0
- package/src/components/ui/overlay/types.ts +196 -0
- package/src/components/ui/performance-demo.tsx +596 -0
- package/src/components/ui/semantic-input-system-demo.tsx +502 -0
- package/src/components/ui/semantic-input-system-demo.tsx.disabled +873 -0
- package/src/components/ui/tablet-layout.tsx +192 -0
- package/src/components/ui/theme-customizer.tsx +386 -0
- package/src/components/ui/theme-preview.tsx +310 -0
- package/src/components/ui/theme-switcher.tsx +264 -0
- package/src/components/ui/theme-toggle.tsx +38 -0
- package/src/components/ui/token-demo.tsx +195 -0
- package/src/components/ui/touch-demo.tsx +462 -0
- package/src/components/ui/touch-friendly-interface-demo.tsx +519 -0
- package/src/components/ui/touch-friendly-interface.tsx +296 -0
- package/src/hooks/index.ts +190 -0
- package/src/hooks/use-accessibility-support.ts +518 -0
- package/src/hooks/use-adaptive-layout.ts +289 -0
- package/src/hooks/use-advanced-patterns.ts +294 -0
- package/src/hooks/use-advanced-transition-system.ts +393 -0
- package/src/hooks/use-animation-profile.ts +288 -0
- package/src/hooks/use-battery-animations.ts +384 -0
- package/src/hooks/use-battery-conscious-loading.ts +475 -0
- package/src/hooks/use-battery-optimization.ts +330 -0
- package/src/hooks/use-battery-status.ts +299 -0
- package/src/hooks/use-component-performance.ts +344 -0
- package/src/hooks/use-device-loading-states.ts +459 -0
- package/src/hooks/use-device.tsx +110 -0
- package/src/hooks/use-enterprise-mobile-experience.ts +488 -0
- package/src/hooks/use-form-feedback.ts +403 -0
- package/src/hooks/use-form-performance.ts +513 -0
- package/src/hooks/use-frame-rate.ts +251 -0
- package/src/hooks/use-gestures.ts +338 -0
- package/src/hooks/use-hardware-acceleration.ts +341 -0
- package/src/hooks/use-input-accessibility.ts +455 -0
- package/src/hooks/use-input-performance.ts +506 -0
- package/src/hooks/use-layout-performance.ts +319 -0
- package/src/hooks/use-loading-accessibility.ts +535 -0
- package/src/hooks/use-loading-performance.ts +473 -0
- package/src/hooks/use-memory-usage.ts +287 -0
- package/src/hooks/use-mobile-form-layout.ts +464 -0
- package/src/hooks/use-mobile-form-validation.ts +518 -0
- package/src/hooks/use-mobile-keyboard-optimization.ts +472 -0
- package/src/hooks/use-mobile-layout.ts +302 -0
- package/src/hooks/use-mobile-optimization.ts +406 -0
- package/src/hooks/use-mobile-skeleton.ts +402 -0
- package/src/hooks/use-mobile-touch.ts +414 -0
- package/src/hooks/use-performance-throttling.ts +348 -0
- package/src/hooks/use-performance.ts +316 -0
- package/src/hooks/use-reusable-architecture.ts +414 -0
- package/src/hooks/use-semantic-input-types.ts +357 -0
- package/src/hooks/use-semantic-input.ts +565 -0
- package/src/hooks/use-tablet-layout.ts +384 -0
- package/src/hooks/use-touch-friendly-input.ts +524 -0
- package/src/hooks/use-touch-friendly-interface.ts +331 -0
- package/src/hooks/use-touch-optimization.ts +375 -0
- package/src/index.ts +279 -279
- package/src/lib/utils.ts +6 -0
- package/src/themes/README.md +272 -0
- package/src/themes/ThemeContext.tsx +31 -0
- package/src/themes/ThemeProvider.tsx +232 -0
- package/src/themes/accessibility/index.ts +27 -0
- package/src/themes/accessibility.ts +259 -0
- package/src/themes/aria-patterns.ts +420 -0
- package/src/themes/base-themes.ts +55 -0
- package/src/themes/colorManager.ts +380 -0
- package/src/themes/examples/dark-theme.ts +154 -0
- package/src/themes/examples/minimal-theme.ts +108 -0
- package/src/themes/focus-management.ts +701 -0
- package/src/themes/fontLoader.ts +201 -0
- package/src/themes/high-contrast.ts +621 -0
- package/src/themes/index.ts +19 -0
- package/src/themes/inheritance.ts +227 -0
- package/src/themes/keyboard-navigation.ts +550 -0
- package/src/themes/motion-reduction.ts +662 -0
- package/src/themes/navigation.ts +238 -0
- package/src/themes/screen-reader.ts +645 -0
- package/src/themes/systemThemeDetector.ts +182 -0
- package/src/themes/themeCSSUpdater.ts +262 -0
- package/src/themes/themePersistence.ts +238 -0
- package/src/themes/themes/default.ts +586 -0
- package/src/themes/themes/harvey.ts +554 -0
- package/src/themes/themes/stan-design.ts +683 -0
- package/src/themes/types.ts +460 -0
- package/src/themes/useSystemTheme.ts +48 -0
- package/src/themes/useTheme.ts +87 -0
- package/src/themes/validation.ts +462 -0
- package/src/tokens/index.ts +34 -0
- package/src/tokens/tokenExporter.ts +397 -0
- package/src/tokens/tokenGenerator.ts +276 -0
- package/src/tokens/tokenManager.ts +248 -0
- package/src/tokens/tokenValidator.ts +543 -0
- package/src/tokens/types.ts +78 -0
- package/src/utils/bundle-analyzer.ts +260 -0
- package/src/utils/bundle-splitting.ts +483 -0
- package/src/utils/lazy-loading.ts +441 -0
- package/src/utils/performance-monitor.ts +513 -0
- package/src/utils/tree-shaking.ts +274 -0
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import React, { useState, useRef, forwardRef } from 'react'
|
|
2
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from './card'
|
|
3
|
+
import { Button } from './button'
|
|
4
|
+
import { Badge } from './badge'
|
|
5
|
+
import { Input } from './input'
|
|
6
|
+
import { Label } from './label'
|
|
7
|
+
import { useMobileFormValidation, ValidationRule } from '../../hooks/use-mobile-form-validation'
|
|
8
|
+
import { useFormFeedback } from '../../hooks/use-form-feedback'
|
|
9
|
+
import { useMobileFormLayout } from '../../hooks/use-mobile-form-layout'
|
|
10
|
+
import { useSemanticInput, InputType } from '../../hooks/use-semantic-input'
|
|
11
|
+
import { useFormPerformance } from '../../hooks/use-form-performance'
|
|
12
|
+
|
|
13
|
+
export interface MobileFormValidationProps {
|
|
14
|
+
title?: string
|
|
15
|
+
description?: string
|
|
16
|
+
fields: Array<{
|
|
17
|
+
name: string
|
|
18
|
+
label: string
|
|
19
|
+
type: InputType
|
|
20
|
+
placeholder?: string
|
|
21
|
+
rules: ValidationRule[]
|
|
22
|
+
initialValue?: any
|
|
23
|
+
}>
|
|
24
|
+
onSubmit?: (formData: Record<string, any>) => void
|
|
25
|
+
onValidationChange?: (isValid: boolean) => void
|
|
26
|
+
className?: string
|
|
27
|
+
enableEnhancedFeatures?: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface MobileFormValidationRef {
|
|
31
|
+
submit: () => Promise<{ success: boolean; data: Record<string, any>; errors: string[] }>
|
|
32
|
+
reset: () => void
|
|
33
|
+
validate: () => Promise<boolean>
|
|
34
|
+
getFieldValidation: (fieldName: string) => any
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const MobileFormValidation = forwardRef<MobileFormValidationRef, MobileFormValidationProps>(
|
|
38
|
+
({
|
|
39
|
+
title = 'Mobile Form Validation',
|
|
40
|
+
description = 'Advanced form validation with mobile optimization',
|
|
41
|
+
fields,
|
|
42
|
+
onSubmit,
|
|
43
|
+
onValidationChange,
|
|
44
|
+
className = '',
|
|
45
|
+
enableEnhancedFeatures = true
|
|
46
|
+
}, ref) => {
|
|
47
|
+
const [formData, setFormData] = useState<Record<string, any>>({})
|
|
48
|
+
const [isSubmitting, setIsSubmitting] = useState(false)
|
|
49
|
+
const formRef = useRef<HTMLFormElement>(null)
|
|
50
|
+
|
|
51
|
+
// Initialize form data
|
|
52
|
+
React.useEffect(() => {
|
|
53
|
+
const initialData = fields.reduce((acc, field) => {
|
|
54
|
+
acc[field.name] = field.initialValue || ''
|
|
55
|
+
return acc
|
|
56
|
+
}, {} as Record<string, any>)
|
|
57
|
+
setFormData(initialData)
|
|
58
|
+
}, [fields])
|
|
59
|
+
|
|
60
|
+
// Initialize hooks with configuration based on enhanced features
|
|
61
|
+
const initialFields = fields.reduce((acc, field) => {
|
|
62
|
+
acc[field.name] = {
|
|
63
|
+
name: field.name,
|
|
64
|
+
value: field.initialValue || '',
|
|
65
|
+
rules: field.rules
|
|
66
|
+
}
|
|
67
|
+
return acc
|
|
68
|
+
}, {} as Record<string, any>)
|
|
69
|
+
|
|
70
|
+
// Form feedback hook
|
|
71
|
+
const feedback = useFormFeedback({
|
|
72
|
+
onFeedbackShow: (feedbackState) => {
|
|
73
|
+
console.log('Feedback shown:', feedbackState)
|
|
74
|
+
}
|
|
75
|
+
}, {
|
|
76
|
+
enableAnimations: true,
|
|
77
|
+
enableTouchFeedback: true,
|
|
78
|
+
enableHapticFeedback: enableEnhancedFeatures,
|
|
79
|
+
enableSoundFeedback: enableEnhancedFeatures,
|
|
80
|
+
enableAccessibility: true
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
// Form validation hook
|
|
84
|
+
const {
|
|
85
|
+
updateField,
|
|
86
|
+
touchField,
|
|
87
|
+
validateAllFields,
|
|
88
|
+
submitForm: submitFormHook,
|
|
89
|
+
resetForm,
|
|
90
|
+
getFieldValidation,
|
|
91
|
+
isFormValid,
|
|
92
|
+
isFormDirty
|
|
93
|
+
} = useMobileFormValidation(initialFields, {
|
|
94
|
+
onFormSubmit: (data, isValid) => {
|
|
95
|
+
if (isValid && onSubmit) {
|
|
96
|
+
onSubmit(data)
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
onValidationComplete: (fieldName, isValid, errors) => {
|
|
100
|
+
// Trigger feedback based on validation result
|
|
101
|
+
if (isValid) {
|
|
102
|
+
feedback.showSuccess(`${fieldName} is valid`)
|
|
103
|
+
} else {
|
|
104
|
+
feedback.showError(`${fieldName}: ${errors.join(', ')}`)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}, {
|
|
108
|
+
enableTouchFeedback: true,
|
|
109
|
+
enableHapticFeedback: enableEnhancedFeatures,
|
|
110
|
+
enableSoundFeedback: enableEnhancedFeatures,
|
|
111
|
+
validationDelay: enableEnhancedFeatures ? 300 : 500,
|
|
112
|
+
enablePerformanceOptimization: enableEnhancedFeatures,
|
|
113
|
+
maxValidationRetries: enableEnhancedFeatures ? 3 : 1
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// Mobile form layout hook
|
|
117
|
+
const layout = useMobileFormLayout({
|
|
118
|
+
onLayoutChange: (layoutState) => {
|
|
119
|
+
console.log('Layout changed:', layoutState)
|
|
120
|
+
}
|
|
121
|
+
}, {
|
|
122
|
+
enableTouchOptimization: true,
|
|
123
|
+
enableKeyboardOptimization: enableEnhancedFeatures,
|
|
124
|
+
enableResponsiveBehavior: true,
|
|
125
|
+
enablePerformanceOptimization: enableEnhancedFeatures,
|
|
126
|
+
enableAutoFocus: enableEnhancedFeatures
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// Form performance hook
|
|
130
|
+
const performance = useFormPerformance({
|
|
131
|
+
onPerformanceWarning: (warning, metrics) => {
|
|
132
|
+
console.warn('Performance warning:', warning, metrics)
|
|
133
|
+
feedback.showWarning(warning)
|
|
134
|
+
},
|
|
135
|
+
onMemoryWarning: (usage, _threshold) => {
|
|
136
|
+
feedback.showWarning(`Memory usage high: ${(usage * 100).toFixed(1)}%`)
|
|
137
|
+
},
|
|
138
|
+
onBatteryWarning: (level, isLow) => {
|
|
139
|
+
if (isLow) {
|
|
140
|
+
feedback.showWarning(`Low battery: ${(level * 100).toFixed(0)}%`)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}, {
|
|
144
|
+
enableValidationThrottling: true,
|
|
145
|
+
enableTouchEventOptimization: enableEnhancedFeatures,
|
|
146
|
+
enableMemoryManagement: enableEnhancedFeatures,
|
|
147
|
+
enableBatteryOptimization: enableEnhancedFeatures
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
// Semantic input hooks for each field
|
|
151
|
+
const semanticInputs = fields.reduce((acc, field) => {
|
|
152
|
+
acc[field.name] = useSemanticInput(field.type, {
|
|
153
|
+
onInputTypeDetected: (inputType) => {
|
|
154
|
+
console.log(`Input type detected for ${field.name}:`, inputType)
|
|
155
|
+
},
|
|
156
|
+
onKeyboardOptimization: (optimized) => {
|
|
157
|
+
console.log(`Keyboard optimization for ${field.name}:`, optimized)
|
|
158
|
+
}
|
|
159
|
+
}, {
|
|
160
|
+
enableAutoDetection: true,
|
|
161
|
+
enableKeyboardOptimization: enableEnhancedFeatures,
|
|
162
|
+
enableAutocomplete: enableEnhancedFeatures,
|
|
163
|
+
enableTouchOptimization: true,
|
|
164
|
+
enableAccessibility: true,
|
|
165
|
+
enablePerformanceMonitoring: enableEnhancedFeatures
|
|
166
|
+
})
|
|
167
|
+
return acc
|
|
168
|
+
}, {} as Record<string, any>)
|
|
169
|
+
|
|
170
|
+
// Handle field changes
|
|
171
|
+
const handleFieldChange = (fieldName: string, value: any) => {
|
|
172
|
+
setFormData(prev => ({ ...prev, [fieldName]: value }))
|
|
173
|
+
|
|
174
|
+
// Update validation state
|
|
175
|
+
updateField(fieldName, value)
|
|
176
|
+
|
|
177
|
+
// Update semantic input
|
|
178
|
+
const semanticInput = semanticInputs[fieldName]
|
|
179
|
+
if (semanticInput) {
|
|
180
|
+
semanticInput.handleInputChange(value, fieldName, fields.find(f => f.name === fieldName)?.placeholder)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Notify validation change
|
|
184
|
+
if (onValidationChange) {
|
|
185
|
+
onValidationChange(isFormValid)
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Handle field blur
|
|
190
|
+
const handleFieldBlur = (fieldName: string) => {
|
|
191
|
+
touchField(fieldName)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Handle form submission
|
|
195
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
196
|
+
e.preventDefault()
|
|
197
|
+
setIsSubmitting(true)
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
const result = await submitFormHook()
|
|
201
|
+
|
|
202
|
+
if (result.success) {
|
|
203
|
+
feedback.showSuccess('Form submitted successfully!')
|
|
204
|
+
if (onSubmit) {
|
|
205
|
+
onSubmit(result.data)
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
feedback.showError(`Form submission failed: ${result.errors.join(', ')}`)
|
|
209
|
+
}
|
|
210
|
+
} catch (error) {
|
|
211
|
+
feedback.showError('An unexpected error occurred')
|
|
212
|
+
console.error('Form submission error:', error)
|
|
213
|
+
} finally {
|
|
214
|
+
setIsSubmitting(false)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Handle form reset
|
|
219
|
+
const handleReset = () => {
|
|
220
|
+
resetForm()
|
|
221
|
+
setFormData(fields.reduce((acc, field) => {
|
|
222
|
+
acc[field.name] = field.initialValue || ''
|
|
223
|
+
return acc
|
|
224
|
+
}, {} as Record<string, any>))
|
|
225
|
+
|
|
226
|
+
// Reset semantic inputs
|
|
227
|
+
Object.values(semanticInputs).forEach((semanticInput: any) => {
|
|
228
|
+
semanticInput.resetOptimizations()
|
|
229
|
+
})
|
|
230
|
+
|
|
231
|
+
// Reset performance
|
|
232
|
+
performance.resetPerformance()
|
|
233
|
+
|
|
234
|
+
// Clear feedback
|
|
235
|
+
feedback.clearFeedback()
|
|
236
|
+
|
|
237
|
+
feedback.showInfo('Form has been reset')
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Expose methods via ref
|
|
241
|
+
React.useImperativeHandle(ref, () => ({
|
|
242
|
+
submit: submitFormHook,
|
|
243
|
+
reset: handleReset,
|
|
244
|
+
validate: validateAllFields,
|
|
245
|
+
getFieldValidation
|
|
246
|
+
}))
|
|
247
|
+
|
|
248
|
+
// Apply performance optimizations
|
|
249
|
+
React.useEffect(() => {
|
|
250
|
+
performance.applyOptimizations()
|
|
251
|
+
}, [performance])
|
|
252
|
+
|
|
253
|
+
// Auto-focus first input on mobile
|
|
254
|
+
React.useEffect(() => {
|
|
255
|
+
if (layout.isMobile && layout.autoFocusFirstInput) {
|
|
256
|
+
layout.autoFocusFirstInput()
|
|
257
|
+
}
|
|
258
|
+
}, [layout.isMobile, layout.autoFocusFirstInput])
|
|
259
|
+
|
|
260
|
+
return (
|
|
261
|
+
<div className={`mobile-form-validation ${className}`}>
|
|
262
|
+
{/* Performance Status */}
|
|
263
|
+
{enableEnhancedFeatures && (
|
|
264
|
+
<div className="mb-4 p-3 bg-gray-50 rounded-lg">
|
|
265
|
+
<div className="flex items-center justify-between text-sm">
|
|
266
|
+
<div className="flex items-center gap-2">
|
|
267
|
+
<span>Performance:</span>
|
|
268
|
+
<Badge variant={performance.performanceState.isOptimized ? 'default' : 'secondary'}>
|
|
269
|
+
{performance.performanceState.isOptimized ? 'Optimized' : 'Not Optimized'}
|
|
270
|
+
</Badge>
|
|
271
|
+
</div>
|
|
272
|
+
<div className="flex items-center gap-2">
|
|
273
|
+
<span>Layout:</span>
|
|
274
|
+
<Badge variant={layout.isOptimized ? 'default' : 'secondary'}>
|
|
275
|
+
{layout.isOptimized ? 'Optimized' : 'Not Optimized'}
|
|
276
|
+
</Badge>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
)}
|
|
281
|
+
|
|
282
|
+
{/* Form Feedback Display */}
|
|
283
|
+
{feedback.isFeedbackVisible() && (
|
|
284
|
+
<div className={`mb-4 p-3 rounded-lg ${feedback.getFeedbackClasses()}`}>
|
|
285
|
+
<div className="flex items-center gap-2">
|
|
286
|
+
<span>{feedback.getFeedbackIcon(feedback.getCurrentFeedbackType())}</span>
|
|
287
|
+
<span>{feedback.feedbackState.currentFeedback.message}</span>
|
|
288
|
+
</div>
|
|
289
|
+
</div>
|
|
290
|
+
)}
|
|
291
|
+
|
|
292
|
+
{/* Form */}
|
|
293
|
+
<form
|
|
294
|
+
ref={formRef}
|
|
295
|
+
onSubmit={handleSubmit}
|
|
296
|
+
className={`space-y-4 ${layout.getLayoutClasses()}`}
|
|
297
|
+
style={layout.getLayoutCSSVariables() as React.CSSProperties}
|
|
298
|
+
>
|
|
299
|
+
<Card>
|
|
300
|
+
<CardHeader>
|
|
301
|
+
<CardTitle className="flex items-center gap-2">
|
|
302
|
+
{title}
|
|
303
|
+
<Badge variant="outline">Story 6 Implementation</Badge>
|
|
304
|
+
</CardTitle>
|
|
305
|
+
<CardDescription>{description}</CardDescription>
|
|
306
|
+
</CardHeader>
|
|
307
|
+
<CardContent className="space-y-4">
|
|
308
|
+
{/* Form Fields */}
|
|
309
|
+
{fields.map((field) => {
|
|
310
|
+
const fieldValidation = getFieldValidation(field.name)
|
|
311
|
+
const semanticInput = semanticInputs[field.name]
|
|
312
|
+
const isFieldValid = fieldValidation.isValid
|
|
313
|
+
const fieldErrors = fieldValidation.errors
|
|
314
|
+
const isFieldTouched = fieldValidation.isTouched
|
|
315
|
+
|
|
316
|
+
return (
|
|
317
|
+
<div key={field.name} className="space-y-2">
|
|
318
|
+
<Label htmlFor={field.name} className="text-sm font-medium">
|
|
319
|
+
{field.label}
|
|
320
|
+
{field.rules.some(rule => rule.type === 'required') && (
|
|
321
|
+
<span className="text-red-500 ml-1">*</span>
|
|
322
|
+
)}
|
|
323
|
+
</Label>
|
|
324
|
+
|
|
325
|
+
<div className="relative">
|
|
326
|
+
<Input
|
|
327
|
+
id={field.name}
|
|
328
|
+
ref={semanticInput?.inputRef}
|
|
329
|
+
type={field.type.type}
|
|
330
|
+
placeholder={field.placeholder}
|
|
331
|
+
value={formData[field.name] || ''}
|
|
332
|
+
onChange={(e) => handleFieldChange(field.name, e.target.value)}
|
|
333
|
+
onBlur={() => handleFieldBlur(field.name)}
|
|
334
|
+
className={`w-full transition-all duration-200 ${
|
|
335
|
+
isFieldTouched && !isFieldValid
|
|
336
|
+
? 'border-red-500 focus:border-red-500 focus:ring-red-500'
|
|
337
|
+
: isFieldTouched && isFieldValid
|
|
338
|
+
? 'border-green-500 focus:border-green-500 focus:ring-green-500'
|
|
339
|
+
: 'border-gray-300 focus:border-blue-500 focus:ring-blue-500'
|
|
340
|
+
} ${semanticInput?.getSemanticClasses() || ''}`}
|
|
341
|
+
style={{
|
|
342
|
+
minHeight: layout.currentSpacing,
|
|
343
|
+
width: layout.currentFieldWidth
|
|
344
|
+
}}
|
|
345
|
+
{...semanticInput?.getOptimizedAttributes(field.type)}
|
|
346
|
+
/>
|
|
347
|
+
|
|
348
|
+
{/* Field Status Indicators */}
|
|
349
|
+
{isFieldTouched && (
|
|
350
|
+
<div className="absolute right-3 top-1/2 transform -translate-y-1/2">
|
|
351
|
+
{isFieldValid ? (
|
|
352
|
+
<span className="text-green-500 text-lg">✓</span>
|
|
353
|
+
) : (
|
|
354
|
+
<span className="text-red-500 text-lg">✗</span>
|
|
355
|
+
)}
|
|
356
|
+
</div>
|
|
357
|
+
)}
|
|
358
|
+
</div>
|
|
359
|
+
|
|
360
|
+
{/* Field Errors */}
|
|
361
|
+
{isFieldTouched && !isFieldValid && fieldErrors.length > 0 && (
|
|
362
|
+
<div className="text-red-500 text-sm space-y-1">
|
|
363
|
+
{fieldErrors.map((error: string, index: number) => (
|
|
364
|
+
<div key={index} className="flex items-center gap-1">
|
|
365
|
+
<span>•</span>
|
|
366
|
+
<span>{error}</span>
|
|
367
|
+
</div>
|
|
368
|
+
))}
|
|
369
|
+
</div>
|
|
370
|
+
)}
|
|
371
|
+
|
|
372
|
+
{/* Semantic Input Status */}
|
|
373
|
+
{enableEnhancedFeatures && semanticInput && (
|
|
374
|
+
<div className="text-xs text-gray-500 space-y-1">
|
|
375
|
+
<div className="flex items-center gap-2">
|
|
376
|
+
<span>Type:</span>
|
|
377
|
+
<Badge variant="outline" className="text-xs">
|
|
378
|
+
{semanticInput.semanticState.detectedType?.type || field.type.type}
|
|
379
|
+
</Badge>
|
|
380
|
+
</div>
|
|
381
|
+
{semanticInput.semanticState.isOptimized && (
|
|
382
|
+
<div className="flex items-center gap-2">
|
|
383
|
+
<span>Optimized:</span>
|
|
384
|
+
<Badge variant="default" className="text-xs">Yes</Badge>
|
|
385
|
+
</div>
|
|
386
|
+
)}
|
|
387
|
+
</div>
|
|
388
|
+
)}
|
|
389
|
+
</div>
|
|
390
|
+
)
|
|
391
|
+
})}
|
|
392
|
+
|
|
393
|
+
{/* Form Actions */}
|
|
394
|
+
<div className="flex flex-col sm:flex-row gap-3 pt-4">
|
|
395
|
+
<Button
|
|
396
|
+
type="submit"
|
|
397
|
+
disabled={!isFormValid || isSubmitting}
|
|
398
|
+
className="flex-1 touch-button"
|
|
399
|
+
style={{ minHeight: layout.currentSpacing }}
|
|
400
|
+
>
|
|
401
|
+
{isSubmitting ? 'Submitting...' : 'Submit'}
|
|
402
|
+
</Button>
|
|
403
|
+
|
|
404
|
+
<Button
|
|
405
|
+
type="button"
|
|
406
|
+
variant="outline"
|
|
407
|
+
onClick={handleReset}
|
|
408
|
+
className="flex-1 touch-button"
|
|
409
|
+
style={{ minHeight: layout.currentSpacing }}
|
|
410
|
+
>
|
|
411
|
+
Reset
|
|
412
|
+
</Button>
|
|
413
|
+
</div>
|
|
414
|
+
|
|
415
|
+
{/* Form Status */}
|
|
416
|
+
<div className="text-sm text-gray-500 space-y-1">
|
|
417
|
+
<div className="flex items-center gap-2">
|
|
418
|
+
<span>Form Status:</span>
|
|
419
|
+
<Badge variant={isFormValid ? 'default' : 'secondary'}>
|
|
420
|
+
{isFormValid ? 'Valid' : 'Invalid'}
|
|
421
|
+
</Badge>
|
|
422
|
+
</div>
|
|
423
|
+
<div className="flex items-center gap-2">
|
|
424
|
+
<span>Dirty:</span>
|
|
425
|
+
<Badge variant={isFormDirty ? 'default' : 'secondary'}>
|
|
426
|
+
{isFormDirty ? 'Yes' : 'No'}
|
|
427
|
+
</Badge>
|
|
428
|
+
</div>
|
|
429
|
+
{enableEnhancedFeatures && (
|
|
430
|
+
<div className="flex items-center gap-2">
|
|
431
|
+
<span>Performance Score:</span>
|
|
432
|
+
<Badge variant={
|
|
433
|
+
performance.performanceState.performanceMetrics.optimizationScore >= 0.8 ? 'default' :
|
|
434
|
+
performance.performanceState.performanceMetrics.optimizationScore >= 0.6 ? 'secondary' : 'destructive'
|
|
435
|
+
}>
|
|
436
|
+
{(performance.performanceState.performanceMetrics.optimizationScore * 100).toFixed(0)}%
|
|
437
|
+
</Badge>
|
|
438
|
+
</div>
|
|
439
|
+
)}
|
|
440
|
+
</div>
|
|
441
|
+
</CardContent>
|
|
442
|
+
</Card>
|
|
443
|
+
</form>
|
|
444
|
+
</div>
|
|
445
|
+
)
|
|
446
|
+
}
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
MobileFormValidation.displayName = 'MobileFormValidation'
|
|
450
|
+
|
|
451
|
+
export default MobileFormValidation
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Card } from './card';
|
|
3
|
+
import { MobileInput, mobileInputConfigs } from './mobile-input';
|
|
4
|
+
|
|
5
|
+
export const MobileInputDemo: React.FC = () => {
|
|
6
|
+
return (
|
|
7
|
+
<div className="space-y-6">
|
|
8
|
+
<div className="text-center">
|
|
9
|
+
<h2 className="text-2xl font-bold text-cs-text-primary mb-2">
|
|
10
|
+
Mobile Input System Recovery
|
|
11
|
+
</h2>
|
|
12
|
+
<p className="text-cs-text-secondary">
|
|
13
|
+
Semantic Input Excellence - Recovered from original project
|
|
14
|
+
</p>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<Card className="p-6">
|
|
18
|
+
<h3 className="text-lg font-semibold text-cs-text-primary mb-4">
|
|
19
|
+
Semantic Input Types
|
|
20
|
+
</h3>
|
|
21
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
22
|
+
<div className="space-y-2">
|
|
23
|
+
<label className="text-sm font-medium text-cs-text-secondary">Name Input</label>
|
|
24
|
+
<MobileInput
|
|
25
|
+
placeholder="Enter your full name"
|
|
26
|
+
mobileConfig={mobileInputConfigs.name}
|
|
27
|
+
className="w-full"
|
|
28
|
+
/>
|
|
29
|
+
<p className="text-xs text-cs-text-muted">
|
|
30
|
+
Auto-capitalizes words, suggests name autocomplete
|
|
31
|
+
</p>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<div className="space-y-2">
|
|
35
|
+
<label className="text-sm font-medium text-cs-text-secondary">Email Input</label>
|
|
36
|
+
<MobileInput
|
|
37
|
+
placeholder="Enter your email"
|
|
38
|
+
mobileConfig={mobileInputConfigs.email}
|
|
39
|
+
className="w-full"
|
|
40
|
+
/>
|
|
41
|
+
<p className="text-xs text-cs-text-muted">
|
|
42
|
+
Email keyboard, no spell check, email autocomplete
|
|
43
|
+
</p>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div className="space-y-2">
|
|
47
|
+
<label className="text-sm font-medium text-cs-text-secondary">Phone Input</label>
|
|
48
|
+
<MobileInput
|
|
49
|
+
placeholder="Enter phone number"
|
|
50
|
+
mobileConfig={mobileInputConfigs.phone}
|
|
51
|
+
className="w-full"
|
|
52
|
+
/>
|
|
53
|
+
<p className="text-xs text-cs-text-muted">
|
|
54
|
+
Numeric keyboard, phone autocomplete
|
|
55
|
+
</p>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div className="space-y-2">
|
|
59
|
+
<label className="text-sm font-medium text-cs-text-secondary">Password Input</label>
|
|
60
|
+
<MobileInput
|
|
61
|
+
placeholder="Enter new password"
|
|
62
|
+
mobileConfig={mobileInputConfigs.newPassword}
|
|
63
|
+
className="w-full"
|
|
64
|
+
/>
|
|
65
|
+
<p className="text-xs text-cs-text-muted">
|
|
66
|
+
Password keyboard, new-password autocomplete
|
|
67
|
+
</p>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div className="space-y-2">
|
|
71
|
+
<label className="text-sm font-medium text-cs-text-secondary">Search Input</label>
|
|
72
|
+
<MobileInput
|
|
73
|
+
placeholder="Search..."
|
|
74
|
+
mobileConfig={mobileInputConfigs.search}
|
|
75
|
+
className="w-full"
|
|
76
|
+
/>
|
|
77
|
+
<p className="text-xs text-cs-text-muted">
|
|
78
|
+
Search keyboard, no autocomplete
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<div className="space-y-2">
|
|
83
|
+
<label className="text-sm font-medium text-cs-text-secondary">Amount Input</label>
|
|
84
|
+
<MobileInput
|
|
85
|
+
placeholder="Enter amount"
|
|
86
|
+
mobileConfig={mobileInputConfigs.amount}
|
|
87
|
+
className="w-full"
|
|
88
|
+
/>
|
|
89
|
+
<p className="text-xs text-cs-text-muted">
|
|
90
|
+
Decimal keyboard, no autocomplete
|
|
91
|
+
</p>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</Card>
|
|
95
|
+
|
|
96
|
+
<Card className="p-6">
|
|
97
|
+
<h3 className="text-lg font-semibold text-cs-text-primary mb-4">
|
|
98
|
+
Custom Mobile Configurations
|
|
99
|
+
</h3>
|
|
100
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
101
|
+
<div className="space-y-2">
|
|
102
|
+
<label className="text-sm font-medium text-cs-text-secondary">Custom Input Mode</label>
|
|
103
|
+
<MobileInput
|
|
104
|
+
placeholder="Custom input mode"
|
|
105
|
+
mobileConfig={{
|
|
106
|
+
semanticType: 'email',
|
|
107
|
+
inputMode: 'tel',
|
|
108
|
+
spellCheck: true,
|
|
109
|
+
autoCapitalize: 'characters'
|
|
110
|
+
}}
|
|
111
|
+
className="w-full"
|
|
112
|
+
/>
|
|
113
|
+
<p className="text-xs text-cs-text-muted">
|
|
114
|
+
Email type with tel input mode, spell check enabled
|
|
115
|
+
</p>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div className="space-y-2">
|
|
119
|
+
<label className="text-sm font-medium text-cs-text-secondary">Disabled Autocomplete</label>
|
|
120
|
+
<MobileInput
|
|
121
|
+
placeholder="No autocomplete"
|
|
122
|
+
mobileConfig={{
|
|
123
|
+
semanticType: 'name',
|
|
124
|
+
enableAutocomplete: false
|
|
125
|
+
}}
|
|
126
|
+
className="w-full"
|
|
127
|
+
/>
|
|
128
|
+
<p className="text-xs text-cs-text-muted">
|
|
129
|
+
Name input with autocomplete disabled
|
|
130
|
+
</p>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</Card>
|
|
134
|
+
|
|
135
|
+
<Card className="p-6">
|
|
136
|
+
<h3 className="text-lg font-semibold text-cs-text-primary mb-4">
|
|
137
|
+
Props Override Behavior
|
|
138
|
+
</h3>
|
|
139
|
+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
|
140
|
+
<div className="space-y-2">
|
|
141
|
+
<label className="text-sm font-medium text-cs-text-secondary">Explicit Type Override</label>
|
|
142
|
+
<MobileInput
|
|
143
|
+
type="password"
|
|
144
|
+
placeholder="Password type overrides semantic"
|
|
145
|
+
mobileConfig={{ semanticType: 'email' }}
|
|
146
|
+
className="w-full"
|
|
147
|
+
/>
|
|
148
|
+
<p className="text-xs text-cs-text-muted">
|
|
149
|
+
Explicit password type overrides email semantic type
|
|
150
|
+
</p>
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
<div className="space-y-2">
|
|
154
|
+
<label className="text-sm font-medium text-cs-text-secondary">Custom Attributes</label>
|
|
155
|
+
<MobileInput
|
|
156
|
+
placeholder="Custom attributes"
|
|
157
|
+
mobileConfig={{ semanticType: 'name' }}
|
|
158
|
+
autoComplete="off"
|
|
159
|
+
spellCheck={true}
|
|
160
|
+
className="w-full"
|
|
161
|
+
/>
|
|
162
|
+
<p className="text-xs text-cs-text-muted">
|
|
163
|
+
Custom autoComplete and spellCheck override mobile config
|
|
164
|
+
</p>
|
|
165
|
+
</div>
|
|
166
|
+
</div>
|
|
167
|
+
</Card>
|
|
168
|
+
|
|
169
|
+
<Card className="p-6">
|
|
170
|
+
<h3 className="text-lg font-semibold text-cs-text-primary mb-4">
|
|
171
|
+
Mobile Optimization Features
|
|
172
|
+
</h3>
|
|
173
|
+
<div className="space-y-4">
|
|
174
|
+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 text-center">
|
|
175
|
+
<div className="p-4 bg-cs-surface-bg rounded-lg">
|
|
176
|
+
<div className="text-2xl mb-2">📱</div>
|
|
177
|
+
<h4 className="font-medium text-cs-text-primary">Touch Optimized</h4>
|
|
178
|
+
<p className="text-sm text-cs-text-secondary">
|
|
179
|
+
44px touch targets, touch-manipulation CSS
|
|
180
|
+
</p>
|
|
181
|
+
</div>
|
|
182
|
+
<div className="p-4 bg-cs-surface-bg rounded-lg">
|
|
183
|
+
<div className="text-2xl mb-2">⌨️</div>
|
|
184
|
+
<h4 className="font-medium text-cs-text-primary">Smart Keyboards</h4>
|
|
185
|
+
<p className="text-sm text-cs-text-secondary">
|
|
186
|
+
Semantic input modes for optimal mobile keyboards
|
|
187
|
+
</p>
|
|
188
|
+
</div>
|
|
189
|
+
<div className="p-4 bg-cs-surface-bg rounded-lg">
|
|
190
|
+
<div className="text-2xl mb-2">🔍</div>
|
|
191
|
+
<h4 className="font-medium text-cs-text-primary">Autocomplete</h4>
|
|
192
|
+
<p className="text-sm text-cs-text-secondary">
|
|
193
|
+
Intelligent autocomplete suggestions for better UX
|
|
194
|
+
</p>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
</Card>
|
|
199
|
+
</div>
|
|
200
|
+
);
|
|
201
|
+
};
|