@xxmachina/components 19.33.1 → 19.35.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.
- package/fesm2022/xxmachina-components-extras-flow.mjs +24 -2
- package/fesm2022/xxmachina-components-extras-flow.mjs.map +1 -1
- package/fesm2022/xxmachina-components-molecules-weekly-header.mjs +2 -2
- package/fesm2022/xxmachina-components-organisms-calendar-section.mjs +2 -2
- package/fesm2022/xxmachina-components-organisms-xterm.mjs +135 -35
- package/fesm2022/xxmachina-components-organisms-xterm.mjs.map +1 -1
- package/fesm2022/xxmachina-components-pages-command.mjs +2 -2
- package/fesm2022/xxmachina-components-pages-query.mjs +2 -2
- package/fesm2022/xxmachina-components-pages-thread.mjs +2 -2
- package/fesm2022/xxmachina-components-templates-agent.mjs +4 -4
- package/fesm2022/xxmachina-components-templates-agent.mjs.map +1 -1
- package/fesm2022/xxmachina-components-templates-background.mjs +20 -16
- package/fesm2022/xxmachina-components-templates-background.mjs.map +1 -1
- package/fesm2022/xxmachina-components.mjs +2 -2
- package/package.json +1 -1
- package/types/xxmachina-components-extras-flow.d.ts +9 -0
- package/types/xxmachina-components-extras-flow.d.ts.map +1 -1
- package/types/xxmachina-components-organisms-xterm.d.ts +44 -7
- package/types/xxmachina-components-organisms-xterm.d.ts.map +1 -1
|
@@ -12,7 +12,7 @@ class WeeklyHeaderMolecule {
|
|
|
12
12
|
<span>{{ day }}</span>
|
|
13
13
|
</div>
|
|
14
14
|
}
|
|
15
|
-
`, isInline: true, styles: [":host{display:block;--primary-color: #404040;--primary-color-SCOPED-IN-
|
|
15
|
+
`, isInline: true, styles: [":host{display:block;--primary-color: #404040;--primary-color-SCOPED-IN-KmPS5kJL: var(--primary-color);--secondary-color: #B0B0B0;--secondary-color-SCOPED-IN-KmPS5kJL: var(--secondary-color)}:host{display:grid;width:100%;grid-template-columns:repeat(7,1fr);background-color:var(--primary-color-SCOPED-IN-KmPS5kJL)}:host .day-container{display:flex;justify-content:center;align-items:center;color:#fff;font-weight:700;width:calc(hvar(--width) / 7)}\n"] });
|
|
16
16
|
}
|
|
17
17
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: WeeklyHeaderMolecule, decorators: [{
|
|
18
18
|
type: Component,
|
|
@@ -22,7 +22,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
22
22
|
<span>{{ day }}</span>
|
|
23
23
|
</div>
|
|
24
24
|
}
|
|
25
|
-
`, styles: [":host{display:block;--primary-color: #404040;--primary-color-SCOPED-IN-
|
|
25
|
+
`, styles: [":host{display:block;--primary-color: #404040;--primary-color-SCOPED-IN-KmPS5kJL: var(--primary-color);--secondary-color: #B0B0B0;--secondary-color-SCOPED-IN-KmPS5kJL: var(--secondary-color)}:host{display:grid;width:100%;grid-template-columns:repeat(7,1fr);background-color:var(--primary-color-SCOPED-IN-KmPS5kJL)}:host .day-container{display:flex;justify-content:center;align-items:center;color:#fff;font-weight:700;width:calc(hvar(--width) / 7)}\n"] }]
|
|
26
26
|
}], ctorParameters: () => [] });
|
|
27
27
|
|
|
28
28
|
/**
|
|
@@ -56,7 +56,7 @@ class CalendarSectionOrganism {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
</div>
|
|
59
|
-
`, isInline: true, styles: [":host{display:block;--row: 80px;--row-SCOPED-IN-
|
|
59
|
+
`, isInline: true, styles: [":host{display:block;--row: 80px;--row-SCOPED-IN-Gu8OJe40: var(--row);--row-num: 0;--row-num-SCOPED-IN-Gu8OJe40: var(--row-num);--border-color: #9E9E9E;--border-color-SCOPED-IN-Gu8OJe40: var(--border-color);--primary-color: #404040;--primary-color-SCOPED-IN-Gu8OJe40: var(--primary-color);--secondary-color: #B0B0B0;--secondary-color-SCOPED-IN-Gu8OJe40: var(--secondary-color)}:host{width:100%;height:auto}:host .calendar.header molecules-weekly-header{--height: 32px}:host .calendar.contents{display:grid;width:var(--width);border:1px solid var(--border-color-SCOPED-IN-Gu8OJe40);grid-gap:1px;grid-template-columns:repeat(7,1fr);grid-template-rows:repeat(var(--row-num-SCOPED-IN-Gu8OJe40),var(--row-SCOPED-IN-Gu8OJe40));box-sizing:border-box;background-color:var(--border-color-SCOPED-IN-Gu8OJe40)}:host .calendar.contents molecules-daily-cell{--width: calc((var(--width) - 8px) / 7);--height: var(--row-SCOPED-IN-Gu8OJe40);background-color:#fff}:host .calendar.description{display:flex;justify-content:flex-end;width:var(--width);height:32px;padding-right:16px}:host .calendar.description .description.container{display:flex;flex-direction:row;justify-content:flex-end;align-items:center;font-size:12px}:host .calendar.description .description.container .circle{display:flex;width:20px;height:20px;justify-content:center;align-items:center;border-radius:50%;color:#fff;background:#00f}:host .calendar.description .description.container label{padding-left:4px;padding-right:8px}\n"], dependencies: [{ kind: "component", type: DailyCellMolecule, selector: "molecules-daily-cell", inputs: ["date", "schedules", "displayDate", "noSchedulesText", "toolTipText", "marked", "markingColor"] }, { kind: "component", type: WeeklyHeaderMolecule, selector: "molecules-weekly-header" }, { kind: "ngmodule", type: MatRippleModule }, { kind: "directive", type: i1.MatRipple, selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
60
60
|
}
|
|
61
61
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImport: i0, type: CalendarSectionOrganism, decorators: [{
|
|
62
62
|
type: Component,
|
|
@@ -90,7 +90,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.6", ngImpor
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
</div>
|
|
93
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;--row: 80px;--row-SCOPED-IN-
|
|
93
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;--row: 80px;--row-SCOPED-IN-Gu8OJe40: var(--row);--row-num: 0;--row-num-SCOPED-IN-Gu8OJe40: var(--row-num);--border-color: #9E9E9E;--border-color-SCOPED-IN-Gu8OJe40: var(--border-color);--primary-color: #404040;--primary-color-SCOPED-IN-Gu8OJe40: var(--primary-color);--secondary-color: #B0B0B0;--secondary-color-SCOPED-IN-Gu8OJe40: var(--secondary-color)}:host{width:100%;height:auto}:host .calendar.header molecules-weekly-header{--height: 32px}:host .calendar.contents{display:grid;width:var(--width);border:1px solid var(--border-color-SCOPED-IN-Gu8OJe40);grid-gap:1px;grid-template-columns:repeat(7,1fr);grid-template-rows:repeat(var(--row-num-SCOPED-IN-Gu8OJe40),var(--row-SCOPED-IN-Gu8OJe40));box-sizing:border-box;background-color:var(--border-color-SCOPED-IN-Gu8OJe40)}:host .calendar.contents molecules-daily-cell{--width: calc((var(--width) - 8px) / 7);--height: var(--row-SCOPED-IN-Gu8OJe40);background-color:#fff}:host .calendar.description{display:flex;justify-content:flex-end;width:var(--width);height:32px;padding-right:16px}:host .calendar.description .description.container{display:flex;flex-direction:row;justify-content:flex-end;align-items:center;font-size:12px}:host .calendar.description .description.container .circle{display:flex;width:20px;height:20px;justify-content:center;align-items:center;border-radius:50%;color:#fff;background:#00f}:host .calendar.description .description.container label{padding-left:4px;padding-right:8px}\n"] }]
|
|
94
94
|
}], propDecorators: { label: [{
|
|
95
95
|
type: Input
|
|
96
96
|
}], displayDays: [{
|
|
@@ -1,20 +1,16 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, Directive, viewChild,
|
|
2
|
+
import { InjectionToken, input, inject, Directive, viewChild, ElementRef, output, signal, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
3
|
import { Terminal } from '@xterm/xterm';
|
|
4
4
|
import { FitAddon } from '@xterm/addon-fit';
|
|
5
5
|
import { InjectableComponent, NgAtomicComponent } from '@ng-atomic/core';
|
|
6
6
|
import { makeDI } from '@ng-atomic/common/services/ui';
|
|
7
7
|
|
|
8
|
-
const URL_REGEX = /https?:\/\/[^\s<>'")\]]+/g;
|
|
8
|
+
const URL_REGEX = /https?:\/\/[^\s<>'")\[\]]+/g;
|
|
9
|
+
const LOCALHOST_REGEX = /^https?:\/\/(?:localhost|127\.0\.0\.1)(?::\d+)?(?:\/|$)/;
|
|
9
10
|
const MAX_SCAN_LINES = 30;
|
|
10
11
|
/**
|
|
11
12
|
* Link provider that detects URLs spanning multiple terminal lines.
|
|
12
|
-
*
|
|
13
|
-
* Handles two wrapping scenarios:
|
|
14
|
-
* 1. Terminal wrapping (isWrapped=true) - xterm splits long output
|
|
15
|
-
* 2. Application wrapping (isWrapped=false) - e.g. Claude Code/Ink explicitly
|
|
16
|
-
* breaks lines at some width. Detected by heuristic: previous line ends
|
|
17
|
-
* without whitespace and current line starts without whitespace.
|
|
13
|
+
* localhost/127.0.0.1 URLs are skipped (handled by ProxyLinksAddon).
|
|
18
14
|
*/
|
|
19
15
|
class WebLinkProvider {
|
|
20
16
|
_terminal;
|
|
@@ -27,14 +23,12 @@ class WebLinkProvider {
|
|
|
27
23
|
}
|
|
28
24
|
provideLinks(bufferLineNumber, callback) {
|
|
29
25
|
const buffer = this._terminal.buffer.active;
|
|
30
|
-
// Find the start of this line group (0-indexed)
|
|
31
26
|
let startY = bufferLineNumber - 1;
|
|
32
27
|
while (startY > 0
|
|
33
28
|
&& (bufferLineNumber - 1 - startY) < MAX_SCAN_LINES
|
|
34
29
|
&& this._isLineContinuation(startY)) {
|
|
35
30
|
startY--;
|
|
36
31
|
}
|
|
37
|
-
// Collect text from all lines in the group
|
|
38
32
|
const lineTexts = [];
|
|
39
33
|
let y = startY;
|
|
40
34
|
do {
|
|
@@ -51,6 +45,8 @@ class WebLinkProvider {
|
|
|
51
45
|
let match;
|
|
52
46
|
const links = [];
|
|
53
47
|
while ((match = URL_REGEX.exec(fullText)) !== null) {
|
|
48
|
+
if (LOCALHOST_REGEX.test(match[0]))
|
|
49
|
+
continue;
|
|
54
50
|
const startPos = this._offsetToPos(match.index, startY, lineTexts);
|
|
55
51
|
const endPos = this._offsetToPos(match.index + match[0].length - 1, startY, lineTexts);
|
|
56
52
|
if (!startPos || !endPos)
|
|
@@ -66,13 +62,6 @@ class WebLinkProvider {
|
|
|
66
62
|
}
|
|
67
63
|
callback(links.length > 0 ? links : undefined);
|
|
68
64
|
}
|
|
69
|
-
/**
|
|
70
|
-
* Determine if a line is a continuation of the previous line.
|
|
71
|
-
* True when either:
|
|
72
|
-
* - xterm marks it as wrapped (isWrapped=true), OR
|
|
73
|
-
* - no whitespace at line boundary (previous line ends without space,
|
|
74
|
-
* current line starts without space) suggesting mid-token line break
|
|
75
|
-
*/
|
|
76
65
|
_isLineContinuation(lineIdx) {
|
|
77
66
|
const buffer = this._terminal.buffer.active;
|
|
78
67
|
const line = buffer.getLine(lineIdx);
|
|
@@ -92,7 +81,6 @@ class WebLinkProvider {
|
|
|
92
81
|
&& currentText.length > 0
|
|
93
82
|
&& !/^\s/.test(currentText));
|
|
94
83
|
}
|
|
95
|
-
/** Convert a character offset in the concatenated text to a buffer position. */
|
|
96
84
|
_offsetToPos(offset, startY, lineTexts) {
|
|
97
85
|
let remaining = offset;
|
|
98
86
|
for (let i = 0; i < lineTexts.length; i++) {
|
|
@@ -109,6 +97,7 @@ class WebLinkProvider {
|
|
|
109
97
|
/**
|
|
110
98
|
* Drop-in replacement for @xterm/addon-web-links that supports
|
|
111
99
|
* URLs spanning wrapped terminal lines.
|
|
100
|
+
* localhost/127.0.0.1 URLs are skipped (handled by ProxyLinksAddon).
|
|
112
101
|
*/
|
|
113
102
|
class WebLinksAddon {
|
|
114
103
|
_handler;
|
|
@@ -358,6 +347,98 @@ class FileLinksAddon {
|
|
|
358
347
|
}
|
|
359
348
|
}
|
|
360
349
|
|
|
350
|
+
/**
|
|
351
|
+
* localhost/127.0.0.1 URLをmachina web proxy URLに変換するリンクプロバイダ。
|
|
352
|
+
*
|
|
353
|
+
* 変換ルール:
|
|
354
|
+
* http://localhost:4200/path → https://{serverUUID}--4200.proxy.machina.at/__content__/path
|
|
355
|
+
* http://127.0.0.1:3000/api → https://{serverUUID}--3000.proxy.machina.at/__content__/api
|
|
356
|
+
*/
|
|
357
|
+
const LOCALHOST_URL_REGEX = /https?:\/\/(?:localhost|127\.0\.0\.1)(?::(\d+))?(\/[^\s<>'")\]]*)?/g;
|
|
358
|
+
class ProxyLinkProvider {
|
|
359
|
+
_terminal;
|
|
360
|
+
_getServerUUID;
|
|
361
|
+
_handler;
|
|
362
|
+
constructor(_terminal, _getServerUUID, _handler = (_, url) => {
|
|
363
|
+
window.open(url, '_blank', 'noopener');
|
|
364
|
+
}) {
|
|
365
|
+
this._terminal = _terminal;
|
|
366
|
+
this._getServerUUID = _getServerUUID;
|
|
367
|
+
this._handler = _handler;
|
|
368
|
+
}
|
|
369
|
+
provideLinks(bufferLineNumber, callback) {
|
|
370
|
+
const lineIndex = bufferLineNumber - 1;
|
|
371
|
+
const line = this._terminal.buffer.active.getLine(lineIndex);
|
|
372
|
+
if (!line) {
|
|
373
|
+
callback(undefined);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
const text = line.translateToString(true);
|
|
377
|
+
const links = [];
|
|
378
|
+
console.log('[proxy-link] provideLinks line', bufferLineNumber, 'text:', text.substring(0, 80));
|
|
379
|
+
LOCALHOST_URL_REGEX.lastIndex = 0;
|
|
380
|
+
let match;
|
|
381
|
+
while ((match = LOCALHOST_URL_REGEX.exec(text)) !== null) {
|
|
382
|
+
const matchedUrl = match[0];
|
|
383
|
+
const port = match[1] || '80';
|
|
384
|
+
const path = match[2] || '/';
|
|
385
|
+
const startX = match.index + 1;
|
|
386
|
+
const endX = match.index + matchedUrl.length;
|
|
387
|
+
links.push({
|
|
388
|
+
text: matchedUrl,
|
|
389
|
+
range: {
|
|
390
|
+
start: { x: startX, y: bufferLineNumber },
|
|
391
|
+
end: { x: endX, y: bufferLineNumber },
|
|
392
|
+
},
|
|
393
|
+
// serverUUIDはクリック時にlazy評価(セッション接続後に値が入る)
|
|
394
|
+
activate: (event) => {
|
|
395
|
+
const uuid = this._getServerUUID();
|
|
396
|
+
const proxyUrl = uuid
|
|
397
|
+
? `https://${uuid}--${port}.proxy.machina.at/__content__${path}`
|
|
398
|
+
: null;
|
|
399
|
+
const targetUrl = proxyUrl || matchedUrl;
|
|
400
|
+
console.log('[proxy-link] activate:', { matchedUrl, uuid, proxyUrl, targetUrl });
|
|
401
|
+
this._handler(event, targetUrl);
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
callback(links.length > 0 ? links : undefined);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
function toProxyUrl(serverUUID, localhostUrl) {
|
|
409
|
+
const match = localhostUrl.match(/^https?:\/\/(?:localhost|127\.0\.0\.1)(?::(\d+))?(\/.*)?$/);
|
|
410
|
+
if (!match)
|
|
411
|
+
return null;
|
|
412
|
+
const port = match[1] || '80';
|
|
413
|
+
const path = match[2] || '/';
|
|
414
|
+
return `https://${serverUUID}--${port}.proxy.machina.at/__content__${path}`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* xterm.js addon: localhost URLをmachina web proxyにリダイレクトするリンクを表示。
|
|
419
|
+
*
|
|
420
|
+
* Usage:
|
|
421
|
+
* ```typescript
|
|
422
|
+
* const addon = new ProxyLinksAddon(() => currentServerUUID);
|
|
423
|
+
* terminal.loadAddon(addon);
|
|
424
|
+
* ```
|
|
425
|
+
*/
|
|
426
|
+
class ProxyLinksAddon {
|
|
427
|
+
_getServerUUID;
|
|
428
|
+
_handler;
|
|
429
|
+
_linkProvider;
|
|
430
|
+
constructor(_getServerUUID, _handler) {
|
|
431
|
+
this._getServerUUID = _getServerUUID;
|
|
432
|
+
this._handler = _handler;
|
|
433
|
+
}
|
|
434
|
+
activate(terminal) {
|
|
435
|
+
this._linkProvider = terminal.registerLinkProvider(new ProxyLinkProvider(terminal, this._getServerUUID, this._handler));
|
|
436
|
+
}
|
|
437
|
+
dispose() {
|
|
438
|
+
this._linkProvider?.dispose();
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
361
442
|
var XtermActionId;
|
|
362
443
|
(function (XtermActionId) {
|
|
363
444
|
XtermActionId["DATA_INPUT"] = "xterm:data-input";
|
|
@@ -366,6 +447,8 @@ var XtermActionId;
|
|
|
366
447
|
XtermActionId["FILE_LINK_CLICK"] = "xterm:file-link-click";
|
|
367
448
|
XtermActionId["FOCUS_INPUT_REQUEST"] = "xterm:focus-input-request";
|
|
368
449
|
})(XtermActionId || (XtermActionId = {}));
|
|
450
|
+
/** DI token for providing serverUUID getter to ProxyLinksAddon */
|
|
451
|
+
const XTERM_SERVER_UUID = new InjectionToken('XTERM_SERVER_UUID');
|
|
369
452
|
class XtermOrganismStore extends InjectableComponent {
|
|
370
453
|
static DI = makeDI(XtermOrganismStore, () => () => ({
|
|
371
454
|
data: '',
|
|
@@ -374,15 +457,13 @@ class XtermOrganismStore extends InjectableComponent {
|
|
|
374
457
|
useInteractiveTheme: false,
|
|
375
458
|
}), ['components', 'organisms', 'xterm']);
|
|
376
459
|
config = XtermOrganismStore.DI.injectConfig();
|
|
377
|
-
// Note: Using simple default values instead of _computed() to ensure
|
|
378
|
-
// input bindings from templates work correctly with Angular signal effects
|
|
379
460
|
data = input(undefined, ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
380
461
|
interactive = input(false, ...(ngDevMode ? [{ debugName: "interactive" }] : []));
|
|
381
462
|
queryResult = input('', ...(ngDevMode ? [{ debugName: "queryResult" }] : []));
|
|
382
|
-
/** Use interactive theme even when not interactive (for display consistency) */
|
|
383
463
|
useInteractiveTheme = input(false, ...(ngDevMode ? [{ debugName: "useInteractiveTheme" }] : []));
|
|
384
|
-
/** Total bytes written to the buffer (for accurate diff detection when buffer overflows) */
|
|
385
464
|
totalWritten = input(0, ...(ngDevMode ? [{ debugName: "totalWritten" }] : []));
|
|
465
|
+
/** Injected serverUUID getter for proxy links (optional) */
|
|
466
|
+
getServerUUID = inject(XTERM_SERVER_UUID, { optional: true });
|
|
386
467
|
constructor() {
|
|
387
468
|
super();
|
|
388
469
|
XtermOrganismStore.DI.initialize(this);
|
|
@@ -456,6 +537,12 @@ class XtermOrganism extends NgAtomicComponent {
|
|
|
456
537
|
terminalInitialized = signal(false, ...(ngDevMode ? [{ debugName: "terminalInitialized" }] : []));
|
|
457
538
|
/** Tracks if initialization was skipped due to container being too small */
|
|
458
539
|
initSkippedDueToSize = false;
|
|
540
|
+
/** IDisposable refs for explicit cleanup (prevents memory leaks on mobile) */
|
|
541
|
+
disposables = [];
|
|
542
|
+
/** Timer refs for cleanup in ngOnDestroy */
|
|
543
|
+
stableTimer = null;
|
|
544
|
+
resizeTimer = null;
|
|
545
|
+
fallbackTimer = null;
|
|
459
546
|
constructor() {
|
|
460
547
|
super();
|
|
461
548
|
// Watch for data input changes (with totalWritten support for buffer overflow handling)
|
|
@@ -607,35 +694,36 @@ class XtermOrganism extends NgAtomicComponent {
|
|
|
607
694
|
}
|
|
608
695
|
});
|
|
609
696
|
this.terminal.loadAddon(this.fileLinksAddon);
|
|
697
|
+
// ProxyLinksAddon: localhost → proxy.machina.at redirect (always loaded)
|
|
698
|
+
this.terminal.loadAddon(new ProxyLinksAddon(this.store.getServerUUID ?? (() => undefined)));
|
|
610
699
|
this.terminal.open(containerElement);
|
|
611
700
|
// Setup event handlers for interactive mode
|
|
612
701
|
if (isInteractive) {
|
|
613
|
-
this.terminal.onData((data) => {
|
|
702
|
+
this.disposables.push(this.terminal.onData((data) => {
|
|
614
703
|
this.dispatch({ id: XtermActionId.DATA_INPUT, payload: data });
|
|
615
|
-
});
|
|
616
|
-
this.terminal.onResize(({ cols, rows }) => this.dispatch({ id: XtermActionId.RESIZED, payload: { cols, rows } }));
|
|
704
|
+
}), this.terminal.onResize(({ cols, rows }) => this.dispatch({ id: XtermActionId.RESIZED, payload: { cols, rows } })));
|
|
617
705
|
}
|
|
618
706
|
// Use ResizeObserver with debounce to wait for container size to stabilize
|
|
619
707
|
// (CSS transitions take 300-500ms, so fixed setTimeout(100ms) is too early)
|
|
620
|
-
let stableTimer = null;
|
|
621
|
-
let resizeTimer = null;
|
|
622
708
|
this.resizeObserver = new ResizeObserver(() => {
|
|
623
709
|
try {
|
|
624
710
|
if (!this.terminalInitialized()) {
|
|
625
711
|
this.fitAddon.fit();
|
|
626
712
|
// Debounce: wait for container to stop changing before initializing
|
|
627
|
-
if (stableTimer)
|
|
628
|
-
clearTimeout(stableTimer);
|
|
629
|
-
stableTimer = setTimeout(() => {
|
|
713
|
+
if (this.stableTimer)
|
|
714
|
+
clearTimeout(this.stableTimer);
|
|
715
|
+
this.stableTimer = setTimeout(() => {
|
|
716
|
+
this.stableTimer = null;
|
|
630
717
|
this.fitAddon.fit();
|
|
631
718
|
this.markInitialized(isInteractive);
|
|
632
719
|
}, 150);
|
|
633
720
|
}
|
|
634
721
|
else if (isInteractive) {
|
|
635
722
|
// Debounce resize to wait for CSS transitions to complete (300ms)
|
|
636
|
-
if (resizeTimer)
|
|
637
|
-
clearTimeout(resizeTimer);
|
|
638
|
-
resizeTimer = setTimeout(() => {
|
|
723
|
+
if (this.resizeTimer)
|
|
724
|
+
clearTimeout(this.resizeTimer);
|
|
725
|
+
this.resizeTimer = setTimeout(() => {
|
|
726
|
+
this.resizeTimer = null;
|
|
639
727
|
this.fitAddon.fit();
|
|
640
728
|
this.dispatch({ id: XtermActionId.RESIZED, payload: { cols: this.cols, rows: this.rows } });
|
|
641
729
|
}, 300);
|
|
@@ -647,7 +735,8 @@ class XtermOrganism extends NgAtomicComponent {
|
|
|
647
735
|
});
|
|
648
736
|
this.resizeObserver.observe(containerElement);
|
|
649
737
|
// Fallback: initialize after 500ms if ResizeObserver hasn't triggered stable state
|
|
650
|
-
setTimeout(() => {
|
|
738
|
+
this.fallbackTimer = setTimeout(() => {
|
|
739
|
+
this.fallbackTimer = null;
|
|
651
740
|
if (!this.terminalInitialized()) {
|
|
652
741
|
this.fitAddon.fit();
|
|
653
742
|
this.markInitialized(isInteractive);
|
|
@@ -655,7 +744,18 @@ class XtermOrganism extends NgAtomicComponent {
|
|
|
655
744
|
}, 500);
|
|
656
745
|
}
|
|
657
746
|
ngOnDestroy() {
|
|
747
|
+
// Clear pending timers to prevent post-destroy callbacks
|
|
748
|
+
if (this.stableTimer)
|
|
749
|
+
clearTimeout(this.stableTimer);
|
|
750
|
+
if (this.resizeTimer)
|
|
751
|
+
clearTimeout(this.resizeTimer);
|
|
752
|
+
if (this.fallbackTimer)
|
|
753
|
+
clearTimeout(this.fallbackTimer);
|
|
658
754
|
this.resizeObserver?.disconnect();
|
|
755
|
+
// Dispose xterm event handlers (onData, onResize) to prevent memory leaks
|
|
756
|
+
for (const d of this.disposables)
|
|
757
|
+
d.dispose();
|
|
758
|
+
this.disposables.length = 0;
|
|
659
759
|
// Remove terminal instance from window for E2E testing cleanup
|
|
660
760
|
if (typeof window !== 'undefined' && window.__XTERM_INSTANCES__) {
|
|
661
761
|
const instances = window.__XTERM_INSTANCES__;
|
|
@@ -1003,5 +1103,5 @@ async function getMachinaAsciiArtSixel(options = {}) {
|
|
|
1003
1103
|
* Generated bundle index. Do not edit.
|
|
1004
1104
|
*/
|
|
1005
1105
|
|
|
1006
|
-
export { GitHubLinkProvider, GitHubLinksAddon, WebLinksAddon, XtermActionId, XtermOrganism, XtermOrganismStore, asciiArtToSvg, generateAsciiArt, getMachinaAsciiArtSixel, svgToSixel };
|
|
1106
|
+
export { GitHubLinkProvider, GitHubLinksAddon, ProxyLinkProvider, ProxyLinksAddon, WebLinksAddon, XTERM_SERVER_UUID, XtermActionId, XtermOrganism, XtermOrganismStore, asciiArtToSvg, generateAsciiArt, getMachinaAsciiArtSixel, svgToSixel, toProxyUrl };
|
|
1007
1107
|
//# sourceMappingURL=xxmachina-components-organisms-xterm.mjs.map
|