@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.2.8 → 0.2.10
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/components/ui/accessibility-demo.esm.js +30 -24
- package/dist/components/ui/accessibility-demo.js +30 -24
- package/dist/components/ui/advanced-component-architecture-demo.esm.js +235 -179
- package/dist/components/ui/advanced-component-architecture-demo.js +235 -179
- package/dist/components/ui/advanced-transition-system-demo.esm.js +110 -64
- package/dist/components/ui/advanced-transition-system-demo.js +110 -64
- package/dist/components/ui/advanced-transition-system.esm.js +166 -122
- package/dist/components/ui/advanced-transition-system.js +166 -122
- package/dist/components/ui/animation/animated-container.esm.js +52 -29
- package/dist/components/ui/animation/animated-container.js +52 -29
- package/dist/components/ui/animation/staggered-container.esm.js +18 -9
- package/dist/components/ui/animation/staggered-container.js +18 -9
- package/dist/components/ui/animation-demo.esm.js +67 -35
- package/dist/components/ui/animation-demo.js +67 -35
- package/dist/components/ui/badge.esm.js +9 -6
- package/dist/components/ui/badge.js +9 -6
- package/dist/components/ui/battery-conscious-animation-demo.esm.js +122 -87
- package/dist/components/ui/battery-conscious-animation-demo.js +122 -87
- package/dist/components/ui/border-radius-shadow-demo.esm.js +23 -12
- package/dist/components/ui/border-radius-shadow-demo.js +23 -12
- package/dist/components/ui/button.esm.js +8 -2
- package/dist/components/ui/button.js +8 -2
- package/dist/components/ui/card.esm.js +33 -8
- package/dist/components/ui/card.js +33 -8
- package/dist/components/ui/checkbox.esm.js +3 -3
- package/dist/components/ui/checkbox.js +3 -3
- package/dist/components/ui/color-preview.esm.js +68 -45
- package/dist/components/ui/color-preview.js +68 -45
- package/dist/components/ui/data-display/chart.esm.js +112 -84
- package/dist/components/ui/data-display/chart.js +112 -84
- package/dist/components/ui/data-display/data-grid-simple.esm.js +1 -1
- package/dist/components/ui/data-display/data-grid-simple.js +1 -1
- package/dist/components/ui/data-display/data-grid.esm.js +80 -67
- package/dist/components/ui/data-display/data-grid.js +80 -67
- package/dist/components/ui/data-display/list.esm.js +53 -45
- package/dist/components/ui/data-display/list.js +53 -45
- package/dist/components/ui/data-display/table.esm.js +62 -54
- package/dist/components/ui/data-display/table.js +62 -54
- package/dist/components/ui/data-display/timeline.esm.js +39 -34
- package/dist/components/ui/data-display/timeline.js +39 -34
- package/dist/components/ui/data-display/tree.esm.js +116 -84
- package/dist/components/ui/data-display/tree.js +116 -84
- package/dist/components/ui/data-display/types.esm.js +389 -364
- package/dist/components/ui/data-display/types.js +389 -364
- package/dist/components/ui/enterprise-mobile-experience-demo.esm.js +120 -70
- package/dist/components/ui/enterprise-mobile-experience-demo.js +120 -70
- package/dist/components/ui/enterprise-mobile-experience.esm.js +124 -73
- package/dist/components/ui/enterprise-mobile-experience.js +124 -73
- package/dist/components/ui/feedback/alert.esm.js +22 -15
- package/dist/components/ui/feedback/alert.js +22 -15
- package/dist/components/ui/feedback/progress.esm.js +47 -24
- package/dist/components/ui/feedback/progress.js +47 -24
- package/dist/components/ui/feedback/skeleton.esm.js +39 -29
- package/dist/components/ui/feedback/skeleton.js +39 -29
- package/dist/components/ui/feedback/toast.esm.js +62 -38
- package/dist/components/ui/feedback/toast.js +62 -38
- package/dist/components/ui/feedback/types.esm.js +83 -83
- package/dist/components/ui/feedback/types.js +83 -83
- package/dist/components/ui/font-preview.esm.js +41 -39
- package/dist/components/ui/font-preview.js +41 -39
- package/dist/components/ui/form-demo.esm.js +150 -113
- package/dist/components/ui/form-demo.js +150 -113
- package/dist/components/ui/hardware-acceleration-demo.esm.js +137 -87
- package/dist/components/ui/hardware-acceleration-demo.js +137 -87
- package/dist/components/ui/input.esm.js +4 -1
- package/dist/components/ui/input.js +4 -1
- package/dist/components/ui/layout-demo.esm.js +81 -56
- package/dist/components/ui/layout-demo.js +81 -56
- package/dist/components/ui/layouts/adaptive-layout.esm.js +27 -8
- package/dist/components/ui/layouts/adaptive-layout.js +27 -8
- package/dist/components/ui/layouts/desktop-layout.esm.js +39 -19
- package/dist/components/ui/layouts/desktop-layout.js +39 -19
- package/dist/components/ui/layouts/mobile-layout.esm.js +19 -9
- package/dist/components/ui/layouts/mobile-layout.js +19 -9
- package/dist/components/ui/layouts/tablet-layout.esm.js +28 -14
- package/dist/components/ui/layouts/tablet-layout.js +28 -14
- package/dist/components/ui/mobile-form-validation.esm.js +120 -87
- package/dist/components/ui/mobile-form-validation.js +120 -87
- package/dist/components/ui/mobile-input-demo.esm.js +19 -13
- package/dist/components/ui/mobile-input-demo.js +19 -13
- package/dist/components/ui/mobile-input.esm.js +185 -120
- package/dist/components/ui/mobile-input.js +185 -120
- package/dist/components/ui/mobile-skeleton-loading-demo.esm.js +128 -111
- package/dist/components/ui/mobile-skeleton-loading-demo.js +128 -111
- package/dist/components/ui/navigation/breadcrumb.esm.js +17 -14
- package/dist/components/ui/navigation/breadcrumb.js +17 -14
- package/dist/components/ui/navigation/index.esm.js +23 -1
- package/dist/components/ui/navigation/index.js +23 -1
- package/dist/components/ui/navigation/menu.esm.js +49 -35
- package/dist/components/ui/navigation/menu.js +49 -35
- package/dist/components/ui/navigation/navigation-demo.esm.js +81 -74
- package/dist/components/ui/navigation/navigation-demo.js +81 -74
- package/dist/components/ui/navigation/pagination.esm.js +62 -50
- package/dist/components/ui/navigation/pagination.js +62 -50
- package/dist/components/ui/navigation/sidebar.esm.js +56 -42
- package/dist/components/ui/navigation/sidebar.js +56 -42
- package/dist/components/ui/navigation/stepper.esm.js +34 -23
- package/dist/components/ui/navigation/stepper.js +34 -23
- package/dist/components/ui/navigation/tabs.esm.js +32 -21
- package/dist/components/ui/navigation/tabs.js +32 -21
- package/dist/components/ui/navigation/types.esm.js +196 -195
- package/dist/components/ui/navigation/types.js +196 -195
- package/dist/components/ui/overlay/backdrop.esm.js +17 -16
- package/dist/components/ui/overlay/backdrop.js +17 -16
- package/dist/components/ui/overlay/focus-manager.esm.js +21 -19
- package/dist/components/ui/overlay/focus-manager.js +21 -19
- package/dist/components/ui/overlay/index.esm.js +22 -2
- package/dist/components/ui/overlay/index.js +22 -2
- package/dist/components/ui/overlay/modal.esm.js +38 -34
- package/dist/components/ui/overlay/modal.js +38 -34
- package/dist/components/ui/overlay/overlay-manager.esm.js +25 -20
- package/dist/components/ui/overlay/overlay-manager.js +25 -20
- package/dist/components/ui/overlay/popover.esm.js +74 -58
- package/dist/components/ui/overlay/popover.js +74 -58
- package/dist/components/ui/overlay/portal.esm.js +7 -7
- package/dist/components/ui/overlay/portal.js +7 -7
- package/dist/components/ui/overlay/tooltip.esm.js +54 -39
- package/dist/components/ui/overlay/tooltip.js +54 -39
- package/dist/components/ui/overlay/types.esm.js +132 -131
- package/dist/components/ui/overlay/types.js +132 -131
- package/dist/components/ui/performance-demo.esm.js +135 -88
- package/dist/components/ui/performance-demo.js +135 -88
- package/dist/components/ui/semantic-input-system-demo.esm.js +117 -80
- package/dist/components/ui/semantic-input-system-demo.js +117 -80
- package/dist/components/ui/theme-customizer.esm.js +84 -52
- package/dist/components/ui/theme-customizer.js +84 -52
- package/dist/components/ui/theme-preview.esm.js +95 -43
- package/dist/components/ui/theme-preview.js +95 -43
- package/dist/components/ui/theme-switcher.esm.js +70 -44
- package/dist/components/ui/theme-switcher.js +70 -44
- package/dist/components/ui/theme-toggle.esm.js +3 -3
- package/dist/components/ui/theme-toggle.js +3 -3
- package/dist/components/ui/token-demo.esm.js +33 -21
- package/dist/components/ui/token-demo.js +33 -21
- package/dist/components/ui/touch-demo.esm.js +102 -73
- package/dist/components/ui/touch-demo.js +102 -73
- package/dist/components/ui/touch-friendly-interface-demo.esm.js +102 -64
- package/dist/components/ui/touch-friendly-interface-demo.js +102 -64
- package/dist/components/ui/touch-friendly-interface.esm.js +85 -61
- package/dist/components/ui/touch-friendly-interface.js +85 -61
- package/dist/hooks/use-accessibility-support.esm.js +115 -85
- package/dist/hooks/use-accessibility-support.js +115 -85
- package/dist/hooks/use-adaptive-layout.esm.js +56 -33
- package/dist/hooks/use-adaptive-layout.js +56 -33
- package/dist/hooks/use-advanced-patterns.esm.js +57 -42
- package/dist/hooks/use-advanced-patterns.js +57 -42
- package/dist/hooks/use-advanced-transition-system.esm.js +112 -71
- package/dist/hooks/use-advanced-transition-system.js +112 -71
- package/dist/hooks/use-animation-profile.esm.js +63 -34
- package/dist/hooks/use-animation-profile.js +63 -34
- package/dist/hooks/use-battery-animations.esm.js +80 -55
- package/dist/hooks/use-battery-animations.js +80 -55
- package/dist/hooks/use-battery-conscious-loading.esm.js +166 -123
- package/dist/hooks/use-battery-conscious-loading.js +166 -123
- package/dist/hooks/use-battery-optimization.esm.js +78 -55
- package/dist/hooks/use-battery-optimization.js +78 -55
- package/dist/hooks/use-battery-status.esm.js +73 -51
- package/dist/hooks/use-battery-status.js +73 -51
- package/dist/hooks/use-component-performance.esm.js +62 -47
- package/dist/hooks/use-component-performance.js +62 -47
- package/dist/hooks/use-device-loading-states.esm.js +152 -109
- package/dist/hooks/use-device-loading-states.js +152 -109
- package/dist/hooks/use-device.esm.js +25 -14
- package/dist/hooks/use-device.js +25 -14
- package/dist/hooks/use-enterprise-mobile-experience.esm.js +137 -88
- package/dist/hooks/use-enterprise-mobile-experience.js +137 -88
- package/dist/hooks/use-form-feedback.esm.js +124 -81
- package/dist/hooks/use-form-feedback.js +124 -81
- package/dist/hooks/use-form-performance.esm.js +127 -92
- package/dist/hooks/use-form-performance.js +127 -92
- package/dist/hooks/use-frame-rate.esm.js +56 -37
- package/dist/hooks/use-frame-rate.js +56 -37
- package/dist/hooks/use-gestures.esm.js +96 -72
- package/dist/hooks/use-gestures.js +96 -72
- package/dist/hooks/use-hardware-acceleration.esm.js +65 -37
- package/dist/hooks/use-hardware-acceleration.js +65 -37
- package/dist/hooks/use-input-accessibility.esm.js +157 -119
- package/dist/hooks/use-input-accessibility.js +157 -119
- package/dist/hooks/use-input-performance.esm.js +139 -104
- package/dist/hooks/use-input-performance.js +139 -104
- package/dist/hooks/use-layout-performance.esm.js +50 -29
- package/dist/hooks/use-layout-performance.js +50 -29
- package/dist/hooks/use-loading-accessibility.esm.js +209 -169
- package/dist/hooks/use-loading-accessibility.js +209 -169
- package/dist/hooks/use-loading-performance.esm.js +117 -93
- package/dist/hooks/use-loading-performance.js +117 -93
- package/dist/hooks/use-memory-usage.esm.js +57 -38
- package/dist/hooks/use-memory-usage.js +57 -38
- package/dist/hooks/use-mobile-form-layout.esm.js +111 -74
- package/dist/hooks/use-mobile-form-layout.js +111 -74
- package/dist/hooks/use-mobile-form-validation.esm.js +211 -144
- package/dist/hooks/use-mobile-form-validation.js +211 -144
- package/dist/hooks/use-mobile-keyboard-optimization.esm.js +154 -113
- package/dist/hooks/use-mobile-keyboard-optimization.js +154 -113
- package/dist/hooks/use-mobile-layout.esm.js +73 -51
- package/dist/hooks/use-mobile-layout.js +73 -51
- package/dist/hooks/use-mobile-optimization.esm.js +72 -44
- package/dist/hooks/use-mobile-optimization.js +72 -44
- package/dist/hooks/use-mobile-skeleton.esm.js +97 -64
- package/dist/hooks/use-mobile-skeleton.js +97 -64
- package/dist/hooks/use-mobile-touch.esm.js +128 -93
- package/dist/hooks/use-mobile-touch.js +128 -93
- package/dist/hooks/use-performance-throttling.esm.js +72 -48
- package/dist/hooks/use-performance-throttling.js +72 -48
- package/dist/hooks/use-performance.esm.js +90 -52
- package/dist/hooks/use-performance.js +90 -52
- package/dist/hooks/use-reusable-architecture.esm.js +94 -65
- package/dist/hooks/use-reusable-architecture.js +94 -65
- package/dist/hooks/use-semantic-input-types.esm.js +166 -124
- package/dist/hooks/use-semantic-input-types.js +166 -124
- package/dist/hooks/use-semantic-input.esm.js +178 -126
- package/dist/hooks/use-semantic-input.js +178 -126
- package/dist/hooks/use-tablet-layout.esm.js +67 -38
- package/dist/hooks/use-tablet-layout.js +67 -38
- package/dist/hooks/use-touch-friendly-input.esm.js +193 -149
- package/dist/hooks/use-touch-friendly-input.js +193 -149
- package/dist/hooks/use-touch-friendly-interface.esm.js +99 -67
- package/dist/hooks/use-touch-friendly-interface.js +99 -67
- package/dist/hooks/use-touch-optimization.esm.js +99 -72
- package/dist/hooks/use-touch-optimization.js +99 -72
- package/dist/index.esm.js +289 -280
- package/dist/index.js +289 -280
- package/dist/lib/utils.esm.js +1 -1
- package/dist/lib/utils.js +1 -1
- package/dist/plugins/theme-css-generator.esm.js +104 -55
- package/dist/plugins/theme-css-generator.js +104 -55
- package/dist/provider.esm.js +4 -4
- package/dist/provider.js +4 -4
- package/dist/styles.css +1 -1
- package/dist/theme.esm.js +633 -468
- package/dist/theme.js +633 -468
- package/dist/themes/ThemeContext.esm.js +15 -15
- package/dist/themes/ThemeContext.js +15 -15
- package/dist/themes/ThemeProvider.esm.js +25 -22
- package/dist/themes/ThemeProvider.js +25 -22
- package/dist/themes/accessibility.esm.js +147 -108
- package/dist/themes/accessibility.js +147 -108
- package/dist/themes/aria-patterns.esm.js +198 -162
- package/dist/themes/aria-patterns.js +198 -162
- package/dist/themes/base-themes.esm.js +14 -11
- package/dist/themes/base-themes.js +14 -11
- package/dist/themes/colorManager.esm.js +101 -83
- package/dist/themes/colorManager.js +101 -83
- package/dist/themes/examples/dark-theme.esm.js +133 -103
- package/dist/themes/examples/dark-theme.js +133 -103
- package/dist/themes/examples/minimal-theme.esm.js +83 -61
- package/dist/themes/examples/minimal-theme.js +83 -61
- package/dist/themes/focus-management.esm.js +202 -143
- package/dist/themes/focus-management.js +202 -143
- package/dist/themes/fontLoader.esm.js +28 -19
- package/dist/themes/fontLoader.js +28 -19
- package/dist/themes/high-contrast.esm.js +152 -104
- package/dist/themes/high-contrast.js +152 -104
- package/dist/themes/inheritance.esm.js +35 -27
- package/dist/themes/inheritance.js +35 -27
- package/dist/themes/keyboard-navigation.esm.js +152 -123
- package/dist/themes/keyboard-navigation.js +152 -123
- package/dist/themes/motion-reduction.esm.js +193 -133
- package/dist/themes/motion-reduction.js +193 -133
- package/dist/themes/navigation.esm.js +146 -146
- package/dist/themes/navigation.js +146 -146
- package/dist/themes/screen-reader.esm.js +159 -94
- package/dist/themes/screen-reader.js +159 -94
- package/dist/themes/systemThemeDetector.esm.js +42 -34
- package/dist/themes/systemThemeDetector.js +42 -34
- package/dist/themes/themeCSSUpdater.esm.js +21 -9
- package/dist/themes/themeCSSUpdater.js +21 -9
- package/dist/themes/themePersistence.esm.js +68 -47
- package/dist/themes/themePersistence.js +68 -47
- package/dist/themes/themes/stan-design.esm.js +633 -468
- package/dist/themes/themes/stan-design.js +633 -468
- package/dist/themes/types.esm.js +301 -287
- package/dist/themes/types.js +301 -287
- package/dist/themes/useSystemTheme.esm.js +4 -4
- package/dist/themes/useSystemTheme.js +4 -4
- package/dist/themes/useTheme.esm.js +4 -4
- package/dist/themes/useTheme.js +4 -4
- package/dist/themes/validation.esm.js +128 -77
- package/dist/themes/validation.js +128 -77
- package/dist/tokens/index.esm.js +15 -4
- package/dist/tokens/index.js +15 -4
- package/dist/tokens/tokenExporter.esm.js +87 -61
- package/dist/tokens/tokenExporter.js +87 -61
- package/dist/tokens/tokenGenerator.esm.js +86 -77
- package/dist/tokens/tokenGenerator.js +86 -77
- package/dist/tokens/tokenManager.esm.js +64 -51
- package/dist/tokens/tokenManager.js +64 -51
- package/dist/tokens/tokenValidator.esm.js +193 -147
- package/dist/tokens/tokenValidator.js +193 -147
- package/dist/tokens/types.esm.js +49 -35
- package/dist/tokens/types.js +49 -35
- package/dist/utils/bundle-analyzer.esm.js +83 -65
- package/dist/utils/bundle-analyzer.js +83 -65
- package/dist/utils/bundle-splitting.esm.js +142 -117
- package/dist/utils/bundle-splitting.js +142 -117
- package/dist/utils/lazy-loading.esm.js +132 -106
- package/dist/utils/lazy-loading.js +132 -106
- package/dist/utils/performance-monitor.esm.js +170 -129
- package/dist/utils/performance-monitor.js +170 -129
- package/dist/utils/tree-shaking.esm.js +69 -61
- package/dist/utils/tree-shaking.js +69 -61
- package/package.json +1 -1
- package/src/index.ts +146 -146
|
@@ -1,94 +1,124 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, useRef, useMemo } from 'react'
|
|
2
2
|
|
|
3
3
|
export interface ValidationRule {
|
|
4
|
-
type
|
|
4
|
+
type: 'required' | 'email' | 'minLength' | 'maxLength' | 'pattern' | 'custom'
|
|
5
|
+
value?: string | number | RegExp
|
|
6
|
+
message: string
|
|
7
|
+
validator?: (value: any) => boolean | Promise<boolean>
|
|
5
8
|
}
|
|
6
9
|
|
|
7
10
|
export interface ValidationState {
|
|
8
|
-
isValid
|
|
9
|
-
|
|
11
|
+
isValid: boolean
|
|
12
|
+
errors: string[]
|
|
13
|
+
isDirty: boolean
|
|
14
|
+
isTouched: boolean
|
|
15
|
+
isSubmitting: boolean
|
|
16
|
+
isSubmitted: boolean
|
|
17
|
+
}
|
|
10
18
|
|
|
11
19
|
export interface FormField {
|
|
12
|
-
name
|
|
13
|
-
|
|
20
|
+
name: string
|
|
21
|
+
value: any
|
|
22
|
+
rules: ValidationRule[]
|
|
23
|
+
validationState: ValidationState
|
|
24
|
+
}
|
|
14
25
|
|
|
15
26
|
export interface MobileFormValidationConfig {
|
|
16
|
-
enableTouchFeedback
|
|
27
|
+
enableTouchFeedback: boolean
|
|
28
|
+
enableHapticFeedback: boolean
|
|
29
|
+
enableSoundFeedback: boolean
|
|
30
|
+
validationDelay: number
|
|
31
|
+
enablePerformanceOptimization: boolean
|
|
32
|
+
maxValidationRetries: number
|
|
33
|
+
}
|
|
17
34
|
|
|
18
35
|
export interface ValidationCallbacks {
|
|
19
|
-
onValidationStart
|
|
20
|
-
onValidationComplete
|
|
21
|
-
onFormSubmit
|
|
22
|
-
onValidationError
|
|
23
|
-
onValidationSuccess
|
|
36
|
+
onValidationStart?: (fieldName: string) => void
|
|
37
|
+
onValidationComplete?: (fieldName: string, isValid: boolean, errors: string[]) => void
|
|
38
|
+
onFormSubmit?: (formData: Record<string, any>, isValid: boolean) => void
|
|
39
|
+
onValidationError?: (fieldName: string, errors: string[]) => void
|
|
40
|
+
onValidationSuccess?: (fieldName: string) => void
|
|
24
41
|
}
|
|
25
42
|
|
|
26
43
|
export interface MobileFormValidationState {
|
|
27
|
-
fields, FormField>
|
|
28
|
-
overallValidation
|
|
44
|
+
fields: Record<string, FormField>
|
|
45
|
+
overallValidation: ValidationState
|
|
46
|
+
isOptimized: boolean
|
|
47
|
+
performanceMetrics: {
|
|
48
|
+
validationCount: number
|
|
49
|
+
averageValidationTime: number
|
|
50
|
+
lastValidationTime: number
|
|
51
|
+
}
|
|
29
52
|
}
|
|
30
53
|
|
|
31
54
|
export const useMobileFormValidation = (
|
|
32
|
-
initialFields, Omit<FormField, 'validationState'>>,
|
|
33
|
-
callbacks= {},
|
|
34
|
-
config= {}
|
|
55
|
+
initialFields: Record<string, Omit<FormField, 'validationState'>>,
|
|
56
|
+
callbacks: ValidationCallbacks = {},
|
|
57
|
+
config: Partial<MobileFormValidationConfig> = {}
|
|
35
58
|
) => {
|
|
36
|
-
const defaultConfig= {
|
|
37
|
-
enableTouchFeedback,
|
|
38
|
-
enableHapticFeedback,
|
|
39
|
-
enableSoundFeedback,
|
|
40
|
-
validationDelay,
|
|
41
|
-
enablePerformanceOptimization,
|
|
42
|
-
maxValidationRetries,
|
|
59
|
+
const defaultConfig: MobileFormValidationConfig = {
|
|
60
|
+
enableTouchFeedback: true,
|
|
61
|
+
enableHapticFeedback: true,
|
|
62
|
+
enableSoundFeedback: false,
|
|
63
|
+
validationDelay: 300,
|
|
64
|
+
enablePerformanceOptimization: true,
|
|
65
|
+
maxValidationRetries: 3,
|
|
43
66
|
...config
|
|
44
67
|
}
|
|
45
68
|
|
|
46
69
|
const [validationState, setValidationState] = useState<MobileFormValidationState>({
|
|
47
|
-
fields).reduce((acc, fieldName) => {
|
|
70
|
+
fields: Object.keys(initialFields).reduce((acc, fieldName) => {
|
|
48
71
|
acc[fieldName] = {
|
|
49
72
|
...initialFields[fieldName],
|
|
50
|
-
validationState
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
validationState: {
|
|
74
|
+
isValid: true,
|
|
75
|
+
errors: [],
|
|
76
|
+
isDirty: false,
|
|
77
|
+
isTouched: false,
|
|
78
|
+
isSubmitting: false,
|
|
79
|
+
isSubmitted: false
|
|
80
|
+
}
|
|
56
81
|
}
|
|
57
82
|
return acc
|
|
58
83
|
}, {} as Record<string, FormField>),
|
|
59
|
-
overallValidation
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
84
|
+
overallValidation: {
|
|
85
|
+
isValid: true,
|
|
86
|
+
errors: [],
|
|
87
|
+
isDirty: false,
|
|
88
|
+
isTouched: false,
|
|
89
|
+
isSubmitting: false,
|
|
90
|
+
isSubmitted: false
|
|
91
|
+
},
|
|
92
|
+
isOptimized: false,
|
|
93
|
+
performanceMetrics: {
|
|
94
|
+
validationCount: 0,
|
|
95
|
+
averageValidationTime: 0,
|
|
96
|
+
lastValidationTime: 0
|
|
97
|
+
}
|
|
69
98
|
})
|
|
70
99
|
|
|
71
100
|
const validationTimersRef = useRef<Record<string, NodeJS.Timeout>>({})
|
|
72
101
|
const validationRetryCountRef = useRef<Record<string, number>>({})
|
|
73
102
|
|
|
74
103
|
// Trigger haptic feedback
|
|
75
|
-
const triggerHapticFeedback = useCallback((intensity= 'medium') => {
|
|
104
|
+
const triggerHapticFeedback = useCallback((intensity: 'light' | 'medium' | 'strong' = 'medium') => {
|
|
76
105
|
if (!defaultConfig.enableHapticFeedback || !('vibrate' in navigator)) return
|
|
77
106
|
|
|
78
107
|
const vibrationPattern = {
|
|
79
|
-
light,
|
|
80
|
-
medium,
|
|
81
|
-
strong
|
|
108
|
+
light: 20,
|
|
109
|
+
medium: 50,
|
|
110
|
+
strong: 100
|
|
111
|
+
}
|
|
82
112
|
|
|
83
113
|
try {
|
|
84
114
|
navigator.vibrate(vibrationPattern[intensity])
|
|
85
115
|
} catch (error) {
|
|
86
|
-
console.warn('Haptic feedback not supported, error)
|
|
116
|
+
console.warn('Haptic feedback not supported:', error)
|
|
87
117
|
}
|
|
88
118
|
}, [defaultConfig.enableHapticFeedback])
|
|
89
119
|
|
|
90
120
|
// Trigger sound feedback
|
|
91
|
-
const triggerSoundFeedback = useCallback((type= 'success') => {
|
|
121
|
+
const triggerSoundFeedback = useCallback((type: 'success' | 'error' = 'success') => {
|
|
92
122
|
if (!defaultConfig.enableSoundFeedback || !('AudioContext' in window)) return
|
|
93
123
|
|
|
94
124
|
try {
|
|
@@ -100,8 +130,8 @@ export const useMobileFormValidation = (
|
|
|
100
130
|
gainNode.connect(audioContext.destination)
|
|
101
131
|
|
|
102
132
|
const soundConfig = {
|
|
103
|
-
success, duration, volume},
|
|
104
|
-
error, duration, volume}
|
|
133
|
+
success: { frequency: 800, duration: 0.1, volume: 0.1 },
|
|
134
|
+
error: { frequency: 400, duration: 0.2, volume: 0.15 }
|
|
105
135
|
}
|
|
106
136
|
|
|
107
137
|
const config = soundConfig[type]
|
|
@@ -111,17 +141,17 @@ export const useMobileFormValidation = (
|
|
|
111
141
|
oscillator.start(audioContext.currentTime)
|
|
112
142
|
oscillator.stop(audioContext.currentTime + config.duration)
|
|
113
143
|
} catch (error) {
|
|
114
|
-
console.warn('Sound feedback not supported, error)
|
|
144
|
+
console.warn('Sound feedback not supported:', error)
|
|
115
145
|
}
|
|
116
146
|
}, [defaultConfig.enableSoundFeedback])
|
|
117
147
|
|
|
118
148
|
// Validate a single field
|
|
119
149
|
const validateField = useCallback(async (
|
|
120
|
-
fieldName,
|
|
121
|
-
value,
|
|
122
|
-
rules]
|
|
123
|
-
); errors] }> => {
|
|
124
|
-
const errors] = []
|
|
150
|
+
fieldName: string,
|
|
151
|
+
value: any,
|
|
152
|
+
rules: ValidationRule[]
|
|
153
|
+
): Promise<{ isValid: boolean; errors: string[] }> => {
|
|
154
|
+
const errors: string[] = []
|
|
125
155
|
const startTime = performance.now()
|
|
126
156
|
|
|
127
157
|
for (const rule of rules) {
|
|
@@ -129,29 +159,35 @@ export const useMobileFormValidation = (
|
|
|
129
159
|
|
|
130
160
|
try {
|
|
131
161
|
switch (rule.type) {
|
|
132
|
-
case 'required'
|
|
162
|
+
case 'required':
|
|
163
|
+
isValid = value !== null && value !== undefined && value !== ''
|
|
133
164
|
break
|
|
134
165
|
|
|
135
|
-
case 'email'
|
|
166
|
+
case 'email':
|
|
167
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
136
168
|
isValid = emailRegex.test(String(value))
|
|
137
169
|
break
|
|
138
170
|
|
|
139
|
-
case 'minLength'
|
|
171
|
+
case 'minLength':
|
|
172
|
+
isValid = String(value).length >= (rule.value as number)
|
|
140
173
|
break
|
|
141
174
|
|
|
142
|
-
case 'maxLength'
|
|
175
|
+
case 'maxLength':
|
|
176
|
+
isValid = String(value).length <= (rule.value as number)
|
|
143
177
|
break
|
|
144
178
|
|
|
145
|
-
case 'pattern'
|
|
179
|
+
case 'pattern':
|
|
180
|
+
if (rule.value instanceof RegExp) {
|
|
146
181
|
isValid = rule.value.test(String(value))
|
|
147
182
|
}
|
|
148
183
|
break
|
|
149
184
|
|
|
150
|
-
case 'custom'
|
|
185
|
+
case 'custom':
|
|
186
|
+
if (rule.validator) {
|
|
151
187
|
try {
|
|
152
188
|
isValid = await rule.validator(value)
|
|
153
189
|
} catch (error) {
|
|
154
|
-
console.error('Custom validation error, error)
|
|
190
|
+
console.error('Custom validation error:', error)
|
|
155
191
|
isValid = false
|
|
156
192
|
}
|
|
157
193
|
}
|
|
@@ -162,7 +198,7 @@ export const useMobileFormValidation = (
|
|
|
162
198
|
errors.push(rule.message)
|
|
163
199
|
}
|
|
164
200
|
} catch (error) {
|
|
165
|
-
console.error(`Validation error for rule ${rule.type} in field ${fieldName}
|
|
201
|
+
console.error(`Validation error for rule ${rule.type} in field ${fieldName}:`, error)
|
|
166
202
|
errors.push(rule.message)
|
|
167
203
|
}
|
|
168
204
|
}
|
|
@@ -173,19 +209,21 @@ export const useMobileFormValidation = (
|
|
|
173
209
|
// Update performance metrics
|
|
174
210
|
setValidationState(prev => ({
|
|
175
211
|
...prev,
|
|
176
|
-
performanceMetrics
|
|
177
|
-
|
|
178
|
-
|
|
212
|
+
performanceMetrics: {
|
|
213
|
+
validationCount: prev.performanceMetrics.validationCount + 1,
|
|
214
|
+
averageValidationTime: (prev.performanceMetrics.averageValidationTime * prev.performanceMetrics.validationCount + validationTime) / (prev.performanceMetrics.validationCount + 1),
|
|
215
|
+
lastValidationTime: validationTime
|
|
216
|
+
}
|
|
179
217
|
}))
|
|
180
218
|
|
|
181
|
-
return { isValid=== 0, errors }
|
|
219
|
+
return { isValid: errors.length === 0, errors }
|
|
182
220
|
}, [])
|
|
183
221
|
|
|
184
222
|
// Debounced field validation
|
|
185
223
|
const debouncedValidateField = useCallback((
|
|
186
|
-
fieldName,
|
|
187
|
-
value,
|
|
188
|
-
rules]
|
|
224
|
+
fieldName: string,
|
|
225
|
+
value: any,
|
|
226
|
+
rules: ValidationRule[]
|
|
189
227
|
) => {
|
|
190
228
|
// Clear existing timer
|
|
191
229
|
if (validationTimersRef.current[fieldName]) {
|
|
@@ -201,12 +239,16 @@ export const useMobileFormValidation = (
|
|
|
201
239
|
|
|
202
240
|
setValidationState(prev => ({
|
|
203
241
|
...prev,
|
|
204
|
-
fields
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
242
|
+
fields: {
|
|
243
|
+
...prev.fields,
|
|
244
|
+
[fieldName]: {
|
|
245
|
+
...prev.fields[fieldName],
|
|
246
|
+
validationState: {
|
|
247
|
+
...prev.fields[fieldName].validationState,
|
|
248
|
+
isValid: result.isValid,
|
|
249
|
+
errors: result.errors,
|
|
250
|
+
isDirty: true
|
|
251
|
+
}
|
|
210
252
|
}
|
|
211
253
|
}
|
|
212
254
|
}))
|
|
@@ -223,7 +265,7 @@ export const useMobileFormValidation = (
|
|
|
223
265
|
|
|
224
266
|
callbacks.onValidationComplete?.(fieldName, result.isValid, result.errors)
|
|
225
267
|
} catch (error) {
|
|
226
|
-
console.error(`Validation error for field ${fieldName}
|
|
268
|
+
console.error(`Validation error for field ${fieldName}:`, error)
|
|
227
269
|
|
|
228
270
|
// Retry validation if enabled
|
|
229
271
|
const retryCount = validationRetryCountRef.current[fieldName] || 0
|
|
@@ -237,17 +279,21 @@ export const useMobileFormValidation = (
|
|
|
237
279
|
|
|
238
280
|
// Update field value and trigger validation
|
|
239
281
|
const updateField = useCallback((
|
|
240
|
-
fieldName,
|
|
241
|
-
value,
|
|
242
|
-
shouldValidate= true
|
|
282
|
+
fieldName: string,
|
|
283
|
+
value: any,
|
|
284
|
+
shouldValidate: boolean = true
|
|
243
285
|
) => {
|
|
244
286
|
setValidationState(prev => ({
|
|
245
287
|
...prev,
|
|
246
|
-
fields
|
|
247
|
-
|
|
288
|
+
fields: {
|
|
289
|
+
...prev.fields,
|
|
290
|
+
[fieldName]: {
|
|
291
|
+
...prev.fields[fieldName],
|
|
248
292
|
value,
|
|
249
|
-
validationState
|
|
250
|
-
|
|
293
|
+
validationState: {
|
|
294
|
+
...prev.fields[fieldName].validationState,
|
|
295
|
+
isTouched: true
|
|
296
|
+
}
|
|
251
297
|
}
|
|
252
298
|
}
|
|
253
299
|
}))
|
|
@@ -258,20 +304,24 @@ export const useMobileFormValidation = (
|
|
|
258
304
|
}, [validationState.fields, debouncedValidateField])
|
|
259
305
|
|
|
260
306
|
// Touch field (mark as touched without validation)
|
|
261
|
-
const touchField = useCallback((fieldName) => {
|
|
307
|
+
const touchField = useCallback((fieldName: string) => {
|
|
262
308
|
setValidationState(prev => ({
|
|
263
309
|
...prev,
|
|
264
|
-
fields
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
310
|
+
fields: {
|
|
311
|
+
...prev.fields,
|
|
312
|
+
[fieldName]: {
|
|
313
|
+
...prev.fields[fieldName],
|
|
314
|
+
validationState: {
|
|
315
|
+
...prev.fields[fieldName].validationState,
|
|
316
|
+
isTouched: true
|
|
317
|
+
}
|
|
268
318
|
}
|
|
269
319
|
}
|
|
270
320
|
}))
|
|
271
321
|
}, [])
|
|
272
322
|
|
|
273
323
|
// Validate all fields
|
|
274
|
-
const validateAllFields = useCallback(async ()=> {
|
|
324
|
+
const validateAllFields = useCallback(async (): Promise<boolean> => {
|
|
275
325
|
const fieldNames = Object.keys(validationState.fields)
|
|
276
326
|
const validationPromises = fieldNames.map(fieldName => {
|
|
277
327
|
const field = validationState.fields[fieldName]
|
|
@@ -285,25 +335,29 @@ export const useMobileFormValidation = (
|
|
|
285
335
|
|
|
286
336
|
setValidationState(prev => ({
|
|
287
337
|
...prev,
|
|
288
|
-
overallValidation
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
338
|
+
overallValidation: {
|
|
339
|
+
...prev.overallValidation,
|
|
340
|
+
isValid: allValid,
|
|
341
|
+
errors: allErrors,
|
|
342
|
+
isDirty: true
|
|
343
|
+
}
|
|
292
344
|
}))
|
|
293
345
|
|
|
294
346
|
return allValid
|
|
295
347
|
} catch (error) {
|
|
296
|
-
console.error('Validation error, error)
|
|
348
|
+
console.error('Validation error:', error)
|
|
297
349
|
return false
|
|
298
350
|
}
|
|
299
351
|
}, [validationState.fields, validateField])
|
|
300
352
|
|
|
301
353
|
// Submit form
|
|
302
|
-
const submitForm = useCallback(async (); data, any>; errors] }> => {
|
|
354
|
+
const submitForm = useCallback(async (): Promise<{ success: boolean; data: Record<string, any>; errors: string[] }> => {
|
|
303
355
|
setValidationState(prev => ({
|
|
304
356
|
...prev,
|
|
305
|
-
overallValidation
|
|
306
|
-
|
|
357
|
+
overallValidation: {
|
|
358
|
+
...prev.overallValidation,
|
|
359
|
+
isSubmitting: true
|
|
360
|
+
}
|
|
307
361
|
}))
|
|
308
362
|
|
|
309
363
|
try {
|
|
@@ -317,39 +371,45 @@ export const useMobileFormValidation = (
|
|
|
317
371
|
|
|
318
372
|
setValidationState(prev => ({
|
|
319
373
|
...prev,
|
|
320
|
-
overallValidation
|
|
321
|
-
|
|
322
|
-
|
|
374
|
+
overallValidation: {
|
|
375
|
+
...prev.overallValidation,
|
|
376
|
+
isSubmitted: true,
|
|
377
|
+
isSubmitting: false
|
|
378
|
+
}
|
|
323
379
|
}))
|
|
324
380
|
|
|
325
381
|
callbacks.onFormSubmit?.(formData, true)
|
|
326
382
|
triggerHapticFeedback('medium')
|
|
327
383
|
triggerSoundFeedback('success')
|
|
328
384
|
|
|
329
|
-
return { success, data, errors] }
|
|
385
|
+
return { success: true, data: formData, errors: [] }
|
|
330
386
|
} else {
|
|
331
387
|
setValidationState(prev => ({
|
|
332
388
|
...prev,
|
|
333
|
-
overallValidation
|
|
334
|
-
|
|
389
|
+
overallValidation: {
|
|
390
|
+
...prev.overallValidation,
|
|
391
|
+
isSubmitting: false
|
|
392
|
+
}
|
|
335
393
|
}))
|
|
336
394
|
|
|
337
395
|
callbacks.onFormSubmit?.({}, false)
|
|
338
396
|
triggerHapticFeedback('strong')
|
|
339
397
|
triggerSoundFeedback('error')
|
|
340
398
|
|
|
341
|
-
return { success, data}, errors}
|
|
399
|
+
return { success: false, data: {}, errors: validationState.overallValidation.errors }
|
|
342
400
|
}
|
|
343
401
|
} catch (error) {
|
|
344
|
-
console.error('Form submission error, error)
|
|
402
|
+
console.error('Form submission error:', error)
|
|
345
403
|
|
|
346
404
|
setValidationState(prev => ({
|
|
347
405
|
...prev,
|
|
348
|
-
overallValidation
|
|
349
|
-
|
|
406
|
+
overallValidation: {
|
|
407
|
+
...prev.overallValidation,
|
|
408
|
+
isSubmitting: false
|
|
409
|
+
}
|
|
350
410
|
}))
|
|
351
411
|
|
|
352
|
-
return { success, data}, errors] }
|
|
412
|
+
return { success: false, data: {}, errors: ['Form submission failed'] }
|
|
353
413
|
}
|
|
354
414
|
}, [validationState.fields, validationState.overallValidation.errors, validateAllFields, callbacks, triggerHapticFeedback, triggerSoundFeedback])
|
|
355
415
|
|
|
@@ -357,25 +417,29 @@ export const useMobileFormValidation = (
|
|
|
357
417
|
const resetForm = useCallback(() => {
|
|
358
418
|
setValidationState(prev => ({
|
|
359
419
|
...prev,
|
|
360
|
-
fields).reduce((acc, fieldName) => {
|
|
420
|
+
fields: Object.keys(prev.fields).reduce((acc, fieldName) => {
|
|
361
421
|
acc[fieldName] = {
|
|
362
422
|
...prev.fields[fieldName],
|
|
363
|
-
value].value,
|
|
364
|
-
validationState
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
423
|
+
value: initialFields[fieldName].value,
|
|
424
|
+
validationState: {
|
|
425
|
+
isValid: true,
|
|
426
|
+
errors: [],
|
|
427
|
+
isDirty: false,
|
|
428
|
+
isTouched: false,
|
|
429
|
+
isSubmitting: false,
|
|
430
|
+
isSubmitted: false
|
|
431
|
+
}
|
|
370
432
|
}
|
|
371
433
|
return acc
|
|
372
434
|
}, {} as Record<string, FormField>),
|
|
373
|
-
overallValidation
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
435
|
+
overallValidation: {
|
|
436
|
+
isValid: true,
|
|
437
|
+
errors: [],
|
|
438
|
+
isDirty: false,
|
|
439
|
+
isTouched: false,
|
|
440
|
+
isSubmitting: false,
|
|
441
|
+
isSubmitted: false
|
|
442
|
+
}
|
|
379
443
|
}))
|
|
380
444
|
|
|
381
445
|
// Clear validation timers
|
|
@@ -385,14 +449,15 @@ export const useMobileFormValidation = (
|
|
|
385
449
|
}, [initialFields])
|
|
386
450
|
|
|
387
451
|
// Get field validation state
|
|
388
|
-
const getFieldValidation = useCallback((fieldName) => {
|
|
452
|
+
const getFieldValidation = useCallback((fieldName: string) => {
|
|
389
453
|
return validationState.fields[fieldName]?.validationState || {
|
|
390
|
-
isValid,
|
|
391
|
-
errors],
|
|
392
|
-
isDirty,
|
|
393
|
-
isTouched,
|
|
394
|
-
isSubmitting,
|
|
395
|
-
isSubmitted
|
|
454
|
+
isValid: true,
|
|
455
|
+
errors: [],
|
|
456
|
+
isDirty: false,
|
|
457
|
+
isTouched: false,
|
|
458
|
+
isSubmitting: false,
|
|
459
|
+
isSubmitted: false
|
|
460
|
+
}
|
|
396
461
|
}, [validationState.fields])
|
|
397
462
|
|
|
398
463
|
// Check if form is valid
|
|
@@ -416,7 +481,7 @@ export const useMobileFormValidation = (
|
|
|
416
481
|
validationState,
|
|
417
482
|
updateField,
|
|
418
483
|
touchField,
|
|
419
|
-
validateField,
|
|
484
|
+
validateField: debouncedValidateField,
|
|
420
485
|
validateAllFields,
|
|
421
486
|
submitForm,
|
|
422
487
|
resetForm,
|
|
@@ -429,23 +494,25 @@ export const useMobileFormValidation = (
|
|
|
429
494
|
}
|
|
430
495
|
|
|
431
496
|
// Convenience hook for basic form validation
|
|
432
|
-
export const useBasicFormValidation = (initialFields, Omit<FormField, 'validationState'>>) => {
|
|
497
|
+
export const useBasicFormValidation = (initialFields: Record<string, Omit<FormField, 'validationState'>>) => {
|
|
433
498
|
return useMobileFormValidation(initialFields, {}, {
|
|
434
|
-
enableTouchFeedback,
|
|
435
|
-
enableHapticFeedback,
|
|
436
|
-
enableSoundFeedback,
|
|
437
|
-
validationDelay,
|
|
438
|
-
enablePerformanceOptimization,
|
|
439
|
-
maxValidationRetries
|
|
499
|
+
enableTouchFeedback: true,
|
|
500
|
+
enableHapticFeedback: false,
|
|
501
|
+
enableSoundFeedback: false,
|
|
502
|
+
validationDelay: 500,
|
|
503
|
+
enablePerformanceOptimization: false,
|
|
504
|
+
maxValidationRetries: 1
|
|
505
|
+
})
|
|
440
506
|
}
|
|
441
507
|
|
|
442
508
|
// Convenience hook for enhanced form validation
|
|
443
|
-
export const useEnhancedFormValidation = (initialFields, Omit<FormField, 'validationState'>>) => {
|
|
509
|
+
export const useEnhancedFormValidation = (initialFields: Record<string, Omit<FormField, 'validationState'>>) => {
|
|
444
510
|
return useMobileFormValidation(initialFields, {}, {
|
|
445
|
-
enableTouchFeedback,
|
|
446
|
-
enableHapticFeedback,
|
|
447
|
-
enableSoundFeedback,
|
|
448
|
-
validationDelay,
|
|
449
|
-
enablePerformanceOptimization,
|
|
450
|
-
maxValidationRetries
|
|
511
|
+
enableTouchFeedback: true,
|
|
512
|
+
enableHapticFeedback: true,
|
|
513
|
+
enableSoundFeedback: true,
|
|
514
|
+
validationDelay: 300,
|
|
515
|
+
enablePerformanceOptimization: true,
|
|
516
|
+
maxValidationRetries: 3
|
|
517
|
+
})
|
|
451
518
|
}
|