@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
@@ -249,44 +249,6 @@ import {
249
249
 
250
250
  ---
251
251
 
252
- ## Migration Guide
253
-
254
- ### For Existing Users
255
-
256
- No breaking changes! All existing code continues to work.
257
-
258
- **Before:**
259
- ```tsx
260
- import { ThemeInspector } from '@shohojdhara/atomix/theme/devtools';
261
- ```
262
-
263
- **After (still works):**
264
- ```tsx
265
- import { ThemeInspector } from '@shohojdhara/atomix/theme/devtools';
266
- ```
267
-
268
- **New (also works):**
269
- ```tsx
270
- import { ThemeInspector } from '@shohojdhara/atomix/theme';
271
- ```
272
-
273
- ### New Features
274
-
275
- Simply import and use the new components:
276
-
277
- ```tsx
278
- import {
279
- ThemeComparator,
280
- ThemeLiveEditor,
281
- } from '@shohojdhara/atomix/theme';
282
-
283
- // Use them immediately
284
- <ThemeComparator themeA={theme1} themeB={theme2} />
285
- <ThemeLiveEditor initialTheme={theme} />
286
- ```
287
-
288
- ---
289
-
290
252
  ## Future Enhancements
291
253
 
292
254
  ### Planned Features
@@ -318,6 +280,145 @@ import {
318
280
 
319
281
  ---
320
282
 
283
+ ## Phase 2: Enhanced DevTools Features (2025-01-27)
284
+
285
+ ### Overview
286
+
287
+ This phase focuses on enhancing the core devtools components (`ThemeLiveEditor`, `ThemePreview`, `ThemeInspector`, `ThemeComparator`) with advanced features inspired by professional theme studio implementations.
288
+
289
+ ### Phase 1: Enhanced ThemeLiveEditor
290
+
291
+ **New Features:**
292
+
293
+ 1. **Undo/Redo System**
294
+ - History stack for theme changes
295
+ - Keyboard shortcuts (Ctrl+Z / Ctrl+Shift+Z)
296
+ - Visual history indicator
297
+ - Maximum history size (50 entries)
298
+
299
+ 2. **Keyboard Shortcuts**
300
+ - `Ctrl+Z` / `Cmd+Z` - Undo
301
+ - `Ctrl+Shift+Z` / `Cmd+Shift+Z` - Redo
302
+ - `Ctrl+S` / `Cmd+S` - Save/Export theme
303
+ - `Ctrl+/` / `Cmd+/` - Toggle edit mode
304
+ - `Escape` - Clear errors
305
+
306
+ 3. **Resizable Layout**
307
+ - Drag-to-resize split between editor and preview
308
+ - Persistent layout preferences (localStorage)
309
+ - Minimum panel sizes enforced
310
+ - Smooth resize animations
311
+
312
+ 4. **Enhanced Color Pickers**
313
+ - Alpha channel support (RGBA)
314
+ - Multiple format support (hex, rgb, hsl)
315
+ - Color format conversion
316
+ - Color history/palette
317
+ - Contrast checker integration
318
+
319
+ **Implementation Details:**
320
+ - Custom `useHistory` hook for undo/redo
321
+ - Resizable panels using mouse drag events
322
+ - Enhanced color input with format detection
323
+ - Keyboard event listeners with proper cleanup
324
+
325
+ ### Phase 2: Enhanced ThemePreview
326
+
327
+ **New Features:**
328
+
329
+ 1. **Interactive Components**
330
+ - Hover states on all interactive elements
331
+ - Focus states for accessibility
332
+ - Active/pressed states for buttons
333
+ - Click interactions with visual feedback
334
+
335
+ 2. **Viewport Controls**
336
+ - Mobile viewport simulation (375px, 414px)
337
+ - Tablet viewport simulation (768px, 1024px)
338
+ - Desktop viewport simulation (1280px, 1920px)
339
+ - Custom viewport size input
340
+ - Responsive breakpoint indicators
341
+
342
+ 3. **Dark Mode Toggle**
343
+ - Independent dark mode preview (separate from system)
344
+ - Smooth theme transition
345
+ - Preview-specific theme override
346
+ - Toggle button with visual indicator
347
+
348
+ **Implementation Details:**
349
+ - Interactive state management for preview components
350
+ - Viewport wrapper with responsive controls
351
+ - Theme mode state independent of system preferences
352
+ - CSS transitions for smooth mode switching
353
+
354
+ ### Phase 3: Enhanced ThemeInspector
355
+
356
+ **New Features:**
357
+
358
+ 1. **Search/Filter**
359
+ - Real-time search across all theme properties
360
+ - Filter by property type (color, typography, spacing, etc.)
361
+ - Highlight matching results
362
+ - Search history
363
+ - Clear search button
364
+
365
+ 2. **Copy Path Functionality**
366
+ - Click property names to copy dot-notation path
367
+ - Visual feedback on copy
368
+ - Copy button for each property
369
+ - Path format: `palette.primary.main`
370
+ - Toast notification on successful copy
371
+
372
+ **Implementation Details:**
373
+ - Debounced search input
374
+ - Recursive property path generation
375
+ - Clipboard API with fallback
376
+ - Highlight matching text in results
377
+
378
+ ### Phase 4: Enhanced ThemeComparator
379
+
380
+ **New Features:**
381
+
382
+ 1. **Search/Filter**
383
+ - Filter differences by type (added/removed/changed)
384
+ - Search within difference paths
385
+ - Filter by property category
386
+ - Clear filters button
387
+
388
+ 2. **Improved Visual Diff**
389
+ - Green background for added properties
390
+ - Red background for removed properties
391
+ - Yellow/orange background for changed properties
392
+ - Side-by-side value highlighting
393
+ - Diff statistics with breakdown
394
+
395
+ **Implementation Details:**
396
+ - Filter state management
397
+ - Enhanced diff styling with better contrast
398
+ - Improved value comparison visualization
399
+ - Category-based filtering
400
+
401
+ ---
402
+
403
+ ## Implementation Status
404
+
405
+ ### Completed ✅
406
+ - [x] IMPROVEMENTS.md documentation
407
+ - [x] useHistory hook implementation (`src/lib/theme/devtools/useHistory.ts`)
408
+ - [x] LiveEditor enhancements (undo/redo, keyboard shortcuts, resizable layout, enhanced color pickers)
409
+ - [x] Preview enhancements (interactive components, viewport controls, dark mode toggle)
410
+ - [x] Inspector enhancements (search/filter, copy path functionality)
411
+ - [x] Comparator enhancements (search/filter, improved visual diff styling)
412
+ - [x] CLI enhancements (list, inspect, compare, export commands)
413
+
414
+ ### Remaining Tasks 🚧
415
+ - [ ] Testing and validation
416
+ - [ ] Storybook stories for new features
417
+ - [ ] Performance optimization
418
+ - [ ] Accessibility audit
419
+
420
+ ---
421
+
321
422
  ## Files Changed
322
423
 
323
424
  ### Modified Files
@@ -2,12 +2,13 @@
2
2
  * Theme Inspector Component
3
3
  *
4
4
  * React component for inspecting and debugging themes
5
+ * Enhanced with search/filter and copy path functionality
5
6
  */
6
7
 
7
- import React, { useState, useMemo } from 'react';
8
+ import React, { useState, useMemo, useCallback, useRef, useEffect } from 'react';
8
9
  import type { Theme } from '../types';
9
- import { generateCSSVariables } from '../generateCSSVariables';
10
- import { ThemeValidator } from '../core/ThemeValidator';
10
+ import { generateCSSVariables } from '../generators/generateCSSVariables';
11
+ import { ThemeValidator } from './ThemeValidator';
11
12
 
12
13
  /**
13
14
  * Theme inspector props
@@ -27,6 +28,15 @@ export interface ThemeInspectorProps {
27
28
  style?: React.CSSProperties;
28
29
  }
29
30
 
31
+ /**
32
+ * Property path information
33
+ */
34
+ interface PropertyPath {
35
+ path: string;
36
+ value: any;
37
+ matches: boolean;
38
+ }
39
+
30
40
  /**
31
41
  * Theme Inspector Component
32
42
  *
@@ -42,6 +52,27 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
42
52
  }) => {
43
53
  const [activeTab, setActiveTab] = useState<'overview' | 'validation' | 'css' | 'structure'>('overview');
44
54
  const [expandedSections, setExpandedSections] = useState<Set<string>>(new Set(['palette']));
55
+ const [searchQuery, setSearchQuery] = useState<string>('');
56
+ const [debouncedSearchQuery, setDebouncedSearchQuery] = useState<string>('');
57
+ const [copiedPath, setCopiedPath] = useState<string | null>(null);
58
+ const searchTimeoutRef = useRef<NodeJS.Timeout>();
59
+
60
+ // Debounce search query
61
+ useEffect(() => {
62
+ if (searchTimeoutRef.current) {
63
+ clearTimeout(searchTimeoutRef.current);
64
+ }
65
+
66
+ searchTimeoutRef.current = setTimeout(() => {
67
+ setDebouncedSearchQuery(searchQuery);
68
+ }, 300);
69
+
70
+ return () => {
71
+ if (searchTimeoutRef.current) {
72
+ clearTimeout(searchTimeoutRef.current);
73
+ }
74
+ };
75
+ }, [searchQuery]);
45
76
 
46
77
  // Validation results
47
78
  const validationResult = useMemo(() => {
@@ -74,6 +105,52 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
74
105
  }
75
106
  }, [theme, showCSSVariables]);
76
107
 
108
+ // Generate all property paths for search
109
+ const allPropertyPaths = useMemo(() => {
110
+ const paths: PropertyPath[] = [];
111
+
112
+ const traverse = (obj: any, path: string = '', depth: number = 0): void => {
113
+ if (depth > 10) return; // Prevent infinite recursion
114
+
115
+ if (obj === null || obj === undefined) {
116
+ paths.push({ path, value: obj, matches: false });
117
+ return;
118
+ }
119
+
120
+ if (typeof obj === 'object' && !Array.isArray(obj)) {
121
+ Object.entries(obj).forEach(([key, value]) => {
122
+ if (key === '__isJSTheme') return;
123
+
124
+ const currentPath = path ? `${path}.${key}` : key;
125
+ const pathLower = currentPath.toLowerCase();
126
+ const queryLower = debouncedSearchQuery.toLowerCase();
127
+ const matches = debouncedSearchQuery ? pathLower.includes(queryLower) : true;
128
+
129
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
130
+ paths.push({ path: currentPath, value: null, matches });
131
+ traverse(value, currentPath, depth + 1);
132
+ } else {
133
+ const valueStr = typeof value === 'string' ? value.toLowerCase() : String(value).toLowerCase();
134
+ const valueMatches = debouncedSearchQuery ? valueStr.includes(queryLower) : true;
135
+ paths.push({
136
+ path: currentPath,
137
+ value,
138
+ matches: matches || valueMatches
139
+ });
140
+ }
141
+ });
142
+ } else {
143
+ const pathLower = path.toLowerCase();
144
+ const queryLower = debouncedSearchQuery.toLowerCase();
145
+ const matches = debouncedSearchQuery ? pathLower.includes(queryLower) : true;
146
+ paths.push({ path, value: obj, matches });
147
+ }
148
+ };
149
+
150
+ traverse(theme);
151
+ return paths;
152
+ }, [theme, debouncedSearchQuery]);
153
+
77
154
  const toggleSection = (section: string) => {
78
155
  const newExpanded = new Set(expandedSections);
79
156
  if (newExpanded.has(section)) {
@@ -84,13 +161,50 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
84
161
  setExpandedSections(newExpanded);
85
162
  };
86
163
 
87
- const renderValue = (value: any, depth = 0): React.ReactNode => {
164
+ const copyPath = useCallback(async (path: string) => {
165
+ try {
166
+ await navigator.clipboard.writeText(path);
167
+ setCopiedPath(path);
168
+ setTimeout(() => setCopiedPath(null), 2000);
169
+ } catch (err) {
170
+ // Fallback for older browsers
171
+ const textArea = document.createElement('textarea');
172
+ textArea.value = path;
173
+ textArea.style.position = 'fixed';
174
+ textArea.style.opacity = '0';
175
+ document.body.appendChild(textArea);
176
+ textArea.select();
177
+ try {
178
+ document.execCommand('copy');
179
+ setCopiedPath(path);
180
+ setTimeout(() => setCopiedPath(null), 2000);
181
+ } catch {
182
+ // Copy failed
183
+ }
184
+ document.body.removeChild(textArea);
185
+ }
186
+ }, []);
187
+
188
+ const highlightText = (text: string, query: string): React.ReactNode => {
189
+ if (!query) return text;
190
+
191
+ const parts = text.split(new RegExp(`(${query})`, 'gi'));
192
+ return parts.map((part, index) =>
193
+ part.toLowerCase() === query.toLowerCase() ? (
194
+ <mark key={index} className="search-highlight">{part}</mark>
195
+ ) : (
196
+ part
197
+ )
198
+ );
199
+ };
200
+
201
+ const renderValue = (value: any, depth = 0, path = ''): React.ReactNode => {
88
202
  if (value === null || value === undefined) {
89
203
  return <span className="value-null">null</span>;
90
204
  }
91
205
 
92
206
  if (typeof value === 'string') {
93
- return <span className="value-string">&quot;{value}&quot;</span>;
207
+ return <span className="value-string">&quot;{highlightText(value, debouncedSearchQuery)}&quot;</span>;
94
208
  }
95
209
 
96
210
  if (typeof value === 'number') {
@@ -110,7 +224,7 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
110
224
  <div className="value-array">
111
225
  [{value.map((item, index) => (
112
226
  <div key={index} className="array-item">
113
- {renderValue(item, depth + 1)}
227
+ {renderValue(item, depth + 1, `${path}[${index}]`)}
114
228
  {index < value.length - 1 && ','}
115
229
  </div>
116
230
  ))}]
@@ -122,12 +236,24 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
122
236
  return (
123
237
  <div className="value-object" style={{ marginLeft: depth * 16 }}>
124
238
  {'{'}
125
- {Object.entries(value).map(([key, val]) => (
126
- <div key={key} className="object-property">
127
- <span className="property-key">{key}:</span>{' '}
128
- {renderValue(val, depth + 1)}
129
- </div>
130
- ))}
239
+ {Object.entries(value).map(([key, val]) => {
240
+ const currentPath = path ? `${path}.${key}` : key;
241
+ return (
242
+ <div key={key} className="object-property">
243
+ <span
244
+ className="property-key clickable"
245
+ onClick={() => copyPath(currentPath)}
246
+ title={`Click to copy: ${currentPath}`}
247
+ >
248
+ {highlightText(key, debouncedSearchQuery)}:
249
+ </span>{' '}
250
+ {renderValue(val, depth + 1, currentPath)}
251
+ {copiedPath === currentPath && (
252
+ <span className="copy-feedback">✓ Copied!</span>
253
+ )}
254
+ </div>
255
+ );
256
+ })}
131
257
  {'}'}
132
258
  </div>
133
259
  );
@@ -282,48 +408,103 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
282
408
  </div>
283
409
  );
284
410
 
285
- const renderStructure = () => (
286
- <div className="inspector-structure">
287
- <h3>Theme Structure</h3>
288
- <div className="structure-tree">
289
- {Object.entries(theme).map(([key, value]) => {
290
- if (key === '__isJSTheme') return null;
291
-
292
- const isExpanded = expandedSections.has(key);
293
- const hasChildren = typeof value === 'object' && value !== null && !Array.isArray(value);
294
-
295
- return (
296
- <div key={key} className="structure-node">
297
- <div
298
- className="structure-header"
299
- onClick={() => hasChildren && toggleSection(key)}
411
+ const renderStructure = () => {
412
+ const filteredPaths = debouncedSearchQuery
413
+ ? allPropertyPaths.filter(p => p.matches)
414
+ : allPropertyPaths;
415
+
416
+ return (
417
+ <div className="inspector-structure">
418
+ <div className="structure-header-controls">
419
+ <h3>Theme Structure</h3>
420
+ <div className="search-controls">
421
+ <input
422
+ type="text"
423
+ placeholder="Search properties..."
424
+ value={searchQuery}
425
+ onChange={(e) => setSearchQuery(e.target.value)}
426
+ className="search-input"
427
+ />
428
+ {searchQuery && (
429
+ <button
430
+ className="clear-search"
431
+ onClick={() => setSearchQuery('')}
432
+ title="Clear search"
300
433
  >
301
- {hasChildren && (
302
- <span className={`expand-icon ${isExpanded ? 'expanded' : ''}`}>
303
-
434
+ ×
435
+ </button>
436
+ )}
437
+ {debouncedSearchQuery && (
438
+ <span className="search-results-count">
439
+ {filteredPaths.length} result{filteredPaths.length !== 1 ? 's' : ''}
440
+ </span>
441
+ )}
442
+ </div>
443
+ </div>
444
+
445
+ {debouncedSearchQuery && filteredPaths.length === 0 && (
446
+ <div className="no-results">
447
+ No properties found matching &quot;{debouncedSearchQuery}&quot;
448
+ </div>
449
+ )}
450
+
451
+ <div className="structure-tree">
452
+ {Object.entries(theme).map(([key, value]) => {
453
+ if (key === '__isJSTheme') return null;
454
+
455
+ const isExpanded = expandedSections.has(key);
456
+ const hasChildren = typeof value === 'object' && value !== null && !Array.isArray(value);
457
+ const pathMatches = debouncedSearchQuery
458
+ ? allPropertyPaths.some(p => p.path.startsWith(key) && p.matches)
459
+ : true;
460
+
461
+ if (debouncedSearchQuery && !pathMatches) return null;
462
+
463
+ return (
464
+ <div key={key} className="structure-node">
465
+ <div
466
+ className="structure-header"
467
+ onClick={() => hasChildren && toggleSection(key)}
468
+ >
469
+ {hasChildren && (
470
+ <span className={`expand-icon ${isExpanded ? 'expanded' : ''}`}>
471
+
472
+ </span>
473
+ )}
474
+ <span
475
+ className="property-name clickable"
476
+ onClick={(e) => {
477
+ e.stopPropagation();
478
+ copyPath(key);
479
+ }}
480
+ title={`Click to copy: ${key}`}
481
+ >
482
+ {highlightText(key, debouncedSearchQuery)}
483
+ </span>
484
+ {copiedPath === key && (
485
+ <span className="copy-feedback">✓ Copied!</span>
486
+ )}
487
+ <span className="property-type">
488
+ {Array.isArray(value) ? 'array' : typeof value}
304
489
  </span>
490
+ </div>
491
+ {hasChildren && isExpanded && (
492
+ <div className="structure-children">
493
+ {renderValue(value, 0, key)}
494
+ </div>
495
+ )}
496
+ {!hasChildren && (
497
+ <div className="structure-value">
498
+ {renderValue(value, 0, key)}
499
+ </div>
305
500
  )}
306
- <span className="property-name">{key}</span>
307
- <span className="property-type">
308
- {Array.isArray(value) ? 'array' : typeof value}
309
- </span>
310
501
  </div>
311
- {hasChildren && isExpanded && (
312
- <div className="structure-children">
313
- {renderValue(value)}
314
- </div>
315
- )}
316
- {!hasChildren && (
317
- <div className="structure-value">
318
- {renderValue(value)}
319
- </div>
320
- )}
321
- </div>
322
- );
323
- })}
502
+ );
503
+ })}
504
+ </div>
324
505
  </div>
325
- </div>
326
- );
506
+ );
507
+ };
327
508
 
328
509
  return (
329
510
  <div className={`atomix-theme-inspector ${className || ''}`} style={style}>
@@ -372,7 +553,7 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
372
553
  {activeTab === 'structure' && renderStructure()}
373
554
  </div>
374
555
 
375
- <style >{`
556
+ <style>{`
376
557
  .atomix-theme-inspector {
377
558
  border: 1px solid #e0e0e0;
378
559
  border-radius: 8px;
@@ -529,6 +710,10 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
529
710
  cursor: pointer;
530
711
  }
531
712
 
713
+ .copy-button:hover {
714
+ background: #1976d2;
715
+ }
716
+
532
717
  .css-code {
533
718
  background: #f5f5f5;
534
719
  padding: 16px;
@@ -539,6 +724,78 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
539
724
  line-height: 1.4;
540
725
  }
541
726
 
727
+ .structure-header-controls {
728
+ display: flex;
729
+ justify-content: space-between;
730
+ align-items: center;
731
+ margin-bottom: 16px;
732
+ flex-wrap: wrap;
733
+ gap: 12px;
734
+ }
735
+
736
+ .structure-header-controls h3 {
737
+ margin: 0;
738
+ }
739
+
740
+ .search-controls {
741
+ display: flex;
742
+ align-items: center;
743
+ gap: 8px;
744
+ }
745
+
746
+ .search-input {
747
+ padding: 8px 12px;
748
+ border: 1px solid #e0e0e0;
749
+ border-radius: 4px;
750
+ font-size: 14px;
751
+ width: 250px;
752
+ }
753
+
754
+ .search-input:focus {
755
+ outline: none;
756
+ border-color: #2196f3;
757
+ }
758
+
759
+ .clear-search {
760
+ background: #f44336;
761
+ color: white;
762
+ border: none;
763
+ border-radius: 50%;
764
+ width: 24px;
765
+ height: 24px;
766
+ cursor: pointer;
767
+ font-size: 18px;
768
+ line-height: 1;
769
+ display: flex;
770
+ align-items: center;
771
+ justify-content: center;
772
+ }
773
+
774
+ .clear-search:hover {
775
+ background: #d32f2f;
776
+ }
777
+
778
+ .search-results-count {
779
+ font-size: 12px;
780
+ color: #666;
781
+ padding: 4px 8px;
782
+ background: #f5f5f5;
783
+ border-radius: 4px;
784
+ }
785
+
786
+ .no-results {
787
+ padding: 24px;
788
+ text-align: center;
789
+ color: #666;
790
+ font-style: italic;
791
+ }
792
+
793
+ .search-highlight {
794
+ background: #fff59d;
795
+ padding: 2px 4px;
796
+ border-radius: 2px;
797
+ }
798
+
542
799
  .structure-node {
543
800
  margin-bottom: 8px;
544
801
  }
@@ -570,6 +827,23 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
570
827
  color: #1976d2;
571
828
  }
572
829
 
830
+ .property-name.clickable {
831
+ cursor: pointer;
832
+ text-decoration: underline;
833
+ text-decoration-style: dotted;
834
+ }
835
+
836
+ .property-name.clickable:hover {
837
+ color: #0d47a1;
838
+ }
839
+
840
+ .copy-feedback {
841
+ font-size: 12px;
842
+ color: #4caf50;
843
+ margin-left: 8px;
844
+ font-weight: normal;
845
+ }
846
+
573
847
  .property-type {
574
848
  font-size: 12px;
575
849
  color: #666;
@@ -603,7 +877,17 @@ export const ThemeInspector: React.FC<ThemeInspectorProps> = ({
603
877
  color: #1976d2;
604
878
  font-weight: bold;
605
879
  }
880
+
881
+ .property-key.clickable {
882
+ cursor: pointer;
883
+ text-decoration: underline;
884
+ text-decoration-style: dotted;
885
+ }
886
+
887
+ .property-key.clickable:hover {
888
+ color: #0d47a1;
889
+ }
606
890
  `}</style>
607
891
  </div>
608
892
  );
609
- };
893
+ };