@shohojdhara/atomix 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/README.md +101 -199
  2. package/atomix.config.ts +241 -0
  3. package/dist/atomix.css +269 -189
  4. package/dist/atomix.css.map +1 -0
  5. package/dist/atomix.min.css +15179 -11
  6. package/dist/atomix.min.css.map +1 -0
  7. package/dist/charts.d.ts +1929 -0
  8. package/dist/charts.js +6477 -0
  9. package/dist/charts.js.map +1 -0
  10. package/dist/core.d.ts +1289 -0
  11. package/dist/core.js +3373 -0
  12. package/dist/core.js.map +1 -0
  13. package/dist/forms.d.ts +1085 -0
  14. package/dist/forms.js +2466 -0
  15. package/dist/forms.js.map +1 -0
  16. package/dist/heavy.d.ts +636 -0
  17. package/dist/heavy.js +4566 -0
  18. package/dist/heavy.js.map +1 -0
  19. package/dist/index.d.ts +5171 -4792
  20. package/dist/index.esm.js +6098 -4563
  21. package/dist/index.esm.js.map +1 -1
  22. package/dist/index.js +6291 -4747
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.min.js +1 -1
  25. package/dist/index.min.js.map +1 -1
  26. package/dist/layout.d.ts +300 -0
  27. package/dist/layout.js +336 -0
  28. package/dist/layout.js.map +1 -0
  29. package/dist/theme.d.ts +2122 -0
  30. package/dist/theme.js +6084 -0
  31. package/dist/theme.js.map +1 -0
  32. package/package.json +59 -27
  33. package/scripts/atomix-cli.js +544 -16
  34. package/scripts/cli/__tests__/cli-commands.test.js +204 -0
  35. package/scripts/cli/__tests__/utils.test.js +201 -0
  36. package/scripts/cli/__tests__/vitest.config.js +26 -0
  37. package/scripts/cli/interactive-init.js +1 -1
  38. package/scripts/cli/token-manager.js +32 -7
  39. package/scripts/cli/utils.js +347 -0
  40. package/src/components/Accordion/Accordion.stories.tsx +50 -17
  41. package/src/components/Accordion/Accordion.tsx +5 -54
  42. package/src/components/Accordion/index.ts +1 -1
  43. package/src/components/AtomixGlass/AtomixGlass.tsx +65 -31
  44. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +11 -4
  45. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1 -32
  46. package/src/components/AtomixGlass/stories/Examples.stories.tsx +2 -2
  47. package/src/components/AtomixGlass/stories/shared-components.tsx +0 -31
  48. package/src/components/Avatar/Avatar.stories.tsx +7 -0
  49. package/src/components/Avatar/Avatar.tsx +3 -3
  50. package/src/components/Badge/Badge.stories.tsx +91 -13
  51. package/src/components/Badge/Badge.tsx +3 -3
  52. package/src/components/Block/Block.stories.tsx +7 -23
  53. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +7 -0
  54. package/src/components/Breadcrumb/Breadcrumb.tsx +3 -3
  55. package/src/components/Button/Button.stories.tsx +141 -22
  56. package/src/components/Button/ButtonGroup.stories.tsx +315 -0
  57. package/src/components/Button/ButtonGroup.tsx +67 -0
  58. package/src/components/Button/index.ts +2 -0
  59. package/src/components/Callout/Callout.stories.tsx +8 -6
  60. package/src/components/Card/Card.stories.tsx +82 -28
  61. package/src/components/Card/ElevationCard.tsx +1 -1
  62. package/src/components/Chart/AnimatedChart.tsx +19 -18
  63. package/src/components/Chart/AreaChart.tsx +5 -2
  64. package/src/components/Chart/BarChart.tsx +1 -1
  65. package/src/components/Chart/BubbleChart.tsx +6 -6
  66. package/src/components/Chart/CandlestickChart.tsx +0 -1
  67. package/src/components/Chart/Chart.stories.tsx +5 -7
  68. package/src/components/Chart/Chart.tsx +0 -16
  69. package/src/components/Chart/ChartRenderer.tsx +1 -1
  70. package/src/components/Chart/ChartToolbar.tsx +1 -0
  71. package/src/components/Chart/DonutChart.tsx +0 -1
  72. package/src/components/Chart/FunnelChart.tsx +1 -2
  73. package/src/components/Chart/GaugeChart.tsx +0 -1
  74. package/src/components/Chart/HeatmapChart.tsx +0 -1
  75. package/src/components/Chart/LineChart.tsx +0 -1
  76. package/src/components/Chart/MultiAxisChart.tsx +0 -1
  77. package/src/components/Chart/PieChart.tsx +0 -1
  78. package/src/components/Chart/RadarChart.tsx +19 -13
  79. package/src/components/Chart/ScatterChart.tsx +3 -4
  80. package/src/components/Chart/TreemapChart.tsx +2 -1
  81. package/src/components/Chart/WaterfallChart.tsx +0 -2
  82. package/src/components/Chart/types.ts +12 -2
  83. package/src/components/Chart/utils.ts +4 -3
  84. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +7 -0
  85. package/src/components/DataTable/DataTable.stories.tsx +23 -16
  86. package/src/components/DataTable/DataTable.tsx +3 -3
  87. package/src/components/DatePicker/DatePicker.stories.tsx +27 -19
  88. package/src/components/Dropdown/Dropdown.stories.tsx +11 -19
  89. package/src/components/Dropdown/Dropdown.tsx +12 -9
  90. package/src/components/EdgePanel/EdgePanel.stories.tsx +1 -0
  91. package/src/components/Footer/Footer.stories.tsx +8 -6
  92. package/src/components/Footer/FooterLink.tsx +9 -2
  93. package/src/components/Footer/FooterSection.tsx +3 -3
  94. package/src/components/Form/Checkbox.stories.tsx +7 -0
  95. package/src/components/Form/Checkbox.tsx +3 -3
  96. package/src/components/Form/Form.stories.tsx +7 -0
  97. package/src/components/Form/FormGroup.stories.tsx +9 -1
  98. package/src/components/Form/Input.stories.tsx +69 -16
  99. package/src/components/Form/Input.tsx +4 -2
  100. package/src/components/Form/Radio.stories.tsx +9 -1
  101. package/src/components/Form/Radio.tsx +3 -3
  102. package/src/components/Form/Select.stories.tsx +9 -1
  103. package/src/components/Form/Select.tsx +3 -3
  104. package/src/components/Form/Textarea.stories.tsx +10 -2
  105. package/src/components/Form/Textarea.tsx +4 -2
  106. package/src/components/Hero/Hero.stories.tsx +7 -0
  107. package/src/components/List/List.stories.tsx +10 -3
  108. package/src/components/List/List.tsx +3 -3
  109. package/src/components/List/ListGroup.tsx +3 -1
  110. package/src/components/Messages/Messages.stories.tsx +8 -7
  111. package/src/components/Modal/Modal.stories.tsx +17 -6
  112. package/src/components/Modal/Modal.tsx +3 -3
  113. package/src/components/Navigation/Menu/MegaMenu.tsx +9 -3
  114. package/src/components/Navigation/Menu/Menu.stories.tsx +7 -0
  115. package/src/components/Navigation/Menu/Menu.tsx +9 -3
  116. package/src/components/Navigation/Nav/Nav.stories.tsx +7 -0
  117. package/src/components/Navigation/Navbar/Navbar.stories.tsx +1 -0
  118. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +1 -1
  119. package/src/components/Pagination/Pagination.stories.tsx +188 -111
  120. package/src/components/Pagination/Pagination.tsx +88 -7
  121. package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -5
  122. package/src/components/PhotoViewer/PhotoViewerImage.tsx +2 -2
  123. package/src/components/Popover/Popover.stories.tsx +191 -115
  124. package/src/components/Popover/Popover.tsx +4 -4
  125. package/src/components/ProductReview/ProductReview.stories.tsx +80 -58
  126. package/src/components/Progress/Progress.stories.tsx +79 -49
  127. package/src/components/Progress/Progress.tsx +6 -2
  128. package/src/components/Rating/Rating.stories.tsx +109 -84
  129. package/src/components/Rating/Rating.tsx +5 -2
  130. package/src/components/River/River.stories.tsx +194 -114
  131. package/src/components/SectionIntro/SectionIntro.stories.tsx +19 -9
  132. package/src/components/Slider/Slider.stories.tsx +7 -0
  133. package/src/components/Slider/Slider.tsx +10 -9
  134. package/src/components/Spinner/Spinner.stories.tsx +15 -11
  135. package/src/components/Spinner/Spinner.tsx +3 -3
  136. package/src/components/Steps/Steps.stories.tsx +132 -98
  137. package/src/components/Tabs/Tabs.stories.tsx +163 -112
  138. package/src/components/Tabs/Tabs.tsx +3 -3
  139. package/src/components/Testimonial/Testimonial.stories.tsx +114 -68
  140. package/src/components/Todo/Todo.stories.tsx +38 -12
  141. package/src/components/Toggle/Toggle.stories.tsx +61 -28
  142. package/src/components/Tooltip/Tooltip.stories.tsx +318 -200
  143. package/src/components/Tooltip/Tooltip.tsx +3 -3
  144. package/src/components/Upload/Upload.stories.tsx +122 -84
  145. package/src/components/VideoPlayer/VideoPlayer.stories.tsx +7 -24
  146. package/src/components/index.ts +6 -2
  147. package/src/layouts/MasonryGrid/MasonryGrid.tsx +2 -2
  148. package/src/lib/composables/useAtomixGlass.ts +2 -3
  149. package/src/lib/composables/useChartPerformance.ts +102 -78
  150. package/src/lib/composables/useChartScale.ts +10 -0
  151. package/src/lib/composables/useHero.ts +9 -2
  152. package/src/lib/composables/useHeroBackgroundSlider.ts +5 -3
  153. package/src/lib/composables/useNavbar.ts +0 -10
  154. package/src/lib/composables/useSideMenu.ts +1 -0
  155. package/src/lib/composables/useVideoPlayer.ts +3 -2
  156. package/src/lib/config/loader.ts +57 -14
  157. package/src/lib/constants/components.ts +10 -0
  158. package/src/lib/hooks/index.ts +0 -1
  159. package/src/lib/hooks/useComponentCustomization.ts +11 -15
  160. package/src/lib/hooks/usePerformanceMonitor.ts +149 -0
  161. package/src/lib/patterns/index.ts +2 -2
  162. package/src/lib/patterns/slots.tsx +2 -2
  163. package/src/lib/theme/README.md +174 -0
  164. package/src/lib/theme/adapters/index.ts +31 -0
  165. package/src/lib/theme/adapters/themeAdapter.ts +287 -0
  166. package/src/lib/theme/config/__tests__/configLoader.test.ts +207 -0
  167. package/src/lib/theme/config/configLoader.ts +254 -0
  168. package/src/lib/theme/config/loader.ts +37 -48
  169. package/src/lib/theme/config/types.ts +2 -2
  170. package/src/lib/theme/config/validator.ts +15 -91
  171. package/src/lib/theme/{constants.ts → constants/constants.ts} +0 -18
  172. package/src/lib/theme/constants/index.ts +8 -0
  173. package/src/lib/theme/core/ThemeRegistry.ts +19 -6
  174. package/src/lib/theme/core/__tests__/createTheme.test.ts +132 -0
  175. package/src/lib/theme/core/composeTheme.ts +155 -0
  176. package/src/lib/theme/core/createTheme.ts +94 -0
  177. package/src/lib/theme/{createTheme.ts → core/createThemeObject.ts} +10 -6
  178. package/src/lib/theme/core/index.ts +5 -19
  179. package/src/lib/theme/devtools/Comparator.tsx +346 -22
  180. package/src/lib/theme/devtools/IMPROVEMENTS.md +139 -38
  181. package/src/lib/theme/devtools/Inspector.tsx +335 -51
  182. package/src/lib/theme/devtools/LiveEditor.tsx +489 -112
  183. package/src/lib/theme/devtools/Preview.tsx +471 -221
  184. package/src/lib/theme/{core → devtools}/ThemeValidator.ts +6 -3
  185. package/src/lib/theme/devtools/index.ts +14 -4
  186. package/src/lib/theme/devtools/useHistory.ts +130 -0
  187. package/src/lib/theme/errors/index.ts +12 -0
  188. package/src/lib/theme/generators/cssFile.ts +79 -0
  189. package/src/lib/theme/generators/generateCSS.ts +89 -0
  190. package/src/lib/theme/{generateCSSVariables.ts → generators/generateCSSVariables.ts} +4 -14
  191. package/src/lib/theme/generators/index.ts +19 -0
  192. package/src/lib/theme/i18n/rtl.ts +7 -7
  193. package/src/lib/theme/index.ts +120 -15
  194. package/src/lib/theme/runtime/ThemeApplicator.ts +53 -95
  195. package/src/lib/theme/{ThemeContext.tsx → runtime/ThemeContext.tsx} +1 -1
  196. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +4 -4
  197. package/src/lib/theme/runtime/ThemeProvider.tsx +456 -179
  198. package/src/lib/theme/runtime/index.ts +1 -2
  199. package/src/lib/theme/runtime/useTheme.ts +1 -2
  200. package/src/lib/theme/test/testTheme.ts +385 -0
  201. package/src/lib/theme/tokens/index.ts +12 -0
  202. package/src/lib/theme/tokens/tokens.ts +721 -0
  203. package/src/lib/theme/types.ts +6 -42
  204. package/src/lib/theme/{utils.ts → utils/domUtils.ts} +2 -2
  205. package/src/lib/theme/utils/index.ts +11 -0
  206. package/src/lib/theme/utils/injectCSS.ts +90 -0
  207. package/src/lib/theme/utils/themeHelpers.ts +78 -0
  208. package/src/lib/theme/{themeUtils.ts → utils/themeUtils.ts} +1 -1
  209. package/src/lib/theme-tools.ts +8 -9
  210. package/src/lib/types/components.ts +93 -34
  211. package/src/lib/types/partProps.ts +0 -16
  212. package/src/lib/utils/componentUtils.ts +1 -1
  213. package/src/lib/utils/fontPreloader.ts +148 -0
  214. package/src/lib/utils/index.ts +11 -0
  215. package/src/lib/utils/memoryMonitor.ts +189 -0
  216. package/src/styles/01-settings/_settings.design-tokens.scss +4 -1
  217. package/src/styles/01-settings/_settings.fonts.scss +2 -5
  218. package/src/styles/02-tools/_tools.button.scss +66 -79
  219. package/src/styles/06-components/_components.atomix-glass.scss +13 -3
  220. package/src/styles/06-components/_components.navbar.scss +0 -6
  221. package/src/styles/06-components/_components.pagination.scss +88 -0
  222. package/scripts/build-themes.js +0 -208
  223. package/scripts/sync-theme-config.js +0 -309
  224. package/src/components/AtomixGlass/atomixGLass.old.tsx +0 -1263
  225. package/src/lib/theme/composeTheme.ts +0 -370
  226. package/src/lib/theme/core/ThemeCache.ts +0 -283
  227. package/src/lib/theme/core/ThemeEngine.test.ts +0 -146
  228. package/src/lib/theme/core/ThemeEngine.ts +0 -657
  229. package/src/lib/theme/createThemeFromConfig.ts +0 -132
  230. package/src/lib/theme/devtools/CLI.ts +0 -364
  231. package/src/lib/theme/runtime/ThemeManager.test.ts +0 -192
  232. package/src/lib/theme/runtime/ThemeManager.ts +0 -442
  233. package/src/styles/03-generic/_generated-root.css +0 -5
  234. package/src/themes/README.md +0 -442
  235. package/src/themes/themes.config.js +0 -35
  236. /package/src/lib/theme/{cssVariableMapper.ts → adapters/cssVariableMapper.ts} +0 -0
  237. /package/src/lib/theme/{errors.ts → errors/errors.ts} +0 -0
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Config Loader
3
+ *
4
+ * Load design tokens from atomix.config.ts and convert to flat token format.
5
+ */
6
+
7
+ import type { DesignTokens } from '../tokens/tokens';
8
+ import type { AtomixConfig, ThemeTokens } from '../../config';
9
+
10
+ /**
11
+ * Convert nested config tokens to flat DesignTokens format
12
+ *
13
+ * Handles conversion from atomix.config.ts structure to flat tokens.
14
+ * Maps config structure to actual DesignTokens key names.
15
+ */
16
+ function flattenConfigTokens(
17
+ tokens: ThemeTokens,
18
+ prefix: string = 'atomix'
19
+ ): Partial<DesignTokens> {
20
+ const flat: Partial<DesignTokens> = {};
21
+
22
+ // Colors
23
+ if (tokens.colors) {
24
+ Object.entries(tokens.colors).forEach(([key, value]) => {
25
+ if (typeof value === 'string') {
26
+ // Simple color: 'primary': '#7AFFD7'
27
+ // Map directly to DesignTokens keys (e.g., 'primary', 'secondary', 'error')
28
+ // Only map if it's a valid semantic color key
29
+ if (['primary', 'secondary', 'success', 'info', 'warning', 'error', 'light', 'dark'].includes(key)) {
30
+ flat[key as keyof DesignTokens] = value;
31
+ }
32
+ } else if (value && typeof value === 'object') {
33
+ // Color scale or palette
34
+ if ('main' in value) {
35
+ // PaletteColorOptions: { main: '#7AFFD7', light?: '#...', dark?: '#...' }
36
+ const palette = value as { main: string; light?: string; dark?: string };
37
+ const baseKey = key as keyof DesignTokens;
38
+
39
+ // Map main to base color (e.g., primary, secondary, error)
40
+ if (['primary', 'secondary', 'success', 'info', 'warning', 'error', 'light', 'dark'].includes(key)) {
41
+ flat[baseKey] = palette.main;
42
+
43
+ // Map light/dark to appropriate scale values
44
+ // light typically maps to step 3, dark to step 9
45
+ if (palette.light) {
46
+ flat[`${key}-3` as keyof DesignTokens] = palette.light;
47
+ }
48
+ if (palette.dark) {
49
+ flat[`${key}-9` as keyof DesignTokens] = palette.dark;
50
+ }
51
+ }
52
+ } else {
53
+ // Color scale: { 1: '#fff', 2: '#eee', ..., 6: '#main', ... }
54
+ // Or full scale: { 1: '#...', 2: '#...', ..., 10: '#...' }
55
+ Object.entries(value).forEach(([scaleKey, scaleValue]) => {
56
+ if (typeof scaleValue === 'string') {
57
+ // Map scale keys to DesignTokens format
58
+ if (scaleKey === 'main' || scaleKey === '6') {
59
+ // Main color maps to base key (e.g., 'primary')
60
+ if (['primary', 'secondary', 'success', 'info', 'warning', 'error', 'light', 'dark'].includes(key)) {
61
+ flat[key as keyof DesignTokens] = scaleValue;
62
+ }
63
+ // Also map to step 6 if it's a scale color
64
+ if (['primary', 'red', 'green', 'blue', 'yellow', 'gray'].includes(key)) {
65
+ flat[`${key}-6` as keyof DesignTokens] = scaleValue;
66
+ }
67
+ } else {
68
+ // Map scale numbers (1-10) to DesignTokens format
69
+ const scaleNum = parseInt(scaleKey, 10);
70
+ if (!isNaN(scaleNum) && scaleNum >= 1 && scaleNum <= 10) {
71
+ flat[`${key}-${scaleKey}` as keyof DesignTokens] = scaleValue;
72
+ }
73
+ }
74
+ }
75
+ });
76
+ }
77
+ }
78
+ });
79
+ }
80
+
81
+ // Spacing
82
+ if (tokens.spacing) {
83
+ Object.entries(tokens.spacing).forEach(([key, value]) => {
84
+ flat[`spacing-${key}` as keyof DesignTokens] = String(value);
85
+ });
86
+ }
87
+
88
+ // Border Radius
89
+ if (tokens.borderRadius) {
90
+ Object.entries(tokens.borderRadius).forEach(([key, value]) => {
91
+ // Map to DesignTokens format
92
+ if (key === 'sm' || key === 'base' || key === '') {
93
+ flat['border-radius-sm' as keyof DesignTokens] = String(value);
94
+ } else if (key === 'md' || key === 'default') {
95
+ flat['border-radius' as keyof DesignTokens] = String(value);
96
+ } else if (key === 'lg') {
97
+ flat['border-radius-lg' as keyof DesignTokens] = String(value);
98
+ } else {
99
+ flat[`border-radius-${key}` as keyof DesignTokens] = String(value);
100
+ }
101
+ });
102
+ }
103
+
104
+ // Typography
105
+ if (tokens.typography) {
106
+ // Font Families
107
+ if (tokens.typography.fontFamilies) {
108
+ Object.entries(tokens.typography.fontFamilies).forEach(([key, value]) => {
109
+ // Map to DesignTokens format
110
+ if (key === 'sans' || key === 'base') {
111
+ flat['font-sans-serif' as keyof DesignTokens] = String(value);
112
+ flat['body-font-family' as keyof DesignTokens] = String(value);
113
+ } else if (key === 'mono') {
114
+ flat['font-monospace' as keyof DesignTokens] = String(value);
115
+ } else {
116
+ flat[`font-family-${key}` as keyof DesignTokens] = String(value);
117
+ }
118
+ });
119
+ }
120
+
121
+ // Font Sizes
122
+ if (tokens.typography.fontSizes) {
123
+ Object.entries(tokens.typography.fontSizes).forEach(([key, value]) => {
124
+ flat[`font-size-${key}` as keyof DesignTokens] = String(value);
125
+ });
126
+ }
127
+
128
+ // Font Weights
129
+ if (tokens.typography.fontWeights) {
130
+ Object.entries(tokens.typography.fontWeights).forEach(([key, value]) => {
131
+ flat[`font-weight-${key}` as keyof DesignTokens] = String(value);
132
+ });
133
+ }
134
+
135
+ // Line Heights
136
+ if (tokens.typography.lineHeights) {
137
+ Object.entries(tokens.typography.lineHeights).forEach(([key, value]) => {
138
+ if (key === 'base' || key === 'default') {
139
+ flat['line-height-base' as keyof DesignTokens] = String(value);
140
+ } else {
141
+ flat[`line-height-${key}` as keyof DesignTokens] = String(value);
142
+ }
143
+ });
144
+ }
145
+ }
146
+
147
+ // Shadows
148
+ if (tokens.shadows) {
149
+ Object.entries(tokens.shadows).forEach(([key, value]) => {
150
+ flat[`shadow-${key}` as keyof DesignTokens] = String(value);
151
+ });
152
+ }
153
+
154
+ // Z-Index
155
+ if (tokens.zIndex) {
156
+ Object.entries(tokens.zIndex).forEach(([key, value]) => {
157
+ flat[`z-index-${key}` as keyof DesignTokens] = String(value);
158
+ });
159
+ }
160
+
161
+ // Transitions
162
+ if (tokens.transitions) {
163
+ if (tokens.transitions.durations) {
164
+ Object.entries(tokens.transitions.durations).forEach(([key, value]) => {
165
+ flat[`transition-${key}` as keyof DesignTokens] = String(value);
166
+ });
167
+ }
168
+ }
169
+
170
+ return flat;
171
+ }
172
+
173
+ /**
174
+ * Load theme tokens from atomix.config.ts
175
+ *
176
+ * Loads atomix.config.ts and extracts theme tokens.
177
+ * Config file is required - throws error if not found.
178
+ *
179
+ * @param configPath - Optional custom config path (default: 'atomix.config.ts')
180
+ * @returns Partial DesignTokens from config
181
+ * @throws Error if config file is not found or cannot be loaded
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const tokens = await loadThemeFromConfig();
186
+ * const css = createTheme(tokens);
187
+ * injectTheme(css);
188
+ * ```
189
+ */
190
+ export async function loadThemeFromConfig(
191
+ configPath: string = 'atomix.config.ts'
192
+ ): Promise<Partial<DesignTokens>> {
193
+ // In browser environments, config loading is not supported
194
+ if (typeof window !== 'undefined') {
195
+ throw new Error('loadThemeFromConfig: Not available in browser environment. Config loading requires Node.js/SSR environment.');
196
+ }
197
+
198
+ // Load config using the existing loader (required)
199
+ const { loadAtomixConfig } = await import('../../config/loader');
200
+ const config = loadAtomixConfig({ configPath, required: true });
201
+
202
+ if (!config || !config.theme) {
203
+ throw new Error(`Config file ${configPath} does not contain theme configuration.`);
204
+ }
205
+
206
+ // Extract tokens from config
207
+ const tokens = config.theme.tokens || config.theme.extend || {};
208
+
209
+ if (Object.keys(tokens).length === 0) {
210
+ throw new Error(`Config file ${configPath} has empty theme configuration.`);
211
+ }
212
+
213
+ // Convert nested structure to flat tokens
214
+ return flattenConfigTokens(tokens, config.prefix || 'atomix');
215
+ }
216
+
217
+ /**
218
+ * Load theme tokens from atomix.config.ts (synchronous version)
219
+ *
220
+ * Synchronous version that uses require() instead of dynamic import.
221
+ * Only works in Node.js environment.
222
+ * Config file is required - throws error if not found.
223
+ *
224
+ * @param configPath - Optional custom config path
225
+ * @returns Partial DesignTokens from config
226
+ * @throws Error if config file is not found or cannot be loaded
227
+ */
228
+ export function loadThemeFromConfigSync(
229
+ configPath: string = 'atomix.config.ts'
230
+ ): Partial<DesignTokens> {
231
+ // In browser environments, config loading is not supported
232
+ if (typeof window !== 'undefined') {
233
+ throw new Error('loadThemeFromConfigSync: Not available in browser environment. Config loading requires Node.js/SSR environment.');
234
+ }
235
+
236
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
237
+ const { loadAtomixConfig } = require('../../config/loader');
238
+ const config = loadAtomixConfig({ configPath, required: true });
239
+
240
+ if (!config || !config.theme) {
241
+ throw new Error(`Config file ${configPath} does not contain theme configuration.`);
242
+ }
243
+
244
+ // Extract tokens from config
245
+ const tokens = config.theme.tokens || config.theme.extend || {};
246
+
247
+ if (Object.keys(tokens).length === 0) {
248
+ throw new Error(`Config file ${configPath} has empty theme configuration.`);
249
+ }
250
+
251
+ // Convert nested structure to flat tokens
252
+ return flattenConfigTokens(tokens, config.prefix || 'atomix');
253
+ }
254
+
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Theme Configuration Loader
3
3
  *
4
- * Loads and validates the theme configuration from theme.config.ts
4
+ * Loads and validates the theme configuration from atomix.config.ts
5
5
  */
6
6
 
7
7
  import type {
@@ -10,12 +10,10 @@ import type {
10
10
  ConfigValidationResult,
11
11
  } from './types';
12
12
  import { validateConfig } from './validator';
13
- import { ThemeError, ThemeErrorCode, getLogger } from '../errors';
13
+ import { ThemeError, ThemeErrorCode, getLogger } from '../errors/errors';
14
14
  import {
15
- DEFAULT_CONFIG_PATH,
16
15
  DEFAULT_ATOMIX_CONFIG_PATH,
17
16
  DEFAULT_CONFIG_RELATIVE_PATH,
18
- DEFAULT_LEGACY_CONFIG_RELATIVE_PATH,
19
17
  DEFAULT_BASE_PATH,
20
18
  DEFAULT_STORAGE_KEY,
21
19
  DEFAULT_DATA_ATTRIBUTE,
@@ -24,7 +22,7 @@ import {
24
22
  DEFAULT_BUILD_OUTPUT_DIR,
25
23
  DEFAULT_SASS_CONFIG,
26
24
  ENV_DEFAULTS,
27
- } from '../constants';
25
+ } from '../constants/constants';
28
26
 
29
27
  /**
30
28
  * Cache for loaded configuration
@@ -37,7 +35,7 @@ let cachedConfig: LoadedThemeConfig | null = null;
37
35
  const logger = getLogger();
38
36
 
39
37
  /**
40
- * Load theme configuration from theme.config.ts
38
+ * Load theme configuration from atomix.config.ts
41
39
  *
42
40
  * @param options - Loader options
43
41
  * @returns Loaded and validated theme configuration
@@ -97,30 +95,25 @@ export function loadThemeConfig(
97
95
  try {
98
96
  configModule = nodeRequire(DEFAULT_CONFIG_RELATIVE_PATH) as ConfigModule;
99
97
  } catch {
100
- // Try fallback to legacy relative path
101
- try {
102
- configModule = nodeRequire(DEFAULT_LEGACY_CONFIG_RELATIVE_PATH) as ConfigModule;
103
- } catch {
104
- // If relative paths fail, try to resolve from process.cwd()
105
- const path = nodeRequire('path') as typeof import('path');
106
- const fs = nodeRequire('fs') as typeof import('fs');
98
+ // If relative path fails, try to resolve from process.cwd()
99
+ const path = nodeRequire('path') as typeof import('path');
100
+ const fs = nodeRequire('fs') as typeof import('fs');
107
101
 
108
- let configFilePath = path.resolve(process.cwd(), configPath);
102
+ let configFilePath = path.resolve(process.cwd(), configPath);
109
103
 
110
- // Fallback if atomix.config.ts not found
111
- if (!fs.existsSync(configFilePath) && configPath === DEFAULT_ATOMIX_CONFIG_PATH) {
112
- configFilePath = path.resolve(process.cwd(), DEFAULT_CONFIG_PATH);
113
- }
104
+ // If atomix.config.ts not found at the root, use the default path
105
+ if (!fs.existsSync(configFilePath) && configPath === DEFAULT_ATOMIX_CONFIG_PATH) {
106
+ configFilePath = path.resolve(process.cwd(), DEFAULT_ATOMIX_CONFIG_PATH);
107
+ }
114
108
 
115
- if (fs.existsSync(configFilePath)) {
116
- const resolvedPath = nodeRequire.resolve(configFilePath);
117
- if (nodeRequire.cache && nodeRequire.cache[resolvedPath]) {
118
- delete nodeRequire.cache[resolvedPath];
119
- }
120
- configModule = nodeRequire(configFilePath) as ConfigModule;
121
- } else {
122
- throw new Error(`Config file not found: ${configFilePath}`);
109
+ if (fs.existsSync(configFilePath)) {
110
+ const resolvedPath = nodeRequire.resolve(configFilePath);
111
+ if (nodeRequire.cache && nodeRequire.cache[resolvedPath]) {
112
+ delete nodeRequire.cache[resolvedPath];
123
113
  }
114
+ configModule = nodeRequire(configFilePath) as ConfigModule;
115
+ } else {
116
+ throw new Error(`Config file not found: ${configFilePath}`);
124
117
  }
125
118
  }
126
119
  } catch (requireError) {
@@ -136,36 +129,30 @@ export function loadThemeConfig(
136
129
 
137
130
  const rawConfig = configModule.default || configModule;
138
131
 
139
- // Handle new AtomixConfig structure vs legacy ThemeConfig
140
- let processedConfig: any;
141
- if (rawConfig.theme && (rawConfig.theme.themes || rawConfig.theme.tokens || rawConfig.theme.extend)) {
142
- // New AtomixConfig structure
143
- processedConfig = {
144
- themes: rawConfig.theme.themes || {},
145
- build: rawConfig.build || {},
146
- runtime: rawConfig.runtime || {},
147
- integration: rawConfig.integration || {},
148
- dependencies: rawConfig.dependencies || {},
149
- // Store tokens for generator
150
- __tokens: rawConfig.theme.tokens,
151
- __extend: rawConfig.theme.extend,
152
- };
153
- } else {
154
- // Legacy ThemeConfig structure
155
- processedConfig = { ...rawConfig };
156
- }
132
+ // Process the AtomixConfig structure
133
+ const processedConfig: LoadedThemeConfig = {
134
+ themes: rawConfig.theme?.themes || {},
135
+ build: rawConfig.build || {},
136
+ runtime: rawConfig.runtime || {},
137
+ integration: rawConfig.integration || {},
138
+ dependencies: rawConfig.dependencies || {},
139
+ validated: false, // Will be set after validation
140
+ // Store tokens for generator
141
+ __tokens: rawConfig.theme?.tokens,
142
+ __extend: rawConfig.theme?.extend,
143
+ };
157
144
 
158
145
  // Apply environment-specific overrides
159
- processedConfig = applyEnvOverrides(processedConfig, env);
146
+ const finalConfig = applyEnvOverrides(processedConfig, env);
160
147
 
161
148
  // Validate if requested
162
149
  let validationResult: ConfigValidationResult | null = null;
163
150
  if (validate) {
164
- validationResult = validateConfig(processedConfig);
151
+ validationResult = validateConfig(finalConfig);
165
152
  }
166
153
 
167
154
  config = {
168
- ...processedConfig,
155
+ ...finalConfig,
169
156
  validated: validate,
170
157
  errors: validationResult?.errors,
171
158
  warnings: validationResult?.warnings,
@@ -212,6 +199,8 @@ export function loadThemeConfig(
212
199
  validated: false,
213
200
  errors: [`Failed to load config: ${error instanceof Error ? error.message : String(error)}`],
214
201
  warnings: [],
202
+ __tokens: {},
203
+ __extend: {},
215
204
  };
216
205
  }
217
206
 
@@ -307,4 +296,4 @@ export function reloadThemeConfig(
307
296
  ): LoadedThemeConfig {
308
297
  clearConfigCache();
309
298
  return loadThemeConfig(options);
310
- }
299
+ }
@@ -18,7 +18,7 @@ import type {
18
18
  * Configuration loader options
19
19
  */
20
20
  export interface ConfigLoaderOptions {
21
- /** Path to theme config file (default: 'theme.config.ts') */
21
+ /** Path to theme config file (default: 'atomix.config.ts') */
22
22
  configPath?: string;
23
23
  /** Enable validation */
24
24
  validate?: boolean;
@@ -109,4 +109,4 @@ export type {
109
109
  BuildConfig,
110
110
  RuntimeConfig,
111
111
  IntegrationConfig,
112
- };
112
+ };
@@ -4,13 +4,7 @@
4
4
  * Validates theme configuration structure and values
5
5
  */
6
6
 
7
- import type {
8
- AtomixConfig,
9
- ThemeDefinition,
10
- CSSThemeDefinition,
11
- JSThemeDefinition,
12
- ConfigValidationResult,
13
- } from './types';
7
+ import type { ConfigValidationResult } from './types';
14
8
 
15
9
  /**
16
10
  * Validate theme configuration
@@ -37,31 +31,25 @@ export function validateConfig(config: any): ConfigValidationResult {
37
31
  warnings.push(...themeErrors.warnings);
38
32
  }
39
33
 
40
- // Validate build config
34
+ // Validate build config (only if provided)
41
35
  if (config.build) {
42
36
  const buildErrors = validateBuildConfig(config.build);
43
37
  errors.push(...buildErrors.errors);
44
38
  warnings.push(...buildErrors.warnings);
45
- } else {
46
- warnings.push('No build configuration provided, using defaults');
47
39
  }
48
40
 
49
- // Validate runtime config
41
+ // Validate runtime config (only if provided)
50
42
  if (config.runtime) {
51
43
  const runtimeErrors = validateRuntimeConfig(config.runtime);
52
44
  errors.push(...runtimeErrors.errors);
53
45
  warnings.push(...runtimeErrors.warnings);
54
- } else {
55
- warnings.push('No runtime configuration provided, using defaults');
56
46
  }
57
47
 
58
- // Validate integration config
48
+ // Validate integration config (only if provided)
59
49
  if (config.integration) {
60
50
  const integrationErrors = validateIntegrationConfig(config.integration);
61
51
  errors.push(...integrationErrors.errors);
62
52
  warnings.push(...integrationErrors.warnings);
63
- } else {
64
- warnings.push('No integration configuration provided, using defaults');
65
53
  }
66
54
 
67
55
  // Validate dependencies
@@ -127,23 +115,9 @@ function validateThemes(themes: Record<string, any>): ConfigValidationResult {
127
115
  warnings.push(...jsErrors.warnings);
128
116
  }
129
117
 
130
- // Validate metadata
131
- if (theme.version && !isValidSemver(theme.version)) {
132
- warnings.push(`Theme "${themeId}" has invalid version format: ${theme.version}`);
133
- }
134
-
135
- if (theme.status && !['stable', 'beta', 'experimental', 'deprecated'].includes(theme.status)) {
136
- warnings.push(`Theme "${themeId}" has invalid status: ${theme.status}`);
137
- }
138
-
139
- // Validate color format
140
- if (theme.color && !isValidColor(theme.color)) {
141
- warnings.push(`Theme "${themeId}" has invalid color format: ${theme.color}`);
142
- }
143
-
144
- // Validate accessibility
145
- if (theme.a11y) {
146
- if (theme.a11y.contrastTarget && (theme.a11y.contrastTarget < 1 || theme.a11y.contrastTarget > 21)) {
118
+ // Validate accessibility (only critical checks)
119
+ if (theme.a11y?.contrastTarget) {
120
+ if (typeof theme.a11y.contrastTarget !== 'number' || theme.a11y.contrastTarget < 1 || theme.a11y.contrastTarget > 21) {
147
121
  warnings.push(`Theme "${themeId}" has invalid contrast target: ${theme.a11y.contrastTarget}`);
148
122
  }
149
123
  }
@@ -187,23 +161,13 @@ function validateBuildConfig(build: any): ConfigValidationResult {
187
161
  const errors: string[] = [];
188
162
  const warnings: string[] = [];
189
163
 
190
- if (!build.output || typeof build.output !== 'object') {
191
- errors.push('Build config must have an "output" object');
192
- } else {
193
- if (!build.output.directory || typeof build.output.directory !== 'string') {
194
- errors.push('Build output must have a "directory" string');
195
- }
196
- if (!build.output.formats || typeof build.output.formats !== 'object') {
197
- errors.push('Build output must have a "formats" object');
198
- }
164
+ // Only validate structure if provided
165
+ if (build.output && typeof build.output !== 'object') {
166
+ errors.push('Build output must be an object');
199
167
  }
200
168
 
201
- if (!build.sass || typeof build.sass !== 'object') {
202
- errors.push('Build config must have a "sass" object');
203
- } else {
204
- if (build.sass.style && !['expanded', 'compressed', 'compact', 'nested'].includes(build.sass.style)) {
205
- warnings.push(`Invalid Sass style: ${build.sass.style}`);
206
- }
169
+ if (build.sass && typeof build.sass !== 'object') {
170
+ errors.push('Build sass config must be an object');
207
171
  }
208
172
 
209
173
  return { valid: errors.length === 0, errors, warnings };
@@ -242,15 +206,9 @@ function validateIntegrationConfig(integration: any): ConfigValidationResult {
242
206
  const errors: string[] = [];
243
207
  const warnings: string[] = [];
244
208
 
245
- if (!integration.classNames || typeof integration.classNames !== 'object') {
246
- errors.push('Integration config must have a "classNames" object');
247
- } else {
248
- if (!integration.classNames.theme || typeof integration.classNames.theme !== 'string') {
249
- errors.push('Integration classNames must have a "theme" string');
250
- }
251
- if (!integration.classNames.colorMode || typeof integration.classNames.colorMode !== 'string') {
252
- errors.push('Integration classNames must have a "colorMode" string');
253
- }
209
+ // Only validate structure if provided
210
+ if (integration.classNames && typeof integration.classNames !== 'object') {
211
+ errors.push('Integration classNames must be an object');
254
212
  }
255
213
 
256
214
  return { valid: errors.length === 0, errors, warnings };
@@ -290,37 +248,3 @@ function validateDependencies(
290
248
  return { valid: errors.length === 0, errors, warnings };
291
249
  }
292
250
 
293
- /**
294
- * Check if string is valid semver
295
- */
296
- function isValidSemver(version: string): boolean {
297
- const semverRegex = /^\d+\.\d+\.\d+(-[\w.]+)?(\+[\w.]+)?$/;
298
- return semverRegex.test(version);
299
- }
300
-
301
- /**
302
- * Check if string is valid color
303
- */
304
- function isValidColor(color: string): boolean {
305
- // Hex color
306
- if (/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(color)) {
307
- return true;
308
- }
309
- // RGB/RGBA
310
- if (/^rgba?\(/.test(color)) {
311
- return true;
312
- }
313
- // HSL/HSLA
314
- if (/^hsla?\(/.test(color)) {
315
- return true;
316
- }
317
- // Named colors (basic check)
318
- const namedColors = [
319
- 'black', 'white', 'red', 'green', 'blue', 'yellow', 'cyan', 'magenta',
320
- 'transparent', 'currentColor',
321
- ];
322
- if (namedColors.includes(color.toLowerCase())) {
323
- return true;
324
- }
325
- return false;
326
- }
@@ -24,14 +24,6 @@ export const DEFAULT_BASE_PATH = '/themes';
24
24
  */
25
25
  export const DEFAULT_STYLE_ID = 'atomix-js-theme-styles';
26
26
 
27
- /**
28
- * Default cache configuration
29
- */
30
- export const DEFAULT_CACHE_CONFIG = {
31
- maxSize: 50,
32
- ttl: 0, // No expiration by default
33
- } as const;
34
-
35
27
  /**
36
28
  * Default engine cache configuration
37
29
  */
@@ -58,21 +50,11 @@ export const CSS_EXTENSIONS = {
58
50
  */
59
51
  export const DEFAULT_ATOMIX_CONFIG_PATH = 'atomix.config.ts';
60
52
 
61
- /**
62
- * Default config file path (legacy)
63
- */
64
- export const DEFAULT_CONFIG_PATH = 'theme.config.ts';
65
-
66
53
  /**
67
54
  * Default config file path (relative)
68
55
  */
69
56
  export const DEFAULT_CONFIG_RELATIVE_PATH = '../../../../atomix.config';
70
57
 
71
- /**
72
- * Default legacy config file path (relative)
73
- */
74
- export const DEFAULT_LEGACY_CONFIG_RELATIVE_PATH = '../../../../theme.config';
75
-
76
58
  /**
77
59
  * Validation thresholds
78
60
  */
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Theme Constants
3
+ *
4
+ * System constants and default values
5
+ */
6
+
7
+ export * from './constants';
8
+
@@ -71,6 +71,8 @@ export class ThemeRegistry {
71
71
  validated: false,
72
72
  errors: [],
73
73
  warnings: [],
74
+ __tokens: {},
75
+ __extend: {},
74
76
  };
75
77
  }
76
78
  } else {
@@ -160,23 +162,34 @@ export class ThemeRegistry {
160
162
  }
161
163
 
162
164
  /**
163
- * Get theme object (for JS themes)
165
+ * Check if a theme is loaded
164
166
  */
165
- getTheme(themeId: string): Theme | undefined {
166
- return this.entries.get(themeId)?.theme;
167
+ isThemeLoaded(themeId: string): boolean {
168
+ const entry = this.entries.get(themeId);
169
+ return entry ? entry.loaded : false;
167
170
  }
168
171
 
169
172
  /**
170
- * Set theme object (for JS themes)
173
+ * Mark a theme as loaded
171
174
  */
172
- setTheme(themeId: string, theme: Theme): void {
175
+ markLoaded(themeId: string, theme?: Theme): void {
173
176
  const entry = this.entries.get(themeId);
174
177
  if (entry) {
175
- entry.theme = theme;
176
178
  entry.loaded = true;
179
+ if (theme) {
180
+ entry.theme = theme;
181
+ }
177
182
  }
178
183
  }
179
184
 
185
+ /**
186
+ * Get theme object (for JS themes)
187
+ */
188
+ getTheme(themeId: string): Theme | undefined {
189
+ const entry = this.entries.get(themeId);
190
+ return entry?.loaded ? entry.theme : undefined;
191
+ }
192
+
180
193
  /**
181
194
  * Get dependencies for a theme
182
195
  */