@dimina-kit/devtools 0.4.0-dev.20260803105710 → 0.4.0-dev.20260828092243

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/dist/main/api.d.ts +1 -1
  2. package/dist/main/app/app.js +66 -2
  3. package/dist/main/index.bundle.js +1454 -540
  4. package/dist/main/ipc/index.d.ts +3 -0
  5. package/dist/main/ipc/index.js +3 -0
  6. package/dist/main/ipc/popover.js +1 -1
  7. package/dist/main/ipc/project-create.d.ts +15 -0
  8. package/dist/main/ipc/project-create.js +26 -0
  9. package/dist/main/ipc/projects.d.ts +1 -1
  10. package/dist/main/ipc/projects.js +11 -0
  11. package/dist/main/ipc/session.js +11 -0
  12. package/dist/main/ipc/settings.js +2 -1
  13. package/dist/main/ipc/simulator-module.d.ts +4 -3
  14. package/dist/main/ipc/simulator-module.js +4 -5
  15. package/dist/main/ipc/tooltip.d.ts +13 -0
  16. package/dist/main/ipc/tooltip.js +28 -0
  17. package/dist/main/ipc/views.d.ts +15 -1
  18. package/dist/main/ipc/views.js +61 -4
  19. package/dist/main/runtime/miniapp-runtime.d.ts +87 -19
  20. package/dist/main/services/layout/index.d.ts +11 -0
  21. package/dist/main/services/layout/index.js +23 -0
  22. package/dist/main/services/network-forward/frontend-dispatch.js +2 -1
  23. package/dist/main/services/notifications/renderer-notifier.d.ts +32 -1
  24. package/dist/main/services/notifications/renderer-notifier.js +29 -1
  25. package/dist/main/services/projects/project-repository.d.ts +4 -1
  26. package/dist/main/services/projects/project-repository.js +63 -5
  27. package/dist/main/services/simulator-current-page/index.d.ts +5 -3
  28. package/dist/main/services/simulator-current-page/index.js +8 -1
  29. package/dist/main/services/update/update-manager.d.ts +17 -3
  30. package/dist/main/services/update/update-manager.js +25 -6
  31. package/dist/main/services/views/clear-console-filter.d.ts +44 -0
  32. package/dist/main/services/views/clear-console-filter.js +86 -0
  33. package/dist/main/services/views/console-filter-test-fixtures.d.ts +94 -0
  34. package/dist/main/services/views/console-filter-test-fixtures.js +82 -0
  35. package/dist/main/services/views/console-filter.d.ts +79 -130
  36. package/dist/main/services/views/console-filter.js +140 -183
  37. package/dist/main/services/views/devtools-tabs.d.ts +24 -4
  38. package/dist/main/services/views/devtools-tabs.js +40 -21
  39. package/dist/main/services/views/host-dialog-port-channel.d.ts +18 -0
  40. package/dist/main/services/views/host-dialog-port-channel.js +15 -0
  41. package/dist/main/services/views/host-dialog-session-runtime.d.ts +10 -0
  42. package/dist/main/services/views/host-dialog-session-runtime.js +17 -0
  43. package/dist/main/services/views/host-dialog-view.d.ts +95 -0
  44. package/dist/main/services/views/host-dialog-view.js +147 -0
  45. package/dist/main/services/views/host-sidebar-port-channel.d.ts +18 -0
  46. package/dist/main/services/views/host-sidebar-port-channel.js +15 -0
  47. package/dist/main/services/views/host-sidebar-session-runtime.d.ts +10 -0
  48. package/dist/main/services/views/host-sidebar-session-runtime.js +17 -0
  49. package/dist/main/services/views/host-sidebar-view.d.ts +59 -0
  50. package/dist/main/services/views/host-sidebar-view.js +44 -0
  51. package/dist/main/services/views/host-slot-port-channel.d.ts +107 -0
  52. package/dist/main/services/views/host-slot-port-channel.js +261 -0
  53. package/dist/main/services/views/host-slot-session-runtime.d.ts +40 -0
  54. package/dist/main/services/views/host-slot-session-runtime.js +50 -0
  55. package/dist/main/services/views/host-slot-view.d.ts +109 -0
  56. package/dist/main/services/views/host-slot-view.js +147 -0
  57. package/dist/main/services/views/host-toolbar-port-channel.d.ts +6 -91
  58. package/dist/main/services/views/host-toolbar-port-channel.js +10 -243
  59. package/dist/main/services/views/host-toolbar-session-runtime.d.ts +5 -30
  60. package/dist/main/services/views/host-toolbar-session-runtime.js +9 -47
  61. package/dist/main/services/views/host-toolbar-view.d.ts +34 -7
  62. package/dist/main/services/views/host-toolbar-view.js +30 -237
  63. package/dist/main/services/views/managed-web-contents-view.d.ts +48 -0
  64. package/dist/main/services/views/managed-web-contents-view.js +123 -0
  65. package/dist/main/services/views/native-simulator-devtools-host.js +64 -45
  66. package/dist/main/services/views/native-simulator-view.js +6 -24
  67. package/dist/main/services/views/native-view-tree.d.ts +25 -0
  68. package/dist/main/services/views/native-view-tree.js +69 -0
  69. package/dist/main/services/views/overlay-panels-view.d.ts +50 -4
  70. package/dist/main/services/views/overlay-panels-view.js +226 -108
  71. package/dist/main/services/views/placement-reconciler.d.ts +18 -18
  72. package/dist/main/services/views/placement-reconciler.js +91 -29
  73. package/dist/main/services/views/placement-test-driver.d.ts +27 -0
  74. package/dist/main/services/views/placement-test-driver.js +29 -0
  75. package/dist/main/services/views/view-manager-devtools-host-test-fixtures.js +3 -1
  76. package/dist/main/services/views/view-manager.d.ts +14 -86
  77. package/dist/main/services/views/view-manager.js +41 -4
  78. package/dist/main/services/views/workbench-view.js +27 -20
  79. package/dist/main/services/workbench-coi-server.d.ts +11 -0
  80. package/dist/main/services/workbench-coi-server.js +32 -0
  81. package/dist/main/services/workspace/rebuild-status.d.ts +21 -8
  82. package/dist/main/services/workspace/rebuild-status.js +24 -8
  83. package/dist/main/utils/paths.d.ts +4 -0
  84. package/dist/main/utils/paths.js +4 -0
  85. package/dist/main/utils/sender-policy.d.ts +1 -1
  86. package/dist/main/utils/sender-policy.js +16 -1
  87. package/dist/main/utils/theme.d.ts +7 -2
  88. package/dist/main/utils/theme.js +8 -3
  89. package/dist/native-host/common/common.js +65 -62
  90. package/dist/native-host/container/pageFrame.css +1 -1
  91. package/dist/native-host/render/render.js +3226 -2898
  92. package/dist/native-host/service/service.js +2 -2
  93. package/dist/preload/runtime/host-dialog-advertiser.d.ts +22 -0
  94. package/dist/preload/runtime/host-dialog-advertiser.js +37 -0
  95. package/dist/preload/runtime/host-dialog-port.d.ts +44 -0
  96. package/dist/preload/runtime/host-dialog-port.js +53 -0
  97. package/dist/preload/runtime/host-dialog-runtime.d.ts +28 -0
  98. package/dist/preload/runtime/host-dialog-runtime.js +36 -0
  99. package/dist/preload/runtime/host-sidebar-advertiser.d.ts +19 -0
  100. package/dist/preload/runtime/host-sidebar-advertiser.js +35 -0
  101. package/dist/preload/runtime/host-sidebar-port.d.ts +44 -0
  102. package/dist/preload/runtime/host-sidebar-port.js +53 -0
  103. package/dist/preload/runtime/host-sidebar-runtime.d.ts +28 -0
  104. package/dist/preload/runtime/host-sidebar-runtime.js +36 -0
  105. package/dist/preload/runtime/host-slot-port-bridge.d.ts +18 -0
  106. package/dist/preload/runtime/host-slot-port-bridge.js +112 -0
  107. package/dist/preload/runtime/host-toolbar-advertiser.d.ts +5 -13
  108. package/dist/preload/runtime/host-toolbar-advertiser.js +18 -38
  109. package/dist/preload/runtime/host-toolbar-port.d.ts +9 -0
  110. package/dist/preload/runtime/host-toolbar-port.js +11 -95
  111. package/dist/preload/runtime/wait-for-slot-root.d.ts +20 -0
  112. package/dist/preload/runtime/wait-for-slot-root.js +52 -0
  113. package/dist/preload/windows/host-dialog-runtime.cjs +353 -0
  114. package/dist/preload/windows/host-dialog-runtime.cjs.map +7 -0
  115. package/dist/preload/windows/host-dialog-runtime.d.ts +2 -0
  116. package/dist/preload/windows/host-dialog-runtime.js +13 -0
  117. package/dist/preload/windows/host-sidebar-runtime.cjs +354 -0
  118. package/dist/preload/windows/host-sidebar-runtime.cjs.map +7 -0
  119. package/dist/preload/windows/host-sidebar-runtime.d.ts +2 -0
  120. package/dist/preload/windows/host-sidebar-runtime.js +13 -0
  121. package/dist/preload/windows/host-toolbar-runtime.cjs +134 -51
  122. package/dist/preload/windows/host-toolbar-runtime.cjs.map +3 -3
  123. package/dist/preload/windows/main.cjs +3176 -14
  124. package/dist/preload/windows/main.cjs.map +4 -4
  125. package/dist/preload/windows/main.css +428 -0
  126. package/dist/preload/windows/main.css.map +7 -0
  127. package/dist/preload/windows/simulator.cjs +5 -2
  128. package/dist/preload/windows/simulator.cjs.map +2 -2
  129. package/dist/preload/windows/simulator.js +5 -2
  130. package/dist/renderer/assets/button-DsNqZm7o.js +2 -0
  131. package/dist/renderer/assets/constants-D7DfVqMp.js +2 -0
  132. package/dist/renderer/assets/constants-D8zsejFq.js +2 -0
  133. package/dist/renderer/assets/createLucideIcon-CYJeT1ji.js +2 -0
  134. package/dist/renderer/assets/dialog-pT4qWmka.js +46 -0
  135. package/dist/renderer/assets/dist-o70xmpc1.js +2 -0
  136. package/dist/renderer/assets/hostSidebarDefault-NvGZlE9O.js +2 -0
  137. package/dist/renderer/assets/index-zErhG3ta.js +5 -0
  138. package/dist/renderer/assets/input-4QxTXMZN.js +2 -0
  139. package/dist/renderer/assets/ipc-channels-overlays-Blr5TNoB.js +2 -0
  140. package/dist/renderer/assets/jsx-runtime-B-3rq1y5.css +1 -0
  141. package/dist/renderer/assets/jsx-runtime-CqVdW3eg.js +9 -0
  142. package/dist/renderer/assets/popover-CJiSWwuE.js +2 -0
  143. package/dist/renderer/assets/project-api-DZ1Zi6EC.js +2 -0
  144. package/dist/renderer/assets/projectCreateDialog-DMWNhw_1.js +2 -0
  145. package/dist/renderer/assets/select-C86pNcsu.js +2 -0
  146. package/dist/renderer/assets/settings-BoI8mLT1.js +2 -0
  147. package/dist/renderer/assets/settings-api-Bs_g4NHs.js +2 -0
  148. package/dist/renderer/assets/settings-tab-bar-DHLLygqv.js +2 -0
  149. package/dist/renderer/assets/tooltip-BhAyY0T4.js +2 -0
  150. package/dist/renderer/assets/types-YYjkvane.js +2 -0
  151. package/dist/renderer/assets/updateDialog-DPum3wx1.js +2 -0
  152. package/dist/renderer/assets/utils-kfQov6Pa.js +2 -0
  153. package/dist/renderer/assets/view-api-DFhb2R8-.js +2 -0
  154. package/dist/renderer/assets/workbenchSettings-DrajRQUk.js +8 -0
  155. package/dist/renderer/entries/host-sidebar-default/index.html +21 -0
  156. package/dist/renderer/entries/main/index.html +15 -7
  157. package/dist/renderer/entries/popover/index.html +10 -6
  158. package/dist/renderer/entries/project-create-dialog/index.html +27 -0
  159. package/dist/renderer/entries/settings/index.html +10 -5
  160. package/dist/renderer/entries/tooltip/index.html +21 -0
  161. package/dist/renderer/entries/update-dialog/index.html +25 -0
  162. package/dist/renderer/entries/workbench-settings/index.html +11 -5
  163. package/dist/service-host/preload.cjs +10 -0
  164. package/dist/service-host/sync-impls/menu-button-geometry.js +1 -0
  165. package/dist/shared/constants.d.ts +22 -0
  166. package/dist/shared/constants.js +22 -0
  167. package/dist/shared/ipc-channels-overlays.d.ts +156 -0
  168. package/dist/shared/ipc-channels-overlays.js +186 -0
  169. package/dist/shared/ipc-channels.d.ts +1 -67
  170. package/dist/shared/ipc-channels.js +9 -81
  171. package/dist/shared/ipc-schemas.d.ts +52 -0
  172. package/dist/shared/ipc-schemas.js +64 -0
  173. package/dist/shared/simulator-route.d.ts +8 -0
  174. package/dist/shared/simulator-route.js +15 -0
  175. package/dist/shared/types.d.ts +17 -0
  176. package/dist/shared/view-ids.d.ts +9 -0
  177. package/dist/shared/view-ids.js +21 -0
  178. package/dist/simulator/assets/device-shell-CmtM1QxP.js +2 -0
  179. package/dist/simulator/assets/device-shell-iFZo1igL.css +1 -0
  180. package/dist/simulator/assets/{simulator-COIE6R49.js → simulator-CIobn3Mh.js} +6 -6
  181. package/dist/simulator/assets/{simulator-mini-app-BLn7XV8e.js → simulator-mini-app-CRe6n9br.js} +2 -2
  182. package/dist/simulator/assets/simulator-ui-BupATgKo.css +1 -0
  183. package/dist/simulator/assets/simulator-ui-C_cP602X.js +2 -0
  184. package/dist/simulator/simulator.html +3 -2
  185. package/dist/vscode-workbench/assets/__vite-browser-external-Bc1vizTf.js +1 -0
  186. package/dist/vscode-workbench/assets/{dist-oHcwN53f.js → dist-CMfmHflW.js} +3 -3
  187. package/dist/vscode-workbench/assets/{iconv-lite-umd-CLMLpdGm.js → iconv-lite-umd-Bx8CgaZq.js} +1 -1
  188. package/dist/vscode-workbench/assets/{index-BE3UJdoH.js → index-CdG6YWhW.js} +436 -436
  189. package/dist/vscode-workbench/assets/{jschardet-BICW8PLJ.js → jschardet-M0qgd2lN.js} +1 -1
  190. package/dist/vscode-workbench/index.html +21 -1
  191. package/package.json +9 -8
  192. package/dist/main/services/views/destroy-child-view.d.ts +0 -9
  193. package/dist/main/services/views/destroy-child-view.js +0 -23
  194. package/dist/renderer/assets/constants-EAMiwL9_.js +0 -2
  195. package/dist/renderer/assets/index-BBg3YI5b.js +0 -49
  196. package/dist/renderer/assets/input-xdmfv-eH.js +0 -2
  197. package/dist/renderer/assets/ipc-transport-B3EpmfNS.js +0 -9
  198. package/dist/renderer/assets/ipc-transport-Blac3sOj.css +0 -1
  199. package/dist/renderer/assets/popover-B88e2hkg.js +0 -2
  200. package/dist/renderer/assets/select-CD9CJyhI.js +0 -2
  201. package/dist/renderer/assets/settings-44hf0QtO.js +0 -2
  202. package/dist/renderer/assets/settings-api-pJKPuP1M.js +0 -2
  203. package/dist/renderer/assets/workbenchSettings-DKD5U1Ql.js +0 -8
  204. package/dist/simulator/assets/device-shell-Cw7c-IkG.js +0 -2
  205. package/dist/simulator/assets/device-shell-DbC5ccs8.css +0 -1
  206. package/dist/simulator/assets/jsx-runtime-DkKmJyBb.js +0 -2
  207. package/dist/simulator/device-shell/menu-button-geometry.js +0 -18
  208. package/dist/vscode-workbench/assets/__vite-browser-external-BON7qP59.js +0 -1
@@ -1,150 +1,268 @@
1
1
  import { WebContentsView } from 'electron';
2
- import path from 'path';
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';
8
+ import { UpdateChannel } from '../../../shared/ipc-channels-overlays.js';
9
9
  export function createOverlayPanelsView(ctx, reconciler, deps) {
10
- let settingsView = null;
11
- let popoverView = null;
12
10
  function overlayHeaderHeight() {
13
11
  return HEADER_H + deps.getHostToolbarHeight();
14
12
  }
15
- // settings/popover bounds are main-computed; publish them into overlayDesired
16
- // and let the reconciler place them (they are top-tier layers, so a reorder
17
- // keeps them above every base overlay — the old raiseTopOverlays is gone).
18
- function applySettingsBounds() {
19
- if (!settingsView || ctx.windows.mainWindow.isDestroyed())
20
- return;
21
- const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
22
- reconciler.setOverlayDesired(VIEW_ID.settings, {
23
- viewId: VIEW_ID.settings,
24
- placement: {
25
- visible: true,
26
- bounds: layout.computeSettingsBounds(w, h, overlayHeaderHeight()),
27
- },
28
- layer: VIEW_LAYER.settings,
29
- });
30
- reconciler.reconcileNow();
13
+ function overlayDesiredSetter(viewId, layer) {
14
+ return (bounds) => {
15
+ if (bounds === null) {
16
+ reconciler.deleteOverlayDesired(viewId);
17
+ }
18
+ else {
19
+ reconciler.setOverlayDesired(viewId, {
20
+ viewId,
21
+ placement: { visible: true, bounds },
22
+ layer,
23
+ });
24
+ }
25
+ reconciler.reconcileNow();
26
+ };
31
27
  }
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();
28
+ const settingsPanel = createOverlayPanel({
29
+ electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
30
+ rendererDir: ctx.rendererDir,
31
+ entry: 'entries/settings/index.html',
32
+ webPreferences: {
33
+ nodeIntegration: false,
34
+ contextIsolation: true,
35
+ sandbox: false,
36
+ preload: mainPreloadPath,
37
+ },
38
+ hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
39
+ setDesired: overlayDesiredSetter(VIEW_ID.settings, VIEW_LAYER.settings),
40
+ registerView: (getView) => reconciler.registerView(VIEW_ID.settings, { getView }),
41
+ destroyView: (view) => reconciler.destroyView(VIEW_ID.settings, view),
42
+ readyMode: 'manual',
43
+ });
44
+ const popoverPanel = createOverlayPanel({
45
+ electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
46
+ rendererDir: ctx.rendererDir,
47
+ entry: 'entries/popover/index.html',
48
+ webPreferences: {
49
+ nodeIntegration: false,
50
+ contextIsolation: true,
51
+ sandbox: false,
52
+ preload: mainPreloadPath,
53
+ },
54
+ hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
55
+ setDesired: overlayDesiredSetter(VIEW_ID.popover, VIEW_LAYER.popover),
56
+ registerView: (getView) => reconciler.registerView(VIEW_ID.popover, { getView }),
57
+ destroyView: (view) => reconciler.destroyView(VIEW_ID.popover, view),
58
+ pushData: (view, data) => ctx.notify.popoverInit(view, data),
59
+ readyMode: 'manual',
60
+ });
61
+ const tooltipPanel = createOverlayPanel({
62
+ electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
63
+ rendererDir: ctx.rendererDir,
64
+ entry: 'entries/tooltip/index.html',
65
+ webPreferences: {
66
+ nodeIntegration: false,
67
+ contextIsolation: true,
68
+ sandbox: false,
69
+ preload: mainPreloadPath,
70
+ },
71
+ hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
72
+ setDesired: overlayDesiredSetter(VIEW_ID.tooltip, VIEW_LAYER.tooltip),
73
+ registerView: (getView) => reconciler.registerView(VIEW_ID.tooltip, { getView }),
74
+ prepareView: (view) => {
75
+ const [width = 0, height = 0] = ctx.windows.mainWindow.getContentSize();
76
+ reconciler.prepareView(VIEW_ID.tooltip, view, {
77
+ x: 0,
78
+ y: 0,
79
+ width: Math.max(1, width),
80
+ height: Math.max(1, height),
81
+ });
82
+ },
83
+ destroyView: (view) => reconciler.destroyView(VIEW_ID.tooltip, view),
84
+ pushData: (view, data) => ctx.notify.tooltipInit(view, data),
85
+ readyMode: 'manual',
86
+ });
87
+ /**
88
+ * Both devtools-owned dialog panels occupy the full main-window content
89
+ * rect (they render their own centered card + backdrop), so unlike
90
+ * settings/popover/tooltip they need no anchor-derived bounds computation —
91
+ * just the window's current content size, recomputed on every show/resize.
92
+ */
93
+ function fullWindowBounds() {
94
+ const [width = 0, height = 0] = ctx.windows.mainWindow.getContentSize();
95
+ return { x: 0, y: 0, width: Math.max(1, width), height: Math.max(1, height) };
45
96
  }
97
+ const projectCreateDialogPanel = createOverlayPanel({
98
+ electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
99
+ rendererDir: ctx.rendererDir,
100
+ entry: 'entries/project-create-dialog/index.html',
101
+ webPreferences: {
102
+ nodeIntegration: false,
103
+ contextIsolation: true,
104
+ sandbox: false,
105
+ preload: mainPreloadPath,
106
+ },
107
+ hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
108
+ setDesired: overlayDesiredSetter(VIEW_ID.projectCreateDialog, VIEW_LAYER.dialog),
109
+ registerView: (getView) => reconciler.registerView(VIEW_ID.projectCreateDialog, { getView }),
110
+ destroyView: (view) => reconciler.destroyView(VIEW_ID.projectCreateDialog, view),
111
+ pushData: (view, data) => ctx.notify.projectCreateInit(view, data),
112
+ readyMode: 'manual',
113
+ });
114
+ const updateDialogPanel = createOverlayPanel({
115
+ electron: { createWebContentsView: (opts) => new WebContentsView(opts) },
116
+ rendererDir: ctx.rendererDir,
117
+ entry: 'entries/update-dialog/index.html',
118
+ webPreferences: {
119
+ nodeIntegration: false,
120
+ contextIsolation: true,
121
+ sandbox: false,
122
+ preload: mainPreloadPath,
123
+ },
124
+ hardenNavigation: (wc) => applyNavigationHardening(wc, ctx.rendererDir),
125
+ setDesired: overlayDesiredSetter(VIEW_ID.updateDialog, VIEW_LAYER.dialog),
126
+ registerView: (getView) => reconciler.registerView(VIEW_ID.updateDialog, { getView }),
127
+ destroyView: (view) => reconciler.destroyView(VIEW_ID.updateDialog, view),
128
+ pushData: (view, data) => ctx.notify.updateAvailable(view, data),
129
+ readyMode: 'manual',
130
+ });
131
+ let tooltipRequestId = 0;
132
+ let activeTooltip = null;
46
133
  async function showSettings() {
47
- if (!settingsView) {
48
- settingsView = new WebContentsView({
49
- webPreferences: {
50
- nodeIntegration: false,
51
- contextIsolation: true,
52
- sandbox: false,
53
- preload: mainPreloadPath,
54
- },
55
- });
56
- // Overlay loads mainPreloadPath, so the same navigation rules as the
57
- // main window apply — see navigation-hardening.ts.
58
- applyNavigationHardening(settingsView.webContents, ctx.rendererDir);
59
- // Transparent backing: the settings view now spans the whole content area
60
- // (computeSettingsBounds) and its renderer paints a transparent backdrop +
61
- // an opaque right-side panel, so the underlying editor/simulator show
62
- // through and a backdrop click closes the overlay (mirrors the popover).
63
- settingsView.setBackgroundColor('#00000000');
64
- await settingsView.webContents.loadFile(path.join(ctx.rendererDir, 'entries/settings/index.html'));
65
- }
66
- applySettingsBounds();
134
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
135
+ settingsPanel.show(undefined, layout.computeSettingsBounds(w, h, overlayHeaderHeight()));
136
+ await settingsPanel.whenReady();
67
137
  }
68
138
  function hideSettings() {
69
- reconciler.deleteOverlayDesired(VIEW_ID.settings);
70
- reconciler.reconcileNow();
139
+ settingsPanel.hide();
71
140
  }
72
141
  function showPopover(data) {
142
+ // Popover carries no state across opens (always fresh init data) — force a
143
+ // brand-new instance rather than reusing/repositioning a live one (and
144
+ // notify like any other close, via the shared hidePopover()).
73
145
  hidePopover();
74
- const popover = new WebContentsView({
75
- webPreferences: {
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'));
146
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
147
+ popoverPanel.show(data, layout.computePopoverBounds(w, h, overlayHeaderHeight()));
91
148
  }
92
149
  function hidePopover() {
93
- if (!popoverView)
150
+ if (!popoverPanel.isPresent())
94
151
  return;
152
+ popoverPanel.destroy();
95
153
  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
154
  reconciler.reconcileNow();
101
155
  ctx.notify.popoverClosed();
102
156
  }
157
+ function prepareTooltip() {
158
+ tooltipPanel.prepare();
159
+ }
160
+ function showTooltip(data) {
161
+ const requestId = ++tooltipRequestId;
162
+ activeTooltip = { requestId, anchor: data.anchor };
163
+ const [contentWidth = 0] = ctx.windows.mainWindow.getContentSize();
164
+ tooltipPanel.show({
165
+ requestId,
166
+ text: data.text,
167
+ maxWidth: layout.computeTooltipMaxWidth(contentWidth),
168
+ }, null);
169
+ }
170
+ function hideTooltip() {
171
+ activeTooltip = null;
172
+ tooltipPanel.hide();
173
+ }
174
+ function showProjectCreateDialog(data) {
175
+ projectCreateDialogPanel.show(data, fullWindowBounds());
176
+ }
177
+ function hideProjectCreateDialog() {
178
+ projectCreateDialogPanel.hide();
179
+ }
180
+ function showUpdateDialog(data) {
181
+ updateDialogPanel.show(data, fullWindowBounds());
182
+ }
183
+ function hideUpdateDialog() {
184
+ updateDialogPanel.hide();
185
+ }
186
+ function notifyUpdateDownloadProgress(percent) {
187
+ const wc = updateDialogPanel.getWebContents();
188
+ if (!wc)
189
+ return;
190
+ wc.send(UpdateChannel.DownloadProgress, { percent });
191
+ }
192
+ function markOverlayReady(webContentsId) {
193
+ settingsPanel.markReady(webContentsId);
194
+ popoverPanel.markReady(webContentsId);
195
+ tooltipPanel.markReady(webContentsId);
196
+ projectCreateDialogPanel.markReady(webContentsId);
197
+ updateDialogPanel.markReady(webContentsId);
198
+ }
199
+ function applyTooltipMeasurement(webContentsId, measurement) {
200
+ const active = activeTooltip;
201
+ if (!active || active.requestId !== measurement.requestId)
202
+ return;
203
+ if (tooltipPanel.getWebContentsId() !== webContentsId)
204
+ return;
205
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
206
+ tooltipPanel.reposition(layout.computeTooltipBounds(active.anchor, w, h, measurement));
207
+ }
103
208
  function reapplyPresentOverlays() {
104
- if (reconciler.hasOverlayDesired(VIEW_ID.settings))
105
- applySettingsBounds();
106
- if (reconciler.hasOverlayDesired(VIEW_ID.popover))
107
- applyPopoverBounds();
209
+ // Fire-and-forget re-trigger — a crash between this call and the panel
210
+ // becoming ready now rejects whenReady() (see overlay-panel.ts teardown);
211
+ // handleViewBroken() already logs it, nothing more to do here.
212
+ if (settingsPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.settings)) {
213
+ showSettings().catch(() => { });
214
+ }
215
+ if (popoverPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.popover)) {
216
+ const [w = 0, h = 0] = ctx.windows.mainWindow.getContentSize();
217
+ popoverPanel.reposition(layout.computePopoverBounds(w, h, overlayHeaderHeight()));
218
+ }
219
+ if (projectCreateDialogPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.projectCreateDialog)) {
220
+ projectCreateDialogPanel.reposition(fullWindowBounds());
221
+ }
222
+ if (updateDialogPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.updateDialog)) {
223
+ updateDialogPanel.reposition(fullWindowBounds());
224
+ }
108
225
  }
109
226
  function applySettingsBoundsIfPresent() {
110
- if (reconciler.hasOverlayDesired(VIEW_ID.settings))
111
- applySettingsBounds();
227
+ // See reapplyPresentOverlays() above for why this swallows a rejection.
228
+ if (settingsPanel.isPresent() && reconciler.hasOverlayDesired(VIEW_ID.settings)) {
229
+ showSettings().catch(() => { });
230
+ }
112
231
  }
113
232
  function destroySettings() {
114
- destroyChildView(ctx.windows.mainWindow, settingsView);
115
- settingsView = null;
233
+ activeTooltip = null;
234
+ settingsPanel.destroy();
235
+ tooltipPanel.destroy();
236
+ }
237
+ function destroyDialogs() {
238
+ projectCreateDialogPanel.destroy();
239
+ updateDialogPanel.destroy();
116
240
  }
117
- reconciler.registerView(VIEW_ID.settings, { getView: () => settingsView });
118
- reconciler.registerView(VIEW_ID.popover, { getView: () => popoverView });
119
241
  return {
120
242
  showSettings,
121
243
  hideSettings,
122
244
  showPopover,
123
245
  hidePopover,
246
+ prepareTooltip,
247
+ showTooltip,
248
+ hideTooltip,
249
+ markOverlayReady,
250
+ applyTooltipMeasurement,
251
+ showProjectCreateDialog,
252
+ hideProjectCreateDialog,
253
+ showUpdateDialog,
254
+ hideUpdateDialog,
255
+ notifyUpdateDownloadProgress,
124
256
  reapplyPresentOverlays,
125
257
  applySettingsBoundsIfPresent,
126
258
  destroySettings,
127
- getSettingsWebContents: () => {
128
- if (!settingsView)
129
- return null;
130
- if (settingsView.webContents.isDestroyed())
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
- },
259
+ destroyDialogs,
260
+ getSettingsWebContents: () => settingsPanel.getWebContents(),
261
+ getSettingsWebContentsId: () => settingsPanel.getWebContentsId(),
262
+ getPopoverWebContentsId: () => popoverPanel.getWebContentsId(),
263
+ getTooltipWebContentsId: () => tooltipPanel.getWebContentsId(),
264
+ getProjectCreateDialogWebContentsId: () => projectCreateDialogPanel.getWebContentsId(),
265
+ getUpdateDialogWebContentsId: () => updateDialogPanel.getWebContentsId(),
148
266
  };
149
267
  }
150
268
  //# 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). */
@@ -44,8 +36,10 @@ export interface ViewSlot {
44
36
  * settings/popover are main-owned and live in `overlayDesired`. Any change
45
37
  * merges the two, runs the pure reconcile core, and applies the ordered ops
46
38
  * through `viewTarget`. `epochCounter` is a single monotonic tick — main is the
47
- * only (serial) reconcile caller, so the core's stale guard passes by
48
- * construction; `rendererGeneration` still drives the reset on renderer restart.
39
+ * only (serial) reconcile caller, so the core's stale-epoch guard passes by
40
+ * construction; `rendererGeneration` is the high-water mark that drives both
41
+ * the reset on a genuinely newer generation and the hard rejection of a
42
+ * snapshot from behind it (see `setPlacementSnapshot`).
49
43
  */
50
44
  export interface PlacementReconciler {
51
45
  registerView(viewId: string, slot: ViewSlot): void;
@@ -55,19 +49,25 @@ export interface PlacementReconciler {
55
49
  * truth for every managed native view's bounds/visibility/z-order.
56
50
  */
57
51
  setPlacementSnapshot(snapshot: PlacementSnapshot<DevtoolsExtra>): void;
58
- /**
59
- * Forget a view's reconciled mount state so the NEXT rebuilt view is treated
60
- * as a fresh attach. Required wherever a view instance is replaced/destroyed
61
- * via a manual removeChildView that bypasses the reconciler (otherwise the
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;
52
+ /** Size a detached view for renderer-side intrinsic measurement. */
53
+ prepareView(viewId: string, view: WebContentsView, bounds: layout.Bounds): void;
54
+ /** Detach and close one concrete view instance through the native-tree owner. */
55
+ destroyView(viewId: string, view: WebContentsView | null): void;
66
56
  setBaseDesired(viewId: string, desired: DesiredView<DevtoolsExtra>): void;
67
57
  deleteBaseDesired(viewId: string): void;
68
58
  setOverlayDesired(viewId: string, desired: DesiredView<DevtoolsExtra>): void;
69
59
  deleteOverlayDesired(viewId: string): void;
70
60
  hasOverlayDesired(viewId: string): boolean;
61
+ /**
62
+ * Hand out a fresh generation seed for a renderer bootstrap (see
63
+ * renderer-placement-generation.ts). Strictly exceeds both the current
64
+ * high-water mark (`rendererGeneration`, which a full renderer reload does
65
+ * NOT reset — this reconciler lives in the long-lived main process) and
66
+ * every previously allocated seed, so a reload that races ahead of its own
67
+ * previous session's accepted snapshots can never be handed a value that
68
+ * `setPlacementSnapshot` would reject as stale.
69
+ */
70
+ allocateGeneration(): number;
71
71
  }
72
72
  export declare function createPlacementReconciler(ctx: ViewManagerContext): PlacementReconciler;
73
73
  //# sourceMappingURL=placement-reconciler.d.ts.map
@@ -1,12 +1,18 @@
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
+ let allocatedGeneration = 0;
9
+ const appliedActual = new Map();
7
10
  const baseDesired = new Map();
8
11
  const overlayDesired = new Map();
9
12
  const slots = new Map();
13
+ // Sole owner of the main window's native child tree. Every attach, detach,
14
+ // reorder and hard destroy passes through this ledger-backed adapter.
15
+ const contentViewHost = createNativeViewTreeHost(ctx, slots);
10
16
  function gateReadiness(v) {
11
17
  const slot = slots.get(v.viewId);
12
18
  if (slot?.gateHidden?.())
@@ -20,59 +26,67 @@ export function createPlacementReconciler(ctx) {
20
26
  const slot = slots.get(viewId);
21
27
  if (!slot)
22
28
  return;
23
- if (slot.beforeAttach?.())
24
- return;
25
29
  const view = slot.ensureView ? slot.ensureView() : slot.getView();
26
30
  if (!view)
27
31
  return;
28
- ctx.windows.mainWindow.contentView.addChildView(view);
29
- slot.setAdded?.(true);
32
+ if (!contentViewHost.addChildView({ id: viewId }))
33
+ return;
34
+ const previous = appliedActual.get(viewId);
35
+ appliedActual.set(viewId, {
36
+ attached: true,
37
+ visible: true,
38
+ bounds: previous?.bounds,
39
+ extra: previous?.extra,
40
+ });
30
41
  },
31
42
  detach(viewId) {
32
- const slot = slots.get(viewId);
33
- const view = slot?.getView() ?? null;
34
- if (view && !ctx.windows.mainWindow.isDestroyed()) {
35
- try {
36
- ctx.windows.mainWindow.contentView.removeChildView(view);
37
- }
38
- catch { /* already removed */ }
39
- }
40
- slot?.setAdded?.(false);
43
+ if (!contentViewHost.removeChildView({ id: viewId }))
44
+ return;
45
+ appliedActual.delete(viewId);
41
46
  },
42
47
  setBounds(viewId, bounds, extra) {
43
48
  const slot = slots.get(viewId);
44
49
  const view = slot?.getView() ?? null;
45
50
  if (!view || view.webContents.isDestroyed())
46
51
  return;
47
- if (slot?.applyBounds) {
48
- slot.applyBounds(view, bounds, extra);
52
+ try {
53
+ if (slot?.applyBounds)
54
+ slot.applyBounds(view, bounds, extra);
55
+ else
56
+ view.setBounds(bounds);
57
+ }
58
+ catch {
49
59
  return;
50
60
  }
51
- view.setBounds(bounds);
61
+ const previous = appliedActual.get(viewId);
62
+ appliedActual.set(viewId, {
63
+ attached: previous?.attached ?? false,
64
+ visible: previous?.visible ?? false,
65
+ bounds,
66
+ extra,
67
+ });
52
68
  },
53
69
  setVisible(viewId, visible) {
54
70
  const view = slots.get(viewId)?.getView() ?? null;
55
- if (!view)
71
+ if (!view || view.webContents.isDestroyed())
56
72
  return;
57
73
  try {
58
74
  view.setVisible(visible);
59
75
  }
60
- catch { /* stub may lack setVisible */ }
76
+ catch {
77
+ return;
78
+ }
79
+ const previous = appliedActual.get(viewId);
80
+ if (!previous)
81
+ return;
82
+ appliedActual.set(viewId, { ...previous, visible });
61
83
  },
62
84
  reorder(order) {
63
85
  // A single attached view is already in place — nothing to reorder.
64
86
  if (order.length <= 1 || ctx.windows.mainWindow.isDestroyed())
65
87
  return;
66
- const cv = ctx.windows.mainWindow.contentView;
67
- for (const viewId of order) {
68
- const view = slots.get(viewId)?.getView() ?? null;
69
- if (view) {
70
- try {
71
- cv.addChildView(view);
72
- }
73
- catch { /* already attached */ }
74
- }
75
- }
88
+ for (const viewId of order)
89
+ contentViewHost.addChildView({ id: viewId });
76
90
  },
77
91
  };
78
92
  // Create the lazily-built views (host-toolbar, workbench) BEFORE reconcile so
@@ -83,6 +97,9 @@ export function createPlacementReconciler(ctx) {
83
97
  slot.ensureLazy?.(baseDesired.get(viewId));
84
98
  }
85
99
  }
100
+ function cloneAppliedActual() {
101
+ return new Map([...appliedActual].map(([viewId, actual]) => [viewId, { ...actual }]));
102
+ }
86
103
  function reconcileNow() {
87
104
  ensureLazyViews();
88
105
  const views = [];
@@ -90,6 +107,7 @@ export function createPlacementReconciler(ctx) {
90
107
  views.push(gateReadiness(v));
91
108
  for (const v of overlayDesired.values())
92
109
  views.push(v);
110
+ placementState = { ...placementState, actual: cloneAppliedActual() };
93
111
  const result = reconcile(placementState, {
94
112
  generation: rendererGeneration,
95
113
  epoch: ++epochCounter,
@@ -97,8 +115,33 @@ export function createPlacementReconciler(ctx) {
97
115
  });
98
116
  placementState = result.state;
99
117
  applyViewOps(result.ops, viewTarget);
118
+ // The planner's next state is optimistic. Keep only desired/epoch metadata;
119
+ // appliedActual is updated by successful native effects above.
120
+ placementState = { ...placementState, actual: cloneAppliedActual() };
100
121
  }
101
122
  function setPlacementSnapshot(snapshot) {
123
+ // Hard reject a snapshot from BEHIND the current high-water mark — a
124
+ // complete no-op, touching neither `rendererGeneration` nor
125
+ // `baseDesired`. The renderer hands out one shared, strictly monotonic
126
+ // sequence across every screen (see renderer-placement-generation.ts),
127
+ // so under normal operation a lower generation can only be a LATE
128
+ // arrival from an already-superseded source (e.g. a dead screen's
129
+ // delayed `dispose()` empty-snapshot flush racing a successor screen's
130
+ // mount). The previous version of this guard clamped
131
+ // `rendererGeneration` to never regress but still unconditionally
132
+ // applied the stale snapshot's CONTENT into `baseDesired` under the
133
+ // clamped (i.e. current) generation number — which defeated the
134
+ // reconcile core's own generation-regression guard
135
+ // (placement-reconcile.ts: `snapshot.generation < prev.generation`) by
136
+ // never letting it see the snapshot's real, lower generation. That let a
137
+ // dead screen's stale/empty view list silently overwrite a currently
138
+ // active screen's real views. Dropping it here, before it ever reaches
139
+ // `baseDesired`, is what actually gives the stale snapshot zero side
140
+ // effects.
141
+ if (snapshot.generation < rendererGeneration) {
142
+ console.warn(`[placement-reconciler] snapshot generation ${snapshot.generation} is behind the current ${rendererGeneration}; dropping without applying its content`);
143
+ return;
144
+ }
102
145
  rendererGeneration = snapshot.generation;
103
146
  baseDesired.clear();
104
147
  for (const v of snapshot.views)
@@ -109,12 +152,31 @@ export function createPlacementReconciler(ctx) {
109
152
  registerView: (viewId, slot) => { slots.set(viewId, slot); },
110
153
  reconcileNow,
111
154
  setPlacementSnapshot,
112
- forgetActual: (viewId) => { placementState.actual.delete(viewId); },
155
+ prepareView: (viewId, view, bounds) => {
156
+ if (slots.get(viewId)?.getView() !== view || view.webContents.isDestroyed())
157
+ return;
158
+ try {
159
+ view.setBounds(bounds);
160
+ }
161
+ catch {
162
+ return;
163
+ }
164
+ appliedActual.set(viewId, { attached: false, visible: false, bounds });
165
+ },
166
+ destroyView: (viewId, view) => {
167
+ contentViewHost.destroyView(viewId, view);
168
+ appliedActual.delete(viewId);
169
+ placementState.actual.delete(viewId);
170
+ },
113
171
  setBaseDesired: (viewId, desired) => { baseDesired.set(viewId, desired); },
114
172
  deleteBaseDesired: (viewId) => { baseDesired.delete(viewId); },
115
173
  setOverlayDesired: (viewId, desired) => { overlayDesired.set(viewId, desired); },
116
174
  deleteOverlayDesired: (viewId) => { overlayDesired.delete(viewId); },
117
175
  hasOverlayDesired: (viewId) => overlayDesired.has(viewId),
176
+ allocateGeneration: () => {
177
+ allocatedGeneration = Math.max(allocatedGeneration, rendererGeneration) + 1;
178
+ return allocatedGeneration;
179
+ },
118
180
  };
119
181
  }
120
182
  //# sourceMappingURL=placement-reconciler.js.map