svger-cli 2.0.0 → 2.0.2
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/dist/cli.js +0 -0
- package/dist/core/error-handler.d.ts +63 -0
- package/dist/core/error-handler.js +224 -0
- package/dist/core/framework-templates.d.ts +17 -0
- package/{src/core/framework-templates.ts → dist/core/framework-templates.js} +100 -137
- package/dist/core/logger.d.ts +22 -0
- package/dist/core/logger.js +85 -0
- package/dist/core/performance-engine.d.ts +67 -0
- package/dist/core/performance-engine.js +251 -0
- package/dist/core/plugin-manager.d.ts +56 -0
- package/dist/core/plugin-manager.js +189 -0
- package/dist/core/style-compiler.d.ts +88 -0
- package/dist/core/style-compiler.js +466 -0
- package/dist/core/template-manager.d.ts +64 -0
- package/{src/core/template-manager.ts → dist/core/template-manager.js} +172 -255
- package/dist/index.d.ts +151 -0
- package/{src/index.ts → dist/index.js} +30 -108
- package/dist/processors/svg-processor.d.ts +67 -0
- package/dist/processors/svg-processor.js +225 -0
- package/dist/services/config.d.ts +55 -0
- package/dist/services/config.js +209 -0
- package/dist/services/file-watcher.d.ts +54 -0
- package/dist/services/file-watcher.js +180 -0
- package/dist/services/svg-service.d.ts +81 -0
- package/dist/services/svg-service.js +383 -0
- package/dist/types/index.d.ts +140 -0
- package/dist/types/index.js +4 -0
- package/dist/utils/native.d.ts +74 -0
- package/dist/utils/native.js +305 -0
- package/package.json +9 -3
- package/.svgconfig.json +0 -3
- package/CODE_OF_CONDUCT.md +0 -79
- package/CONTRIBUTING.md +0 -146
- package/TESTING.md +0 -143
- package/cli-framework.test.js +0 -16
- package/cli-test-angular/Arrowbenddownleft.component.ts +0 -27
- package/cli-test-angular/Vite.component.ts +0 -27
- package/cli-test-angular/index.ts +0 -25
- package/cli-test-output/Arrowbenddownleft.vue +0 -33
- package/cli-test-output/Vite.vue +0 -33
- package/cli-test-output/index.ts +0 -25
- package/cli-test-react/Arrowbenddownleft.tsx +0 -39
- package/cli-test-react/Vite.tsx +0 -39
- package/cli-test-react/index.ts +0 -25
- package/cli-test-svelte/Arrowbenddownleft.svelte +0 -22
- package/cli-test-svelte/Vite.svelte +0 -22
- package/cli-test-svelte/index.ts +0 -25
- package/docs/ADR-SVG-INTRGRATION-METHODS-001.adr.md +0 -157
- package/docs/ADR-SVG-INTRGRATION-METHODS-002.adr.md +0 -550
- package/docs/FRAMEWORK-GUIDE.md +0 -768
- package/docs/IMPLEMENTATION-SUMMARY.md +0 -376
- package/docs/TDR-SVG-INTRGRATION-METHODS-001.tdr.md +0 -115
- package/frameworks.test.js +0 -170
- package/my-svgs/ArrowBendDownLeft.svg +0 -6
- package/my-svgs/vite.svg +0 -1
- package/src/builder.ts +0 -104
- package/src/clean.ts +0 -21
- package/src/cli.ts +0 -221
- package/src/config.ts +0 -81
- package/src/core/error-handler.ts +0 -303
- package/src/core/logger.ts +0 -104
- package/src/core/performance-engine.ts +0 -327
- package/src/core/plugin-manager.ts +0 -228
- package/src/core/style-compiler.ts +0 -605
- package/src/lock.ts +0 -74
- package/src/processors/svg-processor.ts +0 -288
- package/src/services/config.ts +0 -241
- package/src/services/file-watcher.ts +0 -218
- package/src/services/svg-service.ts +0 -468
- package/src/templates/ComponentTemplate.ts +0 -57
- package/src/types/index.ts +0 -169
- package/src/utils/native.ts +0 -352
- package/src/watch.ts +0 -88
- package/test-output-mulit/TestIcon-angular-module.component.ts +0 -26
- package/test-output-mulit/TestIcon-angular-standalone.component.ts +0 -27
- package/test-output-mulit/TestIcon-lit.ts +0 -35
- package/test-output-mulit/TestIcon-preact.tsx +0 -38
- package/test-output-mulit/TestIcon-react.tsx +0 -35
- package/test-output-mulit/TestIcon-solid.tsx +0 -27
- package/test-output-mulit/TestIcon-svelte.svelte +0 -22
- package/test-output-mulit/TestIcon-vanilla.ts +0 -37
- package/test-output-mulit/TestIcon-vue-composition.vue +0 -33
- package/test-output-mulit/TestIcon-vue-options.vue +0 -31
- package/tsconfig.json +0 -18
|
@@ -1,605 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Comprehensive styling system for SVG components
|
|
3
|
-
* Supports all CSS properties, responsive design, theming, and dynamic styling
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface StyleTheme {
|
|
7
|
-
name: string;
|
|
8
|
-
colors: Record<string, string>;
|
|
9
|
-
sizes: Record<string, number | string>;
|
|
10
|
-
spacing: Record<string, number | string>;
|
|
11
|
-
breakpoints?: Record<string, string>;
|
|
12
|
-
animations?: Record<string, string>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface ResponsiveValue<T> {
|
|
16
|
-
base: T;
|
|
17
|
-
sm?: T;
|
|
18
|
-
md?: T;
|
|
19
|
-
lg?: T;
|
|
20
|
-
xl?: T;
|
|
21
|
-
[key: string]: T | undefined;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface SVGStyleOptions {
|
|
25
|
-
// Basic styling
|
|
26
|
-
fill?: string | ResponsiveValue<string>;
|
|
27
|
-
stroke?: string | ResponsiveValue<string>;
|
|
28
|
-
strokeWidth?: number | string | ResponsiveValue<number | string>;
|
|
29
|
-
|
|
30
|
-
// Size and dimensions
|
|
31
|
-
width?: number | string | ResponsiveValue<number | string>;
|
|
32
|
-
height?: number | string | ResponsiveValue<number | string>;
|
|
33
|
-
size?: number | string | ResponsiveValue<number | string>; // shorthand for width & height
|
|
34
|
-
|
|
35
|
-
// Positioning and transform
|
|
36
|
-
transform?: string;
|
|
37
|
-
rotate?: number | string;
|
|
38
|
-
scale?: number | string;
|
|
39
|
-
translateX?: number | string;
|
|
40
|
-
translateY?: number | string;
|
|
41
|
-
|
|
42
|
-
// Visual effects
|
|
43
|
-
opacity?: number | ResponsiveValue<number>;
|
|
44
|
-
filter?: string;
|
|
45
|
-
clipPath?: string;
|
|
46
|
-
mask?: string;
|
|
47
|
-
|
|
48
|
-
// Animation
|
|
49
|
-
animation?: string;
|
|
50
|
-
transition?: string;
|
|
51
|
-
|
|
52
|
-
// Interaction states
|
|
53
|
-
hover?: Partial<SVGStyleOptions>;
|
|
54
|
-
focus?: Partial<SVGStyleOptions>;
|
|
55
|
-
active?: Partial<SVGStyleOptions>;
|
|
56
|
-
disabled?: Partial<SVGStyleOptions>;
|
|
57
|
-
|
|
58
|
-
// Theme integration
|
|
59
|
-
theme?: string | StyleTheme;
|
|
60
|
-
|
|
61
|
-
// Responsive design
|
|
62
|
-
responsive?: boolean;
|
|
63
|
-
|
|
64
|
-
// Custom CSS properties
|
|
65
|
-
css?: Record<string, string | number>;
|
|
66
|
-
|
|
67
|
-
// CSS classes
|
|
68
|
-
className?: string;
|
|
69
|
-
|
|
70
|
-
// Accessibility
|
|
71
|
-
'aria-label'?: string;
|
|
72
|
-
'aria-hidden'?: boolean;
|
|
73
|
-
title?: string;
|
|
74
|
-
role?: string;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface CompiledStyles {
|
|
78
|
-
inline: Record<string, string | number>;
|
|
79
|
-
classes: string[];
|
|
80
|
-
cssRules: string[];
|
|
81
|
-
mediaQueries: string[];
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export class SVGStyleCompiler {
|
|
85
|
-
private static instance: SVGStyleCompiler;
|
|
86
|
-
private themes: Map<string, StyleTheme> = new Map();
|
|
87
|
-
private globalCSS: string[] = [];
|
|
88
|
-
|
|
89
|
-
private constructor() {
|
|
90
|
-
this.loadDefaultThemes();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
public static getInstance(): SVGStyleCompiler {
|
|
94
|
-
if (!SVGStyleCompiler.instance) {
|
|
95
|
-
SVGStyleCompiler.instance = new SVGStyleCompiler();
|
|
96
|
-
}
|
|
97
|
-
return SVGStyleCompiler.instance;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Compile SVG styling options into CSS
|
|
102
|
-
*/
|
|
103
|
-
public compileStyles(
|
|
104
|
-
options: SVGStyleOptions,
|
|
105
|
-
componentName: string
|
|
106
|
-
): CompiledStyles {
|
|
107
|
-
const compiled: CompiledStyles = {
|
|
108
|
-
inline: {},
|
|
109
|
-
classes: [],
|
|
110
|
-
cssRules: [],
|
|
111
|
-
mediaQueries: []
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
// Get theme if specified
|
|
115
|
-
const theme = this.resolveTheme(options.theme);
|
|
116
|
-
|
|
117
|
-
// Compile base styles
|
|
118
|
-
this.compileBaseStyles(options, compiled, theme);
|
|
119
|
-
|
|
120
|
-
// Compile responsive styles
|
|
121
|
-
if (options.responsive) {
|
|
122
|
-
this.compileResponsiveStyles(options, compiled, theme, componentName);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Compile interaction states
|
|
126
|
-
this.compileInteractionStates(options, compiled, componentName);
|
|
127
|
-
|
|
128
|
-
// Add custom CSS
|
|
129
|
-
if (options.css) {
|
|
130
|
-
Object.assign(compiled.inline, options.css);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Add class names
|
|
134
|
-
if (options.className) {
|
|
135
|
-
compiled.classes.push(options.className);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return compiled;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Register a custom theme
|
|
143
|
-
*/
|
|
144
|
-
public registerTheme(theme: StyleTheme): void {
|
|
145
|
-
this.themes.set(theme.name, theme);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Generate CSS for a component with all styling options
|
|
150
|
-
*/
|
|
151
|
-
public generateComponentCSS(
|
|
152
|
-
componentName: string,
|
|
153
|
-
options: SVGStyleOptions
|
|
154
|
-
): string {
|
|
155
|
-
const compiled = this.compileStyles(options, componentName);
|
|
156
|
-
|
|
157
|
-
let css = '';
|
|
158
|
-
|
|
159
|
-
// Add CSS rules
|
|
160
|
-
if (compiled.cssRules.length > 0) {
|
|
161
|
-
css += compiled.cssRules.join('\n') + '\n';
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Add media queries
|
|
165
|
-
if (compiled.mediaQueries.length > 0) {
|
|
166
|
-
css += compiled.mediaQueries.join('\n') + '\n';
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return css;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Generate enhanced React component template with full styling support
|
|
174
|
-
*/
|
|
175
|
-
public generateStyledComponent(
|
|
176
|
-
componentName: string,
|
|
177
|
-
svgContent: string,
|
|
178
|
-
options: SVGStyleOptions = {}
|
|
179
|
-
): string {
|
|
180
|
-
const compiled = this.compileStyles(options, componentName);
|
|
181
|
-
const hasCustomStyles = compiled.cssRules.length > 0 || compiled.mediaQueries.length > 0;
|
|
182
|
-
|
|
183
|
-
const imports = hasCustomStyles
|
|
184
|
-
? `import React from 'react';\nimport type { SVGProps } from "react";`
|
|
185
|
-
: `import type { SVGProps } from "react";`;
|
|
186
|
-
|
|
187
|
-
const styledCSS = hasCustomStyles ? `
|
|
188
|
-
const ${componentName}Styles = \`
|
|
189
|
-
${compiled.cssRules.join('\n')}
|
|
190
|
-
${compiled.mediaQueries.join('\n')}
|
|
191
|
-
\`;
|
|
192
|
-
|
|
193
|
-
// Inject styles
|
|
194
|
-
if (typeof document !== 'undefined') {
|
|
195
|
-
const styleId = '${componentName.toLowerCase()}-styles';
|
|
196
|
-
if (!document.getElementById(styleId)) {
|
|
197
|
-
const style = document.createElement('style');
|
|
198
|
-
style.id = styleId;
|
|
199
|
-
style.textContent = ${componentName}Styles;
|
|
200
|
-
document.head.appendChild(style);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
` : '';
|
|
204
|
-
|
|
205
|
-
const inlineStyleObject = Object.keys(compiled.inline).length > 0
|
|
206
|
-
? `const defaultStyles = ${JSON.stringify(compiled.inline, null, 2)};`
|
|
207
|
-
: '';
|
|
208
|
-
|
|
209
|
-
const classNames = compiled.classes.length > 0
|
|
210
|
-
? `'${compiled.classes.join(' ')} ' + (props.className || '')`
|
|
211
|
-
: 'props.className';
|
|
212
|
-
|
|
213
|
-
return `${imports}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* ${componentName} SVG Component with Enhanced Styling
|
|
217
|
-
* Generated by svger-cli with comprehensive styling support
|
|
218
|
-
*/
|
|
219
|
-
|
|
220
|
-
${styledCSS}${inlineStyleObject}
|
|
221
|
-
|
|
222
|
-
export interface ${componentName}Props extends SVGProps<SVGSVGElement> {
|
|
223
|
-
// Enhanced styling props
|
|
224
|
-
size?: number | string;
|
|
225
|
-
variant?: 'primary' | 'secondary' | 'accent' | 'muted';
|
|
226
|
-
responsive?: boolean;
|
|
227
|
-
|
|
228
|
-
// Animation props
|
|
229
|
-
animate?: boolean;
|
|
230
|
-
animationType?: 'spin' | 'pulse' | 'bounce' | 'fade';
|
|
231
|
-
|
|
232
|
-
// Theme props
|
|
233
|
-
theme?: 'light' | 'dark' | 'auto';
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const ${componentName} = React.forwardRef<SVGSVGElement, ${componentName}Props>(
|
|
237
|
-
({
|
|
238
|
-
size,
|
|
239
|
-
variant = 'primary',
|
|
240
|
-
responsive = false,
|
|
241
|
-
animate = false,
|
|
242
|
-
animationType = 'spin',
|
|
243
|
-
theme = 'auto',
|
|
244
|
-
style,
|
|
245
|
-
className,
|
|
246
|
-
...props
|
|
247
|
-
}, ref) => {
|
|
248
|
-
|
|
249
|
-
// Calculate dimensions
|
|
250
|
-
const dimensions = React.useMemo(() => {
|
|
251
|
-
if (size) {
|
|
252
|
-
return { width: size, height: size };
|
|
253
|
-
}
|
|
254
|
-
return {
|
|
255
|
-
width: props.width || ${options.width || 24},
|
|
256
|
-
height: props.height || ${options.height || 24}
|
|
257
|
-
};
|
|
258
|
-
}, [size, props.width, props.height]);
|
|
259
|
-
|
|
260
|
-
// Combine styles
|
|
261
|
-
const combinedStyles = React.useMemo(() => {
|
|
262
|
-
const baseStyles = ${inlineStyleObject ? 'defaultStyles' : '{}'};
|
|
263
|
-
const variantStyles = getVariantStyles(variant);
|
|
264
|
-
const animationStyles = animate ? getAnimationStyles(animationType) : {};
|
|
265
|
-
const themeStyles = getThemeStyles(theme);
|
|
266
|
-
|
|
267
|
-
return {
|
|
268
|
-
...baseStyles,
|
|
269
|
-
...variantStyles,
|
|
270
|
-
...animationStyles,
|
|
271
|
-
...themeStyles,
|
|
272
|
-
...style
|
|
273
|
-
};
|
|
274
|
-
}, [variant, animate, animationType, theme, style]);
|
|
275
|
-
|
|
276
|
-
// Combine class names
|
|
277
|
-
const combinedClassName = React.useMemo(() => {
|
|
278
|
-
const classes = [];
|
|
279
|
-
${compiled.classes.length > 0 ? `classes.push('${compiled.classes.join(' ')}');` : ''}
|
|
280
|
-
if (responsive) classes.push(\`\${componentName.toLowerCase()}-responsive\`);
|
|
281
|
-
if (animate) classes.push(\`\${componentName.toLowerCase()}-animate-\${animationType}\`);
|
|
282
|
-
classes.push(\`\${componentName.toLowerCase()}-variant-\${variant}\`);
|
|
283
|
-
classes.push(\`\${componentName.toLowerCase()}-theme-\${theme}\`);
|
|
284
|
-
if (className) classes.push(className);
|
|
285
|
-
return classes.join(' ');
|
|
286
|
-
}, [responsive, animate, animationType, variant, theme, className]);
|
|
287
|
-
|
|
288
|
-
return (
|
|
289
|
-
<svg
|
|
290
|
-
ref={ref}
|
|
291
|
-
viewBox="0 0 24 24"
|
|
292
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
293
|
-
width={dimensions.width}
|
|
294
|
-
height={dimensions.height}
|
|
295
|
-
fill={props.fill || "${options.fill || 'currentColor'}"}
|
|
296
|
-
className={combinedClassName}
|
|
297
|
-
style={combinedStyles}
|
|
298
|
-
aria-hidden={props['aria-hidden']}
|
|
299
|
-
aria-label={props['aria-label']}
|
|
300
|
-
role={props.role || 'img'}
|
|
301
|
-
{...props}
|
|
302
|
-
>
|
|
303
|
-
${options.title ? `<title>${options.title}</title>` : ''}
|
|
304
|
-
${svgContent}
|
|
305
|
-
</svg>
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
);
|
|
309
|
-
|
|
310
|
-
// Utility functions for styling
|
|
311
|
-
function getVariantStyles(variant: string): React.CSSProperties {
|
|
312
|
-
const variants = {
|
|
313
|
-
primary: { color: 'var(--color-primary, #007bff)' },
|
|
314
|
-
secondary: { color: 'var(--color-secondary, #6c757d)' },
|
|
315
|
-
accent: { color: 'var(--color-accent, #28a745)' },
|
|
316
|
-
muted: { color: 'var(--color-muted, #6c757d)', opacity: 0.7 }
|
|
317
|
-
};
|
|
318
|
-
return variants[variant as keyof typeof variants] || variants.primary;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
function getAnimationStyles(animationType: string): React.CSSProperties {
|
|
322
|
-
const animations = {
|
|
323
|
-
spin: { animation: 'svger-spin 1s linear infinite' },
|
|
324
|
-
pulse: { animation: 'svger-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite' },
|
|
325
|
-
bounce: { animation: 'svger-bounce 1s infinite' },
|
|
326
|
-
fade: { animation: 'svger-fade 2s ease-in-out infinite alternate' }
|
|
327
|
-
};
|
|
328
|
-
return animations[animationType as keyof typeof animations] || {};
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function getThemeStyles(theme: string): React.CSSProperties {
|
|
332
|
-
if (theme === 'dark') {
|
|
333
|
-
return { filter: 'invert(1) hue-rotate(180deg)' };
|
|
334
|
-
}
|
|
335
|
-
if (theme === 'auto') {
|
|
336
|
-
return { filter: 'var(--svger-theme-filter, none)' };
|
|
337
|
-
}
|
|
338
|
-
return {};
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
${componentName}.displayName = "${componentName}";
|
|
342
|
-
|
|
343
|
-
export default ${componentName};
|
|
344
|
-
|
|
345
|
-
// CSS Animations (injected globally)
|
|
346
|
-
if (typeof document !== 'undefined') {
|
|
347
|
-
const animationCSS = \`
|
|
348
|
-
@keyframes svger-spin {
|
|
349
|
-
from { transform: rotate(0deg); }
|
|
350
|
-
to { transform: rotate(360deg); }
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
@keyframes svger-pulse {
|
|
354
|
-
0%, 100% { opacity: 1; }
|
|
355
|
-
50% { opacity: 0.5; }
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
@keyframes svger-bounce {
|
|
359
|
-
0%, 20%, 53%, 80%, 100% { transform: translate3d(0,0,0); }
|
|
360
|
-
40%, 43% { transform: translate3d(0,-30px,0); }
|
|
361
|
-
70% { transform: translate3d(0,-15px,0); }
|
|
362
|
-
90% { transform: translate3d(0,-4px,0); }
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
@keyframes svger-fade {
|
|
366
|
-
from { opacity: 0.4; }
|
|
367
|
-
to { opacity: 1; }
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/* CSS Custom Properties for theming */
|
|
371
|
-
:root {
|
|
372
|
-
--color-primary: #007bff;
|
|
373
|
-
--color-secondary: #6c757d;
|
|
374
|
-
--color-accent: #28a745;
|
|
375
|
-
--color-muted: #6c757d;
|
|
376
|
-
--svger-theme-filter: none;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
@media (prefers-color-scheme: dark) {
|
|
380
|
-
:root {
|
|
381
|
-
--svger-theme-filter: invert(1) hue-rotate(180deg);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
\`;
|
|
385
|
-
|
|
386
|
-
const globalStyleId = 'svger-global-animations';
|
|
387
|
-
if (!document.getElementById(globalStyleId)) {
|
|
388
|
-
const style = document.createElement('style');
|
|
389
|
-
style.id = globalStyleId;
|
|
390
|
-
style.textContent = animationCSS;
|
|
391
|
-
document.head.appendChild(style);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
`;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// Private helper methods
|
|
398
|
-
|
|
399
|
-
private loadDefaultThemes(): void {
|
|
400
|
-
// Light theme
|
|
401
|
-
this.registerTheme({
|
|
402
|
-
name: 'light',
|
|
403
|
-
colors: {
|
|
404
|
-
primary: '#007bff',
|
|
405
|
-
secondary: '#6c757d',
|
|
406
|
-
success: '#28a745',
|
|
407
|
-
warning: '#ffc107',
|
|
408
|
-
danger: '#dc3545',
|
|
409
|
-
info: '#17a2b8',
|
|
410
|
-
light: '#f8f9fa',
|
|
411
|
-
dark: '#343a40'
|
|
412
|
-
},
|
|
413
|
-
sizes: {
|
|
414
|
-
xs: 12,
|
|
415
|
-
sm: 16,
|
|
416
|
-
md: 24,
|
|
417
|
-
lg: 32,
|
|
418
|
-
xl: 48
|
|
419
|
-
},
|
|
420
|
-
spacing: {
|
|
421
|
-
1: '0.25rem',
|
|
422
|
-
2: '0.5rem',
|
|
423
|
-
3: '0.75rem',
|
|
424
|
-
4: '1rem',
|
|
425
|
-
5: '1.5rem'
|
|
426
|
-
},
|
|
427
|
-
breakpoints: {
|
|
428
|
-
sm: '576px',
|
|
429
|
-
md: '768px',
|
|
430
|
-
lg: '992px',
|
|
431
|
-
xl: '1200px'
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
// Dark theme
|
|
436
|
-
this.registerTheme({
|
|
437
|
-
name: 'dark',
|
|
438
|
-
colors: {
|
|
439
|
-
primary: '#0d6efd',
|
|
440
|
-
secondary: '#6c757d',
|
|
441
|
-
success: '#198754',
|
|
442
|
-
warning: '#ffc107',
|
|
443
|
-
danger: '#dc3545',
|
|
444
|
-
info: '#0dcaf0',
|
|
445
|
-
light: '#212529',
|
|
446
|
-
dark: '#f8f9fa'
|
|
447
|
-
},
|
|
448
|
-
sizes: {
|
|
449
|
-
xs: 12,
|
|
450
|
-
sm: 16,
|
|
451
|
-
md: 24,
|
|
452
|
-
lg: 32,
|
|
453
|
-
xl: 48
|
|
454
|
-
},
|
|
455
|
-
spacing: {
|
|
456
|
-
1: '0.25rem',
|
|
457
|
-
2: '0.5rem',
|
|
458
|
-
3: '0.75rem',
|
|
459
|
-
4: '1rem',
|
|
460
|
-
5: '1.5rem'
|
|
461
|
-
},
|
|
462
|
-
breakpoints: {
|
|
463
|
-
sm: '576px',
|
|
464
|
-
md: '768px',
|
|
465
|
-
lg: '992px',
|
|
466
|
-
xl: '1200px'
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
private resolveTheme(theme?: string | StyleTheme): StyleTheme | null {
|
|
472
|
-
if (!theme) return null;
|
|
473
|
-
|
|
474
|
-
if (typeof theme === 'string') {
|
|
475
|
-
return this.themes.get(theme) || null;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
return theme;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
private compileBaseStyles(
|
|
482
|
-
options: SVGStyleOptions,
|
|
483
|
-
compiled: CompiledStyles,
|
|
484
|
-
theme: StyleTheme | null
|
|
485
|
-
): void {
|
|
486
|
-
// Handle basic properties
|
|
487
|
-
const styleMap: Record<string, keyof SVGStyleOptions> = {
|
|
488
|
-
fill: 'fill',
|
|
489
|
-
stroke: 'stroke',
|
|
490
|
-
strokeWidth: 'strokeWidth',
|
|
491
|
-
opacity: 'opacity',
|
|
492
|
-
transform: 'transform',
|
|
493
|
-
filter: 'filter',
|
|
494
|
-
clipPath: 'clipPath',
|
|
495
|
-
mask: 'mask',
|
|
496
|
-
animation: 'animation',
|
|
497
|
-
transition: 'transition'
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
for (const [cssProp, optionKey] of Object.entries(styleMap)) {
|
|
501
|
-
const value = options[optionKey];
|
|
502
|
-
if (value !== undefined) {
|
|
503
|
-
if (this.isResponsiveValue(value)) {
|
|
504
|
-
compiled.inline[cssProp] = (value as ResponsiveValue<any>).base;
|
|
505
|
-
} else {
|
|
506
|
-
compiled.inline[cssProp] = value as string | number;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Handle size shorthand
|
|
512
|
-
if (options.size !== undefined) {
|
|
513
|
-
const sizeValue = this.isResponsiveValue(options.size)
|
|
514
|
-
? (options.size as ResponsiveValue<any>).base
|
|
515
|
-
: options.size;
|
|
516
|
-
compiled.inline.width = sizeValue;
|
|
517
|
-
compiled.inline.height = sizeValue;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
// Handle transform shortcuts
|
|
521
|
-
const transforms: string[] = [];
|
|
522
|
-
if (options.rotate) transforms.push(`rotate(${options.rotate}deg)`);
|
|
523
|
-
if (options.scale) transforms.push(`scale(${options.scale})`);
|
|
524
|
-
if (options.translateX) transforms.push(`translateX(${options.translateX})`);
|
|
525
|
-
if (options.translateY) transforms.push(`translateY(${options.translateY})`);
|
|
526
|
-
|
|
527
|
-
if (transforms.length > 0) {
|
|
528
|
-
const existingTransform = compiled.inline.transform as string;
|
|
529
|
-
compiled.inline.transform = existingTransform
|
|
530
|
-
? `${existingTransform} ${transforms.join(' ')}`
|
|
531
|
-
: transforms.join(' ');
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
private compileResponsiveStyles(
|
|
536
|
-
options: SVGStyleOptions,
|
|
537
|
-
compiled: CompiledStyles,
|
|
538
|
-
theme: StyleTheme | null,
|
|
539
|
-
componentName: string
|
|
540
|
-
): void {
|
|
541
|
-
const breakpoints = theme?.breakpoints || {
|
|
542
|
-
sm: '576px',
|
|
543
|
-
md: '768px',
|
|
544
|
-
lg: '992px',
|
|
545
|
-
xl: '1200px'
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
for (const [prop, value] of Object.entries(options)) {
|
|
549
|
-
if (this.isResponsiveValue(value)) {
|
|
550
|
-
const responsiveValue = value as ResponsiveValue<any>;
|
|
551
|
-
|
|
552
|
-
for (const [breakpoint, breakpointValue] of Object.entries(responsiveValue)) {
|
|
553
|
-
if (breakpoint === 'base') continue;
|
|
554
|
-
|
|
555
|
-
const mediaQuery = breakpoints[breakpoint];
|
|
556
|
-
if (mediaQuery && breakpointValue !== undefined) {
|
|
557
|
-
const rule = `@media (min-width: ${mediaQuery}) {
|
|
558
|
-
.${componentName.toLowerCase()}-responsive {
|
|
559
|
-
${this.camelToKebab(prop)}: ${breakpointValue};
|
|
560
|
-
}
|
|
561
|
-
}`;
|
|
562
|
-
compiled.mediaQueries.push(rule);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
private compileInteractionStates(
|
|
570
|
-
options: SVGStyleOptions,
|
|
571
|
-
compiled: CompiledStyles,
|
|
572
|
-
componentName: string
|
|
573
|
-
): void {
|
|
574
|
-
const states = ['hover', 'focus', 'active', 'disabled'] as const;
|
|
575
|
-
|
|
576
|
-
for (const state of states) {
|
|
577
|
-
const stateStyles = options[state];
|
|
578
|
-
if (stateStyles) {
|
|
579
|
-
const selector = state === 'disabled'
|
|
580
|
-
? `.${componentName.toLowerCase()}[disabled], .${componentName.toLowerCase()}[aria-disabled="true"]`
|
|
581
|
-
: `.${componentName.toLowerCase()}:${state}`;
|
|
582
|
-
|
|
583
|
-
const rules: string[] = [];
|
|
584
|
-
for (const [prop, value] of Object.entries(stateStyles)) {
|
|
585
|
-
rules.push(` ${this.camelToKebab(prop)}: ${value};`);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
if (rules.length > 0) {
|
|
589
|
-
compiled.cssRules.push(`${selector} {\n${rules.join('\n')}\n}`);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
private isResponsiveValue(value: any): value is ResponsiveValue<any> {
|
|
596
|
-
return value && typeof value === 'object' && 'base' in value;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
private camelToKebab(str: string): string {
|
|
600
|
-
return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
// Export singleton instance
|
|
605
|
-
export const styleCompiler = SVGStyleCompiler.getInstance();
|
package/src/lock.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
|
|
4
|
-
const LOCK_FILE = ".svg-lock";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Get the absolute path to the lock file.
|
|
8
|
-
*
|
|
9
|
-
* @returns {string} Absolute path to .svg-lock
|
|
10
|
-
*/
|
|
11
|
-
function getLockFilePath(): string {
|
|
12
|
-
return path.resolve(LOCK_FILE);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Read the current locked SVG files from the lock file.
|
|
17
|
-
*
|
|
18
|
-
* @returns {string[]} Array of locked SVG file names.
|
|
19
|
-
*/
|
|
20
|
-
function readLockFile(): string[] {
|
|
21
|
-
if (!fs.existsSync(getLockFilePath())) return [];
|
|
22
|
-
try {
|
|
23
|
-
const data = fs.readFileSync(getLockFilePath(), "utf-8");
|
|
24
|
-
return JSON.parse(data);
|
|
25
|
-
} catch (e) {
|
|
26
|
-
return [];
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Write the list of locked SVG files to the lock file.
|
|
32
|
-
*
|
|
33
|
-
* @param {string[]} files - Array of SVG file names to lock.
|
|
34
|
-
*/
|
|
35
|
-
function writeLockFile(files: string[]) {
|
|
36
|
-
fs.writeFileSync(getLockFilePath(), JSON.stringify(files, null, 2), "utf-8");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Lock one or more SVG files to prevent them from being processed.
|
|
41
|
-
*
|
|
42
|
-
* @param {string[]} files - Paths to SVG files to lock.
|
|
43
|
-
*/
|
|
44
|
-
export function lockFiles(files: string[]) {
|
|
45
|
-
const fileNames = files.map(f => path.basename(f));
|
|
46
|
-
const current = readLockFile();
|
|
47
|
-
const newFiles = Array.from(new Set([...current, ...fileNames]));
|
|
48
|
-
writeLockFile(newFiles);
|
|
49
|
-
console.log(`🔒 Locked files: ${newFiles.join(", ")}`);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Unlock one or more SVG files, allowing them to be processed again.
|
|
54
|
-
*
|
|
55
|
-
* @param {string[]} files - Paths to SVG files to unlock.
|
|
56
|
-
*/
|
|
57
|
-
export function unlockFiles(files: string[]) {
|
|
58
|
-
const fileNames = files.map(f => path.basename(f));
|
|
59
|
-
const current = readLockFile();
|
|
60
|
-
const remaining = current.filter(f => !fileNames.includes(f));
|
|
61
|
-
writeLockFile(remaining);
|
|
62
|
-
console.log(`🔓 Unlocked files: ${fileNames.join(", ")}`);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Check if a specific SVG file is locked.
|
|
67
|
-
*
|
|
68
|
-
* @param {string} file - Path to the SVG file to check.
|
|
69
|
-
* @returns {boolean} True if the file is locked, false otherwise.
|
|
70
|
-
*/
|
|
71
|
-
export function isLocked(file: string): boolean {
|
|
72
|
-
const current = readLockFile();
|
|
73
|
-
return current.includes(path.basename(file));
|
|
74
|
-
}
|