@shohojdhara/atomix 0.3.5 → 0.3.7

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 (182) hide show
  1. package/README.md +101 -199
  2. package/atomix.config.ts +241 -0
  3. package/dist/atomix.css +260 -179
  4. package/dist/atomix.css.map +1 -1
  5. package/dist/atomix.min.css +250 -179
  6. package/dist/atomix.min.css.map +1 -1
  7. package/dist/charts.js +69 -166
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.js +184 -263
  10. package/dist/core.js.map +1 -1
  11. package/dist/forms.js +55 -131
  12. package/dist/forms.js.map +1 -1
  13. package/dist/heavy.js +184 -263
  14. package/dist/heavy.js.map +1 -1
  15. package/dist/index.d.ts +1831 -1657
  16. package/dist/index.esm.js +4497 -4318
  17. package/dist/index.esm.js.map +1 -1
  18. package/dist/index.js +4510 -4328
  19. package/dist/index.js.map +1 -1
  20. package/dist/index.min.js +1 -1
  21. package/dist/index.min.js.map +1 -1
  22. package/dist/theme.d.ts +1431 -1472
  23. package/dist/theme.js +4175 -4138
  24. package/dist/theme.js.map +1 -1
  25. package/package.json +6 -20
  26. package/src/components/Accordion/Accordion.stories.tsx +50 -17
  27. package/src/components/AtomixGlass/AtomixGlass.tsx +128 -322
  28. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +12 -5
  29. package/src/components/AtomixGlass/stories/AtomixGlass.stories.tsx +1 -32
  30. package/src/components/AtomixGlass/stories/Examples.stories.tsx +2 -2
  31. package/src/components/AtomixGlass/stories/shared-components.tsx +0 -31
  32. package/src/components/Avatar/Avatar.stories.tsx +7 -0
  33. package/src/components/Badge/Badge.stories.tsx +91 -13
  34. package/src/components/Block/Block.stories.tsx +7 -23
  35. package/src/components/Breadcrumb/Breadcrumb.stories.tsx +7 -0
  36. package/src/components/Button/Button.stories.tsx +141 -22
  37. package/src/components/Button/Button.tsx +85 -167
  38. package/src/components/Button/ButtonGroup.stories.tsx +315 -0
  39. package/src/components/Button/ButtonGroup.tsx +67 -0
  40. package/src/components/Button/index.ts +2 -0
  41. package/src/components/Callout/Callout.stories.tsx +8 -6
  42. package/src/components/Card/Card.stories.tsx +82 -28
  43. package/src/components/Chart/AnimatedChart.tsx +0 -1
  44. package/src/components/Chart/AreaChart.tsx +0 -1
  45. package/src/components/Chart/BarChart.tsx +0 -1
  46. package/src/components/Chart/BubbleChart.tsx +0 -1
  47. package/src/components/Chart/CandlestickChart.tsx +0 -1
  48. package/src/components/Chart/Chart.stories.tsx +5 -7
  49. package/src/components/Chart/Chart.tsx +0 -16
  50. package/src/components/Chart/ChartRenderer.tsx +1 -1
  51. package/src/components/Chart/DonutChart.tsx +0 -1
  52. package/src/components/Chart/FunnelChart.tsx +0 -1
  53. package/src/components/Chart/GaugeChart.tsx +0 -1
  54. package/src/components/Chart/HeatmapChart.tsx +0 -1
  55. package/src/components/Chart/LineChart.tsx +0 -1
  56. package/src/components/Chart/MultiAxisChart.tsx +0 -1
  57. package/src/components/Chart/PieChart.tsx +0 -1
  58. package/src/components/Chart/RadarChart.tsx +0 -1
  59. package/src/components/Chart/ScatterChart.tsx +0 -1
  60. package/src/components/Chart/WaterfallChart.tsx +0 -1
  61. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +7 -0
  62. package/src/components/DataTable/DataTable.stories.tsx +23 -16
  63. package/src/components/DatePicker/DatePicker.stories.tsx +27 -19
  64. package/src/components/Dropdown/Dropdown.stories.tsx +11 -19
  65. package/src/components/EdgePanel/EdgePanel.stories.tsx +1 -0
  66. package/src/components/Footer/Footer.stories.tsx +8 -6
  67. package/src/components/Footer/FooterLink.tsx +9 -2
  68. package/src/components/Form/Checkbox.stories.tsx +7 -0
  69. package/src/components/Form/Form.stories.tsx +7 -0
  70. package/src/components/Form/FormGroup.stories.tsx +9 -1
  71. package/src/components/Form/Input.stories.tsx +69 -16
  72. package/src/components/Form/Radio.stories.tsx +9 -1
  73. package/src/components/Form/Select.stories.tsx +9 -1
  74. package/src/components/Form/Textarea.stories.tsx +10 -2
  75. package/src/components/Hero/Hero.stories.tsx +7 -0
  76. package/src/components/List/List.stories.tsx +7 -0
  77. package/src/components/Messages/Messages.stories.tsx +8 -7
  78. package/src/components/Modal/Modal.stories.tsx +17 -6
  79. package/src/components/Navigation/Menu/Menu.stories.tsx +7 -0
  80. package/src/components/Navigation/Nav/Nav.stories.tsx +7 -0
  81. package/src/components/Navigation/Navbar/Navbar.stories.tsx +1 -0
  82. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +1 -1
  83. package/src/components/Pagination/Pagination.stories.tsx +188 -111
  84. package/src/components/Pagination/Pagination.tsx +83 -3
  85. package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -5
  86. package/src/components/Popover/Popover.stories.tsx +191 -115
  87. package/src/components/ProductReview/ProductReview.stories.tsx +80 -58
  88. package/src/components/Progress/Progress.stories.tsx +79 -49
  89. package/src/components/Rating/Rating.stories.tsx +109 -84
  90. package/src/components/River/River.stories.tsx +194 -114
  91. package/src/components/SectionIntro/SectionIntro.stories.tsx +19 -9
  92. package/src/components/Slider/Slider.stories.tsx +7 -0
  93. package/src/components/Spinner/Spinner.stories.tsx +15 -11
  94. package/src/components/Steps/Steps.stories.tsx +132 -98
  95. package/src/components/Tabs/Tabs.stories.tsx +163 -112
  96. package/src/components/Testimonial/Testimonial.stories.tsx +114 -68
  97. package/src/components/Todo/Todo.stories.tsx +38 -12
  98. package/src/components/Toggle/Toggle.stories.tsx +61 -28
  99. package/src/components/Tooltip/Tooltip.stories.tsx +318 -200
  100. package/src/components/Upload/Upload.stories.tsx +122 -84
  101. package/src/components/VideoPlayer/VideoPlayer.stories.tsx +7 -24
  102. package/src/components/index.ts +1 -0
  103. package/src/lib/composables/useAtomixGlass.ts +9 -10
  104. package/src/lib/composables/useNavbar.ts +0 -10
  105. package/src/lib/config/loader.ts +4 -4
  106. package/src/lib/constants/components.ts +17 -0
  107. package/src/lib/hooks/useComponentCustomization.ts +1 -1
  108. package/src/lib/hooks/usePerformanceMonitor.ts +1 -1
  109. package/src/lib/hooks/useThemeTokens.ts +105 -0
  110. package/src/lib/theme/README.md +174 -0
  111. package/src/lib/theme/adapters/index.ts +31 -0
  112. package/src/lib/theme/adapters/themeAdapter.ts +287 -0
  113. package/src/lib/theme/config/__tests__/configLoader.test.ts +207 -0
  114. package/src/lib/theme/config/configLoader.ts +95 -0
  115. package/src/lib/theme/config/loader.ts +37 -54
  116. package/src/lib/theme/config/types.ts +2 -2
  117. package/src/lib/theme/config/validator.ts +15 -91
  118. package/src/lib/theme/{constants.ts → constants/constants.ts} +1 -19
  119. package/src/lib/theme/constants/index.ts +8 -0
  120. package/src/lib/theme/core/ThemeRegistry.ts +75 -266
  121. package/src/lib/theme/core/__tests__/createTheme.test.ts +132 -0
  122. package/src/lib/theme/core/composeTheme.ts +105 -0
  123. package/src/lib/theme/core/createTheme.ts +108 -0
  124. package/src/lib/theme/{createTheme.ts → core/createThemeObject.ts} +12 -8
  125. package/src/lib/theme/core/index.ts +19 -19
  126. package/src/lib/theme/devtools/Comparator.tsx +346 -22
  127. package/src/lib/theme/devtools/IMPROVEMENTS.md +139 -38
  128. package/src/lib/theme/devtools/Inspector.tsx +335 -51
  129. package/src/lib/theme/devtools/LiveEditor.tsx +478 -107
  130. package/src/lib/theme/devtools/Preview.tsx +471 -221
  131. package/src/lib/theme/{core → devtools}/ThemeValidator.ts +1 -1
  132. package/src/lib/theme/devtools/index.ts +14 -4
  133. package/src/lib/theme/devtools/useHistory.ts +130 -0
  134. package/src/lib/theme/{errors.ts → errors/errors.ts} +1 -1
  135. package/src/lib/theme/errors/index.ts +12 -0
  136. package/src/lib/theme/generators/cssFile.ts +79 -0
  137. package/src/lib/theme/generators/generateCSS.ts +89 -0
  138. package/src/lib/theme/generators/generateCSSNested.ts +130 -0
  139. package/src/lib/theme/{generateCSSVariables.ts → generators/generateCSSVariables.ts} +3 -13
  140. package/src/lib/theme/generators/index.ts +25 -0
  141. package/src/lib/theme/i18n/rtl.ts +5 -6
  142. package/src/lib/theme/index.ts +149 -19
  143. package/src/lib/theme/runtime/ThemeApplicator.ts +53 -112
  144. package/src/lib/theme/{ThemeContext.tsx → runtime/ThemeContext.tsx} +1 -1
  145. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +5 -5
  146. package/src/lib/theme/runtime/ThemeProvider.tsx +266 -282
  147. package/src/lib/theme/runtime/index.ts +2 -2
  148. package/src/lib/theme/runtime/useTheme.ts +1 -2
  149. package/src/lib/theme/runtime/useThemeTokens.ts +131 -0
  150. package/src/lib/theme/test/testTheme.ts +385 -0
  151. package/src/lib/theme/tokens/index.ts +12 -0
  152. package/src/lib/theme/tokens/tokens.ts +721 -0
  153. package/src/lib/theme/types.ts +6 -42
  154. package/src/lib/theme/utils/componentTheming.ts +132 -0
  155. package/src/lib/theme/{utils.ts → utils/domUtils.ts} +2 -2
  156. package/src/lib/theme/utils/index.ts +11 -0
  157. package/src/lib/theme/utils/injectCSS.ts +90 -0
  158. package/src/lib/theme/utils/naming.ts +100 -0
  159. package/src/lib/theme/utils/themeHelpers.ts +78 -0
  160. package/src/lib/theme/{themeUtils.ts → utils/themeUtils.ts} +7 -7
  161. package/src/lib/theme-tools.ts +7 -8
  162. package/src/lib/types/components.ts +40 -130
  163. package/src/lib/utils/componentUtils.ts +2 -2
  164. package/src/lib/utils/memoryMonitor.ts +3 -3
  165. package/src/lib/utils/themeNaming.ts +135 -0
  166. package/src/styles/01-settings/_settings.design-tokens.scss +4 -1
  167. package/src/styles/02-tools/_tools.button.scss +66 -79
  168. package/src/styles/06-components/_components.atomix-glass.scss +13 -3
  169. package/src/styles/06-components/_components.pagination.scss +88 -0
  170. package/scripts/sync-theme-config.js +0 -309
  171. package/src/lib/theme/composeTheme.ts +0 -370
  172. package/src/lib/theme/core/ThemeCache.ts +0 -283
  173. package/src/lib/theme/core/ThemeEngine.test.ts +0 -146
  174. package/src/lib/theme/core/ThemeEngine.ts +0 -665
  175. package/src/lib/theme/createThemeFromConfig.ts +0 -132
  176. package/src/lib/theme/devtools/CLI.ts +0 -364
  177. package/src/lib/theme/runtime/ThemeManager.test.ts +0 -192
  178. package/src/lib/theme/runtime/ThemeManager.ts +0 -446
  179. package/src/styles/03-generic/_generated-root.css +0 -26
  180. package/src/themes/README.md +0 -442
  181. package/src/themes/themes.config.js +0 -68
  182. /package/src/lib/theme/{cssVariableMapper.ts → adapters/cssVariableMapper.ts} +0 -0
@@ -2,11 +2,12 @@
2
2
  * Theme Preview Component
3
3
  *
4
4
  * React component for previewing themes in development
5
+ * Enhanced with interactive components, viewport controls, and dark mode toggle
5
6
  */
6
7
 
7
- import React, { useState, useEffect } from 'react';
8
+ import React, { useState, useEffect, useMemo } from 'react';
8
9
  import type { Theme } from '../types';
9
- import { generateCSSVariables } from '../generateCSSVariables';
10
+ import { generateCSSVariables } from '../generators/generateCSSVariables';
10
11
 
11
12
  /**
12
13
  * Theme preview props
@@ -30,6 +31,27 @@ export interface ThemePreviewProps {
30
31
  style?: React.CSSProperties;
31
32
  }
32
33
 
34
+ /**
35
+ * Viewport preset
36
+ */
37
+ type ViewportPreset = 'mobile' | 'tablet' | 'desktop' | 'custom';
38
+
39
+ /**
40
+ * Viewport configuration
41
+ */
42
+ interface ViewportConfig {
43
+ width: number;
44
+ height: number;
45
+ label: string;
46
+ }
47
+
48
+ const VIEWPORT_PRESETS: Record<ViewportPreset, ViewportConfig> = {
49
+ mobile: { width: 375, height: 667, label: 'Mobile (375px)' },
50
+ tablet: { width: 768, height: 1024, label: 'Tablet (768px)' },
51
+ desktop: { width: 1280, height: 720, label: 'Desktop (1280px)' },
52
+ custom: { width: 1280, height: 720, label: 'Custom' },
53
+ };
54
+
33
55
  /**
34
56
  * Theme Preview Component
35
57
  *
@@ -46,259 +68,473 @@ export const ThemePreview: React.FC<ThemePreviewProps> = ({
46
68
  style,
47
69
  }) => {
48
70
  const [cssVariables, setCssVariables] = useState<string>('');
71
+ const [darkMode, setDarkMode] = useState(false);
72
+ const [viewportPreset, setViewportPreset] = useState<ViewportPreset>('desktop');
73
+ const [customWidth, setCustomWidth] = useState(1280);
74
+ const [customHeight, setCustomHeight] = useState(720);
75
+ const [interactiveStates, setInteractiveStates] = useState<Record<string, boolean>>({});
76
+
77
+ // Get current viewport dimensions
78
+ const viewport = useMemo(() => {
79
+ if (viewportPreset === 'custom') {
80
+ return { width: customWidth, height: customHeight };
81
+ }
82
+ return VIEWPORT_PRESETS[viewportPreset];
83
+ }, [viewportPreset, customWidth, customHeight]);
84
+
85
+ // Generate theme with dark mode override if needed
86
+ const previewTheme = useMemo(() => {
87
+ if (!darkMode) return theme;
88
+
89
+ // Create a dark mode variant (simplified - you might want more sophisticated logic)
90
+ return {
91
+ ...theme,
92
+ palette: {
93
+ ...theme.palette,
94
+ background: {
95
+ default: '#121212',
96
+ subtle: '#1e1e1e',
97
+ },
98
+ text: {
99
+ primary: '#ffffff',
100
+ secondary: 'rgba(255, 255, 255, 0.8)',
101
+ disabled: 'rgba(255, 255, 255, 0.5)',
102
+ },
103
+ },
104
+ };
105
+ }, [theme, darkMode]);
49
106
 
50
107
  useEffect(() => {
51
108
  // Generate CSS variables for the theme
52
- const css = generateCSSVariables(theme, {
109
+ const css = generateCSSVariables(previewTheme as Theme, {
53
110
  selector: ':root',
54
111
  prefix: 'atomix-preview',
55
112
  });
56
113
  setCssVariables(css);
57
- }, [theme]);
114
+ }, [previewTheme]);
115
+
116
+ const toggleInteractiveState = (id: string) => {
117
+ setInteractiveStates(prev => ({
118
+ ...prev,
119
+ [id]: !prev[id],
120
+ }));
121
+ };
122
+
123
+ const handleButtonClick = (id: string) => {
124
+ toggleInteractiveState(id);
125
+ // Reset after animation
126
+ setTimeout(() => {
127
+ setInteractiveStates(prev => {
128
+ const next = { ...prev };
129
+ delete next[id];
130
+ return next;
131
+ });
132
+ }, 200);
133
+ };
58
134
 
59
135
  return (
60
136
  <div className={`atomix-theme-preview ${className || ''}`} style={style}>
61
- {/* Inject theme CSS variables */}
62
- <style>{cssVariables}</style>
63
-
64
- {/* Theme Details */}
65
- {showDetails && (
66
- <div className="theme-details">
67
- <h2>{theme.name}</h2>
68
- {theme.description && <p>{theme.description}</p>}
69
- {theme.author && <p><strong>Author:</strong> {theme.author}</p>}
70
- {theme.version && <p><strong>Version:</strong> {theme.version}</p>}
71
- {theme.status && <p><strong>Status:</strong> {theme.status}</p>}
72
- {theme.tags && theme.tags.length > 0 && (
73
- <p><strong>Tags:</strong> {theme.tags.join(', ')}</p>
74
- )}
137
+ {/* Preview Controls */}
138
+ <div className="preview-controls">
139
+ <div className="control-group">
140
+ <label>Viewport:</label>
141
+ <select
142
+ value={viewportPreset}
143
+ onChange={(e) => setViewportPreset(e.target.value as ViewportPreset)}
144
+ >
145
+ <option value="mobile">Mobile (375px)</option>
146
+ <option value="tablet">Tablet (768px)</option>
147
+ <option value="desktop">Desktop (1280px)</option>
148
+ <option value="custom">Custom</option>
149
+ </select>
150
+ </div>
151
+
152
+ {viewportPreset === 'custom' && (
153
+ <>
154
+ <div className="control-group">
155
+ <label>Width:</label>
156
+ <input
157
+ type="number"
158
+ value={customWidth}
159
+ onChange={(e) => setCustomWidth(parseInt(e.target.value) || 1280)}
160
+ min="320"
161
+ max="3840"
162
+ />
163
+ </div>
164
+ <div className="control-group">
165
+ <label>Height:</label>
166
+ <input
167
+ type="number"
168
+ value={customHeight}
169
+ onChange={(e) => setCustomHeight(parseInt(e.target.value) || 720)}
170
+ min="240"
171
+ max="2160"
172
+ />
173
+ </div>
174
+ </>
175
+ )}
176
+
177
+ <div className="control-group">
178
+ <label>
179
+ <input
180
+ type="checkbox"
181
+ checked={darkMode}
182
+ onChange={(e) => setDarkMode(e.target.checked)}
183
+ />
184
+ Dark Mode
185
+ </label>
75
186
  </div>
76
- )}
77
-
78
- {/* Color Palette */}
79
- {showPalette && (
80
- <div className="theme-palette">
81
- <h3>Color Palette</h3>
82
- <div className="color-grid">
83
- {['primary', 'secondary', 'error', 'warning', 'info', 'success'].map((colorName) => {
84
- const color = theme.palette[colorName as keyof typeof theme.palette];
85
- if (!color || typeof color !== 'object' || !('main' in color)) return null;
86
-
87
- return (
88
- <div key={colorName} className="color-item">
187
+ </div>
188
+
189
+ {/* Viewport Wrapper */}
190
+ <div
191
+ className="viewport-wrapper"
192
+ style={{
193
+ width: `${viewport.width}px`,
194
+ height: `${viewport.height}px`,
195
+ maxWidth: '100%',
196
+ }}
197
+ >
198
+ {/* Inject theme CSS variables */}
199
+ <style>{cssVariables}</style>
200
+
201
+ {/* Theme Details */}
202
+ {showDetails && (
203
+ <div className="theme-details">
204
+ <h2>{previewTheme.name}</h2>
205
+ {previewTheme.description && <p>{previewTheme.description}</p>}
206
+ {previewTheme.author && <p><strong>Author:</strong> {previewTheme.author}</p>}
207
+ {previewTheme.version && <p><strong>Version:</strong> {previewTheme.version}</p>}
208
+ {previewTheme.status && <p><strong>Status:</strong> {previewTheme.status}</p>}
209
+ {previewTheme.tags && previewTheme.tags.length > 0 && (
210
+ <p><strong>Tags:</strong> {previewTheme.tags.join(', ')}</p>
211
+ )}
212
+ </div>
213
+ )}
214
+
215
+ {/* Color Palette */}
216
+ {showPalette && (
217
+ <div className="theme-palette">
218
+ <h3>Color Palette</h3>
219
+ <div className="color-grid">
220
+ {['primary', 'secondary', 'error', 'warning', 'info', 'success'].map((colorName) => {
221
+ const color = previewTheme.palette[colorName as keyof typeof previewTheme.palette];
222
+ if (!color || typeof color !== 'object' || !('main' in color)) return null;
223
+
224
+ return (
225
+ <div key={colorName} className="color-item">
226
+ <div
227
+ className="color-swatch"
228
+ style={{ backgroundColor: color.main }}
229
+ />
230
+ <div className="color-info">
231
+ <strong>{colorName}</strong>
232
+ <code>{color.main}</code>
233
+ </div>
234
+ </div>
235
+ );
236
+ })}
237
+ </div>
238
+
239
+ {/* Background Colors */}
240
+ <h4>Background</h4>
241
+ <div className="color-grid">
242
+ {Object.entries(previewTheme.palette.background).map(([name, value]) => (
243
+ <div key={name} className="color-item">
89
244
  <div
90
245
  className="color-swatch"
91
- style={{ backgroundColor: color.main }}
246
+ style={{ backgroundColor: value }}
92
247
  />
93
248
  <div className="color-info">
94
- <strong>{colorName}</strong>
95
- <code>{color.main}</code>
249
+ <strong>{name}</strong>
250
+ <code>{value}</code>
96
251
  </div>
97
252
  </div>
98
- );
99
- })}
100
- </div>
101
-
102
- {/* Background Colors */}
103
- <h4>Background</h4>
104
- <div className="color-grid">
105
- {Object.entries(theme.palette.background).map(([name, value]) => (
106
- <div key={name} className="color-item">
107
- <div
108
- className="color-swatch"
109
- style={{ backgroundColor: value }}
110
- />
111
- <div className="color-info">
112
- <strong>{name}</strong>
113
- <code>{value}</code>
253
+ ))}
254
+ </div>
255
+
256
+ {/* Text Colors */}
257
+ <h4>Text</h4>
258
+ <div className="color-grid">
259
+ {Object.entries(previewTheme.palette.text).map(([name, value]) => (
260
+ <div key={name} className="color-item">
261
+ <div
262
+ className="color-swatch"
263
+ style={{ backgroundColor: value }}
264
+ />
265
+ <div className="color-info">
266
+ <strong>{name}</strong>
267
+ <code>{value}</code>
268
+ </div>
114
269
  </div>
115
- </div>
116
- ))}
270
+ ))}
271
+ </div>
117
272
  </div>
273
+ )}
118
274
 
119
- {/* Text Colors */}
120
- <h4>Text</h4>
121
- <div className="color-grid">
122
- {Object.entries(theme.palette.text).map(([name, value]) => (
123
- <div key={name} className="color-item">
124
- <div
125
- className="color-swatch"
126
- style={{ backgroundColor: value }}
127
- />
128
- <div className="color-info">
129
- <strong>{name}</strong>
130
- <code>{value}</code>
131
- </div>
132
- </div>
133
- ))}
275
+ {/* Typography */}
276
+ {showTypography && (
277
+ <div className="theme-typography">
278
+ <h3>Typography</h3>
279
+ <div className="typography-info">
280
+ <p><strong>Font Family:</strong> <code>{previewTheme.typography.fontFamily}</code></p>
281
+ <p><strong>Base Font Size:</strong> <code>{previewTheme.typography.fontSize}px</code></p>
282
+ </div>
283
+
284
+ <div className="typography-samples">
285
+ <h1 style={{
286
+ fontSize: previewTheme.typography.h1.fontSize,
287
+ fontWeight: previewTheme.typography.h1.fontWeight,
288
+ lineHeight: previewTheme.typography.h1.lineHeight,
289
+ }}>
290
+ Heading 1
291
+ </h1>
292
+ <h2 style={{
293
+ fontSize: previewTheme.typography.h2.fontSize,
294
+ fontWeight: previewTheme.typography.h2.fontWeight,
295
+ lineHeight: previewTheme.typography.h2.lineHeight,
296
+ }}>
297
+ Heading 2
298
+ </h2>
299
+ <h3 style={{
300
+ fontSize: previewTheme.typography.h3.fontSize,
301
+ fontWeight: previewTheme.typography.h3.fontWeight,
302
+ lineHeight: previewTheme.typography.h3.lineHeight,
303
+ }}>
304
+ Heading 3
305
+ </h3>
306
+ <p style={{
307
+ fontSize: previewTheme.typography.body1.fontSize,
308
+ fontWeight: previewTheme.typography.body1.fontWeight,
309
+ lineHeight: previewTheme.typography.body1.lineHeight,
310
+ }}>
311
+ Body 1: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
312
+ </p>
313
+ <p style={{
314
+ fontSize: previewTheme.typography.body2.fontSize,
315
+ fontWeight: previewTheme.typography.body2.fontWeight,
316
+ lineHeight: previewTheme.typography.body2.lineHeight,
317
+ }}>
318
+ Body 2: Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
319
+ </p>
320
+ </div>
134
321
  </div>
135
- </div>
136
- )}
137
-
138
- {/* Typography */}
139
- {showTypography && (
140
- <div className="theme-typography">
141
- <h3>Typography</h3>
142
- <div className="typography-info">
143
- <p><strong>Font Family:</strong> <code>{theme.typography.fontFamily}</code></p>
144
- <p><strong>Base Font Size:</strong> <code>{theme.typography.fontSize}px</code></p>
322
+ )}
323
+
324
+ {/* Spacing */}
325
+ {showSpacing && (
326
+ <div className="theme-spacing">
327
+ <h3>Spacing</h3>
328
+ <div className="spacing-samples">
329
+ {[1, 2, 3, 4, 6, 8, 12].map((multiplier) => (
330
+ <div key={multiplier} className="spacing-item">
331
+ <div
332
+ className="spacing-box"
333
+ style={{
334
+ width: previewTheme.spacing(multiplier),
335
+ height: previewTheme.spacing(multiplier),
336
+ backgroundColor: previewTheme.palette.primary.main,
337
+ }}
338
+ />
339
+ <code>{multiplier} = {previewTheme.spacing(multiplier)}</code>
340
+ </div>
341
+ ))}
342
+ </div>
145
343
  </div>
344
+ )}
345
+
346
+ {/* Sample Components */}
347
+ <div className="theme-components">
348
+ <h3>Sample Components</h3>
146
349
 
147
- <div className="typography-samples">
148
- <h1 style={{
149
- fontSize: theme.typography.h1.fontSize,
150
- fontWeight: theme.typography.h1.fontWeight,
151
- lineHeight: theme.typography.h1.lineHeight,
152
- }}>
153
- Heading 1
154
- </h1>
155
- <h2 style={{
156
- fontSize: theme.typography.h2.fontSize,
157
- fontWeight: theme.typography.h2.fontWeight,
158
- lineHeight: theme.typography.h2.lineHeight,
159
- }}>
160
- Heading 2
161
- </h2>
162
- <h3 style={{
163
- fontSize: theme.typography.h3.fontSize,
164
- fontWeight: theme.typography.h3.fontWeight,
165
- lineHeight: theme.typography.h3.lineHeight,
166
- }}>
167
- Heading 3
168
- </h3>
169
- <p style={{
170
- fontSize: theme.typography.body1.fontSize,
171
- fontWeight: theme.typography.body1.fontWeight,
172
- lineHeight: theme.typography.body1.lineHeight,
173
- }}>
174
- Body 1: Lorem ipsum dolor sit amet, consectetur adipiscing elit.
175
- </p>
176
- <p style={{
177
- fontSize: theme.typography.body2.fontSize,
178
- fontWeight: theme.typography.body2.fontWeight,
179
- lineHeight: theme.typography.body2.lineHeight,
180
- }}>
181
- Body 2: Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
182
- </p>
183
- </div>
184
- </div>
185
- )}
186
-
187
- {/* Spacing */}
188
- {showSpacing && (
189
- <div className="theme-spacing">
190
- <h3>Spacing</h3>
191
- <div className="spacing-samples">
192
- {[1, 2, 3, 4, 6, 8, 12].map((multiplier) => (
193
- <div key={multiplier} className="spacing-item">
194
- <div
195
- className="spacing-box"
196
- style={{
197
- width: theme.spacing(multiplier),
198
- height: theme.spacing(multiplier),
199
- backgroundColor: theme.palette.primary.main,
200
- }}
201
- />
202
- <code>{multiplier} = {theme.spacing(multiplier)}</code>
203
- </div>
204
- ))}
350
+ {/* Buttons */}
351
+ <div className="component-group">
352
+ <h4>Buttons</h4>
353
+ <div className="button-group">
354
+ <button
355
+ className={`interactive-button ${interactiveStates['btn-primary'] ? 'active' : ''}`}
356
+ onClick={() => handleButtonClick('btn-primary')}
357
+ onMouseEnter={() => setInteractiveStates(prev => ({ ...prev, 'btn-primary-hover': true }))}
358
+ onMouseLeave={() => setInteractiveStates(prev => {
359
+ const next = { ...prev };
360
+ delete next['btn-primary-hover'];
361
+ return next;
362
+ })}
363
+ style={{
364
+ backgroundColor: interactiveStates['btn-primary-hover']
365
+ ? previewTheme.palette.primary.dark || previewTheme.palette.primary.main
366
+ : previewTheme.palette.primary.main,
367
+ color: previewTheme.palette.primary.contrastText,
368
+ border: 'none',
369
+ padding: previewTheme.spacing(1, 2),
370
+ borderRadius: previewTheme.borderRadius.base,
371
+ cursor: 'pointer',
372
+ transform: interactiveStates['btn-primary'] ? 'scale(0.95)' : 'scale(1)',
373
+ transition: 'all 0.2s ease',
374
+ }}
375
+ >
376
+ Primary Button
377
+ </button>
378
+ <button
379
+ className={`interactive-button ${interactiveStates['btn-secondary'] ? 'active' : ''}`}
380
+ onClick={() => handleButtonClick('btn-secondary')}
381
+ onMouseEnter={() => setInteractiveStates(prev => ({ ...prev, 'btn-secondary-hover': true }))}
382
+ onMouseLeave={() => setInteractiveStates(prev => {
383
+ const next = { ...prev };
384
+ delete next['btn-secondary-hover'];
385
+ return next;
386
+ })}
387
+ style={{
388
+ backgroundColor: interactiveStates['btn-secondary-hover']
389
+ ? previewTheme.palette.secondary.dark || previewTheme.palette.secondary.main
390
+ : previewTheme.palette.secondary.main,
391
+ color: previewTheme.palette.secondary.contrastText,
392
+ border: 'none',
393
+ padding: previewTheme.spacing(1, 2),
394
+ borderRadius: previewTheme.borderRadius.base,
395
+ cursor: 'pointer',
396
+ transform: interactiveStates['btn-secondary'] ? 'scale(0.95)' : 'scale(1)',
397
+ transition: 'all 0.2s ease',
398
+ }}
399
+ >
400
+ Secondary Button
401
+ </button>
402
+ <button
403
+ className={`interactive-button ${interactiveStates['btn-outline'] ? 'active' : ''}`}
404
+ onClick={() => handleButtonClick('btn-outline')}
405
+ onMouseEnter={() => setInteractiveStates(prev => ({ ...prev, 'btn-outline-hover': true }))}
406
+ onMouseLeave={() => setInteractiveStates(prev => {
407
+ const next = { ...prev };
408
+ delete next['btn-outline-hover'];
409
+ return next;
410
+ })}
411
+ onFocus={() => setInteractiveStates(prev => ({ ...prev, 'btn-outline-focus': true }))}
412
+ onBlur={() => setInteractiveStates(prev => {
413
+ const next = { ...prev };
414
+ delete next['btn-outline-focus'];
415
+ return next;
416
+ })}
417
+ style={{
418
+ backgroundColor: 'transparent',
419
+ color: previewTheme.palette.primary.main,
420
+ border: `2px solid ${interactiveStates['btn-outline-focus'] ? previewTheme.palette.primary.dark || previewTheme.palette.primary.main : previewTheme.palette.primary.main}`,
421
+ padding: previewTheme.spacing(1, 2),
422
+ borderRadius: previewTheme.borderRadius.base,
423
+ cursor: 'pointer',
424
+ transform: interactiveStates['btn-outline'] ? 'scale(0.95)' : 'scale(1)',
425
+ transition: 'all 0.2s ease',
426
+ outline: interactiveStates['btn-outline-focus'] ? `2px solid ${previewTheme.palette.primary.main}` : 'none',
427
+ outlineOffset: '2px',
428
+ }}
429
+ >
430
+ Outline Button
431
+ </button>
432
+ </div>
205
433
  </div>
206
- </div>
207
- )}
208
434
 
209
- {/* Sample Components */}
210
- <div className="theme-components">
211
- <h3>Sample Components</h3>
212
-
213
- {/* Buttons */}
214
- <div className="component-group">
215
- <h4>Buttons</h4>
216
- <div className="button-group">
217
- <button
435
+ {/* Cards */}
436
+ <div className="component-group">
437
+ <h4>Card</h4>
438
+ <div
439
+ className="interactive-card"
440
+ onMouseEnter={() => setInteractiveStates(prev => ({ ...prev, 'card-hover': true }))}
441
+ onMouseLeave={() => setInteractiveStates(prev => {
442
+ const next = { ...prev };
443
+ delete next['card-hover'];
444
+ return next;
445
+ })}
218
446
  style={{
219
- backgroundColor: theme.palette.primary.main,
220
- color: theme.palette.primary.contrastText,
221
- border: 'none',
222
- padding: theme.spacing(1, 2),
223
- borderRadius: theme.borderRadius.base,
447
+ backgroundColor: previewTheme.palette.background.subtle,
448
+ border: `1px solid ${previewTheme.palette.text.disabled}`,
449
+ borderRadius: previewTheme.borderRadius.lg,
450
+ padding: previewTheme.spacing(3),
451
+ boxShadow: interactiveStates['card-hover']
452
+ ? previewTheme.shadows.lg
453
+ : previewTheme.shadows.md,
454
+ maxWidth: '300px',
455
+ transition: 'all 0.2s ease',
224
456
  cursor: 'pointer',
225
457
  }}
226
458
  >
227
- Primary Button
228
- </button>
229
- <button
230
- style={{
231
- backgroundColor: theme.palette.secondary.main,
232
- color: theme.palette.secondary.contrastText,
233
- border: 'none',
234
- padding: theme.spacing(1, 2),
235
- borderRadius: theme.borderRadius.base,
236
- cursor: 'pointer',
237
- }}
238
- >
239
- Secondary Button
240
- </button>
241
- <button
242
- style={{
243
- backgroundColor: 'transparent',
244
- color: theme.palette.primary.main,
245
- border: `1px solid ${theme.palette.primary.main}`,
246
- padding: theme.spacing(1, 2),
247
- borderRadius: theme.borderRadius.base,
248
- cursor: 'pointer',
249
- }}
250
- >
251
- Outline Button
252
- </button>
459
+ <h5 style={{ margin: 0, marginBottom: previewTheme.spacing(1) }}>Card Title</h5>
460
+ <p style={{
461
+ margin: 0,
462
+ color: previewTheme.palette.text.secondary,
463
+ fontSize: previewTheme.typography.body2.fontSize,
464
+ }}>
465
+ This is a sample card component showing how the theme colors and spacing work together.
466
+ </p>
467
+ </div>
253
468
  </div>
254
469
  </div>
255
470
 
256
- {/* Cards */}
257
- <div className="component-group">
258
- <h4>Card</h4>
259
- <div
260
- style={{
261
- backgroundColor: theme.palette.background.paper,
262
- border: `1px solid ${theme.palette.text.disabled}`,
263
- borderRadius: theme.borderRadius.lg,
264
- padding: theme.spacing(3),
265
- boxShadow: theme.shadows.md,
266
- maxWidth: '300px',
267
- }}
268
- >
269
- <h5 style={{ margin: 0, marginBottom: theme.spacing(1) }}>Card Title</h5>
270
- <p style={{
271
- margin: 0,
272
- color: theme.palette.text.secondary,
273
- fontSize: theme.typography.body2.fontSize,
274
- }}>
275
- This is a sample card component showing how the theme colors and spacing work together.
276
- </p>
471
+ {/* Custom Children */}
472
+ {children && (
473
+ <div className="theme-custom">
474
+ <h3>Custom Components</h3>
475
+ {children}
277
476
  </div>
278
- </div>
477
+ )}
279
478
  </div>
280
479
 
281
- {/* Custom Children */}
282
- {children && (
283
- <div className="theme-custom">
284
- <h3>Custom Components</h3>
285
- {children}
286
- </div>
287
- )}
288
-
289
- <style >{`
480
+ <style>{`
290
481
  .atomix-theme-preview {
291
482
  padding: 24px;
292
- font-family: ${theme.typography.fontFamily};
293
- color: ${theme.palette.text.primary};
294
- background-color: ${theme.palette.background.default};
483
+ font-family: ${previewTheme.typography.fontFamily};
484
+ color: ${previewTheme.palette.text.primary};
485
+ background-color: ${previewTheme.palette.background.default};
486
+ }
487
+
488
+ .preview-controls {
489
+ display: flex;
490
+ gap: 16px;
491
+ align-items: center;
492
+ padding: 16px;
493
+ background: ${previewTheme.palette.background.subtle};
494
+ border-radius: ${previewTheme.borderRadius.md};
495
+ margin-bottom: 24px;
496
+ flex-wrap: wrap;
497
+ }
498
+
499
+ .control-group {
500
+ display: flex;
501
+ align-items: center;
502
+ gap: 8px;
503
+ }
504
+
505
+ .control-group label {
506
+ font-size: 14px;
507
+ color: ${previewTheme.palette.text.secondary};
508
+ }
509
+
510
+ .control-group select,
511
+ .control-group input[type="number"] {
512
+ padding: 6px 12px;
513
+ border: 1px solid ${previewTheme.palette.text.disabled};
514
+ border-radius: ${previewTheme.borderRadius.base};
515
+ font-size: 14px;
516
+ background: ${previewTheme.palette.background.default};
517
+ color: ${previewTheme.palette.text.primary};
518
+ }
519
+
520
+ .control-group input[type="checkbox"] {
521
+ margin-right: 4px;
522
+ }
523
+
524
+ .viewport-wrapper {
525
+ border: 2px solid ${previewTheme.palette.text.disabled};
526
+ border-radius: ${previewTheme.borderRadius.lg};
527
+ overflow: auto;
528
+ background: ${previewTheme.palette.background.default};
529
+ margin: 0 auto;
530
+ box-shadow: ${previewTheme.shadows.lg};
295
531
  }
296
532
 
297
533
  .theme-details {
298
534
  margin-bottom: 32px;
299
535
  padding: 16px;
300
- background-color: ${theme.palette.background.paper};
301
- border-radius: ${theme.borderRadius.lg};
536
+ background-color: ${previewTheme.palette.background.subtle};
537
+ border-radius: ${previewTheme.borderRadius.lg};
302
538
  }
303
539
 
304
540
  .theme-palette,
@@ -306,6 +542,7 @@ export const ThemePreview: React.FC<ThemePreviewProps> = ({
306
542
  .theme-spacing,
307
543
  .theme-components {
308
544
  margin-bottom: 32px;
545
+ padding: 16px;
309
546
  }
310
547
 
311
548
  .color-grid {
@@ -324,8 +561,8 @@ export const ThemePreview: React.FC<ThemePreviewProps> = ({
324
561
  .color-swatch {
325
562
  width: 40px;
326
563
  height: 40px;
327
- border-radius: ${theme.borderRadius.base};
328
- border: 1px solid ${theme.palette.text.disabled};
564
+ border-radius: ${previewTheme.borderRadius.base};
565
+ border: 1px solid ${previewTheme.palette.text.disabled};
329
566
  }
330
567
 
331
568
  .color-info {
@@ -336,7 +573,7 @@ export const ThemePreview: React.FC<ThemePreviewProps> = ({
336
573
 
337
574
  .color-info code {
338
575
  font-size: 12px;
339
- color: ${theme.palette.text.secondary};
576
+ color: ${previewTheme.palette.text.secondary};
340
577
  }
341
578
 
342
579
  .typography-samples {
@@ -362,7 +599,7 @@ export const ThemePreview: React.FC<ThemePreviewProps> = ({
362
599
  }
363
600
 
364
601
  .spacing-box {
365
- border: 1px solid ${theme.palette.text.disabled};
602
+ border: 1px solid ${previewTheme.palette.text.disabled};
366
603
  }
367
604
 
368
605
  .component-group {
@@ -375,18 +612,31 @@ export const ThemePreview: React.FC<ThemePreviewProps> = ({
375
612
  flex-wrap: wrap;
376
613
  }
377
614
 
615
+ .interactive-button {
616
+ transition: all 0.2s ease;
617
+ }
618
+
619
+ .interactive-button:focus-visible {
620
+ outline: 2px solid ${previewTheme.palette.primary.main};
621
+ outline-offset: 2px;
622
+ }
623
+
624
+ .interactive-card {
625
+ transition: all 0.2s ease;
626
+ }
627
+
378
628
  h3 {
379
- color: ${theme.palette.text.primary};
380
- border-bottom: 2px solid ${theme.palette.primary.main};
629
+ color: ${previewTheme.palette.text.primary};
630
+ border-bottom: 2px solid ${previewTheme.palette.primary.main};
381
631
  padding-bottom: 8px;
382
632
  }
383
633
 
384
634
  h4 {
385
- color: ${theme.palette.text.primary};
635
+ color: ${previewTheme.palette.text.primary};
386
636
  margin-top: 24px;
387
637
  margin-bottom: 12px;
388
638
  }
389
639
  `}</style>
390
640
  </div>
391
641
  );
392
- };
642
+ };