flexdesk 0.16.1 → 0.17.1

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 (262) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/LICENSE +0 -0
  3. package/README.md +2435 -42
  4. package/THIRD_PARTY_LICENSES.md +0 -0
  5. package/canvas.js +18 -0
  6. package/charts.js +21 -0
  7. package/core.js +14 -0
  8. package/css/base.css +1834 -75
  9. package/css/flexdesk.css +3165 -159
  10. package/css/overrides.css +16 -0
  11. package/css/reset.css +0 -0
  12. package/css/tokens.css +0 -0
  13. package/dist/canvas.js +6 -239
  14. package/dist/canvas.js.map +3 -3
  15. package/dist/charts.js +707 -18
  16. package/dist/charts.js.map +4 -4
  17. package/dist/chunk-3PHCPZHT.js +0 -0
  18. package/dist/chunk-3PHCPZHT.js.map +0 -0
  19. package/dist/chunk-4A7SJC3T.js +503 -0
  20. package/dist/chunk-4A7SJC3T.js.map +7 -0
  21. package/dist/{chunk-6JSOVNID.js → chunk-CVMCZZX2.js} +635 -10
  22. package/dist/chunk-CVMCZZX2.js.map +7 -0
  23. package/dist/chunk-D3COLZZ2.js +1311 -0
  24. package/dist/chunk-D3COLZZ2.js.map +7 -0
  25. package/dist/chunk-FOOS3T5L.js +0 -0
  26. package/dist/chunk-FOOS3T5L.js.map +0 -0
  27. package/dist/{chunk-SN4LSOAR.js → chunk-GOQLR5WR.js} +452 -2
  28. package/dist/chunk-GOQLR5WR.js.map +7 -0
  29. package/dist/{chunk-FL5KFNQH.js → chunk-HNU6MM2B.js} +52 -17
  30. package/dist/chunk-HNU6MM2B.js.map +7 -0
  31. package/dist/chunk-HYJYYEPK.js +375 -0
  32. package/dist/chunk-HYJYYEPK.js.map +7 -0
  33. package/dist/chunk-JKZLNKG6.js +2041 -0
  34. package/dist/chunk-JKZLNKG6.js.map +7 -0
  35. package/dist/chunk-JYWURG5T.js +0 -0
  36. package/dist/chunk-JYWURG5T.js.map +0 -0
  37. package/dist/{chunk-FBGP5KN5.js → chunk-LWV23YVE.js} +5073 -532
  38. package/dist/chunk-LWV23YVE.js.map +7 -0
  39. package/dist/chunk-N7HC3ADV.js +30 -0
  40. package/dist/chunk-N7HC3ADV.js.map +7 -0
  41. package/dist/{chunk-RQM5Z2MU.js → chunk-RMTRWWEO.js} +633 -311
  42. package/dist/chunk-RMTRWWEO.js.map +7 -0
  43. package/dist/{chunk-NLTOY57M.js → chunk-UURZ37SD.js} +28 -48
  44. package/dist/chunk-UURZ37SD.js.map +7 -0
  45. package/dist/{chunk-B5Q53LAJ.js → chunk-UWO43BZU.js} +2 -2
  46. package/dist/chunk-UWO43BZU.js.map +7 -0
  47. package/dist/chunk-WVFGV5FT.js +0 -0
  48. package/dist/chunk-WVFGV5FT.js.map +0 -0
  49. package/dist/core.js +170 -118
  50. package/dist/core.js.map +2 -2
  51. package/dist/editor.js +156 -70
  52. package/dist/editor.js.map +2 -2
  53. package/dist/flexdesk.css +3165 -159
  54. package/dist/flow.js +2789 -306
  55. package/dist/flow.js.map +4 -4
  56. package/dist/host.js +109 -3
  57. package/dist/host.js.map +3 -3
  58. package/dist/reset.css +0 -0
  59. package/dist/tile_registry-6WZPTUZV.js +0 -0
  60. package/dist/tile_registry-6WZPTUZV.js.map +0 -0
  61. package/dist/tiles.js +657 -234
  62. package/dist/tiles.js.map +4 -4
  63. package/dist/tokens.css +0 -0
  64. package/dist/widgets.js +3290 -2124
  65. package/dist/widgets.js.map +4 -4
  66. package/dist/wm.js +1227 -347
  67. package/dist/wm.js.map +4 -4
  68. package/editor.js +20 -0
  69. package/flow.js +21 -0
  70. package/host.js +14 -0
  71. package/package.json +12 -1
  72. package/src/canvas/canvas_adapter.js +5 -0
  73. package/src/canvas/edge_router.js +0 -0
  74. package/src/canvas/graph/connector_router.js +0 -0
  75. package/src/canvas/graph/history_service.js +0 -0
  76. package/src/canvas/graph/node_platform.js +0 -0
  77. package/src/canvas/index.js +1 -0
  78. package/src/canvas/layered_layout.js +244 -0
  79. package/src/charts/chart_types.js +0 -0
  80. package/src/charts/data_series_plot_window.js +0 -0
  81. package/src/charts/downsample.js +2 -2
  82. package/src/charts/plot_config.js +53 -29
  83. package/src/charts/plot_config_editor.js +627 -0
  84. package/src/charts/plot_grid.js +449 -0
  85. package/src/charts/plot_popout_window.js +103 -317
  86. package/src/charts/plotly_wrapper.js +22 -2
  87. package/src/charts/series_transforms.js +206 -0
  88. package/src/core/event_bus.js +0 -0
  89. package/src/core/logging.js +1 -1
  90. package/src/core/settings.js +105 -19
  91. package/src/core/state_guard.js +93 -51
  92. package/src/core/state_guard_config.js +85 -74
  93. package/src/core/state_machine.js +0 -0
  94. package/src/editor/editor_pane.js +3 -3
  95. package/src/editor/monaco_editor_factory.js +124 -60
  96. package/src/editor/monaco_loader.js +103 -28
  97. package/src/editor/notebook_search.js +0 -0
  98. package/src/editor/notebook_tab_bar.js +38 -52
  99. package/src/editor/notebook_undo_manager.js +0 -0
  100. package/src/editor/split_pane_container.js +6 -3
  101. package/src/flow/canvas_editor/connections.js +90 -0
  102. package/src/flow/canvas_editor/editor.js +2351 -153
  103. package/src/flow/canvas_editor/index.js +2 -1
  104. package/src/flow/canvas_editor/layout.js +119 -12
  105. package/src/flow/canvas_editor/strings.js +80 -0
  106. package/src/flow/kit/always_before.js +0 -0
  107. package/src/flow/kit/catalogue.js +97 -3
  108. package/src/flow/kit/chip_input.js +0 -0
  109. package/src/flow/kit/dom.js +0 -0
  110. package/src/flow/kit/findings.js +0 -0
  111. package/src/flow/kit/history.js +0 -0
  112. package/src/flow/kit/index.js +3 -3
  113. package/src/flow/kit/keys.js +7 -1
  114. package/src/flow/kit/logic_graph.js +97 -15
  115. package/src/flow/kit/references.js +0 -0
  116. package/src/flow/kit/settings_panel.js +0 -0
  117. package/src/flow/kit/settings_schema.js +2 -1
  118. package/src/flow/kit/step_picker.js +0 -0
  119. package/src/flow/kit/strings.js +3 -1
  120. package/src/flow/kit/value_picker.js +0 -0
  121. package/src/flow/kit/widgets.js +86 -109
  122. package/src/flow/lanes/editor.js +136 -14
  123. package/src/flow/lanes/index.js +3 -1
  124. package/src/flow/lanes/layout.js +0 -0
  125. package/src/flow/lanes/pipeline.js +44 -2
  126. package/src/flow/lanes/preview.js +0 -0
  127. package/src/flow/lanes/strings.js +1 -0
  128. package/src/flow/outline/editor.js +0 -0
  129. package/src/flow/outline/index.js +0 -0
  130. package/src/flow/outline/mapping.js +0 -0
  131. package/src/flow/outline/menu.js +0 -0
  132. package/src/flow/outline/operations.js +0 -0
  133. package/src/flow/outline/recognise.js +0 -0
  134. package/src/flow/outline/strings.js +0 -0
  135. package/src/help/help_modal.js +168 -42
  136. package/src/help/help_registry.js +12 -1
  137. package/src/host/external_links.js +0 -0
  138. package/src/host/file_picker.js +117 -0
  139. package/src/host/host.js +10 -2
  140. package/src/host/photino_host.js +9 -0
  141. package/src/host/photino_host.md +21 -3
  142. package/src/host/pywebview_host.js +10 -0
  143. package/src/tiles/chart_tiles.js +53 -245
  144. package/src/tiles/config_schema.js +8 -0
  145. package/src/tiles/figure_tile.js +322 -0
  146. package/src/tiles/layout_persistence.js +3 -3
  147. package/src/tiles/list_tiles.js +7 -7
  148. package/src/tiles/scope_picker.js +0 -0
  149. package/src/tiles/tile_base.js +1 -1
  150. package/src/tiles/tile_config_form.js +442 -0
  151. package/src/tiles/tile_grid.js +2 -0
  152. package/src/tiles/tile_registry.js +0 -0
  153. package/src/tiling/bottom_panel_tabs.js +67 -99
  154. package/src/tiling/command_palette.js +64 -19
  155. package/src/tiling/content_registry.js +4 -1
  156. package/src/tiling/desktops.js +11 -1
  157. package/src/tiling/entity_sources.js +0 -0
  158. package/src/tiling/keymap.js +403 -128
  159. package/src/tiling/kind_taxonomy.js +78 -0
  160. package/src/tiling/landing_table.js +0 -0
  161. package/src/tiling/loading_overlay.js +0 -0
  162. package/src/tiling/nav_panel.js +59 -10
  163. package/src/tiling/page_factory.js +5 -5
  164. package/src/tiling/panel_availability.js +49 -0
  165. package/src/tiling/panel_keys.js +0 -0
  166. package/src/tiling/shell.js +114 -12
  167. package/src/tiling/tab_strip.js +0 -0
  168. package/src/tiling/tile_breadcrumb.js +0 -0
  169. package/src/tiling/tile_renderer.js +105 -9
  170. package/src/tiling/tile_tab_menu.js +0 -0
  171. package/src/tiling/tile_tree.js +0 -0
  172. package/src/tiling/wm.js +562 -30
  173. package/src/tiling/zoom.js +0 -0
  174. package/src/ui/base/component_base.js +0 -0
  175. package/src/ui/base/controller_base.js +0 -0
  176. package/src/ui/base/page_base.js +0 -0
  177. package/src/ui/components/about_dialog.js +0 -0
  178. package/src/ui/components/action_dropdown.js +30 -2
  179. package/src/ui/components/alert_log.js +0 -0
  180. package/src/ui/components/alerts_pane.js +0 -0
  181. package/src/ui/components/attribute_list_editor.js +0 -0
  182. package/src/ui/components/autocomplete_field.js +0 -0
  183. package/src/ui/components/cell_editor_host.js +293 -0
  184. package/src/ui/components/cell_editors.js +480 -0
  185. package/src/ui/components/cell_grid.js +761 -0
  186. package/src/ui/components/cell_paste.js +243 -0
  187. package/src/ui/components/cell_selection.js +220 -0
  188. package/src/ui/components/choice_controls.js +351 -0
  189. package/src/ui/components/color_field.js +211 -0
  190. package/src/ui/components/color_list_field.js +210 -0
  191. package/src/ui/components/column_fit.js +0 -0
  192. package/src/ui/components/column_groups.js +314 -0
  193. package/src/ui/components/column_order.js +142 -0
  194. package/src/ui/components/computing_status_window.js +98 -25
  195. package/src/ui/components/confirm_dialog.js +81 -38
  196. package/src/ui/components/context_menu.js +2 -2
  197. package/src/ui/components/conversation_view.js +440 -0
  198. package/src/ui/components/crosstab.js +289 -0
  199. package/src/ui/components/data_table.js +696 -71
  200. package/src/ui/components/detail_header.js +22 -11
  201. package/src/ui/components/document_outline.js +397 -0
  202. package/src/ui/components/drag_reorder.js +0 -0
  203. package/src/ui/components/fact_table.js +0 -0
  204. package/src/ui/components/fill_handle.js +322 -0
  205. package/src/ui/components/gallery_picker.js +19 -8
  206. package/src/ui/components/header_actions.js +55 -0
  207. package/src/ui/components/inline_renamer.js +0 -0
  208. package/src/ui/components/job_progress.js +51 -0
  209. package/src/ui/components/managed_window.js +27 -4
  210. package/src/ui/components/menu_bar.js +745 -0
  211. package/src/ui/components/modal.js +449 -75
  212. package/src/ui/components/notification_history.js +3 -3
  213. package/src/ui/components/progress.js +483 -0
  214. package/src/ui/components/record_list.js +0 -0
  215. package/src/ui/components/row_activation.js +0 -0
  216. package/src/ui/components/section_stack.js +298 -0
  217. package/src/ui/components/series.js +173 -0
  218. package/src/ui/components/settings_view.js +634 -0
  219. package/src/ui/components/slide_out_panel.js +43 -6
  220. package/src/ui/components/slider_field.js +275 -18
  221. package/src/ui/components/sortable_list.js +0 -0
  222. package/src/ui/components/staged_edits.js +361 -0
  223. package/src/ui/components/staged_history.js +172 -0
  224. package/src/ui/components/table_filter_chips.js +0 -0
  225. package/src/ui/components/table_state_store.js +0 -0
  226. package/src/ui/components/table_structure.js +182 -0
  227. package/src/ui/components/table_values.js +0 -0
  228. package/src/ui/components/tabs.js +497 -0
  229. package/src/ui/components/tag_input.js +215 -0
  230. package/src/ui/components/toast.js +25 -8
  231. package/src/ui/components/toggle_field.js +175 -0
  232. package/src/ui/components/tree_view.js +55 -34
  233. package/src/ui/components/tsv.js +74 -0
  234. package/src/ui/components/window_taskbar.js +0 -0
  235. package/src/ui/components/wizard.js +563 -0
  236. package/src/ui/controllers/window_chrome_controller.js +2 -2
  237. package/src/ui/notification_center.js +375 -119
  238. package/src/ui/utils/auto_scrollbars.js +0 -0
  239. package/src/ui/utils/markdown.js +709 -0
  240. package/src/ui/utils/native_context_menu.js +0 -0
  241. package/src/ui/utils/overlay_scrollbar.js +16 -12
  242. package/src/ui/utils/raf_resize_observer.js +0 -0
  243. package/src/ui/utils/scroll_lock.js +0 -0
  244. package/src/ui/utils/strip_scroll.js +55 -0
  245. package/src/ui/utils/tooltip_service.js +0 -8
  246. package/tiles.js +27 -0
  247. package/widgets.js +69 -0
  248. package/wm.js +28 -0
  249. package/dist/chunk-6JSOVNID.js.map +0 -7
  250. package/dist/chunk-B5Q53LAJ.js.map +0 -7
  251. package/dist/chunk-FBGP5KN5.js.map +0 -7
  252. package/dist/chunk-FL5KFNQH.js.map +0 -7
  253. package/dist/chunk-NLTOY57M.js.map +0 -7
  254. package/dist/chunk-NNFTETK3.js +0 -633
  255. package/dist/chunk-NNFTETK3.js.map +0 -7
  256. package/dist/chunk-O5OHMWBB.js +0 -284
  257. package/dist/chunk-O5OHMWBB.js.map +0 -7
  258. package/dist/chunk-RQM5Z2MU.js.map +0 -7
  259. package/dist/chunk-SN4LSOAR.js.map +0 -7
  260. package/dist/chunk-W6FBJLPW.js +0 -367
  261. package/dist/chunk-W6FBJLPW.js.map +0 -7
  262. package/src/ui/controllers/panel_state_machine.js +0 -634
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/core/settings.js"],
4
- "sourcesContent": ["/**\n * Application Settings \u2014 a generic, schema-driven value store.\n *\n * Purpose\n * -------\n * A persisted key/value store whose UI is driven entirely by a declarative\n * SCHEMA. The store knows nothing about any particular application's settings:\n * it ships the *shell's* own namespaces (workspace, window, logging, data,\n * notebook, ai, \u2026) and an embedder PUSHES its own namespace in at boot with\n * `registerSettings()`. The Settings page renders whatever is in the schema.\n *\n * Two doors, on purpose\n * ---------------------\n * createSettingsStore({ defaults, schema, categories, storageKey })\n * The primitive. A private store with zero global state \u2014 what the\n * library's demo and the unit tests use.\n *\n * getSetting() / setSetting() / registerSettings() / \u2026\n * A thin binding over ONE instance of that primitive for THIS document.\n * The cardinality is correct, not merely convenient: the store has a\n * single physical backing key (`localStorage['ecosim.settings.v1']`), so\n * two live stores in one document would be two writers to one key.\n *\n * Usage\n * -----\n * import { getSetting, setSetting } from '../core/settings.js';\n *\n * // Read a setting\n * if (getSetting('workspace.save.showToast')) { ... }\n *\n * // Write a setting (persists to localStorage, emits events)\n * setSetting('window.macShadows', true);\n *\n * // React to changes (after registerSettingsEventBus is called)\n * eventBus.on('settings:window.macShadows:changed', ({ value }) => { ... });\n *\n * Adding New Settings\n * -------------------\n * Shell-owned setting: add the default under the right namespace in DEFAULTS,\n * add a SCHEMA entry (type, category, group, label, description), done \u2014 the\n * Settings page picks it up.\n *\n * Embedder-owned setting: do NOT add it here. Put it in your own slice and\n * `registerSettings({ defaults, schema, categories })` at bootstrap.\n */\n\n// \u2500\u2500\u2500 Defaults (shell-owned namespaces only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst DEFAULTS = Object.freeze({\n workspace: Object.freeze({\n save: Object.freeze({\n showToast: false,\n showErrorToast: true,\n }),\n import: Object.freeze({\n showToast: false,\n showErrorToast: true,\n }),\n autosave: Object.freeze({\n enabled: true,\n intervalSeconds: 60,\n }),\n undoHistoryLimit: 200,\n }),\n\n host: Object.freeze({\n showConnectedToast: false,\n }),\n\n window: Object.freeze({\n animateMinimize: true,\n macShadows: true,\n }),\n\n notifications: Object.freeze({\n durationMs: 3500,\n }),\n\n data: Object.freeze({\n tablePageSize: 100,\n defaultResampleMethod: 'mean',\n }),\n\n etl: Object.freeze({\n parallelWorkers: 1,\n }),\n\n logging: Object.freeze({\n minLevel: 'info',\n historyLimit: 500,\n enableConsole: false,\n }),\n\n editor: Object.freeze({\n autosaveDelayMs: 5000,\n }),\n\n notebook: Object.freeze({\n cellWidthMode: 'fixed',\n codeCellMaxHeight: false,\n defaultCellView: 'config',\n }),\n\n debug: Object.freeze({\n logSettingsAccess: false,\n }),\n\n projects: Object.freeze({\n directory: null,\n }),\n\n // Only auto-create-defaults survives; the modules directory / addon /\n // ETL-plugin loaders were the node-graph plugin system.\n ai: Object.freeze({\n provider: '',\n cloud: Object.freeze({\n providerId: 'anthropic',\n providers: Object.freeze({}),\n }),\n local: Object.freeze({\n serverType: 'llamacpp',\n modelPath: '',\n baseUrl: '',\n model: '',\n port: 8080,\n gpuLayers: -1,\n contextLength: 32768,\n flashAttention: true,\n evalBatchSize: 512,\n kvCacheOnGpu: true,\n }),\n defaultMode: 'ask',\n maxToolCalls: 25,\n }),\n});\n\n// \u2500\u2500\u2500 Schema (drives the Settings page UI) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * @typedef {Object} SettingDef\n * @property {'boolean'|'select'|'number'|'text'|'colorList'} type\n * @property {string} category - Category ID (matches CATEGORIES[].id)\n * @property {string} group - Visual group within the category\n * @property {string} label - Human-readable label\n * @property {string} description - Explanation shown below the label\n * @property {*} defaultValue - Must match DEFAULTS\n * @property {Array<{value:string,label:string}>} [options] - For 'select' type\n * @property {number} [min] - For 'number' type\n * @property {number} [max] - For 'number' type\n * @property {number|string} [step] - For 'number' type\n * @property {string} [placeholder] - For 'text' type\n */\n\n/**\n * @typedef {Object} SettingsSlice\n * @property {object} [defaults] - Nested default values for the namespace.\n * @property {Object<string, SettingDef>} [schema] - Dot-path -> SettingDef.\n * @property {Array<CategoryDef>} [categories] - Categories the slice adds.\n */\n\n/**\n * @typedef {Object} CategoryDef\n * @property {string} id\n * @property {string} label\n * @property {string} icon\n * @property {string} description\n * @property {number} [order] - Sidebar sort key. Lower sorts first; ties keep\n * registration order. Defaults to 1000.\n */\n\nconst SCHEMA = Object.freeze({\n // \u2500\u2500 General \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n 'workspace.save.showToast': {\n type: 'boolean', category: 'general', group: 'Workspace Notifications',\n label: 'Save success notification',\n description: 'Show a toast notification when a workspace is saved successfully.',\n defaultValue: false,\n },\n 'workspace.save.showErrorToast': {\n type: 'boolean', category: 'general', group: 'Workspace Notifications',\n label: 'Save error notification',\n description: 'Show a toast notification when a workspace save fails.',\n defaultValue: true,\n },\n 'workspace.import.showToast': {\n type: 'boolean', category: 'general', group: 'Workspace Notifications',\n label: 'Import success notification',\n description: 'Show a toast notification when a workspace is imported successfully.',\n defaultValue: false,\n },\n 'workspace.import.showErrorToast': {\n type: 'boolean', category: 'general', group: 'Workspace Notifications',\n label: 'Import error notification',\n description: 'Show a toast notification when a workspace import fails.',\n defaultValue: true,\n },\n 'host.showConnectedToast': {\n type: 'boolean', category: 'general', group: 'Host Bridge',\n label: 'Host connected notification',\n description: 'Show a toast notification when the desktop host bridge connects.',\n defaultValue: false,\n },\n 'notifications.durationMs': {\n type: 'number', category: 'general', group: 'Notifications',\n label: 'Toast notification duration',\n description: 'How long toast notifications stay visible (milliseconds).',\n defaultValue: 3500, min: 1000, max: 15000, step: 500,\n },\n 'workspace.autosave.enabled': {\n type: 'boolean', category: 'general', group: 'Auto-Save',\n label: 'Enable auto-save',\n description: 'Automatically save the workspace at regular intervals.',\n defaultValue: true,\n },\n 'workspace.autosave.intervalSeconds': {\n type: 'number', category: 'general', group: 'Auto-Save',\n label: 'Auto-save interval (seconds)',\n description: 'Time between automatic saves.',\n defaultValue: 60, min: 10, max: 600, step: 10,\n },\n 'workspace.undoHistoryLimit': {\n type: 'number', category: 'general', group: 'History',\n label: 'Undo/redo history depth',\n description: 'Maximum number of undo/redo steps retained in memory.',\n defaultValue: 200, min: 10, max: 1000, step: 10,\n },\n\n // \u2500\u2500 Windows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n 'window.animateMinimize': {\n type: 'boolean', category: 'window', group: 'Appearance',\n label: 'Animate minimize/restore',\n description: 'Animate managed windows toward/from the taskbar when minimizing and restoring.',\n defaultValue: true,\n },\n 'window.macShadows': {\n type: 'boolean', category: 'window', group: 'Appearance',\n label: 'macOS-style shadows',\n description: 'Use multi-layered soft shadows on managed windows.',\n defaultValue: true,\n },\n\n // \u2500\u2500 Data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n 'data.tablePageSize': {\n type: 'number', category: 'data', group: 'Tables',\n label: 'Table page size',\n description: 'Number of rows displayed per page in data tables.',\n defaultValue: 100, min: 25, max: 1000, step: 25,\n },\n 'data.defaultResampleMethod': {\n type: 'select', category: 'data', group: 'Import',\n label: 'Default resample method',\n description: 'Aggregation method used when resampling imported time series.',\n defaultValue: 'mean',\n options: [\n { value: 'mean', label: 'Mean' },\n { value: 'sum', label: 'Sum' },\n { value: 'last', label: 'Last' },\n { value: 'first', label: 'First' },\n { value: 'linear', label: 'Linear interpolation' },\n ],\n },\n 'etl.parallelWorkers': {\n type: 'number', category: 'data', group: 'ETL Pipelines',\n label: 'Parallel pipeline workers',\n description: 'Number of pipelines to execute simultaneously in orchestrations. 1 = sequential.',\n defaultValue: 1, min: 1, max: 8, step: 1,\n },\n\n // \u2500\u2500 Logging \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n 'logging.minLevel': {\n type: 'select', category: 'logging', group: 'Output',\n label: 'Minimum log level',\n description: 'Only messages at this level or above are recorded.',\n defaultValue: 'info',\n options: [\n { value: 'trace', label: 'Trace' },\n { value: 'debug', label: 'Debug' },\n { value: 'info', label: 'Info' },\n { value: 'warn', label: 'Warning' },\n { value: 'error', label: 'Error' },\n { value: 'fatal', label: 'Fatal' },\n ],\n },\n 'logging.enableConsole': {\n type: 'boolean', category: 'logging', group: 'Output',\n label: 'Enable console output',\n description: 'Mirror log messages to the browser console.',\n defaultValue: false,\n },\n 'logging.historyLimit': {\n type: 'number', category: 'logging', group: 'History',\n label: 'Log history limit',\n description: 'Maximum number of log entries retained in memory.',\n defaultValue: 500, min: 50, max: 10000, step: 50,\n },\n\n // \u2500\u2500 Projects \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n 'projects.directory': {\n type: 'text', category: 'general', group: 'Projects',\n label: 'Projects directory',\n description: 'Default directory for new projects and bundled demos. Leave empty for OS default.',\n defaultValue: null,\n placeholder: 'OS default (%APPDATA%/EcoSim/projects)',\n },\n\n // \u2500\u2500 AI Assistant \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // Provider, auth, model, and server settings are managed from the chat UI\n // modals. Only behavior settings appear here.\n 'ai.defaultMode': {\n type: 'select', category: 'ai', group: 'Behavior',\n label: 'Default mode',\n description: 'Default interaction mode for the AI assistant.',\n defaultValue: 'ask',\n options: [\n { value: 'ask', label: 'Ask (preview before applying)' },\n { value: 'edit', label: 'Edit (apply immediately)' },\n ],\n },\n 'ai.maxToolCalls': {\n type: 'number', category: 'ai', group: 'Behavior',\n label: 'Max tool calls',\n description: 'Maximum number of tool calls per AI turn.',\n defaultValue: 25, min: 1, max: 100, step: 1,\n },\n\n // \u2500\u2500 Notebook \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n 'notebook.cellWidthMode': {\n type: 'select', category: 'notebook', group: 'Layout',\n label: 'Cell width mode',\n description: 'Controls how wide all cells appear. \"Fixed\" constrains cells to a max-width; \"Full\" stretches all cells.',\n defaultValue: 'fixed',\n options: [\n { value: 'fixed', label: 'Fixed width (900px)' },\n { value: 'full', label: 'Full width' },\n ],\n },\n 'notebook.codeCellMaxHeight': {\n type: 'boolean', category: 'notebook', group: 'Layout',\n label: 'Limit code cell height',\n description: 'When enabled, code cells have a maximum height and scroll internally instead of expanding to show all content.',\n defaultValue: false,\n },\n 'notebook.paramCellMaxHeight': {\n type: 'boolean', category: 'notebook', group: 'Layout',\n label: 'Limit parameter cell height',\n description: 'When enabled, parameter cells have a maximum height and scroll internally instead of expanding to show all content.',\n defaultValue: false,\n },\n 'notebook.defaultCellView': {\n type: 'select', category: 'notebook', group: 'Layout',\n label: 'Default cell view',\n description: 'Which tab to show by default on all cells: Config (edit) or EcoLang (generated code).',\n defaultValue: 'config',\n options: [\n { value: 'config', label: 'Config' },\n { value: 'dsl', label: 'EcoLang' },\n ],\n },\n\n // \u2500\u2500 Advanced \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n 'editor.autosaveDelayMs': {\n type: 'number', category: 'advanced', group: 'Performance',\n label: 'Editor autosave delay (ms)',\n description: 'Delay before the function editor auto-saves changes.',\n defaultValue: 5000, min: 1000, max: 30000, step: 1000,\n },\n 'debug.logSettingsAccess': {\n type: 'boolean', category: 'advanced', group: 'Debug',\n label: 'Log settings access',\n description: 'Log all getSetting/setSetting calls to the console for debugging.',\n defaultValue: false,\n },\n});\n\n/**\n * Shell-owned categories. `order` is the sidebar sort key \u2014 it exists so a\n * registered slice can slot its category *between* two shell categories\n * instead of being stuck at the end.\n */\nconst CATEGORIES = Object.freeze([\n { id: 'general', label: 'General', icon: 'tune', description: 'Workspace behavior and notifications', order: 10 },\n { id: 'ai', label: 'AI Assistant', icon: 'smart_toy', description: 'AI assistant behavior', order: 30 },\n { id: 'window', label: 'Windows', icon: 'web_asset', description: 'Managed window animation and appearance', order: 40 },\n { id: 'data', label: 'Data', icon: 'database', description: 'Table display, import, and pipeline defaults', order: 50 },\n { id: 'logging', label: 'Logging', icon: 'terminal', description: 'Log level, console output, and history', order: 60 },\n { id: 'notebook', label: 'Notebook', icon: 'menu_book', description: 'Notebook editor layout and behavior', order: 70 },\n { id: 'advanced', label: 'Advanced', icon: 'code', description: 'Debug and developer settings', order: 80 },\n]);\n\nconst STORAGE_KEY = 'ecosim.settings.v1';\n\n// \u2500\u2500\u2500 Path / value helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Traverse an object by dot-path parts and return the value.\n * @param {object} obj\n * @param {string[]} parts\n * @returns {*}\n */\nfunction _getNestedValue(obj, parts) {\n let current = obj;\n for (const part of parts) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return undefined;\n }\n current = current[part];\n }\n return current;\n}\n\n/**\n * Set a value in a nested object by dot-path parts, creating intermediates.\n * @param {object} obj\n * @param {string[]} parts\n * @param {*} value\n */\nfunction _setNestedValue(obj, parts, value) {\n let current = obj;\n for (let i = 0; i < parts.length - 1; i++) {\n if (current[parts[i]] === undefined || current[parts[i]] === null || typeof current[parts[i]] !== 'object') {\n current[parts[i]] = {};\n }\n current = current[parts[i]];\n }\n current[parts[parts.length - 1]] = value;\n}\n\n/**\n * Deep equality check for primitives, arrays, and plain objects.\n */\nfunction _deepEqual(a, b) {\n if (a === b) return true;\n if (a == null || b == null) return a === b;\n if (typeof a !== typeof b) return false;\n if (Array.isArray(a)) {\n if (!Array.isArray(b) || a.length !== b.length) return false;\n return a.every((v, i) => _deepEqual(v, b[i]));\n }\n if (typeof a === 'object') {\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n return keysA.every(k => _deepEqual(a[k], b[k]));\n }\n return false;\n}\n\n/** Deep clone via JSON \u2014 the value tree is JSON by construction (it persists). */\nfunction _clone(value) {\n return value === undefined ? undefined : JSON.parse(JSON.stringify(value));\n}\n\n/** Recursively merge `src` into `target` (plain objects only; arrays replace). */\nfunction _deepMerge(target, src) {\n for (const [key, value] of Object.entries(src || {})) {\n const isPlain = value !== null && typeof value === 'object' && !Array.isArray(value);\n if (isPlain) {\n if (target[key] === null || typeof target[key] !== 'object' || Array.isArray(target[key])) {\n target[key] = {};\n }\n _deepMerge(target[key], value);\n } else {\n target[key] = _clone(value);\n }\n }\n return target;\n}\n\n// \u2500\u2500\u2500 The store (the primitive) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Create an isolated, schema-driven settings store.\n *\n * The store owns no domain knowledge: everything it can hold, validate,\n * persist and render is described by the `defaults` / `schema` / `categories`\n * it is handed. Pass none and you get an empty store that an embedder fills\n * entirely via `extend()`.\n *\n * @param {object} [opts]\n * @param {object} [opts.defaults] Nested default values.\n * @param {Object<string, SettingDef>} [opts.schema] Dot-path -> definition.\n * @param {CategoryDef[]} [opts.categories]\n * @param {string} [opts.storageKey] localStorage key. Omit -> no persistence.\n * @param {object} [opts.eventBus] Optional; may be attached later.\n * @returns {object} Frozen store handle.\n */\nexport function createSettingsStore({\n defaults = {},\n schema = {},\n categories = [],\n storageKey = null,\n eventBus = null,\n} = {}) {\n const _defaults = _clone(defaults) ?? {};\n const _schema = { ...schema };\n let _categories = categories.map(c => ({ ...c }));\n const _values = _clone(defaults) ?? {};\n let _bus = eventBus;\n\n const _sortCategories = () => {\n // Array#sort is stable, so equal `order` keeps registration order.\n _categories.sort((a, b) => (a.order ?? 1000) - (b.order ?? 1000));\n };\n _sortCategories();\n\n const _debug = () => _values.debug?.logSettingsAccess;\n\n /**\n * Load user-persisted values from localStorage (sparse merge).\n * Only paths currently present in the schema are restored; anything else in\n * storage is left untouched in memory \u2014 that is what makes `extend()` able\n * to pick up a late-registered namespace's saved values.\n */\n const _load = () => {\n try {\n if (!storageKey || typeof localStorage === 'undefined') return;\n const raw = localStorage.getItem(storageKey);\n if (!raw) return;\n const saved = JSON.parse(raw);\n for (const path of Object.keys(_schema)) {\n const parts = path.split('.');\n const value = _getNestedValue(saved, parts);\n if (value !== undefined) {\n _setNestedValue(_values, parts, value);\n }\n }\n } catch (err) {\n console.warn('[Settings] Failed to load persisted settings', err);\n }\n };\n\n /** Persist values that differ from their defaults (sparse storage). */\n const _save = () => {\n try {\n if (!storageKey || typeof localStorage === 'undefined') return;\n const sparse = {};\n for (const path of Object.keys(_schema)) {\n const parts = path.split('.');\n const current = _getNestedValue(_values, parts);\n const def = _schema[path].defaultValue;\n if (!_deepEqual(current, def)) {\n _setNestedValue(sparse, parts, current);\n }\n }\n if (Object.keys(sparse).length === 0) {\n localStorage.removeItem(storageKey);\n } else {\n localStorage.setItem(storageKey, JSON.stringify(sparse));\n }\n } catch (err) {\n console.warn('[Settings] Failed to persist settings', err);\n }\n };\n\n const _emit = (path, value) => {\n if (!_bus) return;\n _bus.emit(`settings:${path}:changed`, { path, value });\n _bus.emit('settings:changed', { path, value });\n };\n\n _load();\n\n /**\n * Merge an additional slice in \u2014 an embedder's own namespace \u2014 then re-apply\n * persisted overrides for the newly-known paths.\n *\n * ORDERING RULE: call this before the first `set()`. `_save()` rebuilds\n * storage from `Object.keys(_schema)`, so a write that lands *before* a\n * namespace is registered would garbage-collect that namespace's saved\n * values. Registering at the top of bootstrap satisfies this trivially.\n *\n * @param {SettingsSlice} slice\n */\n const extend = ({ defaults: d = {}, schema: s = {}, categories: c = [] } = {}) => {\n _deepMerge(_defaults, d);\n _deepMerge(_values, d);\n Object.assign(_schema, s);\n for (const cat of c) {\n if (!cat?.id) continue;\n if (_categories.some(x => x.id === cat.id)) continue;\n _categories.push({ ...cat });\n }\n _sortCategories();\n _load(); // idempotent: overlays only paths it finds in storage\n };\n\n const get = (path, defaultValue = undefined) => {\n const parts = path.split('.');\n let current = _values;\n for (const part of parts) {\n if (current === null || current === undefined || typeof current !== 'object') {\n if (_debug()) console.warn(`[Settings] Path not found: ${path}`);\n return defaultValue;\n }\n current = current[part];\n }\n if (current === undefined) return defaultValue;\n if (_debug()) console.log(`[Settings] getSetting('${path}') =>`, current);\n return current;\n };\n\n const set = (path, value) => {\n const parts = path.split('.');\n const lastPart = parts.pop();\n let current = _values;\n for (const part of parts) {\n if (current[part] === undefined || current[part] === null) {\n current[part] = {};\n }\n if (typeof current[part] !== 'object') {\n console.warn(`[Settings] Cannot set '${path}': intermediate path is not an object`);\n return false;\n }\n current = current[part];\n }\n current[lastPart] = value;\n if (_debug()) console.log(`[Settings] setSetting('${path}', ${JSON.stringify(value)})`);\n _save();\n _emit(path, value);\n return true;\n };\n\n const getDefault = (path) => {\n const def = _schema[path];\n if (!def) return _clone(_getNestedValue(_defaults, path.split('.')));\n return _clone(def.defaultValue);\n };\n\n const resetOne = (path) => {\n const defaultVal = getDefault(path);\n if (defaultVal === undefined) {\n console.warn(`[Settings] No default found for '${path}'`);\n return false;\n }\n return set(path, defaultVal);\n };\n\n const resetCategoryFn = (categoryId) => {\n for (const [path, def] of Object.entries(_schema)) {\n if (def.category !== categoryId) continue;\n _setNestedValue(_values, path.split('.'), _clone(def.defaultValue));\n }\n _save();\n if (_bus) {\n _bus.emit('settings:category:reset', { category: categoryId });\n _bus.emit('settings:changed', { path: null, category: categoryId });\n }\n };\n\n const resetAll = () => {\n for (const [path, def] of Object.entries(_schema)) {\n _setNestedValue(_values, path.split('.'), _clone(def.defaultValue));\n }\n _save();\n if (_bus) {\n _bus.emit('settings:reset', {});\n _bus.emit('settings:changed', { path: null });\n }\n };\n\n const getByCategory = (categoryId) => {\n const result = [];\n for (const [path, def] of Object.entries(_schema)) {\n if (def.category === categoryId) result.push({ path, ...def });\n }\n return result;\n };\n\n return Object.freeze({\n get,\n set,\n extend,\n getDefault,\n resetOne,\n resetCategory: resetCategoryFn,\n resetAll,\n getAll: () => _clone(_values),\n getSchema: () => _schema,\n // Frozen snapshot: the old module-level CATEGORIES was a frozen const, and\n // a caller that sorted or spliced the live array in place would silently\n // reorder the Settings sidebar. Same objects, same order \u2014 just not ours\n // to wreck.\n getCategories: () => Object.freeze(_categories.slice()),\n getByCategory,\n setEventBus: (bus) => { _bus = bus; },\n });\n}\n\n// \u2500\u2500\u2500 The app-global binding over ONE store \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n//\n// A capability *port* (the host bridge) may have many implementations at once,\n// so a singleton there is a category error. A *value store* with a single\n// physical backing key has cardinality one by construction: two live stores in\n// one document would be two writers to `localStorage[STORAGE_KEY]`. The\n// singleton is the correct cardinality, not a shortcut \u2014 and the factory above\n// is the primitive, so tests and a standalone demo never touch this binding.\n\nconst _store = createSettingsStore({\n defaults: DEFAULTS,\n schema: SCHEMA,\n categories: CATEGORIES,\n storageKey: STORAGE_KEY,\n});\n\n/**\n * Push an embedder's settings namespace into the app-global store.\n *\n * This is the whole of \"push, don't pull\": the framework ships the shell's own\n * settings and the *embedder* hands over its own \u2014 the store never imports a\n * schema it does not own.\n *\n * MUST run before any setSetting() \u2014 see `extend()`.\n *\n * @param {SettingsSlice} slice\n */\nexport function registerSettings(slice) {\n _store.extend(slice);\n}\n\n/**\n * Register the EventBus instance for settings change notifications.\n * Called once during app bootstrap.\n * @param {object} eventBus\n */\nexport function registerSettingsEventBus(eventBus) {\n _store.setEventBus(eventBus);\n}\n\n/**\n * Get a setting value by dot-notation path.\n * @param {string} path - Dot-separated path (e.g., 'workspace.save.showToast')\n * @param {*} [defaultValue] - Fallback if path not found\n * @returns {*} The setting value or defaultValue\n */\nexport function getSetting(path, defaultValue = undefined) {\n return _store.get(path, defaultValue);\n}\n\n/**\n * Set a setting value. Persists to localStorage and emits change events.\n * @param {string} path - Dot-separated path\n * @param {*} value - Value to set\n * @returns {boolean} True if set successfully\n */\nexport function setSetting(path, value) {\n return _store.set(path, value);\n}\n\n/**\n * Get the default value for a setting path.\n * @param {string} path - Dot-separated path\n * @returns {*} The default value, or undefined if the path is unknown\n */\nexport function getDefaultValue(path) {\n return _store.getDefault(path);\n}\n\n/**\n * Reset a setting to its default value.\n * @param {string} path - Dot-separated path\n * @returns {boolean} True if reset successfully\n */\nexport function resetSetting(path) {\n return _store.resetOne(path);\n}\n\n/**\n * Reset all settings in a category to their defaults.\n * @param {string} categoryId\n */\nexport function resetCategory(categoryId) {\n _store.resetCategory(categoryId);\n}\n\n/** Reset all settings to their defaults. */\nexport function resetAllSettings() {\n _store.resetAll();\n}\n\n/**\n * Get all settings as a plain object (for serialization or debugging).\n * @returns {object} Deep copy of current settings\n */\nexport function getAllSettings() {\n return _store.getAll();\n}\n\n// \u2500\u2500\u2500 Schema / Category API (for Settings page UI) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Get the full settings schema (shell + every registered slice).\n * @returns {Object<string, SettingDef>}\n */\nexport function getSchema() {\n return _store.getSchema();\n}\n\n/**\n * Get the categories list, in sidebar order.\n * @returns {CategoryDef[]}\n */\nexport function getCategories() {\n return _store.getCategories();\n}\n\n/**\n * Get all settings definitions for a given category, in schema order.\n * @param {string} categoryId\n * @returns {Array<{path:string} & SettingDef>}\n */\nexport function getSettingsByCategory(categoryId) {\n return _store.getByCategory(categoryId);\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/editor/notebook_tab_bar.js"],
4
- "sourcesContent": ["/**\n * NotebookTabBar \u2014 tab strip showing open files, with dirty indicators,\n * close buttons, drag-and-drop reordering, double-click rename, and\n * right-click context menu.\n *\n * Uses the same `.tab` / `.tab-title` / `.tab-dirty` / `.tab-close` DOM structure\n * as the flow-page tab bar, so all editor tab bars share a unified appearance.\n *\n * Calls back into parent via:\n * onActivate(filePath)\n * onClose(filePath)\n * onCloseOthers(filePath)\n * onCloseToRight(filePath)\n * onCloseAll()\n * onCloseSaved()\n * onRename(oldPath, newPath)\n * onDuplicate(filePath)\n * onReorder(orderedPaths)\n * onRevealInExplorer(filePath)\n * onSplitRight(filePath)\n * onMoveToOtherPane(filePath)\n * onDropFromOtherPane(filePath) \u2014 cross-pane drag-and-drop\n */\n\nimport { DragReorder } from '../ui/components/drag_reorder.js';\n\n/** Custom MIME type so tab bars recognise cross-pane drags. */\nconst TAB_MIME = 'application/x-ecosim-tab';\n\nexport class NotebookTabBar {\n /** @type {HTMLElement} */\n #container = null;\n\n /** @type {object[]} [{filePath, label, fileType, isDirty}] */\n #tabs = [];\n\n /** @type {string|null} */\n #activeTab = null;\n\n /** @type {object} callbacks */\n #callbacks = {};\n\n // \u2500\u2500\u2500 Context menu \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** @type {HTMLElement|null} */\n #contextMenuEl = null;\n\n /** @type {Function|null} */\n #boundHideContextMenu = null;\n\n // \u2500\u2500\u2500 Drag and drop \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /** Same-pane reorder. Cross-pane drops stay in this class's own\n * container handlers (#onStripDrag*).\n * @type {DragReorder|null} */\n #dragReorder = null;\n\n mount(container, callbacks = {}) {\n this.#container = container;\n this.#callbacks = callbacks;\n this.#container.className = 'tabs notebook-tabs';\n this.#boundHideContextMenu = () => this.#hideContextMenu();\n this.#installStripDnDHandlers();\n // NOT PASSIVE: it has to be able to take the wheel from the page.\n this.#container.addEventListener('wheel', this.#onWheel, { passive: false });\n this.#dragReorder = new DragReorder({\n container: this.#container,\n itemSelector: '.tab',\n keyAttr: 'path',\n axis: 'x',\n draggableGuard: (e) => {\n if (e.target.closest('.twm-tab-close')) return false;\n const title = e.target.closest('.tab')?.querySelector('.twm-tab-title');\n return title?.getAttribute('contenteditable') !== 'true';\n },\n onDragStart: (e, key, item) => {\n // Carry the cross-pane MIME so other panes accept this tab.\n try { e.dataTransfer.setData(TAB_MIME, key); } catch (_) {}\n // C33. \u2026AND LET THE HOST ADD ITS OWN, which is the whole of\n // what a second consumer of this strip needs from it.\n //\n // `DragReorder` publishes this hook for exactly this purpose\n // (\"host hook to augment dataTransfer (e.g. add a cross-pane\n // MIME)\", `../ui/components/drag_reorder.js`), and this class\n // consumed it and stopped there. The tile renderer mounts one\n // of these per tile and needs to mark the drag as one of ITS\n // tabs \u2014 a different question from \"is this an editor tab\",\n // asked of the same gesture.\n //\n // ADDITIVE BY CONSTRUCTION: `TAB_MIME` is set first and\n // unchanged, so `EditorPane`'s existing cross-pane drop cannot\n // notice that anyone else is listening.\n try { this.#callbacks.onDragStart?.(e, key, item); }\n catch (err) { console.error('[tab-bar] onDragStart threw', err); }\n },\n onReorder: (order) => this.#callbacks.onReorder?.(order),\n });\n this.#render();\n }\n\n /**\n * Sync tabs from ProjectModel state.\n * @param {Array<{ filePath: string, fileType: string, isDirty: boolean }>} tabs\n * @param {string|null} activeFilePath\n */\n update(tabs, activeFilePath) {\n this.#tabs = tabs;\n this.#activeTab = activeFilePath;\n this.#render();\n }\n\n markDirty(filePath, isDirty) {\n const tab = this.#tabs.find(t => t.filePath === filePath);\n if (tab) {\n tab.isDirty = isDirty;\n this.#render();\n }\n }\n\n dispose() {\n this.#hideContextMenu();\n this.#removeStripDnDHandlers();\n this.#container?.removeEventListener('wheel', this.#onWheel);\n if (this.#revealFrame) cancelAnimationFrame(this.#revealFrame);\n this.#revealFrame = 0;\n this.#dragReorder?.destroy();\n this.#dragReorder = null;\n this.#container = null;\n }\n\n // Material symbol per file kind, merged over the generic set. The map used to\n // hardcode EcoAgent's kinds \u2014 `scenario`, `dashboard`, `model` \u2014 so a generic\n // tab bar knew one application's file taxonomy. Pass `fileTypeIcons` to add\n // your own.\n static #FILE_TYPE_ICONS = {\n module: 'extension',\n test: 'fact_check',\n diff: 'difference',\n unknown: 'description',\n };\n\n static #EXTRA_ICONS = {};\n\n /**\n * Add your application's file kinds to the tab-bar icon map.\n *\n * The map used to hardcode `scenario: 'science'`, `dashboard: 'dashboard'` and\n * `model: 'schema'` \u2014 EcoAgent's file taxonomy, baked into a generic tab bar.\n *\n * @param {Object.<string, string>} icons fileType -> material symbol name\n */\n static setFileTypeIcons(icons = {}) {\n NotebookTabBar.#EXTRA_ICONS = { ...icons };\n }\n\n static #iconFor(fileType) {\n return NotebookTabBar.#EXTRA_ICONS[fileType]\n ?? NotebookTabBar.#FILE_TYPE_ICONS[fileType]\n ?? NotebookTabBar.#FILE_TYPE_ICONS.unknown;\n }\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // Rendering\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n #render() {\n if (!this.#container) return;\n\n // THE STRIP KEEPS ITS SCROLL ACROSS A REBUILD. Emptying it shrinks its\n // scroll width to nothing, which clamps `scrollLeft` to 0 \u2014 so every\n // render (a tab activated, a title changed) threw a strip scrolled to\n // its tenth tab back to its first.\n const keepLeft = this.#container.scrollLeft;\n this.#container.innerHTML = '';\n\n for (const tab of this.#tabs) {\n const isActive = tab.filePath === this.#activeTab;\n const rawPath = tab.filePath.replace(/^(diff|builtin):\\/\\//, '');\n const label = tab.label\n ?? (tab.fileType === 'diff'\n ? `\u2194 ${rawPath.split('/').pop()}`\n : rawPath.split('/').pop().replace(/\\.[^.]+$/, ''));\n const icon = NotebookTabBar.#iconFor(tab.fileType);\n\n const tabEl = document.createElement('div');\n tabEl.className = `tab${isActive ? ' active' : ''}${tab.isPreview ? ' tab--preview' : ''}`;\n tabEl.dataset.path = tab.filePath;\n tabEl.title = tab.filePath;\n\n tabEl.innerHTML = `\n <span class=\"material-symbols-outlined tab-icon\">${icon}</span>\n <span class=\"twm-tab-title\">${this.#escHtml(label)}</span>\n ${tab.isDirty ? '<span class=\"tab-dirty\">\\u25cf</span>' : ''}\n ${tab.readonly ? '' : '<button class=\"twm-tab-close\" title=\"Close tab\" aria-label=\"Close tab\">\\u00d7</button>'}\n `;\n\n // Click \u2192 activate\n tabEl.addEventListener('click', (e) => {\n if (e.target.closest('.twm-tab-close')) return;\n if (tabEl.querySelector('.twm-tab-title')?.getAttribute('contenteditable') === 'true') return;\n this.#callbacks.onActivate?.(tab.filePath);\n });\n\n // Close button\n tabEl.querySelector('.twm-tab-close')?.addEventListener('click', (e) => {\n e.stopPropagation();\n this.#callbacks.onClose?.(tab.filePath);\n });\n\n // Double-click \u2192 inline rename\n tabEl.addEventListener('dblclick', (e) => {\n if (e.target.closest('.twm-tab-close')) return;\n this.#beginInlineRename(tab.filePath);\n });\n\n // F2 \u2192 inline rename\n tabEl.addEventListener('keydown', (e) => {\n if (e.key === 'F2') {\n e.preventDefault();\n this.#beginInlineRename(tab.filePath);\n }\n });\n\n // Context menu\n tabEl.addEventListener('contextmenu', (e) => {\n e.preventDefault();\n e.stopPropagation();\n this.#showContextMenu(e.clientX, e.clientY, tab.filePath);\n });\n\n this.#container.appendChild(tabEl);\n }\n // Make the freshly-rendered tabs draggable-to-reorder.\n this.#dragReorder?.attach();\n\n this.#container.scrollLeft = keepLeft;\n // A tab that has just BECOME active \u2014 opened, switched to, moved here\n // from another pane \u2014 is scrolled into the strip. Only then: a render\n // for any other reason (a title, a dirty dot) leaves the strip where the\n // reader put it, rather than yanking it back to the active tab.\n const revealKey = `${this.#activeTab}\\u0000${this.#tabs.length}`;\n if (revealKey !== this.#revealedKey) {\n this.#revealedKey = revealKey;\n this.#revealActive(true);\n }\n }\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // Scrolling (1.5) \u2014 the strip scrolls rather than wrapping or shrinking its\n // tabs, and hides its scrollbar (a bar in a 26px strip eats a third of every\n // label). So it owes a mouse user every other way in: a plain wheel, the\n // active tab brought into view, and \u2014 in `DragReorder._autoScrollEdge` \u2014\n // the edges scrolling while a tab is dragged toward them.\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n /** @type {string|null} the active tab + count last scrolled into view */\n #revealedKey = null;\n\n /** @type {number} a pending retry, for a strip not yet laid out */\n #revealFrame = 0;\n\n /** Bring the active tab fully into the strip \u2014 and ONLY the strip. Not\n * `scrollIntoView`, which scrolls every scrollable ancestor as well and\n * would drag the tile, the window or the page along with the tab. */\n #revealActive(retry = false) {\n const el = this.#container;\n if (!el) return;\n const active = el.querySelector(':scope > .tab.active');\n if (!active) return;\n if (!el.isConnected || el.clientWidth === 0) {\n // Mounted but not laid out yet (the renderer updates a strip before\n // it attaches it). Once, on the next frame \u2014 not a loop.\n if (retry && !this.#revealFrame && typeof requestAnimationFrame === 'function') {\n this.#revealFrame = requestAnimationFrame(() => {\n this.#revealFrame = 0;\n this.#revealActive(false);\n });\n }\n return;\n }\n const box = el.getBoundingClientRect();\n const tab = active.getBoundingClientRect();\n // Client pixels to the strip's own: 1 unless something above it zooms.\n const scale = (el.offsetWidth ? box.width / el.offsetWidth : 1) || 1;\n const left = (tab.left - box.left) / scale + el.scrollLeft;\n const right = left + tab.width / scale;\n if (left < el.scrollLeft) el.scrollLeft = left;\n else if (right > el.scrollLeft + el.clientWidth) el.scrollLeft = right - el.clientWidth;\n }\n\n /**\n * A VERTICAL WHEEL SCROLLS THE STRIP SIDEWAYS. Chromium and Firefox scroll\n * an element that overflows only horizontally with Shift+wheel or a\n * touchpad, and not with the plain wheel most people have \u2014 so with the\n * scrollbar hidden, every tab past the edge was unreachable with a mouse.\n *\n * The wheel is taken from the page only while the strip can actually move\n * that way: at either end it is left alone, so a wheel over a strip that\n * has nothing more to show still scrolls whatever is behind it. A gesture\n * that is already horizontal (a touchpad, Shift+wheel) and Ctrl+wheel (zoom)\n * are the browser's, untouched.\n */\n #onWheel = (e) => {\n const el = this.#container;\n if (!el || e.ctrlKey || e.shiftKey) return;\n if (Math.abs(e.deltaX) >= Math.abs(e.deltaY)) return;\n const room = el.scrollWidth - el.clientWidth;\n if (room <= 0) return;\n const unit = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? el.clientWidth : 1;\n const next = Math.max(0, Math.min(room, el.scrollLeft + e.deltaY * unit));\n if (Math.abs(next - el.scrollLeft) < 0.5) return;\n e.preventDefault();\n el.scrollLeft = next;\n };\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // Drag and drop reordering (same-pane + cross-pane)\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n #installStripDnDHandlers() {\n if (!this.#container) return;\n this.#container.addEventListener('dragover', this.#onStripDragOver);\n this.#container.addEventListener('drop', this.#onStripDrop);\n this.#container.addEventListener('dragleave', this.#onStripDragLeave);\n }\n\n #removeStripDnDHandlers() {\n if (!this.#container) return;\n this.#container.removeEventListener('dragover', this.#onStripDragOver);\n this.#container.removeEventListener('drop', this.#onStripDrop);\n this.#container.removeEventListener('dragleave', this.#onStripDragLeave);\n }\n\n /** Check whether a drag event carries a cross-pane tab (not from this bar).\n *\n * C33. A HOST MAY NAME A SECOND MIME, at mount, as\n * `callbacks.externalTabMimes` \u2014 the tile renderer's tabs are not editor\n * tabs and do not carry `application/x-ecosim-tab`, so without this the\n * strip in tile B would refuse a tab dragged out of tile A's strip. Empty\n * by default, so every existing consumer keeps exactly today's admission\n * test.\n *\n * THE `isActive()` EARLY RETURN STAYS FIRST AND STAYS UNCHANGED. It is the\n * one line that keeps this bar's own reorder from being read as a foreign\n * drop, and no widening of the MIME list may be allowed to reach past it.\n *\n * Only `types` is consulted, never `getData` \u2014 under the HTML5 protected\n * mode `getData` returns the empty string for every event except `drop`,\n * so a payload read here would find nothing and arm nothing. */\n #isExternalTabDrag(e) {\n if (this.#dragReorder?.isActive()) return false; // same-pane drag is active\n const extra = Array.isArray(this.#callbacks.externalTabMimes)\n ? this.#callbacks.externalTabMimes : [];\n try {\n const types = e.dataTransfer.types;\n return types.includes(TAB_MIME) || extra.some((m) => types.includes(m));\n } catch { return false; }\n }\n\n // Same-pane reorder is handled by the shared DragReorder module (set\n // up in mount()). These container handlers cover ONLY cross-pane tab\n // drops \u2014 gated on `#isExternalTabDrag`, which defers while our own\n // reorder drag is active.\n\n #onStripDragOver = (e) => {\n if (this.#isExternalTabDrag(e)) {\n e.preventDefault();\n try { e.dataTransfer.dropEffect = 'move'; } catch (_) {}\n this.#container.classList.add('notebook-tabs--drop-target');\n }\n };\n\n #onStripDrop = (e) => {\n if (this.#isExternalTabDrag(e)) {\n e.preventDefault();\n this.#container.classList.remove('notebook-tabs--drop-target');\n const filePath = e.dataTransfer.getData(TAB_MIME) || e.dataTransfer.getData('text/plain');\n if (filePath) {\n this.#callbacks.onDropFromOtherPane?.(filePath);\n }\n }\n };\n\n #onStripDragLeave = (e) => {\n if (!this.#container.contains(e.relatedTarget)) {\n this.#container.classList.remove('notebook-tabs--drop-target');\n }\n };\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // Context menu\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n #showContextMenu(x, y, filePath) {\n this.#hideContextMenu();\n\n const idx = this.#tabs.findIndex(t => t.filePath === filePath);\n const total = this.#tabs.length;\n\n const allItems = [\n { label: 'Rename', icon: 'edit', action: 'rename', shortcut: 'F2' },\n { label: 'Duplicate', icon: 'content_copy', action: 'duplicate' },\n { separator: true },\n { label: 'Split Right', icon: 'vertical_split', action: 'split-right', shortcut: 'Ctrl+\\\\' },\n { label: 'Move to Other Pane',icon: 'swap_horiz', action: 'move-to-other' },\n { separator: true },\n { label: 'Close', icon: 'close', action: 'close', danger: true },\n { label: 'Close Others', icon: 'close_fullscreen', action: 'close-others', danger: true, disabled: total <= 1 },\n { label: 'Close to the Right',icon: 'tab_close', action: 'close-right', danger: true, disabled: idx === -1 || idx >= total - 1 },\n { label: 'Close All', icon: 'tab_close_inactive', action: 'close-all', danger: true },\n { label: 'Close Saved', icon: 'check_circle', action: 'close-saved', danger: true },\n { separator: true },\n { label: 'Reveal in Explorer', icon: 'folder_open', action: 'reveal' },\n ];\n\n const menuFilter = this.#callbacks.menuFilter;\n const items = menuFilter\n ? allItems.filter(item => item.separator || menuFilter(item.action, filePath) !== false)\n : allItems;\n\n // Collapse consecutive / leading / trailing separators\n const cleaned = [];\n for (const item of items) {\n if (item.separator) {\n if (cleaned.length > 0 && !cleaned[cleaned.length - 1].separator) cleaned.push(item);\n } else {\n cleaned.push(item);\n }\n }\n while (cleaned.length > 0 && cleaned[cleaned.length - 1].separator) cleaned.pop();\n\n const menu = document.createElement('div');\n menu.className = 'nb-context-menu';\n\n for (const item of cleaned) {\n if (item.separator) {\n const sep = document.createElement('div');\n sep.className = 'nb-context-menu__separator';\n menu.appendChild(sep);\n continue;\n }\n\n const btn = document.createElement('button');\n btn.className = 'nb-context-menu__item';\n if (item.danger) btn.classList.add('nb-context-menu__item--danger');\n if (item.disabled) btn.classList.add('nb-context-menu__item--disabled');\n\n btn.innerHTML = `<span class=\"material-symbols-outlined\">${item.icon}</span><span>${this.#escHtml(item.label)}</span>${\n item.shortcut ? `<span class=\"nb-context-menu__shortcut\">${item.shortcut}</span>` : ''\n }`;\n\n if (!item.disabled) {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.#hideContextMenu();\n this.#handleContextMenuAction(item.action, filePath);\n });\n }\n menu.appendChild(btn);\n }\n\n document.body.appendChild(menu);\n this.#contextMenuEl = menu;\n\n // Position with viewport clamping\n const rect = menu.getBoundingClientRect();\n const left = Math.min(x, window.innerWidth - rect.width - 8);\n const top = Math.min(y, window.innerHeight - rect.height - 8);\n menu.style.left = `${Math.max(0, left)}px`;\n menu.style.top = `${Math.max(0, top)}px`;\n\n // Animate in\n requestAnimationFrame(() => menu.classList.add('visible'));\n\n // Dismiss on outside click or Escape\n setTimeout(() => {\n document.addEventListener('click', this.#boundHideContextMenu, true);\n document.addEventListener('contextmenu', this.#boundHideContextMenu, true);\n }, 0);\n document.addEventListener('keydown', this.#onKeyDown);\n }\n\n #hideContextMenu() {\n if (!this.#contextMenuEl) return;\n this.#contextMenuEl.remove();\n this.#contextMenuEl = null;\n document.removeEventListener('click', this.#boundHideContextMenu, true);\n document.removeEventListener('contextmenu', this.#boundHideContextMenu, true);\n document.removeEventListener('keydown', this.#onKeyDown);\n }\n\n #onKeyDown = (e) => {\n if (e.key === 'Escape') this.#hideContextMenu();\n };\n\n #handleContextMenuAction(action, filePath) {\n switch (action) {\n case 'rename': this.#beginInlineRename(filePath); break;\n case 'duplicate': this.#callbacks.onDuplicate?.(filePath); break;\n case 'close': this.#callbacks.onClose?.(filePath); break;\n case 'close-others': this.#callbacks.onCloseOthers?.(filePath); break;\n case 'close-right': this.#callbacks.onCloseToRight?.(filePath); break;\n case 'close-all': this.#callbacks.onCloseAll?.(); break;\n case 'close-saved': this.#callbacks.onCloseSaved?.(); break;\n case 'split-right': this.#callbacks.onSplitRight?.(filePath); break;\n case 'move-to-other':this.#callbacks.onMoveToOtherPane?.(filePath); break;\n case 'reveal': this.#callbacks.onRevealInExplorer?.(filePath); break;\n }\n }\n\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n // Inline rename (contenteditable on tab title)\n // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\n #beginInlineRename(filePath) {\n const tabEl = this.#container?.querySelector(`.tab[data-path=\"${CSS.escape(filePath)}\"]`);\n if (!tabEl) return;\n\n const title = tabEl.querySelector('.twm-tab-title');\n if (!title || title.getAttribute('contenteditable') === 'true') return;\n\n const tab = this.#tabs.find(t => t.filePath === filePath);\n if (!tab) return;\n\n // model.notebook, builtin, and readonly files cannot be renamed\n if (tab.fileType === 'model') return;\n if (filePath.startsWith('builtin://')) return;\n if (tab.readonly) return;\n\n const original = title.textContent || '';\n title.setAttribute('contenteditable', 'true');\n title.focus();\n\n try {\n const range = document.createRange();\n range.selectNodeContents(title);\n const sel = window.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n } catch (_) { /* ignore */ }\n\n let committed = false;\n\n const finish = (commit) => {\n if (committed) return;\n committed = true;\n\n const newName = (title.textContent || '').trim();\n title.removeAttribute('contenteditable');\n title.removeEventListener('keydown', onKeyDown);\n title.removeEventListener('blur', onBlur, true);\n\n try { window.getSelection()?.removeAllRanges?.(); } catch (_) { /* ignore */ }\n\n if (commit && newName && newName !== original && /^[\\w][\\w.-]*$/.test(newName)) {\n title.textContent = newName;\n const dir = filePath.split('/').slice(0, -1).join('/');\n const ext = filePath.split('.').pop();\n const newPath = `${dir}/${newName}.${ext}`;\n this.#callbacks.onRename?.(filePath, newPath);\n } else {\n title.textContent = original;\n }\n };\n\n const onKeyDown = (e) => {\n if (e.key === 'Enter') { e.preventDefault(); finish(true); }\n else if (e.key === 'Escape') { e.preventDefault(); finish(false); }\n e.stopPropagation();\n };\n\n const onBlur = () => finish(true);\n\n title.addEventListener('keydown', onKeyDown);\n title.addEventListener('blur', onBlur, true);\n }\n\n #escHtml(s) {\n return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n }\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }