@qodalis/vue-cli 2.0.0-beta.9 → 2.0.0-rc.2

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.
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ __export(index_exports, {
23
23
  Cli: () => Cli,
24
24
  CliConfigKey: () => CliConfigKey,
25
25
  CliConfigProvider: () => CliConfigProvider,
26
- CliEngine: () => import_cli3.CliEngine,
26
+ CliEngine: () => import_cli4.CliEngine,
27
27
  CliInjectionKey: () => CliInjectionKey,
28
28
  CliPanel: () => CliPanel,
29
29
  CliProvider: () => CliProvider,
@@ -49,10 +49,6 @@ var CliConfigProvider = (0, import_vue.defineComponent)({
49
49
  type: Array,
50
50
  default: void 0
51
51
  },
52
- processors: {
53
- type: Array,
54
- default: void 0
55
- },
56
52
  options: {
57
53
  type: Object,
58
54
  default: void 0
@@ -65,7 +61,6 @@ var CliConfigProvider = (0, import_vue.defineComponent)({
65
61
  setup(props, { slots }) {
66
62
  (0, import_vue.provide)(CliConfigKey, {
67
63
  modules: props.modules,
68
- processors: props.processors,
69
64
  options: props.options,
70
65
  services: props.services
71
66
  });
@@ -81,10 +76,6 @@ var Cli = (0, import_vue2.defineComponent)({
81
76
  type: Array,
82
77
  default: void 0
83
78
  },
84
- processors: {
85
- type: Array,
86
- default: void 0
87
- },
88
79
  options: {
89
80
  type: Object,
90
81
  default: void 0
@@ -115,26 +106,10 @@ var Cli = (0, import_vue2.defineComponent)({
115
106
  if (ctx) {
116
107
  return () => null;
117
108
  }
118
- const modules = props.modules ?? config?.modules;
119
- const processors = props.processors ?? config?.processors;
120
- const options = props.options ?? config?.options;
121
- const services = props.services ?? config?.services;
109
+ const hostConfig = (0, import_cli.resolveCliHostConfig)(props, config);
122
110
  (0, import_vue2.onMounted)(async () => {
123
111
  if (!containerRef.value) return;
124
- const engineOptions = props.snapshot ? { ...options, snapshot: props.snapshot } : options;
125
- engine = new import_cli.CliEngine(containerRef.value, engineOptions);
126
- engine.registerService("cli-framework", "Vue");
127
- if (services) {
128
- for (const [token, value] of Object.entries(services)) {
129
- engine.registerService(token, value);
130
- }
131
- }
132
- if (modules) {
133
- engine.registerModules(modules);
134
- }
135
- if (processors) {
136
- engine.registerProcessors(processors);
137
- }
112
+ engine = (0, import_cli.createCliEngine)(containerRef.value, { ...hostConfig, snapshot: props.snapshot, framework: "Vue" });
138
113
  await engine.start();
139
114
  emit("ready", engine);
140
115
  });
@@ -152,878 +127,421 @@ var Cli = (0, import_vue2.defineComponent)({
152
127
 
153
128
  // src/CliPanel.ts
154
129
  var import_vue3 = require("vue");
155
- var import_cli_core = require("@qodalis/cli-core");
156
- var MIN_PANE_WIDTH_PERCENT = 10;
157
- function normalizePanes(panes) {
158
- const total = panes.reduce((s, p) => s + p.widthPercent, 0);
159
- if (total === 0) return;
160
- const scale = 100 / total;
161
- panes.forEach((p) => {
162
- p.widthPercent *= scale;
163
- });
164
- }
165
- var svgAttrs = {
166
- width: "20",
167
- height: "20",
168
- viewBox: "0 0 24 24",
169
- fill: "none",
170
- stroke: "currentColor",
171
- "stroke-width": "1.8",
172
- "stroke-linecap": "round",
173
- "stroke-linejoin": "round"
174
- };
175
- var terminalIcon = () => (0, import_vue3.h)("svg", { ...svgAttrs, width: "22", height: "22", "stroke-width": "2" }, [
176
- (0, import_vue3.h)("polyline", { points: "4 17 10 11 4 5" }),
177
- (0, import_vue3.h)("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
178
- ]);
179
- var maximizeIcon = () => (0, import_vue3.h)("svg", svgAttrs, [
180
- (0, import_vue3.h)("polyline", { points: "15 3 21 3 21 9" }),
181
- (0, import_vue3.h)("polyline", { points: "9 21 3 21 3 15" }),
182
- (0, import_vue3.h)("line", { x1: "21", y1: "3", x2: "14", y2: "10" }),
183
- (0, import_vue3.h)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
184
- ]);
185
- var restoreIcon = () => (0, import_vue3.h)("svg", svgAttrs, [
186
- (0, import_vue3.h)("polyline", { points: "4 14 10 14 10 20" }),
187
- (0, import_vue3.h)("polyline", { points: "20 10 14 10 14 4" }),
188
- (0, import_vue3.h)("line", { x1: "14", y1: "10", x2: "21", y2: "3" }),
189
- (0, import_vue3.h)("line", { x1: "3", y1: "21", x2: "10", y2: "14" })
190
- ]);
191
- var closeIcon = () => (0, import_vue3.h)("svg", svgAttrs, [
192
- (0, import_vue3.h)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
193
- (0, import_vue3.h)("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
194
- ]);
195
- var hideIcon = () => (0, import_vue3.h)("svg", svgAttrs, [
196
- (0, import_vue3.h)("line", { x1: "5", y1: "18", x2: "19", y2: "18" }),
197
- (0, import_vue3.h)("polyline", { points: "9 14 12 17 15 14" })
198
- ]);
199
- function collapseChevron(position, isCollapsed) {
200
- let points;
201
- switch (position) {
202
- case "top":
203
- points = isCollapsed ? "6 9 12 15 18 9" : "18 15 12 9 6 15";
204
- break;
205
- case "left":
206
- points = isCollapsed ? "9 18 15 12 9 6" : "15 6 9 12 15 18";
207
- break;
208
- case "right":
209
- points = isCollapsed ? "15 6 9 12 15 18" : "9 18 15 12 9 6";
210
- break;
211
- default:
212
- points = isCollapsed ? "18 15 12 9 6 15" : "6 9 12 15 18 9";
213
- break;
214
- }
215
- return (0, import_vue3.h)("svg", svgAttrs, [(0, import_vue3.h)("polyline", { points })]);
216
- }
217
- function hideTabChevron(position) {
218
- let points;
219
- switch (position) {
220
- case "top":
221
- points = "6 9 12 15 18 9";
222
- break;
223
- case "left":
224
- points = "9 18 15 12 9 6";
225
- break;
226
- case "right":
227
- points = "15 6 9 12 15 18";
228
- break;
229
- default:
230
- points = "18 15 12 9 6 15";
231
- break;
232
- }
233
- return (0, import_vue3.h)("svg", { class: "cli-panel-hide-tab-arrow", ...svgAttrs, width: "14", height: "14", "stroke-width": "2.5" }, [
234
- (0, import_vue3.h)("polyline", { points })
235
- ]);
236
- }
237
- function positionIcon(pos, size = 20) {
238
- let fillRect;
239
- switch (pos) {
240
- case "top":
241
- fillRect = (0, import_vue3.h)("rect", { x: "4", y: "4", width: "16", height: "5", rx: "1", fill: "currentColor", stroke: "none", opacity: "0.5" });
242
- break;
243
- case "left":
244
- fillRect = (0, import_vue3.h)("rect", { x: "4", y: "4", width: "5", height: "16", rx: "1", fill: "currentColor", stroke: "none", opacity: "0.5" });
245
- break;
246
- case "right":
247
- fillRect = (0, import_vue3.h)("rect", { x: "15", y: "4", width: "5", height: "16", rx: "1", fill: "currentColor", stroke: "none", opacity: "0.5" });
248
- break;
249
- default:
250
- fillRect = (0, import_vue3.h)("rect", { x: "4", y: "15", width: "16", height: "5", rx: "1", fill: "currentColor", stroke: "none", opacity: "0.5" });
251
- break;
252
- }
253
- return (0, import_vue3.h)("svg", { ...svgAttrs, width: String(size), height: String(size) }, [
254
- (0, import_vue3.h)("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
255
- fillRect
256
- ]);
130
+ var import_cli2 = require("@qodalis/cli");
131
+ var PANEL_REF_METHODS = [
132
+ "open",
133
+ "collapse",
134
+ "toggleCollapse",
135
+ "hide",
136
+ "unhide",
137
+ "toggleHide",
138
+ "close",
139
+ "maximize",
140
+ "restore",
141
+ "toggleMaximize",
142
+ "resize",
143
+ "setPosition",
144
+ "addTab",
145
+ "closeTab",
146
+ "selectTab",
147
+ "renameTab",
148
+ "splitPane",
149
+ "closePane",
150
+ "getEngine",
151
+ "getState"
152
+ ];
153
+ function icon(svg, className) {
154
+ return (0, import_vue3.h)("svg", { class: className, ...(0, import_cli2.svgAttrs)(svg) }, svg.shapes.map((shape) => (0, import_vue3.h)(shape.tag, shape.attrs)));
257
155
  }
156
+ var stop = (e) => e.stopPropagation();
258
157
  var CliPanel = (0, import_vue3.defineComponent)({
259
158
  name: "CliPanel",
260
159
  props: {
261
- options: {
262
- type: Object,
263
- default: void 0
264
- },
160
+ options: { type: Object, default: void 0 },
265
161
  modules: { type: Array, default: void 0 },
266
- processors: {
267
- type: Array,
268
- default: void 0
269
- },
270
- services: {
271
- type: Object,
272
- default: void 0
273
- },
274
- onClose: {
275
- type: Function,
276
- default: void 0
277
- },
278
- style: {
279
- type: Object,
280
- default: void 0
281
- },
162
+ services: { type: Object, default: void 0 },
163
+ onClose: { type: Function, default: void 0 },
164
+ collapsed: { type: Boolean, default: void 0 },
165
+ hidden: { type: Boolean, default: void 0 },
166
+ maximized: { type: Boolean, default: void 0 },
167
+ activeTabId: { type: Number, default: void 0 },
168
+ position: { type: String, default: void 0 },
169
+ height: { type: Number, default: void 0 },
170
+ width: { type: Number, default: void 0 },
171
+ style: { type: Object, default: void 0 },
282
172
  class: { type: String, default: void 0 }
283
173
  },
284
- setup(props) {
174
+ emits: [
175
+ "update:collapsed",
176
+ "update:hidden",
177
+ "update:maximized",
178
+ "update:activeTabId",
179
+ "update:position",
180
+ "update:height",
181
+ "update:width",
182
+ "close",
183
+ "tab-added",
184
+ "tab-closed",
185
+ "pane-split",
186
+ "pane-closed"
187
+ ],
188
+ setup(props, { expose, emit }) {
285
189
  const config = (0, import_vue3.inject)(CliConfigKey, null);
286
- const mergedOptions = (0, import_vue3.computed)(() => props.options ?? config?.options);
287
- const mergedModules = (0, import_vue3.computed)(() => props.modules ?? config?.modules);
288
- const mergedProcessors = (0, import_vue3.computed)(() => props.processors ?? config?.processors);
289
- const mergedServices = (0, import_vue3.computed)(() => props.services ?? config?.services);
290
- const visible = (0, import_vue3.ref)(true);
291
- const collapsed = (0, import_vue3.ref)(mergedOptions.value?.isCollapsed ?? true);
292
- const maximized = (0, import_vue3.ref)(false);
293
- const panelHeight = (0, import_vue3.ref)(600);
294
- const panelWidth = (0, import_vue3.ref)(400);
295
- const prevHeight = (0, import_vue3.ref)(600);
296
- const prevWidth = (0, import_vue3.ref)(400);
297
- const initialized = (0, import_vue3.ref)(false);
298
- const hidden = (0, import_vue3.ref)(props.options?.isHidden ?? false);
299
- let preHideCollapsed = true;
300
- const position = (0, import_vue3.ref)((0, import_cli_core.loadPanelPosition)() ?? mergedOptions.value?.position ?? "bottom");
301
- const closable = (0, import_vue3.computed)(() => mergedOptions.value?.closable ?? true);
302
- const resizable = (0, import_vue3.computed)(() => mergedOptions.value?.resizable ?? true);
303
- const isHorizontal = (0, import_vue3.computed)(() => position.value === "left" || position.value === "right");
304
- const hideable = (0, import_vue3.computed)(() => mergedOptions.value?.hideable ?? true);
305
- const hideAlignment = (0, import_vue3.computed)(() => mergedOptions.value?.hideAlignment ?? "center");
306
- const syncTheme = (0, import_vue3.computed)(() => mergedOptions.value?.syncTheme ?? false);
307
- const themeStyles = (0, import_vue3.ref)({});
308
- const tabs = (0, import_vue3.ref)([]);
309
- const activeTabId = (0, import_vue3.ref)(0);
310
- const activePaneId = (0, import_vue3.ref)(0);
311
- let nextTabId = 1;
312
- let nextPaneId = 1;
313
- const contextMenu = (0, import_vue3.ref)({
314
- visible: false,
315
- x: 0,
316
- y: 0,
317
- tabId: 0
190
+ const mergedOptions = (0, import_vue3.computed)(() => (0, import_cli2.mergeCliOptions)(props.options, config?.options));
191
+ const hostConfig = (0, import_vue3.computed)(() => (0, import_cli2.resolveCliHostConfig)(props, config));
192
+ const controlled = () => ({
193
+ collapsed: props.collapsed,
194
+ hidden: props.hidden,
195
+ maximized: props.maximized,
196
+ activeTabId: props.activeTabId,
197
+ position: props.position,
198
+ height: props.height,
199
+ width: props.width
318
200
  });
319
- const engineMap = /* @__PURE__ */ new Map();
320
- const paneResizing = (0, import_vue3.ref)(false);
321
- let paneResizeState = {
322
- tabId: 0,
323
- dividerIndex: 0,
324
- startX: 0,
325
- startWidths: [],
326
- containerWidth: 0
327
- };
328
- const panelResizing = (0, import_vue3.ref)(false);
329
- let panelResizeState = { startY: 0, startHeight: 0, startX: 0, startWidth: 0 };
330
- function addTab() {
331
- const paneId = nextPaneId++;
332
- const tabId = nextTabId++;
333
- const pane = { id: paneId, widthPercent: 100 };
334
- const tab = {
335
- id: tabId,
336
- title: `Terminal ${tabId}`,
337
- isEditing: false,
338
- panes: [pane]
339
- };
340
- tabs.value.push(tab);
341
- activeTabId.value = tabId;
342
- activePaneId.value = paneId;
343
- }
344
- let themeObserver;
345
- function syncThemeFromEngine() {
346
- const engine = engineMap.values().next().value;
347
- if (!engine) return;
348
- const theme = engine.getTerminal().options.theme;
349
- if (theme) themeStyles.value = (0, import_cli_core.derivePanelThemeStyles)(theme);
350
- }
351
- function setupThemeSync() {
352
- if (!syncTheme.value) return;
353
- setTimeout(() => {
354
- syncThemeFromEngine();
355
- const container = document.querySelector(".cli-panel-wrapper .terminal-container");
356
- if (!container) return;
357
- themeObserver?.disconnect();
358
- themeObserver = new MutationObserver(syncThemeFromEngine);
359
- themeObserver.observe(container, { attributes: true, attributeFilter: ["style"] });
360
- }, 200);
361
- }
362
- (0, import_vue3.onMounted)(() => {
363
- document.addEventListener("click", closePositionDropdown);
364
- });
365
- (0, import_vue3.onBeforeUnmount)(() => {
366
- themeObserver?.disconnect();
367
- document.removeEventListener("click", closePositionDropdown);
368
- });
369
- function toggle() {
370
- collapsed.value = !collapsed.value;
371
- if (!collapsed.value && !initialized.value) {
372
- initialized.value = true;
373
- addTab();
374
- setupThemeSync();
375
- }
376
- }
377
- function closeTab(id) {
378
- const idx = tabs.value.findIndex((t) => t.id === id);
379
- if (idx === -1) return;
380
- tabs.value.splice(idx, 1);
381
- if (tabs.value.length === 0) {
382
- initialized.value = false;
383
- collapsed.value = true;
384
- return;
385
- }
386
- if (activeTabId.value === id) {
387
- const newIdx = Math.min(idx, tabs.value.length - 1);
388
- selectTab(tabs.value[newIdx].id);
389
- }
390
- }
391
- function selectTab(id) {
392
- activeTabId.value = id;
393
- const tab = tabs.value.find((t) => t.id === id);
394
- if (tab && tab.panes.length > 0) {
395
- activePaneId.value = tab.panes[0].id;
396
- }
397
- }
398
- function splitRight(tabId) {
399
- const tab = tabs.value.find(
400
- (t) => t.id === (tabId ?? activeTabId.value)
401
- );
402
- if (!tab) return;
403
- const idx = tab.panes.findIndex((p) => p.id === activePaneId.value);
404
- const insertIdx = idx === -1 ? tab.panes.length : idx + 1;
405
- const newPaneId = nextPaneId++;
406
- tab.panes.splice(insertIdx, 0, { id: newPaneId, widthPercent: 0 });
407
- const evenWidth = 100 / tab.panes.length;
408
- tab.panes.forEach((p) => {
409
- p.widthPercent = evenWidth;
410
- });
411
- normalizePanes(tab.panes);
412
- activePaneId.value = newPaneId;
413
- }
414
- function closePane(tabId, paneId) {
415
- const tab = tabs.value.find((t) => t.id === tabId);
416
- if (!tab) return;
417
- if (tab.panes.length <= 1) {
418
- closeTab(tabId);
419
- return;
420
- }
421
- const idx = tab.panes.findIndex((p) => p.id === paneId);
422
- if (idx === -1) return;
423
- tab.panes.splice(idx, 1);
424
- const total = tab.panes.reduce((s, p) => s + p.widthPercent, 0);
425
- if (total > 0)
426
- tab.panes.forEach((p) => {
427
- p.widthPercent = p.widthPercent / total * 100;
428
- });
429
- normalizePanes(tab.panes);
430
- if (activePaneId.value === paneId) {
431
- activePaneId.value = tab.panes[Math.min(idx, tab.panes.length - 1)].id;
432
- }
433
- }
434
- function startRename(tabId) {
435
- tabs.value.forEach((t) => {
436
- t.isEditing = t.id === tabId;
437
- });
438
- }
439
- function commitRename(tabId, value) {
440
- const trimmed = value.trim();
441
- const tab = tabs.value.find((t) => t.id === tabId);
442
- if (tab) {
443
- if (trimmed) tab.title = trimmed;
444
- tab.isEditing = false;
445
- }
446
- }
447
- function closeContextMenu() {
448
- contextMenu.value = { ...contextMenu.value, visible: false };
449
- }
450
- function onDocClick() {
451
- if (contextMenu.value.visible) closeContextMenu();
452
- }
453
- (0, import_vue3.onMounted)(() => document.addEventListener("click", onDocClick));
454
- (0, import_vue3.onBeforeUnmount)(
455
- () => document.removeEventListener("click", onDocClick)
456
- );
457
- function onPanelResizeStart(e) {
458
- if (!resizable.value) return;
459
- e.preventDefault();
460
- if (collapsed.value) toggle();
461
- panelResizing.value = true;
462
- panelResizeState = {
463
- startY: e.clientY,
464
- startHeight: panelHeight.value,
465
- startX: e.clientX,
466
- startWidth: panelWidth.value
467
- };
468
- }
469
- function onPanelResizeMove(e) {
470
- if (!panelResizing.value) return;
471
- if (isHorizontal.value) {
472
- const deltaX = position.value === "left" ? e.clientX - panelResizeState.startX : panelResizeState.startX - e.clientX;
473
- let next = Math.max(100, panelResizeState.startWidth + deltaX);
474
- if (next > window.innerWidth) next = window.innerWidth;
475
- panelWidth.value = next;
476
- } else {
477
- const deltaY = position.value === "top" ? e.clientY - panelResizeState.startY : panelResizeState.startY - e.clientY;
478
- let next = Math.max(100, panelResizeState.startHeight + deltaY);
479
- if (next > window.innerHeight) next = window.innerHeight;
480
- panelHeight.value = next;
201
+ const controller = new import_cli2.CliPanelController({
202
+ config: mergedOptions.value,
203
+ controlled: controlled(),
204
+ callbacks: {
205
+ onCollapsedChange: (v) => emit("update:collapsed", v),
206
+ onHiddenChange: (v) => emit("update:hidden", v),
207
+ onMaximizedChange: (v) => emit("update:maximized", v),
208
+ onActiveTabIdChange: (v) => emit("update:activeTabId", v),
209
+ onPositionChange: (v) => emit("update:position", v),
210
+ onHeightChange: (v) => emit("update:height", v),
211
+ onWidthChange: (v) => emit("update:width", v),
212
+ onClose: () => {
213
+ emit("close");
214
+ props.onClose?.();
215
+ },
216
+ onTabAdded: (e) => emit("tab-added", e),
217
+ onTabClosed: (e) => emit("tab-closed", e),
218
+ onPaneSplit: (e) => emit("pane-split", e),
219
+ onPaneClosed: (e) => emit("pane-closed", e)
481
220
  }
482
- }
483
- function onPanelResizeEnd() {
484
- panelResizing.value = false;
485
- }
486
- (0, import_vue3.onMounted)(() => {
487
- document.addEventListener("mousemove", onPanelResizeMove);
488
- document.addEventListener("mouseup", onPanelResizeEnd);
489
221
  });
490
- (0, import_vue3.onBeforeUnmount)(() => {
491
- document.removeEventListener("mousemove", onPanelResizeMove);
492
- document.removeEventListener("mouseup", onPanelResizeEnd);
493
- });
494
- function onPaneResizeStart(e, tabId, dividerIndex) {
495
- e.preventDefault();
496
- const tab = tabs.value.find((t) => t.id === tabId);
497
- if (!tab) return;
498
- paneResizing.value = true;
499
- const container = e.target.closest(
500
- ".cli-panel-panes-container"
501
- );
502
- paneResizeState = {
503
- tabId,
504
- dividerIndex,
505
- startX: e.clientX,
506
- startWidths: tab.panes.map((p) => p.widthPercent),
507
- containerWidth: container ? container.clientWidth : 1
508
- };
509
- document.body.classList.add("cli-pane-resizing");
510
- }
511
- function onPaneResizeMove(e) {
512
- if (!paneResizing.value) return;
513
- const s = paneResizeState;
514
- const deltaPct = (e.clientX - s.startX) / s.containerWidth * 100;
515
- const i = s.dividerIndex;
516
- let leftW = s.startWidths[i] + deltaPct;
517
- let rightW = s.startWidths[i + 1] - deltaPct;
518
- if (leftW < MIN_PANE_WIDTH_PERCENT) {
519
- leftW = MIN_PANE_WIDTH_PERCENT;
520
- rightW = s.startWidths[i] + s.startWidths[i + 1] - MIN_PANE_WIDTH_PERCENT;
521
- }
522
- if (rightW < MIN_PANE_WIDTH_PERCENT) {
523
- rightW = MIN_PANE_WIDTH_PERCENT;
524
- leftW = s.startWidths[i] + s.startWidths[i + 1] - MIN_PANE_WIDTH_PERCENT;
525
- }
526
- const tab = tabs.value.find((t) => t.id === s.tabId);
527
- if (tab) {
528
- tab.panes[i].widthPercent = leftW;
529
- tab.panes[i + 1].widthPercent = rightW;
530
- }
531
- }
532
- function onPaneResizeEnd() {
533
- if (!paneResizing.value) return;
534
- paneResizing.value = false;
535
- document.body.classList.remove("cli-pane-resizing");
536
- }
537
- (0, import_vue3.onMounted)(() => {
538
- document.addEventListener("mousemove", onPaneResizeMove);
539
- document.addEventListener("mouseup", onPaneResizeEnd);
222
+ const state = (0, import_vue3.shallowRef)(controller.getSnapshot());
223
+ const unsubscribe = controller.subscribe(() => {
224
+ state.value = controller.getSnapshot();
540
225
  });
226
+ (0, import_vue3.watch)(controlled, (values) => controller.setControlled(values));
227
+ (0, import_vue3.watch)(mergedOptions, (options) => controller.setOptions(options));
228
+ const root = (0, import_vue3.shallowRef)(null);
229
+ (0, import_vue3.onMounted)(() => controller.setRootElement(root.value));
541
230
  (0, import_vue3.onBeforeUnmount)(() => {
542
- document.removeEventListener("mousemove", onPaneResizeMove);
543
- document.removeEventListener("mouseup", onPaneResizeEnd);
231
+ unsubscribe();
232
+ controller.destroy();
544
233
  });
545
- function toggleMaximize() {
546
- if (!maximized.value) {
547
- if (isHorizontal.value) {
548
- prevWidth.value = panelWidth.value;
549
- panelWidth.value = window.innerWidth;
550
- } else {
551
- prevHeight.value = panelHeight.value;
552
- panelHeight.value = window.innerHeight;
553
- }
554
- } else {
555
- if (isHorizontal.value) {
556
- panelWidth.value = prevWidth.value;
557
- } else {
558
- panelHeight.value = prevHeight.value;
559
- }
560
- }
561
- maximized.value = !maximized.value;
562
- }
563
- function handleClose() {
564
- visible.value = false;
565
- props.onClose?.();
566
- }
567
- function handleHide() {
568
- preHideCollapsed = collapsed.value;
569
- hidden.value = true;
570
- }
571
- function handleUnhide() {
572
- hidden.value = false;
573
- collapsed.value = preHideCollapsed;
234
+ const exposed = {};
235
+ for (const method of PANEL_REF_METHODS) {
236
+ exposed[method] = controller[method].bind(controller);
574
237
  }
575
- const positionDropdownOpen = (0, import_vue3.ref)(false);
576
- function closePositionDropdown() {
577
- positionDropdownOpen.value = false;
578
- }
579
- function togglePositionDropdown(e) {
238
+ expose(exposed);
239
+ const openDropdown = (e, dropdown) => {
240
+ if (!dropdown) return;
580
241
  e.stopPropagation();
581
- positionDropdownOpen.value = !positionDropdownOpen.value;
582
- }
583
- function selectPosition(pos) {
584
- positionDropdownOpen.value = false;
585
- position.value = pos;
586
- (0, import_cli_core.savePanelPosition)(pos);
587
- }
588
- return () => {
589
- if (!visible.value) return null;
590
- const wrapperClass = [
591
- "cli-panel-wrapper",
592
- collapsed.value && "collapsed",
593
- maximized.value && "maximized",
594
- panelResizing.value && "resizing",
595
- props.class
596
- ].filter(Boolean).join(" ");
597
- const wrapperStyle = {
598
- ...isHorizontal.value ? { width: `${panelWidth.value}px` } : { height: `${panelHeight.value}px` },
599
- ...hidden.value ? { display: "none" } : {},
600
- ...themeStyles.value,
601
- ...props.style
602
- };
603
- const headerEl = (0, import_vue3.h)("div", { class: "cli-panel-header" }, [
242
+ const anchor = e.currentTarget;
243
+ if (dropdown === "services") controller.toggleServicesDropdown(anchor);
244
+ else controller.toggleServersDropdown(anchor);
245
+ };
246
+ const renderHeader = (s) => {
247
+ const indicators = (0, import_cli2.statusIndicators)(s);
248
+ return (0, import_vue3.h)("div", { class: "cli-panel-header" }, [
604
249
  (0, import_vue3.h)(
605
250
  "div",
606
251
  {
607
252
  class: "cli-panel-resize-bar",
608
- onMousedown: onPanelResizeStart
253
+ onMousedown: (e) => {
254
+ if (!s.resizable) return;
255
+ e.preventDefault();
256
+ controller.startPanelResize(e.clientX, e.clientY);
257
+ }
609
258
  },
610
259
  [(0, import_vue3.h)("div", { class: "cli-panel-resize-grip" })]
611
260
  ),
612
261
  (0, import_vue3.h)("div", { class: "cli-panel-header-content" }, [
613
- (0, import_vue3.h)("p", { class: "cli-panel-title" }, [
614
- (0, import_vue3.h)("span", { class: "cli-panel-title-icon" }, [
615
- terminalIcon()
616
- ]),
617
- "CLI"
618
- ]),
262
+ (0, import_vue3.h)("p", { class: "cli-panel-title" }, [(0, import_vue3.h)("span", { class: "cli-panel-title-icon" }, [icon(import_cli2.TERMINAL_ICON)]), import_cli2.PANEL_LABELS.title]),
263
+ s.showStatusIndicators ? (0, import_vue3.h)(
264
+ "div",
265
+ { class: "cli-panel-status-indicators" },
266
+ indicators.map(
267
+ (item) => (0, import_vue3.h)(
268
+ "span",
269
+ {
270
+ key: item.key,
271
+ class: (0, import_cli2.joinClasses)("cli-panel-status-item", item.itemClass),
272
+ onClick: item.dropdown ? (e) => openDropdown(e, item.dropdown) : void 0
273
+ },
274
+ [
275
+ item.dotClass ? (0, import_vue3.h)("span", { class: `cli-panel-status-dot ${item.dotClass}` }) : null,
276
+ item.icon ? (0, import_vue3.h)("span", { class: (0, import_cli2.joinClasses)("cli-panel-status-icon", item.iconClass) }, item.icon) : null,
277
+ (0, import_vue3.h)("span", { class: "cli-panel-status-label" }, item.label)
278
+ ]
279
+ )
280
+ )
281
+ ) : null,
282
+ // Compact indicators for left/right positions (CSS controls visibility).
283
+ (0, import_vue3.h)(
284
+ "div",
285
+ { class: "cli-panel-status-indicators-compact" },
286
+ indicators.map(
287
+ (item) => (0, import_vue3.h)(
288
+ "span",
289
+ {
290
+ key: item.key,
291
+ class: (0, import_cli2.joinClasses)("cli-panel-status-compact-item", item.compactClass),
292
+ title: item.title,
293
+ onClick: item.dropdown ? (e) => openDropdown(e, item.dropdown) : void 0
294
+ },
295
+ [
296
+ item.compactDotClass ? (0, import_vue3.h)("span", { class: item.compactDotClass }) : null,
297
+ item.dotClass ? (0, import_vue3.h)("span", { class: `cli-panel-status-dot ${item.dotClass}` }) : null,
298
+ item.icon ? (0, import_vue3.h)("span", { class: (0, import_cli2.joinClasses)("cli-panel-status-icon", item.iconClass) }, item.icon) : null
299
+ ]
300
+ )
301
+ )
302
+ ),
619
303
  (0, import_vue3.h)("div", { class: "cli-panel-action-buttons" }, [
620
- (0, import_vue3.h)("div", {
621
- class: "cli-panel-btn-position-wrapper",
622
- onClick: (e) => e.stopPropagation()
623
- }, [
624
- (0, import_vue3.h)("button", {
625
- class: "cli-panel-btn cli-panel-btn-position",
626
- title: "Move panel",
627
- onClick: togglePositionDropdown
628
- }, [positionIcon(position.value)]),
629
- positionDropdownOpen.value ? (0, import_vue3.h)(
304
+ (0, import_vue3.h)("div", { class: "cli-panel-btn-position-wrapper", onClick: stop }, [
305
+ (0, import_vue3.h)(
306
+ "button",
307
+ {
308
+ class: "cli-panel-btn cli-panel-btn-position",
309
+ title: import_cli2.PANEL_LABELS.movePanel,
310
+ onClick: () => controller.togglePositionDropdown()
311
+ },
312
+ [icon((0, import_cli2.positionIcon)(s.position))]
313
+ ),
314
+ s.positionDropdownOpen ? (0, import_vue3.h)(
630
315
  "div",
631
316
  { class: "cli-panel-position-dropdown" },
632
- ["bottom", "top", "left", "right"].map(
633
- (pos) => (0, import_vue3.h)("button", {
634
- class: ["cli-panel-position-dropdown-item", position.value === pos ? "active" : ""].filter(Boolean).join(" "),
635
- onClick: () => selectPosition(pos)
636
- }, [
637
- positionIcon(pos, 16),
638
- pos.charAt(0).toUpperCase() + pos.slice(1)
639
- ])
317
+ (0, import_cli2.positionOptions)(s).map(
318
+ (opt) => (0, import_vue3.h)(
319
+ "button",
320
+ { key: opt.position, class: opt.className, onClick: () => controller.setPosition(opt.position) },
321
+ [icon((0, import_cli2.positionIcon)(opt.position, 16)), opt.label]
322
+ )
640
323
  )
641
324
  ) : null
642
325
  ]),
643
- hideable.value ? (0, import_vue3.h)("button", {
644
- class: "cli-panel-btn cli-panel-btn-hide",
645
- title: "Hide",
646
- onClick: handleHide
647
- }, [hideIcon()]) : null,
326
+ s.hideable ? (0, import_vue3.h)("button", { class: "cli-panel-btn cli-panel-btn-hide", title: import_cli2.PANEL_LABELS.hide, onClick: () => controller.hide() }, [icon(import_cli2.HIDE_ICON)]) : null,
648
327
  (0, import_vue3.h)(
649
328
  "button",
650
329
  {
651
330
  class: "cli-panel-btn",
652
- title: maximized.value ? "Restore" : "Maximize",
653
- disabled: collapsed.value,
654
- onClick: toggleMaximize
331
+ title: s.maximized ? import_cli2.PANEL_LABELS.restore : import_cli2.PANEL_LABELS.maximize,
332
+ disabled: s.collapsed,
333
+ onClick: () => controller.toggleMaximize()
655
334
  },
656
- [maximized.value ? restoreIcon() : maximizeIcon()]
335
+ [icon(s.maximized ? import_cli2.RESTORE_ICON : import_cli2.MAXIMIZE_ICON)]
657
336
  ),
658
337
  (0, import_vue3.h)(
659
338
  "button",
660
339
  {
661
340
  class: "cli-panel-btn",
662
- title: collapsed.value ? "Expand" : "Collapse",
663
- onClick: toggle
341
+ title: s.collapsed ? import_cli2.PANEL_LABELS.expand : import_cli2.PANEL_LABELS.collapse,
342
+ onClick: () => controller.toggle()
664
343
  },
665
- [collapseChevron(position.value, collapsed.value)]
344
+ [icon((0, import_cli2.collapseChevronIcon)(s.position, s.collapsed))]
666
345
  ),
667
- closable.value ? (0, import_vue3.h)(
668
- "button",
669
- {
670
- class: "cli-panel-btn cli-panel-btn-close",
671
- title: "Close",
672
- onClick: handleClose
673
- },
674
- [closeIcon()]
675
- ) : null
346
+ s.closable ? (0, import_vue3.h)("button", { class: "cli-panel-btn cli-panel-btn-close", title: import_cli2.PANEL_LABELS.close, onClick: () => controller.close() }, [icon(import_cli2.CLOSE_ICON)]) : null
676
347
  ])
677
- ])
348
+ ]),
349
+ (0, import_vue3.h)("div", { class: (0, import_cli2.glowLineClass)(s) })
678
350
  ]);
679
- const contentEl = initialized.value ? (0, import_vue3.h)("div", { class: "cli-panel-content", style: collapsed.value ? { display: "none" } : void 0 }, [
680
- // Tab bar
681
- (0, import_vue3.h)("div", { class: "cli-panel-tabs" }, [
351
+ };
352
+ const renderTabs = (s) => (0, import_vue3.h)("div", { class: "cli-panel-tabs" }, [
353
+ (0, import_vue3.h)(
354
+ "ul",
355
+ { class: "cli-panel-tab-list" },
356
+ s.tabs.map(
357
+ (tab) => (0, import_vue3.h)(
358
+ "li",
359
+ {
360
+ key: tab.id,
361
+ class: (0, import_cli2.panelTabClass)(s, tab),
362
+ onClick: () => controller.selectTab(tab.id),
363
+ onDblclick: () => controller.startRename(tab.id),
364
+ onContextmenu: (e) => {
365
+ e.preventDefault();
366
+ e.stopPropagation();
367
+ controller.openContextMenu(tab.id, e.clientX, e.clientY);
368
+ }
369
+ },
370
+ tab.isEditing ? [
371
+ (0, import_vue3.h)("input", {
372
+ class: "cli-panel-tab-rename-input",
373
+ type: "text",
374
+ value: tab.title,
375
+ onVnodeMounted: (vnode) => {
376
+ const input = vnode.el;
377
+ input.focus();
378
+ input.select();
379
+ },
380
+ onKeydown: (e) => (0, import_cli2.handleRenameKey)(controller, tab.id, e.key, e.target.value),
381
+ onBlur: (e) => controller.commitRename(tab.id, e.target.value),
382
+ onClick: stop,
383
+ onDblclick: stop
384
+ })
385
+ ] : [
386
+ (0, import_vue3.h)("span", { class: (0, import_cli2.panelTabDotClass)(s, tab) }),
387
+ (0, import_vue3.h)("span", { class: "cli-panel-tab-title" }, tab.title),
388
+ (0, import_vue3.h)(
389
+ "button",
390
+ {
391
+ class: "cli-panel-tab-close-btn",
392
+ title: import_cli2.PANEL_LABELS.closeTab,
393
+ onClick: (e) => {
394
+ e.stopPropagation();
395
+ controller.closeTab(tab.id);
396
+ }
397
+ },
398
+ import_cli2.CLOSE_GLYPH
399
+ )
400
+ ]
401
+ )
402
+ )
403
+ ),
404
+ (0, import_vue3.h)("button", { class: "cli-panel-add-tab", title: import_cli2.PANEL_LABELS.newTerminal, onClick: () => controller.addTab() }, "+")
405
+ ]);
406
+ const renderInstances = (s) => (0, import_vue3.h)(
407
+ "div",
408
+ { class: "cli-panel-instances" },
409
+ s.tabs.map(
410
+ (tab) => (0, import_vue3.h)("div", { key: tab.id, class: "cli-panel-instance", style: { display: tab.id === s.activeTabId ? void 0 : "none" } }, [
682
411
  (0, import_vue3.h)(
683
- "ul",
684
- { class: "cli-panel-tab-list" },
685
- tabs.value.map(
686
- (tab) => (0, import_vue3.h)(
687
- "li",
412
+ "div",
413
+ { class: (0, import_cli2.panesContainerClass)(s) },
414
+ tab.panes.flatMap((pane, i) => [
415
+ i > 0 ? (0, import_vue3.h)(
416
+ "div",
688
417
  {
689
- key: tab.id,
690
- class: [
691
- "cli-panel-tab",
692
- tab.id === activeTabId.value && "active"
693
- ].filter(Boolean).join(" "),
694
- onClick: () => selectTab(tab.id),
695
- onDblclick: () => startRename(tab.id),
696
- onContextmenu: (e) => {
418
+ key: `divider-${pane.id}`,
419
+ class: "cli-panel-pane-divider",
420
+ onMousedown: (e) => {
697
421
  e.preventDefault();
698
- e.stopPropagation();
699
- contextMenu.value = {
700
- visible: true,
701
- x: e.clientX,
702
- y: e.clientY,
703
- tabId: tab.id
704
- };
422
+ controller.startPaneResize(tab.id, i - 1, e.clientX, (0, import_cli2.panesContainerWidth)(e.target));
705
423
  }
706
424
  },
707
- tab.isEditing ? [
708
- (0, import_vue3.h)("input", {
709
- class: "cli-panel-tab-rename-input",
710
- type: "text",
711
- value: tab.title,
712
- onKeydown: (e) => {
713
- if (e.key === "Enter")
714
- commitRename(
715
- tab.id,
716
- e.target.value
717
- );
718
- else if (e.key === "Escape") {
719
- tab.isEditing = false;
720
- }
721
- },
722
- onBlur: (e) => commitRename(
723
- tab.id,
724
- e.target.value
725
- ),
726
- onClick: (e) => e.stopPropagation(),
727
- onDblclick: (e) => e.stopPropagation()
728
- })
729
- ] : [
730
- (0, import_vue3.h)(
731
- "span",
732
- {
733
- class: "cli-panel-tab-title"
734
- },
735
- tab.title
736
- ),
737
- (0, import_vue3.h)(
425
+ [(0, import_vue3.h)("div", { class: "cli-panel-pane-divider-grip" })]
426
+ ) : null,
427
+ (0, import_vue3.h)(
428
+ "div",
429
+ {
430
+ key: pane.id,
431
+ class: (0, import_cli2.paneClass)(s, tab.id, pane.id),
432
+ style: (0, import_cli2.paneStyle)(pane.widthPercent),
433
+ onClick: () => controller.activatePane(tab.id, pane.id)
434
+ },
435
+ [
436
+ tab.panes.length > 1 ? (0, import_vue3.h)(
738
437
  "button",
739
438
  {
740
- class: "cli-panel-tab-close-btn",
741
- title: "Close tab",
439
+ class: "cli-panel-pane-close-btn",
440
+ title: import_cli2.PANEL_LABELS.closePane,
742
441
  onClick: (e) => {
743
442
  e.stopPropagation();
744
- closeTab(
745
- tab.id
746
- );
443
+ controller.closePane(pane.id);
747
444
  }
748
445
  },
749
- "\xD7"
750
- )
446
+ import_cli2.CLOSE_GLYPH
447
+ ) : null,
448
+ (0, import_vue3.h)(Cli, {
449
+ options: mergedOptions.value,
450
+ modules: hostConfig.value.modules,
451
+ services: hostConfig.value.services,
452
+ snapshot: pane.snapshot,
453
+ style: { height: "100%" },
454
+ onReady: (engine) => controller.registerEngine(tab.id, pane.id, engine)
455
+ })
751
456
  ]
752
457
  )
753
- )
754
- ),
755
- (0, import_vue3.h)(
756
- "button",
757
- {
758
- class: "cli-panel-add-tab",
759
- title: "New terminal",
760
- onClick: addTab
761
- },
762
- "+"
458
+ ])
763
459
  )
764
- ]),
765
- // Terminal instances
460
+ ])
461
+ )
462
+ );
463
+ const renderContextMenu = (s) => (0, import_vue3.h)(
464
+ "div",
465
+ { class: "cli-panel-context-menu", style: (0, import_cli2.contextMenuStyle)(s), onClick: stop },
466
+ (0, import_cli2.contextMenuItems)(s).flatMap((item) => [
467
+ item.separatorBefore ? (0, import_vue3.h)("div", { class: "cli-panel-context-menu-separator" }) : null,
468
+ (0, import_vue3.h)(
469
+ "button",
470
+ {
471
+ class: (0, import_cli2.joinClasses)("cli-panel-context-menu-item", item.destructive && "destructive"),
472
+ disabled: item.disabled,
473
+ onClick: () => (0, import_cli2.runContextMenuAction)(controller, item.action)
474
+ },
475
+ item.label
476
+ )
477
+ ])
478
+ );
479
+ const renderStatusDropdown = (s) => {
480
+ const dropdown = (0, import_cli2.openStatusDropdown)(s);
481
+ if (!dropdown) return null;
482
+ return (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown", style: dropdown.style, onClick: stop }, [
483
+ (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-header" }, dropdown.header),
766
484
  (0, import_vue3.h)(
767
485
  "div",
768
- { class: "cli-panel-instances" },
769
- tabs.value.map(
770
- (tab) => (0, import_vue3.h)(
771
- "div",
772
- {
773
- key: tab.id,
774
- class: "cli-panel-instance",
775
- style: {
776
- display: tab.id === activeTabId.value ? void 0 : "none"
777
- }
778
- },
779
- [
780
- (0, import_vue3.h)(
781
- "div",
782
- {
783
- class: [
784
- "cli-panel-panes-container",
785
- paneResizing.value && "resizing"
786
- ].filter(Boolean).join(" ")
787
- },
788
- tab.panes.flatMap((pane, i) => {
789
- const nodes = [];
790
- if (i > 0) {
791
- nodes.push(
792
- (0, import_vue3.h)(
793
- "div",
794
- {
795
- class: "cli-panel-pane-divider",
796
- onMousedown: (e) => onPaneResizeStart(
797
- e,
798
- tab.id,
799
- i - 1
800
- )
801
- },
802
- [
803
- (0, import_vue3.h)("div", {
804
- class: "cli-panel-pane-divider-grip"
805
- })
806
- ]
807
- )
808
- );
809
- }
810
- nodes.push(
811
- (0, import_vue3.h)(
812
- "div",
813
- {
814
- class: [
815
- "cli-panel-pane",
816
- pane.id === activePaneId.value && tab.id === activeTabId.value && "active-pane"
817
- ].filter(
818
- Boolean
819
- ).join(" "),
820
- style: {
821
- flex: `${pane.widthPercent} 1 0`
822
- },
823
- onClick: () => {
824
- activePaneId.value = pane.id;
825
- activeTabId.value = tab.id;
826
- }
827
- },
828
- [
829
- tab.panes.length > 1 ? (0, import_vue3.h)(
830
- "button",
831
- {
832
- class: "cli-panel-pane-close-btn",
833
- title: "Close pane",
834
- onClick: (e) => {
835
- e.stopPropagation();
836
- closePane(
837
- tab.id,
838
- pane.id
839
- );
840
- }
841
- },
842
- "\xD7"
843
- ) : null,
844
- (0, import_vue3.h)(Cli, {
845
- options: mergedOptions.value,
846
- modules: mergedModules.value,
847
- processors: mergedProcessors.value,
848
- services: mergedServices.value,
849
- snapshot: pane.snapshot,
850
- style: {
851
- height: "100%"
852
- },
853
- onReady: (engine) => {
854
- engineMap.set(pane.id, engine);
855
- }
856
- })
857
- ]
858
- )
859
- );
860
- return nodes;
861
- })
862
- )
863
- ]
864
- )
486
+ { class: "cli-panel-services-dropdown-list" },
487
+ dropdown.rows.map(
488
+ (row) => (0, import_vue3.h)("div", { key: row.key, class: "cli-panel-services-dropdown-item" }, [
489
+ (0, import_vue3.h)("span", { class: row.dotClass }),
490
+ (0, import_vue3.h)("div", { class: "cli-panel-svc-info" }, [
491
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-name" }, row.name),
492
+ row.description ? (0, import_vue3.h)("span", { class: "cli-panel-svc-desc" }, row.description) : null
493
+ ]),
494
+ dropdown.kind === "servers" ? (0, import_vue3.h)("div", { class: "cli-panel-srv-meta" }, [
495
+ (0, import_vue3.h)("span", { class: "cli-panel-svc-status" }, row.status),
496
+ ...row.meta.map((m) => (0, import_vue3.h)("span", { key: m, class: "cli-panel-svc-desc" }, m))
497
+ ]) : (0, import_vue3.h)("span", { class: "cli-panel-svc-status" }, row.status)
498
+ ])
865
499
  )
866
- )
867
- ]) : null;
868
- const contextMenuEl = contextMenu.value.visible ? (0, import_vue3.h)(
869
- "div",
870
- {
871
- class: "cli-panel-context-menu",
872
- style: {
873
- left: `${contextMenu.value.x}px`,
874
- top: `${contextMenu.value.y}px`
500
+ ),
501
+ dropdown.rows.length === 0 ? (0, import_vue3.h)("div", { class: "cli-panel-services-dropdown-empty" }, dropdown.emptyText) : null
502
+ ]);
503
+ };
504
+ return () => {
505
+ const s = state.value;
506
+ if (!s.visible) return null;
507
+ return (0, import_vue3.h)(import_vue3.Fragment, [
508
+ s.hidden ? (0, import_vue3.h)(
509
+ "button",
510
+ {
511
+ class: "cli-panel-hide-tab",
512
+ "data-position": s.position,
513
+ "data-hide-align": s.hideAlignment,
514
+ style: s.themeStyles,
515
+ title: import_cli2.PANEL_LABELS.showCli,
516
+ onClick: () => controller.unhide()
875
517
  },
876
- onClick: (e) => e.stopPropagation()
877
- },
878
- [
879
- (0, import_vue3.h)(
880
- "button",
881
- {
882
- class: "cli-panel-context-menu-item",
883
- onClick: () => {
884
- closeContextMenu();
885
- startRename(contextMenu.value.tabId);
886
- }
887
- },
888
- "Rename"
889
- ),
890
- (0, import_vue3.h)(
891
- "button",
892
- {
893
- class: "cli-panel-context-menu-item",
894
- onClick: () => {
895
- const tab = tabs.value.find(
896
- (t) => t.id === contextMenu.value.tabId
897
- );
898
- closeContextMenu();
899
- if (!tab) return;
900
- const sourceEngine = engineMap.get(tab.panes[0]?.id);
901
- const snapshot = sourceEngine?.snapshot();
902
- const paneId = nextPaneId++;
903
- const tabId = nextTabId++;
904
- const idx = tabs.value.indexOf(tab);
905
- tabs.value.splice(idx + 1, 0, {
906
- id: tabId,
907
- title: `${tab.title} (copy)`,
908
- isEditing: false,
909
- panes: [
910
- { id: paneId, widthPercent: 100, snapshot }
911
- ]
912
- });
913
- activeTabId.value = tabId;
914
- activePaneId.value = paneId;
915
- }
916
- },
917
- "Duplicate"
918
- ),
919
- (0, import_vue3.h)(
920
- "button",
921
- {
922
- class: "cli-panel-context-menu-item",
923
- onClick: () => {
924
- closeContextMenu();
925
- splitRight(contextMenu.value.tabId);
926
- }
927
- },
928
- "Split Right"
929
- ),
930
- (0, import_vue3.h)("div", {
931
- class: "cli-panel-context-menu-separator"
932
- }),
933
- (0, import_vue3.h)(
934
- "button",
935
- {
936
- class: "cli-panel-context-menu-item",
937
- onClick: () => {
938
- closeContextMenu();
939
- closeTab(contextMenu.value.tabId);
940
- }
941
- },
942
- "Close"
943
- ),
944
- (0, import_vue3.h)(
945
- "button",
946
- {
947
- class: "cli-panel-context-menu-item",
948
- disabled: tabs.value.length <= 1,
949
- onClick: () => {
950
- const id = contextMenu.value.tabId;
951
- closeContextMenu();
952
- tabs.value = tabs.value.filter(
953
- (t) => t.id === id
954
- );
955
- activeTabId.value = id;
956
- }
957
- },
958
- "Close Others"
959
- ),
960
- (0, import_vue3.h)(
961
- "button",
962
- {
963
- class: "cli-panel-context-menu-item",
964
- onClick: () => {
965
- const id = contextMenu.value.tabId;
966
- closeContextMenu();
967
- const idx = tabs.value.findIndex(
968
- (t) => t.id === id
969
- );
970
- if (idx !== -1)
971
- tabs.value = tabs.value.slice(
972
- 0,
973
- idx + 1
974
- );
975
- }
976
- },
977
- "Close to the Right"
978
- ),
979
- (0, import_vue3.h)("div", {
980
- class: "cli-panel-context-menu-separator"
981
- }),
982
- (0, import_vue3.h)(
983
- "button",
984
- {
985
- class: "cli-panel-context-menu-item destructive",
986
- onClick: () => {
987
- closeContextMenu();
988
- tabs.value = [];
989
- initialized.value = false;
990
- collapsed.value = true;
991
- }
992
- },
993
- "Close All"
994
- )
995
- ]
996
- ) : null;
997
- const hideTabEl = hidden.value ? (0, import_vue3.h)("button", {
998
- class: "cli-panel-hide-tab",
999
- "data-position": position.value,
1000
- "data-hide-align": hideAlignment.value,
1001
- style: themeStyles.value,
1002
- title: "Show CLI",
1003
- onClick: handleUnhide
1004
- }, [
1005
- (0, import_vue3.h)("svg", { class: "cli-panel-hide-tab-icon", ...svgAttrs, width: "16", height: "16", "stroke-width": "2" }, [
1006
- (0, import_vue3.h)("polyline", { points: "4 17 10 11 4 5" }),
1007
- (0, import_vue3.h)("line", { x1: "12", y1: "19", x2: "20", y2: "19" })
1008
- ]),
1009
- (0, import_vue3.h)("span", { class: "cli-panel-hide-tab-label" }, "CLI"),
1010
- hideTabChevron(position.value)
1011
- ]) : null;
1012
- return (0, import_vue3.h)("div", {}, [
1013
- hideTabEl,
518
+ [
519
+ icon(import_cli2.HIDE_TAB_TERMINAL_ICON, "cli-panel-hide-tab-icon"),
520
+ (0, import_vue3.h)("span", { class: "cli-panel-hide-tab-label" }, import_cli2.PANEL_LABELS.title),
521
+ icon((0, import_cli2.hideTabChevronIcon)(s.position), "cli-panel-hide-tab-arrow")
522
+ ]
523
+ ) : null,
1014
524
  (0, import_vue3.h)(
1015
525
  "div",
1016
526
  {
1017
- class: wrapperClass,
1018
- style: wrapperStyle,
1019
- "data-position": position.value,
1020
- "data-resizable": String(resizable.value),
1021
- "data-closable": String(closable.value),
1022
- "data-hideable": String(hideable.value)
527
+ ref: root,
528
+ class: (0, import_cli2.panelWrapperClass)(s, props.class),
529
+ style: { ...(0, import_cli2.panelWrapperStyle)(s), ...props.style },
530
+ "data-position": s.position,
531
+ "data-resizable": String(s.resizable),
532
+ "data-closable": String(s.closable),
533
+ "data-hideable": String(s.hideable)
1023
534
  },
1024
- [headerEl, contentEl]
535
+ [
536
+ renderHeader(s),
537
+ s.initialized ? (0, import_vue3.h)("div", { class: "cli-panel-content", style: s.collapsed ? { display: "none" } : void 0 }, [
538
+ renderTabs(s),
539
+ renderInstances(s)
540
+ ]) : null
541
+ ]
1025
542
  ),
1026
- contextMenuEl
543
+ s.contextMenu.visible ? renderContextMenu(s) : null,
544
+ renderStatusDropdown(s)
1027
545
  ]);
1028
546
  };
1029
547
  }
@@ -1034,24 +552,12 @@ var import_vue5 = require("vue");
1034
552
 
1035
553
  // src/useCliEngine.ts
1036
554
  var import_vue4 = require("vue");
1037
- var import_cli2 = require("@qodalis/cli");
555
+ var import_cli3 = require("@qodalis/cli");
1038
556
  function useCliEngine(containerRef, config) {
1039
557
  const engine = (0, import_vue4.shallowRef)(null);
1040
558
  (0, import_vue4.onMounted)(async () => {
1041
559
  if (!containerRef.value) return;
1042
- const e = new import_cli2.CliEngine(containerRef.value, config?.options);
1043
- e.registerService("cli-framework", "Vue");
1044
- if (config?.services) {
1045
- for (const [token, value] of Object.entries(config.services)) {
1046
- e.registerService(token, value);
1047
- }
1048
- }
1049
- if (config?.modules) {
1050
- e.registerModules(config.modules);
1051
- }
1052
- if (config?.processors) {
1053
- e.registerProcessors(config.processors);
1054
- }
560
+ const e = (0, import_cli3.createCliEngine)(containerRef.value, { ...config, framework: "Vue" });
1055
561
  await e.start();
1056
562
  engine.value = e;
1057
563
  });
@@ -1070,10 +576,6 @@ var CliProvider = (0, import_vue5.defineComponent)({
1070
576
  type: Array,
1071
577
  default: void 0
1072
578
  },
1073
- processors: {
1074
- type: Array,
1075
- default: void 0
1076
- },
1077
579
  options: {
1078
580
  type: Object,
1079
581
  default: void 0
@@ -1092,7 +594,6 @@ var CliProvider = (0, import_vue5.defineComponent)({
1092
594
  const containerRef = (0, import_vue5.ref)(null);
1093
595
  const engine = useCliEngine(containerRef, {
1094
596
  modules: props.modules,
1095
- processors: props.processors,
1096
597
  options: props.options,
1097
598
  services: props.services
1098
599
  });
@@ -1120,7 +621,7 @@ function useCli() {
1120
621
  }
1121
622
 
1122
623
  // src/index.ts
1123
- var import_cli3 = require("@qodalis/cli");
624
+ var import_cli4 = require("@qodalis/cli");
1124
625
  // Annotate the CommonJS export names for ESM import in node:
1125
626
  0 && (module.exports = {
1126
627
  Cli,