@rakeyshgidwani/roger-ui-bank-theme-stan-design 0.1.4 → 0.1.6
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,543 @@
|
|
|
1
|
+
import type { ThemeTokens, DesignToken, TokenType } from './types';
|
|
2
|
+
|
|
3
|
+
export interface ValidationResult {
|
|
4
|
+
isValid: boolean;
|
|
5
|
+
errors: ValidationError[];
|
|
6
|
+
warnings: ValidationWarning[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface ValidationError {
|
|
10
|
+
path: string;
|
|
11
|
+
message: string;
|
|
12
|
+
severity: 'error' | 'critical';
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ValidationWarning {
|
|
16
|
+
path: string;
|
|
17
|
+
message: string;
|
|
18
|
+
suggestion?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class TokenValidator {
|
|
22
|
+
/**
|
|
23
|
+
* Validates a complete theme tokens object
|
|
24
|
+
*/
|
|
25
|
+
static validateTokens(tokens: ThemeTokens): ValidationResult {
|
|
26
|
+
const errors: ValidationError[] = [];
|
|
27
|
+
const warnings: ValidationWarning[] = [];
|
|
28
|
+
|
|
29
|
+
// Validate basic structure
|
|
30
|
+
if (!tokens.theme) {
|
|
31
|
+
errors.push({
|
|
32
|
+
path: 'theme',
|
|
33
|
+
message: 'Theme name is required',
|
|
34
|
+
severity: 'critical'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!tokens.version) {
|
|
39
|
+
errors.push({
|
|
40
|
+
path: 'version',
|
|
41
|
+
message: 'Theme version is required',
|
|
42
|
+
severity: 'critical'
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!tokens.tokens) {
|
|
47
|
+
errors.push({
|
|
48
|
+
path: 'tokens',
|
|
49
|
+
message: 'Tokens object is required',
|
|
50
|
+
severity: 'critical'
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Validate token categories
|
|
55
|
+
if (tokens.tokens) {
|
|
56
|
+
this.validateTokenCategory(tokens.tokens.color, 'color', errors, warnings);
|
|
57
|
+
this.validateTokenCategory(tokens.tokens.font, 'font', errors, warnings);
|
|
58
|
+
this.validateTokenCategory(tokens.tokens.spacing, 'spacing', errors, warnings);
|
|
59
|
+
this.validateTokenCategory(tokens.tokens.shadow, 'shadow', errors, warnings);
|
|
60
|
+
this.validateTokenCategory(tokens.tokens.transition, 'transition', errors, warnings);
|
|
61
|
+
this.validateTokenCategory(tokens.tokens.breakpoint, 'breakpoint', errors, warnings);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
isValid: errors.length === 0,
|
|
66
|
+
errors,
|
|
67
|
+
warnings
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Validates a specific token category
|
|
73
|
+
*/
|
|
74
|
+
private static validateTokenCategory(
|
|
75
|
+
category: any,
|
|
76
|
+
categoryName: string,
|
|
77
|
+
errors: ValidationError[],
|
|
78
|
+
warnings: ValidationWarning[]
|
|
79
|
+
) {
|
|
80
|
+
if (!category) return;
|
|
81
|
+
|
|
82
|
+
if (typeof category !== 'object') {
|
|
83
|
+
errors.push({
|
|
84
|
+
path: `tokens.${categoryName}`,
|
|
85
|
+
message: `${categoryName} category must be an object`,
|
|
86
|
+
severity: 'error'
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.validateTokenGroup(category, `tokens.${categoryName}`, errors, warnings);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Validates a token group recursively
|
|
96
|
+
*/
|
|
97
|
+
private static validateTokenGroup(
|
|
98
|
+
group: any,
|
|
99
|
+
path: string,
|
|
100
|
+
errors: ValidationError[],
|
|
101
|
+
warnings: ValidationWarning[]
|
|
102
|
+
) {
|
|
103
|
+
Object.entries(group).forEach(([key, value]) => {
|
|
104
|
+
const currentPath = `${path}.${key}`;
|
|
105
|
+
|
|
106
|
+
if (this.isToken(value)) {
|
|
107
|
+
this.validateToken(value as DesignToken, currentPath, errors, warnings);
|
|
108
|
+
} else if (typeof value === 'object' && value !== null) {
|
|
109
|
+
// Recursively validate nested groups
|
|
110
|
+
this.validateTokenGroup(value, currentPath, errors, warnings);
|
|
111
|
+
} else {
|
|
112
|
+
errors.push({
|
|
113
|
+
path: currentPath,
|
|
114
|
+
message: `Invalid token structure at ${currentPath}`,
|
|
115
|
+
severity: 'error'
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Validates an individual token
|
|
123
|
+
*/
|
|
124
|
+
private static validateToken(
|
|
125
|
+
token: DesignToken,
|
|
126
|
+
path: string,
|
|
127
|
+
errors: ValidationError[],
|
|
128
|
+
warnings: ValidationWarning[]
|
|
129
|
+
) {
|
|
130
|
+
// Check required properties
|
|
131
|
+
if (token.value === undefined || token.value === null) {
|
|
132
|
+
errors.push({
|
|
133
|
+
path,
|
|
134
|
+
message: 'Token value is required',
|
|
135
|
+
severity: 'error'
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!token.type) {
|
|
140
|
+
errors.push({
|
|
141
|
+
path,
|
|
142
|
+
message: 'Token type is required',
|
|
143
|
+
severity: 'error'
|
|
144
|
+
});
|
|
145
|
+
} else if (!this.isValidTokenType(token.type)) {
|
|
146
|
+
errors.push({
|
|
147
|
+
path,
|
|
148
|
+
message: `Invalid token type: ${token.type}`,
|
|
149
|
+
severity: 'error'
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Validate token type-specific values
|
|
154
|
+
this.validateTokenValue(token, path, errors, warnings);
|
|
155
|
+
|
|
156
|
+
// Check for missing descriptions (warning)
|
|
157
|
+
if (!token.description) {
|
|
158
|
+
warnings.push({
|
|
159
|
+
path,
|
|
160
|
+
message: 'Token description is missing',
|
|
161
|
+
suggestion: 'Add a description to improve token documentation'
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Check for missing tags (warning)
|
|
166
|
+
if (!token.tags || token.tags.length === 0) {
|
|
167
|
+
warnings.push({
|
|
168
|
+
path,
|
|
169
|
+
message: 'Token tags are missing',
|
|
170
|
+
suggestion: 'Add tags to improve token categorization and searchability'
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Validates token value based on type
|
|
177
|
+
*/
|
|
178
|
+
private static validateTokenValue(
|
|
179
|
+
token: DesignToken,
|
|
180
|
+
path: string,
|
|
181
|
+
errors: ValidationError[],
|
|
182
|
+
warnings: ValidationWarning[]
|
|
183
|
+
) {
|
|
184
|
+
switch (token.type) {
|
|
185
|
+
case 'color':
|
|
186
|
+
this.validateColorToken(token, path, errors, warnings);
|
|
187
|
+
break;
|
|
188
|
+
case 'fontFamily':
|
|
189
|
+
this.validateFontFamilyToken(token, path, errors, warnings);
|
|
190
|
+
break;
|
|
191
|
+
case 'fontSize':
|
|
192
|
+
this.validateFontSizeToken(token, path, errors, warnings);
|
|
193
|
+
break;
|
|
194
|
+
case 'fontWeight':
|
|
195
|
+
this.validateFontWeightToken(token, path, errors, warnings);
|
|
196
|
+
break;
|
|
197
|
+
case 'lineHeight':
|
|
198
|
+
this.validateLineHeightToken(token, path, errors, warnings);
|
|
199
|
+
break;
|
|
200
|
+
case 'spacing':
|
|
201
|
+
this.validateSpacingToken(token, path, errors, warnings);
|
|
202
|
+
break;
|
|
203
|
+
case 'shadow':
|
|
204
|
+
this.validateShadowToken(token, path, errors, warnings);
|
|
205
|
+
break;
|
|
206
|
+
case 'transition':
|
|
207
|
+
this.validateTransitionToken(token, path, errors, warnings);
|
|
208
|
+
break;
|
|
209
|
+
case 'breakpoint':
|
|
210
|
+
this.validateBreakpointToken(token, path, errors, warnings);
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Validates color tokens
|
|
217
|
+
*/
|
|
218
|
+
private static validateColorToken(
|
|
219
|
+
token: DesignToken,
|
|
220
|
+
path: string,
|
|
221
|
+
errors: ValidationError[],
|
|
222
|
+
warnings: ValidationWarning[]
|
|
223
|
+
) {
|
|
224
|
+
const value = token.value as string;
|
|
225
|
+
|
|
226
|
+
if (typeof value !== 'string') {
|
|
227
|
+
errors.push({
|
|
228
|
+
path,
|
|
229
|
+
message: 'Color token value must be a string',
|
|
230
|
+
severity: 'error'
|
|
231
|
+
});
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Check if it's a valid color format
|
|
236
|
+
if (!this.isValidColor(value)) {
|
|
237
|
+
errors.push({
|
|
238
|
+
path,
|
|
239
|
+
message: `Invalid color format: ${value}`,
|
|
240
|
+
severity: 'error'
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Check for semantic color consistency
|
|
245
|
+
if (token.category === 'color' && !(token as any).semantic) {
|
|
246
|
+
warnings.push({
|
|
247
|
+
path,
|
|
248
|
+
message: 'Semantic color missing semantic property',
|
|
249
|
+
suggestion: 'Add semantic property (primary, secondary, accent, success, warning, error, neutral)'
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Validates font family tokens
|
|
256
|
+
*/
|
|
257
|
+
private static validateFontFamilyToken(
|
|
258
|
+
token: DesignToken,
|
|
259
|
+
path: string,
|
|
260
|
+
errors: ValidationError[],
|
|
261
|
+
_warnings: ValidationWarning[]
|
|
262
|
+
) {
|
|
263
|
+
const value = token.value as string;
|
|
264
|
+
|
|
265
|
+
if (typeof value !== 'string') {
|
|
266
|
+
errors.push({
|
|
267
|
+
path,
|
|
268
|
+
message: 'Font family token value must be a string',
|
|
269
|
+
severity: 'error'
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (value.trim().length === 0) {
|
|
274
|
+
errors.push({
|
|
275
|
+
path,
|
|
276
|
+
message: 'Font family token value cannot be empty',
|
|
277
|
+
severity: 'error'
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Validates font size tokens
|
|
284
|
+
*/
|
|
285
|
+
private static validateFontSizeToken(
|
|
286
|
+
token: DesignToken,
|
|
287
|
+
path: string,
|
|
288
|
+
errors: ValidationError[],
|
|
289
|
+
_warnings: ValidationWarning[]
|
|
290
|
+
) {
|
|
291
|
+
const value = token.value as string | number;
|
|
292
|
+
|
|
293
|
+
if (typeof value === 'number') {
|
|
294
|
+
if (value <= 0) {
|
|
295
|
+
errors.push({
|
|
296
|
+
path,
|
|
297
|
+
message: 'Font size token value must be positive',
|
|
298
|
+
severity: 'error'
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
} else if (typeof value === 'string') {
|
|
302
|
+
if (!this.isValidCSSUnit(value)) {
|
|
303
|
+
errors.push({
|
|
304
|
+
path,
|
|
305
|
+
message: `Invalid font size unit: ${value}`,
|
|
306
|
+
severity: 'error'
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
errors.push({
|
|
311
|
+
path,
|
|
312
|
+
message: 'Font size token value must be a number or valid CSS unit string',
|
|
313
|
+
severity: 'error'
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Validates font weight tokens
|
|
320
|
+
*/
|
|
321
|
+
private static validateFontWeightToken(
|
|
322
|
+
token: DesignToken,
|
|
323
|
+
path: string,
|
|
324
|
+
errors: ValidationError[],
|
|
325
|
+
_warnings: ValidationWarning[]
|
|
326
|
+
) {
|
|
327
|
+
const value = token.value as string | number;
|
|
328
|
+
|
|
329
|
+
if (typeof value === 'number') {
|
|
330
|
+
if (value < 100 || value > 900 || value % 100 !== 0) {
|
|
331
|
+
errors.push({
|
|
332
|
+
path,
|
|
333
|
+
message: 'Font weight token value must be a multiple of 100 between 100 and 900',
|
|
334
|
+
severity: 'error'
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
} else if (typeof value === 'string') {
|
|
338
|
+
const validWeights = ['normal', 'bold', 'lighter', 'bolder'];
|
|
339
|
+
if (!validWeights.includes(value)) {
|
|
340
|
+
errors.push({
|
|
341
|
+
path,
|
|
342
|
+
message: `Invalid font weight value: ${value}`,
|
|
343
|
+
severity: 'error'
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
errors.push({
|
|
348
|
+
path,
|
|
349
|
+
message: 'Font weight token value must be a number or valid string',
|
|
350
|
+
severity: 'error'
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Validates line height tokens
|
|
357
|
+
*/
|
|
358
|
+
private static validateLineHeightToken(
|
|
359
|
+
token: DesignToken,
|
|
360
|
+
path: string,
|
|
361
|
+
errors: ValidationError[],
|
|
362
|
+
_warnings: ValidationWarning[]
|
|
363
|
+
) {
|
|
364
|
+
const value = token.value as string | number;
|
|
365
|
+
|
|
366
|
+
if (typeof value === 'number') {
|
|
367
|
+
if (value <= 0) {
|
|
368
|
+
errors.push({
|
|
369
|
+
path,
|
|
370
|
+
message: 'Line height token value must be positive',
|
|
371
|
+
severity: 'error'
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
} else if (typeof value === 'string') {
|
|
375
|
+
if (!this.isValidCSSUnit(value) && value !== 'normal') {
|
|
376
|
+
errors.push({
|
|
377
|
+
path,
|
|
378
|
+
message: `Invalid line height value: ${value}`,
|
|
379
|
+
severity: 'error'
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
errors.push({
|
|
384
|
+
path,
|
|
385
|
+
message: 'Line height token value must be a number or valid CSS unit string',
|
|
386
|
+
severity: 'error'
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Validates spacing tokens
|
|
393
|
+
*/
|
|
394
|
+
private static validateSpacingToken(
|
|
395
|
+
token: DesignToken,
|
|
396
|
+
path: string,
|
|
397
|
+
errors: ValidationError[],
|
|
398
|
+
_warnings: ValidationWarning[]
|
|
399
|
+
) {
|
|
400
|
+
const value = token.value as number;
|
|
401
|
+
|
|
402
|
+
if (typeof value !== 'number') {
|
|
403
|
+
errors.push({
|
|
404
|
+
path,
|
|
405
|
+
message: 'Spacing token value must be a number',
|
|
406
|
+
severity: 'error'
|
|
407
|
+
});
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (value < 0) {
|
|
412
|
+
errors.push({
|
|
413
|
+
path,
|
|
414
|
+
message: 'Spacing token value cannot be negative',
|
|
415
|
+
severity: 'error'
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Validates shadow tokens
|
|
422
|
+
*/
|
|
423
|
+
private static validateShadowToken(
|
|
424
|
+
token: DesignToken,
|
|
425
|
+
path: string,
|
|
426
|
+
errors: ValidationError[],
|
|
427
|
+
_warnings: ValidationWarning[]
|
|
428
|
+
) {
|
|
429
|
+
const value = token.value as string;
|
|
430
|
+
|
|
431
|
+
if (typeof value !== 'string') {
|
|
432
|
+
errors.push({
|
|
433
|
+
path,
|
|
434
|
+
message: 'Shadow token value must be a string',
|
|
435
|
+
severity: 'error'
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (value.trim().length === 0) {
|
|
440
|
+
errors.push({
|
|
441
|
+
path,
|
|
442
|
+
message: 'Shadow token value cannot be empty',
|
|
443
|
+
severity: 'error'
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Validates transition tokens
|
|
450
|
+
*/
|
|
451
|
+
private static validateTransitionToken(
|
|
452
|
+
token: DesignToken,
|
|
453
|
+
path: string,
|
|
454
|
+
errors: ValidationError[],
|
|
455
|
+
_warnings: ValidationWarning[]
|
|
456
|
+
) {
|
|
457
|
+
const value = token.value as string;
|
|
458
|
+
|
|
459
|
+
if (typeof value !== 'string') {
|
|
460
|
+
errors.push({
|
|
461
|
+
path,
|
|
462
|
+
message: 'Transition token value must be a string',
|
|
463
|
+
severity: 'error'
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (value.trim().length === 0) {
|
|
468
|
+
errors.push({
|
|
469
|
+
path,
|
|
470
|
+
message: 'Transition token value cannot be empty',
|
|
471
|
+
severity: 'error'
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Validates breakpoint tokens
|
|
478
|
+
*/
|
|
479
|
+
private static validateBreakpointToken(
|
|
480
|
+
token: DesignToken,
|
|
481
|
+
path: string,
|
|
482
|
+
errors: ValidationError[],
|
|
483
|
+
_warnings: ValidationWarning[]
|
|
484
|
+
) {
|
|
485
|
+
const value = token.value as number;
|
|
486
|
+
|
|
487
|
+
if (typeof value !== 'number') {
|
|
488
|
+
errors.push({
|
|
489
|
+
path,
|
|
490
|
+
message: 'Breakpoint token value must be a number',
|
|
491
|
+
severity: 'error'
|
|
492
|
+
});
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (value < 0) {
|
|
497
|
+
errors.push({
|
|
498
|
+
path,
|
|
499
|
+
message: 'Breakpoint token value cannot be negative',
|
|
500
|
+
severity: 'error'
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Checks if a value is a valid token
|
|
507
|
+
*/
|
|
508
|
+
private static isToken(value: any): value is DesignToken {
|
|
509
|
+
return value &&
|
|
510
|
+
typeof value === 'object' &&
|
|
511
|
+
'value' in value &&
|
|
512
|
+
'type' in value;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Checks if a token type is valid
|
|
517
|
+
*/
|
|
518
|
+
private static isValidTokenType(type: any): type is TokenType {
|
|
519
|
+
const validTypes: TokenType[] = [
|
|
520
|
+
'color', 'fontFamily', 'fontSize', 'fontWeight', 'lineHeight',
|
|
521
|
+
'letterSpacing', 'spacing', 'borderRadius', 'shadow', 'transition',
|
|
522
|
+
'zIndex', 'breakpoint'
|
|
523
|
+
];
|
|
524
|
+
return validTypes.includes(type);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Checks if a color value is valid
|
|
529
|
+
*/
|
|
530
|
+
private static isValidColor(color: string): boolean {
|
|
531
|
+
// Basic color validation - hex, rgb, rgba, named colors
|
|
532
|
+
const colorRegex = /^(#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})|rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)|rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)|transparent|currentColor)$/;
|
|
533
|
+
return colorRegex.test(color);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Checks if a CSS unit is valid
|
|
538
|
+
*/
|
|
539
|
+
private static isValidCSSUnit(value: string): boolean {
|
|
540
|
+
const unitRegex = /^[\d.]+(px|em|rem|vh|vw|%|ch|ex|in|cm|mm|pt|pc)$/;
|
|
541
|
+
return unitRegex.test(value);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export interface DesignToken {
|
|
2
|
+
value: string | number;
|
|
3
|
+
type: TokenType;
|
|
4
|
+
description?: string;
|
|
5
|
+
category?: string;
|
|
6
|
+
tags?: string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type TokenType =
|
|
10
|
+
| 'color'
|
|
11
|
+
| 'fontFamily'
|
|
12
|
+
| 'fontSize'
|
|
13
|
+
| 'fontWeight'
|
|
14
|
+
| 'lineHeight'
|
|
15
|
+
| 'letterSpacing'
|
|
16
|
+
| 'spacing'
|
|
17
|
+
| 'borderRadius'
|
|
18
|
+
| 'shadow'
|
|
19
|
+
| 'transition'
|
|
20
|
+
| 'zIndex'
|
|
21
|
+
| 'breakpoint';
|
|
22
|
+
|
|
23
|
+
export interface ColorToken extends DesignToken {
|
|
24
|
+
type: 'color';
|
|
25
|
+
value: string;
|
|
26
|
+
contrast?: {
|
|
27
|
+
light: string;
|
|
28
|
+
dark: string;
|
|
29
|
+
};
|
|
30
|
+
semantic?: 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'neutral';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface FontToken extends DesignToken {
|
|
34
|
+
type: 'fontFamily' | 'fontSize' | 'fontWeight' | 'lineHeight' | 'letterSpacing';
|
|
35
|
+
value: string | number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface SpacingToken extends DesignToken {
|
|
39
|
+
type: 'spacing';
|
|
40
|
+
value: number;
|
|
41
|
+
unit?: 'px' | 'rem' | 'em';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface ShadowToken extends DesignToken {
|
|
45
|
+
type: 'shadow';
|
|
46
|
+
value: string;
|
|
47
|
+
elevation?: 'low' | 'medium' | 'high';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface TransitionToken extends DesignToken {
|
|
51
|
+
type: 'transition';
|
|
52
|
+
value: string;
|
|
53
|
+
easing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface TokenGroup {
|
|
57
|
+
[key: string]: DesignToken | TokenGroup;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ThemeTokens {
|
|
61
|
+
theme: string;
|
|
62
|
+
version: string;
|
|
63
|
+
tokens: {
|
|
64
|
+
color?: TokenGroup;
|
|
65
|
+
font?: TokenGroup;
|
|
66
|
+
spacing?: TokenGroup;
|
|
67
|
+
shadow?: TokenGroup;
|
|
68
|
+
transition?: TokenGroup;
|
|
69
|
+
breakpoint?: TokenGroup;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface TokenExportOptions {
|
|
74
|
+
format: 'json' | 'css' | 'scss' | 'js' | 'ts';
|
|
75
|
+
platform?: 'web' | 'ios' | 'android' | 'figma';
|
|
76
|
+
includeMetadata?: boolean;
|
|
77
|
+
includeComments?: boolean;
|
|
78
|
+
}
|