@shohojdhara/atomix 0.3.0 → 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 +753 -643
- package/dist/atomix.min.css +3 -5
- package/dist/index.d.ts +3075 -247
- package/dist/index.esm.js +20412 -16601
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +20379 -16605
- 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/components/AtomixGlass/AtomixGlass.test.tsx +21 -32
- package/src/components/AtomixGlass/AtomixGlass.tsx +55 -42
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +205 -57
- package/src/components/AtomixGlass/GlassFilter.tsx +22 -8
- package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +221 -0
- package/src/components/AtomixGlass/atomixGLass.old.tsx +0 -3
- package/src/components/AtomixGlass/shader-utils.ts +8 -0
- package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +319 -100
- package/src/components/AtomixGlass/stories/Examples.stories.tsx +601 -105
- package/src/components/AtomixGlass/stories/Modes.stories.tsx +30 -12
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +173 -38
- package/src/components/AtomixGlass/stories/ShaderVariants.stories.tsx +18 -18
- package/src/components/AtomixGlass/stories/shared-components.tsx +27 -5
- package/src/components/Button/Button.tsx +62 -17
- package/src/components/Callout/Callout.test.tsx +8 -14
- package/src/components/Card/Card.tsx +103 -1
- package/src/components/Card/index.ts +3 -2
- package/src/components/Icon/index.ts +1 -1
- package/src/components/Modal/Modal.stories.tsx +29 -38
- package/src/components/Modal/Modal.tsx +4 -4
- package/src/components/Navigation/SideMenu/SideMenu.tsx +49 -41
- package/src/components/Navigation/SideMenu/SideMenuItem.tsx +63 -24
- package/src/components/Popover/Popover.tsx +1 -1
- package/src/components/VideoPlayer/VideoPlayer.stories.tsx +977 -400
- package/src/components/VideoPlayer/VideoPlayer.tsx +1 -6
- package/src/lib/composables/shared-mouse-tracker.ts +133 -0
- package/src/lib/composables/useAtomixGlass.ts +333 -145
- package/src/lib/index.ts +1 -4
- package/src/lib/theme/composeTheme.ts +375 -0
- 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 +521 -0
- 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 +797 -0
- 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 +221 -10
- 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/themeUtils.ts +333 -0
- package/src/lib/theme/types.ts +340 -9
- 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/lib/types/components.ts +148 -59
- package/src/styles/01-settings/_index.scss +2 -2
- package/src/styles/01-settings/_settings.badge.scss +3 -3
- package/src/styles/01-settings/_settings.border-radius.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.maps.scss → _settings.design-tokens.scss} +163 -49
- package/src/styles/01-settings/_settings.input.scss +1 -1
- package/src/styles/01-settings/_settings.modal.scss +1 -1
- package/src/styles/01-settings/_settings.navbar.scss +1 -1
- package/src/styles/01-settings/_settings.spacing.scss +14 -13
- package/src/styles/01-settings/_settings.upload.scss +1 -1
- package/src/styles/03-generic/_generic.root.scss +131 -50
- package/src/styles/05-objects/_objects.block.scss +1 -1
- package/src/styles/06-components/_components.atomix-glass.scss +20 -22
- package/src/styles/06-components/_components.badge.scss +2 -2
- package/src/styles/06-components/_components.button.scss +1 -1
- package/src/styles/06-components/_components.callout.scss +1 -1
- package/src/styles/06-components/_components.card.scss +74 -2
- package/src/styles/06-components/_components.chart.scss +3 -3
- package/src/styles/06-components/_components.dropdown.scss +6 -0
- package/src/styles/06-components/_components.footer.scss +1 -1
- package/src/styles/06-components/_components.list-group.scss +1 -1
- package/src/styles/06-components/_components.list.scss +1 -1
- package/src/styles/06-components/_components.menu.scss +1 -1
- package/src/styles/06-components/_components.messages.scss +1 -1
- package/src/styles/06-components/_components.modal.scss +7 -2
- package/src/styles/06-components/_components.navbar.scss +1 -1
- package/src/styles/06-components/_components.popover.scss +10 -0
- package/src/styles/06-components/_components.product-review.scss +1 -1
- package/src/styles/06-components/_components.progress.scss +1 -1
- package/src/styles/06-components/_components.rating.scss +1 -1
- package/src/styles/06-components/_components.spinner.scss +1 -1
- package/src/styles/99-utilities/_utilities.background.scss +1 -1
- package/src/styles/99-utilities/_utilities.border.scss +28 -59
- package/src/styles/99-utilities/_utilities.gradient.scss +12 -0
- package/src/styles/99-utilities/_utilities.link.scss +1 -1
- 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 +31 -50
- package/dist/themes/applemix.css +0 -15411
- package/dist/themes/applemix.min.css +0 -72
- package/dist/themes/boomdevs.css +0 -15001
- package/dist/themes/boomdevs.min.css +0 -405
- package/dist/themes/esrar.css +0 -17195
- package/dist/themes/esrar.min.css +0 -189
- package/dist/themes/flashtrade.css +0 -16408
- package/dist/themes/flashtrade.min.css +0 -192
- package/dist/themes/mashroom.css +0 -29900
- package/dist/themes/mashroom.min.css +0 -403
- package/dist/themes/shaj-default.css +0 -16024
- package/dist/themes/shaj-default.min.css +0 -500
- package/src/lib/theme/ThemeManager.stories.tsx +0 -472
- package/src/lib/theme/ThemeManager.test.ts +0 -186
- package/src/lib/theme/ThemeManager.ts +0 -501
- package/src/lib/theme/ThemeProvider.tsx +0 -227
- package/src/lib/theme/useTheme.test.tsx +0 -66
- package/src/lib/theme/useTheme.ts +0 -80
- package/src/lib/theme/utils.test.ts +0 -140
package/src/lib/index.ts
CHANGED
|
@@ -10,7 +10,4 @@ export const composables: typeof composablesImport = composablesImport;
|
|
|
10
10
|
export const utils: typeof utilsImport = utilsImport;
|
|
11
11
|
export const types: typeof typesImport = typesImport;
|
|
12
12
|
export const constants: typeof constantsImport = constantsImport;
|
|
13
|
-
export const theme: typeof themeImport = themeImport;
|
|
14
|
-
|
|
15
|
-
// Also export theme utilities directly for convenience
|
|
16
|
-
export * from './theme';
|
|
13
|
+
export const theme: typeof themeImport = themeImport;
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Composition Utilities
|
|
3
|
+
*
|
|
4
|
+
* Utilities for composing, merging, and extending themes.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Theme, ThemeOptions } from './types';
|
|
8
|
+
import { createTheme } from './createTheme';
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Deep Merge Utility
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Check if value is an object
|
|
16
|
+
*/
|
|
17
|
+
function isObject(item: any): item is Record<string, any> {
|
|
18
|
+
return item && typeof item === 'object' && !Array.isArray(item) && typeof item !== 'function';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Deep merge multiple objects
|
|
23
|
+
* Later objects override earlier ones
|
|
24
|
+
*/
|
|
25
|
+
export function deepMerge<T extends Record<string, any>>(...objects: Partial<T>[]): T {
|
|
26
|
+
if (objects.length === 0) return {} as T;
|
|
27
|
+
if (objects.length === 1) return objects[0] as T;
|
|
28
|
+
|
|
29
|
+
const [target, ...sources] = objects;
|
|
30
|
+
const result = { ...target } as T;
|
|
31
|
+
|
|
32
|
+
for (const source of sources) {
|
|
33
|
+
if (!source) continue;
|
|
34
|
+
|
|
35
|
+
for (const key in source) {
|
|
36
|
+
if (!source.hasOwnProperty(key)) continue;
|
|
37
|
+
|
|
38
|
+
const targetValue = result[key];
|
|
39
|
+
const sourceValue = source[key];
|
|
40
|
+
|
|
41
|
+
if (isObject(targetValue) && isObject(sourceValue)) {
|
|
42
|
+
// Recursively merge objects
|
|
43
|
+
result[key] = deepMerge(targetValue as any, sourceValue as any) as any;
|
|
44
|
+
} else {
|
|
45
|
+
// Override with source value
|
|
46
|
+
result[key] = sourceValue as any;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// Theme Merging
|
|
56
|
+
// ============================================================================
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Merge multiple theme options into a single theme options object
|
|
60
|
+
*
|
|
61
|
+
* @param themes - Theme options to merge
|
|
62
|
+
* @returns Merged theme options
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const baseTheme = { palette: { primary: { main: '#000' } } };
|
|
67
|
+
* const customTheme = { palette: { secondary: { main: '#fff' } } };
|
|
68
|
+
* const merged = mergeTheme(baseTheme, customTheme);
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export function mergeTheme(...themes: ThemeOptions[]): ThemeOptions {
|
|
72
|
+
return deepMerge({}, ...themes);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Extend an existing theme with new options
|
|
77
|
+
*
|
|
78
|
+
* @param baseTheme - Base theme to extend (can be Theme or ThemeOptions)
|
|
79
|
+
* @param extension - Theme options to extend with
|
|
80
|
+
* @returns New theme with extended options
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* const base = createTheme({ palette: { primary: { main: '#000' } } });
|
|
85
|
+
* const extended = extendTheme(base, {
|
|
86
|
+
* palette: { secondary: { main: '#fff' } }
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
export function extendTheme(baseTheme: Theme | ThemeOptions, extension: ThemeOptions): Theme {
|
|
91
|
+
// If baseTheme is a complete Theme, extract the options
|
|
92
|
+
const baseOptions: ThemeOptions = (baseTheme as any).__isJSTheme
|
|
93
|
+
? extractThemeOptions(baseTheme as Theme)
|
|
94
|
+
: (baseTheme as ThemeOptions);
|
|
95
|
+
|
|
96
|
+
const merged = mergeTheme(baseOptions, extension);
|
|
97
|
+
return createTheme(merged);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Extract theme options from a complete Theme object
|
|
102
|
+
*/
|
|
103
|
+
function extractThemeOptions(theme: Theme): ThemeOptions {
|
|
104
|
+
return {
|
|
105
|
+
name: theme.name,
|
|
106
|
+
class: theme.class,
|
|
107
|
+
description: theme.description,
|
|
108
|
+
author: theme.author,
|
|
109
|
+
version: theme.version,
|
|
110
|
+
tags: theme.tags,
|
|
111
|
+
supportsDarkMode: theme.supportsDarkMode,
|
|
112
|
+
status: theme.status,
|
|
113
|
+
a11y: theme.a11y,
|
|
114
|
+
color: theme.color,
|
|
115
|
+
features: theme.features,
|
|
116
|
+
dependencies: theme.dependencies,
|
|
117
|
+
palette: {
|
|
118
|
+
primary: theme.palette.primary,
|
|
119
|
+
secondary: theme.palette.secondary,
|
|
120
|
+
error: theme.palette.error,
|
|
121
|
+
warning: theme.palette.warning,
|
|
122
|
+
info: theme.palette.info,
|
|
123
|
+
success: theme.palette.success,
|
|
124
|
+
background: theme.palette.background,
|
|
125
|
+
text: theme.palette.text,
|
|
126
|
+
},
|
|
127
|
+
typography: {
|
|
128
|
+
fontFamily: theme.typography.fontFamily,
|
|
129
|
+
fontSize: theme.typography.fontSize,
|
|
130
|
+
fontWeightLight: theme.typography.fontWeightLight,
|
|
131
|
+
fontWeightRegular: theme.typography.fontWeightRegular,
|
|
132
|
+
fontWeightMedium: theme.typography.fontWeightMedium,
|
|
133
|
+
fontWeightSemiBold: theme.typography.fontWeightSemiBold,
|
|
134
|
+
fontWeightBold: theme.typography.fontWeightBold,
|
|
135
|
+
h1: theme.typography.h1,
|
|
136
|
+
h2: theme.typography.h2,
|
|
137
|
+
h3: theme.typography.h3,
|
|
138
|
+
h4: theme.typography.h4,
|
|
139
|
+
h5: theme.typography.h5,
|
|
140
|
+
h6: theme.typography.h6,
|
|
141
|
+
body1: theme.typography.body1,
|
|
142
|
+
body2: theme.typography.body2,
|
|
143
|
+
},
|
|
144
|
+
shadows: theme.shadows,
|
|
145
|
+
transitions: theme.transitions,
|
|
146
|
+
zIndex: theme.zIndex,
|
|
147
|
+
custom: theme.custom,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ============================================================================
|
|
152
|
+
// Theme Variants
|
|
153
|
+
// ============================================================================
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Create light and dark variants from a base theme
|
|
157
|
+
*
|
|
158
|
+
* @param baseTheme - Base theme options
|
|
159
|
+
* @returns Object with light and dark theme variants
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```typescript
|
|
163
|
+
* const { light, dark } = createThemeVariants({
|
|
164
|
+
* palette: { primary: { main: '#7AFFD7' } }
|
|
165
|
+
* });
|
|
166
|
+
* ```
|
|
167
|
+
*/
|
|
168
|
+
export function createThemeVariants(baseTheme: ThemeOptions): {
|
|
169
|
+
light: Theme;
|
|
170
|
+
dark: Theme;
|
|
171
|
+
} {
|
|
172
|
+
// Light theme (use base as-is or with light adjustments)
|
|
173
|
+
const lightTheme = createTheme({
|
|
174
|
+
...baseTheme,
|
|
175
|
+
name: `${baseTheme.name || 'Custom'} Light`,
|
|
176
|
+
supportsDarkMode: false,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// Dark theme (invert colors)
|
|
180
|
+
const darkTheme = createTheme({
|
|
181
|
+
...baseTheme,
|
|
182
|
+
name: `${baseTheme.name || 'Custom'} Dark`,
|
|
183
|
+
supportsDarkMode: true,
|
|
184
|
+
palette: {
|
|
185
|
+
...baseTheme.palette,
|
|
186
|
+
background: {
|
|
187
|
+
default: '#121212',
|
|
188
|
+
paper: '#1E1E1E',
|
|
189
|
+
subtle: '#2A2A2A',
|
|
190
|
+
...baseTheme.palette?.background,
|
|
191
|
+
},
|
|
192
|
+
text: {
|
|
193
|
+
primary: 'rgba(255, 255, 255, 0.87)',
|
|
194
|
+
secondary: 'rgba(255, 255, 255, 0.6)',
|
|
195
|
+
disabled: 'rgba(255, 255, 255, 0.38)',
|
|
196
|
+
...baseTheme.palette?.text,
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
return { light: lightTheme, dark: darkTheme };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ============================================================================
|
|
205
|
+
// Theme Overrides
|
|
206
|
+
// ============================================================================
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Create a theme with specific overrides
|
|
210
|
+
*
|
|
211
|
+
* @param baseTheme - Base theme
|
|
212
|
+
* @param overrides - Specific overrides to apply
|
|
213
|
+
* @returns New theme with overrides
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* const theme = overrideTheme(baseTheme, {
|
|
218
|
+
* 'palette.primary.main': '#FF0000',
|
|
219
|
+
* 'typography.fontSize': 16,
|
|
220
|
+
* });
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
export function overrideTheme(
|
|
224
|
+
baseTheme: Theme | ThemeOptions,
|
|
225
|
+
overrides: Record<string, any>
|
|
226
|
+
): Theme {
|
|
227
|
+
const baseOptions: ThemeOptions = (baseTheme as any).__isJSTheme
|
|
228
|
+
? extractThemeOptions(baseTheme as Theme)
|
|
229
|
+
: (baseTheme as ThemeOptions);
|
|
230
|
+
|
|
231
|
+
// Convert dot notation overrides to nested object
|
|
232
|
+
const nestedOverrides: any = {};
|
|
233
|
+
for (const [path, value] of Object.entries(overrides)) {
|
|
234
|
+
const keys = path.split('.');
|
|
235
|
+
let current = nestedOverrides;
|
|
236
|
+
|
|
237
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
238
|
+
const key = keys[i] as string;
|
|
239
|
+
if (typeof key !== 'string' || key === '') {
|
|
240
|
+
throw new Error('Invalid override key in theme override: ' + String(key));
|
|
241
|
+
}
|
|
242
|
+
if (typeof current !== 'object' || current === null) {
|
|
243
|
+
throw new Error('Cannot set override for path due to non-object path segment');
|
|
244
|
+
}
|
|
245
|
+
if (!(key in current) || typeof current[key] !== 'object' || current[key] === null) {
|
|
246
|
+
current[key] = {};
|
|
247
|
+
}
|
|
248
|
+
current = current[key] as Record<string, any>;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const lastKey = keys[keys.length - 1] as string;
|
|
252
|
+
if (typeof lastKey === 'string') {
|
|
253
|
+
current[lastKey] = value;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return createTheme(deepMerge(baseOptions, nestedOverrides));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ============================================================================
|
|
262
|
+
// Theme Composition Helpers
|
|
263
|
+
// ============================================================================
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Compose multiple themes by merging them in order
|
|
267
|
+
*
|
|
268
|
+
* @param themes - Themes to compose (later themes override earlier ones)
|
|
269
|
+
* @returns Composed theme
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```typescript
|
|
273
|
+
* const theme = composeThemes(
|
|
274
|
+
* baseTheme,
|
|
275
|
+
* brandTheme,
|
|
276
|
+
* customizationTheme
|
|
277
|
+
* );
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
export function composeThemes(...themes: (Theme | ThemeOptions)[]): Theme {
|
|
281
|
+
const options = themes.map((theme) =>
|
|
282
|
+
(theme as any).__isJSTheme ? extractThemeOptions(theme as Theme) : (theme as ThemeOptions)
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
return createTheme(mergeTheme(...options));
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Create a theme preset with common configurations
|
|
290
|
+
*
|
|
291
|
+
* @param preset - Preset name
|
|
292
|
+
* @param customizations - Additional customizations
|
|
293
|
+
* @returns Theme with preset applied
|
|
294
|
+
*/
|
|
295
|
+
export function createThemePreset(
|
|
296
|
+
preset: 'minimal' | 'modern' | 'classic' | 'vibrant',
|
|
297
|
+
customizations?: ThemeOptions
|
|
298
|
+
): Theme {
|
|
299
|
+
const presets: Record<string, ThemeOptions> = {
|
|
300
|
+
minimal: {
|
|
301
|
+
name: 'Minimal',
|
|
302
|
+
palette: {
|
|
303
|
+
primary: { main: '#000000' },
|
|
304
|
+
secondary: { main: '#FFFFFF' },
|
|
305
|
+
background: {
|
|
306
|
+
default: '#FFFFFF',
|
|
307
|
+
paper: '#F5F5F5',
|
|
308
|
+
subtle: '#FAFAFA',
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
typography: {
|
|
312
|
+
fontFamily: '"Helvetica Neue", Helvetica, Arial, sans-serif',
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
modern: {
|
|
316
|
+
name: 'Modern',
|
|
317
|
+
palette: {
|
|
318
|
+
primary: { main: '#7AFFD7' },
|
|
319
|
+
secondary: { main: '#FF5733' },
|
|
320
|
+
background: {
|
|
321
|
+
default: '#FAFAFA',
|
|
322
|
+
paper: '#FFFFFF',
|
|
323
|
+
subtle: '#F5F5F5',
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
typography: {
|
|
327
|
+
fontFamily: '"Inter", "Roboto", sans-serif',
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
classic: {
|
|
331
|
+
name: 'Classic',
|
|
332
|
+
palette: {
|
|
333
|
+
primary: { main: '#1976D2' },
|
|
334
|
+
secondary: { main: '#DC004E' },
|
|
335
|
+
background: {
|
|
336
|
+
default: '#FFFFFF',
|
|
337
|
+
paper: '#F5F5F5',
|
|
338
|
+
subtle: '#EEEEEE',
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
typography: {
|
|
342
|
+
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
vibrant: {
|
|
346
|
+
name: 'Vibrant',
|
|
347
|
+
palette: {
|
|
348
|
+
primary: { main: '#FF6B6B' },
|
|
349
|
+
secondary: { main: '#4ECDC4' },
|
|
350
|
+
background: {
|
|
351
|
+
default: '#FFF8F0',
|
|
352
|
+
paper: '#FFFFFF',
|
|
353
|
+
subtle: '#FFF0E0',
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
typography: {
|
|
357
|
+
fontFamily: '"Poppins", "Roboto", sans-serif',
|
|
358
|
+
},
|
|
359
|
+
},
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
const basePreset: ThemeOptions = (presets[preset] ?? presets['modern']) as ThemeOptions;
|
|
363
|
+
const customThemeOptions: ThemeOptions = customizations ?? ({} as ThemeOptions);
|
|
364
|
+
return createTheme(mergeTheme(basePreset, customThemeOptions));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export default {
|
|
368
|
+
deepMerge,
|
|
369
|
+
mergeTheme,
|
|
370
|
+
extendTheme,
|
|
371
|
+
createThemeVariants,
|
|
372
|
+
overrideTheme,
|
|
373
|
+
composeThemes,
|
|
374
|
+
createThemePreset,
|
|
375
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Configuration Module
|
|
3
|
+
*
|
|
4
|
+
* Exports for theme configuration loading and validation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { loadThemeConfig, clearConfigCache, getCachedConfig, reloadThemeConfig } from './loader';
|
|
8
|
+
export { validateConfig } from './validator';
|
|
9
|
+
export type {
|
|
10
|
+
ConfigLoaderOptions,
|
|
11
|
+
LoadedThemeConfig,
|
|
12
|
+
ConfigValidationResult,
|
|
13
|
+
ThemeMetadata,
|
|
14
|
+
ThemeConfig,
|
|
15
|
+
ThemeDefinition,
|
|
16
|
+
CSSThemeDefinition,
|
|
17
|
+
JSThemeDefinition,
|
|
18
|
+
BuildConfig,
|
|
19
|
+
RuntimeConfig,
|
|
20
|
+
IntegrationConfig,
|
|
21
|
+
} from './types';
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme Configuration Loader
|
|
3
|
+
*
|
|
4
|
+
* Loads and validates the theme configuration from theme.config.ts
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
ConfigLoaderOptions,
|
|
9
|
+
LoadedThemeConfig,
|
|
10
|
+
ConfigValidationResult,
|
|
11
|
+
} from './types';
|
|
12
|
+
import { validateConfig } from './validator';
|
|
13
|
+
import { ThemeError, ThemeErrorCode, getLogger } from '../errors';
|
|
14
|
+
import {
|
|
15
|
+
DEFAULT_CONFIG_PATH,
|
|
16
|
+
DEFAULT_CONFIG_RELATIVE_PATH,
|
|
17
|
+
DEFAULT_BASE_PATH,
|
|
18
|
+
DEFAULT_STORAGE_KEY,
|
|
19
|
+
DEFAULT_DATA_ATTRIBUTE,
|
|
20
|
+
DEFAULT_INTEGRATION_CLASS_NAMES,
|
|
21
|
+
DEFAULT_INTEGRATION_CSS_VARIABLES,
|
|
22
|
+
DEFAULT_BUILD_OUTPUT_DIR,
|
|
23
|
+
DEFAULT_SASS_CONFIG,
|
|
24
|
+
ENV_DEFAULTS,
|
|
25
|
+
} from '../constants';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Cache for loaded configuration
|
|
29
|
+
*/
|
|
30
|
+
let cachedConfig: LoadedThemeConfig | null = null;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Logger instance
|
|
34
|
+
*/
|
|
35
|
+
const logger = getLogger();
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Load theme configuration from theme.config.ts
|
|
39
|
+
*
|
|
40
|
+
* @param options - Loader options
|
|
41
|
+
* @returns Loaded and validated theme configuration
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* import { loadThemeConfig } from '@shohojdhara/atomix/theme/config';
|
|
46
|
+
* const config = loadThemeConfig();
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export function loadThemeConfig(
|
|
50
|
+
options: ConfigLoaderOptions = {}
|
|
51
|
+
): LoadedThemeConfig {
|
|
52
|
+
const {
|
|
53
|
+
configPath = DEFAULT_CONFIG_PATH,
|
|
54
|
+
validate = true,
|
|
55
|
+
env = typeof process !== 'undefined' && process.env ? (process.env.NODE_ENV === 'production' ? 'production' : 'development') : 'development',
|
|
56
|
+
} = options;
|
|
57
|
+
|
|
58
|
+
// Return cached config if available
|
|
59
|
+
if (cachedConfig) {
|
|
60
|
+
return cachedConfig;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Try to load config dynamically
|
|
64
|
+
let config: LoadedThemeConfig;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
// In browser/Vite environment, we can't load theme.config.ts dynamically
|
|
68
|
+
// This is expected and we'll use the fallback config
|
|
69
|
+
if (typeof window !== 'undefined') {
|
|
70
|
+
throw new Error('Theme config loading not supported in browser environment');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// In Node.js/bundler environment, try require (CommonJS) first
|
|
74
|
+
// Check if we're in a browser environment first
|
|
75
|
+
if (typeof window !== 'undefined' || typeof require === 'undefined') {
|
|
76
|
+
throw new Error('Theme config loading not supported in browser environment');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Type for theme config module
|
|
80
|
+
interface ThemeConfigModule {
|
|
81
|
+
default?: LoadedThemeConfig;
|
|
82
|
+
[key: string]: unknown;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let themeConfigModule: ThemeConfigModule;
|
|
86
|
+
|
|
87
|
+
// Try require (Node.js/CommonJS) - works in Node.js environments
|
|
88
|
+
try {
|
|
89
|
+
// Try relative path first (for build tools)
|
|
90
|
+
try {
|
|
91
|
+
themeConfigModule = require(DEFAULT_CONFIG_RELATIVE_PATH) as ThemeConfigModule;
|
|
92
|
+
} catch {
|
|
93
|
+
// If relative path fails, try to resolve from process.cwd()
|
|
94
|
+
const path = require('path') as typeof import('path');
|
|
95
|
+
const fs = require('fs') as typeof import('fs');
|
|
96
|
+
const configFilePath = path.resolve(process.cwd(), configPath);
|
|
97
|
+
|
|
98
|
+
// Check if file exists
|
|
99
|
+
if (fs.existsSync(configFilePath)) {
|
|
100
|
+
// Delete from cache to force reload
|
|
101
|
+
const resolvedPath = require.resolve(configFilePath);
|
|
102
|
+
if (require.cache && require.cache[resolvedPath]) {
|
|
103
|
+
delete require.cache[resolvedPath];
|
|
104
|
+
}
|
|
105
|
+
themeConfigModule = require(configFilePath) as ThemeConfigModule;
|
|
106
|
+
} else {
|
|
107
|
+
throw new Error(`Config file not found: ${configFilePath}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch (requireError) {
|
|
111
|
+
// If require fails, throw to fall through to error handling
|
|
112
|
+
const errorMessage = requireError instanceof Error
|
|
113
|
+
? requireError.message
|
|
114
|
+
: String(requireError);
|
|
115
|
+
throw new ThemeError(
|
|
116
|
+
`Cannot load theme config: ${errorMessage}`,
|
|
117
|
+
ThemeErrorCode.CONFIG_LOAD_FAILED,
|
|
118
|
+
{ configPath, error: errorMessage }
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const rawConfig = (themeConfigModule.default || themeConfigModule) as LoadedThemeConfig;
|
|
123
|
+
|
|
124
|
+
// Apply environment-specific overrides
|
|
125
|
+
const processedConfig = applyEnvOverrides(rawConfig, env);
|
|
126
|
+
|
|
127
|
+
// Validate if requested
|
|
128
|
+
let validationResult: ConfigValidationResult | null = null;
|
|
129
|
+
if (validate) {
|
|
130
|
+
validationResult = validateConfig(processedConfig);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
config = {
|
|
134
|
+
...processedConfig,
|
|
135
|
+
validated: validate,
|
|
136
|
+
errors: validationResult?.errors,
|
|
137
|
+
warnings: validationResult?.warnings,
|
|
138
|
+
};
|
|
139
|
+
} catch (error) {
|
|
140
|
+
// Fallback: return default config structure
|
|
141
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
142
|
+
logger.warn(`Failed to load theme config from ${configPath}`, {
|
|
143
|
+
configPath,
|
|
144
|
+
error: errorMessage,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
config = {
|
|
148
|
+
themes: {},
|
|
149
|
+
build: {
|
|
150
|
+
output: {
|
|
151
|
+
directory: DEFAULT_BUILD_OUTPUT_DIR,
|
|
152
|
+
formats: {
|
|
153
|
+
expanded: '.css',
|
|
154
|
+
compressed: '.min.css',
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
sass: {
|
|
158
|
+
...DEFAULT_SASS_CONFIG,
|
|
159
|
+
loadPaths: [...DEFAULT_SASS_CONFIG.loadPaths],
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
runtime: {
|
|
163
|
+
basePath: DEFAULT_BASE_PATH,
|
|
164
|
+
cdnPath: null,
|
|
165
|
+
preload: [],
|
|
166
|
+
lazy: true,
|
|
167
|
+
defaultTheme: '', // No default - use built-in styles (empty string instead of undefined)
|
|
168
|
+
storageKey: DEFAULT_STORAGE_KEY,
|
|
169
|
+
dataAttribute: DEFAULT_DATA_ATTRIBUTE,
|
|
170
|
+
enablePersistence: true,
|
|
171
|
+
useMinified: env === 'production',
|
|
172
|
+
},
|
|
173
|
+
integration: {
|
|
174
|
+
cssVariables: DEFAULT_INTEGRATION_CSS_VARIABLES,
|
|
175
|
+
classNames: DEFAULT_INTEGRATION_CLASS_NAMES,
|
|
176
|
+
},
|
|
177
|
+
dependencies: {},
|
|
178
|
+
validated: false,
|
|
179
|
+
errors: [`Failed to load config: ${error instanceof Error ? error.message : String(error)}`],
|
|
180
|
+
warnings: [],
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Cache the loaded config
|
|
185
|
+
cachedConfig = config;
|
|
186
|
+
|
|
187
|
+
return config;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Apply environment-specific overrides to configuration
|
|
192
|
+
*
|
|
193
|
+
* @param config - Base configuration
|
|
194
|
+
* @param env - Environment name
|
|
195
|
+
* @returns Configuration with environment overrides applied
|
|
196
|
+
*/
|
|
197
|
+
function applyEnvOverrides(
|
|
198
|
+
config: LoadedThemeConfig,
|
|
199
|
+
env: 'development' | 'production' | 'test'
|
|
200
|
+
): LoadedThemeConfig {
|
|
201
|
+
const overridden = { ...config };
|
|
202
|
+
|
|
203
|
+
// Production overrides
|
|
204
|
+
if (env === 'production') {
|
|
205
|
+
if (overridden.runtime) {
|
|
206
|
+
overridden.runtime = {
|
|
207
|
+
...overridden.runtime,
|
|
208
|
+
useMinified: true,
|
|
209
|
+
lazy: true,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Development overrides
|
|
215
|
+
if (env === 'development') {
|
|
216
|
+
if (overridden.runtime) {
|
|
217
|
+
overridden.runtime = {
|
|
218
|
+
...overridden.runtime,
|
|
219
|
+
useMinified: false,
|
|
220
|
+
lazy: false,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
if (overridden.build) {
|
|
224
|
+
overridden.build = {
|
|
225
|
+
...overridden.build,
|
|
226
|
+
sass: {
|
|
227
|
+
...overridden.build.sass,
|
|
228
|
+
sourceMap: true,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Test overrides
|
|
235
|
+
if (env === 'test') {
|
|
236
|
+
if (overridden.runtime) {
|
|
237
|
+
overridden.runtime = {
|
|
238
|
+
...overridden.runtime,
|
|
239
|
+
enablePersistence: false,
|
|
240
|
+
preload: [],
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return overridden;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Clear the cached configuration
|
|
250
|
+
* Useful for testing or hot reloading
|
|
251
|
+
*/
|
|
252
|
+
export function clearConfigCache(): void {
|
|
253
|
+
cachedConfig = null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Get cached configuration without loading
|
|
258
|
+
*
|
|
259
|
+
* @returns Cached configuration or null
|
|
260
|
+
*/
|
|
261
|
+
export function getCachedConfig(): LoadedThemeConfig | null {
|
|
262
|
+
return cachedConfig;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Reload configuration (clears cache and loads fresh)
|
|
267
|
+
*
|
|
268
|
+
* @param options - Loader options
|
|
269
|
+
* @returns Freshly loaded configuration
|
|
270
|
+
*/
|
|
271
|
+
export function reloadThemeConfig(
|
|
272
|
+
options: ConfigLoaderOptions = {}
|
|
273
|
+
): LoadedThemeConfig {
|
|
274
|
+
clearConfigCache();
|
|
275
|
+
return loadThemeConfig(options);
|
|
276
|
+
}
|