@dimina-kit/devtools 0.4.0-dev.20260801163345 → 0.4.0-dev.20260824071518
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/main/app/app.js +12 -1
- package/dist/main/index.bundle.js +584 -323
- package/dist/main/ipc/index.d.ts +1 -0
- package/dist/main/ipc/index.js +1 -0
- package/dist/main/ipc/session.js +11 -0
- package/dist/main/ipc/tooltip.d.ts +13 -0
- package/dist/main/ipc/tooltip.js +28 -0
- package/dist/main/services/layout/index.d.ts +11 -0
- package/dist/main/services/layout/index.js +23 -0
- package/dist/main/services/network-forward/frontend-dispatch.js +2 -1
- package/dist/main/services/notifications/renderer-notifier.d.ts +2 -0
- package/dist/main/services/notifications/renderer-notifier.js +7 -1
- package/dist/main/services/simulator-current-page/index.d.ts +5 -3
- package/dist/main/services/simulator-current-page/index.js +8 -1
- package/dist/main/services/views/clear-console-filter.d.ts +44 -0
- package/dist/main/services/views/clear-console-filter.js +86 -0
- package/dist/main/services/views/console-filter-test-fixtures.d.ts +94 -0
- package/dist/main/services/views/console-filter-test-fixtures.js +82 -0
- package/dist/main/services/views/console-filter.d.ts +79 -130
- package/dist/main/services/views/console-filter.js +140 -183
- package/dist/main/services/views/devtools-tabs.d.ts +24 -4
- package/dist/main/services/views/devtools-tabs.js +40 -21
- package/dist/main/services/views/host-toolbar-view.js +5 -18
- package/dist/main/services/views/native-simulator-devtools-host.js +64 -45
- package/dist/main/services/views/native-simulator-view.js +6 -24
- package/dist/main/services/views/native-view-tree.d.ts +25 -0
- package/dist/main/services/views/native-view-tree.js +69 -0
- package/dist/main/services/views/overlay-panels-view.d.ts +27 -4
- package/dist/main/services/views/overlay-panels-view.js +138 -109
- package/dist/main/services/views/placement-reconciler.d.ts +4 -16
- package/dist/main/services/views/placement-reconciler.js +64 -29
- package/dist/main/services/views/placement-test-driver.d.ts +26 -0
- package/dist/main/services/views/placement-test-driver.js +26 -0
- package/dist/main/services/views/view-manager.d.ts +5 -9
- package/dist/main/services/views/view-manager.js +7 -1
- package/dist/main/services/views/workbench-view.js +27 -20
- package/dist/main/services/workbench-coi-server.d.ts +11 -0
- package/dist/main/services/workbench-coi-server.js +32 -0
- package/dist/main/services/workspace/rebuild-status.d.ts +21 -8
- package/dist/main/services/workspace/rebuild-status.js +24 -8
- package/dist/main/utils/sender-policy.d.ts +1 -1
- package/dist/main/utils/sender-policy.js +6 -1
- package/dist/main/utils/theme.d.ts +7 -2
- package/dist/main/utils/theme.js +8 -3
- package/dist/native-host/container/pageFrame.css +1 -1
- package/dist/native-host/render/render.js +1966 -1816
- package/dist/native-host/service/service.js +1 -1
- package/dist/preload/windows/host-toolbar-runtime.cjs.map +2 -2
- package/dist/preload/windows/main.cjs +3176 -14
- package/dist/preload/windows/main.cjs.map +4 -4
- package/dist/preload/windows/main.css +428 -0
- package/dist/preload/windows/main.css.map +7 -0
- package/dist/preload/windows/simulator.cjs +5 -2
- package/dist/preload/windows/simulator.cjs.map +2 -2
- package/dist/preload/windows/simulator.js +5 -2
- package/dist/renderer/assets/constants-Bdz0LHdy.js +2 -0
- package/dist/renderer/assets/index-CtznrmHR.js +49 -0
- package/dist/renderer/assets/{input-xdmfv-eH.js → input-Dmm6nob5.js} +2 -2
- package/dist/renderer/assets/ipc-transport-BOg0gR9W.js +9 -0
- package/dist/renderer/assets/ipc-transport-DgQhZaE9.css +1 -0
- package/dist/renderer/assets/popover-Cd1FEGOX.js +2 -0
- package/dist/renderer/assets/select-BaYox7If.js +2 -0
- package/dist/renderer/assets/settings-BXvwuFaz.js +2 -0
- package/dist/renderer/assets/settings-api-Bo9GbYqs.js +2 -0
- package/dist/renderer/assets/settings-tab-bar-Beia6lMr.js +2 -0
- package/dist/renderer/assets/tooltip-DfQqK3Sk.js +2 -0
- package/dist/renderer/assets/view-api-nn69je7A.js +2 -0
- package/dist/renderer/assets/workbenchSettings-oq_EyfKf.js +8 -0
- package/dist/renderer/entries/main/index.html +8 -7
- package/dist/renderer/entries/popover/index.html +7 -6
- package/dist/renderer/entries/settings/index.html +7 -5
- package/dist/renderer/entries/tooltip/index.html +20 -0
- package/dist/renderer/entries/workbench-settings/index.html +7 -5
- package/dist/service-host/sync-impls/menu-button-geometry.js +1 -0
- package/dist/shared/ipc-channels.d.ts +11 -0
- package/dist/shared/ipc-channels.js +28 -2
- package/dist/shared/ipc-schemas.d.ts +19 -0
- package/dist/shared/ipc-schemas.js +23 -0
- package/dist/shared/simulator-route.d.ts +8 -0
- package/dist/shared/simulator-route.js +15 -0
- package/dist/shared/types.d.ts +7 -0
- package/dist/shared/view-ids.d.ts +2 -0
- package/dist/shared/view-ids.js +11 -0
- package/dist/simulator/assets/device-shell-CmtM1QxP.js +2 -0
- package/dist/simulator/assets/device-shell-iFZo1igL.css +1 -0
- package/dist/simulator/assets/{simulator-COIE6R49.js → simulator-CIobn3Mh.js} +6 -6
- package/dist/simulator/assets/{simulator-mini-app-BLn7XV8e.js → simulator-mini-app-CRe6n9br.js} +2 -2
- package/dist/simulator/assets/simulator-ui-BupATgKo.css +1 -0
- package/dist/simulator/assets/simulator-ui-C_cP602X.js +2 -0
- package/dist/simulator/simulator.html +3 -2
- package/dist/vscode-workbench/assets/__vite-browser-external-Bc1vizTf.js +1 -0
- package/dist/vscode-workbench/assets/{dist-oHcwN53f.js → dist-CMfmHflW.js} +3 -3
- package/dist/vscode-workbench/assets/{iconv-lite-umd-CLMLpdGm.js → iconv-lite-umd-Bx8CgaZq.js} +1 -1
- package/dist/vscode-workbench/assets/{index-BE3UJdoH.js → index-CdG6YWhW.js} +436 -436
- package/dist/vscode-workbench/assets/{jschardet-BICW8PLJ.js → jschardet-M0qgd2lN.js} +1 -1
- package/dist/vscode-workbench/index.html +21 -1
- package/package.json +7 -6
- package/dist/main/services/views/destroy-child-view.d.ts +0 -9
- package/dist/main/services/views/destroy-child-view.js +0 -23
- package/dist/renderer/assets/constants-EAMiwL9_.js +0 -2
- package/dist/renderer/assets/index-BBg3YI5b.js +0 -49
- package/dist/renderer/assets/ipc-transport-B3EpmfNS.js +0 -9
- package/dist/renderer/assets/ipc-transport-Blac3sOj.css +0 -1
- package/dist/renderer/assets/popover-B88e2hkg.js +0 -2
- package/dist/renderer/assets/select-CD9CJyhI.js +0 -2
- package/dist/renderer/assets/settings-44hf0QtO.js +0 -2
- package/dist/renderer/assets/settings-api-pJKPuP1M.js +0 -2
- package/dist/renderer/assets/workbenchSettings-DKD5U1Ql.js +0 -8
- package/dist/simulator/assets/device-shell-Cw7c-IkG.js +0 -2
- package/dist/simulator/assets/device-shell-DbC5ccs8.css +0 -1
- package/dist/simulator/assets/jsx-runtime-DkKmJyBb.js +0 -2
- package/dist/simulator/device-shell/menu-button-geometry.js +0 -18
- package/dist/vscode-workbench/assets/__vite-browser-external-BON7qP59.js +0 -1
|
@@ -1,150 +1,179 @@
|
|
|
1
1
|
import { WebContentsView } from 'electron';
|
|
2
|
-
import
|
|
2
|
+
import { createOverlayPanel } from '@dimina-kit/electron-deck/main';
|
|
3
3
|
import { mainPreloadPath } from '../../utils/paths.js';
|
|
4
4
|
import { applyNavigationHardening } from '../../windows/navigation-hardening.js';
|
|
5
5
|
import * as layout from '../layout/index.js';
|
|
6
6
|
import { HEADER_H } from '../../../shared/constants.js';
|
|
7
7
|
import { VIEW_ID, VIEW_LAYER } from '../../../shared/view-ids.js';
|
|
8
|
-
import { destroyChildView } from './destroy-child-view.js';
|
|
9
8
|
export function createOverlayPanelsView(ctx, reconciler, deps) {
|
|
10
|
-
let settingsView = null;
|
|
11
|
-
let popoverView = null;
|
|
12
9
|
function overlayHeaderHeight() {
|
|
13
10
|
return HEADER_H + deps.getHostToolbarHeight();
|
|
14
11
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
});
|
|
30
|
-
reconciler.reconcileNow();
|
|
31
|
-
}
|
|
32
|
-
function applyPopoverBounds() {
|
|
33
|
-
if (!popoverView || ctx.windows.mainWindow.isDestroyed())
|
|
34
|
-
return;
|
|
35
|
-
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
36
|
-
reconciler.setOverlayDesired(VIEW_ID.popover, {
|
|
37
|
-
viewId: VIEW_ID.popover,
|
|
38
|
-
placement: {
|
|
39
|
-
visible: true,
|
|
40
|
-
bounds: layout.computePopoverBounds(w, h, overlayHeaderHeight()),
|
|
41
|
-
},
|
|
42
|
-
layer: VIEW_LAYER.popover,
|
|
43
|
-
});
|
|
44
|
-
reconciler.reconcileNow();
|
|
12
|
+
function overlayDesiredSetter(viewId, layer) {
|
|
13
|
+
return (bounds) => {
|
|
14
|
+
if (bounds === null) {
|
|
15
|
+
reconciler.deleteOverlayDesired(viewId);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
reconciler.setOverlayDesired(viewId, {
|
|
19
|
+
viewId,
|
|
20
|
+
placement: { visible: true, bounds },
|
|
21
|
+
layer,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
reconciler.reconcileNow();
|
|
25
|
+
};
|
|
45
26
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
27
|
+
const settingsPanel = createOverlayPanel({
|
|
28
|
+
electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
|
|
29
|
+
rendererDir: ctx.rendererDir,
|
|
30
|
+
entry: 'entries/settings/index.html',
|
|
31
|
+
webPreferences: {
|
|
32
|
+
nodeIntegration: false,
|
|
33
|
+
contextIsolation: true,
|
|
34
|
+
sandbox: false,
|
|
35
|
+
preload: mainPreloadPath,
|
|
36
|
+
},
|
|
37
|
+
hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
|
|
38
|
+
setDesired: overlayDesiredSetter(VIEW_ID.settings, VIEW_LAYER.settings),
|
|
39
|
+
registerView: (getView) => reconciler.registerView(VIEW_ID.settings, { getView }),
|
|
40
|
+
destroyView: (view) => reconciler.destroyView(VIEW_ID.settings, view),
|
|
41
|
+
readyMode: 'manual',
|
|
42
|
+
});
|
|
43
|
+
const popoverPanel = createOverlayPanel({
|
|
44
|
+
electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
|
|
45
|
+
rendererDir: ctx.rendererDir,
|
|
46
|
+
entry: 'entries/popover/index.html',
|
|
47
|
+
webPreferences: {
|
|
48
|
+
nodeIntegration: false,
|
|
49
|
+
contextIsolation: true,
|
|
50
|
+
sandbox: false,
|
|
51
|
+
preload: mainPreloadPath,
|
|
52
|
+
},
|
|
53
|
+
hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
|
|
54
|
+
setDesired: overlayDesiredSetter(VIEW_ID.popover, VIEW_LAYER.popover),
|
|
55
|
+
registerView: (getView) => reconciler.registerView(VIEW_ID.popover, { getView }),
|
|
56
|
+
destroyView: (view) => reconciler.destroyView(VIEW_ID.popover, view),
|
|
57
|
+
pushData: (view, data) => ctx.notify.popoverInit(view, data),
|
|
58
|
+
readyMode: 'manual',
|
|
59
|
+
});
|
|
60
|
+
const tooltipPanel = createOverlayPanel({
|
|
61
|
+
electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
|
|
62
|
+
rendererDir: ctx.rendererDir,
|
|
63
|
+
entry: 'entries/tooltip/index.html',
|
|
64
|
+
webPreferences: {
|
|
65
|
+
nodeIntegration: false,
|
|
66
|
+
contextIsolation: true,
|
|
67
|
+
sandbox: false,
|
|
68
|
+
preload: mainPreloadPath,
|
|
69
|
+
},
|
|
70
|
+
hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
|
|
71
|
+
setDesired: overlayDesiredSetter(VIEW_ID.tooltip, VIEW_LAYER.tooltip),
|
|
72
|
+
registerView: (getView) => reconciler.registerView(VIEW_ID.tooltip, { getView }),
|
|
73
|
+
prepareView: (view) => {
|
|
74
|
+
const [width = 0, height = 0] = ctx.windows.mainWindow.getContentSize();
|
|
75
|
+
reconciler.prepareView(VIEW_ID.tooltip, view, {
|
|
76
|
+
x: 0,
|
|
77
|
+
y: 0,
|
|
78
|
+
width: Math.max(1, width),
|
|
79
|
+
height: Math.max(1, height),
|
|
55
80
|
});
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
81
|
+
},
|
|
82
|
+
destroyView: (view) => reconciler.destroyView(VIEW_ID.tooltip, view),
|
|
83
|
+
pushData: (view, data) => ctx.notify.tooltipInit(view, data),
|
|
84
|
+
readyMode: 'manual',
|
|
85
|
+
});
|
|
86
|
+
let tooltipRequestId = 0;
|
|
87
|
+
let activeTooltip = null;
|
|
88
|
+
async function showSettings() {
|
|
89
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
90
|
+
settingsPanel.show(undefined, layout.computeSettingsBounds(w, h, overlayHeaderHeight()));
|
|
91
|
+
await settingsPanel.whenReady();
|
|
67
92
|
}
|
|
68
93
|
function hideSettings() {
|
|
69
|
-
|
|
70
|
-
reconciler.reconcileNow();
|
|
94
|
+
settingsPanel.hide();
|
|
71
95
|
}
|
|
72
96
|
function showPopover(data) {
|
|
97
|
+
// Popover carries no state across opens (always fresh init data) — force a
|
|
98
|
+
// brand-new instance rather than reusing/repositioning a live one (and
|
|
99
|
+
// notify like any other close, via the shared hidePopover()).
|
|
73
100
|
hidePopover();
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
nodeIntegration: false,
|
|
77
|
-
contextIsolation: true,
|
|
78
|
-
sandbox: false,
|
|
79
|
-
preload: mainPreloadPath,
|
|
80
|
-
},
|
|
81
|
-
});
|
|
82
|
-
// Popover overlay loads mainPreloadPath — same navigation rules apply.
|
|
83
|
-
applyNavigationHardening(popover.webContents, ctx.rendererDir);
|
|
84
|
-
popoverView = popover;
|
|
85
|
-
popover.setBackgroundColor('#00000000');
|
|
86
|
-
applyPopoverBounds();
|
|
87
|
-
popover.webContents.once('did-finish-load', () => {
|
|
88
|
-
ctx.notify.popoverInit(popover, data);
|
|
89
|
-
});
|
|
90
|
-
popover.webContents.loadFile(path.join(ctx.rendererDir, 'entries/popover/index.html'));
|
|
101
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
102
|
+
popoverPanel.show(data, layout.computePopoverBounds(w, h, overlayHeaderHeight()));
|
|
91
103
|
}
|
|
92
104
|
function hidePopover() {
|
|
93
|
-
if (!
|
|
105
|
+
if (!popoverPanel.isPresent())
|
|
94
106
|
return;
|
|
107
|
+
popoverPanel.destroy();
|
|
95
108
|
reconciler.deleteOverlayDesired(VIEW_ID.popover);
|
|
96
|
-
// Destroy the WCV first (removeChildView + close), THEN reconcile: the detach
|
|
97
|
-
// op then finds the view already gone and does not double-removeChildView.
|
|
98
|
-
destroyChildView(ctx.windows.mainWindow, popoverView);
|
|
99
|
-
popoverView = null;
|
|
100
109
|
reconciler.reconcileNow();
|
|
101
110
|
ctx.notify.popoverClosed();
|
|
102
111
|
}
|
|
112
|
+
function prepareTooltip() {
|
|
113
|
+
tooltipPanel.prepare();
|
|
114
|
+
}
|
|
115
|
+
function showTooltip(data) {
|
|
116
|
+
const requestId = ++tooltipRequestId;
|
|
117
|
+
activeTooltip = { requestId, anchor: data.anchor };
|
|
118
|
+
const [contentWidth = 0] = ctx.windows.mainWindow.getContentSize();
|
|
119
|
+
tooltipPanel.show({
|
|
120
|
+
requestId,
|
|
121
|
+
text: data.text,
|
|
122
|
+
maxWidth: layout.computeTooltipMaxWidth(contentWidth),
|
|
123
|
+
}, null);
|
|
124
|
+
}
|
|
125
|
+
function hideTooltip() {
|
|
126
|
+
activeTooltip = null;
|
|
127
|
+
tooltipPanel.hide();
|
|
128
|
+
}
|
|
129
|
+
function markOverlayReady(webContentsId) {
|
|
130
|
+
settingsPanel.markReady(webContentsId);
|
|
131
|
+
popoverPanel.markReady(webContentsId);
|
|
132
|
+
tooltipPanel.markReady(webContentsId);
|
|
133
|
+
}
|
|
134
|
+
function applyTooltipMeasurement(webContentsId, measurement) {
|
|
135
|
+
const active = activeTooltip;
|
|
136
|
+
if (!active || active.requestId !== measurement.requestId)
|
|
137
|
+
return;
|
|
138
|
+
if (tooltipPanel.getWebContentsId() !== webContentsId)
|
|
139
|
+
return;
|
|
140
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
141
|
+
tooltipPanel.reposition(layout.computeTooltipBounds(active.anchor, w, h, measurement));
|
|
142
|
+
}
|
|
103
143
|
function reapplyPresentOverlays() {
|
|
104
|
-
if (reconciler.hasOverlayDesired(VIEW_ID.settings))
|
|
105
|
-
|
|
106
|
-
if (reconciler.hasOverlayDesired(VIEW_ID.popover))
|
|
107
|
-
|
|
144
|
+
if (settingsPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.settings))
|
|
145
|
+
void showSettings();
|
|
146
|
+
if (popoverPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.popover)) {
|
|
147
|
+
const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
|
|
148
|
+
popoverPanel.reposition(layout.computePopoverBounds(w, h, overlayHeaderHeight()));
|
|
149
|
+
}
|
|
108
150
|
}
|
|
109
151
|
function applySettingsBoundsIfPresent() {
|
|
110
|
-
if (reconciler.hasOverlayDesired(VIEW_ID.settings))
|
|
111
|
-
|
|
152
|
+
if (settingsPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.settings))
|
|
153
|
+
void showSettings();
|
|
112
154
|
}
|
|
113
155
|
function destroySettings() {
|
|
114
|
-
|
|
115
|
-
|
|
156
|
+
activeTooltip = null;
|
|
157
|
+
settingsPanel.destroy();
|
|
158
|
+
tooltipPanel.destroy();
|
|
116
159
|
}
|
|
117
|
-
reconciler.registerView(VIEW_ID.settings, { getView: () => settingsView });
|
|
118
|
-
reconciler.registerView(VIEW_ID.popover, { getView: () => popoverView });
|
|
119
160
|
return {
|
|
120
161
|
showSettings,
|
|
121
162
|
hideSettings,
|
|
122
163
|
showPopover,
|
|
123
164
|
hidePopover,
|
|
165
|
+
prepareTooltip,
|
|
166
|
+
showTooltip,
|
|
167
|
+
hideTooltip,
|
|
168
|
+
markOverlayReady,
|
|
169
|
+
applyTooltipMeasurement,
|
|
124
170
|
reapplyPresentOverlays,
|
|
125
171
|
applySettingsBoundsIfPresent,
|
|
126
172
|
destroySettings,
|
|
127
|
-
getSettingsWebContents: () =>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return null;
|
|
132
|
-
return settingsView.webContents;
|
|
133
|
-
},
|
|
134
|
-
getSettingsWebContentsId: () => {
|
|
135
|
-
if (!settingsView)
|
|
136
|
-
return null;
|
|
137
|
-
if (settingsView.webContents.isDestroyed())
|
|
138
|
-
return null;
|
|
139
|
-
return settingsView.webContents.id;
|
|
140
|
-
},
|
|
141
|
-
getPopoverWebContentsId: () => {
|
|
142
|
-
if (!popoverView)
|
|
143
|
-
return null;
|
|
144
|
-
if (popoverView.webContents.isDestroyed())
|
|
145
|
-
return null;
|
|
146
|
-
return popoverView.webContents.id;
|
|
147
|
-
},
|
|
173
|
+
getSettingsWebContents: () => settingsPanel.getWebContents(),
|
|
174
|
+
getSettingsWebContentsId: () => settingsPanel.getWebContentsId(),
|
|
175
|
+
getPopoverWebContentsId: () => popoverPanel.getWebContentsId(),
|
|
176
|
+
getTooltipWebContentsId: () => tooltipPanel.getWebContentsId(),
|
|
148
177
|
};
|
|
149
178
|
}
|
|
150
179
|
//# sourceMappingURL=overlay-panels-view.js.map
|
|
@@ -12,8 +12,6 @@ import type { ViewManagerContext } from './view-manager.js';
|
|
|
12
12
|
export interface ViewSlot {
|
|
13
13
|
/** The live WebContentsView for this slot, or null when not yet created. */
|
|
14
14
|
getView(): WebContentsView | null;
|
|
15
|
-
/** Record whether the view is currently added to the contentView. */
|
|
16
|
-
setAdded?(added: boolean): void;
|
|
17
15
|
/**
|
|
18
16
|
* When true, force the desired placement to hidden — the view-creation site
|
|
19
17
|
* has not produced the WCV yet, so the reconciler must never record an attach
|
|
@@ -21,12 +19,6 @@ export interface ViewSlot {
|
|
|
21
19
|
* to re-open the gate.
|
|
22
20
|
*/
|
|
23
21
|
gateHidden?(): boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Run before the generic attach. Return true when the slot fully handled the
|
|
26
|
-
* attach itself (e.g. a lazy async load that adds the view on completion), so
|
|
27
|
-
* the reconciler must NOT addChildView here.
|
|
28
|
-
*/
|
|
29
|
-
beforeAttach?(): boolean;
|
|
30
22
|
/** Lazily create the view on attach (host-toolbar); used instead of getView. */
|
|
31
23
|
ensureView?(): WebContentsView | null;
|
|
32
24
|
/** Domain-specific setBounds (simulator zoom rides here). */
|
|
@@ -55,14 +47,10 @@ export interface PlacementReconciler {
|
|
|
55
47
|
* truth for every managed native view's bounds/visibility/z-order.
|
|
56
48
|
*/
|
|
57
49
|
setPlacementSnapshot(snapshot: PlacementSnapshot<DevtoolsExtra>): void;
|
|
58
|
-
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
* level-triggered core still records the old instance as attached and never
|
|
63
|
-
* emits the attach op for the replacement — a sticky invisible view).
|
|
64
|
-
*/
|
|
65
|
-
forgetActual(viewId: string): void;
|
|
50
|
+
/** Size a detached view for renderer-side intrinsic measurement. */
|
|
51
|
+
prepareView(viewId: string, view: WebContentsView, bounds: layout.Bounds): void;
|
|
52
|
+
/** Detach and close one concrete view instance through the native-tree owner. */
|
|
53
|
+
destroyView(viewId: string, view: WebContentsView | null): void;
|
|
66
54
|
setBaseDesired(viewId: string, desired: DesiredView<DevtoolsExtra>): void;
|
|
67
55
|
deleteBaseDesired(viewId: string): void;
|
|
68
56
|
setOverlayDesired(viewId: string, desired: DesiredView<DevtoolsExtra>): void;
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { reconcile, createInitialState } from '@dimina-kit/electron-deck/layout';
|
|
2
2
|
import { applyViewOps } from './apply-view-ops.js';
|
|
3
|
+
import { createNativeViewTreeHost } from './native-view-tree.js';
|
|
3
4
|
export function createPlacementReconciler(ctx) {
|
|
4
5
|
let placementState = createInitialState();
|
|
5
6
|
let epochCounter = 0;
|
|
6
7
|
let rendererGeneration = 0;
|
|
8
|
+
const appliedActual = new Map();
|
|
7
9
|
const baseDesired = new Map();
|
|
8
10
|
const overlayDesired = new Map();
|
|
9
11
|
const slots = new Map();
|
|
12
|
+
// Sole owner of the main window's native child tree. Every attach, detach,
|
|
13
|
+
// reorder and hard destroy passes through this ledger-backed adapter.
|
|
14
|
+
const contentViewHost = createNativeViewTreeHost(ctx, slots);
|
|
10
15
|
function gateReadiness(v) {
|
|
11
16
|
const slot = slots.get(v.viewId);
|
|
12
17
|
if (slot?.gateHidden?.())
|
|
@@ -20,59 +25,67 @@ export function createPlacementReconciler(ctx) {
|
|
|
20
25
|
const slot = slots.get(viewId);
|
|
21
26
|
if (!slot)
|
|
22
27
|
return;
|
|
23
|
-
if (slot.beforeAttach?.())
|
|
24
|
-
return;
|
|
25
28
|
const view = slot.ensureView ? slot.ensureView() : slot.getView();
|
|
26
29
|
if (!view)
|
|
27
30
|
return;
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
if (!contentViewHost.addChildView({ id: viewId }))
|
|
32
|
+
return;
|
|
33
|
+
const previous = appliedActual.get(viewId);
|
|
34
|
+
appliedActual.set(viewId, {
|
|
35
|
+
attached: true,
|
|
36
|
+
visible: true,
|
|
37
|
+
bounds: previous?.bounds,
|
|
38
|
+
extra: previous?.extra,
|
|
39
|
+
});
|
|
30
40
|
},
|
|
31
41
|
detach(viewId) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
ctx.windows.mainWindow.contentView.removeChildView(view);
|
|
37
|
-
}
|
|
38
|
-
catch { /* already removed */ }
|
|
39
|
-
}
|
|
40
|
-
slot?.setAdded?.(false);
|
|
42
|
+
if (!contentViewHost.removeChildView({ id: viewId }))
|
|
43
|
+
return;
|
|
44
|
+
appliedActual.delete(viewId);
|
|
41
45
|
},
|
|
42
46
|
setBounds(viewId, bounds, extra) {
|
|
43
47
|
const slot = slots.get(viewId);
|
|
44
48
|
const view = slot?.getView() ?? null;
|
|
45
49
|
if (!view || view.webContents.isDestroyed())
|
|
46
50
|
return;
|
|
47
|
-
|
|
48
|
-
slot
|
|
51
|
+
try {
|
|
52
|
+
if (slot?.applyBounds)
|
|
53
|
+
slot.applyBounds(view, bounds, extra);
|
|
54
|
+
else
|
|
55
|
+
view.setBounds(bounds);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
49
58
|
return;
|
|
50
59
|
}
|
|
51
|
-
|
|
60
|
+
const previous = appliedActual.get(viewId);
|
|
61
|
+
appliedActual.set(viewId, {
|
|
62
|
+
attached: previous?.attached ?? false,
|
|
63
|
+
visible: previous?.visible ?? false,
|
|
64
|
+
bounds,
|
|
65
|
+
extra,
|
|
66
|
+
});
|
|
52
67
|
},
|
|
53
68
|
setVisible(viewId, visible) {
|
|
54
69
|
const view = slots.get(viewId)?.getView() ?? null;
|
|
55
|
-
if (!view)
|
|
70
|
+
if (!view || view.webContents.isDestroyed())
|
|
56
71
|
return;
|
|
57
72
|
try {
|
|
58
73
|
view.setVisible(visible);
|
|
59
74
|
}
|
|
60
|
-
catch {
|
|
75
|
+
catch {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const previous = appliedActual.get(viewId);
|
|
79
|
+
if (!previous)
|
|
80
|
+
return;
|
|
81
|
+
appliedActual.set(viewId, { ...previous, visible });
|
|
61
82
|
},
|
|
62
83
|
reorder(order) {
|
|
63
84
|
// A single attached view is already in place — nothing to reorder.
|
|
64
85
|
if (order.length <= 1 || ctx.windows.mainWindow.isDestroyed())
|
|
65
86
|
return;
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
const view = slots.get(viewId)?.getView() ?? null;
|
|
69
|
-
if (view) {
|
|
70
|
-
try {
|
|
71
|
-
cv.addChildView(view);
|
|
72
|
-
}
|
|
73
|
-
catch { /* already attached */ }
|
|
74
|
-
}
|
|
75
|
-
}
|
|
87
|
+
for (const viewId of order)
|
|
88
|
+
contentViewHost.addChildView({ id: viewId });
|
|
76
89
|
},
|
|
77
90
|
};
|
|
78
91
|
// Create the lazily-built views (host-toolbar, workbench) BEFORE reconcile so
|
|
@@ -83,6 +96,9 @@ export function createPlacementReconciler(ctx) {
|
|
|
83
96
|
slot.ensureLazy?.(baseDesired.get(viewId));
|
|
84
97
|
}
|
|
85
98
|
}
|
|
99
|
+
function cloneAppliedActual() {
|
|
100
|
+
return new Map([...appliedActual].map(([viewId, actual]) => [viewId, { ...actual }]));
|
|
101
|
+
}
|
|
86
102
|
function reconcileNow() {
|
|
87
103
|
ensureLazyViews();
|
|
88
104
|
const views = [];
|
|
@@ -90,6 +106,7 @@ export function createPlacementReconciler(ctx) {
|
|
|
90
106
|
views.push(gateReadiness(v));
|
|
91
107
|
for (const v of overlayDesired.values())
|
|
92
108
|
views.push(v);
|
|
109
|
+
placementState = { ...placementState, actual: cloneAppliedActual() };
|
|
93
110
|
const result = reconcile(placementState, {
|
|
94
111
|
generation: rendererGeneration,
|
|
95
112
|
epoch: ++epochCounter,
|
|
@@ -97,6 +114,9 @@ export function createPlacementReconciler(ctx) {
|
|
|
97
114
|
});
|
|
98
115
|
placementState = result.state;
|
|
99
116
|
applyViewOps(result.ops, viewTarget);
|
|
117
|
+
// The planner's next state is optimistic. Keep only desired/epoch metadata;
|
|
118
|
+
// appliedActual is updated by successful native effects above.
|
|
119
|
+
placementState = { ...placementState, actual: cloneAppliedActual() };
|
|
100
120
|
}
|
|
101
121
|
function setPlacementSnapshot(snapshot) {
|
|
102
122
|
rendererGeneration = snapshot.generation;
|
|
@@ -109,7 +129,22 @@ export function createPlacementReconciler(ctx) {
|
|
|
109
129
|
registerView: (viewId, slot) => { slots.set(viewId, slot); },
|
|
110
130
|
reconcileNow,
|
|
111
131
|
setPlacementSnapshot,
|
|
112
|
-
|
|
132
|
+
prepareView: (viewId, view, bounds) => {
|
|
133
|
+
if (slots.get(viewId)?.getView() !== view || view.webContents.isDestroyed())
|
|
134
|
+
return;
|
|
135
|
+
try {
|
|
136
|
+
view.setBounds(bounds);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
appliedActual.set(viewId, { attached: false, visible: false, bounds });
|
|
142
|
+
},
|
|
143
|
+
destroyView: (viewId, view) => {
|
|
144
|
+
contentViewHost.destroyView(viewId, view);
|
|
145
|
+
appliedActual.delete(viewId);
|
|
146
|
+
placementState.actual.delete(viewId);
|
|
147
|
+
},
|
|
113
148
|
setBaseDesired: (viewId, desired) => { baseDesired.set(viewId, desired); },
|
|
114
149
|
deleteBaseDesired: (viewId) => { baseDesired.delete(viewId); },
|
|
115
150
|
setOverlayDesired: (viewId, desired) => { overlayDesired.set(viewId, desired); },
|
|
@@ -13,9 +13,35 @@ interface SnapshotSink {
|
|
|
13
13
|
views: DesiredView<DevtoolsExtra>[];
|
|
14
14
|
}): void;
|
|
15
15
|
}
|
|
16
|
+
interface OverlaySink {
|
|
17
|
+
showSettings(): Promise<void>;
|
|
18
|
+
showPopover(data: unknown): void;
|
|
19
|
+
showTooltip(data: {
|
|
20
|
+
anchor: Rect;
|
|
21
|
+
text: string;
|
|
22
|
+
}): void;
|
|
23
|
+
getSettingsWebContentsId(): number | null;
|
|
24
|
+
getPopoverWebContentsId(): number | null;
|
|
25
|
+
getTooltipWebContentsId(): number | null;
|
|
26
|
+
markOverlayReady(webContentsId: number): void;
|
|
27
|
+
applyTooltipMeasurement(webContentsId: number, measurement: {
|
|
28
|
+
requestId: number;
|
|
29
|
+
width: number;
|
|
30
|
+
height: number;
|
|
31
|
+
}): void;
|
|
32
|
+
}
|
|
16
33
|
export declare function hostToolbarBounds(mgr: SnapshotSink, rect: Rect): void;
|
|
17
34
|
export declare function simulatorDevtoolsBounds(mgr: SnapshotSink, rect: Rect): void;
|
|
18
35
|
export declare function workbenchBounds(mgr: SnapshotSink, rect: Rect): void;
|
|
36
|
+
export declare function showSettingsReady(mgr: OverlaySink): Promise<void>;
|
|
37
|
+
export declare function showPopoverReady(mgr: OverlaySink, data: unknown): void;
|
|
38
|
+
export declare function showTooltipReady(mgr: OverlaySink, data: {
|
|
39
|
+
anchor: Rect;
|
|
40
|
+
text: string;
|
|
41
|
+
}, size?: {
|
|
42
|
+
width: number;
|
|
43
|
+
height: number;
|
|
44
|
+
}): void;
|
|
19
45
|
export declare function simulatorBounds(mgr: SnapshotSink, params: Rect & {
|
|
20
46
|
zoom: number;
|
|
21
47
|
}): void;
|
|
@@ -12,6 +12,7 @@ import { VIEW_ID, VIEW_LAYER } from '../../../shared/view-ids.js';
|
|
|
12
12
|
// pushes on one manager never look stale.
|
|
13
13
|
let globalEpoch = 0;
|
|
14
14
|
const desiredByMgr = new WeakMap();
|
|
15
|
+
const tooltipRequestByMgr = new WeakMap();
|
|
15
16
|
function toPlacement(r) {
|
|
16
17
|
return r.width > 0 && r.height > 0 ? { visible: true, bounds: r } : { visible: false };
|
|
17
18
|
}
|
|
@@ -33,6 +34,31 @@ export function simulatorDevtoolsBounds(mgr, rect) {
|
|
|
33
34
|
export function workbenchBounds(mgr, rect) {
|
|
34
35
|
pushView(mgr, { viewId: VIEW_ID.workbench, placement: toPlacement(rect), layer: VIEW_LAYER.base });
|
|
35
36
|
}
|
|
37
|
+
export async function showSettingsReady(mgr) {
|
|
38
|
+
const shown = mgr.showSettings();
|
|
39
|
+
const webContentsId = mgr.getSettingsWebContentsId();
|
|
40
|
+
if (webContentsId === null)
|
|
41
|
+
throw new Error('settings view was not created');
|
|
42
|
+
mgr.markOverlayReady(webContentsId);
|
|
43
|
+
await shown;
|
|
44
|
+
}
|
|
45
|
+
export function showPopoverReady(mgr, data) {
|
|
46
|
+
mgr.showPopover(data);
|
|
47
|
+
const webContentsId = mgr.getPopoverWebContentsId();
|
|
48
|
+
if (webContentsId === null)
|
|
49
|
+
throw new Error('popover view was not created');
|
|
50
|
+
mgr.markOverlayReady(webContentsId);
|
|
51
|
+
}
|
|
52
|
+
export function showTooltipReady(mgr, data, size = { width: 80, height: 28 }) {
|
|
53
|
+
mgr.showTooltip(data);
|
|
54
|
+
const webContentsId = mgr.getTooltipWebContentsId();
|
|
55
|
+
if (webContentsId === null)
|
|
56
|
+
throw new Error('tooltip view was not created');
|
|
57
|
+
mgr.markOverlayReady(webContentsId);
|
|
58
|
+
const requestId = (tooltipRequestByMgr.get(mgr) ?? 0) + 1;
|
|
59
|
+
tooltipRequestByMgr.set(mgr, requestId);
|
|
60
|
+
mgr.applyTooltipMeasurement(webContentsId, { requestId, ...size });
|
|
61
|
+
}
|
|
36
62
|
export function simulatorBounds(mgr, params) {
|
|
37
63
|
const { zoom, ...rect } = params;
|
|
38
64
|
pushView(mgr, { viewId: VIEW_ID.simulator, placement: toPlacement(rect), layer: VIEW_LAYER.base, extra: { zoom } });
|
|
@@ -4,6 +4,8 @@ import { type WorkbenchContext } from '../workbench-context.js';
|
|
|
4
4
|
import type { HostToolbarMessageSubscription } from './host-toolbar-port-channel.js';
|
|
5
5
|
import type { PlacementSnapshot } from '@dimina-kit/electron-deck/layout';
|
|
6
6
|
import type { DevtoolsExtra } from '../../../shared/view-ids.js';
|
|
7
|
+
import { type OverlayPanelsView, type TooltipShowPayload } from './overlay-panels-view.js';
|
|
8
|
+
export type { TooltipShowPayload };
|
|
7
9
|
export { resolveProjectEditorTarget, type ProjectEditorTarget, } from './resolve-project-editor-target.js';
|
|
8
10
|
/**
|
|
9
11
|
* Context surface used by the ViewManager. We only need a small slice of the
|
|
@@ -89,7 +91,7 @@ export interface ViewManagerContext {
|
|
|
89
91
|
* panels) and shares a single injected placement reconciler; this file wires
|
|
90
92
|
* them together and exposes their combined method surface.
|
|
91
93
|
*/
|
|
92
|
-
export interface ViewManager {
|
|
94
|
+
export interface ViewManager extends Pick<OverlayPanelsView, 'showSettings' | 'hideSettings' | 'showPopover' | 'hidePopover' | 'prepareTooltip' | 'showTooltip' | 'hideTooltip' | 'markOverlayReady' | 'applyTooltipMeasurement'> {
|
|
93
95
|
/**
|
|
94
96
|
* NATIVE-HOST ONLY. Create the simulator itself as a top-level
|
|
95
97
|
* WebContentsView (not a renderer `<webview>` guest) loading `simulatorUrl`,
|
|
@@ -132,14 +134,6 @@ export interface ViewManager {
|
|
|
132
134
|
* `windows/views.ts` module, which every detach call relied on.
|
|
133
135
|
*/
|
|
134
136
|
detachSimulator(): void;
|
|
135
|
-
/** Lazy-create and show the settings overlay view. */
|
|
136
|
-
showSettings(): Promise<void>;
|
|
137
|
-
/** Remove the settings overlay view (kept around for next open). */
|
|
138
|
-
hideSettings(): void;
|
|
139
|
-
/** Create and show the popover overlay with the given init payload. */
|
|
140
|
-
showPopover(data: unknown): void;
|
|
141
|
-
/** Destroy the popover overlay and notify the renderer. */
|
|
142
|
-
hidePopover(): void;
|
|
143
137
|
/** Re-apply layout for every currently visible overlay (on window resize). */
|
|
144
138
|
repositionAll(): void;
|
|
145
139
|
/**
|
|
@@ -170,6 +164,8 @@ export interface ViewManager {
|
|
|
170
164
|
getSettingsWebContentsId(): number | null;
|
|
171
165
|
/** Return the webContents ID of the popover overlay if alive, else null. */
|
|
172
166
|
getPopoverWebContentsId(): number | null;
|
|
167
|
+
/** Return the webContents ID of the tooltip overlay if alive, else null. */
|
|
168
|
+
getTooltipWebContentsId(): number | null;
|
|
173
169
|
/**
|
|
174
170
|
* Return the webContents ID of the host-toolbar overlay if alive, else null.
|
|
175
171
|
* The host-toolbar WCV is the one overlay whose OWN renderer drives an IPC
|
|
@@ -3,7 +3,7 @@ import { createPlacementReconciler } from './placement-reconciler.js';
|
|
|
3
3
|
import { createWorkbenchView } from './workbench-view.js';
|
|
4
4
|
import { createDevtoolsHost } from './native-simulator-devtools-host.js';
|
|
5
5
|
import { createHostToolbarView } from './host-toolbar-view.js';
|
|
6
|
-
import { createOverlayPanelsView } from './overlay-panels-view.js';
|
|
6
|
+
import { createOverlayPanelsView, } from './overlay-panels-view.js';
|
|
7
7
|
import { createNativeSimulatorView } from './native-simulator-view.js';
|
|
8
8
|
export { resolveProjectEditorTarget, } from './resolve-project-editor-target.js';
|
|
9
9
|
/**
|
|
@@ -77,6 +77,11 @@ export function createViewManager(ctx) {
|
|
|
77
77
|
hideSettings: overlayPanels.hideSettings,
|
|
78
78
|
showPopover: overlayPanels.showPopover,
|
|
79
79
|
hidePopover: overlayPanels.hidePopover,
|
|
80
|
+
prepareTooltip: overlayPanels.prepareTooltip,
|
|
81
|
+
showTooltip: overlayPanels.showTooltip,
|
|
82
|
+
hideTooltip: overlayPanels.hideTooltip,
|
|
83
|
+
markOverlayReady: overlayPanels.markOverlayReady,
|
|
84
|
+
applyTooltipMeasurement: overlayPanels.applyTooltipMeasurement,
|
|
80
85
|
repositionAll: () => overlayPanels.reapplyPresentOverlays(),
|
|
81
86
|
disposeProjectViews,
|
|
82
87
|
disposeAll,
|
|
@@ -86,6 +91,7 @@ export function createViewManager(ctx) {
|
|
|
86
91
|
getSettingsWebContents: overlayPanels.getSettingsWebContents,
|
|
87
92
|
getSettingsWebContentsId: overlayPanels.getSettingsWebContentsId,
|
|
88
93
|
getPopoverWebContentsId: overlayPanels.getPopoverWebContentsId,
|
|
94
|
+
getTooltipWebContentsId: overlayPanels.getTooltipWebContentsId,
|
|
89
95
|
getHostToolbarWebContentsId: hostToolbar.getHostToolbarWebContentsId,
|
|
90
96
|
getHostToolbarHeight: hostToolbar.getHostToolbarHeight,
|
|
91
97
|
resize: () => overlayPanels.applySettingsBoundsIfPresent(),
|