@shohojdhara/atomix 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -21
- package/dist/atomix.css +96 -121
- package/dist/atomix.min.css +3 -3
- package/dist/index.d.ts +7937 -7765
- package/dist/index.esm.js +3677 -4031
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +3648 -3952
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +44 -16
- package/scripts/atomix-cli.js +1764 -0
- package/scripts/build-themes.js +208 -0
- package/scripts/cli/interactive-init.js +520 -0
- package/scripts/cli/migration-tools.js +603 -0
- package/scripts/cli/theme-bridge.js +129 -0
- package/scripts/cli/token-manager.js +519 -0
- package/scripts/sync-theme-config.js +309 -0
- package/src/components/Button/Button.tsx +36 -1
- package/src/components/List/ListGroup.tsx +1 -2
- package/src/components/Popover/Popover.tsx +2 -2
- package/src/components/Tooltip/Tooltip.stories.tsx +49 -12
- package/src/components/Tooltip/Tooltip.tsx +32 -58
- package/src/lib/composables/useTooltip.ts +285 -0
- package/src/lib/config/index.ts +275 -0
- package/src/lib/config/loader.ts +105 -0
- package/src/lib/constants/cssVariables.ts +390 -0
- package/src/lib/hooks/__tests__/useComponentCustomization.test.ts +151 -0
- package/src/lib/hooks/index.ts +19 -0
- package/src/lib/hooks/useComponentCustomization.ts +175 -0
- package/src/lib/index.ts +14 -1
- package/src/lib/patterns/__tests__/slots.test.ts +108 -0
- package/src/lib/patterns/index.ts +35 -0
- package/src/lib/patterns/slots.tsx +421 -0
- package/src/lib/theme/composeTheme.ts +0 -5
- package/src/lib/theme/config/index.ts +1 -1
- package/src/lib/theme/config/loader.ts +75 -41
- package/src/lib/theme/config/types.ts +21 -7
- package/src/lib/theme/config/validator.ts +1 -1
- package/src/lib/theme/constants.ts +12 -2
- package/src/lib/theme/createTheme.ts +2 -135
- package/src/lib/theme/createThemeFromConfig.ts +132 -0
- package/src/lib/theme/cssVariableMapper.ts +261 -0
- package/src/lib/theme/devtools/CLI.ts +161 -76
- package/src/lib/theme/devtools/Comparator.tsx +343 -0
- package/src/lib/theme/devtools/IMPROVEMENTS.md +429 -0
- package/src/lib/theme/devtools/Inspector.tsx +21 -6
- package/src/lib/theme/devtools/LiveEditor.tsx +393 -0
- package/src/lib/theme/devtools/README.md +433 -0
- package/src/lib/theme/devtools/index.ts +12 -11
- package/src/lib/theme/generateCSSVariables.ts +79 -38
- package/src/lib/theme/index.ts +45 -246
- package/src/lib/theme/runtime/ThemeApplicator.ts +252 -0
- package/src/lib/theme/runtime/ThemeManager.test.ts +17 -1
- package/src/lib/theme/runtime/ThemeManager.ts +7 -7
- package/src/lib/theme/themeUtils.ts +27 -5
- package/src/lib/theme/types.ts +59 -1
- package/src/lib/theme-tools.ts +125 -0
- package/src/lib/types/components.ts +260 -72
- package/src/lib/types/partProps.ts +426 -0
- package/src/lib/utils/__tests__/componentUtils.test.ts +144 -0
- package/src/lib/utils/componentUtils.ts +163 -0
- package/src/lib/utils/index.ts +17 -57
- package/src/styles/01-settings/_settings.colors.scss +10 -10
- package/src/styles/01-settings/_settings.navbar.scss +1 -1
- package/src/styles/01-settings/_settings.tooltip.scss +1 -1
- package/src/styles/03-generic/_generated-root.css +5 -0
- package/src/styles/06-components/_components.navbar.scss +12 -5
- package/src/styles/06-components/_components.tooltip.scss +31 -81
- package/src/themes/README.md +442 -0
- package/src/themes/themes.config.js +35 -0
- package/src/lib/theme/errors.test.ts +0 -207
- package/src/lib/theme/generators/CSSGenerator.ts +0 -311
- package/src/lib/theme/generators/ConfigGenerator.ts +0 -287
- package/src/lib/theme/generators/TypeGenerator.ts +0 -228
- package/src/lib/theme/generators/index.ts +0 -21
- package/src/lib/theme/monitoring/ThemeAnalytics.ts +0 -409
- package/src/lib/theme/monitoring/index.ts +0 -17
- package/src/lib/theme/overrides/ComponentOverrides.ts +0 -243
- package/src/lib/theme/overrides/index.ts +0 -15
- package/src/lib/theme/studio/ThemeStudio.tsx +0 -312
- package/src/lib/theme/studio/index.ts +0 -8
- package/src/lib/theme/whitelabel/WhiteLabelManager.ts +0 -364
- package/src/lib/theme/whitelabel/index.ts +0 -13
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TypeScript Type Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates TypeScript type definitions from theme objects
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Theme } from '../types';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Type generation options
|
|
11
|
-
*/
|
|
12
|
-
export interface TypeGeneratorOptions {
|
|
13
|
-
/** Module name for generated types */
|
|
14
|
-
moduleName?: string;
|
|
15
|
-
/** Include JSDoc comments */
|
|
16
|
-
includeComments?: boolean;
|
|
17
|
-
/** Export style */
|
|
18
|
-
exportStyle?: 'named' | 'default' | 'both';
|
|
19
|
-
/** Include theme interface augmentation */
|
|
20
|
-
includeAugmentation?: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* TypeScript Type Generator
|
|
25
|
-
*
|
|
26
|
-
* Generates TypeScript definitions for theme objects
|
|
27
|
-
*/
|
|
28
|
-
export class TypeGenerator {
|
|
29
|
-
private options: Required<TypeGeneratorOptions>;
|
|
30
|
-
|
|
31
|
-
constructor(options: TypeGeneratorOptions = {}) {
|
|
32
|
-
this.options = {
|
|
33
|
-
moduleName: options.moduleName || 'Theme',
|
|
34
|
-
includeComments: options.includeComments ?? true,
|
|
35
|
-
exportStyle: options.exportStyle || 'named',
|
|
36
|
-
includeAugmentation: options.includeAugmentation ?? false,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Generate TypeScript definitions from theme
|
|
42
|
-
*/
|
|
43
|
-
generate(theme: Theme): string {
|
|
44
|
-
let output = '';
|
|
45
|
-
|
|
46
|
-
if (this.options.includeComments) {
|
|
47
|
-
output += this.generateHeader();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
output += this.generateImports();
|
|
51
|
-
output += this.generateThemeInterface(theme);
|
|
52
|
-
|
|
53
|
-
if (this.options.includeAugmentation) {
|
|
54
|
-
output += this.generateAugmentation();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return output;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Generate file header
|
|
62
|
-
*/
|
|
63
|
-
private generateHeader(): string {
|
|
64
|
-
return `/**
|
|
65
|
-
* Generated Theme Types
|
|
66
|
-
*
|
|
67
|
-
* Auto-generated TypeScript definitions for ${this.options.moduleName}
|
|
68
|
-
* Do not edit this file directly.
|
|
69
|
-
*/
|
|
70
|
-
|
|
71
|
-
`;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Generate imports
|
|
76
|
-
*/
|
|
77
|
-
private generateImports(): string {
|
|
78
|
-
return `import type { Theme as BaseTheme } from '@shohojdhara/atomix/theme';
|
|
79
|
-
|
|
80
|
-
`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Generate theme interface
|
|
85
|
-
*/
|
|
86
|
-
private generateThemeInterface(theme: Theme): string {
|
|
87
|
-
let output = '';
|
|
88
|
-
|
|
89
|
-
if (this.options.includeComments) {
|
|
90
|
-
output += `/**
|
|
91
|
-
* ${theme.name || 'Custom'} Theme Interface
|
|
92
|
-
*/
|
|
93
|
-
`;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
output += `export interface ${this.options.moduleName} extends BaseTheme {\n`;
|
|
97
|
-
output += ` name: '${theme.name}';\n`;
|
|
98
|
-
|
|
99
|
-
if (theme.class) {
|
|
100
|
-
output += ` class: '${theme.class}';\n`;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Generate palette types
|
|
104
|
-
output += this.generatePaletteTypes(theme.palette);
|
|
105
|
-
|
|
106
|
-
// Generate typography types
|
|
107
|
-
output += this.generateTypographyTypes(theme.typography);
|
|
108
|
-
|
|
109
|
-
// Generate custom properties if any
|
|
110
|
-
if (Object.keys(theme.custom).length > 0) {
|
|
111
|
-
output += this.generateCustomTypes(theme.custom);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
output += '}\n\n';
|
|
115
|
-
|
|
116
|
-
// Generate exports
|
|
117
|
-
if (this.options.exportStyle === 'default' || this.options.exportStyle === 'both') {
|
|
118
|
-
output += `declare const theme: ${this.options.moduleName};\n`;
|
|
119
|
-
output += `export default theme;\n\n`;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (this.options.exportStyle === 'named' || this.options.exportStyle === 'both') {
|
|
123
|
-
output += `export type { ${this.options.moduleName} };\n`;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return output;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Generate palette types
|
|
131
|
-
*/
|
|
132
|
-
private generatePaletteTypes(palette: Theme['palette']): string {
|
|
133
|
-
let output = ' palette: {\n';
|
|
134
|
-
|
|
135
|
-
const colors = ['primary', 'secondary', 'error', 'warning', 'info', 'success'] as const;
|
|
136
|
-
for (const color of colors) {
|
|
137
|
-
const colorObj = palette[color];
|
|
138
|
-
if (colorObj) {
|
|
139
|
-
output += ` ${color}: {\n`;
|
|
140
|
-
output += ` main: '${colorObj.main}';\n`;
|
|
141
|
-
if (colorObj.light) output += ` light: '${colorObj.light}';\n`;
|
|
142
|
-
if (colorObj.dark) output += ` dark: '${colorObj.dark}';\n`;
|
|
143
|
-
if (colorObj.contrastText) output += ` contrastText: '${colorObj.contrastText}';\n`;
|
|
144
|
-
output += ' };\n';
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Background
|
|
149
|
-
if (palette.background) {
|
|
150
|
-
output += ' background: {\n';
|
|
151
|
-
output += ` default: '${palette.background.default}';\n`;
|
|
152
|
-
output += ` paper: '${palette.background.paper}';\n`;
|
|
153
|
-
output += ` subtle: '${palette.background.subtle}';\n`;
|
|
154
|
-
output += ' };\n';
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// Text
|
|
158
|
-
if (palette.text) {
|
|
159
|
-
output += ' text: {\n';
|
|
160
|
-
output += ` primary: '${palette.text.primary}';\n`;
|
|
161
|
-
output += ` secondary: '${palette.text.secondary}';\n`;
|
|
162
|
-
output += ` disabled: '${palette.text.disabled}';\n`;
|
|
163
|
-
output += ' };\n';
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
output += ' };\n';
|
|
167
|
-
return output;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Generate typography types
|
|
172
|
-
*/
|
|
173
|
-
private generateTypographyTypes(typography: Theme['typography']): string {
|
|
174
|
-
let output = ' typography: {\n';
|
|
175
|
-
output += ` fontFamily: '${typography.fontFamily}';\n`;
|
|
176
|
-
output += ` fontSize: ${typography.fontSize};\n`;
|
|
177
|
-
|
|
178
|
-
// Font weights
|
|
179
|
-
if (typography.fontWeightLight) output += ` fontWeightLight: ${typography.fontWeightLight};\n`;
|
|
180
|
-
if (typography.fontWeightRegular) output += ` fontWeightRegular: ${typography.fontWeightRegular};\n`;
|
|
181
|
-
if (typography.fontWeightMedium) output += ` fontWeightMedium: ${typography.fontWeightMedium};\n`;
|
|
182
|
-
if (typography.fontWeightSemiBold) output += ` fontWeightSemiBold: ${typography.fontWeightSemiBold};\n`;
|
|
183
|
-
if (typography.fontWeightBold) output += ` fontWeightBold: ${typography.fontWeightBold};\n`;
|
|
184
|
-
|
|
185
|
-
output += ' };\n';
|
|
186
|
-
return output;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Generate custom property types
|
|
191
|
-
*/
|
|
192
|
-
private generateCustomTypes(custom: Theme['custom']): string {
|
|
193
|
-
let output = ' custom: {\n';
|
|
194
|
-
|
|
195
|
-
for (const [key, value] of Object.entries(custom)) {
|
|
196
|
-
const type = typeof value === 'string' ? `'${value}'` : typeof value;
|
|
197
|
-
output += ` ${key}: ${type};\n`;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
output += ' };\n';
|
|
201
|
-
return output;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Generate module augmentation
|
|
206
|
-
*/
|
|
207
|
-
private generateAugmentation(): string {
|
|
208
|
-
return `
|
|
209
|
-
declare module '@shohojdhara/atomix/theme' {
|
|
210
|
-
interface ThemeCustomProperties {
|
|
211
|
-
${this.options.moduleName}: ${this.options.moduleName};
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
`;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Generate TypeScript types from theme
|
|
220
|
-
*
|
|
221
|
-
* @param theme - Theme object
|
|
222
|
-
* @param options - Generation options
|
|
223
|
-
* @returns TypeScript definition string
|
|
224
|
-
*/
|
|
225
|
-
export function generateTypes(theme: Theme, options: TypeGeneratorOptions = {}): string {
|
|
226
|
-
const generator = new TypeGenerator(options);
|
|
227
|
-
return generator.generate(theme);
|
|
228
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Theme Generators Module
|
|
3
|
-
*
|
|
4
|
-
* Code generation utilities for themes
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
export { CSSGenerator, generateCSS } from './CSSGenerator';
|
|
8
|
-
export { TypeGenerator, generateTypes } from './TypeGenerator';
|
|
9
|
-
export { ConfigGenerator, generateConfigTemplate } from './ConfigGenerator';
|
|
10
|
-
|
|
11
|
-
export type {
|
|
12
|
-
CSSGeneratorOptions,
|
|
13
|
-
} from './CSSGenerator';
|
|
14
|
-
|
|
15
|
-
export type {
|
|
16
|
-
TypeGeneratorOptions,
|
|
17
|
-
} from './TypeGenerator';
|
|
18
|
-
|
|
19
|
-
export type {
|
|
20
|
-
ConfigGeneratorOptions,
|
|
21
|
-
} from './ConfigGenerator';
|
|
@@ -1,409 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Theme Analytics and Performance Monitoring
|
|
3
|
-
*
|
|
4
|
-
* Tracks theme usage, performance metrics, and provides analytics
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { getLogger } from '../errors';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Theme analytics event types
|
|
11
|
-
*/
|
|
12
|
-
export type ThemeAnalyticsEvent =
|
|
13
|
-
| 'theme_load'
|
|
14
|
-
| 'theme_switch'
|
|
15
|
-
| 'theme_error'
|
|
16
|
-
| 'theme_revert'
|
|
17
|
-
| 'css_load'
|
|
18
|
-
| 'performance_metric';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Theme analytics event
|
|
22
|
-
*/
|
|
23
|
-
export interface ThemeAnalyticsEventData {
|
|
24
|
-
/** Event type */
|
|
25
|
-
type: ThemeAnalyticsEvent;
|
|
26
|
-
/** Event timestamp */
|
|
27
|
-
timestamp: number;
|
|
28
|
-
/** Theme name */
|
|
29
|
-
themeName?: string;
|
|
30
|
-
/** Additional event data */
|
|
31
|
-
data?: Record<string, any>;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Performance metric
|
|
36
|
-
*/
|
|
37
|
-
export interface PerformanceMetric {
|
|
38
|
-
/** Metric name */
|
|
39
|
-
name: string;
|
|
40
|
-
/** Metric value */
|
|
41
|
-
value: number;
|
|
42
|
-
/** Unit */
|
|
43
|
-
unit: 'ms' | 'bytes' | 'count';
|
|
44
|
-
/** Timestamp */
|
|
45
|
-
timestamp: number;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Analytics configuration
|
|
50
|
-
*/
|
|
51
|
-
export interface AnalyticsConfig {
|
|
52
|
-
/** Enable analytics */
|
|
53
|
-
enabled?: boolean;
|
|
54
|
-
/** Enable performance tracking */
|
|
55
|
-
trackPerformance?: boolean;
|
|
56
|
-
/** Enable error tracking */
|
|
57
|
-
trackErrors?: boolean;
|
|
58
|
-
/** Custom event handler */
|
|
59
|
-
onEvent?: (event: ThemeAnalyticsEventData) => void;
|
|
60
|
-
/** Custom performance handler */
|
|
61
|
-
onPerformance?: (metric: PerformanceMetric) => void;
|
|
62
|
-
/** Buffer size for events */
|
|
63
|
-
bufferSize?: number;
|
|
64
|
-
/** Flush interval (ms) */
|
|
65
|
-
flushInterval?: number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Default analytics configuration
|
|
70
|
-
*/
|
|
71
|
-
const DEFAULT_CONFIG: Required<Omit<AnalyticsConfig, 'onEvent' | 'onPerformance'>> = {
|
|
72
|
-
enabled: true,
|
|
73
|
-
trackPerformance: true,
|
|
74
|
-
trackErrors: true,
|
|
75
|
-
bufferSize: 100,
|
|
76
|
-
flushInterval: 5000,
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Theme Analytics Manager
|
|
81
|
-
*
|
|
82
|
-
* Tracks theme usage, performance, and errors
|
|
83
|
-
*/
|
|
84
|
-
export class ThemeAnalytics {
|
|
85
|
-
private config: Required<Omit<AnalyticsConfig, 'onEvent' | 'onPerformance'>> & {
|
|
86
|
-
onEvent?: AnalyticsConfig['onEvent'];
|
|
87
|
-
onPerformance?: AnalyticsConfig['onPerformance'];
|
|
88
|
-
};
|
|
89
|
-
private events: ThemeAnalyticsEventData[] = [];
|
|
90
|
-
private metrics: PerformanceMetric[] = [];
|
|
91
|
-
private flushTimer: ReturnType<typeof setInterval> | null = null;
|
|
92
|
-
private logger = getLogger();
|
|
93
|
-
|
|
94
|
-
constructor(config: AnalyticsConfig = {}) {
|
|
95
|
-
this.config = {
|
|
96
|
-
...DEFAULT_CONFIG,
|
|
97
|
-
...config,
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
if (this.config.enabled) {
|
|
101
|
-
this.startFlushTimer();
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Track theme load event
|
|
107
|
-
*/
|
|
108
|
-
trackThemeLoad(themeName: string, loadTime?: number): void {
|
|
109
|
-
if (!this.config.enabled) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const event: ThemeAnalyticsEventData = {
|
|
114
|
-
type: 'theme_load',
|
|
115
|
-
timestamp: Date.now(),
|
|
116
|
-
themeName,
|
|
117
|
-
data: loadTime ? { loadTime } : undefined,
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
this.addEvent(event);
|
|
121
|
-
|
|
122
|
-
if (loadTime !== undefined) {
|
|
123
|
-
this.trackPerformance('theme_load_time', loadTime, 'ms');
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Track theme switch event
|
|
129
|
-
*/
|
|
130
|
-
trackThemeSwitch(fromTheme: string, toTheme: string, switchTime?: number): void {
|
|
131
|
-
if (!this.config.enabled) {
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const event: ThemeAnalyticsEventData = {
|
|
136
|
-
type: 'theme_switch',
|
|
137
|
-
timestamp: Date.now(),
|
|
138
|
-
themeName: toTheme,
|
|
139
|
-
data: {
|
|
140
|
-
fromTheme,
|
|
141
|
-
toTheme,
|
|
142
|
-
...(switchTime ? { switchTime } : {}),
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
this.addEvent(event);
|
|
147
|
-
|
|
148
|
-
if (switchTime !== undefined) {
|
|
149
|
-
this.trackPerformance('theme_switch_time', switchTime, 'ms');
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* Track theme error
|
|
155
|
-
*/
|
|
156
|
-
trackError(themeName: string, error: Error | string): void {
|
|
157
|
-
if (!this.config.enabled || !this.config.trackErrors) {
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
const event: ThemeAnalyticsEventData = {
|
|
162
|
-
type: 'theme_error',
|
|
163
|
-
timestamp: Date.now(),
|
|
164
|
-
themeName,
|
|
165
|
-
data: {
|
|
166
|
-
error: error instanceof Error ? error.message : error,
|
|
167
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
168
|
-
},
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
this.addEvent(event);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Track theme revert
|
|
176
|
-
*/
|
|
177
|
-
trackThemeRevert(attemptedTheme: string, revertedToTheme: string | null, error: Error): void {
|
|
178
|
-
if (!this.config.enabled || !this.config.trackErrors) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const event: ThemeAnalyticsEventData = {
|
|
183
|
-
type: 'theme_revert',
|
|
184
|
-
timestamp: Date.now(),
|
|
185
|
-
themeName: attemptedTheme,
|
|
186
|
-
data: {
|
|
187
|
-
attemptedTheme,
|
|
188
|
-
revertedToTheme,
|
|
189
|
-
error: error.message,
|
|
190
|
-
stack: error.stack,
|
|
191
|
-
},
|
|
192
|
-
};
|
|
193
|
-
|
|
194
|
-
this.addEvent(event);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Track CSS load
|
|
199
|
-
*/
|
|
200
|
-
trackCSSLoad(themeName: string, loadTime: number, size?: number): void {
|
|
201
|
-
if (!this.config.enabled) {
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
const event: ThemeAnalyticsEventData = {
|
|
206
|
-
type: 'css_load',
|
|
207
|
-
timestamp: Date.now(),
|
|
208
|
-
themeName,
|
|
209
|
-
data: {
|
|
210
|
-
loadTime,
|
|
211
|
-
...(size ? { size } : {}),
|
|
212
|
-
},
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
this.addEvent(event);
|
|
216
|
-
|
|
217
|
-
this.trackPerformance('css_load_time', loadTime, 'ms');
|
|
218
|
-
if (size !== undefined) {
|
|
219
|
-
this.trackPerformance('css_size', size, 'bytes');
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Track performance metric
|
|
225
|
-
*/
|
|
226
|
-
trackPerformance(name: string, value: number, unit: PerformanceMetric['unit'] = 'ms'): void {
|
|
227
|
-
if (!this.config.enabled || !this.config.trackPerformance) {
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const metric: PerformanceMetric = {
|
|
232
|
-
name,
|
|
233
|
-
value,
|
|
234
|
-
unit,
|
|
235
|
-
timestamp: Date.now(),
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
this.metrics.push(metric);
|
|
239
|
-
|
|
240
|
-
// Keep only last N metrics
|
|
241
|
-
if (this.metrics.length > this.config.bufferSize) {
|
|
242
|
-
this.metrics.shift();
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Notify handler
|
|
246
|
-
if (this.config.onPerformance) {
|
|
247
|
-
try {
|
|
248
|
-
this.config.onPerformance(metric);
|
|
249
|
-
} catch (error) {
|
|
250
|
-
this.logger.error(
|
|
251
|
-
'Error in performance handler',
|
|
252
|
-
error instanceof Error ? error : new Error(String(error)),
|
|
253
|
-
{ metric }
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Add event to buffer
|
|
261
|
-
*/
|
|
262
|
-
private addEvent(event: ThemeAnalyticsEventData): void {
|
|
263
|
-
this.events.push(event);
|
|
264
|
-
|
|
265
|
-
// Keep only last N events
|
|
266
|
-
if (this.events.length > this.config.bufferSize) {
|
|
267
|
-
this.events.shift();
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Notify handler immediately
|
|
271
|
-
if (this.config.onEvent) {
|
|
272
|
-
try {
|
|
273
|
-
this.config.onEvent(event);
|
|
274
|
-
} catch (error) {
|
|
275
|
-
this.logger.error(
|
|
276
|
-
'Error in event handler',
|
|
277
|
-
error instanceof Error ? error : new Error(String(error)),
|
|
278
|
-
{ event }
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Get all events
|
|
286
|
-
*/
|
|
287
|
-
getEvents(): ThemeAnalyticsEventData[] {
|
|
288
|
-
return [...this.events];
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Get all metrics
|
|
293
|
-
*/
|
|
294
|
-
getMetrics(): PerformanceMetric[] {
|
|
295
|
-
return [...this.metrics];
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Get events by type
|
|
300
|
-
*/
|
|
301
|
-
getEventsByType(type: ThemeAnalyticsEvent): ThemeAnalyticsEventData[] {
|
|
302
|
-
return this.events.filter(event => event.type === type);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Get metrics by name
|
|
307
|
-
*/
|
|
308
|
-
getMetricsByName(name: string): PerformanceMetric[] {
|
|
309
|
-
return this.metrics.filter(metric => metric.name === name);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Get average performance metric
|
|
314
|
-
*/
|
|
315
|
-
getAverageMetric(name: string): number | null {
|
|
316
|
-
const metrics = this.getMetricsByName(name);
|
|
317
|
-
if (metrics.length === 0) {
|
|
318
|
-
return null;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
const sum = metrics.reduce((acc, metric) => acc + metric.value, 0);
|
|
322
|
-
return sum / metrics.length;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
/**
|
|
326
|
-
* Clear all events and metrics
|
|
327
|
-
*/
|
|
328
|
-
clear(): void {
|
|
329
|
-
this.events = [];
|
|
330
|
-
this.metrics = [];
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Start flush timer
|
|
335
|
-
*/
|
|
336
|
-
private startFlushTimer(): void {
|
|
337
|
-
if (this.flushTimer) {
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
this.flushTimer = setInterval(() => {
|
|
342
|
-
// Auto-flush can be implemented here if needed
|
|
343
|
-
// For now, events are sent immediately via onEvent callback
|
|
344
|
-
}, this.config.flushInterval);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Stop flush timer
|
|
349
|
-
*/
|
|
350
|
-
private stopFlushTimer(): void {
|
|
351
|
-
if (this.flushTimer) {
|
|
352
|
-
clearInterval(this.flushTimer);
|
|
353
|
-
this.flushTimer = null;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Enable analytics
|
|
359
|
-
*/
|
|
360
|
-
enable(): void {
|
|
361
|
-
this.config.enabled = true;
|
|
362
|
-
this.startFlushTimer();
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Disable analytics
|
|
367
|
-
*/
|
|
368
|
-
disable(): void {
|
|
369
|
-
this.config.enabled = false;
|
|
370
|
-
this.stopFlushTimer();
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Destroy analytics instance
|
|
375
|
-
*/
|
|
376
|
-
destroy(): void {
|
|
377
|
-
this.stopFlushTimer();
|
|
378
|
-
this.clear();
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Create theme analytics instance
|
|
384
|
-
*/
|
|
385
|
-
export function createThemeAnalytics(config?: AnalyticsConfig): ThemeAnalytics {
|
|
386
|
-
return new ThemeAnalytics(config);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Global analytics instance (optional)
|
|
391
|
-
*/
|
|
392
|
-
let globalAnalytics: ThemeAnalytics | null = null;
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Get or create global analytics instance
|
|
396
|
-
*/
|
|
397
|
-
export function getGlobalAnalytics(): ThemeAnalytics {
|
|
398
|
-
if (!globalAnalytics) {
|
|
399
|
-
globalAnalytics = createThemeAnalytics();
|
|
400
|
-
}
|
|
401
|
-
return globalAnalytics;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Set global analytics instance
|
|
406
|
-
*/
|
|
407
|
-
export function setGlobalAnalytics(analytics: ThemeAnalytics): void {
|
|
408
|
-
globalAnalytics = analytics;
|
|
409
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Theme Monitoring and Analytics Module
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export * from './ThemeAnalytics';
|
|
6
|
-
export {
|
|
7
|
-
ThemeAnalytics,
|
|
8
|
-
createThemeAnalytics,
|
|
9
|
-
getGlobalAnalytics,
|
|
10
|
-
setGlobalAnalytics,
|
|
11
|
-
} from './ThemeAnalytics';
|
|
12
|
-
export type {
|
|
13
|
-
ThemeAnalyticsEvent,
|
|
14
|
-
ThemeAnalyticsEventData,
|
|
15
|
-
PerformanceMetric,
|
|
16
|
-
AnalyticsConfig,
|
|
17
|
-
} from './ThemeAnalytics';
|