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,610 @@
1
+ // src/ui/components/autocomplete_field.js
2
+ var AutocompleteField = class {
3
+ constructor({
4
+ fieldId,
5
+ field = {},
6
+ provider = null,
7
+ onChange = null,
8
+ logger = null,
9
+ namespace = null,
10
+ namespaceOptions = [],
11
+ showNamespaceSelect = false,
12
+ variant = null,
13
+ showNamespaceChip = false,
14
+ allowScopeToggle = false,
15
+ namespaceLabel = null,
16
+ scopeMode = "current",
17
+ skipNamespacePrefix = false,
18
+ // Material symbol per completion type, merged over the generic set. The
19
+ // framework's map used to include `sector: 'domain'` — an EcoAgent
20
+ // completion type — so the widget knew one application's ontology.
21
+ typeIcons = {}
22
+ } = {}) {
23
+ if (!fieldId) {
24
+ throw new Error("AutocompleteField requires a fieldId");
25
+ }
26
+ this.fieldId = fieldId;
27
+ this.field = field;
28
+ this.provider = typeof provider === "function" ? provider : () => [];
29
+ this.onChange = typeof onChange === "function" ? onChange : null;
30
+ this.logger = logger;
31
+ this.typeIcons = typeIcons ?? {};
32
+ this.namespace = namespace;
33
+ this.namespaceOptions = Array.isArray(namespaceOptions) ? [...namespaceOptions] : [];
34
+ if (this.namespace && !this.namespaceOptions.some((opt) => opt.value === this.namespace)) {
35
+ const fallbackLabel = this.field.namespaceLabel || "This Tab";
36
+ this.namespaceOptions.push({ value: this.namespace, label: fallbackLabel, token: fallbackLabel });
37
+ }
38
+ this.showNamespaceSelect = Boolean(showNamespaceSelect);
39
+ this.variant = variant;
40
+ this.showNamespaceChip = Boolean(showNamespaceChip);
41
+ this.allowScopeToggle = Boolean(allowScopeToggle);
42
+ this.namespaceLabel = namespaceLabel;
43
+ this.scope = scopeMode === "all" ? "all" : "current";
44
+ this.skipNamespacePrefix = Boolean(skipNamespacePrefix);
45
+ this.disabled = Boolean(field.disabled);
46
+ const parsed = this.#parseInitialNamespace(field.value ?? "");
47
+ this.selectedNamespace = parsed.initialNamespace;
48
+ this.initialFragment = parsed.initialFragment;
49
+ this._lastDropdownRect = null;
50
+ this.root = null;
51
+ this.input = null;
52
+ this.dropdown = null;
53
+ this.helperEl = null;
54
+ this.scopeControl = null;
55
+ this.namespaceSelect = null;
56
+ this.ghost = null;
57
+ this._items = [];
58
+ this._activeIndex = -1;
59
+ this._isOpen = false;
60
+ this._disposers = [];
61
+ this._suggestSeq = 0;
62
+ }
63
+ getValue() {
64
+ return this.#composeValue();
65
+ }
66
+ setComposedValue(value) {
67
+ if (!this.input) return;
68
+ const safeValue = typeof value === "string" ? value : "";
69
+ if (this.skipNamespacePrefix) {
70
+ this.input.value = safeValue;
71
+ this.initialFragment = safeValue;
72
+ this.#renderGhost();
73
+ this.#close();
74
+ return;
75
+ }
76
+ const parsed = this.#parseInitialNamespace(safeValue);
77
+ this.selectedNamespace = parsed.initialNamespace;
78
+ this.initialFragment = parsed.initialFragment;
79
+ if (this.namespaceSelect) {
80
+ this.namespaceSelect.value = this.selectedNamespace;
81
+ }
82
+ this.#updateNamespaceChip();
83
+ this.input.value = parsed.initialFragment;
84
+ this.#renderGhost();
85
+ this.#close();
86
+ }
87
+ #parseInitialNamespace(rawValue) {
88
+ const value = typeof rawValue === "string" ? rawValue.trim() : "";
89
+ const options = this.namespaceOptions;
90
+ const defaultNs = this.namespace ? options.find((opt) => opt.value === this.namespace)?.value ?? this.namespace : options[0]?.value ?? "__ALL__";
91
+ if (!options.length) {
92
+ return { initialNamespace: defaultNs, initialFragment: value };
93
+ }
94
+ if (!value) {
95
+ return { initialNamespace: defaultNs, initialFragment: "" };
96
+ }
97
+ const dotIndex = value.indexOf(".");
98
+ if (dotIndex > 0) {
99
+ const nsCandidate = value.slice(0, dotIndex);
100
+ const match = options.find(
101
+ (opt) => (opt.value || "").toLowerCase() === nsCandidate.toLowerCase() || (opt.label || "").toLowerCase() === nsCandidate.toLowerCase()
102
+ );
103
+ if (match) {
104
+ return { initialNamespace: match.value, initialFragment: value.slice(dotIndex + 1) };
105
+ }
106
+ }
107
+ return { initialNamespace: defaultNs, initialFragment: value };
108
+ }
109
+ #resolveNamespaceLabel() {
110
+ if (this.scope === "all") {
111
+ return "All Namespaces";
112
+ }
113
+ if (typeof this.namespaceLabel === "string" && this.namespaceLabel.trim()) {
114
+ return this.namespaceLabel.trim();
115
+ }
116
+ if (typeof this.field.namespaceLabel === "string" && this.field.namespaceLabel.trim()) {
117
+ return this.field.namespaceLabel.trim();
118
+ }
119
+ if (typeof this.namespace === "string" && this.namespace.trim()) {
120
+ return this.namespace.trim();
121
+ }
122
+ return "This Tab";
123
+ }
124
+ #toggleScope() {
125
+ if (this.disabled) return;
126
+ this.scope = this.scope === "all" ? "current" : "all";
127
+ this.root?.classList?.toggle("twm-autocomplete-field--scope-all", this.scope === "all");
128
+ this.#updateNamespaceChip();
129
+ this.#updateSuggestions();
130
+ }
131
+ #updateNamespaceChip() {
132
+ if (!this.scopeControl) return;
133
+ this.scopeControl.textContent = this.#resolveNamespaceLabel();
134
+ this.scopeControl.dataset.scope = this.scope;
135
+ this.scopeControl.title = this.scope === "all" ? "Searching across all namespaces (click to limit to this tab)" : "Searching this tab (click to search all namespaces)";
136
+ }
137
+ render() {
138
+ if (this.root) {
139
+ return this.root;
140
+ }
141
+ this.root = document.createElement("div");
142
+ this.root.className = "twm-autocomplete-field";
143
+ if (this.variant) {
144
+ this.root.classList.add(`twm-autocomplete-field--${this.variant}`);
145
+ }
146
+ this.root.classList.toggle("twm-autocomplete-field--scope-all", this.scope === "all");
147
+ const inputWrapper = document.createElement("div");
148
+ inputWrapper.className = "twm-autocomplete-field__input-wrapper";
149
+ if (this.showNamespaceSelect && this.namespaceOptions.length) {
150
+ const select = document.createElement("select");
151
+ select.className = "twm-autocomplete-field__namespace-select";
152
+ this.namespaceOptions.forEach((opt) => {
153
+ const option = document.createElement("option");
154
+ option.value = opt.value;
155
+ option.textContent = opt.label ?? opt.value;
156
+ if (opt.value === this.selectedNamespace) {
157
+ option.selected = true;
158
+ }
159
+ select.appendChild(option);
160
+ });
161
+ this.namespaceSelect = select;
162
+ inputWrapper.appendChild(select);
163
+ }
164
+ if (this.showNamespaceChip) {
165
+ const nsChip = document.createElement(this.allowScopeToggle ? "button" : "span");
166
+ nsChip.className = "twm-autocomplete-field__namespace";
167
+ if (this.allowScopeToggle) {
168
+ nsChip.setAttribute("type", "button");
169
+ }
170
+ if (this.allowScopeToggle) {
171
+ nsChip.classList.add("twm-autocomplete-field__namespace--toggle");
172
+ nsChip.addEventListener("click", () => this.#toggleScope());
173
+ }
174
+ this.scopeControl = nsChip;
175
+ this.#updateNamespaceChip();
176
+ inputWrapper.appendChild(nsChip);
177
+ }
178
+ this.input = document.createElement("input");
179
+ this.input.type = "text";
180
+ this.input.className = "twm-autocomplete-field__input";
181
+ this.input.id = this.fieldId;
182
+ this.input.autocomplete = "off";
183
+ this.input.spellcheck = false;
184
+ if (this.field.placeholder) {
185
+ this.input.placeholder = this.field.placeholder;
186
+ }
187
+ if (this.field.value != null) {
188
+ this.input.value = this.initialFragment;
189
+ }
190
+ if (this.disabled) {
191
+ this.input.disabled = true;
192
+ this.root.classList.add("twm-autocomplete-field--disabled");
193
+ }
194
+ inputWrapper.appendChild(this.input);
195
+ this.ghost = null;
196
+ this.dropdown = document.createElement("div");
197
+ this.dropdown.className = "twm-autocomplete-field__dropdown";
198
+ this.dropdown.setAttribute("role", "listbox");
199
+ document.body.appendChild(this.dropdown);
200
+ this.helperEl = document.createElement("div");
201
+ this.helperEl.className = "twm-autocomplete-field__helper twm-config-hint";
202
+ if (this.field.helperText) {
203
+ this.helperEl.textContent = this.field.helperText;
204
+ }
205
+ this.root.appendChild(inputWrapper);
206
+ this.root.appendChild(this.helperEl);
207
+ this.#wireEvents();
208
+ this.#renderGhost();
209
+ return this.root;
210
+ }
211
+ #wireEvents() {
212
+ const onInput = () => {
213
+ if (this.disabled) return;
214
+ this.#syncNamespaceFromInput();
215
+ this.#renderGhost();
216
+ this.#updateSuggestions();
217
+ };
218
+ const onChange = () => {
219
+ this.onChange?.(this.#composeValue(), { immediate: false, namespace: this.selectedNamespace });
220
+ };
221
+ const onPaste = () => {
222
+ };
223
+ const onKeyDown = (e) => {
224
+ if (this.disabled) return;
225
+ this.#handleKeyDown(e);
226
+ };
227
+ const onFocus = () => {
228
+ if (this.disabled) return;
229
+ this.#updateSuggestions();
230
+ };
231
+ const onBlur = (e) => {
232
+ setTimeout(() => {
233
+ if (!this.root?.contains(document.activeElement)) {
234
+ this.#close();
235
+ this.onChange?.(this.#composeValue(), { immediate: false, namespace: this.selectedNamespace });
236
+ }
237
+ }, 150);
238
+ };
239
+ const onDropdownMouseDown = (e) => {
240
+ e.preventDefault();
241
+ };
242
+ const onDropdownClick = (e) => {
243
+ const item = e.target.closest(".twm-autocomplete-field__item");
244
+ if (item) {
245
+ const index = parseInt(item.dataset.index, 10);
246
+ if (!isNaN(index)) {
247
+ this.#selectItem(index);
248
+ }
249
+ }
250
+ };
251
+ this.input.addEventListener("input", onInput);
252
+ this.input.addEventListener("change", onChange);
253
+ this.input.addEventListener("paste", onPaste);
254
+ this.input.addEventListener("keydown", onKeyDown);
255
+ this.input.addEventListener("focus", onFocus);
256
+ this.input.addEventListener("blur", onBlur);
257
+ this.dropdown.addEventListener("mousedown", onDropdownMouseDown);
258
+ this.dropdown.addEventListener("click", onDropdownClick);
259
+ if (this.namespaceSelect) {
260
+ const onSelectChange = () => {
261
+ this.selectedNamespace = this.namespaceSelect.value;
262
+ this.#updateSuggestions();
263
+ this.onChange?.(this.#composeValue(), {
264
+ immediate: false,
265
+ namespace: this.selectedNamespace,
266
+ viewNamespace: this.selectedNamespace
267
+ });
268
+ };
269
+ this.namespaceSelect.addEventListener("change", onSelectChange);
270
+ this._disposers.push(() => this.namespaceSelect.removeEventListener("change", onSelectChange));
271
+ }
272
+ const onWindowResize = () => {
273
+ if (this._isOpen) {
274
+ this.#positionDropdown();
275
+ }
276
+ };
277
+ window.addEventListener("resize", onWindowResize);
278
+ const onScroll = (e) => {
279
+ if (!this._isOpen) return;
280
+ if (this.dropdown?.contains(e.target)) return;
281
+ this.#close();
282
+ };
283
+ document.addEventListener("scroll", onScroll, true);
284
+ this._disposers.push(() => {
285
+ document.removeEventListener("scroll", onScroll, true);
286
+ });
287
+ const onDocumentClick = (e) => {
288
+ if (!this._isOpen) return;
289
+ const clickedInRoot = this.root?.contains(e.target);
290
+ const clickedInDropdown = this.dropdown?.contains(e.target);
291
+ if (!clickedInRoot && !clickedInDropdown) {
292
+ this.#close();
293
+ }
294
+ };
295
+ document.addEventListener("click", onDocumentClick, true);
296
+ this._disposers.push(() => {
297
+ window.removeEventListener("resize", onWindowResize);
298
+ });
299
+ this._disposers.push(() => {
300
+ document.removeEventListener("click", onDocumentClick, true);
301
+ });
302
+ this._disposers.push(() => {
303
+ this.input.removeEventListener("input", onInput);
304
+ this.input.removeEventListener("change", onChange);
305
+ this.input.removeEventListener("paste", onPaste);
306
+ this.input.removeEventListener("keydown", onKeyDown);
307
+ this.input.removeEventListener("focus", onFocus);
308
+ this.input.removeEventListener("blur", onBlur);
309
+ this.dropdown.removeEventListener("mousedown", onDropdownMouseDown);
310
+ this.dropdown.removeEventListener("click", onDropdownClick);
311
+ });
312
+ }
313
+ #handleKeyDown(e) {
314
+ if (!this._isOpen) {
315
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
316
+ this.#updateSuggestions();
317
+ e.preventDefault();
318
+ }
319
+ return;
320
+ }
321
+ switch (e.key) {
322
+ case "ArrowDown":
323
+ e.preventDefault();
324
+ this.#moveSelection(1);
325
+ break;
326
+ case "ArrowUp":
327
+ e.preventDefault();
328
+ this.#moveSelection(-1);
329
+ break;
330
+ case "Enter":
331
+ e.preventDefault();
332
+ if (this._activeIndex >= 0) {
333
+ this.#selectItem(this._activeIndex);
334
+ }
335
+ this.input?.blur();
336
+ break;
337
+ case "Tab":
338
+ if (this._activeIndex >= 0) {
339
+ e.preventDefault();
340
+ this.#selectItem(this._activeIndex);
341
+ }
342
+ break;
343
+ case "Escape":
344
+ e.preventDefault();
345
+ this.#close();
346
+ break;
347
+ }
348
+ }
349
+ #updateSuggestions() {
350
+ const fragment = this.#getInputFragment();
351
+ const request = ++this._suggestSeq;
352
+ let produced;
353
+ try {
354
+ produced = this.provider({
355
+ value: fragment,
356
+ scope: this.scope,
357
+ namespace: this.selectedNamespace
358
+ });
359
+ } catch (err) {
360
+ this.logger?.warn?.("autocomplete", "Provider error", { err });
361
+ this._items = [];
362
+ this.#close();
363
+ return;
364
+ }
365
+ if (produced && typeof produced.then === "function") {
366
+ produced.then(
367
+ (items) => {
368
+ if (request !== this._suggestSeq) return;
369
+ this.#applySuggestions(items);
370
+ },
371
+ (err) => {
372
+ this.logger?.warn?.("autocomplete", "Provider error", { err });
373
+ if (request !== this._suggestSeq) return;
374
+ this._items = [];
375
+ this.#close();
376
+ }
377
+ );
378
+ return;
379
+ }
380
+ this.#applySuggestions(produced);
381
+ }
382
+ /** Draw whatever the provider produced. Split out of `#updateSuggestions`
383
+ * so the synchronous and the awaited paths cannot drift apart. */
384
+ #applySuggestions(produced) {
385
+ const items = Array.isArray(produced) ? produced : [];
386
+ this._items = items;
387
+ this._activeIndex = items.length > 0 ? 0 : -1;
388
+ this.#renderDropdown();
389
+ if (items.length > 0) {
390
+ this.#open();
391
+ } else {
392
+ this.#close();
393
+ }
394
+ }
395
+ #renderDropdown() {
396
+ this.dropdown.innerHTML = "";
397
+ const showingAll = this.selectedNamespace === "__ALL__";
398
+ this._items.forEach((item, index) => {
399
+ const el = document.createElement("div");
400
+ el.className = "twm-autocomplete-field__item";
401
+ el.setAttribute("role", "option");
402
+ el.dataset.index = index;
403
+ el.dataset.type = item.type || item.iconType || "variable";
404
+ if (index === this._activeIndex) {
405
+ el.classList.add("active");
406
+ }
407
+ const icon = document.createElement("span");
408
+ icon.className = "twm-autocomplete-field__icon material-symbols-outlined";
409
+ icon.textContent = this.#getIconForType(item.type || item.iconType);
410
+ el.appendChild(icon);
411
+ const label = document.createElement("span");
412
+ label.className = "twm-autocomplete-field__label";
413
+ label.textContent = item.label || item.insertText || "";
414
+ el.appendChild(label);
415
+ if (showingAll && item.metadata?.namespaceId) {
416
+ const nsLabel = this.#resolveNamespaceToken(item.metadata.namespaceId);
417
+ if (nsLabel) {
418
+ const nsIndicator = document.createElement("span");
419
+ nsIndicator.className = "twm-autocomplete-field__namespace-indicator";
420
+ nsIndicator.textContent = nsLabel;
421
+ el.appendChild(nsIndicator);
422
+ }
423
+ }
424
+ if (item.type && !showingAll) {
425
+ const badge = document.createElement("span");
426
+ badge.className = "twm-autocomplete-field__badge";
427
+ badge.textContent = item.type;
428
+ el.appendChild(badge);
429
+ }
430
+ this.dropdown.appendChild(el);
431
+ });
432
+ if (this._isOpen) {
433
+ this.#positionDropdown();
434
+ }
435
+ }
436
+ #resolveNamespaceToken(namespaceId) {
437
+ if (!namespaceId) return null;
438
+ const opt = this.namespaceOptions.find((o) => o.value === namespaceId);
439
+ return opt?.token || opt?.label || null;
440
+ }
441
+ #getIconForType(type) {
442
+ const icons = {
443
+ variable: "functions",
444
+ "variable-qualified": "link",
445
+ stock: "account_balance",
446
+ account: "savings",
447
+ function: "code",
448
+ constant: "numbers",
449
+ operator: "calculate",
450
+ snippet: "content_paste",
451
+ ...this.typeIcons
452
+ };
453
+ return icons[type] || "label";
454
+ }
455
+ #moveSelection(delta) {
456
+ if (this._items.length === 0) return;
457
+ let newIndex = this._activeIndex + delta;
458
+ if (newIndex < 0) newIndex = this._items.length - 1;
459
+ if (newIndex >= this._items.length) newIndex = 0;
460
+ this._activeIndex = newIndex;
461
+ this.#renderDropdown();
462
+ this.#scrollToActive();
463
+ }
464
+ #scrollToActive() {
465
+ const activeEl = this.dropdown.querySelector(".twm-autocomplete-field__item.active");
466
+ if (activeEl) {
467
+ activeEl.scrollIntoView({ block: "nearest", behavior: "smooth" });
468
+ }
469
+ }
470
+ #selectItem(index) {
471
+ const item = this._items[index];
472
+ if (!item) return;
473
+ const itemNamespace = item.metadata?.namespaceId || null;
474
+ const insertText = item.insertText || item.label || "";
475
+ this.input.value = insertText;
476
+ const viewNamespace = this.selectedNamespace;
477
+ const resolvedNamespace = viewNamespace === "__ALL__" && itemNamespace ? itemNamespace : viewNamespace;
478
+ this.#close();
479
+ this.input.focus();
480
+ this.onChange?.(this.#composeValue(), {
481
+ immediate: true,
482
+ namespace: resolvedNamespace,
483
+ viewNamespace,
484
+ metadata: item.metadata || null
485
+ });
486
+ }
487
+ #open() {
488
+ if (this._isOpen) {
489
+ return;
490
+ }
491
+ this._isOpen = true;
492
+ this.#positionDropdown();
493
+ this.dropdown.classList.add("visible");
494
+ }
495
+ #close() {
496
+ if (!this._isOpen) return;
497
+ this._isOpen = false;
498
+ this.dropdown.classList.remove("visible");
499
+ this._activeIndex = -1;
500
+ }
501
+ #syncNamespaceFromInput() {
502
+ if (!this.namespaceOptions.length) return;
503
+ const value = this.input?.value || "";
504
+ const dotIndex = value.indexOf(".");
505
+ if (dotIndex > 0) {
506
+ const nsCandidate = value.slice(0, dotIndex);
507
+ const match = this.namespaceOptions.find(
508
+ (opt) => opt.value !== "__ALL__" && ((opt.value || "").toLowerCase() === nsCandidate.toLowerCase() || (opt.label || "").toLowerCase() === nsCandidate.toLowerCase() || (opt.token || "").toLowerCase() === nsCandidate.toLowerCase())
509
+ );
510
+ if (match && this.namespaceSelect && this.namespaceSelect.value !== match.value) {
511
+ this.namespaceSelect.value = match.value;
512
+ this.selectedNamespace = match.value;
513
+ }
514
+ }
515
+ }
516
+ #getInputFragment() {
517
+ const value = this.input?.value || "";
518
+ const dotIndex = value.indexOf(".");
519
+ if (dotIndex > 0) {
520
+ const nsCandidate = value.slice(0, dotIndex);
521
+ const match = this.namespaceOptions.find(
522
+ (opt) => opt.value !== "__ALL__" && ((opt.value || "").toLowerCase() === nsCandidate.toLowerCase() || (opt.label || "").toLowerCase() === nsCandidate.toLowerCase())
523
+ );
524
+ if (match) {
525
+ return value.slice(dotIndex + 1);
526
+ }
527
+ }
528
+ return value;
529
+ }
530
+ #composeValue() {
531
+ const rawInput = this.input?.value || "";
532
+ if (!rawInput) return "";
533
+ if (this.skipNamespacePrefix) {
534
+ return rawInput;
535
+ }
536
+ const dotIndex = rawInput.indexOf(".");
537
+ if (dotIndex > 0) {
538
+ const nsCandidate = rawInput.slice(0, dotIndex);
539
+ const match = this.namespaceOptions.find(
540
+ (opt) => opt.value !== "__ALL__" && ((opt.value || "").toLowerCase() === nsCandidate.toLowerCase() || (opt.label || "").toLowerCase() === nsCandidate.toLowerCase())
541
+ );
542
+ if (match) {
543
+ return rawInput;
544
+ }
545
+ }
546
+ const ns = this.selectedNamespace;
547
+ if (!ns || ns === "__ALL__") {
548
+ return rawInput;
549
+ }
550
+ const nsOption = this.namespaceOptions.find(
551
+ (opt) => opt.value === ns || (opt.value || "").toLowerCase() === (ns || "").toLowerCase()
552
+ );
553
+ const nsToken = nsOption?.token || nsOption?.label || "";
554
+ 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;
555
+ if (ns === "__ALL__" || (nsToken || "").toUpperCase() === "__ALL__") {
556
+ return rawInput;
557
+ }
558
+ if (!nsToken || uuidPattern.test(nsToken)) {
559
+ return rawInput;
560
+ }
561
+ return `${nsToken}.${rawInput}`;
562
+ }
563
+ #renderGhost() {
564
+ if (this.ghost) {
565
+ this.ghost.style.display = "none";
566
+ }
567
+ }
568
+ #positionDropdown() {
569
+ if (!this.dropdown || !this.root) return;
570
+ const wrapper = this.root.querySelector(".twm-autocomplete-field__input-wrapper");
571
+ if (!wrapper) return;
572
+ const rect = wrapper.getBoundingClientRect();
573
+ this._lastDropdownRect = rect;
574
+ const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
575
+ const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
576
+ const width = Math.min(rect.width, viewportWidth - rect.left - 8);
577
+ const maxHeight = Math.max(120, viewportHeight - rect.bottom - 12);
578
+ Object.assign(this.dropdown.style, {
579
+ position: "fixed",
580
+ top: `${rect.bottom}px`,
581
+ left: `${rect.left}px`,
582
+ width: `${width}px`,
583
+ maxWidth: `${width}px`,
584
+ maxHeight: `${maxHeight}px`
585
+ });
586
+ }
587
+ dispose() {
588
+ this._suggestSeq += 1;
589
+ this.#close();
590
+ this._disposers.forEach((fn) => {
591
+ try {
592
+ fn();
593
+ } catch (e) {
594
+ }
595
+ });
596
+ this._disposers = [];
597
+ if (this.dropdown && this.dropdown.parentNode) {
598
+ this.dropdown.parentNode.removeChild(this.dropdown);
599
+ }
600
+ this.root = null;
601
+ this.input = null;
602
+ this.dropdown = null;
603
+ this.helperEl = null;
604
+ }
605
+ };
606
+
607
+ export {
608
+ AutocompleteField
609
+ };
610
+ //# sourceMappingURL=chunk-QWQJUDPD.js.map