@shohojdhara/atomix 0.3.1 → 0.3.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/CHANGELOG.md +0 -1
- package/README.md +3 -5
- package/dist/atomix.css +458 -552
- package/dist/atomix.min.css +3 -3
- package/dist/index.d.ts +2435 -358
- package/dist/index.esm.js +5758 -1901
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +5768 -1933
- 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 +1 -11
- package/src/lib/composables/useAtomixGlass.ts +46 -46
- package/src/lib/index.ts +1 -4
- package/src/lib/theme/config/index.ts +21 -0
- package/src/lib/theme/config/loader.ts +276 -0
- package/src/lib/theme/config/types.ts +98 -0
- package/src/lib/theme/config/validator.ts +326 -0
- package/src/lib/theme/constants.ts +183 -0
- package/src/lib/theme/core/ThemeCache.ts +283 -0
- package/src/lib/theme/core/ThemeEngine.test.ts +146 -0
- package/src/lib/theme/core/ThemeEngine.ts +657 -0
- package/src/lib/theme/core/ThemeRegistry.ts +284 -0
- package/src/lib/theme/core/ThemeValidator.ts +530 -0
- package/src/lib/theme/core/index.ts +24 -0
- package/src/lib/theme/createTheme.ts +81 -70
- package/src/lib/theme/devtools/CLI.ts +279 -0
- package/src/lib/theme/devtools/Inspector.tsx +594 -0
- package/src/lib/theme/devtools/Preview.tsx +392 -0
- package/src/lib/theme/devtools/index.ts +21 -0
- package/src/lib/theme/errors.test.ts +207 -0
- package/src/lib/theme/errors.ts +233 -0
- package/src/lib/theme/generateCSSVariables.ts +93 -9
- package/src/lib/theme/generators/CSSGenerator.ts +311 -0
- package/src/lib/theme/generators/ConfigGenerator.ts +287 -0
- package/src/lib/theme/generators/TypeGenerator.ts +228 -0
- package/src/lib/theme/generators/index.ts +21 -0
- package/src/lib/theme/i18n/index.ts +9 -0
- package/src/lib/theme/i18n/rtl.ts +325 -0
- package/src/lib/theme/index.ts +155 -11
- package/src/lib/theme/monitoring/ThemeAnalytics.ts +409 -0
- package/src/lib/theme/monitoring/index.ts +17 -0
- package/src/lib/theme/overrides/ComponentOverrides.ts +243 -0
- package/src/lib/theme/overrides/index.ts +15 -0
- package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +233 -0
- package/src/lib/theme/runtime/ThemeManager.test.ts +176 -0
- package/src/lib/theme/runtime/ThemeManager.ts +442 -0
- package/src/lib/theme/runtime/ThemeProvider.tsx +318 -0
- package/src/lib/theme/runtime/index.ts +17 -0
- package/src/lib/theme/runtime/useTheme.ts +52 -0
- package/src/lib/theme/studio/ThemeStudio.tsx +312 -0
- package/src/lib/theme/studio/index.ts +8 -0
- package/src/lib/theme/types.ts +3 -1
- package/src/lib/theme/utils.ts +23 -22
- package/src/lib/theme/whitelabel/WhiteLabelManager.ts +364 -0
- package/src/lib/theme/whitelabel/index.ts +13 -0
- package/src/styles/01-settings/_settings.badge.scss +1 -1
- package/src/styles/01-settings/_settings.callout.scss +1 -1
- package/src/styles/01-settings/_settings.card.scss +1 -1
- package/src/styles/01-settings/_settings.input.scss +1 -1
- package/src/styles/01-settings/_settings.navbar.scss +1 -1
- package/src/styles/01-settings/_settings.upload.scss +1 -1
- package/src/styles/06-components/_components.chart.scss +2 -2
- package/src/styles/99-utilities/_utilities.border.scss +27 -58
- package/src/styles/99-utilities/_utilities.gradient.scss +12 -0
- package/src/styles/99-utilities/_utilities.position.scss +8 -15
- package/src/styles/99-utilities/_utilities.scss +2 -0
- package/src/styles/99-utilities/_utilities.spacing.scss +76 -121
- package/src/styles/99-utilities/_utilities.text.scss +30 -49
- package/dist/themes/applemix.css +0 -15615
- package/dist/themes/applemix.min.css +0 -70
- package/dist/themes/boomdevs.css +0 -15193
- package/dist/themes/boomdevs.min.css +0 -403
- package/dist/themes/esrar.css +0 -17399
- package/dist/themes/esrar.min.css +0 -187
- package/dist/themes/flashtrade.css +0 -16613
- package/dist/themes/flashtrade.min.css +0 -190
- package/dist/themes/mashroom.css +0 -30104
- package/dist/themes/mashroom.min.css +0 -401
- package/dist/themes/shaj-default.css +0 -16228
- package/dist/themes/shaj-default.min.css +0 -498
- package/src/lib/theme/ThemeManager.integration.test.ts +0 -124
- package/src/lib/theme/ThemeManager.stories.tsx +0 -472
- package/src/lib/theme/ThemeManager.test.ts +0 -190
- package/src/lib/theme/ThemeManager.ts +0 -645
- package/src/lib/theme/ThemeProvider.tsx +0 -377
- package/src/lib/theme/createTheme.test.ts +0 -475
- package/src/lib/theme/useTheme.test.tsx +0 -67
- package/src/lib/theme/useTheme.ts +0 -64
- package/src/lib/theme/utils.test.ts +0 -140
|
@@ -1,377 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Theme Provider
|
|
3
|
-
*
|
|
4
|
-
* React context provider for theme management
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
|
|
8
|
-
import { ThemeManager } from './ThemeManager';
|
|
9
|
-
import { ThemeContext } from './ThemeContext';
|
|
10
|
-
import type { ThemeProviderProps, ThemeMetadata, Theme } from './types';
|
|
11
|
-
import { isJSTheme } from './themeUtils';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* ThemeProvider component
|
|
15
|
-
*
|
|
16
|
-
* Provides theme context to child components and manages theme state.
|
|
17
|
-
*
|
|
18
|
-
* @example
|
|
19
|
-
* ```tsx
|
|
20
|
-
* import { ThemeProvider } from '@shohojdhara/atomix/theme';
|
|
21
|
-
* import { themesConfig } from '@shohojdhara/atomix/themes/themes.config';
|
|
22
|
-
*
|
|
23
|
-
* function App() {
|
|
24
|
-
* return (
|
|
25
|
-
* <ThemeProvider
|
|
26
|
-
* themes={themesConfig.metadata}
|
|
27
|
-
* defaultTheme="shaj-default"
|
|
28
|
-
* >
|
|
29
|
-
* <YourApp />
|
|
30
|
-
* </ThemeProvider>
|
|
31
|
-
* );
|
|
32
|
-
* }
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
export const ThemeProvider: React.FC<ThemeProviderProps> = ({
|
|
36
|
-
children,
|
|
37
|
-
defaultTheme = 'shaj-default',
|
|
38
|
-
themes = {},
|
|
39
|
-
basePath = '/themes',
|
|
40
|
-
cdnPath = null,
|
|
41
|
-
preload = [],
|
|
42
|
-
lazy = true,
|
|
43
|
-
storageKey = 'atomix-theme',
|
|
44
|
-
dataAttribute = 'data-theme',
|
|
45
|
-
enablePersistence = true,
|
|
46
|
-
useMinified = false,
|
|
47
|
-
onThemeChange,
|
|
48
|
-
onError,
|
|
49
|
-
}) => {
|
|
50
|
-
// Store callbacks in refs to avoid recreating ThemeManager when they change
|
|
51
|
-
const onThemeChangeRef = useRef(onThemeChange);
|
|
52
|
-
const onErrorRef = useRef(onError);
|
|
53
|
-
|
|
54
|
-
// Update refs when callbacks change
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
onThemeChangeRef.current = onThemeChange;
|
|
57
|
-
onErrorRef.current = onError;
|
|
58
|
-
}, [onThemeChange, onError]);
|
|
59
|
-
|
|
60
|
-
// Create stable wrapper functions that read from refs
|
|
61
|
-
const handleThemeChange = useCallback((theme: string | Theme) => {
|
|
62
|
-
onThemeChangeRef.current?.(theme);
|
|
63
|
-
}, []);
|
|
64
|
-
|
|
65
|
-
const handleError = useCallback((error: Error, themeName: string) => {
|
|
66
|
-
onErrorRef.current?.(error, themeName);
|
|
67
|
-
}, []);
|
|
68
|
-
|
|
69
|
-
// Stabilize themes object reference to prevent unnecessary recreations
|
|
70
|
-
const themesRef = useRef(themes);
|
|
71
|
-
const themesStable = useMemo(() => {
|
|
72
|
-
// Only update if themes object actually changed (shallow comparison)
|
|
73
|
-
const currentKeys = Object.keys(themes);
|
|
74
|
-
const prevKeys = Object.keys(themesRef.current);
|
|
75
|
-
|
|
76
|
-
if (currentKeys.length !== prevKeys.length) {
|
|
77
|
-
themesRef.current = themes;
|
|
78
|
-
return themes;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const hasChanged = currentKeys.some(key => themes[key] !== themesRef.current[key]);
|
|
82
|
-
if (hasChanged) {
|
|
83
|
-
themesRef.current = themes;
|
|
84
|
-
return themes;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return themesRef.current;
|
|
88
|
-
}, [themes]);
|
|
89
|
-
|
|
90
|
-
// Initialize theme manager (only recreate when config changes, not callbacks)
|
|
91
|
-
const themeManager = useMemo(() => {
|
|
92
|
-
try {
|
|
93
|
-
return new ThemeManager({
|
|
94
|
-
themes: themesStable,
|
|
95
|
-
defaultTheme,
|
|
96
|
-
basePath,
|
|
97
|
-
cdnPath,
|
|
98
|
-
preload,
|
|
99
|
-
lazy,
|
|
100
|
-
storageKey,
|
|
101
|
-
dataAttribute,
|
|
102
|
-
enablePersistence,
|
|
103
|
-
useMinified,
|
|
104
|
-
onThemeChange: handleThemeChange,
|
|
105
|
-
onError: handleError,
|
|
106
|
-
});
|
|
107
|
-
} catch (error) {
|
|
108
|
-
console.error('Failed to initialize ThemeManager:', error);
|
|
109
|
-
// Return a minimal fallback manager
|
|
110
|
-
const fallbackThemes: Record<string, ThemeMetadata> = {};
|
|
111
|
-
let fallbackDefault: string | Theme | undefined = defaultTheme;
|
|
112
|
-
|
|
113
|
-
if (typeof defaultTheme === 'string') {
|
|
114
|
-
// If defaultTheme is a string, add it to fallback themes
|
|
115
|
-
fallbackThemes[defaultTheme] = { name: defaultTheme };
|
|
116
|
-
} else if (defaultTheme && typeof defaultTheme === 'object') {
|
|
117
|
-
// If defaultTheme is a Theme object, add it to fallback themes map
|
|
118
|
-
// so it can be looked up by name later (e.g., getThemeMetadata, validateTheme)
|
|
119
|
-
const themeName = defaultTheme.name || 'custom-theme';
|
|
120
|
-
// Extract ThemeMetadata properties from Theme object (Theme extends ThemeMetadata)
|
|
121
|
-
// Use themeName (with fallback) instead of defaultTheme.name directly to ensure name is always a string
|
|
122
|
-
fallbackThemes[themeName] = {
|
|
123
|
-
name: themeName,
|
|
124
|
-
class: defaultTheme.class,
|
|
125
|
-
description: defaultTheme.description,
|
|
126
|
-
author: defaultTheme.author,
|
|
127
|
-
version: defaultTheme.version,
|
|
128
|
-
tags: defaultTheme.tags,
|
|
129
|
-
supportsDarkMode: defaultTheme.supportsDarkMode,
|
|
130
|
-
status: defaultTheme.status,
|
|
131
|
-
a11y: defaultTheme.a11y,
|
|
132
|
-
color: defaultTheme.color,
|
|
133
|
-
features: defaultTheme.features,
|
|
134
|
-
dependencies: defaultTheme.dependencies,
|
|
135
|
-
};
|
|
136
|
-
// Keep the Theme object as defaultTheme for ThemeManager
|
|
137
|
-
fallbackDefault = defaultTheme;
|
|
138
|
-
} else {
|
|
139
|
-
// If defaultTheme is undefined, create a minimal fallback theme
|
|
140
|
-
// to prevent ThemeManager from throwing an error
|
|
141
|
-
const fallbackThemeName = 'fallback-theme';
|
|
142
|
-
fallbackThemes[fallbackThemeName] = { name: fallbackThemeName };
|
|
143
|
-
fallbackDefault = fallbackThemeName;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
try {
|
|
147
|
-
return new ThemeManager({
|
|
148
|
-
themes: fallbackThemes,
|
|
149
|
-
defaultTheme: fallbackDefault,
|
|
150
|
-
basePath,
|
|
151
|
-
cdnPath,
|
|
152
|
-
preload,
|
|
153
|
-
lazy,
|
|
154
|
-
storageKey,
|
|
155
|
-
dataAttribute,
|
|
156
|
-
enablePersistence,
|
|
157
|
-
useMinified,
|
|
158
|
-
onThemeChange: handleThemeChange,
|
|
159
|
-
onError: handleError,
|
|
160
|
-
});
|
|
161
|
-
} catch (fallbackError) {
|
|
162
|
-
// If even the fallback fails, log and throw
|
|
163
|
-
console.error('Failed to create fallback ThemeManager:', fallbackError);
|
|
164
|
-
throw new Error(
|
|
165
|
-
'ThemeManager initialization failed. Please provide a valid themes configuration or defaultTheme.'
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}, [
|
|
170
|
-
themesStable,
|
|
171
|
-
defaultTheme,
|
|
172
|
-
basePath,
|
|
173
|
-
cdnPath,
|
|
174
|
-
preload,
|
|
175
|
-
lazy,
|
|
176
|
-
storageKey,
|
|
177
|
-
dataAttribute,
|
|
178
|
-
enablePersistence,
|
|
179
|
-
useMinified,
|
|
180
|
-
handleThemeChange,
|
|
181
|
-
handleError,
|
|
182
|
-
]);
|
|
183
|
-
|
|
184
|
-
// State
|
|
185
|
-
const [currentTheme, setCurrentTheme] = useState<string>(themeManager.getTheme());
|
|
186
|
-
const [activeTheme, setActiveTheme] = useState<Theme | null>(themeManager.getActiveTheme());
|
|
187
|
-
const [isLoading, setIsLoading] = useState<boolean>(false);
|
|
188
|
-
const [error, setError] = useState<Error | null>(null);
|
|
189
|
-
|
|
190
|
-
// Get available themes
|
|
191
|
-
const availableThemes = useMemo<ThemeMetadata[]>(
|
|
192
|
-
() => themeManager.getAvailableThemes(),
|
|
193
|
-
[themeManager]
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
// Set theme function
|
|
197
|
-
const setTheme = useCallback(
|
|
198
|
-
async (themeOrName: string | Theme, options?: { fallbackOnError?: boolean }): Promise<void> => {
|
|
199
|
-
setIsLoading(true);
|
|
200
|
-
setError(null);
|
|
201
|
-
|
|
202
|
-
try {
|
|
203
|
-
await themeManager.setTheme(themeOrName, options);
|
|
204
|
-
setCurrentTheme(themeManager.getTheme());
|
|
205
|
-
setActiveTheme(themeManager.getActiveTheme());
|
|
206
|
-
} catch (err) {
|
|
207
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
208
|
-
setError(error);
|
|
209
|
-
|
|
210
|
-
// If fallback is enabled and it's safe to fallback
|
|
211
|
-
if (options?.fallbackOnError && defaultTheme) {
|
|
212
|
-
// Avoid infinite loops if fallback is same as current attempt
|
|
213
|
-
const targetName = isJSTheme(themeOrName) ? themeOrName.name : themeOrName;
|
|
214
|
-
const defName = isJSTheme(defaultTheme) ? defaultTheme.name : defaultTheme;
|
|
215
|
-
|
|
216
|
-
if (targetName !== defName) {
|
|
217
|
-
try {
|
|
218
|
-
await themeManager.setTheme(defaultTheme, { fallbackOnError: false });
|
|
219
|
-
setCurrentTheme(themeManager.getTheme());
|
|
220
|
-
setActiveTheme(themeManager.getActiveTheme());
|
|
221
|
-
setError(null);
|
|
222
|
-
return;
|
|
223
|
-
} catch (fallbackErr) {
|
|
224
|
-
// If fallback also fails, throw original error
|
|
225
|
-
throw error;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
throw error;
|
|
231
|
-
} finally {
|
|
232
|
-
setIsLoading(false);
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
[themeManager, defaultTheme]
|
|
236
|
-
);
|
|
237
|
-
|
|
238
|
-
// Check if theme is loaded
|
|
239
|
-
const isThemeLoaded = useCallback(
|
|
240
|
-
(themeName: string): boolean => {
|
|
241
|
-
return themeManager.isThemeLoaded(themeName);
|
|
242
|
-
},
|
|
243
|
-
[themeManager]
|
|
244
|
-
);
|
|
245
|
-
|
|
246
|
-
// Preload theme
|
|
247
|
-
const preloadTheme = useCallback(
|
|
248
|
-
async (themeName: string): Promise<void> => {
|
|
249
|
-
try {
|
|
250
|
-
await themeManager.preloadTheme(themeName);
|
|
251
|
-
} catch (err) {
|
|
252
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
253
|
-
setError(error);
|
|
254
|
-
throw error;
|
|
255
|
-
}
|
|
256
|
-
},
|
|
257
|
-
[themeManager]
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
// Listen for theme changes
|
|
261
|
-
useEffect(() => {
|
|
262
|
-
const handleThemeChange = () => {
|
|
263
|
-
setCurrentTheme(themeManager.getTheme());
|
|
264
|
-
setActiveTheme(themeManager.getActiveTheme());
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
themeManager.on('themeChange', handleThemeChange);
|
|
268
|
-
|
|
269
|
-
return () => {
|
|
270
|
-
themeManager.off('themeChange', handleThemeChange);
|
|
271
|
-
};
|
|
272
|
-
}, [themeManager]);
|
|
273
|
-
|
|
274
|
-
// Track the last themeManager instance we initialized
|
|
275
|
-
const initializedManagerRef = useRef<ThemeManager | null>(null);
|
|
276
|
-
|
|
277
|
-
// Load initial theme (once per themeManager instance)
|
|
278
|
-
useEffect(() => {
|
|
279
|
-
// Skip if we've already initialized this exact themeManager instance
|
|
280
|
-
if (initializedManagerRef.current === themeManager) {
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Mark this themeManager as initialized synchronously before async work
|
|
285
|
-
// This prevents race conditions where the effect runs again before async completes
|
|
286
|
-
initializedManagerRef.current = themeManager;
|
|
287
|
-
|
|
288
|
-
let isMounted = true;
|
|
289
|
-
|
|
290
|
-
const loadInitialTheme = async () => {
|
|
291
|
-
setIsLoading(true);
|
|
292
|
-
try {
|
|
293
|
-
// If currentTheme is set (from config/storage), use it.
|
|
294
|
-
// If activeTheme is set (from config default), use it.
|
|
295
|
-
const current = themeManager.getTheme();
|
|
296
|
-
const active = themeManager.getActiveTheme();
|
|
297
|
-
|
|
298
|
-
// Only load if theme is not already loaded
|
|
299
|
-
const isAlreadyLoaded = themeManager.isThemeLoaded(current) || (active && themeManager.isThemeLoaded(active.name || ''));
|
|
300
|
-
|
|
301
|
-
if (!isAlreadyLoaded) {
|
|
302
|
-
// If we have an active object, or a name, ensure it's "set" (loaded).
|
|
303
|
-
if (active) {
|
|
304
|
-
await themeManager.setTheme(active, { removePrevious: false });
|
|
305
|
-
} else if (current) {
|
|
306
|
-
await themeManager.setTheme(current, { removePrevious: false });
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Update state even if theme was already loaded
|
|
311
|
-
if (isMounted) {
|
|
312
|
-
setCurrentTheme(themeManager.getTheme());
|
|
313
|
-
setActiveTheme(themeManager.getActiveTheme());
|
|
314
|
-
}
|
|
315
|
-
} catch (err) {
|
|
316
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
317
|
-
if (isMounted) {
|
|
318
|
-
setError(error);
|
|
319
|
-
console.error('Failed to load initial theme:', error);
|
|
320
|
-
}
|
|
321
|
-
} finally {
|
|
322
|
-
if (isMounted) {
|
|
323
|
-
setIsLoading(false);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
loadInitialTheme();
|
|
329
|
-
|
|
330
|
-
return () => {
|
|
331
|
-
isMounted = false;
|
|
332
|
-
};
|
|
333
|
-
}, [themeManager]);
|
|
334
|
-
|
|
335
|
-
// Cleanup on unmount
|
|
336
|
-
useEffect(() => {
|
|
337
|
-
return () => {
|
|
338
|
-
themeManager.destroy();
|
|
339
|
-
};
|
|
340
|
-
}, [themeManager]);
|
|
341
|
-
|
|
342
|
-
// Context value
|
|
343
|
-
const contextValue = useMemo(
|
|
344
|
-
() => ({
|
|
345
|
-
theme: currentTheme,
|
|
346
|
-
activeTheme,
|
|
347
|
-
setTheme,
|
|
348
|
-
availableThemes,
|
|
349
|
-
isLoading,
|
|
350
|
-
error,
|
|
351
|
-
isThemeLoaded,
|
|
352
|
-
preloadTheme,
|
|
353
|
-
themeManager,
|
|
354
|
-
}),
|
|
355
|
-
[
|
|
356
|
-
currentTheme,
|
|
357
|
-
activeTheme,
|
|
358
|
-
setTheme,
|
|
359
|
-
availableThemes,
|
|
360
|
-
isLoading,
|
|
361
|
-
error,
|
|
362
|
-
isThemeLoaded,
|
|
363
|
-
preloadTheme,
|
|
364
|
-
themeManager,
|
|
365
|
-
]
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
return (
|
|
369
|
-
<ThemeContext.Provider value={contextValue}>
|
|
370
|
-
{children}
|
|
371
|
-
</ThemeContext.Provider>
|
|
372
|
-
);
|
|
373
|
-
};
|
|
374
|
-
|
|
375
|
-
ThemeProvider.displayName = 'ThemeProvider';
|
|
376
|
-
|
|
377
|
-
export default ThemeProvider;
|