visualifyjs 2.5.3-2.dev → 3.0.0

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 (252) hide show
  1. package/.claude/mem/TIMELINE.md +36 -0
  2. package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-external-script-solution.md +24 -0
  3. package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-session-summary.md +43 -0
  4. package/.claude/mem/notes/2026-02-11-cli-fix-editor-command-alias.md +26 -0
  5. package/.claude/mem/notes/2026-02-11-phase-3-developer-experience-completed.md +51 -0
  6. package/.claude/mem/notes/2026-02-11-phase-4-web-workers-implementation-complete.md +59 -0
  7. package/.claude/mem/notes/2026-02-11-visualify-phase-2-3d-visualization-complete.md +50 -0
  8. package/.claude/mem/notes/2026-02-11-visualify-phase-2-committed-ready-for-phase-3.md +33 -0
  9. package/.claude/mem/notes/2026-02-11-visualify-phase-3-complete-developer-experience.md +52 -0
  10. package/.claude/mem/notes/2026-02-11-visualify-repository-cleanup-complete.md +28 -0
  11. package/.claude/mem/notes/2026-02-18-codebase-cleanup-docsify-plugin-documentation.md +37 -0
  12. package/.claude/mem/notes/2026-02-19-css-grid-layout-fix-displaycontents-on-vcontroller.md +18 -0
  13. package/.claude/mem/notes/2026-02-19-docsify-plugin-fixes-latex-and-visualify-code-bloc.md +26 -0
  14. package/.claude/mem/notes/2026-02-19-page-mode-docs-update-decisions.md +23 -0
  15. package/.claude/mem/notes/2026-02-19-react-context-infinite-re-render-loop-fix-pattern.md +31 -0
  16. package/.claude/mem/notes/2026-02-19-version-300-bump-and-build-fixes.md +32 -0
  17. package/.claude/mem/notes/2026-02-19-visualify-build-deployment-architecture-bug-fixes.md +25 -0
  18. package/.claude/mem/notes/2026-02-19-visualify-dist-iife-self-contained-build-config.md +30 -0
  19. package/.claude/mem/notes/2026-02-19-visualify-infinite-loop-i18n-fixes.md +31 -0
  20. package/.claude/mem/notes/2026-02-19-visualify-v3-bundle-splitting-docs-restructuring.md +32 -0
  21. package/.claude/mem/notes/2026-02-20-bundle-externalization-final-architecture.md +29 -0
  22. package/.claude/mem/notes/2026-02-20-chromium-page-fix-unstable-keys-and-double-event-b.md +27 -0
  23. package/.claude/mem/notes/2026-02-20-console-cleanup-bundle-optimization-commit.md +20 -0
  24. package/.claude/mem/notes/2026-02-20-dotbio-dot-plot-fix-useeffect-dependency.md +21 -0
  25. package/.claude/mem/notes/2026-02-20-public-folder-cleanup-and-readme-rewrite.md +25 -0
  26. package/.claude/mem/notes/2026-02-20-v300-release-and-beta-channel-strategy.md +29 -0
  27. package/.claude/mem/notes/2026-02-20-visium-background-image-unknown-legend-fix.md +19 -0
  28. package/.claude/mem/notes/2026-02-20-visualify-cdn-loader-bundle-externalization.md +34 -0
  29. package/.claude/mem/sessions/session-2026-02-20-031524.md +54 -0
  30. package/.claude/settings.local.json +21 -0
  31. package/.github/workflows/static.yml.bak +51 -51
  32. package/.sisyphus/boulder.json +65 -0
  33. package/.sisyphus/plans/phase-4-advanced-optimizations.md +217 -0
  34. package/LICENSE +674 -674
  35. package/README.md +94 -59
  36. package/config-overrides.js +31 -31
  37. package/dist/stats.html +4949 -0
  38. package/dist/visualify-3d.esm.js +1 -0
  39. package/dist/visualify-3d.js +1 -0
  40. package/dist/visualify-core.esm.js +1 -0
  41. package/dist/visualify-core.js +1 -0
  42. package/dist/visualify-docs.esm.js +1 -0
  43. package/dist/visualify-docs.js +1 -0
  44. package/dist/visualify-loader.js +1 -0
  45. package/dist/visualify-pages.esm.js +1 -0
  46. package/dist/visualify-pages.js +1 -0
  47. package/dist/visualify-portal.esm.js +1 -0
  48. package/dist/visualify-portal.js +1 -0
  49. package/dist/visualify-shared.js +26571 -0
  50. package/dist/visualify.js +1 -188
  51. package/docs/CHANGELOG.md +148 -0
  52. package/docs/cli/commands.md +513 -0
  53. package/docs/configuration/visualify-json.md +474 -0
  54. package/docs/docs/3d-visualization.md +374 -0
  55. package/docs/docs/CLI.md +303 -34
  56. package/docs/docs/README.md +65 -65
  57. package/docs/docs/Rechart/bar.md +190 -190
  58. package/docs/docs/Rechart/funnel.md +241 -241
  59. package/docs/docs/Rechart/line.md +355 -355
  60. package/docs/docs/Rechart/pie.md +225 -225
  61. package/docs/docs/Rechart/radar.md +253 -253
  62. package/docs/docs/Rechart/scatter.md +298 -298
  63. package/docs/docs/_404.md +51 -51
  64. package/docs/docs/_coverpage.md +11 -11
  65. package/docs/docs/_sidebar.md +54 -44
  66. package/docs/docs/components/dotBio.md +87 -34
  67. package/docs/docs/components/echart.md +171 -82
  68. package/docs/docs/components/html.md +61 -34
  69. package/docs/docs/components/macaron.md +156 -145
  70. package/docs/docs/components/markdown.md +42 -0
  71. package/docs/docs/components/more.md +183 -142
  72. package/docs/docs/components/plotly.md +132 -62
  73. package/docs/docs/components/scatterL.md +171 -70
  74. package/docs/docs/components/visium.md +112 -57
  75. package/docs/docs/configuration.md +121 -121
  76. package/docs/docs/deploy.md +31 -31
  77. package/docs/docs/docsify-plugin.md +655 -0
  78. package/docs/docs/hmr.md +165 -0
  79. package/docs/docs/i18n.md +332 -0
  80. package/docs/docs/log.md +30 -9
  81. package/docs/docs/more-pages.md +23 -23
  82. package/docs/docs/quickstart.md +148 -124
  83. package/docs/docs/rechart-attributes.md +74 -74
  84. package/docs/docs/rechart-basic-usage.md +160 -162
  85. package/docs/docs/theme.md +5 -5
  86. package/docs/docs/typescript.md +306 -0
  87. package/docs/docs/visual-editor.md +359 -0
  88. package/docs/index.html +85 -71
  89. package/docs/manifest.json +23 -23
  90. package/docs/migration/v3-migration.md +392 -0
  91. package/docs/static/css/fluff-stuff.css +169 -169
  92. package/docs/static/css/font-awesome.min.css +4 -4
  93. package/docs/static/css/visualify.css +6 -25
  94. package/docs/static/js/3d-viz-examples.js +181 -0
  95. package/docs/static/js/configuration.js +630 -448
  96. package/docs/static/js/visualify.js +1 -188
  97. package/package.json +106 -84
  98. package/rollup.config.mjs +766 -76
  99. package/src/_css/404.css +115 -115
  100. package/src/_css/App.css +37 -37
  101. package/src/_css/autoSuggestion.css +26 -26
  102. package/src/_css/circular-progress.css +32 -32
  103. package/src/_css/index.css +36 -36
  104. package/src/_css/modern.css +350 -25
  105. package/src/_media/corner.svg +8 -8
  106. package/src/_media/download.svg +3 -3
  107. package/src/_media/logo.svg +14 -14
  108. package/src/_test/App.test.js +15 -15
  109. package/src/_utils/reportWebVitals.js +13 -13
  110. package/src/a11y/README.md +177 -0
  111. package/src/a11y/aria-labels.js +339 -0
  112. package/src/a11y/color-contrast.js +535 -0
  113. package/src/a11y/index.js +197 -0
  114. package/src/a11y/keyboard-nav.js +523 -0
  115. package/src/a11y/styles.css +165 -0
  116. package/src/cli/commands/dev.js +214 -0
  117. package/src/cli/commands/docs.js +521 -0
  118. package/src/cli/commands/edit.js +379 -0
  119. package/src/cli/commands/init.js +213 -0
  120. package/src/cli/commands/portal.js +236 -0
  121. package/src/cli/dev-server.js +530 -0
  122. package/src/cli/hmr.js +456 -0
  123. package/src/cli/index.js +180 -0
  124. package/src/cli/utils/config.js +207 -0
  125. package/src/cli/utils/logger.js +241 -0
  126. package/src/config/defaults.ts +122 -0
  127. package/src/config/index.ts +72 -0
  128. package/src/config/loader.ts +478 -0
  129. package/src/config/schema.ts +227 -0
  130. package/src/config/validator.ts +337 -0
  131. package/src/core/appContext.js +34 -27
  132. package/src/core/components/Bar.js +383 -0
  133. package/src/core/components/Bar3D.js +473 -0
  134. package/src/core/components/LargeDatasetChart.js +296 -0
  135. package/src/core/components/Line3D.js +310 -0
  136. package/src/core/components/Scatter.js +392 -188
  137. package/src/core/components/Scatter3D.js +455 -0
  138. package/src/core/components/ScatterBio.js +601 -572
  139. package/src/core/components/Surface3D.js +326 -0
  140. package/src/core/components/ThreeCustom.js +648 -0
  141. package/src/core/components/ThreeScene.js +459 -0
  142. package/src/core/components/VisiumPlot.js +191 -165
  143. package/src/core/components/browser.js +42 -42
  144. package/src/core/components/dotplot.js +413 -413
  145. package/src/core/components/html.js +29 -29
  146. package/src/core/components/list.js +178 -178
  147. package/src/core/components/macaron.js +206 -201
  148. package/src/core/components/markdown.js +56 -56
  149. package/src/core/components/parser.scatterBio.js +582 -587
  150. package/src/core/components/ratio.js +82 -80
  151. package/src/core/components/scatterL.js +206 -173
  152. package/src/core/components/searchbar.js +156 -131
  153. package/src/core/components/selection.js +310 -193
  154. package/src/core/components/timeline.js +236 -281
  155. package/src/core/components/visium.js +114 -97
  156. package/src/core/data-processor.js +413 -0
  157. package/src/core/fetch/condfetch.js +82 -82
  158. package/src/core/fetch/fetch.js +92 -92
  159. package/src/core/fetch/json.js +29 -29
  160. package/src/core/fetch/vfetch.js +42 -42
  161. package/src/core/hmr-client.js +724 -0
  162. package/src/core/liveEditor.js +44 -44
  163. package/src/core/modules/codeEditorWithPreview.js +104 -104
  164. package/src/core/modules/echarts/common.js +20 -20
  165. package/src/core/modules/echarts/gl.js +228 -0
  166. package/src/core/modules/echarts/presetHandler.js +41 -41
  167. package/src/core/modules/echarts/presets/esodev.chromium.js +172 -172
  168. package/src/core/modules/echarts/presets/esodev.codex.js +130 -130
  169. package/src/core/modules/echarts/presets/esodev.visium.js +123 -123
  170. package/src/core/modules/echarts/presets/mmtrbc.js +186 -186
  171. package/src/core/modules/echarts.js +70 -71
  172. package/src/core/modules/echartsUtils.js +43 -43
  173. package/src/core/modules/echartswitcher.js +227 -152
  174. package/src/core/modules/replotly/presetHandler.js +24 -24
  175. package/src/core/modules/replotly/presets/minimum.js +18 -18
  176. package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -114
  177. package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -100
  178. package/src/core/modules/replotly.js +74 -71
  179. package/src/core/modules/threejs/Camera.js +373 -0
  180. package/src/core/modules/threejs/Lighting.js +459 -0
  181. package/src/core/modules/threejs/Renderer.js +364 -0
  182. package/src/core/modules/threejs/Scene.js +266 -0
  183. package/src/core/modules/threejs/index.js +155 -0
  184. package/src/core/pages/404.js +50 -50
  185. package/src/core/pages/error.js +27 -27
  186. package/src/core/pages/jsonPage.js +62 -62
  187. package/src/core/pages/loading.js +44 -44
  188. package/src/core/parser/echart.data.js +204 -183
  189. package/src/core/parser/echart.features.js +125 -125
  190. package/src/core/parser/echart.general.js +147 -147
  191. package/src/core/parser/echart.hilbert.js +57 -57
  192. package/src/core/parser/echart.parser.js +210 -210
  193. package/src/core/parser/echart.series.js +67 -67
  194. package/src/core/parser/echart.types.js +76 -76
  195. package/src/core/parser/plotly.config.js +10 -10
  196. package/src/core/parser/plotly.data.js +132 -132
  197. package/src/core/parser/plotly.layout.js +9 -9
  198. package/src/core/parser/plotly.violin.js +18 -18
  199. package/src/core/recharts.js +361 -62
  200. package/src/core/router/alias.js +49 -49
  201. package/src/core/router/jsonRouter.js +31 -31
  202. package/src/core/themes/modern.js +32 -32
  203. package/src/core/themes/themeSelector.js +33 -33
  204. package/src/core/visualify.js +213 -47
  205. package/src/core/widgets/circularProgress.js +23 -23
  206. package/src/core/widgets/controller.js +116 -83
  207. package/src/core/widgets/errorBoundary.js +36 -36
  208. package/src/core/widgets/footer.js +185 -177
  209. package/src/core/widgets/header.js +238 -234
  210. package/src/core/widgets/layout/Grid.js +31 -31
  211. package/src/core/widgets/layout.js +36 -36
  212. package/src/core/widgets/mapping.js +56 -42
  213. package/src/core/workers/data-worker.js +349 -0
  214. package/src/core/workers/worker-pool.js +396 -0
  215. package/src/docsify/bundle.js +215 -0
  216. package/src/docsify/markdown.js +271 -0
  217. package/src/docsify/plugin.js +268 -0
  218. package/src/editor/README.md +172 -0
  219. package/src/editor/components/ChartBuilder.jsx +341 -0
  220. package/src/editor/components/ChartTypeSidebar.jsx +91 -0
  221. package/src/editor/components/Editor.jsx +367 -0
  222. package/src/editor/components/Preview.jsx +446 -0
  223. package/src/editor/components/PropertyPanel.jsx +468 -0
  224. package/src/editor/components/StatusBar.jsx +85 -0
  225. package/src/editor/context/EditorContext.js +248 -0
  226. package/src/editor/hooks/useDebounce.js +32 -0
  227. package/src/editor/index.js +315 -0
  228. package/src/editor/styles/editor.css +637 -0
  229. package/src/editor/utils/chartValidator.js +263 -0
  230. package/src/entries/charts3d.js +70 -0
  231. package/src/entries/core.js +78 -0
  232. package/src/entries/docs.js +154 -0
  233. package/src/entries/pages.js +93 -0
  234. package/src/entries/portal.js +204 -0
  235. package/src/entries/shared.js +50 -0
  236. package/src/i18n/formatters.js +455 -0
  237. package/src/i18n/index.js +169 -0
  238. package/src/i18n/locales/ar.json +137 -0
  239. package/src/i18n/locales/de.json +137 -0
  240. package/src/i18n/locales/en.json +137 -0
  241. package/src/i18n/locales/es.json +137 -0
  242. package/src/i18n/locales/he.json +137 -0
  243. package/src/i18n/locales/zh.json +137 -0
  244. package/src/i18n/rtl.css +183 -0
  245. package/src/index.js +82 -62
  246. package/src/loader.js +103 -0
  247. package/src/setupTests.js +5 -5
  248. package/tsconfig.json +51 -0
  249. package/types/charts.d.ts +569 -0
  250. package/types/components.d.ts +441 -0
  251. package/types/config.d.ts +199 -0
  252. package/types/index.d.ts +353 -0
@@ -0,0 +1,367 @@
1
+
2
+ /**
3
+ * @fileoverview Main Editor UI Component
4
+ * @module editor/components/Editor
5
+ *
6
+ * Provides the main layout with toolbar, sidebar, canvas, and property panel.
7
+ */
8
+
9
+ import React, { useState, useCallback, useEffect } from 'react';
10
+ import {
11
+ Navbar,
12
+ Container,
13
+ Button,
14
+ ButtonGroup,
15
+ Modal,
16
+ Form,
17
+ } from 'react-bootstrap';
18
+ import {
19
+ Plus,
20
+ FolderOpen,
21
+ Download,
22
+ Undo,
23
+ Redo,
24
+ Trash2,
25
+ Eye,
26
+ Code,
27
+ } from 'react-bootstrap-icons';
28
+ import { useEditor } from '../context/EditorContext';
29
+ import ChartBuilder from './ChartBuilder';
30
+ import PropertyPanel from './PropertyPanel';
31
+ import Preview from './Preview';
32
+ import ChartTypeSidebar from './ChartTypeSidebar';
33
+ import StatusBar from './StatusBar';
34
+
35
+ /**
36
+ * Main Editor Component
37
+ */
38
+ function Editor() {
39
+ const {
40
+ state,
41
+ setConfig,
42
+ undo,
43
+ redo,
44
+ canUndo,
45
+ canRedo,
46
+ selectedChart,
47
+ setSelectedChart,
48
+ clearAll,
49
+ } = useEditor();
50
+
51
+ const [showPreview, setShowPreview] = useState(false);
52
+ const [showJsonModal, setShowJsonModal] = useState(false);
53
+ const [jsonContent, setJsonContent] = useState('');
54
+ const [importError, setImportError] = useState(null);
55
+ const [lastSaved, setLastSaved] = useState(null);
56
+
57
+ const { config } = state;
58
+
59
+ // Keyboard shortcuts
60
+ useEffect(() => {
61
+ const handleKeyDown = (e) => {
62
+ // Ctrl/Cmd + Z - Undo
63
+ if ((e.ctrlKey || e.metaKey) && e.key === 'z' && !e.shiftKey) {
64
+ e.preventDefault();
65
+ if (canUndo) undo();
66
+ }
67
+
68
+ // Ctrl/Cmd + Y or Ctrl/Cmd + Shift + Z - Redo
69
+ if (
70
+ (e.ctrlKey || e.metaKey) &&
71
+ (e.key === 'y' || (e.key === 'z' && e.shiftKey))
72
+ ) {
73
+ e.preventDefault();
74
+ if (canRedo) redo();
75
+ }
76
+
77
+ // Ctrl/Cmd + S - Save/Export
78
+ if ((e.ctrlKey || e.metaKey) && e.key === 's') {
79
+ e.preventDefault();
80
+ handleExport();
81
+ }
82
+
83
+ // Escape - Close modals
84
+ if (e.key === 'Escape') {
85
+ setShowPreview(false);
86
+ setShowJsonModal(false);
87
+ }
88
+ };
89
+
90
+ window.addEventListener('keydown', handleKeyDown);
91
+ return () => window.removeEventListener('keydown', handleKeyDown);
92
+ }, [canUndo, canRedo, undo, redo]);
93
+
94
+ // Handle file import
95
+ const handleImport = useCallback(() => {
96
+ const input = document.createElement('input');
97
+ input.type = 'file';
98
+ input.accept = '.json';
99
+ input.onchange = (e) => {
100
+ const file = e.target.files[0];
101
+ if (file) {
102
+ const reader = new FileReader();
103
+ reader.onload = (event) => {
104
+ try {
105
+ const imported = JSON.parse(event.target.result);
106
+ setConfig(imported);
107
+ setLastSaved(new Date());
108
+ } catch (error) {
109
+ alert(`Import failed: ${error.message}`);
110
+ }
111
+ };
112
+ reader.readAsText(file);
113
+ }
114
+ };
115
+ input.click();
116
+ }, [setConfig]);
117
+
118
+ // Handle export
119
+ const handleExport = useCallback(() => {
120
+ try {
121
+ const exportData = {
122
+ ...config,
123
+ charts: config.charts.map((chart) => {
124
+ const { id, ...rest } = chart;
125
+ return rest;
126
+ }),
127
+ };
128
+
129
+ const json = JSON.stringify(exportData, null, 2);
130
+ const blob = new Blob([json], { type: 'application/json' });
131
+ const url = URL.createObjectURL(blob);
132
+
133
+ const link = document.createElement('a');
134
+ link.href = url;
135
+ link.download = 'visualify.json';
136
+ document.body.appendChild(link);
137
+ link.click();
138
+ document.body.removeChild(link);
139
+ URL.revokeObjectURL(url);
140
+
141
+ setLastSaved(new Date());
142
+ } catch (error) {
143
+ alert(`Export failed: ${error.message}`);
144
+ }
145
+ }, [config]);
146
+
147
+ // Handle show JSON
148
+ const handleShowJson = useCallback(() => {
149
+ const exportData = {
150
+ ...config,
151
+ charts: config.charts.map((chart) => {
152
+ const { id, ...rest } = chart;
153
+ return rest;
154
+ }),
155
+ };
156
+ setJsonContent(JSON.stringify(exportData, null, 2));
157
+ setShowJsonModal(true);
158
+ }, [config]);
159
+
160
+ // Handle JSON import from modal
161
+ const handleJsonImport = useCallback(() => {
162
+ try {
163
+ const imported = JSON.parse(jsonContent);
164
+ setConfig(imported);
165
+ setImportError(null);
166
+ setShowJsonModal(false);
167
+ setLastSaved(new Date());
168
+ } catch (error) {
169
+ setImportError(error.message);
170
+ }
171
+ }, [jsonContent, setConfig]);
172
+
173
+ // Handle new config
174
+ const handleNew = useCallback(() => {
175
+ if (
176
+ config.charts.length > 0 &&
177
+ !window.confirm(
178
+ 'Are you sure you want to create a new configuration? Unsaved changes will be lost.',
179
+ )
180
+ ) {
181
+ return;
182
+ }
183
+ setConfig({
184
+ version: '3.0.0',
185
+ charts: [],
186
+ layout: { type: 'grid', rows: 1, cols: 1, gap: '10px' },
187
+ theme: 'modern',
188
+ });
189
+ setSelectedChart(null);
190
+ }, [config.charts.length, setConfig, setSelectedChart]);
191
+
192
+ return (
193
+ <div className='visualify-editor'>
194
+ {/* Toolbar */}
195
+ <Navbar className='editor-toolbar' bg='light' expand='lg'>
196
+ <Container fluid>
197
+ <Navbar.Brand className='editor-toolbar-title'>
198
+ Visualify Editor
199
+ </Navbar.Brand>
200
+
201
+ <div className='d-flex align-items-center gap-2'>
202
+ <ButtonGroup>
203
+ <Button
204
+ variant='outline-primary'
205
+ size='sm'
206
+ onClick={handleNew}
207
+ title='New Configuration (Ctrl+N)'>
208
+ <Plus className='me-1' />
209
+ New
210
+ </Button>
211
+ <Button
212
+ variant='outline-secondary'
213
+ size='sm'
214
+ onClick={handleImport}
215
+ title='Import JSON (Ctrl+O)'>
216
+ <FolderOpen className='me-1' />
217
+ Open
218
+ </Button>
219
+ <Button
220
+ variant='outline-success'
221
+ size='sm'
222
+ onClick={handleExport}
223
+ title='Export JSON (Ctrl+S)'>
224
+ <Download className='me-1' />
225
+ Export
226
+ </Button>
227
+ </ButtonGroup>
228
+
229
+ <div className='vr mx-2' />
230
+
231
+ <ButtonGroup>
232
+ <Button
233
+ variant='outline-secondary'
234
+ size='sm'
235
+ onClick={undo}
236
+ disabled={!canUndo}
237
+ title='Undo (Ctrl+Z)'>
238
+ <Undo />
239
+ </Button>
240
+ <Button
241
+ variant='outline-secondary'
242
+ size='sm'
243
+ onClick={redo}
244
+ disabled={!canRedo}
245
+ title='Redo (Ctrl+Y)'>
246
+ <Redo />
247
+ </Button>
248
+ </ButtonGroup>
249
+
250
+ <div className='vr mx-2' />
251
+
252
+ <ButtonGroup>
253
+ <Button
254
+ variant='outline-info'
255
+ size='sm'
256
+ onClick={() => setShowPreview(true)}
257
+ title='Preview'>
258
+ <Eye className='me-1' />
259
+ Preview
260
+ </Button>
261
+ <Button
262
+ variant='outline-dark'
263
+ size='sm'
264
+ onClick={handleShowJson}
265
+ title='View/Edit JSON'>
266
+ <Code className='me-1' />
267
+ JSON
268
+ </Button>
269
+ </ButtonGroup>
270
+
271
+ <div className='vr mx-2' />
272
+
273
+ <Button
274
+ variant='outline-danger'
275
+ size='sm'
276
+ onClick={clearAll}
277
+ disabled={config.charts.length === 0}
278
+ title='Clear All'>
279
+ <Trash2 />
280
+ </Button>
281
+ </div>
282
+ </Container>
283
+ </Navbar>
284
+
285
+ {/* Main Content */}
286
+ <div className='editor-main'>
287
+ {/* Sidebar - Chart Types */}
288
+ <ChartTypeSidebar />
289
+
290
+ {/* Canvas */}
291
+ <ChartBuilder />
292
+
293
+ {/* Property Panel */}
294
+ <PropertyPanel />
295
+ </div>
296
+
297
+ {/* Status Bar */}
298
+ <StatusBar
299
+ chartCount={config.charts.length}
300
+ lastSaved={lastSaved}
301
+ selectedChart={selectedChart}
302
+ />
303
+
304
+ {/* Preview Modal */}
305
+ <Modal
306
+ show={showPreview}
307
+ onHide={() => setShowPreview(false)}
308
+ size='xl'
309
+ fullscreen='lg-down'
310
+ className='editor-modal'>
311
+ <Modal.Header closeButton>
312
+ <Modal.Title>Preview</Modal.Title>
313
+ </Modal.Header>
314
+ <Modal.Body className='p-0'>
315
+ <Preview config={config} fullscreen />
316
+ </Modal.Body>
317
+ <Modal.Footer>
318
+ <Button
319
+ variant='secondary'
320
+ onClick={() => setShowPreview(false)}>
321
+ Close
322
+ </Button>
323
+ </Modal.Footer>
324
+ </Modal>
325
+
326
+ {/* JSON Modal */}
327
+ <Modal
328
+ show={showJsonModal}
329
+ onHide={() => setShowJsonModal(false)}
330
+ size='lg'
331
+ className='editor-modal'>
332
+ <Modal.Header closeButton>
333
+ <Modal.Title>Configuration JSON</Modal.Title>
334
+ </Modal.Header>
335
+ <Modal.Body>
336
+ {importError && (
337
+ <div className='alert alert-danger'>{importError}</div>
338
+ )}
339
+ <Form.Group>
340
+ <Form.Control
341
+ as='textarea'
342
+ value={jsonContent}
343
+ onChange={(e) => setJsonContent(e.target.value)}
344
+ style={{
345
+ fontFamily: 'monospace',
346
+ minHeight: '400px',
347
+ fontSize: '0.875rem',
348
+ }}
349
+ />
350
+ </Form.Group>
351
+ </Modal.Body>
352
+ <Modal.Footer>
353
+ <Button
354
+ variant='secondary'
355
+ onClick={() => setShowJsonModal(false)}>
356
+ Cancel
357
+ </Button>
358
+ <Button variant='primary' onClick={handleJsonImport}>
359
+ Import JSON
360
+ </Button>
361
+ </Modal.Footer>
362
+ </Modal>
363
+ </div>
364
+ );
365
+ }
366
+
367
+ export default Editor;