flexdesk 0.17.17 → 0.18.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 (300) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/LICENSE +0 -0
  3. package/README.md +1 -0
  4. package/THIRD_PARTY_LICENSES.md +0 -0
  5. package/canvas.js +0 -0
  6. package/charts.js +0 -0
  7. package/core.js +0 -0
  8. package/css/flexdesk.css +7499 -5851
  9. package/css/reset.css +1 -1
  10. package/css/tokens.css +23 -1
  11. package/dist/canvas.js +0 -0
  12. package/dist/canvas.js.map +0 -0
  13. package/dist/charts.js +10 -6
  14. package/dist/charts.js.map +1 -1
  15. package/dist/chunk-3PHCPZHT.js +0 -0
  16. package/dist/chunk-3PHCPZHT.js.map +0 -0
  17. package/dist/chunk-5W4EEKSK.js +778 -0
  18. package/dist/chunk-5W4EEKSK.js.map +7 -0
  19. package/dist/chunk-DNJ3N4T4.js +82 -0
  20. package/dist/chunk-DNJ3N4T4.js.map +7 -0
  21. package/dist/chunk-FOOS3T5L.js +0 -0
  22. package/dist/chunk-FOOS3T5L.js.map +0 -0
  23. package/dist/chunk-GOQLR5WR.js +0 -0
  24. package/dist/chunk-GOQLR5WR.js.map +0 -0
  25. package/dist/{chunk-JKZLNKG6.js → chunk-HKPB6OFA.js} +90 -25
  26. package/dist/{chunk-JKZLNKG6.js.map → chunk-HKPB6OFA.js.map} +2 -2
  27. package/dist/chunk-HNU6MM2B.js +0 -0
  28. package/dist/chunk-HNU6MM2B.js.map +0 -0
  29. package/dist/{chunk-REJ5HLIM.js → chunk-HYJYYEPK.js} +2 -2
  30. package/dist/chunk-JYWURG5T.js +0 -0
  31. package/dist/chunk-JYWURG5T.js.map +0 -0
  32. package/dist/{chunk-7U4IB65H.js → chunk-LLBJ2SJH.js} +5 -3
  33. package/dist/{chunk-7U4IB65H.js.map → chunk-LLBJ2SJH.js.map} +1 -1
  34. package/dist/chunk-N7HC3ADV.js +0 -0
  35. package/dist/chunk-N7HC3ADV.js.map +0 -0
  36. package/dist/{chunk-7OL6F2AM.js → chunk-P74F6I6P.js} +6 -4
  37. package/dist/{chunk-7OL6F2AM.js.map → chunk-P74F6I6P.js.map} +1 -1
  38. package/dist/chunk-PAI2ZUWV.js +260 -0
  39. package/dist/chunk-PAI2ZUWV.js.map +7 -0
  40. package/dist/chunk-Q7BALEPX.js +527 -0
  41. package/dist/chunk-Q7BALEPX.js.map +7 -0
  42. package/dist/chunk-QXAOTGCC.js +40 -0
  43. package/dist/chunk-QXAOTGCC.js.map +7 -0
  44. package/dist/{chunk-XJNADRGR.js → chunk-RKVYIXDC.js} +664 -91
  45. package/dist/chunk-RKVYIXDC.js.map +7 -0
  46. package/dist/{chunk-2Z2ENHR3.js → chunk-U5GKJUOC.js} +3 -3
  47. package/dist/{chunk-2Z2ENHR3.js.map → chunk-U5GKJUOC.js.map} +1 -1
  48. package/dist/chunk-UKP22RUG.js +219 -0
  49. package/dist/chunk-UKP22RUG.js.map +7 -0
  50. package/dist/chunk-VLOAI3HS.js +43 -0
  51. package/dist/chunk-VLOAI3HS.js.map +7 -0
  52. package/dist/{chunk-WUFLGETN.js → chunk-WVFGV5FT.js} +2 -39
  53. package/dist/{chunk-WUFLGETN.js.map → chunk-WVFGV5FT.js.map} +3 -3
  54. package/dist/{chunk-PGZ4EHSE.js → chunk-ZL3VKINP.js} +41 -390
  55. package/dist/chunk-ZL3VKINP.js.map +7 -0
  56. package/dist/editor.js +3 -2
  57. package/dist/editor.js.map +1 -1
  58. package/dist/flexdesk.css +7499 -5851
  59. package/dist/flow.js +29 -97
  60. package/dist/flow.js.map +3 -3
  61. package/dist/git.js +1356 -0
  62. package/dist/git.js.map +7 -0
  63. package/dist/host.js +0 -0
  64. package/dist/host.js.map +0 -0
  65. package/dist/reset.css +1 -1
  66. package/dist/tile_registry-6WZPTUZV.js +0 -0
  67. package/dist/tile_registry-6WZPTUZV.js.map +0 -0
  68. package/dist/tiles.js +20 -15
  69. package/dist/tiles.js.map +2 -2
  70. package/dist/tokens.css +23 -1
  71. package/dist/widgets.js +3969 -1189
  72. package/dist/widgets.js.map +4 -4
  73. package/dist/wm.js +121 -33
  74. package/dist/wm.js.map +2 -2
  75. package/docs/README.md +9 -4
  76. package/docs/best-practices.md +2 -2
  77. package/docs/components/chat-shell.md +198 -0
  78. package/docs/components/command-palette.md +0 -0
  79. package/docs/components/conversation.md +10 -0
  80. package/docs/components/data-table-grid.md +0 -0
  81. package/docs/components/data-table.md +0 -0
  82. package/docs/components/editor.md +0 -0
  83. package/docs/components/filter-builder.md +246 -0
  84. package/docs/components/flow-canvas-editor.md +0 -0
  85. package/docs/components/flow-editors.md +0 -0
  86. package/docs/components/flow-lane-editor.md +0 -0
  87. package/docs/components/flow-outline-editor.md +0 -0
  88. package/docs/components/forms-and-dialogs.md +22 -0
  89. package/docs/components/git.md +355 -0
  90. package/docs/components/input-fields.md +167 -2
  91. package/docs/components/keymap.md +8 -0
  92. package/docs/components/markdown-and-outline.md +0 -0
  93. package/docs/components/menus.md +120 -3
  94. package/docs/components/panels-and-desktops.md +16 -5
  95. package/docs/components/record-list-and-fact-table.md +0 -0
  96. package/docs/components/settings-view.md +0 -0
  97. package/docs/components/shell.md +104 -1
  98. package/docs/components/wizard.md +0 -0
  99. package/docs/components/workspace-picker.md +149 -0
  100. package/docs/concepts/building-and-packaging.md +2 -2
  101. package/docs/concepts/domain-neutrality.md +0 -0
  102. package/docs/concepts/host-port.md +0 -0
  103. package/docs/concepts/packages-and-entry-points.md +14 -13
  104. package/docs/concepts/peer-dependencies.md +0 -0
  105. package/docs/concepts/state-guard.md +3 -3
  106. package/docs/quickstart.md +1 -1
  107. package/editor.js +0 -0
  108. package/flow.js +0 -0
  109. package/git.js +13 -0
  110. package/host.js +0 -0
  111. package/package.json +6 -1
  112. package/src/canvas/canvas_adapter.js +0 -0
  113. package/src/canvas/edge_router.js +0 -0
  114. package/src/canvas/graph/connector_router.js +0 -0
  115. package/src/canvas/graph/history_service.js +0 -0
  116. package/src/canvas/graph/node_platform.js +0 -0
  117. package/src/canvas/index.js +0 -0
  118. package/src/canvas/layered_layout.js +0 -0
  119. package/src/charts/data_series_plot_window.js +0 -0
  120. package/src/charts/downsample.js +0 -0
  121. package/src/charts/plot_config.js +0 -0
  122. package/src/charts/plotly_wrapper.js +0 -0
  123. package/src/core/event_bus.js +0 -0
  124. package/src/core/logging.js +0 -0
  125. package/src/core/settings.js +0 -0
  126. package/src/core/state_guard.js +0 -0
  127. package/src/core/state_machine.js +0 -0
  128. package/src/editor/editor_pane.js +0 -0
  129. package/src/editor/monaco_editor_factory.js +0 -0
  130. package/src/editor/monaco_loader.js +0 -0
  131. package/src/editor/notebook_search.js +0 -0
  132. package/src/editor/notebook_undo_manager.js +0 -0
  133. package/src/editor/split_pane_container.js +0 -0
  134. package/src/flow/canvas_editor/connections.js +0 -0
  135. package/src/flow/canvas_editor/editor.js +0 -0
  136. package/src/flow/canvas_editor/index.js +0 -0
  137. package/src/flow/canvas_editor/layout.js +0 -0
  138. package/src/flow/canvas_editor/strings.js +0 -0
  139. package/src/flow/kit/always_before.js +0 -0
  140. package/src/flow/kit/catalogue.js +0 -0
  141. package/src/flow/kit/chip_input.js +0 -0
  142. package/src/flow/kit/dom.js +28 -119
  143. package/src/flow/kit/findings.js +0 -0
  144. package/src/flow/kit/history.js +0 -0
  145. package/src/flow/kit/index.js +0 -0
  146. package/src/flow/kit/keys.js +0 -0
  147. package/src/flow/kit/logic_graph.js +0 -0
  148. package/src/flow/kit/references.js +0 -0
  149. package/src/flow/kit/settings_panel.js +0 -0
  150. package/src/flow/kit/settings_schema.js +0 -0
  151. package/src/flow/kit/step_picker.js +1 -1
  152. package/src/flow/kit/strings.js +0 -0
  153. package/src/flow/kit/value_picker.js +1 -1
  154. package/src/flow/kit/widgets.js +0 -0
  155. package/src/flow/lanes/editor.js +0 -0
  156. package/src/flow/lanes/index.js +0 -0
  157. package/src/flow/lanes/layout.js +0 -0
  158. package/src/flow/lanes/pipeline.js +0 -0
  159. package/src/flow/lanes/preview.js +0 -0
  160. package/src/flow/lanes/strings.js +0 -0
  161. package/src/flow/outline/editor.js +0 -0
  162. package/src/flow/outline/index.js +0 -0
  163. package/src/flow/outline/mapping.js +0 -0
  164. package/src/flow/outline/menu.js +1 -1
  165. package/src/flow/outline/operations.js +0 -0
  166. package/src/flow/outline/recognise.js +0 -0
  167. package/src/flow/outline/strings.js +0 -0
  168. package/src/git/diff_viewer.js +212 -0
  169. package/src/git/diff_window.js +51 -0
  170. package/src/git/git_graph.js +401 -0
  171. package/src/git/git_ops.js +61 -0
  172. package/src/git/git_panel.js +755 -0
  173. package/src/git/index.js +9 -0
  174. package/src/git/line_diff.js +202 -0
  175. package/src/help/help_modal.js +0 -0
  176. package/src/help/help_registry.js +0 -0
  177. package/src/host/external_links.js +0 -0
  178. package/src/host/file_picker.js +0 -0
  179. package/src/host/host.js +0 -0
  180. package/src/host/photino_host.js +0 -0
  181. package/src/host/photino_host.md +0 -0
  182. package/src/host/pywebview_host.js +0 -0
  183. package/src/tiles/chart_tiles.js +0 -0
  184. package/src/tiles/config_schema.js +0 -0
  185. package/src/tiles/figure_tile.js +0 -0
  186. package/src/tiles/layout_persistence.js +0 -0
  187. package/src/tiles/list_tiles.js +0 -0
  188. package/src/tiles/scope_picker.js +0 -0
  189. package/src/tiles/tile_base.js +5 -4
  190. package/src/tiles/tile_config_form.js +0 -0
  191. package/src/tiles/tile_registry.js +0 -0
  192. package/src/tiling/bottom_panel_tabs.js +0 -0
  193. package/src/tiling/command_palette.js +0 -0
  194. package/src/tiling/content_registry.js +0 -0
  195. package/src/tiling/desktops.js +10 -8
  196. package/src/tiling/entity_sources.js +0 -0
  197. package/src/tiling/keymap.js +6 -5
  198. package/src/tiling/kind_taxonomy.js +15 -2
  199. package/src/tiling/landing_table.js +0 -0
  200. package/src/tiling/loading_overlay.js +0 -0
  201. package/src/tiling/nav_panel.js +0 -0
  202. package/src/tiling/page_factory.js +0 -0
  203. package/src/tiling/panel_availability.js +0 -0
  204. package/src/tiling/panel_keys.js +0 -0
  205. package/src/tiling/shell.js +124 -17
  206. package/src/tiling/tab_strip.js +0 -0
  207. package/src/tiling/tile_renderer.js +2 -3
  208. package/src/tiling/tile_tab_menu.js +0 -0
  209. package/src/tiling/zoom.js +0 -0
  210. package/src/ui/base/component_base.js +0 -0
  211. package/src/ui/base/controller_base.js +0 -0
  212. package/src/ui/base/page_base.js +0 -0
  213. package/src/ui/components/about_dialog.js +0 -0
  214. package/src/ui/components/action_dropdown.js +4 -78
  215. package/src/ui/components/alert_log.js +0 -0
  216. package/src/ui/components/alerts_pane.js +0 -0
  217. package/src/ui/components/anchored_layer.js +255 -0
  218. package/src/ui/components/attribute_list_editor.js +0 -0
  219. package/src/ui/components/autocomplete_field.js +0 -0
  220. package/src/ui/components/cell_editor_host.js +0 -0
  221. package/src/ui/components/cell_editors.js +0 -0
  222. package/src/ui/components/cell_grid.js +0 -0
  223. package/src/ui/components/cell_paste.js +0 -0
  224. package/src/ui/components/cell_selection.js +0 -0
  225. package/src/ui/components/chat_shell.js +920 -0
  226. package/src/ui/components/chat_state_machine.js +223 -0
  227. package/src/ui/components/choice_controls.js +45 -2
  228. package/src/ui/components/color_field.js +3 -2
  229. package/src/ui/components/color_list_field.js +3 -2
  230. package/src/ui/components/column_fit.js +0 -0
  231. package/src/ui/components/column_groups.js +0 -0
  232. package/src/ui/components/column_order.js +0 -0
  233. package/src/ui/components/combobox.js +422 -0
  234. package/src/ui/components/conversation_view.js +17 -2
  235. package/src/ui/components/crosstab.js +0 -0
  236. package/src/ui/components/data_table.js +2 -2
  237. package/src/ui/components/detail_header.js +0 -0
  238. package/src/ui/components/document_outline.js +0 -0
  239. package/src/ui/components/drag_reorder.js +0 -0
  240. package/src/ui/components/fact_table.js +0 -0
  241. package/src/ui/components/fill_handle.js +0 -0
  242. package/src/ui/components/filter_builder.js +766 -0
  243. package/src/ui/components/filter_model.js +614 -0
  244. package/src/ui/components/gallery_picker.js +0 -0
  245. package/src/ui/components/header_actions.js +0 -0
  246. package/src/ui/components/inline_renamer.js +0 -0
  247. package/src/ui/components/job_progress.js +0 -0
  248. package/src/ui/components/managed_window.js +24 -47
  249. package/src/ui/components/menu_bar.js +101 -24
  250. package/src/ui/components/modal.js +79 -109
  251. package/src/ui/components/option_list.js +160 -0
  252. package/src/ui/components/popover.js +94 -0
  253. package/src/ui/components/progress.js +0 -0
  254. package/src/ui/components/recent_items.js +169 -0
  255. package/src/ui/components/record_list.js +0 -0
  256. package/src/ui/components/row_activation.js +0 -0
  257. package/src/ui/components/section_stack.js +0 -0
  258. package/src/ui/components/select.js +322 -0
  259. package/src/ui/components/series.js +0 -0
  260. package/src/ui/components/settings_view.js +0 -0
  261. package/src/ui/components/slide_out_panel.js +0 -0
  262. package/src/ui/components/slider_field.js +0 -0
  263. package/src/ui/components/sortable_list.js +0 -0
  264. package/src/ui/components/staged_edits.js +0 -0
  265. package/src/ui/components/staged_history.js +0 -0
  266. package/src/ui/components/table_filter_chips.js +0 -0
  267. package/src/ui/components/table_state_store.js +0 -0
  268. package/src/ui/components/table_structure.js +0 -0
  269. package/src/ui/components/table_values.js +0 -0
  270. package/src/ui/components/tabs.js +0 -0
  271. package/src/ui/components/tag_input.js +77 -8
  272. package/src/ui/components/toast.js +0 -0
  273. package/src/ui/components/toggle_field.js +0 -0
  274. package/src/ui/components/tsv.js +0 -0
  275. package/src/ui/components/window_taskbar.js +0 -0
  276. package/src/ui/components/workspace_picker.js +1155 -0
  277. package/src/ui/controllers/window_chrome_controller.js +4 -1
  278. package/src/ui/utils/auto_scrollbars.js +0 -0
  279. package/src/ui/utils/fire_event.js +17 -0
  280. package/src/ui/utils/focusable.js +25 -0
  281. package/src/ui/utils/markdown.js +0 -0
  282. package/src/ui/utils/modal_host.js +27 -0
  283. package/src/ui/utils/native_context_menu.js +0 -0
  284. package/src/ui/utils/overlay_scrollbar.js +0 -0
  285. package/src/ui/utils/raf_resize_observer.js +0 -0
  286. package/src/ui/utils/scroll_lock.js +0 -0
  287. package/src/ui/utils/strip_scroll.js +0 -0
  288. package/src/ui/utils/tooltip_service.js +0 -0
  289. package/tiles.js +0 -0
  290. package/widgets.js +12 -2
  291. package/wm.js +0 -0
  292. package/css/base.css +0 -10527
  293. package/css/overrides.css +0 -2596
  294. package/dist/chunk-7JI7HHSY.js +0 -107
  295. package/dist/chunk-7JI7HHSY.js.map +0 -7
  296. package/dist/chunk-MIW7D6WC.js +0 -526
  297. package/dist/chunk-MIW7D6WC.js.map +0 -7
  298. package/dist/chunk-PGZ4EHSE.js.map +0 -7
  299. package/dist/chunk-XJNADRGR.js.map +0 -7
  300. /package/dist/{chunk-REJ5HLIM.js.map → chunk-HYJYYEPK.js.map} +0 -0
@@ -0,0 +1,219 @@
1
+ // src/ui/base/component_base.js
2
+ var ComponentBase = class _ComponentBase {
3
+ constructor({ eventBus, logger } = {}) {
4
+ if (new.target === _ComponentBase) {
5
+ throw new Error("ComponentBase is abstract \u2013 extend it instead");
6
+ }
7
+ this.eventBus = eventBus;
8
+ this.logger = logger;
9
+ this._mounted = false;
10
+ }
11
+ mount() {
12
+ throw new Error("ComponentBase.mount must be implemented by subclasses");
13
+ }
14
+ update() {
15
+ }
16
+ dispose() {
17
+ this._mounted = false;
18
+ }
19
+ };
20
+
21
+ // src/ui/components/slide_out_panel.js
22
+ var SlideOutPanel = class extends ComponentBase {
23
+ /** @type {HTMLElement} */
24
+ #container = null;
25
+ /** @type {HTMLElement} */
26
+ #backdrop = null;
27
+ /** @type {HTMLElement} */
28
+ #panel = null;
29
+ /** @type {HTMLElement} */
30
+ #headerIcon = null;
31
+ /** @type {HTMLElement} */
32
+ #headerTitle = null;
33
+ /** @type {HTMLElement} */
34
+ #body = null;
35
+ /** @type {number} */
36
+ #width;
37
+ /** @type {Function|null} */
38
+ #onClose;
39
+ /** @type {boolean} */
40
+ #open = false;
41
+ /** @type {ResizeObserver|null} */
42
+ #hostObserver = null;
43
+ /**
44
+ * @param {object} opts
45
+ * @param {number} [opts.width=380] Panel width in px.
46
+ * @param {Function} [opts.onClose] Called after the panel closes.
47
+ */
48
+ constructor({ width = 700, onClose } = {}) {
49
+ super();
50
+ this.#width = width;
51
+ this.#onClose = onClose ?? null;
52
+ }
53
+ // ─── Lifecycle ──────────────────────────────────────────────────────────
54
+ /**
55
+ * Mount the panel DOM into a host container.
56
+ * @param {HTMLElement} container Must have position:relative; overflow:hidden.
57
+ */
58
+ mount(container) {
59
+ if (this._mounted) return;
60
+ this.#container = container;
61
+ this.#backdrop = document.createElement("div");
62
+ this.#backdrop.className = "twm-slide-out-panel__backdrop";
63
+ this.#backdrop.addEventListener("click", this.#handleBackdropClick);
64
+ this.#panel = document.createElement("div");
65
+ this.#panel.className = "twm-slide-out-panel";
66
+ this.#panel.style.width = `${this.#width}px`;
67
+ const header = document.createElement("div");
68
+ header.className = "twm-slide-out-panel__header";
69
+ this.#headerIcon = document.createElement("span");
70
+ this.#headerIcon.className = "twm-slide-out-panel__icon material-symbols-outlined";
71
+ this.#headerTitle = document.createElement("span");
72
+ this.#headerTitle.className = "twm-slide-out-panel__title";
73
+ const closeBtn = document.createElement("button");
74
+ closeBtn.className = "twm-slide-out-panel__close twm-btn-icon";
75
+ closeBtn.type = "button";
76
+ closeBtn.title = "Close";
77
+ closeBtn.innerHTML = '<span class="material-symbols-outlined">close</span>';
78
+ closeBtn.addEventListener("click", this.#handleCloseClick);
79
+ header.append(this.#headerIcon, this.#headerTitle, closeBtn);
80
+ this.#body = document.createElement("div");
81
+ this.#body.className = "twm-slide-out-panel__body";
82
+ this.#panel.append(header, this.#body);
83
+ this.#container.append(this.#backdrop, this.#panel);
84
+ this._mounted = true;
85
+ }
86
+ dispose() {
87
+ this.close();
88
+ this.#backdrop?.remove();
89
+ this.#panel?.remove();
90
+ this.#backdrop = null;
91
+ this.#panel = null;
92
+ this.#body = null;
93
+ this.#container = null;
94
+ super.dispose();
95
+ }
96
+ // ─── Public API ─────────────────────────────────────────────────────────
97
+ /** The inner content element — callers render config into this. */
98
+ get contentEl() {
99
+ return this.#body;
100
+ }
101
+ get isOpen() {
102
+ return this.#open;
103
+ }
104
+ /**
105
+ * Open (or re-open) the panel with a new title/icon.
106
+ * Clears previous content. Returns contentEl for rendering.
107
+ * @param {string} title
108
+ * @param {string} icon Material Symbols icon name.
109
+ * @returns {HTMLElement} contentEl
110
+ */
111
+ open(title, icon) {
112
+ if (!this._mounted) return null;
113
+ this.#body.innerHTML = "";
114
+ this.#headerIcon.textContent = icon || "";
115
+ this.#headerIcon.style.display = icon ? "" : "none";
116
+ this.#headerTitle.textContent = title || "";
117
+ if (!this.#open) {
118
+ this.#open = true;
119
+ this.#backdrop.classList.add("twm-slide-out-panel__backdrop--visible");
120
+ this.#panel.classList.add("twm-slide-out-panel--open");
121
+ document.addEventListener("keydown", this.#handleEsc);
122
+ this.#trackGeometry();
123
+ window.addEventListener("scroll", this.#trackGeometry, true);
124
+ window.addEventListener("resize", this.#trackGeometry);
125
+ this.#observeHost();
126
+ }
127
+ return this.#body;
128
+ }
129
+ /** Close the panel and clear content. */
130
+ close() {
131
+ if (!this.#open) return;
132
+ this.#open = false;
133
+ this.#panel.classList.remove("twm-slide-out-panel--open");
134
+ this.#backdrop.classList.remove("twm-slide-out-panel__backdrop--visible");
135
+ document.removeEventListener("keydown", this.#handleEsc);
136
+ window.removeEventListener("scroll", this.#trackGeometry, true);
137
+ window.removeEventListener("resize", this.#trackGeometry);
138
+ this.#hostObserver?.disconnect();
139
+ this.#hostObserver = null;
140
+ this.#body.innerHTML = "";
141
+ this.#onClose?.();
142
+ }
143
+ // ─── Event handlers (arrow fns for stable `this`) ───────────────────────
144
+ #handleBackdropClick = () => {
145
+ this.close();
146
+ };
147
+ #handleCloseClick = () => {
148
+ this.close();
149
+ };
150
+ #handleEsc = (e) => {
151
+ if (e.key === "Escape") {
152
+ e.stopPropagation();
153
+ this.close();
154
+ }
155
+ };
156
+ /** The host moves or resizes without any window event when a tile
157
+ * splitter is dragged or a dock panel toggles, and the fixed geometry
158
+ * would then stay at the old coordinates. Observe the host AND each
159
+ * ancestor: a host can move without changing size of its own (a dock
160
+ * panel toggling beside a fixed-width tile shrinks the content area,
161
+ * an ancestor, and the tile only shifts). The callback runs
162
+ * synchronously, after layout and before paint, so the panel follows
163
+ * a drag without a frame of lag; it only writes the panel's own
164
+ * `position: fixed` geometry, which is out of flow and resizes
165
+ * nothing observed, so it cannot loop. */
166
+ #observeHost() {
167
+ this.#hostObserver = new ResizeObserver(this.#trackGeometry);
168
+ for (let el = this.#container; el; el = el.parentElement) {
169
+ this.#hostObserver.observe(el);
170
+ }
171
+ }
172
+ /** Pin the panel to the right edge of its host's *visible* frame
173
+ * using `position: fixed`. Re-run on every window scroll/resize and
174
+ * every host resize (#observeHost) so the panel always overlays the
175
+ * host correctly even when the host itself sits inside a scrolled
176
+ * ancestor.
177
+ *
178
+ * UNDER A CSS `zoom` (the shell's content zoom scales a tile body),
179
+ * `getBoundingClientRect()` answers in screen pixels, which already
180
+ * carry the zoom, while the panel's own `top`/`left`/`height` are
181
+ * CSS pixels that the same zoom multiplies again. Copied across
182
+ * unchanged, every length was scaled twice: at 150% the panel landed
183
+ * right of and below its host, at 50% it was half the host's height.
184
+ * So the rect is divided by the panel's effective zoom
185
+ * (`currentCSSZoom`: 1 when nothing above it zooms, `undefined` in an
186
+ * engine that predates it), and the width subtracted is the panel's
187
+ * laid-out one, which `min-width` may hold above the requested
188
+ * width. Rounding happens in screen pixels, so at 100% the output is
189
+ * exactly what it always was.
190
+ *
191
+ * NEVER WIDER THAN THE HOST (BUG-0035). The right edge is pinned, so a
192
+ * panel wider than its host (700px by default, `min-width: 400px`)
193
+ * reached past the host's left edge across the neighbouring pane. The
194
+ * host's width, in the panel's CSS pixels, goes on the panel as
195
+ * `--twm-slide-out-host-w`, which the stylesheet uses as `max-width`
196
+ * and as the ceiling of the 400px `min-width`; it is set BEFORE the
197
+ * width is read so the read sees the capped layout, and the width is
198
+ * capped here too for an engine that lays nothing out. */
199
+ #trackGeometry = () => {
200
+ if (!this.#open || !this.#panel || !this.#container) return;
201
+ const r = this.#container.getBoundingClientRect();
202
+ const zoom = this.#panel.currentCSSZoom || 1;
203
+ const hostWidth = r.width / zoom;
204
+ const s = this.#panel.style;
205
+ s.setProperty("--twm-slide-out-host-w", `${hostWidth}px`);
206
+ const width = Math.min(this.#panel.offsetWidth || this.#width, hostWidth);
207
+ s.position = "fixed";
208
+ s.top = `${Math.round(r.top) / zoom}px`;
209
+ s.left = `${Math.round(r.right - width * zoom) / zoom}px`;
210
+ s.right = "auto";
211
+ s.height = `${Math.round(r.height) / zoom}px`;
212
+ };
213
+ };
214
+
215
+ export {
216
+ ComponentBase,
217
+ SlideOutPanel
218
+ };
219
+ //# sourceMappingURL=chunk-UKP22RUG.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/ui/base/component_base.js", "../src/ui/components/slide_out_panel.js"],
4
+ "sourcesContent": ["/**\r\n * ComponentBase (js_new)\r\n *\r\n * Ultra-lightweight base for leaf UI widgets rendered inside controllers/panels.\r\n * Handles props/state updates and deterministic teardown without storing data on\r\n * DOM elements.\r\n */\r\nexport class ComponentBase {\r\n constructor({ eventBus, logger } = {}) {\r\n if (new.target === ComponentBase) {\r\n throw new Error('ComponentBase is abstract \u2013 extend it instead');\r\n }\r\n\r\n this.eventBus = eventBus;\r\n this.logger = logger;\r\n this._mounted = false;\r\n }\r\n\r\n mount(/* container, props */) {\r\n throw new Error('ComponentBase.mount must be implemented by subclasses');\r\n }\r\n\r\n update(/* props */) {\r\n // default no-op for stateless components\r\n }\r\n\r\n dispose() {\r\n this._mounted = false;\r\n }\r\n}\r\n", "/**\n * SlideOutPanel\n *\n * Reusable inline slide-out config panel that overlays its host container\n * from the right edge. Used by pages to show element-specific config\n * (plot config, widget config, ETL node config) without the global right panel.\n *\n * Host container must have `position: relative; overflow: hidden`.\n */\nimport { ComponentBase } from '../base/component_base.js';\n\nexport class SlideOutPanel extends ComponentBase {\n\n /** @type {HTMLElement} */ #container = null;\n /** @type {HTMLElement} */ #backdrop = null;\n /** @type {HTMLElement} */ #panel = null;\n /** @type {HTMLElement} */ #headerIcon = null;\n /** @type {HTMLElement} */ #headerTitle = null;\n /** @type {HTMLElement} */ #body = null;\n /** @type {number} */ #width;\n /** @type {Function|null} */#onClose;\n /** @type {boolean} */ #open = false;\n /** @type {ResizeObserver|null} */ #hostObserver = null;\n\n /**\n * @param {object} opts\n * @param {number} [opts.width=380] Panel width in px.\n * @param {Function} [opts.onClose] Called after the panel closes.\n */\n constructor({ width = 700, onClose } = {}) {\n super();\n this.#width = width;\n this.#onClose = onClose ?? null;\n }\n\n // \u2500\u2500\u2500 Lifecycle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Mount the panel DOM into a host container.\n * @param {HTMLElement} container Must have position:relative; overflow:hidden.\n */\n mount(container) {\n if (this._mounted) return;\n this.#container = container;\n\n // Backdrop (transparent click-catcher)\n this.#backdrop = document.createElement('div');\n this.#backdrop.className = 'twm-slide-out-panel__backdrop';\n this.#backdrop.addEventListener('click', this.#handleBackdropClick);\n\n // Panel\n this.#panel = document.createElement('div');\n this.#panel.className = 'twm-slide-out-panel';\n this.#panel.style.width = `${this.#width}px`;\n\n // Header\n const header = document.createElement('div');\n header.className = 'twm-slide-out-panel__header';\n\n this.#headerIcon = document.createElement('span');\n this.#headerIcon.className = 'twm-slide-out-panel__icon material-symbols-outlined';\n\n this.#headerTitle = document.createElement('span');\n this.#headerTitle.className = 'twm-slide-out-panel__title';\n\n const closeBtn = document.createElement('button');\n closeBtn.className = 'twm-slide-out-panel__close twm-btn-icon';\n closeBtn.type = 'button';\n closeBtn.title = 'Close';\n closeBtn.innerHTML = '<span class=\"material-symbols-outlined\">close</span>';\n closeBtn.addEventListener('click', this.#handleCloseClick);\n\n header.append(this.#headerIcon, this.#headerTitle, closeBtn);\n\n // Body (scrollable content area)\n this.#body = document.createElement('div');\n this.#body.className = 'twm-slide-out-panel__body';\n\n this.#panel.append(header, this.#body);\n this.#container.append(this.#backdrop, this.#panel);\n\n this._mounted = true;\n }\n\n dispose() {\n this.close();\n this.#backdrop?.remove();\n this.#panel?.remove();\n this.#backdrop = null;\n this.#panel = null;\n this.#body = null;\n this.#container = null;\n super.dispose();\n }\n\n // \u2500\u2500\u2500 Public API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 /** The inner content element \u2014 callers render config into this. */\n get contentEl() { return this.#body; }\n\n get isOpen() { return this.#open; }\n\n /**\n * Open (or re-open) the panel with a new title/icon.\n * Clears previous content. Returns contentEl for rendering.\n * @param {string} title\n * @param {string} icon Material Symbols icon name.\n * @returns {HTMLElement} contentEl\n */\n open(title, icon) {\n if (!this._mounted) return null;\n\n this.#body.innerHTML = '';\n this.#headerIcon.textContent = icon || '';\n this.#headerIcon.style.display = icon ? '' : 'none';\n this.#headerTitle.textContent = title || '';\n\n if (!this.#open) {\n this.#open = true;\n this.#backdrop.classList.add('twm-slide-out-panel__backdrop--visible');\n this.#panel.classList.add('twm-slide-out-panel--open');\n document.addEventListener('keydown', this.#handleEsc);\n\n // The host may be a scroll container \u2014 absolutely-positioned\n // descendants of one DO scroll along with the content\n // (Web spec: a position:absolute element is clipped + offset\n // by its containing scroll context). We escape that by\n // switching the panel to `position: fixed` while open and\n // tracking the host's bounding rect on scroll / resize, so\n // the panel stays pinned to the host's visible frame at\n // full height regardless of how the user scrolls inside.\n this.#trackGeometry();\n window.addEventListener('scroll', this.#trackGeometry, true);\n window.addEventListener('resize', this.#trackGeometry);\n this.#observeHost();\n }\n\n return this.#body;\n }\n\n /** Close the panel and clear content. */\n close() {\n if (!this.#open) return;\n this.#open = false;\n\n this.#panel.classList.remove('twm-slide-out-panel--open');\n this.#backdrop.classList.remove('twm-slide-out-panel__backdrop--visible');\n document.removeEventListener('keydown', this.#handleEsc);\n window.removeEventListener('scroll', this.#trackGeometry, true);\n window.removeEventListener('resize', this.#trackGeometry);\n this.#hostObserver?.disconnect();\n this.#hostObserver = null;\n // Leave the inline position:fixed geometry in place. The panel\n // slides off-screen via the transform animation (translateX\n // 100%); the next open() re-runs #trackGeometry which will\n // refresh top/left/height from the host's current rect.\n\n this.#body.innerHTML = '';\n this.#onClose?.();\n }\n\n // \u2500\u2500\u2500 Event handlers (arrow fns for stable `this`) \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 #handleBackdropClick = () => { this.close(); };\n\n #handleCloseClick = () => { this.close(); };\n\n #handleEsc = (e) => {\n if (e.key === 'Escape') {\n e.stopPropagation();\n this.close();\n }\n };\n\n /** The host moves or resizes without any window event when a tile\n * splitter is dragged or a dock panel toggles, and the fixed geometry\n * would then stay at the old coordinates. Observe the host AND each\n * ancestor: a host can move without changing size of its own (a dock\n * panel toggling beside a fixed-width tile shrinks the content area,\n * an ancestor, and the tile only shifts). The callback runs\n * synchronously, after layout and before paint, so the panel follows\n * a drag without a frame of lag; it only writes the panel's own\n * `position: fixed` geometry, which is out of flow and resizes\n * nothing observed, so it cannot loop. */\n #observeHost() {\n this.#hostObserver = new ResizeObserver(this.#trackGeometry);\n for (let el = this.#container; el; el = el.parentElement) {\n this.#hostObserver.observe(el);\n }\n }\n\n /** Pin the panel to the right edge of its host's *visible* frame\n * using `position: fixed`. Re-run on every window scroll/resize and\n * every host resize (#observeHost) so the panel always overlays the\n * host correctly even when the host itself sits inside a scrolled\n * ancestor.\n *\n * UNDER A CSS `zoom` (the shell's content zoom scales a tile body),\n * `getBoundingClientRect()` answers in screen pixels, which already\n * carry the zoom, while the panel's own `top`/`left`/`height` are\n * CSS pixels that the same zoom multiplies again. Copied across\n * unchanged, every length was scaled twice: at 150% the panel landed\n * right of and below its host, at 50% it was half the host's height.\n * So the rect is divided by the panel's effective zoom\n * (`currentCSSZoom`: 1 when nothing above it zooms, `undefined` in an\n * engine that predates it), and the width subtracted is the panel's\n * laid-out one, which `min-width` may hold above the requested\n * width. Rounding happens in screen pixels, so at 100% the output is\n * exactly what it always was.\n *\n * NEVER WIDER THAN THE HOST (BUG-0035). The right edge is pinned, so a\n * panel wider than its host (700px by default, `min-width: 400px`)\n * reached past the host's left edge across the neighbouring pane. The\n * host's width, in the panel's CSS pixels, goes on the panel as\n * `--twm-slide-out-host-w`, which the stylesheet uses as `max-width`\n * and as the ceiling of the 400px `min-width`; it is set BEFORE the\n * width is read so the read sees the capped layout, and the width is\n * capped here too for an engine that lays nothing out. */\n #trackGeometry = () => {\n if (!this.#open || !this.#panel || !this.#container) return;\n const r = this.#container.getBoundingClientRect();\n const zoom = this.#panel.currentCSSZoom || 1;\n const hostWidth = r.width / zoom;\n const s = this.#panel.style;\n s.setProperty('--twm-slide-out-host-w', `${hostWidth}px`);\n const width = Math.min(this.#panel.offsetWidth || this.#width, hostWidth);\n s.position = 'fixed';\n s.top = `${Math.round(r.top) / zoom}px`;\n s.left = `${Math.round(r.right - width * zoom) / zoom}px`;\n s.right = 'auto';\n s.height = `${Math.round(r.height) / zoom}px`;\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,43 @@
1
+ // src/ui/components/row_activation.js
2
+ var ROW_CONTROL_SELECTOR = [
3
+ "button",
4
+ "a",
5
+ "input",
6
+ "select",
7
+ "textarea",
8
+ "label",
9
+ "summary",
10
+ '[contenteditable=""]',
11
+ '[contenteditable="true"]',
12
+ "[data-twm-action]"
13
+ ].join(", ");
14
+ function isRowControl(target, scope = null) {
15
+ const hit = target?.closest?.(ROW_CONTROL_SELECTOR);
16
+ return !!hit && (!scope || scope.contains(hit));
17
+ }
18
+ function endsTextSelection(target, scope = null) {
19
+ const doc = target?.ownerDocument || (typeof document !== "undefined" ? document : null);
20
+ const sel = doc?.getSelection?.();
21
+ if (!sel || sel.isCollapsed || !String(sel)) return false;
22
+ if (!scope) return true;
23
+ const inside = (node) => !!node && scope.contains(node);
24
+ return inside(sel.anchorNode) || inside(sel.focusNode);
25
+ }
26
+ function isRowActivation(ev, gesture = "click", { scope = null } = {}) {
27
+ const target = ev?.target;
28
+ if (!target?.closest) return false;
29
+ if (isRowControl(target, scope)) return false;
30
+ if (gesture === "click") {
31
+ if ((ev.detail ?? 0) > 1) return false;
32
+ if (endsTextSelection(target, scope)) return false;
33
+ }
34
+ return true;
35
+ }
36
+
37
+ export {
38
+ ROW_CONTROL_SELECTOR,
39
+ isRowControl,
40
+ endsTextSelection,
41
+ isRowActivation
42
+ };
43
+ //# sourceMappingURL=chunk-VLOAI3HS.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/ui/components/row_activation.js"],
4
+ "sourcesContent": ["/**\n * row_activation.js \u2014 WHEN A ROW GESTURE OPENS THE ROW. One rule, shared by\n * `DataTable`'s `onRowActivate` (0.5.0) and the landing helper\n * `attachLandingTableBehavior`, so a list built either way opens on exactly the\n * same gestures and refuses exactly the same ones.\n *\n * A row \"activates\" \u2014 opens the thing it stands for \u2014 on a click, a double-click\n * or Enter, as the table asks. Three things that look like a click are not one:\n *\n * 1. **A control in the row is its own gesture.** A button, a link, a field, a\n * `[data-twm-action]` verb: pressing it does what it says, and must not ALSO\n * open the row underneath it.\n * 2. **Dragging across a cell to copy it is not a click on the row.** A drag\n * that ends a text selection fires `click` on the cell it ends on; the\n * selection being non-empty is how it is told apart. Only a selection that\n * touches the list counts \u2014 one elsewhere on the page is not this gesture.\n * 3. **The second click of a double-click opens nothing.** A double-click is\n * two `click`s (`detail` 1, then 2) before the `dblclick`; the first one has\n * already opened the row. A list that draws the thing it opened IN PLACE\n * would otherwise take the second click as a click on whatever is now under\n * the pointer. `detail` is the platform's click count, not a timing guess;\n * a synthetic or keyboard `click` carries 0 and is a single click.\n *\n * A `dblclick` gesture skips rule 2: a double-click on text selects the word\n * under it, so a selection is the ordinary result of the gesture, not evidence\n * of a drag.\n */\n\n/** What a press inside a row is never a ROW gesture on: a control or a verb. */\nexport const ROW_CONTROL_SELECTOR = [\n 'button', 'a', 'input', 'select', 'textarea', 'label', 'summary',\n '[contenteditable=\"\"]', '[contenteditable=\"true\"]', '[data-twm-action]',\n].join(', ');\n\n/** Did this press land on a control inside the row (rule 1)? */\nexport function isRowControl(target, scope = null) {\n const hit = target?.closest?.(ROW_CONTROL_SELECTOR);\n return !!hit && (!scope || scope.contains(hit));\n}\n\n/** Does a non-empty text selection touch `scope` (rule 2)? Without a scope,\n * any non-empty selection in the target's document counts. */\nexport function endsTextSelection(target, scope = null) {\n const doc = target?.ownerDocument || (typeof document !== 'undefined' ? document : null);\n const sel = doc?.getSelection?.();\n if (!sel || sel.isCollapsed || !String(sel)) return false;\n if (!scope) return true;\n const inside = (node) => !!node && scope.contains(node);\n return inside(sel.anchorNode) || inside(sel.focusNode);\n}\n\n/**\n * Is this event a row activation of kind `gesture`, by the three rules above?\n *\n * @param {Event} ev\n * @param {'click'|'dblclick'} [gesture='click']\n * @param {{scope?: Element}} [o] the list's own element: a control or a\n * selection outside it is not this list's business\n * @returns {boolean}\n */\nexport function isRowActivation(ev, gesture = 'click', { scope = null } = {}) {\n const target = ev?.target;\n if (!target?.closest) return false;\n if (isRowControl(target, scope)) return false;\n if (gesture === 'click') {\n if ((ev.detail ?? 0) > 1) return false;\n if (endsTextSelection(target, scope)) return false;\n }\n return true;\n}\n"],
5
+ "mappings": ";AA6BO,IAAM,uBAAuB;AAAA,EAChC;AAAA,EAAU;AAAA,EAAK;AAAA,EAAS;AAAA,EAAU;AAAA,EAAY;AAAA,EAAS;AAAA,EACvD;AAAA,EAAwB;AAAA,EAA4B;AACxD,EAAE,KAAK,IAAI;AAGJ,SAAS,aAAa,QAAQ,QAAQ,MAAM;AAC/C,QAAM,MAAM,QAAQ,UAAU,oBAAoB;AAClD,SAAO,CAAC,CAAC,QAAQ,CAAC,SAAS,MAAM,SAAS,GAAG;AACjD;AAIO,SAAS,kBAAkB,QAAQ,QAAQ,MAAM;AACpD,QAAM,MAAM,QAAQ,kBAAkB,OAAO,aAAa,cAAc,WAAW;AACnF,QAAM,MAAM,KAAK,eAAe;AAChC,MAAI,CAAC,OAAO,IAAI,eAAe,CAAC,OAAO,GAAG,EAAG,QAAO;AACpD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,SAAS,CAAC,SAAS,CAAC,CAAC,QAAQ,MAAM,SAAS,IAAI;AACtD,SAAO,OAAO,IAAI,UAAU,KAAK,OAAO,IAAI,SAAS;AACzD;AAWO,SAAS,gBAAgB,IAAI,UAAU,SAAS,EAAE,QAAQ,KAAK,IAAI,CAAC,GAAG;AAC1E,QAAM,SAAS,IAAI;AACnB,MAAI,CAAC,QAAQ,QAAS,QAAO;AAC7B,MAAI,aAAa,QAAQ,KAAK,EAAG,QAAO;AACxC,MAAI,YAAY,SAAS;AACrB,SAAK,GAAG,UAAU,KAAK,EAAG,QAAO;AACjC,QAAI,kBAAkB,QAAQ,KAAK,EAAG,QAAO;AAAA,EACjD;AACA,SAAO;AACX;",
6
+ "names": []
7
+ }
@@ -199,44 +199,7 @@ var DragReorder = class {
199
199
  }
200
200
  };
201
201
 
202
- // src/ui/utils/menu_viewport.js
203
- var MENU_VIEWPORT_MARGIN = 8;
204
- function placeMenuInViewport(menu, x, y, margin = MENU_VIEWPORT_MARGIN) {
205
- const view = menu.ownerDocument?.defaultView || window;
206
- const vw = view.innerWidth;
207
- const vh = view.innerHeight;
208
- const maxHeight = Math.max(0, vh - 2 * margin);
209
- menu.style.maxHeight = `${maxHeight}px`;
210
- menu.scrollTop = 0;
211
- const rect = menu.getBoundingClientRect();
212
- const left = Math.min(x, vw - rect.width - margin);
213
- const top = Math.min(y, vh - rect.height - margin);
214
- menu.style.left = `${Math.max(0, left)}px`;
215
- menu.style.top = `${Math.max(0, top)}px`;
216
- }
217
- function focusMenuItem(item) {
218
- if (!item) return;
219
- item.focus({ preventScroll: true });
220
- item.scrollIntoView?.({ block: "nearest", inline: "nearest" });
221
- }
222
- function moveMenuFocus(e, items) {
223
- if (!items.length) return false;
224
- const at = items.indexOf(items[0].ownerDocument.activeElement);
225
- let next = null;
226
- if (e.key === "ArrowDown") next = items[(at + 1 + items.length) % items.length];
227
- else if (e.key === "ArrowUp") next = items[(at - 1 + items.length) % items.length];
228
- else if (e.key === "Home") next = items[0];
229
- else if (e.key === "End") next = items[items.length - 1];
230
- if (!next) return false;
231
- e.preventDefault();
232
- focusMenuItem(next);
233
- return true;
234
- }
235
-
236
202
  export {
237
- DragReorder,
238
- placeMenuInViewport,
239
- focusMenuItem,
240
- moveMenuFocus
203
+ DragReorder
241
204
  };
242
- //# sourceMappingURL=chunk-WUFLGETN.js.map
205
+ //# sourceMappingURL=chunk-WVFGV5FT.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/ui/components/drag_reorder.js", "../src/ui/utils/menu_viewport.js"],
4
- "sourcesContent": ["/**\n * DragReorder \u2014 the one same-list drag-to-reorder implementation, with\n * the \"classic\" ghost (`.dragging` on the dragged element) + drop\n * placeholder (an indicator div inserted at the drop position) and\n * edge auto-scroll. Native HTML5 drag-and-drop.\n *\n * Extracted from the duplicated tab-bar reorder code so the notebook tab\n * bar, the workspace tab bar, and the schema column strip all share one\n * implementation. Axis-aware (`x` for horizontal strips, `y` for\n * vertical lists) and parameterised so it makes no assumptions about\n * tabs specifically.\n *\n * Usage:\n * const dr = new DragReorder({\n * container, itemSelector: '.tab', keyAttr: 'tabId', axis: 'x',\n * onReorder: (order) => { ... }, // order = array of keys\n * });\n * dr.attach(); // after each (re)render of the items\n * dr.destroy(); // on teardown\n *\n * Coexistence: the container-level handlers no-op unless THIS instance's\n * drag is active, so a host can keep its own dragover/drop handlers for\n * other concerns (e.g. cross-pane tab drops) alongside it \u2014 gate those\n * on `dr.isActive() === false`.\n */\nexport class DragReorder {\n /**\n * @param {Object} opts\n * @param {HTMLElement} opts.container\n * @param {string} [opts.itemSelector='.tab'] selector for reorderable items\n * @param {string} [opts.keyAttr='path'] dataset key / data-attr identifying an item\n * @param {'x'|'y'} [opts.axis='x']\n * @param {string} [opts.indicatorClass='tab-drop-indicator']\n * @param {boolean} [opts.autoScroll=true]\n * @param {(e: DragEvent, item: HTMLElement) => boolean} [opts.draggableGuard]\n * return false to cancel a drag start (e.g. from a close button)\n * @param {(e: DragEvent, key: string, item: HTMLElement) => void} [opts.onDragStart]\n * host hook to augment dataTransfer (e.g. add a cross-pane MIME)\n * @param {(order: string[]) => void} [opts.onReorder]\n */\n constructor(opts = {}) {\n this.container = opts.container || null;\n this.itemSelector = opts.itemSelector || '.tab';\n this.keyAttr = opts.keyAttr || 'path';\n this.axis = opts.axis === 'y' ? 'y' : 'x';\n this.indicatorClass = opts.indicatorClass || 'twm-tab-drop-indicator';\n this.autoScroll = opts.autoScroll !== false;\n this.draggableGuard = opts.draggableGuard || null;\n this.onDragStart = opts.onDragStart || null;\n this.onReorder = opts.onReorder || null;\n\n this._draggingEl = null;\n this._indicatorEl = null;\n this._lastSnapshot = [];\n\n this._onOver = this._onOver.bind(this);\n this._onDrop = this._onDrop.bind(this);\n this._onLeave = this._onLeave.bind(this);\n if (this.container) {\n this.container.addEventListener('dragover', this._onOver);\n this.container.addEventListener('drop', this._onDrop);\n this.container.addEventListener('dragleave', this._onLeave);\n }\n }\n\n /** Mark current items draggable + wire dragstart/dragend. Idempotent \u2014\n * call after every (re)render; already-wired items are skipped. */\n attach() {\n if (!this.container) return;\n for (const item of this.container.querySelectorAll(this.itemSelector)) {\n if (item.__dragReorder) continue;\n item.__dragReorder = true;\n item.setAttribute('draggable', 'true');\n item.addEventListener('dragstart', (e) => this._start(e, item));\n item.addEventListener('dragend', () => this._end());\n }\n }\n\n /** True while this instance is mid-drag. */\n isActive() { return !!this._draggingEl; }\n\n destroy() {\n if (this.container) {\n this.container.removeEventListener('dragover', this._onOver);\n this.container.removeEventListener('drop', this._onDrop);\n this.container.removeEventListener('dragleave', this._onLeave);\n }\n this._removeIndicator();\n this._draggingEl = null;\n }\n\n // \u2500\u2500 internals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 _key(el) {\n if (!el) return null;\n return el.dataset?.[this.keyAttr]\n ?? el.getAttribute?.(`data-${this.keyAttr}`)\n ?? null;\n }\n\n _items() {\n return Array.from(this.container.querySelectorAll(this.itemSelector));\n }\n\n _snapshot() {\n return this._items().map((el) => this._key(el)).filter((k) => k != null);\n }\n\n _centerOf(rect) {\n return this.axis === 'y'\n ? rect.top + rect.height / 2\n : rect.left + rect.width / 2;\n }\n\n _start(e, item) {\n if (this.draggableGuard && !this.draggableGuard(e, item)) {\n e.preventDefault();\n return;\n }\n const key = this._key(item);\n this._draggingEl = item;\n this._lastSnapshot = this._snapshot();\n item.classList.add('dragging');\n try {\n e.dataTransfer.effectAllowed = 'move';\n if (key != null) e.dataTransfer.setData('text/plain', String(key));\n } catch { /* ignore */ }\n this.onDragStart?.(e, key, item);\n this._ensureIndicator();\n this._positionByNearest(this._centerOf(item.getBoundingClientRect()));\n }\n\n _end() {\n if (!this._draggingEl) return;\n this._draggingEl.classList.remove('dragging');\n this._draggingEl = null;\n this._removeIndicator();\n this._commitIfChanged();\n }\n\n _onOver(e) {\n if (!this._draggingEl) return; // not our drag \u2014 let the host handle it\n e.preventDefault();\n try { e.dataTransfer.dropEffect = 'move'; } catch { /* ignore */ }\n const coord = this.axis === 'y' ? e.clientY : e.clientX;\n this._positionByNearest(coord);\n if (this.autoScroll) this._autoScrollEdge(coord);\n }\n\n _onDrop(e) {\n if (!this._draggingEl) return;\n e.preventDefault();\n const indicator = this._ensureIndicator();\n if (indicator?.parentElement) {\n this.container.insertBefore(this._draggingEl, indicator);\n }\n this._finalize();\n }\n\n _onLeave(e) {\n if (!this._draggingEl) return;\n if (e.currentTarget !== this.container) return;\n if (this.container.contains(e.relatedTarget)) return;\n this._finalize();\n }\n\n _finalize() {\n if (this._draggingEl) this._draggingEl.classList.remove('dragging');\n this._removeIndicator();\n this._draggingEl = null;\n this._commitIfChanged();\n }\n\n _commitIfChanged() {\n const order = this._snapshot();\n if (!order.length) return;\n if (this._lastSnapshot.join('\u0000') === order.join('\u0000')) return;\n this._lastSnapshot = order;\n this.onReorder?.(order);\n }\n\n _ensureIndicator() {\n if (!this._indicatorEl) {\n this._indicatorEl = document.createElement('div');\n this._indicatorEl.className = this.indicatorClass;\n this._indicatorEl.setAttribute('aria-hidden', 'true');\n }\n if (!this._indicatorEl.parentElement) {\n this.container.appendChild(this._indicatorEl);\n }\n return this._indicatorEl;\n }\n\n _removeIndicator() { this._indicatorEl?.remove(); }\n\n _positionByNearest(coord) {\n if (!this.container || !this._indicatorEl || !this._draggingEl) return;\n const items = this._items().filter((t) => t !== this._draggingEl);\n if (!items.length) return;\n let best = null;\n let bestDist = Infinity;\n for (const it of items) {\n const center = this._centerOf(it.getBoundingClientRect());\n const dist = Math.abs(coord - center);\n if (dist < bestDist) { bestDist = dist; best = { it, center }; }\n }\n if (!best) return;\n const after = coord >= best.center;\n const ref = after ? best.it.nextElementSibling : best.it;\n this.container.insertBefore(this._indicatorEl, ref || null);\n }\n\n _autoScrollEdge(coord) {\n if (!this.container) return;\n const rect = this.container.getBoundingClientRect();\n const edge = 24;\n const step = 16;\n if (this.axis === 'y') {\n if (coord - rect.top < edge) {\n this.container.scrollTop = Math.max(0, this.container.scrollTop - step);\n } else if (rect.bottom - coord < edge) {\n this.container.scrollTop = Math.min(\n this.container.scrollHeight, this.container.scrollTop + step);\n }\n } else {\n if (coord - rect.left < edge) {\n this.container.scrollLeft = Math.max(0, this.container.scrollLeft - step);\n } else if (rect.right - coord < edge) {\n this.container.scrollLeft = Math.min(\n this.container.scrollWidth, this.container.scrollLeft + step);\n }\n }\n }\n}\n", "/**\n * menu_viewport.js \u2014 keeping a context menu inside the window (BUG-0040).\n *\n * FlexDesk draws three context menus of its own: `showContextMenu`\n * (../components/context_menu.js), the DataTable's right-click menu\n * (../components/data_table.js) and `NotebookTabBar`'s tab menu\n * (../../editor/notebook_tab_bar.js). Each placed itself with its own copy of\n * `top = min(y, innerHeight - height - 8)`, and none had a max-height. A menu\n * taller than the window then opened above its top edge (the DataTable's did\n * not clamp at all: a 101-item row menu opened at y=-2153 in a 761 px window)\n * or ran off its bottom, and nothing scrolled, so the items past the edge could\n * not be reached by any means.\n *\n * One placement now, for all three:\n * - the menu is at most the window's height less a margin above and below,\n * and scrolls inside when it is longer (`overflow-y: auto` in flexdesk.css);\n * - it opens at the pointer, moved left or up just enough to fit, and never\n * above the window's top or left edge;\n * - keyboard movement focuses an item and scrolls it into view within the\n * menu, so every item can be reached with the arrows.\n */\n\n/** The gap kept between a menu and the window's edges, in px. */\nexport const MENU_VIEWPORT_MARGIN = 8;\n\n/**\n * Size and place an open (displayed) menu at `(x, y)` inside its window.\n *\n * @param {HTMLElement} menu the menu, already in the document and displayed\n * @param {number} x client x of the pointer\n * @param {number} y client y of the pointer\n * @param {number} [margin] gap to the window's edges\n */\nexport function placeMenuInViewport(menu, x, y, margin = MENU_VIEWPORT_MARGIN) {\n const view = menu.ownerDocument?.defaultView || window;\n const vw = view.innerWidth;\n const vh = view.innerHeight;\n const maxHeight = Math.max(0, vh - 2 * margin);\n menu.style.maxHeight = `${maxHeight}px`;\n menu.scrollTop = 0;\n // flexdesk.css makes the menu `box-sizing: border-box`, so its measured\n // height (padding and border included) is at most `maxHeight`.\n const rect = menu.getBoundingClientRect();\n const left = Math.min(x, vw - rect.width - margin);\n const top = Math.min(y, vh - rect.height - margin);\n menu.style.left = `${Math.max(0, left)}px`;\n menu.style.top = `${Math.max(0, top)}px`;\n}\n\n/**\n * Focus a menu item and bring it into view inside the (scrolling) menu.\n * `preventScroll` keeps the page where it is; `block: 'nearest'` scrolls the\n * menu only as far as the item needs.\n */\nexport function focusMenuItem(item) {\n if (!item) return;\n item.focus({ preventScroll: true });\n item.scrollIntoView?.({ block: 'nearest', inline: 'nearest' });\n}\n\n/**\n * Up/Down/Home/End over `items` (the enabled ones), wrapping, from the one\n * that has focus. Returns true when the key moved focus (the caller's event\n * has then been `preventDefault`ed).\n *\n * @param {KeyboardEvent} e\n * @param {HTMLElement[]} items\n */\nexport function moveMenuFocus(e, items) {\n if (!items.length) return false;\n const at = items.indexOf(items[0].ownerDocument.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 false;\n e.preventDefault();\n focusMenuItem(next);\n return true;\n}\n"],
5
- "mappings": "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",
3
+ "sources": ["../src/ui/components/drag_reorder.js"],
4
+ "sourcesContent": ["/**\n * DragReorder \u2014 the one same-list drag-to-reorder implementation, with\n * the \"classic\" ghost (`.dragging` on the dragged element) + drop\n * placeholder (an indicator div inserted at the drop position) and\n * edge auto-scroll. Native HTML5 drag-and-drop.\n *\n * Extracted from the duplicated tab-bar reorder code so the notebook tab\n * bar, the workspace tab bar, and the schema column strip all share one\n * implementation. Axis-aware (`x` for horizontal strips, `y` for\n * vertical lists) and parameterised so it makes no assumptions about\n * tabs specifically.\n *\n * Usage:\n * const dr = new DragReorder({\n * container, itemSelector: '.tab', keyAttr: 'tabId', axis: 'x',\n * onReorder: (order) => { ... }, // order = array of keys\n * });\n * dr.attach(); // after each (re)render of the items\n * dr.destroy(); // on teardown\n *\n * Coexistence: the container-level handlers no-op unless THIS instance's\n * drag is active, so a host can keep its own dragover/drop handlers for\n * other concerns (e.g. cross-pane tab drops) alongside it \u2014 gate those\n * on `dr.isActive() === false`.\n */\nexport class DragReorder {\n /**\n * @param {Object} opts\n * @param {HTMLElement} opts.container\n * @param {string} [opts.itemSelector='.tab'] selector for reorderable items\n * @param {string} [opts.keyAttr='path'] dataset key / data-attr identifying an item\n * @param {'x'|'y'} [opts.axis='x']\n * @param {string} [opts.indicatorClass='tab-drop-indicator']\n * @param {boolean} [opts.autoScroll=true]\n * @param {(e: DragEvent, item: HTMLElement) => boolean} [opts.draggableGuard]\n * return false to cancel a drag start (e.g. from a close button)\n * @param {(e: DragEvent, key: string, item: HTMLElement) => void} [opts.onDragStart]\n * host hook to augment dataTransfer (e.g. add a cross-pane MIME)\n * @param {(order: string[]) => void} [opts.onReorder]\n */\n constructor(opts = {}) {\n this.container = opts.container || null;\n this.itemSelector = opts.itemSelector || '.tab';\n this.keyAttr = opts.keyAttr || 'path';\n this.axis = opts.axis === 'y' ? 'y' : 'x';\n this.indicatorClass = opts.indicatorClass || 'twm-tab-drop-indicator';\n this.autoScroll = opts.autoScroll !== false;\n this.draggableGuard = opts.draggableGuard || null;\n this.onDragStart = opts.onDragStart || null;\n this.onReorder = opts.onReorder || null;\n\n this._draggingEl = null;\n this._indicatorEl = null;\n this._lastSnapshot = [];\n\n this._onOver = this._onOver.bind(this);\n this._onDrop = this._onDrop.bind(this);\n this._onLeave = this._onLeave.bind(this);\n if (this.container) {\n this.container.addEventListener('dragover', this._onOver);\n this.container.addEventListener('drop', this._onDrop);\n this.container.addEventListener('dragleave', this._onLeave);\n }\n }\n\n /** Mark current items draggable + wire dragstart/dragend. Idempotent \u2014\n * call after every (re)render; already-wired items are skipped. */\n attach() {\n if (!this.container) return;\n for (const item of this.container.querySelectorAll(this.itemSelector)) {\n if (item.__dragReorder) continue;\n item.__dragReorder = true;\n item.setAttribute('draggable', 'true');\n item.addEventListener('dragstart', (e) => this._start(e, item));\n item.addEventListener('dragend', () => this._end());\n }\n }\n\n /** True while this instance is mid-drag. */\n isActive() { return !!this._draggingEl; }\n\n destroy() {\n if (this.container) {\n this.container.removeEventListener('dragover', this._onOver);\n this.container.removeEventListener('drop', this._onDrop);\n this.container.removeEventListener('dragleave', this._onLeave);\n }\n this._removeIndicator();\n this._draggingEl = null;\n }\n\n // \u2500\u2500 internals \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 _key(el) {\n if (!el) return null;\n return el.dataset?.[this.keyAttr]\n ?? el.getAttribute?.(`data-${this.keyAttr}`)\n ?? null;\n }\n\n _items() {\n return Array.from(this.container.querySelectorAll(this.itemSelector));\n }\n\n _snapshot() {\n return this._items().map((el) => this._key(el)).filter((k) => k != null);\n }\n\n _centerOf(rect) {\n return this.axis === 'y'\n ? rect.top + rect.height / 2\n : rect.left + rect.width / 2;\n }\n\n _start(e, item) {\n if (this.draggableGuard && !this.draggableGuard(e, item)) {\n e.preventDefault();\n return;\n }\n const key = this._key(item);\n this._draggingEl = item;\n this._lastSnapshot = this._snapshot();\n item.classList.add('dragging');\n try {\n e.dataTransfer.effectAllowed = 'move';\n if (key != null) e.dataTransfer.setData('text/plain', String(key));\n } catch { /* ignore */ }\n this.onDragStart?.(e, key, item);\n this._ensureIndicator();\n this._positionByNearest(this._centerOf(item.getBoundingClientRect()));\n }\n\n _end() {\n if (!this._draggingEl) return;\n this._draggingEl.classList.remove('dragging');\n this._draggingEl = null;\n this._removeIndicator();\n this._commitIfChanged();\n }\n\n _onOver(e) {\n if (!this._draggingEl) return; // not our drag \u2014 let the host handle it\n e.preventDefault();\n try { e.dataTransfer.dropEffect = 'move'; } catch { /* ignore */ }\n const coord = this.axis === 'y' ? e.clientY : e.clientX;\n this._positionByNearest(coord);\n if (this.autoScroll) this._autoScrollEdge(coord);\n }\n\n _onDrop(e) {\n if (!this._draggingEl) return;\n e.preventDefault();\n const indicator = this._ensureIndicator();\n if (indicator?.parentElement) {\n this.container.insertBefore(this._draggingEl, indicator);\n }\n this._finalize();\n }\n\n _onLeave(e) {\n if (!this._draggingEl) return;\n if (e.currentTarget !== this.container) return;\n if (this.container.contains(e.relatedTarget)) return;\n this._finalize();\n }\n\n _finalize() {\n if (this._draggingEl) this._draggingEl.classList.remove('dragging');\n this._removeIndicator();\n this._draggingEl = null;\n this._commitIfChanged();\n }\n\n _commitIfChanged() {\n const order = this._snapshot();\n if (!order.length) return;\n if (this._lastSnapshot.join('\u0000') === order.join('\u0000')) return;\n this._lastSnapshot = order;\n this.onReorder?.(order);\n }\n\n _ensureIndicator() {\n if (!this._indicatorEl) {\n this._indicatorEl = document.createElement('div');\n this._indicatorEl.className = this.indicatorClass;\n this._indicatorEl.setAttribute('aria-hidden', 'true');\n }\n if (!this._indicatorEl.parentElement) {\n this.container.appendChild(this._indicatorEl);\n }\n return this._indicatorEl;\n }\n\n _removeIndicator() { this._indicatorEl?.remove(); }\n\n _positionByNearest(coord) {\n if (!this.container || !this._indicatorEl || !this._draggingEl) return;\n const items = this._items().filter((t) => t !== this._draggingEl);\n if (!items.length) return;\n let best = null;\n let bestDist = Infinity;\n for (const it of items) {\n const center = this._centerOf(it.getBoundingClientRect());\n const dist = Math.abs(coord - center);\n if (dist < bestDist) { bestDist = dist; best = { it, center }; }\n }\n if (!best) return;\n const after = coord >= best.center;\n const ref = after ? best.it.nextElementSibling : best.it;\n this.container.insertBefore(this._indicatorEl, ref || null);\n }\n\n _autoScrollEdge(coord) {\n if (!this.container) return;\n const rect = this.container.getBoundingClientRect();\n const edge = 24;\n const step = 16;\n if (this.axis === 'y') {\n if (coord - rect.top < edge) {\n this.container.scrollTop = Math.max(0, this.container.scrollTop - step);\n } else if (rect.bottom - coord < edge) {\n this.container.scrollTop = Math.min(\n this.container.scrollHeight, this.container.scrollTop + step);\n }\n } else {\n if (coord - rect.left < edge) {\n this.container.scrollLeft = Math.max(0, this.container.scrollLeft - step);\n } else if (rect.right - coord < edge) {\n this.container.scrollLeft = Math.min(\n this.container.scrollWidth, this.container.scrollLeft + step);\n }\n }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }