flexdesk 0.16.0 → 0.17.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 (251) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/LICENSE +0 -0
  3. package/README.md +2261 -42
  4. package/THIRD_PARTY_LICENSES.md +0 -0
  5. package/css/base.css +1834 -75
  6. package/css/flexdesk.css +3373 -238
  7. package/css/overrides.css +16 -0
  8. package/css/reset.css +0 -0
  9. package/css/tokens.css +0 -0
  10. package/dist/canvas.js +6 -239
  11. package/dist/canvas.js.map +3 -3
  12. package/dist/charts.js +709 -18
  13. package/dist/charts.js.map +4 -4
  14. package/dist/chunk-3PHCPZHT.js +0 -0
  15. package/dist/chunk-3PHCPZHT.js.map +0 -0
  16. package/dist/chunk-4A7SJC3T.js +503 -0
  17. package/dist/chunk-4A7SJC3T.js.map +7 -0
  18. package/dist/{chunk-6JSOVNID.js → chunk-CVMCZZX2.js} +635 -10
  19. package/dist/chunk-CVMCZZX2.js.map +7 -0
  20. package/dist/chunk-D3COLZZ2.js +1311 -0
  21. package/dist/chunk-D3COLZZ2.js.map +7 -0
  22. package/dist/chunk-FOOS3T5L.js +0 -0
  23. package/dist/chunk-FOOS3T5L.js.map +0 -0
  24. package/dist/{chunk-SN4LSOAR.js → chunk-GOQLR5WR.js} +452 -2
  25. package/dist/chunk-GOQLR5WR.js.map +7 -0
  26. package/dist/{chunk-FL5KFNQH.js → chunk-HNU6MM2B.js} +52 -17
  27. package/dist/chunk-HNU6MM2B.js.map +7 -0
  28. package/dist/chunk-HYJYYEPK.js +375 -0
  29. package/dist/chunk-HYJYYEPK.js.map +7 -0
  30. package/dist/chunk-JKZLNKG6.js +2041 -0
  31. package/dist/chunk-JKZLNKG6.js.map +7 -0
  32. package/dist/chunk-JYWURG5T.js +0 -0
  33. package/dist/chunk-JYWURG5T.js.map +0 -0
  34. package/dist/{chunk-RQM5Z2MU.js → chunk-MCIXFNVF.js} +633 -311
  35. package/dist/chunk-MCIXFNVF.js.map +7 -0
  36. package/dist/chunk-N7HC3ADV.js +30 -0
  37. package/dist/chunk-N7HC3ADV.js.map +7 -0
  38. package/dist/{chunk-FBGP5KN5.js → chunk-Q36EPT2R.js} +3268 -203
  39. package/dist/chunk-Q36EPT2R.js.map +7 -0
  40. package/dist/chunk-QWQJUDPD.js +610 -0
  41. package/dist/chunk-QWQJUDPD.js.map +7 -0
  42. package/dist/{chunk-NLTOY57M.js → chunk-UURZ37SD.js} +28 -48
  43. package/dist/chunk-UURZ37SD.js.map +7 -0
  44. package/dist/chunk-UWO43BZU.js +111 -0
  45. package/dist/chunk-UWO43BZU.js.map +7 -0
  46. package/dist/chunk-WVFGV5FT.js +0 -0
  47. package/dist/chunk-WVFGV5FT.js.map +0 -0
  48. package/dist/core.js +170 -118
  49. package/dist/core.js.map +2 -2
  50. package/dist/editor.js +156 -70
  51. package/dist/editor.js.map +2 -2
  52. package/dist/flexdesk.css +3373 -238
  53. package/dist/flow.js +2789 -306
  54. package/dist/flow.js.map +4 -4
  55. package/dist/host.js +109 -3
  56. package/dist/host.js.map +3 -3
  57. package/dist/reset.css +0 -0
  58. package/dist/tile_registry-6WZPTUZV.js +0 -0
  59. package/dist/tile_registry-6WZPTUZV.js.map +0 -0
  60. package/dist/tiles.js +1131 -253
  61. package/dist/tiles.js.map +4 -4
  62. package/dist/tokens.css +0 -0
  63. package/dist/widgets.js +3254 -2112
  64. package/dist/widgets.js.map +4 -4
  65. package/dist/wm.js +1227 -345
  66. package/dist/wm.js.map +4 -4
  67. package/package.json +3 -1
  68. package/src/canvas/canvas_adapter.js +5 -0
  69. package/src/canvas/edge_router.js +0 -0
  70. package/src/canvas/graph/connector_router.js +0 -0
  71. package/src/canvas/graph/history_service.js +0 -0
  72. package/src/canvas/graph/node_platform.js +0 -0
  73. package/src/canvas/index.js +1 -0
  74. package/src/canvas/layered_layout.js +244 -0
  75. package/src/charts/chart_types.js +0 -0
  76. package/src/charts/data_series_plot_window.js +0 -0
  77. package/src/charts/downsample.js +2 -2
  78. package/src/charts/plot_config.js +53 -29
  79. package/src/charts/plot_config_editor.js +627 -0
  80. package/src/charts/plot_grid.js +449 -0
  81. package/src/charts/plot_popout_window.js +103 -317
  82. package/src/charts/plotly_wrapper.js +22 -2
  83. package/src/charts/series_transforms.js +206 -0
  84. package/src/core/event_bus.js +0 -0
  85. package/src/core/logging.js +1 -1
  86. package/src/core/settings.js +105 -19
  87. package/src/core/state_guard.js +93 -51
  88. package/src/core/state_guard_config.js +85 -74
  89. package/src/core/state_machine.js +0 -0
  90. package/src/editor/editor_pane.js +3 -3
  91. package/src/editor/monaco_editor_factory.js +124 -60
  92. package/src/editor/monaco_loader.js +103 -28
  93. package/src/editor/notebook_search.js +0 -0
  94. package/src/editor/notebook_tab_bar.js +38 -52
  95. package/src/editor/notebook_undo_manager.js +0 -0
  96. package/src/editor/split_pane_container.js +6 -3
  97. package/src/flow/canvas_editor/connections.js +90 -0
  98. package/src/flow/canvas_editor/editor.js +2351 -153
  99. package/src/flow/canvas_editor/index.js +2 -1
  100. package/src/flow/canvas_editor/layout.js +119 -12
  101. package/src/flow/canvas_editor/strings.js +80 -0
  102. package/src/flow/kit/always_before.js +0 -0
  103. package/src/flow/kit/catalogue.js +97 -3
  104. package/src/flow/kit/chip_input.js +0 -0
  105. package/src/flow/kit/dom.js +0 -0
  106. package/src/flow/kit/findings.js +0 -0
  107. package/src/flow/kit/history.js +0 -0
  108. package/src/flow/kit/index.js +3 -3
  109. package/src/flow/kit/keys.js +7 -1
  110. package/src/flow/kit/logic_graph.js +97 -15
  111. package/src/flow/kit/references.js +0 -0
  112. package/src/flow/kit/settings_panel.js +0 -0
  113. package/src/flow/kit/settings_schema.js +2 -1
  114. package/src/flow/kit/step_picker.js +0 -0
  115. package/src/flow/kit/strings.js +3 -1
  116. package/src/flow/kit/value_picker.js +0 -0
  117. package/src/flow/kit/widgets.js +86 -109
  118. package/src/flow/lanes/editor.js +136 -14
  119. package/src/flow/lanes/index.js +3 -1
  120. package/src/flow/lanes/layout.js +0 -0
  121. package/src/flow/lanes/pipeline.js +44 -2
  122. package/src/flow/lanes/preview.js +0 -0
  123. package/src/flow/lanes/strings.js +1 -0
  124. package/src/flow/outline/editor.js +0 -0
  125. package/src/flow/outline/index.js +0 -0
  126. package/src/flow/outline/mapping.js +0 -0
  127. package/src/flow/outline/menu.js +0 -0
  128. package/src/flow/outline/operations.js +0 -0
  129. package/src/flow/outline/recognise.js +0 -0
  130. package/src/flow/outline/strings.js +0 -0
  131. package/src/help/help_modal.js +168 -42
  132. package/src/help/help_registry.js +12 -1
  133. package/src/host/external_links.js +0 -0
  134. package/src/host/file_picker.js +117 -0
  135. package/src/host/host.js +10 -2
  136. package/src/host/photino_host.js +9 -0
  137. package/src/host/photino_host.md +21 -3
  138. package/src/host/pywebview_host.js +10 -0
  139. package/src/tiles/chart_tiles.js +53 -245
  140. package/src/tiles/config_schema.js +8 -0
  141. package/src/tiles/figure_tile.js +322 -0
  142. package/src/tiles/layout_persistence.js +3 -3
  143. package/src/tiles/list_tiles.js +422 -0
  144. package/src/tiles/scope_picker.js +96 -0
  145. package/src/tiles/tile_base.js +12 -1
  146. package/src/tiles/tile_config_form.js +442 -0
  147. package/src/tiles/tile_grid.js +38 -1
  148. package/src/tiles/tile_registry.js +0 -0
  149. package/src/tiling/bottom_panel_tabs.js +67 -99
  150. package/src/tiling/command_palette.js +64 -19
  151. package/src/tiling/content_registry.js +4 -1
  152. package/src/tiling/desktops.js +11 -1
  153. package/src/tiling/entity_sources.js +0 -0
  154. package/src/tiling/keymap.js +403 -128
  155. package/src/tiling/kind_taxonomy.js +78 -0
  156. package/src/tiling/landing_table.js +0 -0
  157. package/src/tiling/loading_overlay.js +0 -0
  158. package/src/tiling/nav_panel.js +59 -10
  159. package/src/tiling/page_factory.js +5 -5
  160. package/src/tiling/panel_availability.js +49 -0
  161. package/src/tiling/panel_keys.js +0 -0
  162. package/src/tiling/shell.js +114 -12
  163. package/src/tiling/tab_strip.js +0 -0
  164. package/src/tiling/tile_breadcrumb.js +0 -0
  165. package/src/tiling/tile_renderer.js +105 -9
  166. package/src/tiling/tile_tab_menu.js +0 -0
  167. package/src/tiling/tile_tree.js +0 -0
  168. package/src/tiling/wm.js +562 -30
  169. package/src/tiling/zoom.js +0 -0
  170. package/src/ui/base/component_base.js +0 -0
  171. package/src/ui/base/controller_base.js +0 -0
  172. package/src/ui/base/page_base.js +0 -0
  173. package/src/ui/components/about_dialog.js +0 -0
  174. package/src/ui/components/action_dropdown.js +30 -2
  175. package/src/ui/components/alert_log.js +0 -0
  176. package/src/ui/components/alerts_pane.js +0 -0
  177. package/src/ui/components/attribute_list_editor.js +0 -0
  178. package/src/ui/components/autocomplete_field.js +0 -0
  179. package/src/ui/components/cell_editor_host.js +211 -0
  180. package/src/ui/components/cell_grid.js +648 -0
  181. package/src/ui/components/cell_selection.js +220 -0
  182. package/src/ui/components/choice_controls.js +351 -0
  183. package/src/ui/components/color_field.js +211 -0
  184. package/src/ui/components/color_list_field.js +210 -0
  185. package/src/ui/components/column_fit.js +0 -0
  186. package/src/ui/components/column_groups.js +314 -0
  187. package/src/ui/components/column_order.js +142 -0
  188. package/src/ui/components/computing_status_window.js +98 -25
  189. package/src/ui/components/confirm_dialog.js +81 -38
  190. package/src/ui/components/context_menu.js +2 -2
  191. package/src/ui/components/conversation_view.js +440 -0
  192. package/src/ui/components/crosstab.js +289 -0
  193. package/src/ui/components/data_table.js +601 -62
  194. package/src/ui/components/detail_header.js +22 -11
  195. package/src/ui/components/document_outline.js +397 -0
  196. package/src/ui/components/drag_reorder.js +0 -0
  197. package/src/ui/components/fact_table.js +0 -0
  198. package/src/ui/components/fill_handle.js +322 -0
  199. package/src/ui/components/gallery_picker.js +19 -8
  200. package/src/ui/components/header_actions.js +55 -0
  201. package/src/ui/components/inline_renamer.js +0 -0
  202. package/src/ui/components/job_progress.js +51 -0
  203. package/src/ui/components/managed_window.js +27 -4
  204. package/src/ui/components/menu_bar.js +745 -0
  205. package/src/ui/components/modal.js +449 -75
  206. package/src/ui/components/notification_history.js +3 -3
  207. package/src/ui/components/progress.js +483 -0
  208. package/src/ui/components/record_list.js +0 -0
  209. package/src/ui/components/row_activation.js +0 -0
  210. package/src/ui/components/section_stack.js +298 -0
  211. package/src/ui/components/series.js +173 -0
  212. package/src/ui/components/settings_view.js +634 -0
  213. package/src/ui/components/slide_out_panel.js +43 -6
  214. package/src/ui/components/slider_field.js +275 -18
  215. package/src/ui/components/sortable_list.js +26 -4
  216. package/src/ui/components/staged_edits.js +343 -0
  217. package/src/ui/components/staged_history.js +172 -0
  218. package/src/ui/components/table_filter_chips.js +0 -0
  219. package/src/ui/components/table_state_store.js +0 -0
  220. package/src/ui/components/table_structure.js +182 -0
  221. package/src/ui/components/table_values.js +0 -0
  222. package/src/ui/components/tabs.js +497 -0
  223. package/src/ui/components/tag_input.js +215 -0
  224. package/src/ui/components/toast.js +25 -8
  225. package/src/ui/components/toggle_field.js +175 -0
  226. package/src/ui/components/tree_view.js +55 -34
  227. package/src/ui/components/window_taskbar.js +0 -0
  228. package/src/ui/components/wizard.js +563 -0
  229. package/src/ui/controllers/window_chrome_controller.js +2 -2
  230. package/src/ui/notification_center.js +375 -119
  231. package/src/ui/utils/auto_scrollbars.js +0 -0
  232. package/src/ui/utils/markdown.js +709 -0
  233. package/src/ui/utils/native_context_menu.js +0 -0
  234. package/src/ui/utils/overlay_scrollbar.js +16 -12
  235. package/src/ui/utils/raf_resize_observer.js +0 -0
  236. package/src/ui/utils/scroll_lock.js +0 -0
  237. package/src/ui/utils/strip_scroll.js +55 -0
  238. package/src/ui/utils/tooltip_service.js +0 -8
  239. package/dist/chunk-6JSOVNID.js.map +0 -7
  240. package/dist/chunk-CWPMLX67.js +0 -475
  241. package/dist/chunk-CWPMLX67.js.map +0 -7
  242. package/dist/chunk-FBGP5KN5.js.map +0 -7
  243. package/dist/chunk-FL5KFNQH.js.map +0 -7
  244. package/dist/chunk-NLTOY57M.js.map +0 -7
  245. package/dist/chunk-NNFTETK3.js +0 -633
  246. package/dist/chunk-NNFTETK3.js.map +0 -7
  247. package/dist/chunk-O5OHMWBB.js +0 -284
  248. package/dist/chunk-O5OHMWBB.js.map +0 -7
  249. package/dist/chunk-RQM5Z2MU.js.map +0 -7
  250. package/dist/chunk-SN4LSOAR.js.map +0 -7
  251. package/src/ui/controllers/panel_state_machine.js +0 -634
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/ui/components/autocomplete_field.js"],
4
+ "sourcesContent": ["/**\n * Autocomplete Field Component\n * Location: ui/components/autocomplete_field.js\n *\n * Purpose: Provide autocomplete dropdown for text input fields,\n * specifically designed for variable reference inputs.\n *\n * Usage:\n * const ac = new AutocompleteField({\n * fieldId: 'my-input',\n * field: { placeholder: '...', value: '...' },\n * provider: ({ value }) => [{ label: 'foo', type: 'variable' }, ...],\n * onChange: (value) => { ... }\n * });\n * container.appendChild(ac.render());\n */\n\nexport class AutocompleteField {\n constructor({\n fieldId,\n field = {},\n provider = null,\n onChange = null,\n logger = null,\n namespace = null,\n namespaceOptions = [],\n showNamespaceSelect = false,\n variant = null,\n showNamespaceChip = false,\n allowScopeToggle = false,\n namespaceLabel = null,\n scopeMode = 'current',\n skipNamespacePrefix = false,\n // Material symbol per completion type, merged over the generic set. The\n // framework's map used to include `sector: 'domain'` \u2014 an EcoAgent\n // completion type \u2014 so the widget knew one application's ontology.\n typeIcons = {},\n } = {}) {\n if (!fieldId) {\n throw new Error('AutocompleteField requires a fieldId');\n }\n this.fieldId = fieldId;\n this.field = field;\n this.provider = typeof provider === 'function' ? provider : () => [];\n this.onChange = typeof onChange === 'function' ? onChange : null;\n this.logger = logger;\n this.typeIcons = typeIcons ?? {};\n this.namespace = namespace;\n this.namespaceOptions = Array.isArray(namespaceOptions) ? [...namespaceOptions] : [];\n // Ensure the active namespace is always present as an option, even if\n // it was not provided (e.g., data manager not yet hydrated).\n if (this.namespace && !this.namespaceOptions.some((opt) => opt.value === this.namespace)) {\n const fallbackLabel = this.field.namespaceLabel || 'This Tab';\n this.namespaceOptions.push({ value: this.namespace, label: fallbackLabel, token: fallbackLabel });\n }\n this.showNamespaceSelect = Boolean(showNamespaceSelect);\n this.variant = variant;\n this.showNamespaceChip = Boolean(showNamespaceChip);\n this.allowScopeToggle = Boolean(allowScopeToggle);\n this.namespaceLabel = namespaceLabel;\n this.scope = scopeMode === 'all' ? 'all' : 'current';\n this.skipNamespacePrefix = Boolean(skipNamespacePrefix);\n this.disabled = Boolean(field.disabled);\n\n const parsed = this.#parseInitialNamespace(field.value ?? '');\n this.selectedNamespace = parsed.initialNamespace;\n this.initialFragment = parsed.initialFragment;\n\n this._lastDropdownRect = null;\n\n this.root = null;\n this.input = null;\n this.dropdown = null;\n this.helperEl = null;\n this.scopeControl = null;\n this.namespaceSelect = null;\n this.ghost = null;\n\n this._items = [];\n this._activeIndex = -1;\n this._isOpen = false;\n this._disposers = [];\n // Every call to the provider is numbered. See `#updateSuggestions`: a\n // provider that answers over the network answers out of order, and the\n // reply to \"No\" must not be allowed to overwrite the reply to \"North\".\n this._suggestSeq = 0;\n }\n\n getValue() {\n return this.#composeValue();\n }\n\n setComposedValue(value) {\n if (!this.input) return;\n const safeValue = typeof value === 'string' ? value : '';\n\n // When namespace prefixing is disabled, store the raw value\n if (this.skipNamespacePrefix) {\n this.input.value = safeValue;\n this.initialFragment = safeValue;\n this.#renderGhost();\n this.#close();\n return;\n }\n\n const parsed = this.#parseInitialNamespace(safeValue);\n this.selectedNamespace = parsed.initialNamespace;\n this.initialFragment = parsed.initialFragment;\n\n if (this.namespaceSelect) {\n this.namespaceSelect.value = this.selectedNamespace;\n }\n this.#updateNamespaceChip();\n this.input.value = parsed.initialFragment;\n this.#renderGhost();\n this.#close();\n }\n\n #parseInitialNamespace(rawValue) {\n const value = typeof rawValue === 'string' ? rawValue.trim() : '';\n const options = this.namespaceOptions;\n \n // Default to provided namespace when available; otherwise fall back to first option or '__ALL__'.\n const defaultNs = this.namespace \n ? (options.find((opt) => opt.value === this.namespace)?.value ?? this.namespace)\n : (options[0]?.value ?? '__ALL__');\n \n if (!options.length) {\n return { initialNamespace: defaultNs, initialFragment: value };\n }\n if (!value) {\n return { initialNamespace: defaultNs, initialFragment: '' };\n }\n \n // Check for namespace prefix (by value OR label)\n const dotIndex = value.indexOf('.');\n if (dotIndex > 0) {\n const nsCandidate = value.slice(0, dotIndex);\n const match = options.find((opt) => \n (opt.value || '').toLowerCase() === nsCandidate.toLowerCase() ||\n (opt.label || '').toLowerCase() === nsCandidate.toLowerCase()\n );\n if (match) {\n return { initialNamespace: match.value, initialFragment: value.slice(dotIndex + 1) };\n }\n }\n return { initialNamespace: defaultNs, initialFragment: value };\n }\n\n #resolveNamespaceLabel() {\n if (this.scope === 'all') {\n return 'All Namespaces';\n }\n if (typeof this.namespaceLabel === 'string' && this.namespaceLabel.trim()) {\n return this.namespaceLabel.trim();\n }\n if (typeof this.field.namespaceLabel === 'string' && this.field.namespaceLabel.trim()) {\n return this.field.namespaceLabel.trim();\n }\n if (typeof this.namespace === 'string' && this.namespace.trim()) {\n return this.namespace.trim();\n }\n return 'This Tab';\n }\n\n #toggleScope() {\n if (this.disabled) return;\n this.scope = this.scope === 'all' ? 'current' : 'all';\n this.root?.classList?.toggle('twm-autocomplete-field--scope-all', this.scope === 'all');\n this.#updateNamespaceChip();\n this.#updateSuggestions();\n }\n\n #updateNamespaceChip() {\n if (!this.scopeControl) return;\n this.scopeControl.textContent = this.#resolveNamespaceLabel();\n this.scopeControl.dataset.scope = this.scope;\n this.scopeControl.title = this.scope === 'all'\n ? 'Searching across all namespaces (click to limit to this tab)'\n : 'Searching this tab (click to search all namespaces)';\n }\n\n render() {\n if (this.root) {\n return this.root;\n }\n\n this.root = document.createElement('div');\n this.root.className = 'twm-autocomplete-field';\n if (this.variant) {\n this.root.classList.add(`twm-autocomplete-field--${this.variant}`);\n }\n this.root.classList.toggle('twm-autocomplete-field--scope-all', this.scope === 'all');\n\n const inputWrapper = document.createElement('div');\n inputWrapper.className = 'twm-autocomplete-field__input-wrapper';\n\n if (this.showNamespaceSelect && this.namespaceOptions.length) {\n const select = document.createElement('select');\n select.className = 'twm-autocomplete-field__namespace-select';\n this.namespaceOptions.forEach((opt) => {\n const option = document.createElement('option');\n option.value = opt.value;\n option.textContent = opt.label ?? opt.value;\n if (opt.value === this.selectedNamespace) {\n option.selected = true;\n }\n select.appendChild(option);\n });\n this.namespaceSelect = select;\n inputWrapper.appendChild(select);\n }\n\n if (this.showNamespaceChip) {\n const nsChip = document.createElement(this.allowScopeToggle ? 'button' : 'span');\n nsChip.className = 'twm-autocomplete-field__namespace';\n if (this.allowScopeToggle) {\n nsChip.setAttribute('type', 'button');\n }\n if (this.allowScopeToggle) {\n nsChip.classList.add('twm-autocomplete-field__namespace--toggle');\n nsChip.addEventListener('click', () => this.#toggleScope());\n }\n this.scopeControl = nsChip;\n this.#updateNamespaceChip();\n inputWrapper.appendChild(nsChip);\n }\n\n this.input = document.createElement('input');\n this.input.type = 'text';\n this.input.className = 'twm-autocomplete-field__input';\n this.input.id = this.fieldId;\n this.input.autocomplete = 'off';\n this.input.spellcheck = false;\n if (this.field.placeholder) {\n this.input.placeholder = this.field.placeholder;\n }\n if (this.field.value != null) {\n this.input.value = this.initialFragment;\n }\n if (this.disabled) {\n this.input.disabled = true;\n this.root.classList.add('twm-autocomplete-field--disabled');\n }\n inputWrapper.appendChild(this.input);\n\n // Ghost overlay disabled - namespace select provides visual context\n this.ghost = null;\n\n this.dropdown = document.createElement('div');\n this.dropdown.className = 'twm-autocomplete-field__dropdown';\n this.dropdown.setAttribute('role', 'listbox');\n // Append dropdown to body to escape stacking context limitations\n document.body.appendChild(this.dropdown);\n\n this.helperEl = document.createElement('div');\n this.helperEl.className = 'twm-autocomplete-field__helper twm-config-hint';\n if (this.field.helperText) {\n this.helperEl.textContent = this.field.helperText;\n }\n\n this.root.appendChild(inputWrapper);\n this.root.appendChild(this.helperEl);\n\n this.#wireEvents();\n this.#renderGhost();\n return this.root;\n }\n\n #wireEvents() {\n const onInput = () => {\n if (this.disabled) return;\n this.#syncNamespaceFromInput();\n this.#renderGhost();\n this.#updateSuggestions();\n };\n\n const onChange = () => {\n this.onChange?.(this.#composeValue(), { immediate: false, namespace: this.selectedNamespace });\n };\n\n const onPaste = () => {\n // No special paste handling needed\n };\n\n const onKeyDown = (e) => {\n if (this.disabled) return;\n this.#handleKeyDown(e);\n };\n\n const onFocus = () => {\n if (this.disabled) return;\n this.#updateSuggestions();\n };\n\n const onBlur = (e) => {\n // Delay close to allow click on dropdown items\n setTimeout(() => {\n if (!this.root?.contains(document.activeElement)) {\n this.#close();\n // Trigger save on blur (similar to change event)\n this.onChange?.(this.#composeValue(), { immediate: false, namespace: this.selectedNamespace });\n }\n }, 150);\n };\n\n const onDropdownMouseDown = (e) => {\n // Prevent blur when clicking dropdown\n e.preventDefault();\n };\n\n const onDropdownClick = (e) => {\n const item = e.target.closest('.twm-autocomplete-field__item');\n if (item) {\n const index = parseInt(item.dataset.index, 10);\n if (!isNaN(index)) {\n this.#selectItem(index);\n }\n }\n };\n\n this.input.addEventListener('input', onInput);\n this.input.addEventListener('change', onChange);\n this.input.addEventListener('paste', onPaste);\n this.input.addEventListener('keydown', onKeyDown);\n this.input.addEventListener('focus', onFocus);\n this.input.addEventListener('blur', onBlur);\n this.dropdown.addEventListener('mousedown', onDropdownMouseDown);\n this.dropdown.addEventListener('click', onDropdownClick);\n\n if (this.namespaceSelect) {\n const onSelectChange = () => {\n // Store the new namespace selection\n this.selectedNamespace = this.namespaceSelect.value;\n // Refresh suggestions and notify listener so selection can be persisted\n this.#updateSuggestions();\n this.onChange?.(this.#composeValue(), { \n immediate: false, \n namespace: this.selectedNamespace,\n viewNamespace: this.selectedNamespace\n });\n };\n this.namespaceSelect.addEventListener('change', onSelectChange);\n this._disposers.push(() => this.namespaceSelect.removeEventListener('change', onSelectChange));\n }\n\n const onWindowResize = () => {\n if (this._isOpen) {\n this.#positionDropdown();\n }\n };\n window.addEventListener('resize', onWindowResize);\n\n // Close dropdown when user scrolls (dropdown is position: fixed so doesn't move with content)\n const onScroll = (e) => {\n if (!this._isOpen) return;\n // Don't close if scrolling inside the dropdown itself\n if (this.dropdown?.contains(e.target)) return;\n this.#close();\n };\n document.addEventListener('scroll', onScroll, true); // capture phase catches all scroll events\n this._disposers.push(() => {\n document.removeEventListener('scroll', onScroll, true);\n });\n\n // Close dropdown when clicking outside (anywhere not in root or dropdown)\n const onDocumentClick = (e) => {\n if (!this._isOpen) return;\n const clickedInRoot = this.root?.contains(e.target);\n const clickedInDropdown = this.dropdown?.contains(e.target);\n if (!clickedInRoot && !clickedInDropdown) {\n this.#close();\n }\n };\n document.addEventListener('click', onDocumentClick, true);\n\n this._disposers.push(() => {\n window.removeEventListener('resize', onWindowResize);\n });\n this._disposers.push(() => {\n document.removeEventListener('click', onDocumentClick, true);\n });\n\n this._disposers.push(() => {\n this.input.removeEventListener('input', onInput);\n this.input.removeEventListener('change', onChange);\n this.input.removeEventListener('paste', onPaste);\n this.input.removeEventListener('keydown', onKeyDown);\n this.input.removeEventListener('focus', onFocus);\n this.input.removeEventListener('blur', onBlur);\n this.dropdown.removeEventListener('mousedown', onDropdownMouseDown);\n this.dropdown.removeEventListener('click', onDropdownClick);\n });\n }\n\n #handleKeyDown(e) {\n if (!this._isOpen) {\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n this.#updateSuggestions();\n e.preventDefault();\n }\n return;\n }\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n this.#moveSelection(1);\n break;\n case 'ArrowUp':\n e.preventDefault();\n this.#moveSelection(-1);\n break;\n case 'Enter':\n e.preventDefault();\n if (this._activeIndex >= 0) {\n this.#selectItem(this._activeIndex);\n }\n // Always blur on Enter to trigger save\n this.input?.blur();\n break;\n case 'Tab':\n if (this._activeIndex >= 0) {\n e.preventDefault();\n this.#selectItem(this._activeIndex);\n }\n break;\n case 'Escape':\n e.preventDefault();\n this.#close();\n break;\n }\n }\n\n #updateSuggestions() {\n // Pass the fragment (variable part) for filtering, not the full composed value\n const fragment = this.#getInputFragment();\n\n // A PROVIDER MAY ANSWER LATER THAN IT WAS ASKED.\n //\n // This used to require the answer synchronously \u2014 `provider(...) || []`\n // straight into `Array.isArray`, so a provider that returned a promise\n // produced an empty list and a dropdown that closed on every keystroke.\n // That ruled out the entire class of completion source that lives on a\n // server, which is most of them outside a single-page simulation: a\n // table's rows, a query's result set, an index's matches.\n //\n // A provider that answers synchronously still takes the synchronous\n // path, unchanged and untouched, so nothing that works today changes.\n // A provider that hands back a thenable is awaited, and the reply is\n // used only if it is the reply to the most recent question \u2014 typing\n // \"North\" fires five requests and the network is free to answer them in\n // any order, so without the sequence number the list can settle on the\n // matches for \"Nor\".\n const request = ++this._suggestSeq;\n let produced;\n try {\n produced = this.provider({\n value: fragment,\n scope: this.scope,\n namespace: this.selectedNamespace\n });\n } catch (err) {\n this.logger?.warn?.('autocomplete', 'Provider error', { err });\n this._items = [];\n this.#close();\n return;\n }\n\n if (produced && typeof produced.then === 'function') {\n produced.then(\n (items) => {\n if (request !== this._suggestSeq) return;\n this.#applySuggestions(items);\n },\n (err) => {\n this.logger?.warn?.('autocomplete', 'Provider error', { err });\n if (request !== this._suggestSeq) return;\n this._items = [];\n this.#close();\n }\n );\n return;\n }\n\n this.#applySuggestions(produced);\n }\n\n /** Draw whatever the provider produced. Split out of `#updateSuggestions`\n * so the synchronous and the awaited paths cannot drift apart. */\n #applySuggestions(produced) {\n const items = Array.isArray(produced) ? produced : [];\n this._items = items;\n this._activeIndex = items.length > 0 ? 0 : -1;\n this.#renderDropdown();\n if (items.length > 0) {\n this.#open();\n } else {\n this.#close();\n }\n }\n\n #renderDropdown() {\n this.dropdown.innerHTML = '';\n const showingAll = this.selectedNamespace === '__ALL__';\n \n this._items.forEach((item, index) => {\n const el = document.createElement('div');\n el.className = 'twm-autocomplete-field__item';\n el.setAttribute('role', 'option');\n el.dataset.index = index;\n el.dataset.type = item.type || item.iconType || 'variable';\n if (index === this._activeIndex) {\n el.classList.add('active');\n }\n\n // Icon based on type\n const icon = document.createElement('span');\n icon.className = 'twm-autocomplete-field__icon material-symbols-outlined';\n icon.textContent = this.#getIconForType(item.type || item.iconType);\n el.appendChild(icon);\n\n // Label\n const label = document.createElement('span');\n label.className = 'twm-autocomplete-field__label';\n label.textContent = item.label || item.insertText || '';\n el.appendChild(label);\n\n // Show namespace indicator when viewing all namespaces\n if (showingAll && item.metadata?.namespaceId) {\n const nsLabel = this.#resolveNamespaceToken(item.metadata.namespaceId);\n if (nsLabel) {\n const nsIndicator = document.createElement('span');\n nsIndicator.className = 'twm-autocomplete-field__namespace-indicator';\n nsIndicator.textContent = nsLabel;\n el.appendChild(nsIndicator);\n }\n }\n\n // Optional badge (type)\n if (item.type && !showingAll) {\n const badge = document.createElement('span');\n badge.className = 'twm-autocomplete-field__badge';\n badge.textContent = item.type;\n el.appendChild(badge);\n }\n\n this.dropdown.appendChild(el);\n });\n if (this._isOpen) {\n this.#positionDropdown();\n }\n }\n\n #resolveNamespaceToken(namespaceId) {\n if (!namespaceId) return null;\n const opt = this.namespaceOptions.find((o) => o.value === namespaceId);\n return opt?.token || opt?.label || null;\n }\n\n #getIconForType(type) {\n const icons = {\n variable: 'functions',\n 'variable-qualified': 'link',\n stock: 'account_balance',\n account: 'savings',\n function: 'code',\n constant: 'numbers',\n operator: 'calculate',\n snippet: 'content_paste',\n ...this.typeIcons,\n };\n return icons[type] || 'label';\n }\n\n #moveSelection(delta) {\n if (this._items.length === 0) return;\n let newIndex = this._activeIndex + delta;\n if (newIndex < 0) newIndex = this._items.length - 1;\n if (newIndex >= this._items.length) newIndex = 0;\n this._activeIndex = newIndex;\n this.#renderDropdown();\n this.#scrollToActive();\n }\n\n #scrollToActive() {\n const activeEl = this.dropdown.querySelector('.twm-autocomplete-field__item.active');\n if (activeEl) {\n activeEl.scrollIntoView({ block: 'nearest', behavior: 'smooth' });\n }\n }\n\n #selectItem(index) {\n const item = this._items[index];\n if (!item) return;\n \n // Extract namespace from the selected item's metadata\n const itemNamespace = item.metadata?.namespaceId || null;\n \n // Put just the variable name in the input (not qualified)\n const insertText = item.insertText || item.label || '';\n this.input.value = insertText;\n \n // When \"All\" is selected, do NOT change the dropdown - keep it at \"All\"\n // Instead, pass the item's namespace via the callback so it's saved correctly\n // This allows users to stay in \"All\" view while browsing/selecting variables\n const viewNamespace = this.selectedNamespace; // What the dropdown shows (\"__ALL__\" or specific)\n const resolvedNamespace = (viewNamespace === '__ALL__' && itemNamespace) \n ? itemNamespace \n : viewNamespace;\n \n this.#close();\n this.input.focus();\n // Emit composed value with both namespace values and item metadata\n this.onChange?.(this.#composeValue(), {\n immediate: true,\n namespace: resolvedNamespace,\n viewNamespace: viewNamespace,\n metadata: item.metadata || null,\n });\n }\n\n #open() {\n if (this._isOpen) {\n return;\n }\n this._isOpen = true;\n this.#positionDropdown();\n this.dropdown.classList.add('visible');\n }\n\n #close() {\n if (!this._isOpen) return;\n this._isOpen = false;\n this.dropdown.classList.remove('visible');\n this._activeIndex = -1;\n }\n\n #syncNamespaceFromInput() {\n // Auto-switch namespace dropdown when user types \"Namespace.\" prefix\n // But do NOT modify the input value - keep what user typed\n // Also do NOT switch away from \"__ALL__\" unless user explicitly types a namespace prefix\n if (!this.namespaceOptions.length) return;\n const value = this.input?.value || '';\n const dotIndex = value.indexOf('.');\n if (dotIndex > 0) {\n const nsCandidate = value.slice(0, dotIndex);\n // Match by value OR display label\n const match = this.namespaceOptions.find((opt) => \n opt.value !== '__ALL__' && (\n (opt.value || '').toLowerCase() === nsCandidate.toLowerCase() ||\n (opt.label || '').toLowerCase() === nsCandidate.toLowerCase() ||\n (opt.token || '').toLowerCase() === nsCandidate.toLowerCase()\n )\n );\n if (match && this.namespaceSelect && this.namespaceSelect.value !== match.value) {\n this.namespaceSelect.value = match.value;\n this.selectedNamespace = match.value;\n }\n }\n // Note: We no longer auto-reset to a namespace when typing without a dot\n // This allows \"All\" selection to remain stable\n }\n\n #getInputFragment() {\n // Get the variable name fragment from input (strip namespace prefix if present)\n const value = this.input?.value || '';\n const dotIndex = value.indexOf('.');\n if (dotIndex > 0) {\n const nsCandidate = value.slice(0, dotIndex);\n const match = this.namespaceOptions.find((opt) => \n opt.value !== '__ALL__' && (\n (opt.value || '').toLowerCase() === nsCandidate.toLowerCase() ||\n (opt.label || '').toLowerCase() === nsCandidate.toLowerCase()\n )\n );\n if (match) {\n return value.slice(dotIndex + 1);\n }\n }\n return value;\n }\n\n #composeValue() {\n // Compose the full reference value for saving\n // Use the raw input value - it may already contain namespace prefix\n const rawInput = this.input?.value || '';\n if (!rawInput) return '';\n \n // Skip namespace prefixing for simple value fields (e.g., sector, account name)\n if (this.skipNamespacePrefix) {\n return rawInput;\n }\n \n // If input already has a namespace prefix, return as-is\n const dotIndex = rawInput.indexOf('.');\n if (dotIndex > 0) {\n const nsCandidate = rawInput.slice(0, dotIndex);\n const match = this.namespaceOptions.find((opt) => \n opt.value !== '__ALL__' && (\n (opt.value || '').toLowerCase() === nsCandidate.toLowerCase() ||\n (opt.label || '').toLowerCase() === nsCandidate.toLowerCase()\n )\n );\n if (match) {\n // Input already has valid namespace prefix, return as-is\n return rawInput;\n }\n }\n \n // No namespace prefix in input - prepend from dropdown if not \"All\"\n const ns = this.selectedNamespace;\n if (!ns || ns === '__ALL__') {\n return rawInput;\n }\n \n // Find display label for the namespace (case-insensitive search)\n const nsOption = this.namespaceOptions.find((opt) => \n opt.value === ns || (opt.value || '').toLowerCase() === (ns || '').toLowerCase()\n );\n\n // Choose a human-friendly token; fall back to label. If we only have a UUID-looking\n // token, avoid prefixing to prevent UUIDs leaking into the input.\n const nsToken = nsOption?.token || nsOption?.label || '';\n const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\n if (ns === '__ALL__' || (nsToken || '').toUpperCase() === '__ALL__') {\n return rawInput;\n }\n if (!nsToken || uuidPattern.test(nsToken)) {\n return rawInput;\n }\n\n return `${nsToken}.${rawInput}`;\n }\n\n #renderGhost() {\n // Ghost overlay is disabled - it interferes with the input\n // The namespace select already provides visual context\n if (this.ghost) {\n this.ghost.style.display = 'none';\n }\n }\n\n #positionDropdown() {\n if (!this.dropdown || !this.root) return;\n const wrapper = this.root.querySelector('.twm-autocomplete-field__input-wrapper');\n if (!wrapper) return;\n const rect = wrapper.getBoundingClientRect();\n this._lastDropdownRect = rect;\n const viewportWidth = document.documentElement.clientWidth || window.innerWidth;\n const viewportHeight = document.documentElement.clientHeight || window.innerHeight;\n const width = Math.min(rect.width, viewportWidth - rect.left - 8);\n const maxHeight = Math.max(120, viewportHeight - rect.bottom - 12);\n Object.assign(this.dropdown.style, {\n position: 'fixed',\n top: `${rect.bottom}px`,\n left: `${rect.left}px`,\n width: `${width}px`,\n maxWidth: `${width}px`,\n maxHeight: `${maxHeight}px`,\n });\n }\n\n dispose() {\n // Retire the outstanding question first. An awaited provider can answer\n // after the field is gone, and `#applySuggestions` would then paint into\n // a dropdown that has been removed and nulled.\n this._suggestSeq += 1;\n // Close dropdown before cleanup\n this.#close();\n this._disposers.forEach((fn) => {\n try { fn(); } catch (e) { /* ignore */ }\n });\n this._disposers = [];\n // Remove dropdown from body since we appended it there\n if (this.dropdown && this.dropdown.parentNode) {\n this.dropdown.parentNode.removeChild(this.dropdown);\n }\n this.root = null;\n this.input = null;\n this.dropdown = null;\n this.helperEl = null;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,9 +1,20 @@
1
+ import {
2
+ revealInStrip,
3
+ wheelStripSideways
4
+ } from "./chunk-N7HC3ADV.js";
1
5
  import {
2
6
  DragReorder
3
7
  } from "./chunk-WVFGV5FT.js";
4
8
 
5
9
  // src/editor/notebook_tab_bar.js
6
- var TAB_MIME = "application/x-ecosim-tab";
10
+ var DEFAULT_TAB_DRAG_MIME = "application/x-flexdesk-tab";
11
+ var _tabMime = DEFAULT_TAB_DRAG_MIME;
12
+ function setTabDragMime(mime = DEFAULT_TAB_DRAG_MIME) {
13
+ _tabMime = typeof mime === "string" && mime ? mime : DEFAULT_TAB_DRAG_MIME;
14
+ }
15
+ function getTabDragMime() {
16
+ return _tabMime;
17
+ }
7
18
  var NotebookTabBar = class _NotebookTabBar {
8
19
  /** @type {HTMLElement} */
9
20
  #container = null;
@@ -42,7 +53,7 @@ var NotebookTabBar = class _NotebookTabBar {
42
53
  },
43
54
  onDragStart: (e, key, item) => {
44
55
  try {
45
- e.dataTransfer.setData(TAB_MIME, key);
56
+ e.dataTransfer.setData(_tabMime, key);
46
57
  } catch (_) {
47
58
  }
48
59
  try {
@@ -174,55 +185,21 @@ var NotebookTabBar = class _NotebookTabBar {
174
185
  #revealedKey = null;
175
186
  /** @type {number} a pending retry, for a strip not yet laid out */
176
187
  #revealFrame = 0;
177
- /** Bring the active tab fully into the strip — and ONLY the strip. Not
178
- * `scrollIntoView`, which scrolls every scrollable ancestor as well and
179
- * would drag the tile, the window or the page along with the tab. */
188
+ /** Bring the active tab fully into the strip (`revealInStrip`). */
180
189
  #revealActive(retry = false) {
181
190
  const el = this.#container;
182
191
  if (!el) return;
183
192
  const active = el.querySelector(":scope > .tab.active");
184
193
  if (!active) return;
185
- if (!el.isConnected || el.clientWidth === 0) {
186
- if (retry && !this.#revealFrame && typeof requestAnimationFrame === "function") {
187
- this.#revealFrame = requestAnimationFrame(() => {
188
- this.#revealFrame = 0;
189
- this.#revealActive(false);
190
- });
191
- }
192
- return;
194
+ if (!revealInStrip(el, active) && retry && !this.#revealFrame && typeof requestAnimationFrame === "function") {
195
+ this.#revealFrame = requestAnimationFrame(() => {
196
+ this.#revealFrame = 0;
197
+ this.#revealActive(false);
198
+ });
193
199
  }
194
- const box = el.getBoundingClientRect();
195
- const tab = active.getBoundingClientRect();
196
- const scale = (el.offsetWidth ? box.width / el.offsetWidth : 1) || 1;
197
- const left = (tab.left - box.left) / scale + el.scrollLeft;
198
- const right = left + tab.width / scale;
199
- if (left < el.scrollLeft) el.scrollLeft = left;
200
- else if (right > el.scrollLeft + el.clientWidth) el.scrollLeft = right - el.clientWidth;
201
200
  }
202
- /**
203
- * A VERTICAL WHEEL SCROLLS THE STRIP SIDEWAYS. Chromium and Firefox scroll
204
- * an element that overflows only horizontally with Shift+wheel or a
205
- * touchpad, and not with the plain wheel most people have — so with the
206
- * scrollbar hidden, every tab past the edge was unreachable with a mouse.
207
- *
208
- * The wheel is taken from the page only while the strip can actually move
209
- * that way: at either end it is left alone, so a wheel over a strip that
210
- * has nothing more to show still scrolls whatever is behind it. A gesture
211
- * that is already horizontal (a touchpad, Shift+wheel) and Ctrl+wheel (zoom)
212
- * are the browser's, untouched.
213
- */
214
- #onWheel = (e) => {
215
- const el = this.#container;
216
- if (!el || e.ctrlKey || e.shiftKey) return;
217
- if (Math.abs(e.deltaX) >= Math.abs(e.deltaY)) return;
218
- const room = el.scrollWidth - el.clientWidth;
219
- if (room <= 0) return;
220
- const unit = e.deltaMode === 1 ? 16 : e.deltaMode === 2 ? el.clientWidth : 1;
221
- const next = Math.max(0, Math.min(room, el.scrollLeft + e.deltaY * unit));
222
- if (Math.abs(next - el.scrollLeft) < 0.5) return;
223
- e.preventDefault();
224
- el.scrollLeft = next;
225
- };
201
+ /** A vertical wheel scrolls the strip sideways (`wheelStripSideways`). */
202
+ #onWheel = (e) => wheelStripSideways(this.#container, e);
226
203
  // ═════════════════════════════════════════════════════════════════════════
227
204
  // Drag and drop reordering (same-pane + cross-pane)
228
205
  // ═════════════════════════════════════════════════════════════════════════
@@ -242,7 +219,7 @@ var NotebookTabBar = class _NotebookTabBar {
242
219
  *
243
220
  * C33. A HOST MAY NAME A SECOND MIME, at mount, as
244
221
  * `callbacks.externalTabMimes` — the tile renderer's tabs are not editor
245
- * tabs and do not carry `application/x-ecosim-tab`, so without this the
222
+ * tabs and do not carry the editor tab MIME (getTabDragMime()), so without this the
246
223
  * strip in tile B would refuse a tab dragged out of tile A's strip. Empty
247
224
  * by default, so every existing consumer keeps exactly today's admission
248
225
  * test.
@@ -259,7 +236,7 @@ var NotebookTabBar = class _NotebookTabBar {
259
236
  const extra = Array.isArray(this.#callbacks.externalTabMimes) ? this.#callbacks.externalTabMimes : [];
260
237
  try {
261
238
  const types = e.dataTransfer.types;
262
- return types.includes(TAB_MIME) || extra.some((m) => types.includes(m));
239
+ return types.includes(_tabMime) || extra.some((m) => types.includes(m));
263
240
  } catch {
264
241
  return false;
265
242
  }
@@ -282,7 +259,7 @@ var NotebookTabBar = class _NotebookTabBar {
282
259
  if (this.#isExternalTabDrag(e)) {
283
260
  e.preventDefault();
284
261
  this.#container.classList.remove("notebook-tabs--drop-target");
285
- const filePath = e.dataTransfer.getData(TAB_MIME) || e.dataTransfer.getData("text/plain");
262
+ const filePath = e.dataTransfer.getData(_tabMime) || e.dataTransfer.getData("text/plain");
286
263
  if (filePath) {
287
264
  this.#callbacks.onDropFromOtherPane?.(filePath);
288
265
  }
@@ -474,6 +451,9 @@ var NotebookTabBar = class _NotebookTabBar {
474
451
  };
475
452
 
476
453
  export {
454
+ DEFAULT_TAB_DRAG_MIME,
455
+ setTabDragMime,
456
+ getTabDragMime,
477
457
  NotebookTabBar
478
458
  };
479
- //# sourceMappingURL=chunk-NLTOY57M.js.map
459
+ //# sourceMappingURL=chunk-UURZ37SD.js.map
@@ -0,0 +1,7 @@
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';\nimport { revealInStrip, wheelStripSideways } from '../ui/utils/strip_scroll.js';\n\n/** The MIME type a dragged editor tab carries when the embedder names none. */\nexport const DEFAULT_TAB_DRAG_MIME = 'application/x-flexdesk-tab';\n\n/** Custom MIME type so tab bars and editor panes recognise cross-pane drags. */\nlet _tabMime = DEFAULT_TAB_DRAG_MIME;\n\n/**\n * Name the MIME type editor tabs carry while dragged. Every NotebookTabBar and\n * EditorPane in the document reads it at drag time, so they always agree.\n * Call at boot, before the first drag.\n *\n * @param {string} [mime=DEFAULT_TAB_DRAG_MIME]\n */\nexport function setTabDragMime(mime = DEFAULT_TAB_DRAG_MIME) {\n _tabMime = (typeof mime === 'string' && mime) ? mime : DEFAULT_TAB_DRAG_MIME;\n}\n\n/** @returns {string} The MIME type editor tabs carry while dragged. */\nexport function getTabDragMime() {\n return _tabMime;\n}\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(_tabMime, 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: the 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 (`revealInStrip`). */\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 // Mounted but not laid out yet (the renderer updates a strip before it\n // attaches it). Once, on the next frame \u2014 not a loop.\n if (!revealInStrip(el, active) && retry && !this.#revealFrame\n && typeof requestAnimationFrame === 'function') {\n this.#revealFrame = requestAnimationFrame(() => {\n this.#revealFrame = 0;\n this.#revealActive(false);\n });\n }\n }\n\n /** A vertical wheel scrolls the strip sideways (`wheelStripSideways`). */\n #onWheel = (e) => wheelStripSideways(this.#container, e);\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 the editor tab MIME (getTabDragMime()), 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(_tabMime) || 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(_tabMime) || 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
+ }
@@ -0,0 +1,111 @@
1
+ import {
2
+ modalHost
3
+ } from "./chunk-D3COLZZ2.js";
4
+
5
+ // src/ui/components/context_menu.js
6
+ var _activeMenu = null;
7
+ var _returnFocusTo = null;
8
+ function showContextMenu(x, y, items, onAction) {
9
+ hideContextMenu();
10
+ _returnFocusTo = document.activeElement;
11
+ const menu = document.createElement("div");
12
+ menu.className = "twm-context-menu ea-context-menu";
13
+ menu.setAttribute("role", "menu");
14
+ for (const it of items) {
15
+ if (it.separator) {
16
+ const sep = document.createElement("div");
17
+ sep.className = "twm-context-menu__separator";
18
+ sep.setAttribute("role", "separator");
19
+ menu.appendChild(sep);
20
+ continue;
21
+ }
22
+ const row = document.createElement("button");
23
+ row.type = "button";
24
+ row.setAttribute("role", "menuitem");
25
+ let cls = "twm-context-menu-item";
26
+ if (it.danger) cls += " twm-delete-node";
27
+ if (it.disabled) cls += " disabled";
28
+ row.className = cls;
29
+ if (it.disabled) {
30
+ row.disabled = true;
31
+ row.setAttribute("aria-disabled", "true");
32
+ }
33
+ if (it.title) row.title = it.title;
34
+ row.innerHTML = `
35
+ <span class="material-symbols-outlined">${it.icon || ""}</span>
36
+ <span>${escapeHtml(it.label)}</span>
37
+ `;
38
+ if (!it.disabled) {
39
+ row.addEventListener("click", (e) => {
40
+ e.stopPropagation();
41
+ hideContextMenu();
42
+ onAction?.(it.action);
43
+ });
44
+ }
45
+ menu.appendChild(row);
46
+ }
47
+ (modalHost() || document.body).appendChild(menu);
48
+ menu.style.display = "block";
49
+ _activeMenu = menu;
50
+ const rect = menu.getBoundingClientRect();
51
+ const left = Math.min(x, window.innerWidth - rect.width - 8);
52
+ const top = Math.min(y, window.innerHeight - rect.height - 8);
53
+ menu.style.left = `${Math.max(0, left)}px`;
54
+ menu.style.top = `${Math.max(0, top)}px`;
55
+ setTimeout(() => {
56
+ document.addEventListener("mousedown", _outsideHandler, { once: true, capture: true });
57
+ }, 0);
58
+ document.addEventListener("keydown", _keyHandler);
59
+ window.addEventListener("scroll", hideContextMenu, { once: true, capture: true });
60
+ _enabledItems(menu)[0]?.focus({ preventScroll: true });
61
+ }
62
+ function hideContextMenu() {
63
+ if (!_activeMenu) return;
64
+ const returnTo = _returnFocusTo;
65
+ const held = _activeMenu.contains(document.activeElement);
66
+ _activeMenu.remove();
67
+ _activeMenu = null;
68
+ _returnFocusTo = null;
69
+ document.removeEventListener("keydown", _keyHandler);
70
+ if (held && returnTo?.isConnected) returnTo.focus?.({ preventScroll: true });
71
+ }
72
+ function _enabledItems(menu) {
73
+ return [...menu.querySelectorAll(".twm-context-menu-item:not(.disabled)")];
74
+ }
75
+ function _keyHandler(e) {
76
+ if (!_activeMenu) return;
77
+ if (e.key === "Escape") {
78
+ e.preventDefault();
79
+ hideContextMenu();
80
+ return;
81
+ }
82
+ const items = _enabledItems(_activeMenu);
83
+ if (items.length === 0) return;
84
+ const at = items.indexOf(document.activeElement);
85
+ let next = null;
86
+ if (e.key === "ArrowDown") next = items[(at + 1 + items.length) % items.length];
87
+ else if (e.key === "ArrowUp") next = items[(at - 1 + items.length) % items.length];
88
+ else if (e.key === "Home") next = items[0];
89
+ else if (e.key === "End") next = items[items.length - 1];
90
+ if (!next) return;
91
+ e.preventDefault();
92
+ next.focus({ preventScroll: true });
93
+ }
94
+ function _outsideHandler(e) {
95
+ if (_activeMenu && !_activeMenu.contains(e.target)) hideContextMenu();
96
+ }
97
+ function escapeHtml(s) {
98
+ return String(s).replace(/[&<>"']/g, (c) => ({
99
+ "&": "&amp;",
100
+ "<": "&lt;",
101
+ ">": "&gt;",
102
+ '"': "&quot;",
103
+ "'": "&#39;"
104
+ })[c]);
105
+ }
106
+
107
+ export {
108
+ showContextMenu,
109
+ hideContextMenu
110
+ };
111
+ //# sourceMappingURL=chunk-UWO43BZU.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/ui/components/context_menu.js"],
4
+ "sourcesContent": ["/**\n * context_menu.js \u2014 small popup menu in the `.context-menu` idiom the\n * DataTable's own right-click menu uses (./data_table.js).\n *\n * Usage:\n * showContextMenu(x, y, [\n * { label: 'Open', icon: 'open_in_new', action: 'open' },\n * { separator: true },\n * { label: 'Delete', icon: 'delete', action: 'delete', danger: true },\n * ], (action) => { ... });\n *\n * The menu auto-closes on outside click / scroll / Escape.\n *\n * \u2500\u2500 It is operable by keyboard \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Items were bare `<div>`s with a click listener: no role, no tab stop, no\n * arrow-key movement, and `showContextMenu` never moved focus into the menu.\n * A consumer that opened this from Shift+F10 \u2014 the rail in Tables does \u2014 put a\n * menu on screen that the keyboard could only dismiss. Every command in it was\n * unreachable without a pointer, and nothing said so.\n *\n * So an item is a `<button role=\"menuitem\">`, the first enabled one takes focus\n * when the menu opens, Up/Down/Home/End move between them and wrap, Enter and\n * Space activate, Escape closes, and focus returns to whatever had it before.\n * Disabled items are skipped by the arrows rather than focusable-but-inert.\n * `<button>` rather than a div with `tabindex`: the browser then gives Enter and\n * Space for free and screen readers announce it without further help.\n */\n\nimport { modalHost } from './modal.js';\n\nlet _activeMenu = null;\nlet _returnFocusTo = null;\n\nexport function showContextMenu(x, y, items, onAction) {\n hideContextMenu();\n\n // Whatever had focus when the menu opened gets it back when the menu\n // closes. Without this a keyboard user who presses Escape is returned to\n // `document.body` and has to tab back to where they were.\n _returnFocusTo = document.activeElement;\n\n const menu = document.createElement('div');\n menu.className = 'twm-context-menu ea-context-menu';\n menu.setAttribute('role', 'menu');\n\n for (const it of items) {\n if (it.separator) {\n const sep = document.createElement('div');\n sep.className = 'twm-context-menu__separator';\n sep.setAttribute('role', 'separator');\n menu.appendChild(sep);\n continue;\n }\n const row = document.createElement('button');\n row.type = 'button';\n row.setAttribute('role', 'menuitem');\n let cls = 'twm-context-menu-item';\n if (it.danger) cls += ' twm-delete-node';\n if (it.disabled) cls += ' disabled';\n row.className = cls;\n if (it.disabled) {\n row.disabled = true;\n row.setAttribute('aria-disabled', 'true');\n }\n // A DISABLED ROW WITH NO EXPLANATION IS A DEAD CONTROL. `title` was\n // accepted by callers and rendered by nothing \u2014 the item was built with\n // one, the row silently dropped it, and the user got a greyed line with\n // no way to learn why. It is the same shape as the classes this\n // repository keeps finding: no error, no throw, and invisible to every\n // test that checks the row is disabled.\n if (it.title) row.title = it.title;\n row.innerHTML = `\n <span class=\"material-symbols-outlined\">${it.icon || ''}</span>\n <span>${escapeHtml(it.label)}</span>\n `;\n if (!it.disabled) {\n row.addEventListener('click', (e) => {\n e.stopPropagation();\n hideContextMenu();\n onAction?.(it.action);\n });\n }\n menu.appendChild(row);\n }\n\n // C25. THE SAME QUESTION A MODAL ASKS: which window is the user in? A\n // consumer spanning two browser windows sets the host when its focus moves;\n // null \u2014 every consumer today \u2014 is `document.body`, exactly as before. A\n // menu in the wrong window is worse than a modal in the wrong window,\n // because it is positioned at coordinates from the OTHER one.\n (modalHost() || document.body).appendChild(menu);\n menu.style.display = 'block';\n _activeMenu = 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 // Close on outside click / scroll / Escape.\n setTimeout(() => {\n document.addEventListener('mousedown', _outsideHandler, { once: true, capture: true });\n }, 0);\n document.addEventListener('keydown', _keyHandler);\n window.addEventListener('scroll', hideContextMenu, { once: true, capture: true });\n\n // Focus the first item the keyboard can actually use. `preventScroll` so a\n // menu opened near the bottom of a long page does not jump it.\n _enabledItems(menu)[0]?.focus({ preventScroll: true });\n}\n\nexport function hideContextMenu() {\n if (!_activeMenu) return;\n const returnTo = _returnFocusTo;\n const held = _activeMenu.contains(document.activeElement);\n _activeMenu.remove();\n _activeMenu = null;\n _returnFocusTo = null;\n document.removeEventListener('keydown', _keyHandler);\n // Only take focus back if the menu still had it. A click elsewhere has\n // already moved focus deliberately and must not be undone.\n if (held && returnTo?.isConnected) returnTo.focus?.({ preventScroll: true });\n}\n\nfunction _enabledItems(menu) {\n return [...menu.querySelectorAll('.twm-context-menu-item:not(.disabled)')];\n}\n\n/** Up/Down/Home/End move; the list WRAPS, which is what a menu of four items\n * wants and what every desktop menu does. Enter and Space are the button's\n * own, so they are not bound here. */\nfunction _keyHandler(e) {\n if (!_activeMenu) return;\n if (e.key === 'Escape') { e.preventDefault(); hideContextMenu(); return; }\n const items = _enabledItems(_activeMenu);\n if (items.length === 0) return;\n const at = items.indexOf(document.activeElement);\n let next = null;\n if (e.key === 'ArrowDown') next = items[(at + 1 + items.length) % items.length];\n else if (e.key === 'ArrowUp') next = items[(at - 1 + items.length) % items.length];\n else if (e.key === 'Home') next = items[0];\n else if (e.key === 'End') next = items[items.length - 1];\n if (!next) return;\n e.preventDefault();\n next.focus({ preventScroll: true });\n}\n\nfunction _outsideHandler(e) {\n if (_activeMenu && !_activeMenu.contains(e.target)) hideContextMenu();\n}\n\nfunction escapeHtml(s) {\n return String(s).replace(/[&<>\"']/g, (c) => ({\n '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;',\n }[c]));\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
File without changes
File without changes