velo-plot 2.20.0 → 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 (236) hide show
  1. package/README.md +15 -8
  2. package/dist/{ChartCore-ivzLqxVb.js → ChartCore-BpzRvN4Y.js} +978 -861
  3. package/dist/ChartCore-BpzRvN4Y.js.map +1 -0
  4. package/dist/a11y-Bw6urYpr.js +105 -0
  5. package/dist/a11y-Bw6urYpr.js.map +1 -0
  6. package/dist/angular/hooks-entry.d.ts +1 -0
  7. package/dist/angular/hooks.d.ts +26 -0
  8. package/dist/angular/index.d.ts +8 -0
  9. package/dist/angular/velo-plot.component.d.ts +46 -0
  10. package/dist/angular-hooks.d.ts +1 -0
  11. package/dist/angular-hooks.js +9 -0
  12. package/dist/angular-hooks.js.map +1 -0
  13. package/dist/angular.d.ts +1 -0
  14. package/dist/angular.js +166 -0
  15. package/dist/angular.js.map +1 -0
  16. package/dist/assets/indicator.worker-bv0zC4EX.js.map +1 -1
  17. package/dist/astro/StackedPlot.astro +19 -0
  18. package/dist/astro/VeloPlot.astro +23 -0
  19. package/dist/bindings/shared/a11y.d.ts +26 -0
  20. package/dist/bindings/shared/chartLifecycle.d.ts +16 -0
  21. package/dist/bindings/shared/chartSyncBridge.d.ts +8 -0
  22. package/dist/bindings/shared/dimensions.d.ts +1 -0
  23. package/dist/bindings/shared/index.d.ts +9 -0
  24. package/dist/bindings/shared/indicatorBridge.d.ts +11 -0
  25. package/dist/bindings/shared/optionsSync.d.ts +7 -0
  26. package/dist/bindings/shared/seriesDiff.d.ts +8 -0
  27. package/dist/bindings/shared/stackedSync.d.ts +9 -0
  28. package/dist/bindings/shared/types.d.ts +46 -0
  29. package/dist/bindings/test-utils/index.d.ts +35 -0
  30. package/dist/bindings/test-utils/mockLifecycle.d.ts +120 -0
  31. package/dist/bindings/test-utils/vitestSveltePlugin.d.ts +3 -0
  32. package/dist/chartSyncBridge-DbWrwtyP.js +57 -0
  33. package/dist/chartSyncBridge-DbWrwtyP.js.map +1 -0
  34. package/dist/core/Chart.d.ts +1 -1
  35. package/dist/core/InteractionManager.d.ts +7 -1
  36. package/dist/core/OverlayRenderer.d.ts +5 -0
  37. package/dist/core/annotations/types.d.ts +1 -1
  38. package/dist/core/chart/ChartCore.d.ts +2 -2
  39. package/dist/core/chart/types.d.ts +1 -1
  40. package/dist/core/clipboard/index.d.ts +1 -1
  41. package/dist/core/debug/index.d.ts +1 -1
  42. package/dist/core/keybindings/index.d.ts +1 -1
  43. package/dist/core/loading/index.d.ts +1 -1
  44. package/dist/core/locale/index.d.ts +1 -1
  45. package/dist/core/stacked/paneResize.d.ts +3 -0
  46. package/dist/core/stacked/types.d.ts +10 -0
  47. package/dist/core/theme-editor/index.d.ts +1 -1
  48. package/dist/createStackedChart-Dm-YqUT7.js +756 -0
  49. package/dist/createStackedChart-Dm-YqUT7.js.map +1 -0
  50. package/dist/examples/PluginDemonstration.d.ts +1 -1
  51. package/dist/gpuRenderer-BpaMYz-k.js.map +1 -1
  52. package/dist/hooks-CYPCxoZx.js +69 -0
  53. package/dist/hooks-CYPCxoZx.js.map +1 -0
  54. package/dist/{index-BBpJwOct.js → index-0InEyj0q.js} +119 -121
  55. package/dist/index-0InEyj0q.js.map +1 -0
  56. package/dist/index-BMiZoKmm.js.map +1 -1
  57. package/dist/{index-DoYxf1cV.js → index-CWxIHdwX.js} +38 -98
  58. package/dist/index-CWxIHdwX.js.map +1 -0
  59. package/dist/index-CaXWSOTk.js.map +1 -1
  60. package/dist/index-Dag88bW4.js.map +1 -1
  61. package/dist/index-qhscKTDy.js.map +1 -1
  62. package/dist/index-qunX30Xu.js.map +1 -1
  63. package/dist/index-x4stH3jD.js.map +1 -1
  64. package/dist/{index.core-COREBDNq.js → index.core-BmZe2jRQ.js} +9 -9
  65. package/dist/index.core-BmZe2jRQ.js.map +1 -0
  66. package/dist/index.core.d.ts +1 -1
  67. package/dist/index.d.ts +2 -2
  68. package/dist/indicators--eJGmVox.js.map +1 -1
  69. package/dist/{mockDatafeed-927foCM4.js → mockDatafeed-DHIDPcpX.js} +150 -146
  70. package/dist/mockDatafeed-DHIDPcpX.js.map +1 -0
  71. package/dist/optionsSync-QUiN4Inw.js +119 -0
  72. package/dist/optionsSync-QUiN4Inw.js.map +1 -0
  73. package/dist/plugins/3d/index.d.ts +2 -2
  74. package/dist/plugins/3d.d.ts +2 -2
  75. package/dist/plugins/3d.js.map +1 -1
  76. package/dist/plugins/analysis/index.d.ts +1 -1
  77. package/dist/plugins/analysis/indicators.d.ts +1 -1
  78. package/dist/plugins/analysis.d.ts +2 -2
  79. package/dist/plugins/analysis.js +2 -2
  80. package/dist/plugins/analysis.js.map +1 -1
  81. package/dist/plugins/annotations/index.d.ts +1 -1
  82. package/dist/plugins/annotations.d.ts +2 -2
  83. package/dist/plugins/annotations.js.map +1 -1
  84. package/dist/plugins/anomaly-detection.js +1 -1
  85. package/dist/plugins/anomaly-detection.js.map +1 -1
  86. package/dist/plugins/broken-axis.d.ts +2 -2
  87. package/dist/plugins/builtins/crosshair/CrosshairPlugin.d.ts +1 -1
  88. package/dist/plugins/builtins/index.d.ts +1 -1
  89. package/dist/plugins/caching.d.ts +2 -2
  90. package/dist/plugins/clipboard/index.d.ts +2 -2
  91. package/dist/plugins/clipboard.d.ts +2 -2
  92. package/dist/plugins/clipboard.js.map +1 -1
  93. package/dist/plugins/context-menu/index.d.ts +1 -1
  94. package/dist/plugins/context-menu.d.ts +2 -2
  95. package/dist/plugins/context-menu.js +1 -1
  96. package/dist/plugins/context-menu.js.map +1 -1
  97. package/dist/plugins/data-export/index.d.ts +1 -1
  98. package/dist/plugins/data-export.d.ts +2 -2
  99. package/dist/plugins/data-export.js +2 -2
  100. package/dist/plugins/data-export.js.map +1 -1
  101. package/dist/plugins/data-transform.d.ts +2 -2
  102. package/dist/plugins/data-transform.js +19 -19
  103. package/dist/plugins/data-transform.js.map +1 -1
  104. package/dist/plugins/debug/index.d.ts +2 -2
  105. package/dist/plugins/debug.d.ts +2 -2
  106. package/dist/plugins/debug.js +2 -2
  107. package/dist/plugins/debug.js.map +1 -1
  108. package/dist/plugins/forecasting/index.d.ts +1 -1
  109. package/dist/plugins/forecasting.js.map +1 -1
  110. package/dist/plugins/gpu/index.d.ts +2 -2
  111. package/dist/plugins/gpu.d.ts +2 -2
  112. package/dist/plugins/gpu.js.map +1 -1
  113. package/dist/plugins/i18n/index.d.ts +2 -2
  114. package/dist/plugins/i18n.d.ts +2 -2
  115. package/dist/plugins/i18n.js.map +1 -1
  116. package/dist/plugins/index.d.ts +1 -1
  117. package/dist/plugins/keyboard.d.ts +2 -2
  118. package/dist/plugins/keyboard.js +65 -5
  119. package/dist/plugins/keyboard.js.map +1 -1
  120. package/dist/plugins/latex.js.map +1 -1
  121. package/dist/plugins/lazy-load.d.ts +2 -2
  122. package/dist/plugins/loading/index.d.ts +1 -1
  123. package/dist/plugins/loading.d.ts +2 -2
  124. package/dist/plugins/ml-integration.d.ts +2 -2
  125. package/dist/plugins/ml-integration.js +5 -5
  126. package/dist/plugins/ml-integration.js.map +1 -1
  127. package/dist/plugins/offscreen.d.ts +2 -2
  128. package/dist/plugins/pattern-recognition.d.ts +2 -2
  129. package/dist/plugins/pattern-recognition.js +1 -1
  130. package/dist/plugins/pattern-recognition.js.map +1 -1
  131. package/dist/plugins/radar.d.ts +2 -2
  132. package/dist/plugins/regression.d.ts +2 -2
  133. package/dist/plugins/regression.js +1 -1
  134. package/dist/plugins/regression.js.map +1 -1
  135. package/dist/plugins/roi.js +9 -9
  136. package/dist/plugins/roi.js.map +1 -1
  137. package/dist/plugins/snapshot/index.d.ts +1 -1
  138. package/dist/plugins/snapshot/types.d.ts +1 -1
  139. package/dist/plugins/snapshot.d.ts +2 -2
  140. package/dist/plugins/snapshot.js.map +1 -1
  141. package/dist/plugins/streaming/index.d.ts +2 -2
  142. package/dist/plugins/streaming.d.ts +2 -2
  143. package/dist/plugins/sync/index.d.ts +3 -2
  144. package/dist/plugins/sync.d.ts +2 -2
  145. package/dist/plugins/sync.js.map +1 -1
  146. package/dist/plugins/theme-editor/index.d.ts +1 -1
  147. package/dist/plugins/theme-editor.d.ts +2 -2
  148. package/dist/plugins/tools/index.d.ts +1 -1
  149. package/dist/plugins/tools/tooltip/index.d.ts +1 -1
  150. package/dist/plugins/tools.d.ts +2 -2
  151. package/dist/plugins/types.d.ts +1 -1
  152. package/dist/plugins/video-recorder.d.ts +2 -2
  153. package/dist/plugins/virtualization.d.ts +2 -2
  154. package/dist/plugins/virtualization.js +1 -1
  155. package/dist/pool-DZ8shSqv.js +109 -0
  156. package/dist/pool-DZ8shSqv.js.map +1 -0
  157. package/dist/react/StackedPlot.d.ts +31 -0
  158. package/dist/react/VeloPlot.d.ts +29 -0
  159. package/dist/react/index.d.ts +25 -3
  160. package/dist/react/useChartSync.d.ts +8 -0
  161. package/dist/react/useIndicator.d.ts +12 -0
  162. package/dist/react/useVeloPlot.d.ts +19 -0
  163. package/dist/react.js +328 -24
  164. package/dist/react.js.map +1 -1
  165. package/dist/scientific/index.d.ts +48 -0
  166. package/dist/scientific.d.ts +1 -0
  167. package/dist/scientific.js +91 -0
  168. package/dist/scientific.js.map +1 -0
  169. package/dist/solid/VeloPlot.d.ts +16 -0
  170. package/dist/solid/index.d.ts +13 -0
  171. package/dist/solid/useChartSync.d.ts +6 -0
  172. package/dist/solid/useIndicator.d.ts +11 -0
  173. package/dist/solid/useStackedPlot.d.ts +14 -0
  174. package/dist/solid/useVeloPlot.d.ts +18 -0
  175. package/dist/solid.d.ts +1 -0
  176. package/dist/solid.js +172 -0
  177. package/dist/solid.js.map +1 -0
  178. package/dist/stackedSync-tnrunZMt.js +100 -0
  179. package/dist/stackedSync-tnrunZMt.js.map +1 -0
  180. package/dist/svelte/StackedPlot.svelte +29 -0
  181. package/dist/svelte/StackedPlot.test.ts +114 -0
  182. package/dist/svelte/VeloPlot.svelte +44 -0
  183. package/dist/svelte/VeloPlot.test.ts +105 -0
  184. package/dist/svelte/index.d.ts +11 -0
  185. package/dist/svelte/index.test.ts +20 -0
  186. package/dist/svelte/index.ts +15 -0
  187. package/dist/svelte/useChartSync.d.ts +8 -0
  188. package/dist/svelte/useChartSync.test.ts +49 -0
  189. package/dist/svelte/useChartSync.ts +29 -0
  190. package/dist/svelte/useIndicator.d.ts +13 -0
  191. package/dist/svelte/useIndicator.test.ts +67 -0
  192. package/dist/svelte/useIndicator.ts +43 -0
  193. package/dist/svelte/useStackedPlot.d.ts +16 -0
  194. package/dist/svelte/useStackedPlot.test.ts +76 -0
  195. package/dist/svelte/useStackedPlot.ts +54 -0
  196. package/dist/svelte/useVeloPlot.d.ts +21 -0
  197. package/dist/svelte/useVeloPlot.test.ts +100 -0
  198. package/dist/svelte/useVeloPlot.ts +81 -0
  199. package/dist/svelte.d.ts +1 -0
  200. package/dist/svelte.js +143 -0
  201. package/dist/svelte.js.map +1 -0
  202. package/dist/testing/index.d.ts +1 -1
  203. package/dist/theme/index.d.ts +2 -1
  204. package/dist/trading.js +6 -6
  205. package/dist/types.d.ts +1 -1
  206. package/dist/{utils-BK5UUXxj.js → utils-Dx0h0bgQ.js} +9 -9
  207. package/dist/{utils-BK5UUXxj.js.map → utils-Dx0h0bgQ.js.map} +1 -1
  208. package/dist/velo-plot.full.js +452 -443
  209. package/dist/velo-plot.full.js.map +1 -1
  210. package/dist/velo-plot.js +15 -15
  211. package/dist/vue/StackedPlot.vue.d.ts +48 -0
  212. package/dist/vue/VeloPlot.vue.d.ts +64 -0
  213. package/dist/vue/index.d.ts +250 -0
  214. package/dist/vue/useChartSync.d.ts +52 -0
  215. package/dist/vue/useIndicator.d.ts +23 -0
  216. package/dist/vue/useStackedPlot.d.ts +15 -0
  217. package/dist/vue/useVeloPlot.d.ts +20 -0
  218. package/dist/vue.d.ts +1 -0
  219. package/dist/vue.js +312 -0
  220. package/dist/vue.js.map +1 -0
  221. package/dist/workers/indicatorsAsync.d.ts +2 -0
  222. package/dist/workers/pool.d.ts +9 -0
  223. package/package.json +88 -10
  224. package/dist/ChartCore-ivzLqxVb.js.map +0 -1
  225. package/dist/SciPlot-CEU4ApgD.js +0 -463
  226. package/dist/SciPlot-CEU4ApgD.js.map +0 -1
  227. package/dist/createStackedChart-DxNW0VkF.js +0 -705
  228. package/dist/createStackedChart-DxNW0VkF.js.map +0 -1
  229. package/dist/index-BBpJwOct.js.map +0 -1
  230. package/dist/index-DoYxf1cV.js.map +0 -1
  231. package/dist/index.core-COREBDNq.js.map +0 -1
  232. package/dist/mockDatafeed-927foCM4.js.map +0 -1
  233. package/dist/pool-15HMCNv8.js +0 -88
  234. package/dist/pool-15HMCNv8.js.map +0 -1
  235. package/dist/react/SciPlot.d.ts +0 -60
  236. package/dist/react/useSciPlot.d.ts +0 -56
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-CWxIHdwX.js","sources":["../src/core/keybindings/index.ts"],"sourcesContent":["/**\n * Velo Plot - Keyboard Shortcuts Module\n * \n * Provides customizable keyboard shortcuts for chart interactions.\n * Supports key combinations, custom actions, and enable/disable per key.\n * \n * @module keybindings\n */\n\n// ============================================\n// Types\n// ============================================\n\n/** Available built-in actions */\nexport type KeyAction =\n | 'resetZoom'\n | 'autoScale'\n | 'zoomIn'\n | 'zoomOut'\n | 'panLeft'\n | 'panRight'\n | 'panUp'\n | 'panDown'\n | 'togglePan'\n | 'toggleSelect'\n | 'clearSelection'\n | 'deleteSelected'\n | 'selectAll'\n | 'copy'\n | 'exportImage'\n | 'toggleLegend'\n | 'toggleDebug'\n | 'escape'\n | 'undo'\n | 'redo'\n | 'custom';\n\n/** Key binding configuration */\nexport interface KeyBinding {\n /** The key code (e.g., 'KeyR', 'Escape', 'ArrowLeft') */\n key: string;\n /** Action to perform */\n action: KeyAction;\n /** Require Ctrl/Cmd key */\n ctrl?: boolean;\n /** Require Shift key */\n shift?: boolean;\n /** Require Alt key */\n alt?: boolean;\n /** Require Meta key (Cmd on Mac) */\n meta?: boolean;\n /** Custom handler function (required if action is 'custom') */\n handler?: () => void;\n /** Whether this binding is enabled (default: true) */\n enabled?: boolean;\n /** Description for help/UI display */\n description?: string;\n}\n\n/** Callbacks for keyboard actions */\nexport interface KeyBindingCallbacks {\n onResetZoom?: () => void;\n onAutoScale?: () => void;\n onZoomIn?: () => void;\n onZoomOut?: () => void;\n onPanLeft?: () => void;\n onPanRight?: () => void;\n onPanUp?: () => void;\n onPanDown?: () => void;\n onTogglePan?: () => void;\n onToggleSelect?: () => void;\n onClearSelection?: () => void;\n onDeleteSelected?: () => void;\n onSelectAll?: () => void;\n onCopy?: () => void;\n onExportImage?: () => void;\n onToggleLegend?: () => void;\n onToggleDebug?: () => void;\n onEscape?: () => void;\n onUndo?: () => void;\n onRedo?: () => void;\n}\n\nexport interface KeyBindingManagerOptions {\n /** Enable keyboard shortcuts (default: true) */\n enabled?: boolean;\n /** Custom key bindings (merged with defaults) */\n bindings?: KeyBinding[];\n /** Override all default bindings (replace instead of merge) */\n replaceDefaults?: boolean;\n /** Callbacks for built-in actions */\n callbacks: KeyBindingCallbacks;\n /** Target element for keyboard events (default: document) */\n target?: HTMLElement | Document;\n /** Prevent default browser behavior for matched keys (default: true) */\n preventDefault?: boolean;\n}\n\n// ============================================\n// Default Key Bindings\n// ============================================\n\nexport const DEFAULT_KEY_BINDINGS: KeyBinding[] = [\n // Zoom/Scale\n { key: 'KeyR', action: 'resetZoom', description: 'Reset zoom to fit data' },\n { key: 'KeyH', action: 'autoScale', description: 'Auto-scale axes' },\n { key: 'Equal', action: 'zoomIn', ctrl: true, description: 'Zoom in' },\n { key: 'Minus', action: 'zoomOut', ctrl: true, description: 'Zoom out' },\n { key: 'Digit0', action: 'resetZoom', ctrl: true, description: 'Reset zoom' },\n \n // Pan (Arrow keys)\n { key: 'ArrowLeft', action: 'panLeft', description: 'Pan left' },\n { key: 'ArrowRight', action: 'panRight', description: 'Pan right' },\n { key: 'ArrowUp', action: 'panUp', description: 'Pan up' },\n { key: 'ArrowDown', action: 'panDown', description: 'Pan down' },\n \n // Mode toggles\n { key: 'KeyP', action: 'togglePan', description: 'Toggle pan mode' },\n { key: 'KeyS', action: 'toggleSelect', description: 'Toggle select mode' },\n \n // Selection\n { key: 'Escape', action: 'escape', description: 'Clear selection / Cancel' },\n { key: 'Delete', action: 'deleteSelected', description: 'Delete selected points' },\n { key: 'Backspace', action: 'deleteSelected', description: 'Delete selected points' },\n { key: 'KeyA', action: 'selectAll', ctrl: true, description: 'Select all points' },\n \n // Clipboard\n { key: 'KeyC', action: 'copy', ctrl: true, description: 'Copy selected to clipboard' },\n \n // Export\n { key: 'KeyE', action: 'exportImage', ctrl: true, description: 'Export chart as image' },\n \n // UI toggles\n { key: 'KeyL', action: 'toggleLegend', description: 'Toggle legend visibility' },\n { key: 'KeyD', action: 'toggleDebug', ctrl: true, shift: true, description: 'Toggle debug overlay' },\n \n // Undo/Redo\n { key: 'KeyZ', action: 'undo', ctrl: true, description: 'Undo' },\n { key: 'KeyZ', action: 'redo', ctrl: true, shift: true, description: 'Redo' },\n { key: 'KeyY', action: 'redo', ctrl: true, description: 'Redo' },\n];\n\n// ============================================\n// Key Binding Manager\n// ============================================\n\nexport class KeyBindingManager {\n private bindings: KeyBinding[] = [];\n private callbacks: KeyBindingCallbacks;\n private target: HTMLElement | Document;\n private enabled: boolean = true;\n private preventDefault: boolean = true;\n private boundHandler: (e: KeyboardEvent) => void;\n\n constructor(options: KeyBindingManagerOptions) {\n this.callbacks = options.callbacks;\n this.target = options.target || document;\n this.enabled = options.enabled !== false;\n this.preventDefault = options.preventDefault !== false;\n\n // Merge or replace bindings\n if (options.replaceDefaults) {\n this.bindings = [...(options.bindings || [])];\n } else {\n this.bindings = [...DEFAULT_KEY_BINDINGS, ...(options.bindings || [])];\n }\n\n // Bind handler\n this.boundHandler = this.handleKeyDown.bind(this);\n this.attach();\n }\n\n /**\n * Attach keyboard event listeners\n */\n attach(): void {\n this.target.addEventListener('keydown', this.boundHandler as EventListener);\n }\n\n /**\n * Detach keyboard event listeners\n */\n detach(): void {\n this.target.removeEventListener('keydown', this.boundHandler as EventListener);\n }\n\n /**\n * Enable/disable all keyboard shortcuts\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n\n /**\n * Check if keyboard shortcuts are enabled\n */\n isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Add a custom key binding\n */\n addBinding(binding: KeyBinding): void {\n this.bindings.push(binding);\n }\n\n /**\n * Remove a key binding by key code\n */\n removeBinding(key: string, modifiers?: { ctrl?: boolean; shift?: boolean; alt?: boolean }): void {\n this.bindings = this.bindings.filter(b => {\n if (b.key !== key) return true;\n if (modifiers) {\n if (modifiers.ctrl !== undefined && b.ctrl !== modifiers.ctrl) return true;\n if (modifiers.shift !== undefined && b.shift !== modifiers.shift) return true;\n if (modifiers.alt !== undefined && b.alt !== modifiers.alt) return true;\n }\n return false;\n });\n }\n\n /**\n * Update an existing binding\n */\n updateBinding(key: string, updates: Partial<KeyBinding>): void {\n const binding = this.bindings.find(b => b.key === key);\n if (binding) {\n Object.assign(binding, updates);\n }\n }\n\n /**\n * Enable/disable a specific binding\n */\n setBindingEnabled(key: string, enabled: boolean): void {\n const binding = this.bindings.find(b => b.key === key);\n if (binding) {\n binding.enabled = enabled;\n }\n }\n\n /**\n * Get all current bindings\n */\n getBindings(): KeyBinding[] {\n return [...this.bindings];\n }\n\n /**\n * Get binding for a specific key\n */\n getBinding(key: string): KeyBinding | undefined {\n return this.bindings.find(b => b.key === key);\n }\n\n /**\n * Get a formatted list of all shortcuts (for help display)\n */\n getShortcutList(): { key: string; description: string }[] {\n return this.bindings\n .filter(b => b.enabled !== false && b.description)\n .map(b => ({\n key: this.formatKeyBinding(b),\n description: b.description || b.action,\n }));\n }\n\n /**\n * Format a key binding for display\n */\n formatKeyBinding(binding: KeyBinding): string {\n const parts: string[] = [];\n if (binding.ctrl) parts.push('Ctrl');\n if (binding.alt) parts.push('Alt');\n if (binding.shift) parts.push('Shift');\n if (binding.meta) parts.push('⌘');\n \n // Convert key code to display name\n let keyName = binding.key;\n if (keyName.startsWith('Key')) {\n keyName = keyName.slice(3);\n } else if (keyName.startsWith('Digit')) {\n keyName = keyName.slice(5);\n } else if (keyName === 'Equal') {\n keyName = '+';\n } else if (keyName === 'Minus') {\n keyName = '-';\n } else if (keyName.startsWith('Arrow')) {\n keyName = '←→↑↓'['LeftRightUpDown'.indexOf(keyName.slice(5)) / 5 | 0] || keyName;\n }\n \n parts.push(keyName);\n return parts.join('+');\n }\n\n /**\n * Handle keydown events\n */\n private handleKeyDown(e: KeyboardEvent): void {\n if (!this.enabled) return;\n\n // Skip if typing in an input element\n const target = e.target as HTMLElement;\n if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {\n return;\n }\n\n // Find matching binding\n const binding = this.findMatchingBinding(e);\n if (!binding || binding.enabled === false) return;\n\n // Execute action\n const executed = this.executeAction(binding);\n \n if (executed && this.preventDefault) {\n e.preventDefault();\n e.stopPropagation();\n }\n }\n\n /**\n * Find a binding that matches the current key event\n */\n private findMatchingBinding(e: KeyboardEvent): KeyBinding | undefined {\n return this.bindings.find(b => {\n if (b.key !== e.code) return false;\n if (b.ctrl && !e.ctrlKey && !e.metaKey) return false;\n if (b.shift && !e.shiftKey) return false;\n if (b.alt && !e.altKey) return false;\n if (b.meta && !e.metaKey) return false;\n \n // Also check that extra modifiers aren't pressed\n if (!b.ctrl && (e.ctrlKey || e.metaKey)) return false;\n if (!b.shift && e.shiftKey) return false;\n if (!b.alt && e.altKey) return false;\n \n return true;\n });\n }\n\n /**\n * Execute the action for a binding\n */\n private executeAction(binding: KeyBinding): boolean {\n const { action, handler } = binding;\n\n switch (action) {\n case 'resetZoom':\n this.callbacks.onResetZoom?.();\n return true;\n case 'autoScale':\n this.callbacks.onAutoScale?.();\n return true;\n case 'zoomIn':\n this.callbacks.onZoomIn?.();\n return true;\n case 'zoomOut':\n this.callbacks.onZoomOut?.();\n return true;\n case 'panLeft':\n this.callbacks.onPanLeft?.();\n return true;\n case 'panRight':\n this.callbacks.onPanRight?.();\n return true;\n case 'panUp':\n this.callbacks.onPanUp?.();\n return true;\n case 'panDown':\n this.callbacks.onPanDown?.();\n return true;\n case 'togglePan':\n this.callbacks.onTogglePan?.();\n return true;\n case 'toggleSelect':\n this.callbacks.onToggleSelect?.();\n return true;\n case 'clearSelection':\n case 'escape':\n this.callbacks.onEscape?.();\n this.callbacks.onClearSelection?.();\n return true;\n case 'deleteSelected':\n this.callbacks.onDeleteSelected?.();\n return true;\n case 'selectAll':\n this.callbacks.onSelectAll?.();\n return true;\n case 'copy':\n this.callbacks.onCopy?.();\n return true;\n case 'exportImage':\n this.callbacks.onExportImage?.();\n return true;\n case 'toggleLegend':\n this.callbacks.onToggleLegend?.();\n return true;\n case 'toggleDebug':\n this.callbacks.onToggleDebug?.();\n return true;\n case 'undo':\n this.callbacks.onUndo?.();\n return true;\n case 'redo':\n this.callbacks.onRedo?.();\n return true;\n case 'custom':\n handler?.();\n return true;\n default:\n return false;\n }\n }\n\n /**\n * Destroy the manager and cleanup\n */\n destroy(): void {\n this.detach();\n this.bindings = [];\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\n/**\n * Create a simple key binding configuration\n */\nexport function createKeyBinding(\n key: string,\n action: KeyAction,\n options?: Partial<KeyBinding>\n): KeyBinding {\n return {\n key,\n action,\n ...options,\n };\n}\n\n/**\n * Parse a shortcut string (e.g., \"Ctrl+R\") into a KeyBinding\n */\nexport function parseShortcut(shortcut: string, action: KeyAction): KeyBinding {\n const parts = shortcut.split('+').map(p => p.trim().toLowerCase());\n const binding: KeyBinding = {\n key: '',\n action,\n ctrl: false,\n shift: false,\n alt: false,\n meta: false,\n };\n\n for (const part of parts) {\n switch (part) {\n case 'ctrl':\n case 'control':\n binding.ctrl = true;\n break;\n case 'shift':\n binding.shift = true;\n break;\n case 'alt':\n binding.alt = true;\n break;\n case 'meta':\n case 'cmd':\n case 'command':\n binding.meta = true;\n break;\n default:\n // Convert to key code\n if (part.length === 1) {\n if (/[a-z]/i.test(part)) {\n binding.key = 'Key' + part.toUpperCase();\n } else if (/[0-9]/.test(part)) {\n binding.key = 'Digit' + part;\n } else if (part === '+') {\n binding.key = 'Equal';\n } else if (part === '-') {\n binding.key = 'Minus';\n }\n } else {\n // Handle special keys\n const specialKeys: Record<string, string> = {\n 'escape': 'Escape',\n 'esc': 'Escape',\n 'enter': 'Enter',\n 'return': 'Enter',\n 'space': 'Space',\n 'tab': 'Tab',\n 'delete': 'Delete',\n 'backspace': 'Backspace',\n 'left': 'ArrowLeft',\n 'right': 'ArrowRight',\n 'up': 'ArrowUp',\n 'down': 'ArrowDown',\n };\n binding.key = specialKeys[part] || part;\n }\n }\n }\n\n return binding;\n}\n"],"names":["DEFAULT_KEY_BINDINGS","KeyBindingManager","options","__publicField","enabled","binding","key","modifiers","b","updates","parts","keyName","target","_a","_b","_c","_d","_e","_f","_g","_h","_i","_j","_k","_l","_m","_n","_o","_p","_q","_r","_s","_t","_u","_v","_w","_x","_y","_z","_A","_B","_C","_D","_E","_F","_G","_H","_I","_J","_K","_L","_M","_N","action","handler","createKeyBinding","parseShortcut","shortcut","p","part","specialKeys"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index-CaXWSOTk.js","sources":["../src/core/sync/index.ts"],"sourcesContent":["/**\n * Sci Plot - Chart Synchronization Module\n *\n * @module sync\n */\n\nimport type { Bounds, Range } from \"../../types\";\n\nexport type SyncAxis = 'x' | 'y' | 'xy' | 'none';\n\nexport interface SyncOptions {\n axis?: SyncAxis;\n syncCursor?: boolean;\n syncSelection?: boolean;\n syncZoom?: boolean;\n syncPan?: boolean;\n debounce?: number;\n bidirectional?: boolean;\n /** When set, used for fitAll; with bidirectional sync any pane can drive pan/zoom */\n masterId?: string;\n}\n\nexport interface ChartLike {\n getId(): string;\n getViewBounds(): Bounds;\n zoom(options: { x?: Range; y?: Range; animate?: boolean }): void;\n pan(dx: number, dy: number): void;\n fit?(options?: { x?: Range; y?: Range; padding?: number | { x?: number; y?: number } }): void;\n getCursorPosition?(): { x: number; y: number } | null;\n setExternalCursor?(x: number, y: number): void;\n clearExternalCursor?(): void;\n getSelectedPoints?(): { seriesId: string; indices: number[] }[];\n selectPoints?(points: { seriesId: string; indices: number[] }[]): void;\n clearSelection?(): void;\n on(event: string, callback: (...args: unknown[]) => void): void;\n off(event: string, callback: (...args: unknown[]) => void): void;\n}\n\nexport interface SyncEvent {\n sourceId: string;\n type: 'zoom' | 'pan' | 'cursor' | 'selection' | 'bounds';\n data: unknown;\n}\n\ntype RequiredSyncOptions = Required<Omit<SyncOptions, 'masterId'>> & Pick<SyncOptions, 'masterId'>;\n\nexport class ChartGroup {\n private charts: Map<string, ChartLike> = new Map();\n private options: RequiredSyncOptions;\n private eventHandlers: Map<string, Map<string, (...args: unknown[]) => void>> = new Map();\n private isUpdating: boolean = false;\n private debounceTimers: Map<string, number> = new Map();\n private rafTimers: Map<string, number> = new Map();\n\n constructor(options?: SyncOptions) {\n this.options = {\n axis: 'x',\n syncCursor: true,\n syncSelection: false,\n syncZoom: true,\n syncPan: true,\n debounce: 0,\n bidirectional: true,\n masterId: undefined,\n ...options,\n };\n }\n\n add(chart: ChartLike): this {\n const chartId = chart.getId();\n if (this.charts.has(chartId)) {\n console.warn(`[ChartGroup] Chart ${chartId} is already in the group`);\n return this;\n }\n this.charts.set(chartId, chart);\n this.attachEventHandlers(chart);\n return this;\n }\n\n addAll(...charts: ChartLike[]): this {\n for (const chart of charts) this.add(chart);\n return this;\n }\n\n remove(chart: ChartLike): this {\n const chartId = chart.getId();\n if (!this.charts.has(chartId)) return this;\n this.detachEventHandlers(chart);\n this.charts.delete(chartId);\n return this;\n }\n\n getCharts(): ChartLike[] {\n return Array.from(this.charts.values());\n }\n\n size(): number {\n return this.charts.size;\n }\n\n has(chart: ChartLike): boolean {\n return this.charts.has(chart.getId());\n }\n\n syncAxis(axis: SyncAxis): this {\n this.options.axis = axis;\n return this;\n }\n\n syncZoom(enabled: boolean): this {\n if (this.options.syncZoom === enabled) return this;\n return this.updateOptions({ syncZoom: enabled });\n }\n\n syncPan(enabled: boolean): this {\n if (this.options.syncPan === enabled) return this;\n return this.updateOptions({ syncPan: enabled });\n }\n\n syncCursor(enabled: boolean): this {\n this.options.syncCursor = enabled;\n return this;\n }\n\n syncSelection(enabled: boolean): this {\n this.options.syncSelection = enabled;\n return this;\n }\n\n /** Update sync options and re-bind event handlers on all charts */\n updateOptions(partial: Partial<SyncOptions>): this {\n Object.assign(this.options, partial);\n for (const chart of this.charts.values()) {\n this.detachEventHandlers(chart);\n this.attachEventHandlers(chart);\n }\n return this;\n }\n\n getOptions(): Readonly<SyncOptions> {\n return { ...this.options };\n }\n\n syncTo(bounds: Partial<Bounds>, excludeChartId?: string): void {\n this.propagateZoom(excludeChartId || '', bounds);\n }\n\n resetAll(): void {\n this.batch(() => {\n for (const chart of this.charts.values()) {\n if (chart.fit) chart.fit();\n else chart.zoom({ x: undefined, y: undefined });\n }\n });\n }\n\n fitAll(options?: { x?: Range; padding?: number }): void {\n this.batch(() => {\n let sharedX: Range | undefined = options?.x;\n const masterId = this.options.masterId;\n const master = masterId ? this.charts.get(masterId) : this.charts.values().next().value;\n\n if (!sharedX && master?.fit) {\n master.fit({ padding: options?.padding });\n const b = master.getViewBounds();\n if (this.hasValidViewBounds(b)) sharedX = [b.xMin, b.xMax];\n }\n\n for (const [chartId, chart] of this.charts.entries()) {\n if (!chart.fit) continue;\n if (chartId === masterId) continue;\n chart.fit(\n sharedX\n ? { x: sharedX, padding: options?.padding }\n : { padding: options?.padding },\n );\n }\n });\n }\n\n batch<T>(fn: () => T): T {\n const prev = this.isUpdating;\n this.isUpdating = true;\n try {\n return fn();\n } finally {\n this.isUpdating = prev;\n }\n }\n\n clearAllSelections(): void {\n for (const chart of this.charts.values()) {\n chart.clearSelection?.();\n }\n }\n\n destroy(): void {\n for (const chart of this.charts.values()) {\n this.detachEventHandlers(chart);\n }\n this.charts.clear();\n this.eventHandlers.clear();\n for (const timerId of this.debounceTimers.values()) clearTimeout(timerId);\n this.debounceTimers.clear();\n for (const rafId of this.rafTimers.values()) cancelAnimationFrame(rafId);\n this.rafTimers.clear();\n }\n\n private isSyncSource(chartId: string): boolean {\n if (this.options.bidirectional) return true;\n if (this.options.masterId) return chartId === this.options.masterId;\n return true;\n }\n\n private hasValidViewBounds(bounds: Bounds): boolean {\n const xSpan = bounds.xMax - bounds.xMin;\n const ySpan = bounds.yMax - bounds.yMin;\n if (!Number.isFinite(xSpan) || !Number.isFinite(ySpan)) return false;\n if (xSpan <= 0 && ySpan <= 0) return false;\n return true;\n }\n\n private attachEventHandlers(chart: ChartLike): void {\n const chartId = chart.getId();\n const handlers = new Map<string, (...args: unknown[]) => void>();\n\n if (this.options.syncZoom && this.isSyncSource(chartId)) {\n const zoomHandler = (...args: unknown[]) => {\n this.handleZoom(chartId, args[0] as { x: Range; y: Range });\n };\n chart.on('zoom', zoomHandler);\n handlers.set('zoom', zoomHandler);\n }\n\n if (this.options.syncPan && this.isSyncSource(chartId)) {\n const panHandler = (...args: unknown[]) => {\n this.handlePan(chartId, args[0] as { deltaX: number; deltaY: number });\n };\n chart.on('pan', panHandler);\n handlers.set('pan', panHandler);\n }\n\n if (this.options.syncCursor) {\n const hoverHandler = (...args: unknown[]) => {\n this.handleCursor(chartId, args[0] as { point?: { x: number; y: number } } | null);\n };\n chart.on('hover', hoverHandler);\n handlers.set('hover', hoverHandler);\n }\n\n if (this.options.syncSelection) {\n const selectionHandler = (...args: unknown[]) => {\n this.handleSelection(chartId, args[0] as { selected: unknown[] });\n };\n chart.on('selectionChange', selectionHandler);\n handlers.set('selectionChange', selectionHandler);\n }\n\n this.eventHandlers.set(chartId, handlers);\n }\n\n private detachEventHandlers(chart: ChartLike): void {\n const chartId = chart.getId();\n const handlers = this.eventHandlers.get(chartId);\n if (!handlers) return;\n for (const [event, handler] of handlers.entries()) {\n chart.off(event, handler);\n }\n this.eventHandlers.delete(chartId);\n }\n\n private handleZoom(sourceId: string, event: { x: Range; y: Range }): void {\n if (this.isUpdating) return;\n // No canPropagateFrom guard needed: zoom handlers are only attached to sync\n // sources (see attachEventHandlers + isSyncSource), which use identical logic.\n\n const sourceChart = this.charts.get(sourceId);\n if (sourceChart && !this.hasValidViewBounds(sourceChart.getViewBounds())) return;\n\n const bounds: Partial<Bounds> = {};\n if (this.options.axis === 'x' || this.options.axis === 'xy') {\n bounds.xMin = event.x[0];\n bounds.xMax = event.x[1];\n }\n if (this.options.axis === 'y' || this.options.axis === 'xy') {\n bounds.yMin = event.y[0];\n bounds.yMax = event.y[1];\n }\n\n if (bounds.xMin !== undefined && bounds.xMax !== undefined) {\n const xSpan = bounds.xMax - bounds.xMin;\n if (!Number.isFinite(xSpan) || xSpan <= 0) return;\n }\n\n this.scheduleSyncAction(`zoom-${sourceId}`, () => {\n this.propagateZoom(sourceId, bounds);\n });\n }\n\n private handlePan(sourceId: string, event: { deltaX: number; deltaY: number }): void {\n if (this.isUpdating) return;\n // Pan handlers are only attached to sync sources (see attachEventHandlers).\n\n const dx = (this.options.axis === 'x' || this.options.axis === 'xy') ? event.deltaX : 0;\n const dy = (this.options.axis === 'y' || this.options.axis === 'xy') ? event.deltaY : 0;\n if (dx === 0 && dy === 0) return;\n\n this.scheduleSyncAction(`pan-${sourceId}`, () => {\n this.propagatePan(sourceId, dx, dy);\n });\n }\n\n private handleCursor(sourceId: string, event: { point?: { x: number; y: number } } | null): void {\n if (this.isUpdating) return;\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n if (event?.point) chart.setExternalCursor?.(event.point.x, event.point.y);\n else chart.clearExternalCursor?.();\n }\n }\n\n private handleSelection(sourceId: string, event: { selected: unknown[] }): void {\n if (this.isUpdating || !this.options.syncSelection) return;\n\n const sourceChart = this.charts.get(sourceId);\n if (!sourceChart) return;\n\n const selected =\n (event?.selected as { seriesId: string; indices: number[] }[]) ??\n sourceChart.getSelectedPoints?.() ??\n [];\n\n this.isUpdating = true;\n try {\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n if (selected.length === 0) {\n chart.clearSelection?.();\n } else {\n chart.selectPoints?.(selected);\n }\n }\n } finally {\n this.isUpdating = false;\n }\n }\n\n private propagateZoom(sourceId: string, bounds: Partial<Bounds>): void {\n if (this.isUpdating) return;\n this.isUpdating = true;\n try {\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n const zoomOptions: { x?: Range; y?: Range; animate?: boolean } = { animate: false };\n if (bounds.xMin !== undefined && bounds.xMax !== undefined) {\n zoomOptions.x = [bounds.xMin, bounds.xMax];\n }\n if (bounds.yMin !== undefined && bounds.yMax !== undefined) {\n zoomOptions.y = [bounds.yMin, bounds.yMax];\n }\n chart.zoom(zoomOptions);\n }\n } finally {\n this.isUpdating = false;\n }\n }\n\n private propagatePan(sourceId: string, _dx: number, _dy: number): void {\n if (this.isUpdating) return;\n this.isUpdating = true;\n try {\n const sourceChart = this.charts.get(sourceId);\n if (!sourceChart || !this.hasValidViewBounds(sourceChart.getViewBounds())) return;\n\n const masterBounds = sourceChart.getViewBounds();\n\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n\n const zoomOptions: { x?: Range; y?: Range; animate?: boolean } = { animate: false };\n\n if (this.options.axis === 'x' || this.options.axis === 'xy') {\n zoomOptions.x = [masterBounds.xMin, masterBounds.xMax];\n }\n\n if (this.options.axis === 'y' || this.options.axis === 'xy') {\n zoomOptions.y = [masterBounds.yMin, masterBounds.yMax];\n }\n\n if (zoomOptions.x || zoomOptions.y) {\n chart.zoom(zoomOptions);\n }\n }\n } finally {\n this.isUpdating = false;\n }\n }\n\n private scheduleSyncAction(key: string, action: () => void): void {\n if (this.options.debounce > 0) {\n this.debounceAction(key, action);\n return;\n }\n if (this.rafTimers.has(key)) return;\n const rafId = requestAnimationFrame(() => {\n this.rafTimers.delete(key);\n action();\n });\n this.rafTimers.set(key, rafId);\n }\n\n private debounceAction(key: string, action: () => void): void {\n const existingTimer = this.debounceTimers.get(key);\n if (existingTimer) clearTimeout(existingTimer);\n const timerId = window.setTimeout(() => {\n this.debounceTimers.delete(key);\n action();\n }, this.options.debounce);\n this.debounceTimers.set(key, timerId);\n }\n}\n\nexport function createChartGroup(charts: ChartLike[], options?: SyncOptions): ChartGroup {\n const group = new ChartGroup(options);\n group.addAll(...charts);\n return group;\n}\n\nexport function linkCharts(chart1: ChartLike, chart2: ChartLike, options?: SyncOptions): ChartGroup {\n return createChartGroup([chart1, chart2], options);\n}\n\nexport function createMasterSlave(\n master: ChartLike,\n slave: ChartLike,\n axis: SyncAxis = 'x',\n): ChartGroup {\n return createChartGroup([master, slave], {\n axis,\n bidirectional: false,\n masterId: master.getId(),\n syncCursor: true,\n syncZoom: true,\n syncPan: true,\n });\n}\n"],"names":["ChartGroup","options","__publicField","chart","chartId","charts","axis","enabled","partial","bounds","excludeChartId","sharedX","masterId","master","b","fn","prev","_a","timerId","rafId","xSpan","ySpan","handlers","zoomHandler","args","panHandler","hoverHandler","selectionHandler","event","handler","sourceId","sourceChart","dx","dy","_b","_c","selected","zoomOptions","_dx","_dy","masterBounds","key","action","existingTimer","createChartGroup","group","linkCharts","chart1","chart2","createMasterSlave","slave"],"mappings":"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"}
1
+ {"version":3,"file":"index-CaXWSOTk.js","sources":["../src/core/sync/index.ts"],"sourcesContent":["/**\n * Velo Plot - Chart Synchronization Module\n *\n * @module sync\n */\n\nimport type { Bounds, Range } from \"../../types\";\n\nexport type SyncAxis = 'x' | 'y' | 'xy' | 'none';\n\nexport interface SyncOptions {\n axis?: SyncAxis;\n syncCursor?: boolean;\n syncSelection?: boolean;\n syncZoom?: boolean;\n syncPan?: boolean;\n debounce?: number;\n bidirectional?: boolean;\n /** When set, used for fitAll; with bidirectional sync any pane can drive pan/zoom */\n masterId?: string;\n}\n\nexport interface ChartLike {\n getId(): string;\n getViewBounds(): Bounds;\n zoom(options: { x?: Range; y?: Range; animate?: boolean }): void;\n pan(dx: number, dy: number): void;\n fit?(options?: { x?: Range; y?: Range; padding?: number | { x?: number; y?: number } }): void;\n getCursorPosition?(): { x: number; y: number } | null;\n setExternalCursor?(x: number, y: number): void;\n clearExternalCursor?(): void;\n getSelectedPoints?(): { seriesId: string; indices: number[] }[];\n selectPoints?(points: { seriesId: string; indices: number[] }[]): void;\n clearSelection?(): void;\n on(event: string, callback: (...args: unknown[]) => void): void;\n off(event: string, callback: (...args: unknown[]) => void): void;\n}\n\nexport interface SyncEvent {\n sourceId: string;\n type: 'zoom' | 'pan' | 'cursor' | 'selection' | 'bounds';\n data: unknown;\n}\n\ntype RequiredSyncOptions = Required<Omit<SyncOptions, 'masterId'>> & Pick<SyncOptions, 'masterId'>;\n\nexport class ChartGroup {\n private charts: Map<string, ChartLike> = new Map();\n private options: RequiredSyncOptions;\n private eventHandlers: Map<string, Map<string, (...args: unknown[]) => void>> = new Map();\n private isUpdating: boolean = false;\n private debounceTimers: Map<string, number> = new Map();\n private rafTimers: Map<string, number> = new Map();\n\n constructor(options?: SyncOptions) {\n this.options = {\n axis: 'x',\n syncCursor: true,\n syncSelection: false,\n syncZoom: true,\n syncPan: true,\n debounce: 0,\n bidirectional: true,\n masterId: undefined,\n ...options,\n };\n }\n\n add(chart: ChartLike): this {\n const chartId = chart.getId();\n if (this.charts.has(chartId)) {\n console.warn(`[ChartGroup] Chart ${chartId} is already in the group`);\n return this;\n }\n this.charts.set(chartId, chart);\n this.attachEventHandlers(chart);\n return this;\n }\n\n addAll(...charts: ChartLike[]): this {\n for (const chart of charts) this.add(chart);\n return this;\n }\n\n remove(chart: ChartLike): this {\n const chartId = chart.getId();\n if (!this.charts.has(chartId)) return this;\n this.detachEventHandlers(chart);\n this.charts.delete(chartId);\n return this;\n }\n\n getCharts(): ChartLike[] {\n return Array.from(this.charts.values());\n }\n\n size(): number {\n return this.charts.size;\n }\n\n has(chart: ChartLike): boolean {\n return this.charts.has(chart.getId());\n }\n\n syncAxis(axis: SyncAxis): this {\n this.options.axis = axis;\n return this;\n }\n\n syncZoom(enabled: boolean): this {\n if (this.options.syncZoom === enabled) return this;\n return this.updateOptions({ syncZoom: enabled });\n }\n\n syncPan(enabled: boolean): this {\n if (this.options.syncPan === enabled) return this;\n return this.updateOptions({ syncPan: enabled });\n }\n\n syncCursor(enabled: boolean): this {\n this.options.syncCursor = enabled;\n return this;\n }\n\n syncSelection(enabled: boolean): this {\n this.options.syncSelection = enabled;\n return this;\n }\n\n /** Update sync options and re-bind event handlers on all charts */\n updateOptions(partial: Partial<SyncOptions>): this {\n Object.assign(this.options, partial);\n for (const chart of this.charts.values()) {\n this.detachEventHandlers(chart);\n this.attachEventHandlers(chart);\n }\n return this;\n }\n\n getOptions(): Readonly<SyncOptions> {\n return { ...this.options };\n }\n\n syncTo(bounds: Partial<Bounds>, excludeChartId?: string): void {\n this.propagateZoom(excludeChartId || '', bounds);\n }\n\n resetAll(): void {\n this.batch(() => {\n for (const chart of this.charts.values()) {\n if (chart.fit) chart.fit();\n else chart.zoom({ x: undefined, y: undefined });\n }\n });\n }\n\n fitAll(options?: { x?: Range; padding?: number }): void {\n this.batch(() => {\n let sharedX: Range | undefined = options?.x;\n const masterId = this.options.masterId;\n const master = masterId ? this.charts.get(masterId) : this.charts.values().next().value;\n\n if (!sharedX && master?.fit) {\n master.fit({ padding: options?.padding });\n const b = master.getViewBounds();\n if (this.hasValidViewBounds(b)) sharedX = [b.xMin, b.xMax];\n }\n\n for (const [chartId, chart] of this.charts.entries()) {\n if (!chart.fit) continue;\n if (chartId === masterId) continue;\n chart.fit(\n sharedX\n ? { x: sharedX, padding: options?.padding }\n : { padding: options?.padding },\n );\n }\n });\n }\n\n batch<T>(fn: () => T): T {\n const prev = this.isUpdating;\n this.isUpdating = true;\n try {\n return fn();\n } finally {\n this.isUpdating = prev;\n }\n }\n\n clearAllSelections(): void {\n for (const chart of this.charts.values()) {\n chart.clearSelection?.();\n }\n }\n\n destroy(): void {\n for (const chart of this.charts.values()) {\n this.detachEventHandlers(chart);\n }\n this.charts.clear();\n this.eventHandlers.clear();\n for (const timerId of this.debounceTimers.values()) clearTimeout(timerId);\n this.debounceTimers.clear();\n for (const rafId of this.rafTimers.values()) cancelAnimationFrame(rafId);\n this.rafTimers.clear();\n }\n\n private isSyncSource(chartId: string): boolean {\n if (this.options.bidirectional) return true;\n if (this.options.masterId) return chartId === this.options.masterId;\n return true;\n }\n\n private hasValidViewBounds(bounds: Bounds): boolean {\n const xSpan = bounds.xMax - bounds.xMin;\n const ySpan = bounds.yMax - bounds.yMin;\n if (!Number.isFinite(xSpan) || !Number.isFinite(ySpan)) return false;\n if (xSpan <= 0 && ySpan <= 0) return false;\n return true;\n }\n\n private attachEventHandlers(chart: ChartLike): void {\n const chartId = chart.getId();\n const handlers = new Map<string, (...args: unknown[]) => void>();\n\n if (this.options.syncZoom && this.isSyncSource(chartId)) {\n const zoomHandler = (...args: unknown[]) => {\n this.handleZoom(chartId, args[0] as { x: Range; y: Range });\n };\n chart.on('zoom', zoomHandler);\n handlers.set('zoom', zoomHandler);\n }\n\n if (this.options.syncPan && this.isSyncSource(chartId)) {\n const panHandler = (...args: unknown[]) => {\n this.handlePan(chartId, args[0] as { deltaX: number; deltaY: number });\n };\n chart.on('pan', panHandler);\n handlers.set('pan', panHandler);\n }\n\n if (this.options.syncCursor) {\n const hoverHandler = (...args: unknown[]) => {\n this.handleCursor(chartId, args[0] as { point?: { x: number; y: number } } | null);\n };\n chart.on('hover', hoverHandler);\n handlers.set('hover', hoverHandler);\n }\n\n if (this.options.syncSelection) {\n const selectionHandler = (...args: unknown[]) => {\n this.handleSelection(chartId, args[0] as { selected: unknown[] });\n };\n chart.on('selectionChange', selectionHandler);\n handlers.set('selectionChange', selectionHandler);\n }\n\n this.eventHandlers.set(chartId, handlers);\n }\n\n private detachEventHandlers(chart: ChartLike): void {\n const chartId = chart.getId();\n const handlers = this.eventHandlers.get(chartId);\n if (!handlers) return;\n for (const [event, handler] of handlers.entries()) {\n chart.off(event, handler);\n }\n this.eventHandlers.delete(chartId);\n }\n\n private handleZoom(sourceId: string, event: { x: Range; y: Range }): void {\n if (this.isUpdating) return;\n // No canPropagateFrom guard needed: zoom handlers are only attached to sync\n // sources (see attachEventHandlers + isSyncSource), which use identical logic.\n\n const sourceChart = this.charts.get(sourceId);\n if (sourceChart && !this.hasValidViewBounds(sourceChart.getViewBounds())) return;\n\n const bounds: Partial<Bounds> = {};\n if (this.options.axis === 'x' || this.options.axis === 'xy') {\n bounds.xMin = event.x[0];\n bounds.xMax = event.x[1];\n }\n if (this.options.axis === 'y' || this.options.axis === 'xy') {\n bounds.yMin = event.y[0];\n bounds.yMax = event.y[1];\n }\n\n if (bounds.xMin !== undefined && bounds.xMax !== undefined) {\n const xSpan = bounds.xMax - bounds.xMin;\n if (!Number.isFinite(xSpan) || xSpan <= 0) return;\n }\n\n this.scheduleSyncAction(`zoom-${sourceId}`, () => {\n this.propagateZoom(sourceId, bounds);\n });\n }\n\n private handlePan(sourceId: string, event: { deltaX: number; deltaY: number }): void {\n if (this.isUpdating) return;\n // Pan handlers are only attached to sync sources (see attachEventHandlers).\n\n const dx = (this.options.axis === 'x' || this.options.axis === 'xy') ? event.deltaX : 0;\n const dy = (this.options.axis === 'y' || this.options.axis === 'xy') ? event.deltaY : 0;\n if (dx === 0 && dy === 0) return;\n\n this.scheduleSyncAction(`pan-${sourceId}`, () => {\n this.propagatePan(sourceId, dx, dy);\n });\n }\n\n private handleCursor(sourceId: string, event: { point?: { x: number; y: number } } | null): void {\n if (this.isUpdating) return;\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n if (event?.point) chart.setExternalCursor?.(event.point.x, event.point.y);\n else chart.clearExternalCursor?.();\n }\n }\n\n private handleSelection(sourceId: string, event: { selected: unknown[] }): void {\n if (this.isUpdating || !this.options.syncSelection) return;\n\n const sourceChart = this.charts.get(sourceId);\n if (!sourceChart) return;\n\n const selected =\n (event?.selected as { seriesId: string; indices: number[] }[]) ??\n sourceChart.getSelectedPoints?.() ??\n [];\n\n this.isUpdating = true;\n try {\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n if (selected.length === 0) {\n chart.clearSelection?.();\n } else {\n chart.selectPoints?.(selected);\n }\n }\n } finally {\n this.isUpdating = false;\n }\n }\n\n private propagateZoom(sourceId: string, bounds: Partial<Bounds>): void {\n if (this.isUpdating) return;\n this.isUpdating = true;\n try {\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n const zoomOptions: { x?: Range; y?: Range; animate?: boolean } = { animate: false };\n if (bounds.xMin !== undefined && bounds.xMax !== undefined) {\n zoomOptions.x = [bounds.xMin, bounds.xMax];\n }\n if (bounds.yMin !== undefined && bounds.yMax !== undefined) {\n zoomOptions.y = [bounds.yMin, bounds.yMax];\n }\n chart.zoom(zoomOptions);\n }\n } finally {\n this.isUpdating = false;\n }\n }\n\n private propagatePan(sourceId: string, _dx: number, _dy: number): void {\n if (this.isUpdating) return;\n this.isUpdating = true;\n try {\n const sourceChart = this.charts.get(sourceId);\n if (!sourceChart || !this.hasValidViewBounds(sourceChart.getViewBounds())) return;\n\n const masterBounds = sourceChart.getViewBounds();\n\n for (const [chartId, chart] of this.charts.entries()) {\n if (chartId === sourceId) continue;\n\n const zoomOptions: { x?: Range; y?: Range; animate?: boolean } = { animate: false };\n\n if (this.options.axis === 'x' || this.options.axis === 'xy') {\n zoomOptions.x = [masterBounds.xMin, masterBounds.xMax];\n }\n\n if (this.options.axis === 'y' || this.options.axis === 'xy') {\n zoomOptions.y = [masterBounds.yMin, masterBounds.yMax];\n }\n\n if (zoomOptions.x || zoomOptions.y) {\n chart.zoom(zoomOptions);\n }\n }\n } finally {\n this.isUpdating = false;\n }\n }\n\n private scheduleSyncAction(key: string, action: () => void): void {\n if (this.options.debounce > 0) {\n this.debounceAction(key, action);\n return;\n }\n if (this.rafTimers.has(key)) return;\n const rafId = requestAnimationFrame(() => {\n this.rafTimers.delete(key);\n action();\n });\n this.rafTimers.set(key, rafId);\n }\n\n private debounceAction(key: string, action: () => void): void {\n const existingTimer = this.debounceTimers.get(key);\n if (existingTimer) clearTimeout(existingTimer);\n const timerId = window.setTimeout(() => {\n this.debounceTimers.delete(key);\n action();\n }, this.options.debounce);\n this.debounceTimers.set(key, timerId);\n }\n}\n\nexport function createChartGroup(charts: ChartLike[], options?: SyncOptions): ChartGroup {\n const group = new ChartGroup(options);\n group.addAll(...charts);\n return group;\n}\n\nexport function linkCharts(chart1: ChartLike, chart2: ChartLike, options?: SyncOptions): ChartGroup {\n return createChartGroup([chart1, chart2], options);\n}\n\nexport function createMasterSlave(\n master: ChartLike,\n slave: ChartLike,\n axis: SyncAxis = 'x',\n): ChartGroup {\n return createChartGroup([master, slave], {\n axis,\n bidirectional: false,\n masterId: master.getId(),\n syncCursor: true,\n syncZoom: true,\n syncPan: true,\n });\n}\n"],"names":["ChartGroup","options","__publicField","chart","chartId","charts","axis","enabled","partial","bounds","excludeChartId","sharedX","masterId","master","b","fn","prev","_a","timerId","rafId","xSpan","ySpan","handlers","zoomHandler","args","panHandler","hoverHandler","selectionHandler","event","handler","sourceId","sourceChart","dx","dy","_b","_c","selected","zoomOptions","_dx","_dy","masterBounds","key","action","existingTimer","createChartGroup","group","linkCharts","chart1","chart2","createMasterSlave","slave"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index-Dag88bW4.js","sources":["../src/core/theme-editor/index.ts","../src/plugins/theme-editor/index.ts"],"sourcesContent":["/**\n * Sci Plot - Theme Editor Module\n * \n * Provides a visual theme editor for customizing chart appearance:\n * - Color pickers for all theme elements\n * - Live preview\n * - Theme export/import\n * - Preset theme gallery\n * \n * @module theme-editor\n */\n\n// Use a flexible internal type to avoid strict EditorTheme compatibility issues\n// The editor works with partial theme configs that can be applied via createTheme()\nexport type EditorTheme = Record<string, unknown>;\n\n// ============================================\n// Types\n// ============================================\n\nexport interface ThemeEditorOptions {\n /** Base theme to start from */\n baseTheme?: EditorTheme | string;\n /** Enable live preview (default: true) */\n livePreview?: boolean;\n /** Show advanced options (default: false) */\n showAdvanced?: boolean;\n /** Custom CSS class for the editor */\n className?: string;\n /** Callback when theme changes */\n onChange?: (theme: EditorTheme) => void;\n /** Callback when export is requested */\n onExport?: (theme: EditorTheme, json: string) => void;\n}\n\nexport interface ThemePreset {\n /** Preset name */\n name: string;\n /** Description */\n description?: string;\n /** Theme configuration */\n theme: EditorTheme;\n /** Preview colors (for UI) */\n previewColors?: string[];\n /** Tags for filtering */\n tags?: string[];\n}\n\nexport interface ColorGroup {\n /** Group label */\n label: string;\n /** Group description */\n description?: string;\n /** Color properties in this group */\n colors: ColorProperty[];\n}\n\nexport interface ColorProperty {\n /** Property key path (e.g., 'background', 'axis.color') */\n key: string;\n /** Display label */\n label: string;\n /** Description/tooltip */\n description?: string;\n /** Current value */\n value: string;\n /** Default value */\n defaultValue?: string;\n}\n\n// ============================================\n// Default Theme Structure\n// ============================================\n\nconst THEME_COLOR_GROUPS: ColorGroup[] = [\n {\n label: \"Background & Canvas\",\n description: \"Chart background and canvas colors\",\n colors: [\n { key: \"backgroundColor\", label: \"Background\", value: \"\", description: \"Main chart background\" },\n { key: \"plotAreaBackground\", label: \"Plot Area\", value: \"\", description: \"Data plotting area background\" },\n ],\n },\n {\n label: \"Axes\",\n description: \"Axis lines, ticks, and labels\",\n colors: [\n { key: \"axis.color\", label: \"Axis Lines\", value: \"\", description: \"Axis line color\" },\n { key: \"axis.labelColor\", label: \"Axis Labels\", value: \"\", description: \"Axis label text color\" },\n { key: \"axis.titleColor\", label: \"Axis Titles\", value: \"\", description: \"Axis title text color\" },\n ],\n },\n {\n label: \"Grid\",\n description: \"Grid lines and markers\",\n colors: [\n { key: \"grid.color\", label: \"Grid Lines\", value: \"\", description: \"Major grid line color\" },\n { key: \"grid.minorColor\", label: \"Minor Grid\", value: \"\", description: \"Minor grid line color\" },\n ],\n },\n {\n label: \"Series Palette\",\n description: \"Default colors for data series\",\n colors: [\n { key: \"seriesPalette.0\", label: \"Series 1\", value: \"\", description: \"First series color\" },\n { key: \"seriesPalette.1\", label: \"Series 2\", value: \"\", description: \"Second series color\" },\n { key: \"seriesPalette.2\", label: \"Series 3\", value: \"\", description: \"Third series color\" },\n { key: \"seriesPalette.3\", label: \"Series 4\", value: \"\", description: \"Fourth series color\" },\n { key: \"seriesPalette.4\", label: \"Series 5\", value: \"\", description: \"Fifth series color\" },\n { key: \"seriesPalette.5\", label: \"Series 6\", value: \"\", description: \"Sixth series color\" },\n ],\n },\n {\n label: \"Legend\",\n description: \"Legend styling\",\n colors: [\n { key: \"legend.backgroundColor\", label: \"Legend Background\", value: \"\", description: \"Legend panel background\" },\n { key: \"legend.textColor\", label: \"Legend Text\", value: \"\", description: \"Legend text color\" },\n { key: \"legend.borderColor\", label: \"Legend Border\", value: \"\", description: \"Legend border color\" },\n ],\n },\n {\n label: \"Cursor & Selection\",\n description: \"Interactive elements\",\n colors: [\n { key: \"cursor.color\", label: \"Crosshair\", value: \"\", description: \"Cursor crosshair color\" },\n { key: \"cursor.labelBackground\", label: \"Cursor Label BG\", value: \"\", description: \"Cursor label background\" },\n { key: \"selection.color\", label: \"Selection\", value: \"\", description: \"Selection highlight color\" },\n { key: \"selection.handleColor\", label: \"Selection Handles\", value: \"\", description: \"Selection handle color\" },\n ],\n },\n {\n label: \"Annotations\",\n description: \"Annotation default colors\",\n colors: [\n { key: \"annotation.lineColor\", label: \"Line Annotations\", value: \"\", description: \"Default line annotation color\" },\n { key: \"annotation.fillColor\", label: \"Fill Annotations\", value: \"\", description: \"Default fill annotation color\" },\n { key: \"annotation.textColor\", label: \"Text Annotations\", value: \"\", description: \"Default text annotation color\" },\n ],\n },\n];\n\n// ============================================\n// Theme Presets\n// ============================================\n\nexport const THEME_PRESETS: ThemePreset[] = [\n {\n name: \"Dark\",\n description: \"Classic dark theme with cyan accents\",\n previewColors: [\"#1a1a2e\", \"#00f2ff\", \"#4ecdc4\"],\n tags: [\"dark\", \"default\"],\n theme: {\n backgroundColor: \"#1a1a2e\",\n plotAreaBackground: \"#16213e\",\n axis: {\n color: \"#4a5568\",\n labelColor: \"#a0aec0\",\n titleColor: \"#e2e8f0\",\n labelFontSize: 11,\n titleFontSize: 13,\n },\n grid: {\n color: \"rgba(74, 85, 104, 0.3)\",\n opacity: 0.3,\n },\n legend: {\n background: \"rgba(26, 26, 46, 0.9)\",\n textColor: \"#e2e8f0\",\n borderColor: \"rgba(255, 255, 255, 0.1)\",\n },\n cursor: {\n color: \"#00f2ff\",\n labelBackground: \"rgba(0, 242, 255, 0.9)\",\n labelColor: \"#000000\",\n },\n seriesPalette: [\"#00f2ff\", \"#4ecdc4\", \"#ff6b6b\", \"#ffd93d\", \"#6c5ce7\", \"#a29bfe\", \"#fd79a8\", \"#00cec9\"],\n highlightColor: \"#00f2ff\",\n },\n },\n {\n name: \"Light\",\n description: \"Clean light theme for publications\",\n previewColors: [\"#ffffff\", \"#2563eb\", \"#4f46e5\"],\n tags: [\"light\", \"publication\"],\n theme: {\n backgroundColor: \"#ffffff\",\n plotAreaBackground: \"#f8fafc\",\n axis: {\n color: \"#94a3b8\",\n labelColor: \"#475569\",\n titleColor: \"#1e293b\",\n labelFontSize: 11,\n titleFontSize: 13,\n },\n grid: {\n color: \"rgba(148, 163, 184, 0.3)\",\n opacity: 0.3,\n },\n legend: {\n backgroundColor: \"rgba(255, 255, 255, 0.95)\",\n textColor: \"#1e293b\",\n borderColor: \"rgba(0, 0, 0, 0.1)\",\n },\n cursor: {\n color: \"#2563eb\",\n labelBackground: \"rgba(37, 99, 235, 0.95)\",\n labelColor: \"#ffffff\",\n },\n seriesPalette: [\"#2563eb\", \"#7c3aed\", \"#db2777\", \"#ea580c\", \"#16a34a\", \"#0891b2\", \"#4f46e5\", \"#be185d\"],\n highlightColor: \"#2563eb\",\n },\n },\n {\n name: \"Midnight\",\n description: \"Deep blue dark theme\",\n previewColors: [\"#0f172a\", \"#3b82f6\", \"#8b5cf6\"],\n tags: [\"dark\", \"blue\"],\n theme: {\n backgroundColor: \"#0f172a\",\n plotAreaBackground: \"#1e293b\",\n axis: {\n color: \"#475569\",\n labelColor: \"#94a3b8\",\n titleColor: \"#f1f5f9\",\n labelFontSize: 11,\n titleFontSize: 13,\n },\n grid: {\n color: \"rgba(71, 85, 105, 0.25)\",\n opacity: 0.25,\n },\n legend: {\n backgroundColor: \"rgba(15, 23, 42, 0.95)\",\n textColor: \"#f1f5f9\",\n borderColor: \"rgba(255, 255, 255, 0.08)\",\n },\n cursor: {\n color: \"#3b82f6\",\n labelBackground: \"rgba(59, 130, 246, 0.95)\",\n labelColor: \"#ffffff\",\n },\n seriesPalette: [\"#3b82f6\", \"#8b5cf6\", \"#ec4899\", \"#f59e0b\", \"#10b981\", \"#06b6d4\", \"#6366f1\", \"#f43f5e\"],\n highlightColor: \"#3b82f6\",\n },\n },\n {\n name: \"Scientific\",\n description: \"Clean theme for scientific publications\",\n previewColors: [\"#fafafa\", \"#1f2937\", \"#059669\"],\n tags: [\"light\", \"scientific\", \"publication\"],\n theme: {\n backgroundColor: \"#fafafa\",\n plotAreaBackground: \"#ffffff\",\n axis: {\n color: \"#374151\",\n labelColor: \"#1f2937\",\n titleColor: \"#111827\",\n labelFontSize: 12,\n titleFontSize: 14,\n },\n grid: {\n color: \"rgba(156, 163, 175, 0.4)\",\n opacity: 0.4,\n },\n legend: {\n backgroundColor: \"#ffffff\",\n textColor: \"#111827\",\n borderColor: \"#e5e7eb\",\n },\n cursor: {\n color: \"#059669\",\n labelBackground: \"#059669\",\n labelColor: \"#ffffff\",\n },\n seriesPalette: [\"#1f2937\", \"#059669\", \"#dc2626\", \"#2563eb\", \"#7c3aed\", \"#ea580c\", \"#0891b2\", \"#be123c\"],\n highlightColor: \"#059669\",\n },\n },\n {\n name: \"Electrochemistry\",\n description: \"Theme optimized for electrochemical data\",\n previewColors: [\"#0d1117\", \"#00f2ff\", \"#ff6b6b\"],\n tags: [\"dark\", \"scientific\", \"electrochemistry\"],\n theme: {\n backgroundColor: \"#0d1117\",\n plotAreaBackground: \"#161b22\",\n axis: {\n color: \"#30363d\",\n labelColor: \"#8b949e\",\n titleColor: \"#c9d1d9\",\n labelFontSize: 11,\n titleFontSize: 13,\n },\n grid: {\n color: \"rgba(48, 54, 61, 0.5)\",\n opacity: 0.5,\n },\n legend: {\n backgroundColor: \"rgba(13, 17, 23, 0.95)\",\n textColor: \"#c9d1d9\",\n borderColor: \"rgba(48, 54, 61, 0.8)\",\n },\n cursor: {\n color: \"#00f2ff\",\n labelBackground: \"rgba(0, 242, 255, 0.95)\",\n labelColor: \"#000000\",\n },\n seriesPalette: [\"#00f2ff\", \"#ff6b6b\", \"#4ecdc4\", \"#feca57\", \"#a29bfe\", \"#fd79a8\", \"#00cec9\", \"#e17055\"],\n highlightColor: \"#00f2ff\",\n },\n },\n {\n name: \"High Contrast\",\n description: \"Maximum visibility theme\",\n previewColors: [\"#000000\", \"#ffffff\", \"#ffff00\"],\n tags: [\"dark\", \"accessibility\", \"high-contrast\"],\n theme: {\n backgroundColor: \"#000000\",\n plotAreaBackground: \"#0a0a0a\",\n axis: {\n color: \"#ffffff\",\n labelColor: \"#ffffff\",\n titleColor: \"#ffffff\",\n labelFontSize: 12,\n titleFontSize: 14,\n },\n grid: {\n color: \"rgba(255, 255, 255, 0.2)\",\n opacity: 0.2,\n },\n legend: {\n backgroundColor: \"#000000\",\n textColor: \"#ffffff\",\n borderColor: \"#ffffff\",\n },\n cursor: {\n color: \"#ffff00\",\n labelBackground: \"#ffff00\",\n labelColor: \"#000000\",\n },\n seriesPalette: [\"#ffff00\", \"#00ffff\", \"#ff00ff\", \"#00ff00\", \"#ff8800\", \"#00ff88\", \"#8800ff\", \"#ff0088\"],\n highlightColor: \"#ffff00\",\n },\n },\n];\n\n// ============================================\n// Theme Editor Class\n// ============================================\n\nexport class ThemeEditor {\n private container: HTMLElement;\n private options: Required<ThemeEditorOptions>;\n private currentTheme: EditorTheme;\n private element: HTMLDivElement | null = null;\n\n constructor(container: HTMLElement, options?: ThemeEditorOptions) {\n this.container = container;\n this.options = {\n baseTheme: THEME_PRESETS[0].theme,\n livePreview: true,\n showAdvanced: false,\n className: 'velo-plot-theme-editor',\n onChange: undefined,\n onExport: undefined,\n ...options,\n } as Required<ThemeEditorOptions>;\n\n this.currentTheme = this.resolveTheme(this.options.baseTheme);\n this.render();\n }\n\n /**\n * Get current theme\n */\n getTheme(): EditorTheme {\n return { ...this.currentTheme };\n }\n\n /**\n * Set theme\n */\n setTheme(theme: EditorTheme | string): void {\n this.currentTheme = this.resolveTheme(theme);\n this.render();\n this.notifyChange();\n }\n\n /**\n * Update a specific theme property\n */\n updateProperty(key: string, value: string): void {\n this.setNestedValue(this.currentTheme, key, value);\n this.notifyChange();\n }\n\n /**\n * Export theme as JSON\n */\n exportTheme(): string {\n const json = JSON.stringify(this.currentTheme, null, 2);\n this.options.onExport?.(this.currentTheme, json);\n return json;\n }\n\n /**\n * Import theme from JSON\n */\n importTheme(json: string): void {\n try {\n const theme = JSON.parse(json) as EditorTheme;\n this.currentTheme = theme;\n this.render();\n this.notifyChange();\n } catch (e) {\n console.error('[ThemeEditor] Failed to import theme:', e);\n }\n }\n\n /**\n * Get theme preset by name\n */\n getPreset(name: string): ThemePreset | undefined {\n return THEME_PRESETS.find(p => p.name.toLowerCase() === name.toLowerCase());\n }\n\n /**\n * Apply a preset\n */\n applyPreset(name: string): void {\n const preset = this.getPreset(name);\n if (preset) {\n this.currentTheme = { ...preset.theme };\n this.render();\n this.notifyChange();\n }\n }\n\n /**\n * Get all available presets\n */\n getPresets(): ThemePreset[] {\n return THEME_PRESETS;\n }\n\n /**\n * Destroy the editor\n */\n destroy(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private resolveTheme(theme: EditorTheme | string): EditorTheme {\n if (typeof theme === 'string') {\n const preset = this.getPreset(theme);\n return preset ? { ...preset.theme } : { ...THEME_PRESETS[0].theme };\n }\n return { ...theme };\n }\n\n private setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {\n const keys = path.split('.');\n let current = obj;\n \n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n if (!(key in current)) {\n current[key] = {};\n }\n current = current[key] as Record<string, unknown>;\n }\n \n current[keys[keys.length - 1]] = value;\n }\n\n private getNestedValue(obj: Record<string, unknown>, path: string): unknown {\n const keys = path.split('.');\n let current: unknown = obj;\n \n for (const key of keys) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n \n return current;\n }\n\n private notifyChange(): void {\n if (this.options.livePreview) {\n this.options.onChange?.(this.currentTheme);\n }\n }\n\n private render(): void {\n // This creates an HTML structure that can be styled with CSS\n // In a real implementation, this would create interactive color pickers\n if (!this.element) {\n this.element = document.createElement('div');\n this.element.className = this.options.className;\n this.container.appendChild(this.element);\n }\n\n this.element.innerHTML = this.generateHTML();\n this.attachEventListeners();\n }\n\n private generateHTML(): string {\n const presetButtons = THEME_PRESETS.map(preset => `\n <button class=\"preset-btn\" data-preset=\"${preset.name}\" title=\"${preset.description || preset.name}\">\n <div class=\"preset-colors\">\n ${(preset.previewColors || []).map(c => `<span style=\"background:${c}\"></span>`).join('')}\n </div>\n <span class=\"preset-name\">${preset.name}</span>\n </button>\n `).join('');\n\n const colorGroups = THEME_COLOR_GROUPS.map(group => {\n const colorInputs = group.colors.map(color => {\n const value = this.getNestedValue(this.currentTheme as Record<string, unknown>, color.key) as string || '#000000';\n return `\n <div class=\"color-row\">\n <label title=\"${color.description || ''}\">${color.label}</label>\n <input type=\"color\" data-key=\"${color.key}\" value=\"${this.normalizeColor(value)}\" />\n <input type=\"text\" data-key=\"${color.key}\" value=\"${value}\" class=\"color-text\" />\n </div>\n `;\n }).join('');\n\n return `\n <div class=\"color-group\">\n <h4>${group.label}</h4>\n ${group.description ? `<p class=\"group-desc\">${group.description}</p>` : ''}\n ${colorInputs}\n </div>\n `;\n }).join('');\n\n return `\n <div class=\"theme-editor-inner\">\n <div class=\"presets-section\">\n <h3>Presets</h3>\n <div class=\"presets-grid\">${presetButtons}</div>\n </div>\n <div class=\"colors-section\">\n <h3>Customize</h3>\n ${colorGroups}\n </div>\n <div class=\"actions-section\">\n <button class=\"export-btn\">Export JSON</button>\n <button class=\"import-btn\">Import JSON</button>\n </div>\n </div>\n `;\n }\n\n private normalizeColor(color: string): string {\n // Convert rgba/rgb to hex for color picker\n if (color.startsWith('rgba') || color.startsWith('rgb')) {\n const match = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (match) {\n const r = parseInt(match[1]).toString(16).padStart(2, '0');\n const g = parseInt(match[2]).toString(16).padStart(2, '0');\n const b = parseInt(match[3]).toString(16).padStart(2, '0');\n return `#${r}${g}${b}`;\n }\n }\n return color;\n }\n\n private attachEventListeners(): void {\n if (!this.element) return;\n\n // Preset buttons\n this.element.querySelectorAll('.preset-btn').forEach(btn => {\n btn.addEventListener('click', () => {\n const presetName = btn.getAttribute('data-preset');\n if (presetName) {\n this.applyPreset(presetName);\n }\n });\n });\n\n // Color inputs\n this.element.querySelectorAll('input[type=\"color\"], input.color-text').forEach(input => {\n input.addEventListener('input', (e) => {\n const target = e.target as HTMLInputElement;\n const key = target.getAttribute('data-key');\n if (key) {\n this.updateProperty(key, target.value);\n // Sync color picker and text input\n const sibling = target.type === 'color' \n ? target.nextElementSibling as HTMLInputElement\n : target.previousElementSibling as HTMLInputElement;\n if (sibling) {\n sibling.value = target.type === 'color' ? target.value : this.normalizeColor(target.value);\n }\n }\n });\n });\n\n // Export button\n this.element.querySelector('.export-btn')?.addEventListener('click', () => {\n const json = this.exportTheme();\n navigator.clipboard?.writeText(json).then(() => {\n });\n });\n\n // Import button\n this.element.querySelector('.import-btn')?.addEventListener('click', () => {\n const json = prompt('Paste theme JSON:');\n if (json) {\n this.importTheme(json);\n }\n });\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\n/**\n * Create a theme editor instance\n */\nexport function createThemeEditor(\n container: HTMLElement,\n options?: ThemeEditorOptions\n): ThemeEditor {\n return new ThemeEditor(container, options);\n}\n\n/**\n * Get a preset theme by name\n */\nexport function getPresetTheme(name: string): EditorTheme | undefined {\n const preset = THEME_PRESETS.find(p => p.name.toLowerCase() === name.toLowerCase());\n return preset ? { ...preset.theme } : undefined;\n}\n\n/**\n * Get all preset names\n */\nexport function getPresetNames(): string[] {\n return THEME_PRESETS.map(p => p.name);\n}\n","/**\n * Sci Plot - Theme Editor Plugin\n * \n * Provides a visual interface for editing chart themes in real-time.\n * \n * @module plugins/theme-editor\n */\n\nimport { ThemeEditor } from \"../../core/theme-editor\";\nimport type { EditorTheme, ThemePreset } from \"../../core/theme-editor\";\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginThemeEditorConfig {\n /** Initial theme to edit */\n initialTheme?: string;\n /** Position in the UI */\n position?: \"left\" | \"right\";\n}\n\nconst manifestThemeEditor: PluginManifest = {\n name: \"velo-plot-theme-editor\",\n version: \"1.0.0\",\n description: \"Visual theme editor for velo-plot\",\n provides: [\"ui\", \"theme\"],\n tags: [\"theme\", \"editor\", \"styling\", \"ui\"],\n};\n\n/**\n * SciPlot Theme Editor Plugin\n * \n * Adds a visual panel to customize chart colors and styles.\n */\nexport function PluginThemeEditor(_config: PluginThemeEditorConfig = {}): ChartPlugin<PluginThemeEditorConfig> {\n return {\n manifest: manifestThemeEditor,\n\n onInit(_ctx: PluginContext) {\n },\n\n onDestroy(_ctx: PluginContext) {\n }\n };\n}\n\nexport { ThemeEditor };\nexport type { EditorTheme, ThemePreset };\nexport default PluginThemeEditor;\n"],"names":["THEME_COLOR_GROUPS","THEME_PRESETS","ThemeEditor","container","options","__publicField","theme","key","value","_a","_b","json","e","name","p","preset","obj","path","keys","current","i","presetButtons","c","colorGroups","group","colorInputs","color","match","r","g","b","btn","presetName","input","target","sibling","createThemeEditor","getPresetTheme","getPresetNames","manifestThemeEditor","PluginThemeEditor","_config","_ctx"],"mappings":"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"}
1
+ {"version":3,"file":"index-Dag88bW4.js","sources":["../src/core/theme-editor/index.ts","../src/plugins/theme-editor/index.ts"],"sourcesContent":["/**\n * Velo Plot - Theme Editor Module\n * \n * Provides a visual theme editor for customizing chart appearance:\n * - Color pickers for all theme elements\n * - Live preview\n * - Theme export/import\n * - Preset theme gallery\n * \n * @module theme-editor\n */\n\n// Use a flexible internal type to avoid strict EditorTheme compatibility issues\n// The editor works with partial theme configs that can be applied via createTheme()\nexport type EditorTheme = Record<string, unknown>;\n\n// ============================================\n// Types\n// ============================================\n\nexport interface ThemeEditorOptions {\n /** Base theme to start from */\n baseTheme?: EditorTheme | string;\n /** Enable live preview (default: true) */\n livePreview?: boolean;\n /** Show advanced options (default: false) */\n showAdvanced?: boolean;\n /** Custom CSS class for the editor */\n className?: string;\n /** Callback when theme changes */\n onChange?: (theme: EditorTheme) => void;\n /** Callback when export is requested */\n onExport?: (theme: EditorTheme, json: string) => void;\n}\n\nexport interface ThemePreset {\n /** Preset name */\n name: string;\n /** Description */\n description?: string;\n /** Theme configuration */\n theme: EditorTheme;\n /** Preview colors (for UI) */\n previewColors?: string[];\n /** Tags for filtering */\n tags?: string[];\n}\n\nexport interface ColorGroup {\n /** Group label */\n label: string;\n /** Group description */\n description?: string;\n /** Color properties in this group */\n colors: ColorProperty[];\n}\n\nexport interface ColorProperty {\n /** Property key path (e.g., 'background', 'axis.color') */\n key: string;\n /** Display label */\n label: string;\n /** Description/tooltip */\n description?: string;\n /** Current value */\n value: string;\n /** Default value */\n defaultValue?: string;\n}\n\n// ============================================\n// Default Theme Structure\n// ============================================\n\nconst THEME_COLOR_GROUPS: ColorGroup[] = [\n {\n label: \"Background & Canvas\",\n description: \"Chart background and canvas colors\",\n colors: [\n { key: \"backgroundColor\", label: \"Background\", value: \"\", description: \"Main chart background\" },\n { key: \"plotAreaBackground\", label: \"Plot Area\", value: \"\", description: \"Data plotting area background\" },\n ],\n },\n {\n label: \"Axes\",\n description: \"Axis lines, ticks, and labels\",\n colors: [\n { key: \"axis.color\", label: \"Axis Lines\", value: \"\", description: \"Axis line color\" },\n { key: \"axis.labelColor\", label: \"Axis Labels\", value: \"\", description: \"Axis label text color\" },\n { key: \"axis.titleColor\", label: \"Axis Titles\", value: \"\", description: \"Axis title text color\" },\n ],\n },\n {\n label: \"Grid\",\n description: \"Grid lines and markers\",\n colors: [\n { key: \"grid.color\", label: \"Grid Lines\", value: \"\", description: \"Major grid line color\" },\n { key: \"grid.minorColor\", label: \"Minor Grid\", value: \"\", description: \"Minor grid line color\" },\n ],\n },\n {\n label: \"Series Palette\",\n description: \"Default colors for data series\",\n colors: [\n { key: \"seriesPalette.0\", label: \"Series 1\", value: \"\", description: \"First series color\" },\n { key: \"seriesPalette.1\", label: \"Series 2\", value: \"\", description: \"Second series color\" },\n { key: \"seriesPalette.2\", label: \"Series 3\", value: \"\", description: \"Third series color\" },\n { key: \"seriesPalette.3\", label: \"Series 4\", value: \"\", description: \"Fourth series color\" },\n { key: \"seriesPalette.4\", label: \"Series 5\", value: \"\", description: \"Fifth series color\" },\n { key: \"seriesPalette.5\", label: \"Series 6\", value: \"\", description: \"Sixth series color\" },\n ],\n },\n {\n label: \"Legend\",\n description: \"Legend styling\",\n colors: [\n { key: \"legend.backgroundColor\", label: \"Legend Background\", value: \"\", description: \"Legend panel background\" },\n { key: \"legend.textColor\", label: \"Legend Text\", value: \"\", description: \"Legend text color\" },\n { key: \"legend.borderColor\", label: \"Legend Border\", value: \"\", description: \"Legend border color\" },\n ],\n },\n {\n label: \"Cursor & Selection\",\n description: \"Interactive elements\",\n colors: [\n { key: \"cursor.color\", label: \"Crosshair\", value: \"\", description: \"Cursor crosshair color\" },\n { key: \"cursor.labelBackground\", label: \"Cursor Label BG\", value: \"\", description: \"Cursor label background\" },\n { key: \"selection.color\", label: \"Selection\", value: \"\", description: \"Selection highlight color\" },\n { key: \"selection.handleColor\", label: \"Selection Handles\", value: \"\", description: \"Selection handle color\" },\n ],\n },\n {\n label: \"Annotations\",\n description: \"Annotation default colors\",\n colors: [\n { key: \"annotation.lineColor\", label: \"Line Annotations\", value: \"\", description: \"Default line annotation color\" },\n { key: \"annotation.fillColor\", label: \"Fill Annotations\", value: \"\", description: \"Default fill annotation color\" },\n { key: \"annotation.textColor\", label: \"Text Annotations\", value: \"\", description: \"Default text annotation color\" },\n ],\n },\n];\n\n// ============================================\n// Theme Presets\n// ============================================\n\nexport const THEME_PRESETS: ThemePreset[] = [\n {\n name: \"Dark\",\n description: \"Classic dark theme with cyan accents\",\n previewColors: [\"#1a1a2e\", \"#00f2ff\", \"#4ecdc4\"],\n tags: [\"dark\", \"default\"],\n theme: {\n backgroundColor: \"#1a1a2e\",\n plotAreaBackground: \"#16213e\",\n axis: {\n color: \"#4a5568\",\n labelColor: \"#a0aec0\",\n titleColor: \"#e2e8f0\",\n labelFontSize: 11,\n titleFontSize: 13,\n },\n grid: {\n color: \"rgba(74, 85, 104, 0.3)\",\n opacity: 0.3,\n },\n legend: {\n background: \"rgba(26, 26, 46, 0.9)\",\n textColor: \"#e2e8f0\",\n borderColor: \"rgba(255, 255, 255, 0.1)\",\n },\n cursor: {\n color: \"#00f2ff\",\n labelBackground: \"rgba(0, 242, 255, 0.9)\",\n labelColor: \"#000000\",\n },\n seriesPalette: [\"#00f2ff\", \"#4ecdc4\", \"#ff6b6b\", \"#ffd93d\", \"#6c5ce7\", \"#a29bfe\", \"#fd79a8\", \"#00cec9\"],\n highlightColor: \"#00f2ff\",\n },\n },\n {\n name: \"Light\",\n description: \"Clean light theme for publications\",\n previewColors: [\"#ffffff\", \"#2563eb\", \"#4f46e5\"],\n tags: [\"light\", \"publication\"],\n theme: {\n backgroundColor: \"#ffffff\",\n plotAreaBackground: \"#f8fafc\",\n axis: {\n color: \"#94a3b8\",\n labelColor: \"#475569\",\n titleColor: \"#1e293b\",\n labelFontSize: 11,\n titleFontSize: 13,\n },\n grid: {\n color: \"rgba(148, 163, 184, 0.3)\",\n opacity: 0.3,\n },\n legend: {\n backgroundColor: \"rgba(255, 255, 255, 0.95)\",\n textColor: \"#1e293b\",\n borderColor: \"rgba(0, 0, 0, 0.1)\",\n },\n cursor: {\n color: \"#2563eb\",\n labelBackground: \"rgba(37, 99, 235, 0.95)\",\n labelColor: \"#ffffff\",\n },\n seriesPalette: [\"#2563eb\", \"#7c3aed\", \"#db2777\", \"#ea580c\", \"#16a34a\", \"#0891b2\", \"#4f46e5\", \"#be185d\"],\n highlightColor: \"#2563eb\",\n },\n },\n {\n name: \"Midnight\",\n description: \"Deep blue dark theme\",\n previewColors: [\"#0f172a\", \"#3b82f6\", \"#8b5cf6\"],\n tags: [\"dark\", \"blue\"],\n theme: {\n backgroundColor: \"#0f172a\",\n plotAreaBackground: \"#1e293b\",\n axis: {\n color: \"#475569\",\n labelColor: \"#94a3b8\",\n titleColor: \"#f1f5f9\",\n labelFontSize: 11,\n titleFontSize: 13,\n },\n grid: {\n color: \"rgba(71, 85, 105, 0.25)\",\n opacity: 0.25,\n },\n legend: {\n backgroundColor: \"rgba(15, 23, 42, 0.95)\",\n textColor: \"#f1f5f9\",\n borderColor: \"rgba(255, 255, 255, 0.08)\",\n },\n cursor: {\n color: \"#3b82f6\",\n labelBackground: \"rgba(59, 130, 246, 0.95)\",\n labelColor: \"#ffffff\",\n },\n seriesPalette: [\"#3b82f6\", \"#8b5cf6\", \"#ec4899\", \"#f59e0b\", \"#10b981\", \"#06b6d4\", \"#6366f1\", \"#f43f5e\"],\n highlightColor: \"#3b82f6\",\n },\n },\n {\n name: \"Scientific\",\n description: \"Clean theme for scientific publications\",\n previewColors: [\"#fafafa\", \"#1f2937\", \"#059669\"],\n tags: [\"light\", \"scientific\", \"publication\"],\n theme: {\n backgroundColor: \"#fafafa\",\n plotAreaBackground: \"#ffffff\",\n axis: {\n color: \"#374151\",\n labelColor: \"#1f2937\",\n titleColor: \"#111827\",\n labelFontSize: 12,\n titleFontSize: 14,\n },\n grid: {\n color: \"rgba(156, 163, 175, 0.4)\",\n opacity: 0.4,\n },\n legend: {\n backgroundColor: \"#ffffff\",\n textColor: \"#111827\",\n borderColor: \"#e5e7eb\",\n },\n cursor: {\n color: \"#059669\",\n labelBackground: \"#059669\",\n labelColor: \"#ffffff\",\n },\n seriesPalette: [\"#1f2937\", \"#059669\", \"#dc2626\", \"#2563eb\", \"#7c3aed\", \"#ea580c\", \"#0891b2\", \"#be123c\"],\n highlightColor: \"#059669\",\n },\n },\n {\n name: \"Electrochemistry\",\n description: \"Theme optimized for electrochemical data\",\n previewColors: [\"#0d1117\", \"#00f2ff\", \"#ff6b6b\"],\n tags: [\"dark\", \"scientific\", \"electrochemistry\"],\n theme: {\n backgroundColor: \"#0d1117\",\n plotAreaBackground: \"#161b22\",\n axis: {\n color: \"#30363d\",\n labelColor: \"#8b949e\",\n titleColor: \"#c9d1d9\",\n labelFontSize: 11,\n titleFontSize: 13,\n },\n grid: {\n color: \"rgba(48, 54, 61, 0.5)\",\n opacity: 0.5,\n },\n legend: {\n backgroundColor: \"rgba(13, 17, 23, 0.95)\",\n textColor: \"#c9d1d9\",\n borderColor: \"rgba(48, 54, 61, 0.8)\",\n },\n cursor: {\n color: \"#00f2ff\",\n labelBackground: \"rgba(0, 242, 255, 0.95)\",\n labelColor: \"#000000\",\n },\n seriesPalette: [\"#00f2ff\", \"#ff6b6b\", \"#4ecdc4\", \"#feca57\", \"#a29bfe\", \"#fd79a8\", \"#00cec9\", \"#e17055\"],\n highlightColor: \"#00f2ff\",\n },\n },\n {\n name: \"High Contrast\",\n description: \"Maximum visibility theme\",\n previewColors: [\"#000000\", \"#ffffff\", \"#ffff00\"],\n tags: [\"dark\", \"accessibility\", \"high-contrast\"],\n theme: {\n backgroundColor: \"#000000\",\n plotAreaBackground: \"#0a0a0a\",\n axis: {\n color: \"#ffffff\",\n labelColor: \"#ffffff\",\n titleColor: \"#ffffff\",\n labelFontSize: 12,\n titleFontSize: 14,\n },\n grid: {\n color: \"rgba(255, 255, 255, 0.2)\",\n opacity: 0.2,\n },\n legend: {\n backgroundColor: \"#000000\",\n textColor: \"#ffffff\",\n borderColor: \"#ffffff\",\n },\n cursor: {\n color: \"#ffff00\",\n labelBackground: \"#ffff00\",\n labelColor: \"#000000\",\n },\n seriesPalette: [\"#ffff00\", \"#00ffff\", \"#ff00ff\", \"#00ff00\", \"#ff8800\", \"#00ff88\", \"#8800ff\", \"#ff0088\"],\n highlightColor: \"#ffff00\",\n },\n },\n];\n\n// ============================================\n// Theme Editor Class\n// ============================================\n\nexport class ThemeEditor {\n private container: HTMLElement;\n private options: Required<ThemeEditorOptions>;\n private currentTheme: EditorTheme;\n private element: HTMLDivElement | null = null;\n\n constructor(container: HTMLElement, options?: ThemeEditorOptions) {\n this.container = container;\n this.options = {\n baseTheme: THEME_PRESETS[0].theme,\n livePreview: true,\n showAdvanced: false,\n className: 'velo-plot-theme-editor',\n onChange: undefined,\n onExport: undefined,\n ...options,\n } as Required<ThemeEditorOptions>;\n\n this.currentTheme = this.resolveTheme(this.options.baseTheme);\n this.render();\n }\n\n /**\n * Get current theme\n */\n getTheme(): EditorTheme {\n return { ...this.currentTheme };\n }\n\n /**\n * Set theme\n */\n setTheme(theme: EditorTheme | string): void {\n this.currentTheme = this.resolveTheme(theme);\n this.render();\n this.notifyChange();\n }\n\n /**\n * Update a specific theme property\n */\n updateProperty(key: string, value: string): void {\n this.setNestedValue(this.currentTheme, key, value);\n this.notifyChange();\n }\n\n /**\n * Export theme as JSON\n */\n exportTheme(): string {\n const json = JSON.stringify(this.currentTheme, null, 2);\n this.options.onExport?.(this.currentTheme, json);\n return json;\n }\n\n /**\n * Import theme from JSON\n */\n importTheme(json: string): void {\n try {\n const theme = JSON.parse(json) as EditorTheme;\n this.currentTheme = theme;\n this.render();\n this.notifyChange();\n } catch (e) {\n console.error('[ThemeEditor] Failed to import theme:', e);\n }\n }\n\n /**\n * Get theme preset by name\n */\n getPreset(name: string): ThemePreset | undefined {\n return THEME_PRESETS.find(p => p.name.toLowerCase() === name.toLowerCase());\n }\n\n /**\n * Apply a preset\n */\n applyPreset(name: string): void {\n const preset = this.getPreset(name);\n if (preset) {\n this.currentTheme = { ...preset.theme };\n this.render();\n this.notifyChange();\n }\n }\n\n /**\n * Get all available presets\n */\n getPresets(): ThemePreset[] {\n return THEME_PRESETS;\n }\n\n /**\n * Destroy the editor\n */\n destroy(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private resolveTheme(theme: EditorTheme | string): EditorTheme {\n if (typeof theme === 'string') {\n const preset = this.getPreset(theme);\n return preset ? { ...preset.theme } : { ...THEME_PRESETS[0].theme };\n }\n return { ...theme };\n }\n\n private setNestedValue(obj: Record<string, unknown>, path: string, value: unknown): void {\n const keys = path.split('.');\n let current = obj;\n \n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n if (!(key in current)) {\n current[key] = {};\n }\n current = current[key] as Record<string, unknown>;\n }\n \n current[keys[keys.length - 1]] = value;\n }\n\n private getNestedValue(obj: Record<string, unknown>, path: string): unknown {\n const keys = path.split('.');\n let current: unknown = obj;\n \n for (const key of keys) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return undefined;\n }\n current = (current as Record<string, unknown>)[key];\n }\n \n return current;\n }\n\n private notifyChange(): void {\n if (this.options.livePreview) {\n this.options.onChange?.(this.currentTheme);\n }\n }\n\n private render(): void {\n // This creates an HTML structure that can be styled with CSS\n // In a real implementation, this would create interactive color pickers\n if (!this.element) {\n this.element = document.createElement('div');\n this.element.className = this.options.className;\n this.container.appendChild(this.element);\n }\n\n this.element.innerHTML = this.generateHTML();\n this.attachEventListeners();\n }\n\n private generateHTML(): string {\n const presetButtons = THEME_PRESETS.map(preset => `\n <button class=\"preset-btn\" data-preset=\"${preset.name}\" title=\"${preset.description || preset.name}\">\n <div class=\"preset-colors\">\n ${(preset.previewColors || []).map(c => `<span style=\"background:${c}\"></span>`).join('')}\n </div>\n <span class=\"preset-name\">${preset.name}</span>\n </button>\n `).join('');\n\n const colorGroups = THEME_COLOR_GROUPS.map(group => {\n const colorInputs = group.colors.map(color => {\n const value = this.getNestedValue(this.currentTheme as Record<string, unknown>, color.key) as string || '#000000';\n return `\n <div class=\"color-row\">\n <label title=\"${color.description || ''}\">${color.label}</label>\n <input type=\"color\" data-key=\"${color.key}\" value=\"${this.normalizeColor(value)}\" />\n <input type=\"text\" data-key=\"${color.key}\" value=\"${value}\" class=\"color-text\" />\n </div>\n `;\n }).join('');\n\n return `\n <div class=\"color-group\">\n <h4>${group.label}</h4>\n ${group.description ? `<p class=\"group-desc\">${group.description}</p>` : ''}\n ${colorInputs}\n </div>\n `;\n }).join('');\n\n return `\n <div class=\"theme-editor-inner\">\n <div class=\"presets-section\">\n <h3>Presets</h3>\n <div class=\"presets-grid\">${presetButtons}</div>\n </div>\n <div class=\"colors-section\">\n <h3>Customize</h3>\n ${colorGroups}\n </div>\n <div class=\"actions-section\">\n <button class=\"export-btn\">Export JSON</button>\n <button class=\"import-btn\">Import JSON</button>\n </div>\n </div>\n `;\n }\n\n private normalizeColor(color: string): string {\n // Convert rgba/rgb to hex for color picker\n if (color.startsWith('rgba') || color.startsWith('rgb')) {\n const match = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (match) {\n const r = parseInt(match[1]).toString(16).padStart(2, '0');\n const g = parseInt(match[2]).toString(16).padStart(2, '0');\n const b = parseInt(match[3]).toString(16).padStart(2, '0');\n return `#${r}${g}${b}`;\n }\n }\n return color;\n }\n\n private attachEventListeners(): void {\n if (!this.element) return;\n\n // Preset buttons\n this.element.querySelectorAll('.preset-btn').forEach(btn => {\n btn.addEventListener('click', () => {\n const presetName = btn.getAttribute('data-preset');\n if (presetName) {\n this.applyPreset(presetName);\n }\n });\n });\n\n // Color inputs\n this.element.querySelectorAll('input[type=\"color\"], input.color-text').forEach(input => {\n input.addEventListener('input', (e) => {\n const target = e.target as HTMLInputElement;\n const key = target.getAttribute('data-key');\n if (key) {\n this.updateProperty(key, target.value);\n // Sync color picker and text input\n const sibling = target.type === 'color' \n ? target.nextElementSibling as HTMLInputElement\n : target.previousElementSibling as HTMLInputElement;\n if (sibling) {\n sibling.value = target.type === 'color' ? target.value : this.normalizeColor(target.value);\n }\n }\n });\n });\n\n // Export button\n this.element.querySelector('.export-btn')?.addEventListener('click', () => {\n const json = this.exportTheme();\n navigator.clipboard?.writeText(json).then(() => {\n });\n });\n\n // Import button\n this.element.querySelector('.import-btn')?.addEventListener('click', () => {\n const json = prompt('Paste theme JSON:');\n if (json) {\n this.importTheme(json);\n }\n });\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\n/**\n * Create a theme editor instance\n */\nexport function createThemeEditor(\n container: HTMLElement,\n options?: ThemeEditorOptions\n): ThemeEditor {\n return new ThemeEditor(container, options);\n}\n\n/**\n * Get a preset theme by name\n */\nexport function getPresetTheme(name: string): EditorTheme | undefined {\n const preset = THEME_PRESETS.find(p => p.name.toLowerCase() === name.toLowerCase());\n return preset ? { ...preset.theme } : undefined;\n}\n\n/**\n * Get all preset names\n */\nexport function getPresetNames(): string[] {\n return THEME_PRESETS.map(p => p.name);\n}\n","/**\n * Velo Plot - Theme Editor Plugin\n * \n * Provides a visual interface for editing chart themes in real-time.\n * \n * @module plugins/theme-editor\n */\n\nimport { ThemeEditor } from \"../../core/theme-editor\";\nimport type { EditorTheme, ThemePreset } from \"../../core/theme-editor\";\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginThemeEditorConfig {\n /** Initial theme to edit */\n initialTheme?: string;\n /** Position in the UI */\n position?: \"left\" | \"right\";\n}\n\nconst manifestThemeEditor: PluginManifest = {\n name: \"velo-plot-theme-editor\",\n version: \"1.0.0\",\n description: \"Visual theme editor for velo-plot\",\n provides: [\"ui\", \"theme\"],\n tags: [\"theme\", \"editor\", \"styling\", \"ui\"],\n};\n\n/**\n * VeloPlot Theme Editor Plugin\n * \n * Adds a visual panel to customize chart colors and styles.\n */\nexport function PluginThemeEditor(_config: PluginThemeEditorConfig = {}): ChartPlugin<PluginThemeEditorConfig> {\n return {\n manifest: manifestThemeEditor,\n\n onInit(_ctx: PluginContext) {\n },\n\n onDestroy(_ctx: PluginContext) {\n }\n };\n}\n\nexport { ThemeEditor };\nexport type { EditorTheme, ThemePreset };\nexport default PluginThemeEditor;\n"],"names":["THEME_COLOR_GROUPS","THEME_PRESETS","ThemeEditor","container","options","__publicField","theme","key","value","_a","_b","json","e","name","p","preset","obj","path","keys","current","i","presetButtons","c","colorGroups","group","colorInputs","color","match","r","g","b","btn","presetName","input","target","sibling","createThemeEditor","getPresetTheme","getPresetNames","manifestThemeEditor","PluginThemeEditor","_config","_ctx"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index-qhscKTDy.js","sources":["../src/core/loading/index.ts","../src/plugins/loading/index.ts"],"sourcesContent":["/**\n * Sci Plot - Loading Indicator Module\n * \n * Provides visual loading/progress indicators for chart operations.\n * Supports progress bars, spinners, and skeleton placeholders.\n * \n * @module loading\n */\n\n// ============================================\n// Types\n// ============================================\n\nexport type LoadingIndicatorType = 'spinner' | 'progress' | 'skeleton' | 'pulse';\n\nexport interface LoadingIndicatorOptions {\n /** Indicator type (default: 'spinner') */\n type?: LoadingIndicatorType;\n /** Message to display (default: 'Loading...') */\n message?: string;\n /** Show percentage for progress type (default: true) */\n showPercentage?: boolean;\n /** Background overlay opacity (0-1, default: 0.7) */\n overlayOpacity?: number;\n /** Accent color for spinner/progress (default: '#00f2ff') */\n accentColor?: string;\n /** Background color (default: 'rgba(0,0,0,0.7)') */\n backgroundColor?: string;\n /** Text color (default: '#ffffff') */\n textColor?: string;\n /** Size: 'small', 'medium', 'large' (default: 'medium') */\n size?: 'small' | 'medium' | 'large';\n /** Custom CSS class */\n className?: string;\n /** Auto-hide after completion (default: true) */\n autoHide?: boolean;\n /** Hide delay in ms after completion (default: 300) */\n hideDelay?: number;\n}\n\nexport interface LoadingState {\n /** Whether loading is in progress */\n isLoading: boolean;\n /** Progress value (0-100) */\n progress: number;\n /** Current message */\n message: string;\n /** Start time of loading */\n startTime: number | null;\n /** Estimated time remaining in ms */\n eta: number | null;\n}\n\n// ============================================\n// Loading Indicator Implementation\n// ============================================\n\nexport class LoadingIndicator {\n private container: HTMLElement;\n private element: HTMLDivElement | null = null;\n private options: Required<LoadingIndicatorOptions>;\n private state: LoadingState = {\n isLoading: false,\n progress: 0,\n message: '',\n startTime: null,\n eta: null,\n };\n\n // For ETA calculation\n private progressHistory: { time: number; progress: number }[] = [];\n\n constructor(container: HTMLElement, options?: LoadingIndicatorOptions) {\n this.container = container;\n this.options = {\n type: 'spinner',\n message: 'Loading...',\n showPercentage: true,\n overlayOpacity: 0.7,\n accentColor: '#00f2ff',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n textColor: '#ffffff',\n size: 'medium',\n className: 'velo-plot-loading',\n autoHide: true,\n hideDelay: 200,\n ...options,\n };\n this.state.message = this.options.message;\n }\n\n /**\n * Show the loading indicator\n */\n show(message?: string): void {\n this.state.isLoading = true;\n this.state.progress = 0;\n this.state.startTime = performance.now();\n this.state.eta = null;\n this.progressHistory = [];\n \n if (message) {\n this.state.message = message;\n }\n\n this.createElement();\n this.render();\n }\n\n /**\n * Hide the loading indicator\n */\n hide(): void {\n if (!this.state.isLoading) return;\n this.state.isLoading = false;\n \n if (this.element) {\n this.element.style.opacity = '0';\n }\n\n if (this.options.autoHide) {\n setTimeout(() => {\n this.destroyElement();\n }, this.options.hideDelay);\n } else {\n this.destroyElement();\n }\n }\n\n /**\n * Update progress (0-100)\n */\n setProgress(progress: number, message?: string): void {\n const clampedProgress = Math.max(0, Math.min(100, progress));\n this.state.progress = clampedProgress;\n \n if (message) {\n this.state.message = message;\n }\n\n // Track progress for ETA\n this.progressHistory.push({\n time: performance.now(),\n progress: clampedProgress,\n });\n\n // Keep only recent history\n if (this.progressHistory.length > 10) {\n this.progressHistory.shift();\n }\n\n // Calculate ETA\n this.calculateEta();\n \n this.render();\n\n // Auto-complete\n if (clampedProgress >= 100 && this.options.autoHide) {\n this.hide();\n }\n }\n\n /**\n * Update message only\n */\n setMessage(message: string): void {\n this.state.message = message;\n this.render();\n }\n\n /**\n * Check if loading is in progress\n */\n isLoading(): boolean {\n return this.state.isLoading;\n }\n\n /**\n * Get current progress\n */\n getProgress(): number {\n return this.state.progress;\n }\n\n /**\n * Get current state\n */\n getState(): LoadingState {\n return { ...this.state };\n }\n\n /**\n * Destroy the indicator\n */\n destroy(): void {\n this.hide();\n this.destroyElement();\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private createElement(): void {\n if (this.element) return;\n\n this.element = document.createElement('div');\n this.element.className = this.options.className;\n \n // Apply overlay styles\n Object.assign(this.element.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n right: '0',\n bottom: '0',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: this.options.backgroundColor,\n zIndex: '9998',\n transition: 'opacity 0.2s ease',\n });\n\n // Create inner content\n this.element.innerHTML = this.getInnerHtml();\n \n // Inject styles\n this.injectStyles();\n\n this.container.style.position = 'relative';\n this.container.appendChild(this.element);\n }\n\n private destroyElement(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n }\n\n private render(): void {\n if (!this.element) return;\n this.element.innerHTML = this.getInnerHtml();\n }\n\n private getInnerHtml(): string {\n const { type, accentColor, textColor, size, showPercentage } = this.options;\n const { progress, message, eta } = this.state;\n \n const sizeMap = { small: 24, medium: 40, large: 56 };\n const spinnerSize = sizeMap[size];\n const fontSize = size === 'small' ? 12 : size === 'large' ? 16 : 14;\n\n let content = '';\n\n switch (type) {\n case 'spinner':\n content = `\n <div class=\"velo-plot-loading-spinner\" style=\"\n width: ${spinnerSize}px;\n height: ${spinnerSize}px;\n border: 3px solid rgba(255,255,255,0.2);\n border-top-color: ${accentColor};\n border-radius: 50%;\n animation: velo-plot-spin 0.8s linear infinite;\n \"></div>\n `;\n break;\n\n case 'progress':\n content = `\n <div class=\"velo-plot-loading-progress\" style=\"\n width: 200px;\n height: 8px;\n background: rgba(255,255,255,0.2);\n border-radius: 4px;\n overflow: hidden;\n \">\n <div style=\"\n width: ${progress}%;\n height: 100%;\n background: ${accentColor};\n transition: width 0.2s ease;\n \"></div>\n </div>\n ${showPercentage ? `\n <div style=\"\n color: ${textColor};\n font-size: ${fontSize}px;\n margin-top: 8px;\n font-family: system-ui, sans-serif;\n \">${Math.round(progress)}%</div>\n ` : ''}\n `;\n break;\n\n case 'skeleton':\n content = `\n <div class=\"velo-plot-loading-skeleton\" style=\"\n width: 80%;\n max-width: 300px;\n \">\n <div class=\"velo-plot-skeleton-line\" style=\"height: 20px; margin-bottom: 8px;\"></div>\n <div class=\"velo-plot-skeleton-line\" style=\"height: 16px; width: 60%; margin-bottom: 8px;\"></div>\n <div class=\"velo-plot-skeleton-line\" style=\"height: 40px;\"></div>\n </div>\n `;\n break;\n\n case 'pulse':\n content = `\n <div class=\"velo-plot-loading-pulse\" style=\"\n width: ${spinnerSize}px;\n height: ${spinnerSize}px;\n background: ${accentColor};\n border-radius: 50%;\n animation: velo-plot-pulse 1.2s ease-in-out infinite;\n \"></div>\n `;\n break;\n }\n\n // Add message\n if (message) {\n content += `\n <div style=\"\n color: ${textColor};\n font-size: ${fontSize}px;\n margin-top: 12px;\n font-family: system-ui, sans-serif;\n \">${message}</div>\n `;\n }\n\n // Add ETA if available\n if (eta !== null && eta > 0 && type === 'progress') {\n content += `\n <div style=\"\n color: rgba(255,255,255,0.6);\n font-size: ${fontSize - 2}px;\n margin-top: 4px;\n font-family: system-ui, sans-serif;\n \">~${this.formatTime(eta)} remaining</div>\n `;\n }\n\n return content;\n }\n\n private injectStyles(): void {\n const styleId = 'velo-plot-loading-styles';\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = `\n @keyframes velo-plot-spin {\n to { transform: rotate(360deg); }\n }\n \n @keyframes velo-plot-pulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.2); opacity: 0.7; }\n }\n \n @keyframes velo-plot-skeleton-shimmer {\n 0% { background-position: -200% 0; }\n 100% { background-position: 200% 0; }\n }\n \n .velo-plot-skeleton-line {\n background: linear-gradient(\n 90deg,\n rgba(255,255,255,0.1) 25%,\n rgba(255,255,255,0.2) 50%,\n rgba(255,255,255,0.1) 75%\n );\n background-size: 200% 100%;\n animation: velo-plot-skeleton-shimmer 1.5s infinite;\n border-radius: 4px;\n }\n `;\n document.head.appendChild(style);\n }\n\n private calculateEta(): void {\n if (this.progressHistory.length < 2) {\n this.state.eta = null;\n return;\n }\n\n const first = this.progressHistory[0];\n const last = this.progressHistory[this.progressHistory.length - 1];\n \n const progressDelta = last.progress - first.progress;\n const timeDelta = last.time - first.time;\n\n if (progressDelta <= 0) {\n this.state.eta = null;\n return;\n }\n\n const remainingProgress = 100 - last.progress;\n const rate = progressDelta / timeDelta;\n this.state.eta = remainingProgress / rate;\n }\n\n private formatTime(ms: number): string {\n const seconds = Math.ceil(ms / 1000);\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = seconds % 60;\n return `${minutes}m ${remainingSeconds}s`;\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\n/**\n * Create a loading indicator for a container\n */\nexport function createLoadingIndicator(\n container: HTMLElement,\n options?: LoadingIndicatorOptions\n): LoadingIndicator {\n return new LoadingIndicator(container, options);\n}\n\n/**\n * Show loading with a simple spinner\n */\nexport function showLoading(\n container: HTMLElement,\n message?: string\n): LoadingIndicator {\n const indicator = new LoadingIndicator(container, { message });\n indicator.show();\n return indicator;\n}\n\n/**\n * Show progress loading\n */\nexport function showProgress(\n container: HTMLElement,\n message?: string\n): LoadingIndicator {\n const indicator = new LoadingIndicator(container, {\n type: 'progress',\n message,\n });\n indicator.show();\n return indicator;\n}\n","/**\n * SciPlot Engine - Loading Indicator Plugin\n * \n * Provides customizable loading and progress indicators.\n * \n * @module plugins/loading\n */\n\nimport { LoadingIndicator } from \"../../core/loading\";\nimport type { LoadingIndicatorOptions } from \"../../core/loading\";\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginLoadingConfig extends Partial<LoadingIndicatorOptions> {\n /** Auto-show on heavy data operations */\n autoShow?: boolean;\n}\n\nconst manifestLoading: PluginManifest = {\n name: \"velo-plot-loading\",\n version: \"1.0.0\",\n description: \"Loading and progress indicators for velo-plot\",\n provides: [\"ui\"],\n tags: [\"loading\", \"progress\", \"ui\", \"ux\"],\n};\n\n/**\n * SciPlot Loading Plugin\n * \n * Adds sleek loading indicators and progress trackers to the chart.\n */\nexport function PluginLoading(_config: PluginLoadingConfig = {}): ChartPlugin<PluginLoadingConfig> {\n let indicator: LoadingIndicator | null = null;\n\n return {\n manifest: manifestLoading,\n\n onInit(ctx: PluginContext) { \n // Create the indicator using the container from the UI context\n indicator = new LoadingIndicator(ctx.ui.container, {\n ..._config,\n // Inherit theme colors if not explicitly provided\n accentColor: _config.accentColor || (ctx.ui.theme.isDark ? '#00f2ff' : '#00b4d8'),\n });\n\n // If autoShow is enabled (or by default during init), show it\n if (_config.autoShow !== false) {\n indicator.show(_config.message || 'Initializing Chart...');\n }\n\n // Optional: Auto-hide on first successful render WITH data\n if (_config.autoHide !== false) {\n const off = ctx.events.on('render', () => {\n const hasData = ctx.data.getAllSeries().some(s => s.getPointCount() > 0);\n if (hasData) {\n indicator?.hide();\n off();\n }\n });\n }\n },\n\n onDestroy(_ctx: PluginContext) {\n indicator?.destroy();\n indicator = null;\n },\n\n api: {\n show(message?: string) {\n indicator?.show(message);\n },\n hide() {\n indicator?.hide();\n },\n setProgress(progress: number, message?: string) {\n indicator?.setProgress(progress, message);\n },\n setMessage(message: string) {\n indicator?.setMessage(message);\n },\n getIndicator: () => indicator\n }\n };\n}\n\nexport { LoadingIndicator };\nexport default PluginLoading;\n"],"names":["LoadingIndicator","container","options","__publicField","message","progress","clampedProgress","type","accentColor","textColor","size","showPercentage","eta","spinnerSize","fontSize","content","styleId","style","first","last","progressDelta","timeDelta","remainingProgress","rate","ms","seconds","minutes","remainingSeconds","createLoadingIndicator","showLoading","indicator","showProgress","manifestLoading","PluginLoading","_config","ctx","off","s","_ctx"],"mappings":"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"}
1
+ {"version":3,"file":"index-qhscKTDy.js","sources":["../src/core/loading/index.ts","../src/plugins/loading/index.ts"],"sourcesContent":["/**\n * Velo Plot - Loading Indicator Module\n * \n * Provides visual loading/progress indicators for chart operations.\n * Supports progress bars, spinners, and skeleton placeholders.\n * \n * @module loading\n */\n\n// ============================================\n// Types\n// ============================================\n\nexport type LoadingIndicatorType = 'spinner' | 'progress' | 'skeleton' | 'pulse';\n\nexport interface LoadingIndicatorOptions {\n /** Indicator type (default: 'spinner') */\n type?: LoadingIndicatorType;\n /** Message to display (default: 'Loading...') */\n message?: string;\n /** Show percentage for progress type (default: true) */\n showPercentage?: boolean;\n /** Background overlay opacity (0-1, default: 0.7) */\n overlayOpacity?: number;\n /** Accent color for spinner/progress (default: '#00f2ff') */\n accentColor?: string;\n /** Background color (default: 'rgba(0,0,0,0.7)') */\n backgroundColor?: string;\n /** Text color (default: '#ffffff') */\n textColor?: string;\n /** Size: 'small', 'medium', 'large' (default: 'medium') */\n size?: 'small' | 'medium' | 'large';\n /** Custom CSS class */\n className?: string;\n /** Auto-hide after completion (default: true) */\n autoHide?: boolean;\n /** Hide delay in ms after completion (default: 300) */\n hideDelay?: number;\n}\n\nexport interface LoadingState {\n /** Whether loading is in progress */\n isLoading: boolean;\n /** Progress value (0-100) */\n progress: number;\n /** Current message */\n message: string;\n /** Start time of loading */\n startTime: number | null;\n /** Estimated time remaining in ms */\n eta: number | null;\n}\n\n// ============================================\n// Loading Indicator Implementation\n// ============================================\n\nexport class LoadingIndicator {\n private container: HTMLElement;\n private element: HTMLDivElement | null = null;\n private options: Required<LoadingIndicatorOptions>;\n private state: LoadingState = {\n isLoading: false,\n progress: 0,\n message: '',\n startTime: null,\n eta: null,\n };\n\n // For ETA calculation\n private progressHistory: { time: number; progress: number }[] = [];\n\n constructor(container: HTMLElement, options?: LoadingIndicatorOptions) {\n this.container = container;\n this.options = {\n type: 'spinner',\n message: 'Loading...',\n showPercentage: true,\n overlayOpacity: 0.7,\n accentColor: '#00f2ff',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n textColor: '#ffffff',\n size: 'medium',\n className: 'velo-plot-loading',\n autoHide: true,\n hideDelay: 200,\n ...options,\n };\n this.state.message = this.options.message;\n }\n\n /**\n * Show the loading indicator\n */\n show(message?: string): void {\n this.state.isLoading = true;\n this.state.progress = 0;\n this.state.startTime = performance.now();\n this.state.eta = null;\n this.progressHistory = [];\n \n if (message) {\n this.state.message = message;\n }\n\n this.createElement();\n this.render();\n }\n\n /**\n * Hide the loading indicator\n */\n hide(): void {\n if (!this.state.isLoading) return;\n this.state.isLoading = false;\n \n if (this.element) {\n this.element.style.opacity = '0';\n }\n\n if (this.options.autoHide) {\n setTimeout(() => {\n this.destroyElement();\n }, this.options.hideDelay);\n } else {\n this.destroyElement();\n }\n }\n\n /**\n * Update progress (0-100)\n */\n setProgress(progress: number, message?: string): void {\n const clampedProgress = Math.max(0, Math.min(100, progress));\n this.state.progress = clampedProgress;\n \n if (message) {\n this.state.message = message;\n }\n\n // Track progress for ETA\n this.progressHistory.push({\n time: performance.now(),\n progress: clampedProgress,\n });\n\n // Keep only recent history\n if (this.progressHistory.length > 10) {\n this.progressHistory.shift();\n }\n\n // Calculate ETA\n this.calculateEta();\n \n this.render();\n\n // Auto-complete\n if (clampedProgress >= 100 && this.options.autoHide) {\n this.hide();\n }\n }\n\n /**\n * Update message only\n */\n setMessage(message: string): void {\n this.state.message = message;\n this.render();\n }\n\n /**\n * Check if loading is in progress\n */\n isLoading(): boolean {\n return this.state.isLoading;\n }\n\n /**\n * Get current progress\n */\n getProgress(): number {\n return this.state.progress;\n }\n\n /**\n * Get current state\n */\n getState(): LoadingState {\n return { ...this.state };\n }\n\n /**\n * Destroy the indicator\n */\n destroy(): void {\n this.hide();\n this.destroyElement();\n }\n\n // ============================================\n // Private Methods\n // ============================================\n\n private createElement(): void {\n if (this.element) return;\n\n this.element = document.createElement('div');\n this.element.className = this.options.className;\n \n // Apply overlay styles\n Object.assign(this.element.style, {\n position: 'absolute',\n top: '0',\n left: '0',\n right: '0',\n bottom: '0',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: this.options.backgroundColor,\n zIndex: '9998',\n transition: 'opacity 0.2s ease',\n });\n\n // Create inner content\n this.element.innerHTML = this.getInnerHtml();\n \n // Inject styles\n this.injectStyles();\n\n this.container.style.position = 'relative';\n this.container.appendChild(this.element);\n }\n\n private destroyElement(): void {\n if (this.element && this.element.parentNode) {\n this.element.parentNode.removeChild(this.element);\n }\n this.element = null;\n }\n\n private render(): void {\n if (!this.element) return;\n this.element.innerHTML = this.getInnerHtml();\n }\n\n private getInnerHtml(): string {\n const { type, accentColor, textColor, size, showPercentage } = this.options;\n const { progress, message, eta } = this.state;\n \n const sizeMap = { small: 24, medium: 40, large: 56 };\n const spinnerSize = sizeMap[size];\n const fontSize = size === 'small' ? 12 : size === 'large' ? 16 : 14;\n\n let content = '';\n\n switch (type) {\n case 'spinner':\n content = `\n <div class=\"velo-plot-loading-spinner\" style=\"\n width: ${spinnerSize}px;\n height: ${spinnerSize}px;\n border: 3px solid rgba(255,255,255,0.2);\n border-top-color: ${accentColor};\n border-radius: 50%;\n animation: velo-plot-spin 0.8s linear infinite;\n \"></div>\n `;\n break;\n\n case 'progress':\n content = `\n <div class=\"velo-plot-loading-progress\" style=\"\n width: 200px;\n height: 8px;\n background: rgba(255,255,255,0.2);\n border-radius: 4px;\n overflow: hidden;\n \">\n <div style=\"\n width: ${progress}%;\n height: 100%;\n background: ${accentColor};\n transition: width 0.2s ease;\n \"></div>\n </div>\n ${showPercentage ? `\n <div style=\"\n color: ${textColor};\n font-size: ${fontSize}px;\n margin-top: 8px;\n font-family: system-ui, sans-serif;\n \">${Math.round(progress)}%</div>\n ` : ''}\n `;\n break;\n\n case 'skeleton':\n content = `\n <div class=\"velo-plot-loading-skeleton\" style=\"\n width: 80%;\n max-width: 300px;\n \">\n <div class=\"velo-plot-skeleton-line\" style=\"height: 20px; margin-bottom: 8px;\"></div>\n <div class=\"velo-plot-skeleton-line\" style=\"height: 16px; width: 60%; margin-bottom: 8px;\"></div>\n <div class=\"velo-plot-skeleton-line\" style=\"height: 40px;\"></div>\n </div>\n `;\n break;\n\n case 'pulse':\n content = `\n <div class=\"velo-plot-loading-pulse\" style=\"\n width: ${spinnerSize}px;\n height: ${spinnerSize}px;\n background: ${accentColor};\n border-radius: 50%;\n animation: velo-plot-pulse 1.2s ease-in-out infinite;\n \"></div>\n `;\n break;\n }\n\n // Add message\n if (message) {\n content += `\n <div style=\"\n color: ${textColor};\n font-size: ${fontSize}px;\n margin-top: 12px;\n font-family: system-ui, sans-serif;\n \">${message}</div>\n `;\n }\n\n // Add ETA if available\n if (eta !== null && eta > 0 && type === 'progress') {\n content += `\n <div style=\"\n color: rgba(255,255,255,0.6);\n font-size: ${fontSize - 2}px;\n margin-top: 4px;\n font-family: system-ui, sans-serif;\n \">~${this.formatTime(eta)} remaining</div>\n `;\n }\n\n return content;\n }\n\n private injectStyles(): void {\n const styleId = 'velo-plot-loading-styles';\n if (document.getElementById(styleId)) return;\n\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = `\n @keyframes velo-plot-spin {\n to { transform: rotate(360deg); }\n }\n \n @keyframes velo-plot-pulse {\n 0%, 100% { transform: scale(1); opacity: 1; }\n 50% { transform: scale(1.2); opacity: 0.7; }\n }\n \n @keyframes velo-plot-skeleton-shimmer {\n 0% { background-position: -200% 0; }\n 100% { background-position: 200% 0; }\n }\n \n .velo-plot-skeleton-line {\n background: linear-gradient(\n 90deg,\n rgba(255,255,255,0.1) 25%,\n rgba(255,255,255,0.2) 50%,\n rgba(255,255,255,0.1) 75%\n );\n background-size: 200% 100%;\n animation: velo-plot-skeleton-shimmer 1.5s infinite;\n border-radius: 4px;\n }\n `;\n document.head.appendChild(style);\n }\n\n private calculateEta(): void {\n if (this.progressHistory.length < 2) {\n this.state.eta = null;\n return;\n }\n\n const first = this.progressHistory[0];\n const last = this.progressHistory[this.progressHistory.length - 1];\n \n const progressDelta = last.progress - first.progress;\n const timeDelta = last.time - first.time;\n\n if (progressDelta <= 0) {\n this.state.eta = null;\n return;\n }\n\n const remainingProgress = 100 - last.progress;\n const rate = progressDelta / timeDelta;\n this.state.eta = remainingProgress / rate;\n }\n\n private formatTime(ms: number): string {\n const seconds = Math.ceil(ms / 1000);\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.floor(seconds / 60);\n const remainingSeconds = seconds % 60;\n return `${minutes}m ${remainingSeconds}s`;\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\n/**\n * Create a loading indicator for a container\n */\nexport function createLoadingIndicator(\n container: HTMLElement,\n options?: LoadingIndicatorOptions\n): LoadingIndicator {\n return new LoadingIndicator(container, options);\n}\n\n/**\n * Show loading with a simple spinner\n */\nexport function showLoading(\n container: HTMLElement,\n message?: string\n): LoadingIndicator {\n const indicator = new LoadingIndicator(container, { message });\n indicator.show();\n return indicator;\n}\n\n/**\n * Show progress loading\n */\nexport function showProgress(\n container: HTMLElement,\n message?: string\n): LoadingIndicator {\n const indicator = new LoadingIndicator(container, {\n type: 'progress',\n message,\n });\n indicator.show();\n return indicator;\n}\n","/**\n * VeloPlot Engine - Loading Indicator Plugin\n * \n * Provides customizable loading and progress indicators.\n * \n * @module plugins/loading\n */\n\nimport { LoadingIndicator } from \"../../core/loading\";\nimport type { LoadingIndicatorOptions } from \"../../core/loading\";\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginLoadingConfig extends Partial<LoadingIndicatorOptions> {\n /** Auto-show on heavy data operations */\n autoShow?: boolean;\n}\n\nconst manifestLoading: PluginManifest = {\n name: \"velo-plot-loading\",\n version: \"1.0.0\",\n description: \"Loading and progress indicators for velo-plot\",\n provides: [\"ui\"],\n tags: [\"loading\", \"progress\", \"ui\", \"ux\"],\n};\n\n/**\n * VeloPlot Loading Plugin\n * \n * Adds sleek loading indicators and progress trackers to the chart.\n */\nexport function PluginLoading(_config: PluginLoadingConfig = {}): ChartPlugin<PluginLoadingConfig> {\n let indicator: LoadingIndicator | null = null;\n\n return {\n manifest: manifestLoading,\n\n onInit(ctx: PluginContext) { \n // Create the indicator using the container from the UI context\n indicator = new LoadingIndicator(ctx.ui.container, {\n ..._config,\n // Inherit theme colors if not explicitly provided\n accentColor: _config.accentColor || (ctx.ui.theme.isDark ? '#00f2ff' : '#00b4d8'),\n });\n\n // If autoShow is enabled (or by default during init), show it\n if (_config.autoShow !== false) {\n indicator.show(_config.message || 'Initializing Chart...');\n }\n\n // Optional: Auto-hide on first successful render WITH data\n if (_config.autoHide !== false) {\n const off = ctx.events.on('render', () => {\n const hasData = ctx.data.getAllSeries().some(s => s.getPointCount() > 0);\n if (hasData) {\n indicator?.hide();\n off();\n }\n });\n }\n },\n\n onDestroy(_ctx: PluginContext) {\n indicator?.destroy();\n indicator = null;\n },\n\n api: {\n show(message?: string) {\n indicator?.show(message);\n },\n hide() {\n indicator?.hide();\n },\n setProgress(progress: number, message?: string) {\n indicator?.setProgress(progress, message);\n },\n setMessage(message: string) {\n indicator?.setMessage(message);\n },\n getIndicator: () => indicator\n }\n };\n}\n\nexport { LoadingIndicator };\nexport default PluginLoading;\n"],"names":["LoadingIndicator","container","options","__publicField","message","progress","clampedProgress","type","accentColor","textColor","size","showPercentage","eta","spinnerSize","fontSize","content","styleId","style","first","last","progressDelta","timeDelta","remainingProgress","rate","ms","seconds","minutes","remainingSeconds","createLoadingIndicator","showLoading","indicator","showProgress","manifestLoading","PluginLoading","_config","ctx","off","s","_ctx"],"mappings":"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"}