@vibecook/ghosttea-react 0.11.1 → 0.13.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/README.md +86 -4
- package/dist/TerminalSurface.d.ts +53 -0
- package/dist/TerminalSurface.d.ts.map +1 -1
- package/dist/TerminalSurface.js +106 -12
- package/dist/TerminalSurface.js.map +1 -1
- package/dist/appearance/AppearanceSettings.d.ts +5 -2
- package/dist/appearance/AppearanceSettings.d.ts.map +1 -1
- package/dist/appearance/AppearanceSettings.js +14 -3
- package/dist/appearance/AppearanceSettings.js.map +1 -1
- package/dist/appearance/BackdropBlurControl.d.ts +5 -0
- package/dist/appearance/BackdropBlurControl.d.ts.map +1 -0
- package/dist/appearance/BackdropBlurControl.js +42 -0
- package/dist/appearance/BackdropBlurControl.js.map +1 -0
- package/dist/appearance/types.d.ts +10 -0
- package/dist/appearance/types.d.ts.map +1 -1
- package/dist/catalog-budget.d.ts +2 -2
- package/dist/catalog-budget.d.ts.map +1 -1
- package/dist/catalog-budget.js +2 -2
- package/dist/catalog-budget.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/link-input.d.ts +18 -0
- package/dist/link-input.d.ts.map +1 -0
- package/dist/link-input.js +27 -0
- package/dist/link-input.js.map +1 -0
- package/dist/renderers/background-geometry.d.ts +16 -0
- package/dist/renderers/background-geometry.d.ts.map +1 -0
- package/dist/renderers/background-geometry.js +20 -0
- package/dist/renderers/background-geometry.js.map +1 -0
- package/dist/renderers/glyph-atlas.d.ts +43 -0
- package/dist/renderers/glyph-atlas.d.ts.map +1 -0
- package/dist/renderers/glyph-atlas.js +175 -0
- package/dist/renderers/glyph-atlas.js.map +1 -0
- package/dist/renderers/light-adaptation.d.ts +36 -0
- package/dist/renderers/light-adaptation.d.ts.map +1 -0
- package/dist/renderers/light-adaptation.js +332 -0
- package/dist/renderers/light-adaptation.js.map +1 -0
- package/dist/renderers/types.d.ts +23 -0
- package/dist/renderers/types.d.ts.map +1 -1
- package/dist/renderers/types.js.map +1 -1
- package/dist/renderers/webgpu-renderer.d.ts +4 -0
- package/dist/renderers/webgpu-renderer.d.ts.map +1 -1
- package/dist/renderers/webgpu-renderer.js +331 -239
- package/dist/renderers/webgpu-renderer.js.map +1 -1
- package/dist/routed-control.d.ts +26 -2
- package/dist/routed-control.d.ts.map +1 -1
- package/dist/routed-control.js +145 -27
- package/dist/routed-control.js.map +1 -1
- package/dist/routed-frames.d.ts +1 -1
- package/dist/routed-frames.d.ts.map +1 -1
- package/dist/routed-frames.js +3 -7
- package/dist/routed-frames.js.map +1 -1
- package/dist/row-damage.d.ts +21 -0
- package/dist/row-damage.d.ts.map +1 -0
- package/dist/row-damage.js +76 -0
- package/dist/row-damage.js.map +1 -0
- package/dist/runtime.d.ts +97 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +489 -49
- package/dist/runtime.js.map +1 -1
- package/dist/styles.css +24 -0
- package/dist/terminal-render.worker.js +979 -297
- package/dist/terminal-render.worker.js.map +4 -4
- package/dist/use-terminal-links.d.ts +17 -0
- package/dist/use-terminal-links.d.ts.map +1 -0
- package/dist/use-terminal-links.js +101 -0
- package/dist/use-terminal-links.js.map +1 -0
- package/dist/worker-messages.d.ts +27 -1
- package/dist/worker-messages.d.ts.map +1 -1
- package/dist/workspace/Workspace.d.ts +19 -3
- package/dist/workspace/Workspace.d.ts.map +1 -1
- package/dist/workspace/Workspace.js +53 -20
- package/dist/workspace/Workspace.js.map +1 -1
- package/dist/workspace/index.d.ts +2 -2
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/pane-focus.d.ts +8 -0
- package/dist/workspace/pane-focus.d.ts.map +1 -0
- package/dist/workspace/pane-focus.js +24 -0
- package/dist/workspace/pane-focus.js.map +1 -0
- package/dist/workspace/pane-layout.d.ts +5 -2
- package/dist/workspace/pane-layout.d.ts.map +1 -1
- package/dist/workspace/pane-layout.js +45 -6
- package/dist/workspace/pane-layout.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { PointerEvent, RefObject } from "react";
|
|
2
|
+
import type { TerminalLink } from "@vibecook/ghosttea-frame";
|
|
3
|
+
import type { GhostteaTerminalRuntime } from "./runtime.js";
|
|
4
|
+
type Pointer = PointerEvent<HTMLTextAreaElement>;
|
|
5
|
+
export declare function useTerminalLinks(runtime: GhostteaTerminalRuntime, sessionHandle: string, input: RefObject<HTMLTextAreaElement | null>, grid: RefObject<{
|
|
6
|
+
cols: number;
|
|
7
|
+
rows: number;
|
|
8
|
+
}>, platform: string | undefined, visible: boolean): {
|
|
9
|
+
hoveredLink: TerminalLink | null;
|
|
10
|
+
clear: () => void;
|
|
11
|
+
move: (event: Pointer) => void;
|
|
12
|
+
begin: (event: Pointer) => boolean;
|
|
13
|
+
finish: (event: Pointer) => void;
|
|
14
|
+
leave: () => void;
|
|
15
|
+
};
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=use-terminal-links.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-terminal-links.d.ts","sourceRoot":"","sources":["../src/use-terminal-links.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAI5D,KAAK,OAAO,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;AAEjD,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,uBAAuB,EAChC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,EAC5C,IAAI,EAAE,SAAS,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/C,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,OAAO;;;kBAmEA,OAAO;mBAQN,OAAO,KAAG,OAAO;oBAShB,OAAO;;EAe1B"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { CELL_WIDTH, LINE_HEIGHT, ORIGIN_X, ORIGIN_Y } from "./renderers/types.js";
|
|
3
|
+
import { linkAtCell, linkModifierPressed, TerminalLinkGesture } from "./link-input.js";
|
|
4
|
+
export function useTerminalLinks(runtime, sessionHandle, input, grid, platform, visible) {
|
|
5
|
+
const [hoveredLink, setHoveredLink] = useState(null);
|
|
6
|
+
const position = useRef(null);
|
|
7
|
+
const gesture = useRef(new TerminalLinkGesture());
|
|
8
|
+
const hostPlatform = platform ?? (/Mac/.test(navigator.platform) ? "darwin" : "linux");
|
|
9
|
+
const atPosition = useCallback((x, y, modifiers) => {
|
|
10
|
+
if (!visible || !linkModifierPressed(modifiers, hostPlatform))
|
|
11
|
+
return null;
|
|
12
|
+
const bounds = input.current?.getBoundingClientRect();
|
|
13
|
+
if (!bounds)
|
|
14
|
+
return null;
|
|
15
|
+
const column = Math.floor((x - bounds.left - ORIGIN_X) / CELL_WIDTH);
|
|
16
|
+
const row = Math.floor((y - bounds.top - ORIGIN_Y) / LINE_HEIGHT);
|
|
17
|
+
if (x >= bounds.right ||
|
|
18
|
+
y >= bounds.bottom ||
|
|
19
|
+
column < 0 ||
|
|
20
|
+
column >= grid.current.cols ||
|
|
21
|
+
row < 0 ||
|
|
22
|
+
row >= grid.current.rows)
|
|
23
|
+
return null;
|
|
24
|
+
return linkAtCell(runtime.links(sessionHandle), column, row);
|
|
25
|
+
}, [grid, hostPlatform, input, runtime, sessionHandle, visible]);
|
|
26
|
+
const clear = useCallback(() => {
|
|
27
|
+
position.current = null;
|
|
28
|
+
gesture.current.cancel();
|
|
29
|
+
setHoveredLink(null);
|
|
30
|
+
}, []);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
const refresh = () => {
|
|
33
|
+
const point = position.current;
|
|
34
|
+
setHoveredLink(point ? atPosition(point.x, point.y, point.modifiers) : null);
|
|
35
|
+
};
|
|
36
|
+
const onLinks = (event) => {
|
|
37
|
+
if (event.detail.sessionHandle !== sessionHandle)
|
|
38
|
+
return;
|
|
39
|
+
// The target changed while a button was held: require a fresh click.
|
|
40
|
+
gesture.current.cancel();
|
|
41
|
+
refresh();
|
|
42
|
+
};
|
|
43
|
+
const onKey = (event) => {
|
|
44
|
+
if (position.current)
|
|
45
|
+
position.current.modifiers = event;
|
|
46
|
+
if (!linkModifierPressed(event, hostPlatform))
|
|
47
|
+
gesture.current.cancel();
|
|
48
|
+
refresh();
|
|
49
|
+
};
|
|
50
|
+
window.addEventListener("keydown", onKey, true);
|
|
51
|
+
window.addEventListener("keyup", onKey, true);
|
|
52
|
+
window.addEventListener("blur", clear);
|
|
53
|
+
runtime.addEventListener("link-targets", onLinks);
|
|
54
|
+
runtime.addEventListener("config-changed", refresh);
|
|
55
|
+
return () => {
|
|
56
|
+
window.removeEventListener("keydown", onKey, true);
|
|
57
|
+
window.removeEventListener("keyup", onKey, true);
|
|
58
|
+
window.removeEventListener("blur", clear);
|
|
59
|
+
runtime.removeEventListener("link-targets", onLinks);
|
|
60
|
+
runtime.removeEventListener("config-changed", refresh);
|
|
61
|
+
};
|
|
62
|
+
}, [atPosition, clear, hostPlatform, runtime, sessionHandle]);
|
|
63
|
+
return {
|
|
64
|
+
hoveredLink: visible ? hoveredLink : null,
|
|
65
|
+
clear,
|
|
66
|
+
move: (event) => {
|
|
67
|
+
position.current = { x: event.clientX, y: event.clientY, modifiers: event };
|
|
68
|
+
for (const sample of event.nativeEvent.getCoalescedEvents?.() ?? []) {
|
|
69
|
+
gesture.current.move(event.pointerId, sample.clientX, sample.clientY);
|
|
70
|
+
}
|
|
71
|
+
gesture.current.move(event.pointerId, event.clientX, event.clientY);
|
|
72
|
+
setHoveredLink(event.buttons === 0 ? atPosition(event.clientX, event.clientY, event) : null);
|
|
73
|
+
},
|
|
74
|
+
begin: (event) => {
|
|
75
|
+
if (event.button !== 0)
|
|
76
|
+
return false;
|
|
77
|
+
const link = atPosition(event.clientX, event.clientY, event);
|
|
78
|
+
if (!link)
|
|
79
|
+
return false;
|
|
80
|
+
position.current = { x: event.clientX, y: event.clientY, modifiers: event };
|
|
81
|
+
gesture.current.begin(event.pointerId, link, event.clientX, event.clientY);
|
|
82
|
+
setHoveredLink(link);
|
|
83
|
+
return true;
|
|
84
|
+
},
|
|
85
|
+
finish: (event) => {
|
|
86
|
+
gesture.current.move(event.pointerId, event.clientX, event.clientY);
|
|
87
|
+
const link = event.type === "pointerup" ? atPosition(event.clientX, event.clientY, event) : null;
|
|
88
|
+
const uri = gesture.current.finish(event.pointerId, link);
|
|
89
|
+
setHoveredLink(link);
|
|
90
|
+
if (uri)
|
|
91
|
+
void runtime
|
|
92
|
+
.openLink(uri)
|
|
93
|
+
.catch((error) => console.error("[terminal-runtime] open link failed", error));
|
|
94
|
+
},
|
|
95
|
+
leave: () => {
|
|
96
|
+
position.current = null;
|
|
97
|
+
setHoveredLink(null);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=use-terminal-links.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-terminal-links.js","sourceRoot":"","sources":["../src/use-terminal-links.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { TerminalLink } from "@vibecook/ghosttea-frame";
|
|
2
|
+
import type { CellSelection, PixelSize, TerminalEffects, TerminalTheme } from "./renderers/types.js";
|
|
2
3
|
import type { TerminalScrollbarState } from "@vibecook/ghosttea-protocol";
|
|
3
4
|
import type { TerminalRenderCounterSnapshot, TerminalRenderPerformanceSnapshot } from "./performance.js";
|
|
4
5
|
import type { RoutedFramesAttachRequest, RoutedFramesTransportEvent } from "./routed-frames.js";
|
|
@@ -13,6 +14,7 @@ export type RendererToWorkerMessage = {
|
|
|
13
14
|
surfaceId: string;
|
|
14
15
|
sessionHandle: string;
|
|
15
16
|
canvas: OffscreenCanvas;
|
|
17
|
+
size: PixelSize;
|
|
16
18
|
} | {
|
|
17
19
|
type: "unmount";
|
|
18
20
|
surfaceId: string;
|
|
@@ -94,6 +96,10 @@ export type RendererToWorkerMessage = {
|
|
|
94
96
|
activationId: string;
|
|
95
97
|
};
|
|
96
98
|
export type WorkerToRendererMessage = {
|
|
99
|
+
type: "link-targets";
|
|
100
|
+
sessionHandle: string;
|
|
101
|
+
links: TerminalLink[];
|
|
102
|
+
} | {
|
|
97
103
|
type: "renderer-status";
|
|
98
104
|
backend: string;
|
|
99
105
|
textEngine?: string;
|
|
@@ -125,6 +131,26 @@ export type WorkerToRendererMessage = {
|
|
|
125
131
|
sessionEpoch: bigint;
|
|
126
132
|
frameSequence: bigint;
|
|
127
133
|
fullSnapshot: boolean;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The first committed frame of this handle that put something on screen (a
|
|
137
|
+
* glyph, or text that is not blank). Posted once per handle until the handle
|
|
138
|
+
* is dropped; the runtime publishes it per session as `session-drawn`.
|
|
139
|
+
*/
|
|
140
|
+
| {
|
|
141
|
+
type: "session-drawn";
|
|
142
|
+
sessionHandle: string;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* A routed session's mouse modes, as of the frame just committed. The legacy
|
|
146
|
+
* bridge's frames pass the main thread, which reads them from each header; a
|
|
147
|
+
* routed frame reaches only this worker, so the worker says them — once per
|
|
148
|
+
* change, and again after the session's activation re-attaches.
|
|
149
|
+
*/
|
|
150
|
+
| {
|
|
151
|
+
type: "terminal-modes";
|
|
152
|
+
sessionHandle: string;
|
|
153
|
+
mouseTracking: boolean;
|
|
128
154
|
} | {
|
|
129
155
|
type: "catalog-pressure";
|
|
130
156
|
sessionHandle: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-messages.d.ts","sourceRoot":"","sources":["../src/worker-messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"worker-messages.d.ts","sourceRoot":"","sources":["../src/worker-messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EAAE,6BAA6B,EAAE,iCAAiC,EAAE,MAAM,kBAAkB,CAAC;AACzG,OAAO,KAAK,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAEhG,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,SAAS,CAAA;CAAE,GACrG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACjF;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAClF;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GACxF;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,aAAa,GAAG,IAAI,CAAA;CAAE,GACjG;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GACnF;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE;AAC/E,iFAAiF;GAC/E;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACrF;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,OAAO,EAAE,yBAAyB,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3D,MAAM,MAAM,uBAAuB,GAC/B;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,YAAY,EAAE,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,sBAAsB,CAAA;CAAE,GACrF;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;AAC1D;;;;;;GAMG;GACD;IACE,IAAI,EAAE,iBAAiB,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB;AACH;;;;GAIG;GACD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE;AAClD;;;;;GAKG;GACD;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,4BAA4B,CAAA;CAAE,GACzF;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,iCAAiC,CAAA;CAAE,GAC9F;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,6BAA6B,CAAA;CAAE,GAC5F;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,KAAK,EAAE,0BAA0B,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,0BAA0B,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
|
@@ -2,9 +2,9 @@ import { type ComponentType } from "react";
|
|
|
2
2
|
import type { ConfigSnapshot, SessionSummary } from "@vibecook/ghosttea-protocol";
|
|
3
3
|
import { type TerminalMenuAction } from "../TerminalSurface.js";
|
|
4
4
|
import { type TerminalEffects, type TerminalTheme } from "../renderers/types.js";
|
|
5
|
-
import type { GhostteaAppearanceUpdate, GhostteaConfigEditorBridge } from "../appearance/types.js";
|
|
5
|
+
import type { GhostteaAppearanceUpdate, GhostteaBackdropBlurBridge, GhostteaConfigEditorBridge } from "../appearance/types.js";
|
|
6
6
|
import { useGhostteaRuntime } from "../context.js";
|
|
7
|
-
import { type PaneNode, type SplitAxis } from "./pane-layout.js";
|
|
7
|
+
import { type PaneNode, type SplitAxis, type SplitSizing } from "./pane-layout.js";
|
|
8
8
|
export declare function workspaceOwnsHotkey(active: boolean, root: Pick<HTMLElement, "contains"> | null, target: EventTarget | null, activeElement: Element | null, blocked?: boolean): boolean;
|
|
9
9
|
export interface GhostteaWorkspacePlatform {
|
|
10
10
|
platform?: string;
|
|
@@ -29,6 +29,7 @@ export interface GhostteaWorkspacePlatform {
|
|
|
29
29
|
saveAppearance?: (update: GhostteaAppearanceUpdate) => Promise<void>;
|
|
30
30
|
/** Edit only the host's profile-owned final Ghostty overlay. */
|
|
31
31
|
configEditor?: GhostteaConfigEditorBridge;
|
|
32
|
+
backdropBlur?: GhostteaBackdropBlurBridge;
|
|
32
33
|
newTab?: (cwd?: string) => void;
|
|
33
34
|
selectTab?: (target: "previous" | "next" | "last" | number) => void;
|
|
34
35
|
closeTab?: () => void;
|
|
@@ -47,6 +48,9 @@ export interface GhostteaWorkspaceContext {
|
|
|
47
48
|
activateSession: (sessionId: string) => void;
|
|
48
49
|
mountSession: (session: SessionSummary) => void;
|
|
49
50
|
placeSession: (session: SessionSummary) => void;
|
|
51
|
+
/** Atomically replace an expected session's attachments without activating, splitting or unzooming.
|
|
52
|
+
* Returns false if it is no longer attached. Safe after an asynchronous session birth. */
|
|
53
|
+
replaceSession: (expectedId: string, session: SessionSummary) => boolean;
|
|
50
54
|
createSessionInActivePane: () => Promise<SessionSummary | undefined>;
|
|
51
55
|
splitActive: (axis?: SplitAxis) => Promise<SessionSummary | undefined>;
|
|
52
56
|
}
|
|
@@ -108,15 +112,27 @@ export interface GhostteaWorkspaceProps {
|
|
|
108
112
|
* is host policy because the same PTY may be mirrored in another pane/window.
|
|
109
113
|
*/
|
|
110
114
|
onPaneClose?: ((context: GhostteaPaneClose) => void) | undefined;
|
|
115
|
+
/** Override presentation while retaining the configured workspace zoom binding. */
|
|
116
|
+
onTogglePaneZoom?: (paneId: string) => void;
|
|
111
117
|
onActiveSessionChange?: (session: SessionSummary | undefined) => void;
|
|
112
118
|
createSplitSession?: (activeSession: SessionSummary, axis: SplitAxis) => Promise<SessionSummary>;
|
|
119
|
+
/** Size splits by halving the active pane (default) or equalizing its row/column after insertion and removal. */
|
|
120
|
+
splitSizing?: SplitSizing;
|
|
113
121
|
enableRemoteSessions?: boolean;
|
|
114
122
|
active?: boolean;
|
|
123
|
+
/** Host visibility without remounting panes or changing split geometry. */
|
|
124
|
+
paneVisibility?: Readonly<Record<string, boolean>> | undefined;
|
|
115
125
|
showTitlebar?: boolean;
|
|
116
126
|
claimExistingSessions?: boolean;
|
|
117
127
|
initialCwd?: string;
|
|
118
128
|
onSessionsChange?: (sessionIds: readonly string[]) => void;
|
|
119
129
|
resizeCommitPolicy?: GhostteaResizeCommitPolicy;
|
|
130
|
+
/**
|
|
131
|
+
* Take a session's geometry seat whenever one of its panes gains focus
|
|
132
|
+
* (`TerminalSurface`'s `takeGeometryOnFocus`), so the pane focused last
|
|
133
|
+
* sizes the PTY across windows and devices. Off by default.
|
|
134
|
+
*/
|
|
135
|
+
takeGeometryOnFocus?: boolean;
|
|
120
136
|
}
|
|
121
137
|
interface InitialWorkspace {
|
|
122
138
|
layout: PaneNode;
|
|
@@ -128,6 +144,6 @@ export declare function resolveWorkspaceEffects(effects: TerminalEffects | undef
|
|
|
128
144
|
/** Canonicalize renderer semantics so equivalent host objects share a memo dependency. */
|
|
129
145
|
export declare function workspaceEffectsKey(effects: TerminalEffects): string;
|
|
130
146
|
export declare function initializeWorkspace(terminalRuntime: ReturnType<typeof useGhostteaRuntime>, storageKey: string, defaultShell: string, claimExistingSessions: boolean, initialCwd: string | undefined, rehydratePane: (context: GhostteaPaneRehydration) => Promise<SessionSummary | null> | SessionSummary | null): Promise<InitialWorkspace>;
|
|
131
|
-
export declare function GhostteaWorkspace({ platform, storageKey, sidebar, theme, effects: effectsOverride, decoratePane, paneMeta, onRehydratePane, onPaneClose, onActiveSessionChange, createSplitSession, enableRemoteSessions, active, showTitlebar, claimExistingSessions, initialCwd, onSessionsChange, resizeCommitPolicy, }: GhostteaWorkspaceProps): import("react").JSX.Element;
|
|
147
|
+
export declare function GhostteaWorkspace({ platform, storageKey, sidebar, theme, effects: effectsOverride, decoratePane, paneMeta, onRehydratePane, onPaneClose, onTogglePaneZoom, onActiveSessionChange, createSplitSession, splitSizing, enableRemoteSessions, active, paneVisibility, showTitlebar, claimExistingSessions, initialCwd, onSessionsChange, resizeCommitPolicy, takeGeometryOnFocus, }: GhostteaWorkspaceProps): import("react").JSX.Element;
|
|
132
148
|
export {};
|
|
133
149
|
//# sourceMappingURL=Workspace.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Workspace.d.ts","sourceRoot":"","sources":["../../src/workspace/Workspace.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,aAAa,EAEnB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,EAAmB,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAElG,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"Workspace.d.ts","sourceRoot":"","sources":["../../src/workspace/Workspace.tsx"],"names":[],"mappings":"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"}
|
|
@@ -9,11 +9,12 @@ import { RemoteSessionPalette } from "./RemoteSessionPalette.js";
|
|
|
9
9
|
import { RemoteSessionBanner, useInputSuppressionHint, useRemoteSessionLifecycle } from "./RemoteSessionBanner.js";
|
|
10
10
|
import { paneIsFrozen } from "./remote-banner.js";
|
|
11
11
|
import { TERMINAL_THEMES } from "./themes.js";
|
|
12
|
-
import { appendPane, collectDeadPanes, containsPane, equalize, insertPane, layoutId, leaves, mountSessionInPane, pane, persistedWorkspace, removePane, resizeForPane, restoreNode, updateSession, updateSplit, } from "./pane-layout.js";
|
|
12
|
+
import { appendPane, collectDeadPanes, containsPane, equalize, insertPane, layoutId, leaves, mountSessionInPane, pane, persistedWorkspace, removePane, replaceSessionInPanes, resizeForPane, restoreNode, updateSession, updateSplit, } from "./pane-layout.js";
|
|
13
13
|
import { resolveKeyEvent, routeConsumesInput } from "../bindings/action-route.js";
|
|
14
14
|
import { configuredBindingsForPlatform } from "../bindings/ghostty-bindings.js";
|
|
15
15
|
import { PendingPromiseCache } from "./pending-cache.js";
|
|
16
16
|
import { sessionsToClaim } from "./session-scope.js";
|
|
17
|
+
import { createPaneFocusScheduler } from "./pane-focus.js";
|
|
17
18
|
import { decodeWorkspaceDocument } from "./workspace-model.js";
|
|
18
19
|
const DEFAULT_STORAGE_KEY = "ghosttea:workspace:v1";
|
|
19
20
|
export function workspaceOwnsHotkey(active, root, target, activeElement, blocked = false) {
|
|
@@ -112,7 +113,7 @@ function sharedInitialization(terminalRuntime, storageKey, defaultShell, claimEx
|
|
|
112
113
|
const key = `${storageKey}\u0000${defaultShell}\u0000${claimExistingSessions}\u0000${initialCwd ?? ""}`;
|
|
113
114
|
return initializations.get(terminalRuntime, key, () => initializeWorkspace(terminalRuntime, storageKey, defaultShell, claimExistingSessions, initialCwd, rehydratePane));
|
|
114
115
|
}
|
|
115
|
-
function WorkspacePane({ paneId, session, active, zoomed, hiddenByZoom, workspaceActive, platform, theme, effects, bindings, decoration, onActivate, onClose, onBrowseDevice, }) {
|
|
116
|
+
function WorkspacePane({ paneId, session, active, zoomed, hiddenByZoom, workspaceActive, takeGeometryOnFocus, platform, theme, effects, bindings, decoration, onActivate, onClose, onBrowseDevice, }) {
|
|
116
117
|
const terminalRuntime = useGhostteaRuntime();
|
|
117
118
|
const lifecycle = useRemoteSessionLifecycle(session.id);
|
|
118
119
|
const hint = useInputSuppressionHint(session.id);
|
|
@@ -136,9 +137,9 @@ function WorkspacePane({ paneId, session, active, zoomed, hiddenByZoom, workspac
|
|
|
136
137
|
}, [session.id, terminalRuntime]);
|
|
137
138
|
const frozen = paneIsFrozen(lifecycle);
|
|
138
139
|
const paneStyle = decoration?.color ? { "--ghostty-pane-color": decoration.color } : undefined;
|
|
139
|
-
return (_jsxs("div", { className: `ghostty-pane${active ? " is-active" : ""}${zoomed ? " is-zoomed" : ""}${frozen ? " is-frozen" : ""}`, "data-pane-id": paneId, "data-pane-accent": decoration?.color ? "true" : undefined, style: paneStyle, onPointerDown: onActivate, children: [lifecycle ? (_jsx(RemoteSessionBanner, { lifecycle: lifecycle, hint: hint, retrying: retrying, onRetry: retry, onClose: onClose, onBrowse: () => onBrowseDevice(lifecycle.deviceId) })) : null, _jsx(TerminalSurface, { session: session, theme: theme, effects: effects, bindings: bindings, active: active, ...(platform.platform ? { platform: platform.platform } : {}), visible: workspaceActive && !hiddenByZoom, controlsResize: !hiddenByZoom, onActivate: onActivate, readClipboard: platform.readClipboard, ...(active && platform.setCanCopy ? { onCopyAvailabilityChange: platform.setCanCopy } : {}), onContextMenu: platform.showContextMenu, onToggleFullscreen: platform.toggleFullscreen, onMenuAction: platform.onMenuAction }), decoration?.label ? _jsx("span", { className: "ghostty-pane-badge", children: decoration.label }) : null, !session.readWrite ? _jsx("span", { className: "ghostty-pane-access", children: "View only" }) : null] }));
|
|
140
|
+
return (_jsxs("div", { className: `ghostty-pane${active ? " is-active" : ""}${zoomed ? " is-zoomed" : ""}${frozen ? " is-frozen" : ""}`, "data-pane-id": paneId, "data-pane-accent": decoration?.color ? "true" : undefined, style: paneStyle, onPointerDown: onActivate, children: [lifecycle ? (_jsx(RemoteSessionBanner, { lifecycle: lifecycle, hint: hint, retrying: retrying, onRetry: retry, onClose: onClose, onBrowse: () => onBrowseDevice(lifecycle.deviceId) })) : null, _jsx(TerminalSurface, { session: session, theme: theme, effects: effects, bindings: bindings, active: active, ...(platform.platform ? { platform: platform.platform } : {}), visible: workspaceActive && !hiddenByZoom, controlsResize: workspaceActive && !hiddenByZoom, takeGeometryOnFocus: takeGeometryOnFocus, onActivate: onActivate, readClipboard: platform.readClipboard, ...(active && platform.setCanCopy ? { onCopyAvailabilityChange: platform.setCanCopy } : {}), onContextMenu: platform.showContextMenu, onToggleFullscreen: platform.toggleFullscreen, onMenuAction: platform.onMenuAction }), decoration?.label ? _jsx("span", { className: "ghostty-pane-badge", children: decoration.label }) : null, !session.readWrite ? _jsx("span", { className: "ghostty-pane-access", children: "View only" }) : null] }));
|
|
140
141
|
}
|
|
141
|
-
function SplitView({ node, activePaneId, workspaceActive, zoomedPaneId, platform, theme, effects, bindings, onActivate, onClosePane, onBrowseDevice, decoratePane, resizeLiveIntervalMs, onRatio, }) {
|
|
142
|
+
function SplitView({ node, activePaneId, workspaceActive, takeGeometryOnFocus, paneVisibility, zoomedPaneId, platform, theme, effects, bindings, onActivate, onClosePane, onBrowseDevice, decoratePane, resizeLiveIntervalMs, onRatio, }) {
|
|
142
143
|
const splitRef = useRef(null);
|
|
143
144
|
const dragRef = useRef(null);
|
|
144
145
|
useEffect(() => () => {
|
|
@@ -147,7 +148,7 @@ function SplitView({ node, activePaneId, workspaceActive, zoomedPaneId, platform
|
|
|
147
148
|
window.clearTimeout(timer);
|
|
148
149
|
}, []);
|
|
149
150
|
if (node.kind === "pane") {
|
|
150
|
-
return (_jsx(WorkspacePane, { paneId: node.id, session: node.session, active: workspaceActive && node.id === activePaneId, zoomed: node.id === zoomedPaneId, hiddenByZoom: zoomedPaneId !== null && node.id !== zoomedPaneId, workspaceActive: workspaceActive, platform: platform, theme: theme, effects: effects, bindings: bindings, decoration: decoratePane?.(node.session, node.id), onActivate: () => onActivate(node.id), onClose: () => onClosePane(node.id), onBrowseDevice: onBrowseDevice }));
|
|
151
|
+
return (_jsx(WorkspacePane, { paneId: node.id, session: node.session, active: workspaceActive && node.id === activePaneId, zoomed: node.id === zoomedPaneId, hiddenByZoom: zoomedPaneId !== null && node.id !== zoomedPaneId, workspaceActive: workspaceActive && paneVisibility?.[node.id] !== false, takeGeometryOnFocus: takeGeometryOnFocus, platform: platform, theme: theme, effects: effects, bindings: bindings, decoration: decoratePane?.(node.session, node.id), onActivate: () => onActivate(node.id), onClose: () => onClosePane(node.id), onBrowseDevice: onBrowseDevice }));
|
|
151
152
|
}
|
|
152
153
|
const zoomedInFirst = zoomedPaneId !== null && containsPane(node.first, zoomedPaneId);
|
|
153
154
|
const zoomedInSecond = zoomedPaneId !== null && containsPane(node.second, zoomedPaneId);
|
|
@@ -208,6 +209,8 @@ function SplitView({ node, activePaneId, workspaceActive, zoomedPaneId, platform
|
|
|
208
209
|
return (_jsxs("div", { ref: splitRef, className: `ghostty-split is-${node.axis}`, style: style, children: [_jsx(SplitView, { node: node.first,
|
|
209
210
|
activePaneId,
|
|
210
211
|
workspaceActive,
|
|
212
|
+
takeGeometryOnFocus,
|
|
213
|
+
paneVisibility,
|
|
211
214
|
zoomedPaneId,
|
|
212
215
|
platform,
|
|
213
216
|
theme,
|
|
@@ -240,6 +243,8 @@ function SplitView({ node, activePaneId, workspaceActive, zoomedPaneId, platform
|
|
|
240
243
|
} }), _jsx(SplitView, { node: node.second,
|
|
241
244
|
activePaneId,
|
|
242
245
|
workspaceActive,
|
|
246
|
+
takeGeometryOnFocus,
|
|
247
|
+
paneVisibility,
|
|
243
248
|
zoomedPaneId,
|
|
244
249
|
platform,
|
|
245
250
|
theme,
|
|
@@ -252,9 +257,10 @@ function SplitView({ node, activePaneId, workspaceActive, zoomedPaneId, platform
|
|
|
252
257
|
resizeLiveIntervalMs,
|
|
253
258
|
onRatio }, node.second.id)] }));
|
|
254
259
|
}
|
|
255
|
-
export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY, sidebar, theme, effects: effectsOverride, decoratePane, paneMeta, onRehydratePane, onPaneClose, onActiveSessionChange, createSplitSession, enableRemoteSessions = true, active = true, showTitlebar = true, claimExistingSessions = true, initialCwd, onSessionsChange, resizeCommitPolicy, }) {
|
|
260
|
+
export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY, sidebar, theme, effects: effectsOverride, decoratePane, paneMeta, onRehydratePane, onPaneClose, onTogglePaneZoom, onActiveSessionChange, createSplitSession, splitSizing = "halves", enableRemoteSessions = true, active = true, paneVisibility, showTitlebar = true, claimExistingSessions = true, initialCwd, onSessionsChange, resizeCommitPolicy, takeGeometryOnFocus = false, }) {
|
|
256
261
|
const Sidebar = sidebar;
|
|
257
262
|
const terminalRuntime = useGhostteaRuntime();
|
|
263
|
+
const hostZoom = onTogglePaneZoom !== undefined;
|
|
258
264
|
const [config, setConfig] = useState(terminalRuntime.configSnapshot);
|
|
259
265
|
const [configPreview, setConfigPreview] = useState();
|
|
260
266
|
const [layout, setLayout] = useState();
|
|
@@ -307,7 +313,7 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
307
313
|
return;
|
|
308
314
|
setLayout(workspace.layout);
|
|
309
315
|
setActivePaneId(workspace.activePaneId);
|
|
310
|
-
setZoomedPaneId(workspace.zoomedPaneId);
|
|
316
|
+
setZoomedPaneId(hostZoom ? null : workspace.zoomedPaneId);
|
|
311
317
|
}, (cause) => {
|
|
312
318
|
if (mounted)
|
|
313
319
|
setError(cause instanceof Error ? cause.message : String(cause));
|
|
@@ -316,7 +322,7 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
316
322
|
mounted = false;
|
|
317
323
|
mountedRef.current = false;
|
|
318
324
|
};
|
|
319
|
-
}, [claimExistingSessions, initialCwd, platform.defaultShell, rehydratePane, storageKey, terminalRuntime]);
|
|
325
|
+
}, [claimExistingSessions, hostZoom, initialCwd, platform.defaultShell, rehydratePane, storageKey, terminalRuntime]);
|
|
320
326
|
useEffect(() => {
|
|
321
327
|
layoutRef.current = layout;
|
|
322
328
|
activePaneIdRef.current = activePaneId;
|
|
@@ -356,13 +362,21 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
356
362
|
window.removeEventListener("blur", onBlur);
|
|
357
363
|
};
|
|
358
364
|
}, []);
|
|
365
|
+
const focusPane = useCallback((paneId) => {
|
|
366
|
+
const target = Array.from(workspaceRef.current?.querySelectorAll("[data-pane-id]") ?? []).find((element) => element.dataset.paneId === paneId);
|
|
367
|
+
target?.querySelector(".terminal-input")?.focus({ preventScroll: true });
|
|
368
|
+
}, []);
|
|
369
|
+
const [paneFocus] = useState(() => createPaneFocusScheduler(window));
|
|
370
|
+
useEffect(() => paneFocus.cancel, [paneFocus]);
|
|
371
|
+
useEffect(() => {
|
|
372
|
+
if (!active)
|
|
373
|
+
paneFocus.cancel();
|
|
374
|
+
}, [active, paneFocus]);
|
|
359
375
|
const activatePane = useCallback((paneId) => {
|
|
376
|
+
activePaneIdRef.current = paneId;
|
|
360
377
|
setActivePaneId(paneId);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
target?.querySelector(".terminal-input")?.focus({ preventScroll: true });
|
|
364
|
-
});
|
|
365
|
-
}, []);
|
|
378
|
+
paneFocus.request(paneId, focusPane);
|
|
379
|
+
}, [focusPane, paneFocus]);
|
|
366
380
|
const activateSession = useCallback((sessionId) => {
|
|
367
381
|
const target = leaves(layoutRef.current).find((candidate) => candidate.session.id === sessionId);
|
|
368
382
|
if (target)
|
|
@@ -382,6 +396,18 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
382
396
|
activatePane(paneId);
|
|
383
397
|
}, [activatePane, terminalRuntime]);
|
|
384
398
|
const placeSession = mountSession;
|
|
399
|
+
const replaceSession = useCallback((expectedId, session) => {
|
|
400
|
+
const current = layoutRef.current;
|
|
401
|
+
if (!mountedRef.current || !current)
|
|
402
|
+
return false;
|
|
403
|
+
const updated = replaceSessionInPanes(current, expectedId, session);
|
|
404
|
+
if (updated === current)
|
|
405
|
+
return false;
|
|
406
|
+
terminalRuntime.registerSession(session);
|
|
407
|
+
layoutRef.current = updated;
|
|
408
|
+
setLayout(updated);
|
|
409
|
+
return true;
|
|
410
|
+
}, [terminalRuntime]);
|
|
385
411
|
const addSession = useCallback((session, axis = "horizontal") => {
|
|
386
412
|
terminalRuntime.registerSession(session);
|
|
387
413
|
const current = layoutRef.current;
|
|
@@ -391,7 +417,7 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
391
417
|
return;
|
|
392
418
|
}
|
|
393
419
|
const next = pane(layoutId("pane"), session);
|
|
394
|
-
const updated = insertPane(current, next, activePaneIdRef.current, axis, layoutId("split"));
|
|
420
|
+
const updated = insertPane(current, next, activePaneIdRef.current, axis, layoutId("split"), splitSizing);
|
|
395
421
|
// Commit the ref synchronously so multiple agent/session callbacks in
|
|
396
422
|
// one React turn compose instead of each splitting the same stale tree.
|
|
397
423
|
layoutRef.current = updated;
|
|
@@ -399,7 +425,7 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
399
425
|
setZoomedPaneId(null);
|
|
400
426
|
setOperationError(undefined);
|
|
401
427
|
activatePane(next.id);
|
|
402
|
-
}, [activatePane, terminalRuntime]);
|
|
428
|
+
}, [activatePane, splitSizing, terminalRuntime]);
|
|
403
429
|
const newSplit = useCallback(async (axis = "horizontal") => {
|
|
404
430
|
const current = layoutRef.current;
|
|
405
431
|
const active = leaves(current).find((candidate) => candidate.id === activePaneIdRef.current);
|
|
@@ -525,9 +551,10 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
525
551
|
}
|
|
526
552
|
const index = panes.findIndex((candidate) => candidate.id === target.id);
|
|
527
553
|
const next = panes[index === panes.length - 1 ? index - 1 : index + 1];
|
|
528
|
-
const remaining = removePane(current, target.id);
|
|
554
|
+
const remaining = removePane(current, target.id, splitSizing);
|
|
529
555
|
if (!remaining)
|
|
530
556
|
return;
|
|
557
|
+
layoutRef.current = remaining;
|
|
531
558
|
setLayout(remaining);
|
|
532
559
|
setZoomedPaneId(null);
|
|
533
560
|
activatePane(next.id);
|
|
@@ -536,7 +563,7 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
536
563
|
session: target.session,
|
|
537
564
|
remainingSessionIds: [...new Set(leaves(remaining).map((pane) => pane.session.id))],
|
|
538
565
|
});
|
|
539
|
-
}, [activatePane, onPaneClose, platform]);
|
|
566
|
+
}, [activatePane, onPaneClose, platform, splitSizing]);
|
|
540
567
|
const closeActivePane = useCallback(() => {
|
|
541
568
|
if (activePaneIdRef.current)
|
|
542
569
|
closePane(activePaneIdRef.current);
|
|
@@ -604,12 +631,16 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
604
631
|
setLayout((current) => (current ? equalize(current) : current));
|
|
605
632
|
}
|
|
606
633
|
else if (command.type === "toggle-zoom") {
|
|
607
|
-
|
|
634
|
+
if (onTogglePaneZoom && activePaneId)
|
|
635
|
+
onTogglePaneZoom(activePaneId);
|
|
636
|
+
else
|
|
637
|
+
setZoomedPaneId((current) => (current ? null : (activePaneId ?? null)));
|
|
608
638
|
}
|
|
609
639
|
else if (command.type === "close-pane") {
|
|
610
640
|
closeActivePane();
|
|
611
641
|
}
|
|
612
642
|
}, [
|
|
643
|
+
onTogglePaneZoom,
|
|
613
644
|
activePane?.session.cwd,
|
|
614
645
|
activePaneId,
|
|
615
646
|
closeActivePane,
|
|
@@ -709,6 +740,7 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
709
740
|
activateSession,
|
|
710
741
|
mountSession,
|
|
711
742
|
placeSession,
|
|
743
|
+
replaceSession,
|
|
712
744
|
createSessionInActivePane,
|
|
713
745
|
splitActive: newSplit,
|
|
714
746
|
}), [
|
|
@@ -721,16 +753,17 @@ export function GhostteaWorkspace({ platform, storageKey = DEFAULT_STORAGE_KEY,
|
|
|
721
753
|
newSplit,
|
|
722
754
|
panes,
|
|
723
755
|
placeSession,
|
|
756
|
+
replaceSession,
|
|
724
757
|
sessions,
|
|
725
758
|
]);
|
|
726
759
|
const settingsButton = platform.saveAppearance || platform.configEditor ? (_jsx("button", { type: "button", className: "ghosttea-settings-button", "aria-label": "Open settings", title: "Settings", disabled: !config, onClick: () => setAppearanceSettingsOpen(true), children: "\u2699" })) : null;
|
|
727
|
-
return (_jsxs("main", { ref: workspaceRef, className: `ghostty-window${active && focused ? " is-focused" : ""}${showTitlebar ? " has-titlebar" : ""}`, children: [showTitlebar ? (_jsxs("header", { className: "ghostty-titlebar", "aria-label": title, children: [_jsx("span", { className: "ghostty-title", children: title }), settingsButton] })) : (settingsButton), _jsxs("div", { className: "ghosttea-workspace-body", children: [_jsxs("section", { className: "terminal-host", children: [error ? (_jsx("div", { className: "terminal-error", role: "alert", children: error })) : layout && activePaneId ? (_jsx(SplitView, { node: layout, activePaneId: activePaneId, workspaceActive: active, zoomedPaneId: zoomedPaneId, platform: platform, theme: resolvedTheme, effects: effects, bindings: bindings, onActivate: activatePane, onClosePane: closePane, onBrowseDevice: browseDeviceSessions, decoratePane: decoratePane, resizeLiveIntervalMs: resizeCommitPolicy?.liveIntervalMs ?? 33, onRatio: (splitId, ratio, commit) => {
|
|
760
|
+
return (_jsxs("main", { ref: workspaceRef, className: `ghostty-window${active && focused ? " is-focused" : ""}${showTitlebar ? " has-titlebar" : ""}`, children: [showTitlebar ? (_jsxs("header", { className: "ghostty-titlebar", "aria-label": title, children: [_jsx("span", { className: "ghostty-title", children: title }), settingsButton] })) : (settingsButton), _jsxs("div", { className: "ghosttea-workspace-body", children: [_jsxs("section", { className: "terminal-host", children: [error ? (_jsx("div", { className: "terminal-error", role: "alert", children: error })) : layout && activePaneId ? (_jsx(SplitView, { node: layout, activePaneId: activePaneId, workspaceActive: active, takeGeometryOnFocus: takeGeometryOnFocus, paneVisibility: paneVisibility, zoomedPaneId: zoomedPaneId, platform: platform, theme: resolvedTheme, effects: effects, bindings: bindings, onActivate: activatePane, onClosePane: closePane, onBrowseDevice: browseDeviceSessions, decoratePane: decoratePane, resizeLiveIntervalMs: resizeCommitPolicy?.liveIntervalMs ?? 33, onRatio: (splitId, ratio, commit) => {
|
|
728
761
|
setLayout((current) => current ? updateSplit(current, splitId, (split) => ({ ...split, ratio })) : current);
|
|
729
762
|
if (commit)
|
|
730
763
|
resizeCommitPolicy?.onCommit?.({ splitId, ratio });
|
|
731
764
|
} }, layout.id)) : null, operationError ? (_jsx("div", { className: "terminal-operation-error", role: "status", children: operationError })) : null, remotePaletteOpen ? (_jsx(RemoteSessionPalette, { ...(remotePaletteDeviceId ? { deviceId: remotePaletteDeviceId } : {}), onClose: () => {
|
|
732
765
|
setRemotePaletteOpen(false);
|
|
733
766
|
setRemotePaletteDeviceId(undefined);
|
|
734
|
-
}, onOpen: openRemoteChoice })) : null] }), Sidebar ? (_jsx("aside", { className: "ghosttea-workspace-sidebar", children: _jsx(Sidebar, { workspace: workspaceContext }) })) : null] }), appearanceSettingsOpen && (platform.saveAppearance || platform.configEditor) && config ? (_jsx(AppearanceSettings, { config: config, onClose: () => setAppearanceSettingsOpen(false), ...(platform.saveAppearance ? { onSave: platform.saveAppearance } : {}), ...(platform.configEditor ? { configEditor: platform.configEditor } : {}), onPreview: setConfigPreview })) : null] }));
|
|
767
|
+
}, onOpen: openRemoteChoice })) : null] }), Sidebar ? (_jsx("aside", { className: "ghosttea-workspace-sidebar", children: _jsx(Sidebar, { workspace: workspaceContext }) })) : null] }), appearanceSettingsOpen && (platform.saveAppearance || platform.configEditor) && config ? (_jsx(AppearanceSettings, { config: config, onClose: () => setAppearanceSettingsOpen(false), ...(platform.saveAppearance ? { onSave: platform.saveAppearance } : {}), ...(platform.configEditor ? { configEditor: platform.configEditor } : {}), ...(platform.backdropBlur ? { backdropBlur: platform.backdropBlur } : {}), onPreview: setConfigPreview })) : null] }));
|
|
735
768
|
}
|
|
736
769
|
//# sourceMappingURL=Workspace.js.map
|