@shohojdhara/atomix 0.3.5 → 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 (173) 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 +61 -66
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.js +47 -31
  10. package/dist/core.js.map +1 -1
  11. package/dist/forms.js +47 -31
  12. package/dist/forms.js.map +1 -1
  13. package/dist/heavy.js +47 -31
  14. package/dist/heavy.js.map +1 -1
  15. package/dist/index.d.ts +1841 -1633
  16. package/dist/index.esm.js +4975 -4113
  17. package/dist/index.esm.js.map +1 -1
  18. package/dist/index.js +5151 -4290
  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 +1572 -1442
  23. package/dist/theme.js +4816 -4080
  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 +65 -31
  28. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +11 -4
  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/ButtonGroup.stories.tsx +315 -0
  38. package/src/components/Button/ButtonGroup.tsx +67 -0
  39. package/src/components/Button/index.ts +2 -0
  40. package/src/components/Callout/Callout.stories.tsx +8 -6
  41. package/src/components/Card/Card.stories.tsx +82 -28
  42. package/src/components/Chart/AnimatedChart.tsx +0 -1
  43. package/src/components/Chart/AreaChart.tsx +0 -1
  44. package/src/components/Chart/BarChart.tsx +0 -1
  45. package/src/components/Chart/BubbleChart.tsx +0 -1
  46. package/src/components/Chart/CandlestickChart.tsx +0 -1
  47. package/src/components/Chart/Chart.stories.tsx +5 -7
  48. package/src/components/Chart/Chart.tsx +0 -16
  49. package/src/components/Chart/ChartRenderer.tsx +1 -1
  50. package/src/components/Chart/DonutChart.tsx +0 -1
  51. package/src/components/Chart/FunnelChart.tsx +0 -1
  52. package/src/components/Chart/GaugeChart.tsx +0 -1
  53. package/src/components/Chart/HeatmapChart.tsx +0 -1
  54. package/src/components/Chart/LineChart.tsx +0 -1
  55. package/src/components/Chart/MultiAxisChart.tsx +0 -1
  56. package/src/components/Chart/PieChart.tsx +0 -1
  57. package/src/components/Chart/RadarChart.tsx +0 -1
  58. package/src/components/Chart/ScatterChart.tsx +0 -1
  59. package/src/components/Chart/WaterfallChart.tsx +0 -1
  60. package/src/components/ColorModeToggle/ColorModeToggle.stories.tsx +7 -0
  61. package/src/components/DataTable/DataTable.stories.tsx +23 -16
  62. package/src/components/DatePicker/DatePicker.stories.tsx +27 -19
  63. package/src/components/Dropdown/Dropdown.stories.tsx +11 -19
  64. package/src/components/EdgePanel/EdgePanel.stories.tsx +1 -0
  65. package/src/components/Footer/Footer.stories.tsx +8 -6
  66. package/src/components/Footer/FooterLink.tsx +9 -2
  67. package/src/components/Form/Checkbox.stories.tsx +7 -0
  68. package/src/components/Form/Form.stories.tsx +7 -0
  69. package/src/components/Form/FormGroup.stories.tsx +9 -1
  70. package/src/components/Form/Input.stories.tsx +69 -16
  71. package/src/components/Form/Radio.stories.tsx +9 -1
  72. package/src/components/Form/Select.stories.tsx +9 -1
  73. package/src/components/Form/Textarea.stories.tsx +10 -2
  74. package/src/components/Hero/Hero.stories.tsx +7 -0
  75. package/src/components/List/List.stories.tsx +7 -0
  76. package/src/components/Messages/Messages.stories.tsx +8 -7
  77. package/src/components/Modal/Modal.stories.tsx +17 -6
  78. package/src/components/Navigation/Menu/Menu.stories.tsx +7 -0
  79. package/src/components/Navigation/Nav/Nav.stories.tsx +7 -0
  80. package/src/components/Navigation/Navbar/Navbar.stories.tsx +1 -0
  81. package/src/components/Navigation/SideMenu/SideMenu.stories.tsx +1 -1
  82. package/src/components/Pagination/Pagination.stories.tsx +188 -111
  83. package/src/components/Pagination/Pagination.tsx +83 -3
  84. package/src/components/PhotoViewer/PhotoViewer.stories.tsx +10 -5
  85. package/src/components/Popover/Popover.stories.tsx +191 -115
  86. package/src/components/ProductReview/ProductReview.stories.tsx +80 -58
  87. package/src/components/Progress/Progress.stories.tsx +79 -49
  88. package/src/components/Rating/Rating.stories.tsx +109 -84
  89. package/src/components/River/River.stories.tsx +194 -114
  90. package/src/components/SectionIntro/SectionIntro.stories.tsx +19 -9
  91. package/src/components/Slider/Slider.stories.tsx +7 -0
  92. package/src/components/Spinner/Spinner.stories.tsx +15 -11
  93. package/src/components/Steps/Steps.stories.tsx +132 -98
  94. package/src/components/Tabs/Tabs.stories.tsx +163 -112
  95. package/src/components/Testimonial/Testimonial.stories.tsx +114 -68
  96. package/src/components/Todo/Todo.stories.tsx +38 -12
  97. package/src/components/Toggle/Toggle.stories.tsx +61 -28
  98. package/src/components/Tooltip/Tooltip.stories.tsx +318 -200
  99. package/src/components/Upload/Upload.stories.tsx +122 -84
  100. package/src/components/VideoPlayer/VideoPlayer.stories.tsx +7 -24
  101. package/src/components/index.ts +1 -0
  102. package/src/lib/composables/useAtomixGlass.ts +2 -3
  103. package/src/lib/composables/useNavbar.ts +0 -10
  104. package/src/lib/config/loader.ts +2 -1
  105. package/src/lib/constants/components.ts +10 -0
  106. package/src/lib/hooks/useComponentCustomization.ts +1 -1
  107. package/src/lib/theme/README.md +174 -0
  108. package/src/lib/theme/adapters/index.ts +31 -0
  109. package/src/lib/theme/adapters/themeAdapter.ts +287 -0
  110. package/src/lib/theme/config/__tests__/configLoader.test.ts +207 -0
  111. package/src/lib/theme/config/configLoader.ts +254 -0
  112. package/src/lib/theme/config/loader.ts +37 -48
  113. package/src/lib/theme/config/types.ts +2 -2
  114. package/src/lib/theme/config/validator.ts +15 -91
  115. package/src/lib/theme/{constants.ts → constants/constants.ts} +0 -18
  116. package/src/lib/theme/constants/index.ts +8 -0
  117. package/src/lib/theme/core/ThemeRegistry.ts +19 -6
  118. package/src/lib/theme/core/__tests__/createTheme.test.ts +132 -0
  119. package/src/lib/theme/core/composeTheme.ts +155 -0
  120. package/src/lib/theme/core/createTheme.ts +94 -0
  121. package/src/lib/theme/{createTheme.ts → core/createThemeObject.ts} +10 -6
  122. package/src/lib/theme/core/index.ts +5 -19
  123. package/src/lib/theme/devtools/Comparator.tsx +346 -22
  124. package/src/lib/theme/devtools/IMPROVEMENTS.md +139 -38
  125. package/src/lib/theme/devtools/Inspector.tsx +335 -51
  126. package/src/lib/theme/devtools/LiveEditor.tsx +478 -107
  127. package/src/lib/theme/devtools/Preview.tsx +471 -221
  128. package/src/lib/theme/{core → devtools}/ThemeValidator.ts +1 -1
  129. package/src/lib/theme/devtools/index.ts +14 -4
  130. package/src/lib/theme/devtools/useHistory.ts +130 -0
  131. package/src/lib/theme/errors/index.ts +12 -0
  132. package/src/lib/theme/generators/cssFile.ts +79 -0
  133. package/src/lib/theme/generators/generateCSS.ts +89 -0
  134. package/src/lib/theme/{generateCSSVariables.ts → generators/generateCSSVariables.ts} +3 -13
  135. package/src/lib/theme/generators/index.ts +19 -0
  136. package/src/lib/theme/i18n/rtl.ts +5 -6
  137. package/src/lib/theme/index.ts +120 -15
  138. package/src/lib/theme/runtime/ThemeApplicator.ts +52 -111
  139. package/src/lib/theme/{ThemeContext.tsx → runtime/ThemeContext.tsx} +1 -1
  140. package/src/lib/theme/runtime/ThemeErrorBoundary.tsx +1 -1
  141. package/src/lib/theme/runtime/ThemeProvider.tsx +456 -179
  142. package/src/lib/theme/runtime/index.ts +1 -2
  143. package/src/lib/theme/runtime/useTheme.ts +1 -2
  144. package/src/lib/theme/test/testTheme.ts +385 -0
  145. package/src/lib/theme/tokens/index.ts +12 -0
  146. package/src/lib/theme/tokens/tokens.ts +721 -0
  147. package/src/lib/theme/types.ts +6 -42
  148. package/src/lib/theme/{utils.ts → utils/domUtils.ts} +2 -2
  149. package/src/lib/theme/utils/index.ts +11 -0
  150. package/src/lib/theme/utils/injectCSS.ts +90 -0
  151. package/src/lib/theme/utils/themeHelpers.ts +78 -0
  152. package/src/lib/theme/{themeUtils.ts → utils/themeUtils.ts} +1 -1
  153. package/src/lib/theme-tools.ts +7 -8
  154. package/src/lib/types/components.ts +40 -130
  155. package/src/lib/utils/componentUtils.ts +1 -1
  156. package/src/styles/01-settings/_settings.design-tokens.scss +4 -1
  157. package/src/styles/02-tools/_tools.button.scss +66 -79
  158. package/src/styles/06-components/_components.atomix-glass.scss +13 -3
  159. package/src/styles/06-components/_components.pagination.scss +88 -0
  160. package/scripts/sync-theme-config.js +0 -309
  161. package/src/lib/theme/composeTheme.ts +0 -370
  162. package/src/lib/theme/core/ThemeCache.ts +0 -283
  163. package/src/lib/theme/core/ThemeEngine.test.ts +0 -146
  164. package/src/lib/theme/core/ThemeEngine.ts +0 -665
  165. package/src/lib/theme/createThemeFromConfig.ts +0 -132
  166. package/src/lib/theme/devtools/CLI.ts +0 -364
  167. package/src/lib/theme/runtime/ThemeManager.test.ts +0 -192
  168. package/src/lib/theme/runtime/ThemeManager.ts +0 -446
  169. package/src/styles/03-generic/_generated-root.css +0 -26
  170. package/src/themes/README.md +0 -442
  171. package/src/themes/themes.config.js +0 -68
  172. /package/src/lib/theme/{cssVariableMapper.ts → adapters/cssVariableMapper.ts} +0 -0
  173. /package/src/lib/theme/{errors.ts → errors/errors.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
+ };