bun-app-window 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +400 -2
- package/README.zh-CN.md +399 -0
- package/README.zh-TW.md +399 -0
- package/dist/libshell.dll +0 -0
- package/native/build.ps1 +67 -0
- package/native/fetch.ps1 +66 -0
- package/native/shell.cc +2134 -0
- package/package.json +67 -5
- package/src/shell/assets.d.ts +16 -0
- package/src/shell/debug.ts +40 -0
- package/src/shell/embedded.ts +42 -0
- package/src/shell/index.ts +291 -0
- package/src/shell/ipc.ts +569 -0
- package/src/shell/native.ts +92 -0
- package/src/shell/port.ts +77 -0
- package/src/shell/resolve.ts +211 -0
- package/src/shell/state.ts +211 -0
- package/src/shell/types.ts +144 -0
- package/src/ui/titlebar.ts +436 -0
- package/vendor/webview/compatibility/CMakeLists.txt +3 -0
- package/vendor/webview/compatibility/mingw/CMakeLists.txt +14 -0
- package/vendor/webview/compatibility/mingw/include/EventToken.h +25 -0
- package/vendor/webview/core/CMakeLists.txt +94 -0
- package/vendor/webview/core/include/webview/api.h +251 -0
- package/vendor/webview/core/include/webview/backends.hh +40 -0
- package/vendor/webview/core/include/webview/c_api_impl.hh +258 -0
- package/vendor/webview/core/include/webview/detail/backends/cocoa_webkit.hh +626 -0
- package/vendor/webview/core/include/webview/detail/backends/gtk_webkitgtk.hh +355 -0
- package/vendor/webview/core/include/webview/detail/backends/win32_edge.hh +909 -0
- package/vendor/webview/core/include/webview/detail/basic_result.hh +119 -0
- package/vendor/webview/core/include/webview/detail/engine_base.hh +382 -0
- package/vendor/webview/core/include/webview/detail/exceptions.hh +42 -0
- package/vendor/webview/core/include/webview/detail/json.hh +337 -0
- package/vendor/webview/core/include/webview/detail/native_library.hh +170 -0
- package/vendor/webview/core/include/webview/detail/optional.hh +118 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSApplication.hh +107 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSBundle.hh +56 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSEvent.hh +71 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSInvocation.hh +66 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSMethodSignature.hh +52 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSNotification.hh +51 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSNumber.hh +53 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSObject.hh +51 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSOpenPanel.hh +71 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSPoint.hh +53 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSRect.hh +53 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSSavePanel.hh +52 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSSize.hh +53 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSString.hh +87 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSURL.hh +63 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSURLRequest.hh +52 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSValue.hh +56 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSView.hh +91 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/NSWindow.hh +137 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/cocoa.hh +59 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/cocoa/types.hh +49 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/objc/Class.hh +55 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/objc/autoreleasepool.hh +70 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/objc/invoke.hh +75 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/objc/memory.hh +57 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/objc/objc.hh +47 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/webkit/WKOpenPanelParameters.hh +57 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/webkit/WKScriptMessage.hh +51 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/webkit/WKUserContentController.hh +61 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/webkit/WKUserScript.hh +71 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/webkit/WKWebView.hh +108 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/webkit/WKWebViewConfiguration.hh +60 -0
- package/vendor/webview/core/include/webview/detail/platform/darwin/webkit/webkit.hh +46 -0
- package/vendor/webview/core/include/webview/detail/platform/linux/gtk/compat.hh +137 -0
- package/vendor/webview/core/include/webview/detail/platform/linux/webkitgtk/compat.hh +142 -0
- package/vendor/webview/core/include/webview/detail/platform/linux/webkitgtk/dmabuf.hh +167 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/com_init_wrapper.hh +126 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/dpi.hh +161 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/dwmapi.hh +67 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/iid.hh +78 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/ntdll.hh +58 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/reg_key.hh +135 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/shcore.hh +59 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/theme.hh +76 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/user32.hh +90 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/version.hh +151 -0
- package/vendor/webview/core/include/webview/detail/platform/windows/webview2/loader.hh +391 -0
- package/vendor/webview/core/include/webview/detail/user_script.hh +76 -0
- package/vendor/webview/core/include/webview/detail/utility/string.hh +99 -0
- package/vendor/webview/core/include/webview/errors.h +67 -0
- package/vendor/webview/core/include/webview/errors.hh +85 -0
- package/vendor/webview/core/include/webview/json_deprecated.hh +61 -0
- package/vendor/webview/core/include/webview/macros.h +123 -0
- package/vendor/webview/core/include/webview/types.h +81 -0
- package/vendor/webview/core/include/webview/types.hh +48 -0
- package/vendor/webview/core/include/webview/version.h +67 -0
- package/vendor/webview/core/include/webview/webview.h +32 -0
- package/vendor/webview/core/include/webview.h +15 -0
- package/vendor/webview/core/src/webview.cc +1 -0
- package/vendor/webview/core/tests/CMakeLists.txt +18 -0
- package/vendor/webview/core/tests/src/functional_tests.cc +316 -0
- package/vendor/webview/core/tests/src/unit_tests.cc +188 -0
- package/vendor/webview2/build/native/include/WebView2.h +23568 -0
- package/vendor/webview2/build/native/include/WebView2EnvironmentOptions.h +144 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dolores (TiancongLx)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,401 @@
|
|
|
1
|
-
#
|
|
1
|
+
# bun-app-window
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/bun-app-window)
|
|
4
|
+
[](https://bun.sh)
|
|
5
|
+
[](#requirements--design-boundaries)
|
|
6
|
+
[](#requirements--design-boundaries)
|
|
7
|
+
[](./LICENSE)
|
|
8
|
+
|
|
9
|
+
English | [简体中文](./README.zh-CN.md) | [正體中文](./README.zh-TW.md)
|
|
10
|
+
|
|
11
|
+
A native window shell for Bun applications on Windows, hosting web UIs via the system WebView2 runtime without bundling a browser.
|
|
12
|
+
|
|
13
|
+
This library maintains a strict, minimal scope: it handles window lifecycle, DPI-aware geometry, frameless chrome customization, and the native message channel. Business logic and UI rendering live entirely outside the shell.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { openShell, serveOnSafePort, FLAG_FRAMELESS } from "bun-app-window";
|
|
17
|
+
|
|
18
|
+
const server = serveOnSafePort({ fetch: () => new Response("<h1>Hello</h1>") });
|
|
19
|
+
await openShell({ url: `http://127.0.0.1:${server.port}`, flags: FLAG_FRAMELESS });
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Requirements & Design Boundaries
|
|
25
|
+
|
|
26
|
+
Before adopting this package, please review the following architectural constraints and trade-offs:
|
|
27
|
+
|
|
28
|
+
| Constraint | Implication |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| Windows x64 only | Enforced via `os` and `cpu` fields in `package.json` (the platform-neutral package name is reserved for future expansion). A prebuilt `libshell.dll` is shipped in the package; no install-time compilation is required |
|
|
31
|
+
| Bun runtime required | Ships raw TypeScript source files and requires Bun >= 1.4.3. While Node.js can install the package, it cannot execute it |
|
|
32
|
+
| Built on `bun:ffi` | `bun:ffi` is marked as experimental in Bun. While Bun recommends Node-API for production stability, this library chooses `bun:ffi` to achieve a zero-dependency footprint |
|
|
33
|
+
|
|
34
|
+
Runtime prerequisites and non-goals:
|
|
35
|
+
|
|
36
|
+
- System WebView2 Runtime: Requires the evergreen WebView2 Runtime installed on the host machine (pre-installed on Windows 11).
|
|
37
|
+
- Interactive desktop session: Due to Windows Session 0 isolation, WebView2 cannot run inside non-interactive background services. However, running inside elevated (High Integrity Level) administrator processes is fully supported.
|
|
38
|
+
- Explicit non-goals: System tray icons, native application menu bars, auto-updaters, multi-window orchestration, and cross-platform abstractions.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
bun add bun-app-window
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { openShell, serveOnSafePort, FLAG_FRAMELESS, FLAG_CENTER } from "bun-app-window";
|
|
50
|
+
|
|
51
|
+
const server = serveOnSafePort({
|
|
52
|
+
fetch: () => new Response("<h1>Hello</h1>", {
|
|
53
|
+
headers: { "content-type": "text/html; charset=utf-8" },
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const shell = await openShell({
|
|
58
|
+
url: `http://127.0.0.1:${server.port}`,
|
|
59
|
+
title: "My App",
|
|
60
|
+
width: 1000,
|
|
61
|
+
height: 680,
|
|
62
|
+
flags: FLAG_FRAMELESS | FLAG_CENTER,
|
|
63
|
+
minWidth: 480,
|
|
64
|
+
minHeight: 320,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
shell.post(JSON.stringify({ t: "ready" })); // Host -> Page one-way message
|
|
68
|
+
shell.setTitle("Doing work…");
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Note: `createShell(opts)` only resolves and loads the native DLL without opening a window. `openShell(opts)` creates the instance, starts the window immediately, and throws an error on failure.
|
|
72
|
+
|
|
73
|
+
## Core API
|
|
74
|
+
|
|
75
|
+
### Instance Methods & Properties
|
|
76
|
+
|
|
77
|
+
| Member | Description |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| `start()` | Opens the window and returns `{ rc, error }`. Returns immediately while the UI message loop runs on a dedicated native thread |
|
|
80
|
+
| `stop()` | Destroys the window and releases native resources. Safe to call multiple times (idempotent) |
|
|
81
|
+
| `show()` | Reveals the window. Typically paired with `FLAG_DEFER_SHOW` to display the window only after the web UI is ready |
|
|
82
|
+
| `isAlive()` | Checks whether the native window still exists (unlike `state()`, which cannot distinguish between unstarted and destroyed states) |
|
|
83
|
+
| `state()` | Returns current window state: `{ maximized, minimized, focused, dark, raw }` |
|
|
84
|
+
| `lastError()` | Returns the most recent failure message, or an empty string if no error occurred |
|
|
85
|
+
| `setTitle` / `minimize` / `toggleMaximize` / `close` | Standard window control operations; each returns a status code `rc` |
|
|
86
|
+
| `setMinSize(w, h)` | Sets the minimum window dimensions in logical pixels |
|
|
87
|
+
| `drag()` | Initiates native window dragging from a page `pointerdown` event (preserves Windows Snap Layouts) |
|
|
88
|
+
| `beginResize(edge)` | Initiates native border resizing from a page `pointermove` event (`edge` uses `RESIZE_EDGE.*` constants) |
|
|
89
|
+
| `post(json)` | Sends a fire-and-forget JSON message from the host to the web page |
|
|
90
|
+
| `setZoom(f)` / `getZoom()` | Gets or sets the page zoom factor (clamped automatically to `0.25`–`3.0`) |
|
|
91
|
+
| `reload()` / `openDevTools()` / `toggleFullscreen()` | Equivalent to `Ctrl+R`, `F12`, and `F11` respectively |
|
|
92
|
+
| `setBrowserUi(mask)` | Disables specific default browser behaviors using a bitwise OR of `BROWSER_UI_*` flags |
|
|
93
|
+
| `showContextMenu(x, y, items)` | Displays a native Win32 context menu at the specified screen coordinates (see below) |
|
|
94
|
+
| `pickFolder(title?)` | Opens a native folder selection dialog (synchronously blocks the calling thread) |
|
|
95
|
+
| `libInfo` | Metadata of the resolved native library (file path, resolution source, SHA-256 hash) |
|
|
96
|
+
| `symbols` | Escape hatch providing direct access to the raw `dlopen` FFI symbols |
|
|
97
|
+
|
|
98
|
+
### Window Flags
|
|
99
|
+
|
|
100
|
+
Combine via bitwise OR (`|`) and pass to `opts.flags`:
|
|
101
|
+
|
|
102
|
+
| Flag | Description |
|
|
103
|
+
| --- | --- |
|
|
104
|
+
| `FLAG_FRAMELESS` | Creates a frameless window without the default system title bar, delegating title bar rendering to the web UI |
|
|
105
|
+
| `FLAG_RESIZABLE` | Allows user resizing |
|
|
106
|
+
| `FLAG_CENTER` | Centers the window within the active monitor work area on startup (works in both standard and frameless modes) |
|
|
107
|
+
| `FLAG_TOPMOST` | Keeps the window always on top |
|
|
108
|
+
| `FLAG_DEFER_SHOW` | Creates the window hidden initially until `show()` is explicitly called |
|
|
109
|
+
| `FLAG_ACCEPT_DROP` | Enables native file and folder drag-and-drop from Windows Explorer |
|
|
110
|
+
| `FLAG_START_MAXIMIZED` | Opens the window directly in a maximized state without an intermediate normal-sized frame flash |
|
|
111
|
+
|
|
112
|
+
## Subpath Exports
|
|
113
|
+
|
|
114
|
+
Additional capabilities outside core window management are modularized into dedicated subpath exports.
|
|
115
|
+
|
|
116
|
+
### `bun-app-window/ipc` — Typed RPC & Event Bus
|
|
117
|
+
|
|
118
|
+
Share a single TypeScript contract between the host and the web page for compile-time verification of method signatures and event payloads:
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
// api.ts — Imported by both host and page
|
|
122
|
+
export type Api = { greet(name: string): string };
|
|
123
|
+
export type Events = { windowState: { maximized: boolean } };
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
// Host
|
|
128
|
+
import { createIpcServer } from "bun-app-window/ipc";
|
|
129
|
+
|
|
130
|
+
const ipc = createIpcServer({
|
|
131
|
+
service: { greet: (name: string) => `Hello ${name}` },
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
serveOnSafePort({
|
|
135
|
+
fetch(req) { /* Serve assets & authenticate */ },
|
|
136
|
+
websocket: {
|
|
137
|
+
open: (ws) => ipc.attach(ws),
|
|
138
|
+
message: (ws, raw) => ipc.handle(ws, raw),
|
|
139
|
+
close: (ws) => ipc.detach(ws),
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
ipc.emit("windowState", { maximized: false }); // Push event to connected pages
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
// Page
|
|
148
|
+
import { connect } from "bun-app-window/ipc";
|
|
149
|
+
import type { Api, Events } from "./api";
|
|
150
|
+
|
|
151
|
+
const api = await connect<Api, Events>();
|
|
152
|
+
await api.greet("Ada"); // Inferred return type: string
|
|
153
|
+
api.on("windowState", (s) => bar.setMaximized(s.maximized));
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
By default, `connect()` extracts the auth token from the page URL's `?t=` query parameter and connects to `/ws`. Pass a custom `url` or `channel` option to override this behavior.
|
|
157
|
+
|
|
158
|
+
### `bun-app-window/titlebar` — Windows 11 Title Bar
|
|
159
|
+
|
|
160
|
+
Mounts a customizable Windows 11 title bar inside frameless windows:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
// Page
|
|
164
|
+
import { mountTitleBar, bridgeFromWindowService } from "bun-app-window/titlebar";
|
|
165
|
+
|
|
166
|
+
const bar = mountTitleBar({
|
|
167
|
+
title: "My App",
|
|
168
|
+
icon: "/icon.svg",
|
|
169
|
+
bridge: bridgeFromWindowService(api.window),
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
api.on("windowState", (s) => bar.setMaximized(s.maximized));
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Expose the four corresponding window control methods on the host IPC service:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// Host
|
|
179
|
+
createIpcServer({
|
|
180
|
+
service: {
|
|
181
|
+
window: {
|
|
182
|
+
minimize: () => shell.minimize(),
|
|
183
|
+
toggleMaximize: () => shell.toggleMaximize(),
|
|
184
|
+
close: () => shell.close(),
|
|
185
|
+
drag: () => shell.drag(),
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Implementation notes:
|
|
192
|
+
|
|
193
|
+
- Native dragging: Calling `shell.drag()` dispatches a native `WM_NCLBUTTONDOWN` (`HTCAPTION`) message, preserving Windows 11 Snap Layouts and double-click maximize behavior.
|
|
194
|
+
- Theming & icons: Colors and dimensions are controlled via CSS custom properties (`--ws-tb-*`). Window control buttons default to geometric glyphs for universal compatibility; setting `icons: "fluent"` switches to `Segoe Fluent Icons` (note: missing fonts on older systems will render as missing-glyph boxes).
|
|
195
|
+
|
|
196
|
+
### `bun-app-window/state` — Window Placement Persistence
|
|
197
|
+
|
|
198
|
+
Automatically persists and restores window coordinates, dimensions, and maximized state across sessions:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import { attachPlacementStore, loadPlacement, restorePlacement } from "bun-app-window/state";
|
|
202
|
+
|
|
203
|
+
const FILE = "C:\\Users\\me\\AppData\\Roaming\\MyApp\\window.json";
|
|
204
|
+
const shell = await openShell({ url, flags: FLAG_DEFER_SHOW });
|
|
205
|
+
|
|
206
|
+
const saved = await loadPlacement(FILE);
|
|
207
|
+
if (saved) restorePlacement(shell, saved);
|
|
208
|
+
|
|
209
|
+
shell.show();
|
|
210
|
+
|
|
211
|
+
const store = attachPlacementStore(shell, FILE); // Polls state; skips disk writes when idle
|
|
212
|
+
process.on("beforeExit", () => store.flush());
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The native placement layer handles edge cases automatically:
|
|
216
|
+
|
|
217
|
+
- Captures the normal restore rectangle (`rcNormalPosition`) when maximized rather than full-screen bounds.
|
|
218
|
+
- Translates coordinates across monitors with different DPI scaling factors.
|
|
219
|
+
- Validates and clamps off-screen coordinates when monitor topology changes.
|
|
220
|
+
|
|
221
|
+
For one-off reads and writes without polling timers, use `capturePlacement` and `savePlacement` directly.
|
|
222
|
+
|
|
223
|
+
### `bun-app-window/debug` — Diagnostics
|
|
224
|
+
|
|
225
|
+
Exposes internal metrics and hit-testing utilities. Note: This module is excluded from semver stability guarantees and may change at any time.
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
import { debugOf } from "bun-app-window/debug";
|
|
229
|
+
|
|
230
|
+
const d = debugOf(shell);
|
|
231
|
+
d.metrics(); // Returns pos / win / client / work / border / round geometry
|
|
232
|
+
d.dpi(); // Returns DPI awareness level and scaling factor
|
|
233
|
+
d.hittest(x, y);
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Common Recipes & Best Practices
|
|
237
|
+
|
|
238
|
+
### 1. Disabling Browser-Specific UI
|
|
239
|
+
|
|
240
|
+
WebView2 enables standard browser interactions by default. Desktop applications typically disable all of them:
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { BROWSER_UI_ALL } from "bun-app-window";
|
|
244
|
+
|
|
245
|
+
const shell = await openShell({ url, browserUi: BROWSER_UI_ALL });
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Individual flags can also be combined via bitwise OR:
|
|
249
|
+
|
|
250
|
+
| Flag | Disabled Behavior |
|
|
251
|
+
| --- | --- |
|
|
252
|
+
| `BROWSER_UI_MENU` | Default Edge right-click context menu |
|
|
253
|
+
| `BROWSER_UI_KEYS` | Built-in browser shortcuts (`Ctrl+P`, `Ctrl+F`, `Ctrl+S`) |
|
|
254
|
+
| `BROWSER_UI_STATUSBAR` | Bottom-left URL hover status bar |
|
|
255
|
+
| `BROWSER_UI_SWIPE` | Trackpad horizontal swipe back/forward navigation |
|
|
256
|
+
| `BROWSER_UI_AUTOFILL` | Form autofill popups |
|
|
257
|
+
|
|
258
|
+
Note: `F11`, `F12`, and `Ctrl±` zoom shortcuts are handled directly by the native shell and remain active regardless of these flags.
|
|
259
|
+
|
|
260
|
+
### 2. Native Context Menu
|
|
261
|
+
|
|
262
|
+
After disabling the default browser menu, render native Win32 popup menus (`TrackPopupMenu`) via `showContextMenu`. The page cannot call it directly — expose it through the IPC service first:
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
// Host: expose the menu capability on the window service
|
|
266
|
+
createIpcServer({
|
|
267
|
+
service: {
|
|
268
|
+
window: {
|
|
269
|
+
showContextMenu: (x: number, y: number, items: string) =>
|
|
270
|
+
shell.showContextMenu(x, y, items),
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
// Page: trigger the native menu
|
|
278
|
+
document.addEventListener("contextmenu", async (e) => {
|
|
279
|
+
e.preventDefault();
|
|
280
|
+
await api.window.showContextMenu(
|
|
281
|
+
Math.round(e.screenX),
|
|
282
|
+
Math.round(e.screenY),
|
|
283
|
+
"open|Open\nrefresh|Refresh\n-\nquit|Quit"
|
|
284
|
+
);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Page: handle menu item selection
|
|
288
|
+
window.addEventListener("shell-msg", (e) => {
|
|
289
|
+
if (e.detail.t === "menu") console.log("Selected ID:", e.detail.id);
|
|
290
|
+
});
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Menu items are specified as a newline-delimited string: `id|Label` per line, or `-` for a separator line.
|
|
294
|
+
|
|
295
|
+
### 3. File Drag and Drop
|
|
296
|
+
|
|
297
|
+
Pass `FLAG_ACCEPT_DROP` to receive file and folder drops from Windows Explorer:
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
// Host
|
|
301
|
+
import { openShell, FLAG_ACCEPT_DROP } from "bun-app-window";
|
|
302
|
+
|
|
303
|
+
const shell = await openShell({ url, flags: FLAG_ACCEPT_DROP });
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
```js
|
|
307
|
+
// Page
|
|
308
|
+
window.addEventListener("shell-msg", (e) => {
|
|
309
|
+
if (e.detail.t === "drop") console.log("Dropped paths:", e.detail.paths);
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
When running in an elevated administrator process (High Integrity Level) while Explorer runs at Medium Integrity Level, the shell automatically whitelists drop messages across UIPI via `ChangeWindowMessageFilterEx`.
|
|
314
|
+
|
|
315
|
+
### 4. Recommended Desktop CSS Reset
|
|
316
|
+
|
|
317
|
+
The shell does not inject any implicit DOM nodes or stylesheets into your page. To make your web UI feel like a native desktop app, include the following baseline rules:
|
|
318
|
+
|
|
319
|
+
```css
|
|
320
|
+
html, body { cursor: default; }
|
|
321
|
+
body { user-select: none; }
|
|
322
|
+
input, textarea, .log { user-select: text; cursor: auto; }
|
|
323
|
+
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
```html
|
|
327
|
+
<input type="text" spellcheck="false" autocomplete="off" autocapitalize="off">
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Setting `spellcheck="false"` is particularly important—red squiggly underlines beneath file paths and numeric inputs immediately give away a web view.
|
|
331
|
+
|
|
332
|
+
### 5. Compiling to a Standalone Executable (.exe)
|
|
333
|
+
|
|
334
|
+
When bundling with `bun build --compile`, import `bun-app-window/embedded` to embed `libshell.dll` directly inside the single-file executable:
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
import { createShell } from "bun-app-window";
|
|
338
|
+
import { embeddedDll } from "bun-app-window/embedded"; // Embeds the DLL into the binary
|
|
339
|
+
|
|
340
|
+
const shell = await createShell({ url, embedded: embeddedDll });
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
bun build --compile --windows-hide-console src/index.ts --outfile dist/app.exe
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
Tips:
|
|
348
|
+
|
|
349
|
+
- A side-effect import `import "bun-app-window/embedded";` also works automatically.
|
|
350
|
+
- Always pass `--windows-hide-console` for GUI builds; omitting it will spawn a black command prompt window alongside your application.
|
|
351
|
+
|
|
352
|
+
## Internals & Reference
|
|
353
|
+
|
|
354
|
+
### Native Library Resolution Order
|
|
355
|
+
|
|
356
|
+
At runtime, `libshell.dll` is located in the following order:
|
|
357
|
+
|
|
358
|
+
1. Explicit path: `opts.nativeLibPath`, bypassing all fallback heuristics.
|
|
359
|
+
2. Embedded payload: Extracted to `%LOCALAPPDATA%\<appName>\runtime` named by content hash (stale versions are automatically pruned).
|
|
360
|
+
3. Executable directory: `libshell.dll` located next to the running `.exe`.
|
|
361
|
+
4. Development paths: `.build/libshell.dll` followed by `dist/libshell.dll` relative to the package root.
|
|
362
|
+
|
|
363
|
+
### Built-in Keyboard & Mouse Shortcuts
|
|
364
|
+
|
|
365
|
+
| Input | Behavior |
|
|
366
|
+
| --- | --- |
|
|
367
|
+
| `Ctrl +` / `Ctrl -` / `Ctrl 0` | Zoom in / Zoom out / Reset zoom to 100% |
|
|
368
|
+
| `Ctrl + Mouse Wheel` | Zoom in / Zoom out |
|
|
369
|
+
| `F11` | Toggle fullscreen mode (hides window borders and covers the taskbar) |
|
|
370
|
+
| `F5` / `Ctrl + R` | Reload page |
|
|
371
|
+
| `F12` | Open WebView2 Developer Tools |
|
|
372
|
+
| `Alt + Space` / Right-click title bar | Open native Windows system menu |
|
|
373
|
+
|
|
374
|
+
## Development & Verification
|
|
375
|
+
|
|
376
|
+
Built with Bun 1.4.3 and TypeScript 7.0.2 with full strict type-checking enabled. Quality gates use standard CLI commands:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
bun check # Run TypeScript type checker
|
|
380
|
+
bun test # Run automated test suite (tests/, 103 test cases)
|
|
381
|
+
bun run demo # Launch interactive self-test demo (requires desktop session)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Whenever `src/shell/` or `package.json` is modified, run the external consumer smoke test documented under the package acceptance section in `AGENTS.md`.
|
|
385
|
+
|
|
386
|
+
For window enumeration (`EnumWindows`) or automated screenshot scripts, filter by the corresponding Win32 window class name:
|
|
387
|
+
|
|
388
|
+
| Window Mode | Window Class Name |
|
|
389
|
+
| --- | --- |
|
|
390
|
+
| Standard framed (without `FLAG_FRAMELESS`) | `webview` |
|
|
391
|
+
| Frameless (with `FLAG_FRAMELESS`) | `webview_shell` |
|
|
392
|
+
|
|
393
|
+
## Acknowledgments
|
|
394
|
+
|
|
395
|
+
- Platform windowing layer based on [webview/webview](https://github.com/webview/webview) `0.12.0` (MIT License, Serge Zaitsev & Steffen André Langnes). `vendor/webview/` contains an unmodified upstream copy.
|
|
396
|
+
- WebView2 SDK provided by [Microsoft.Web.WebView2](https://www.nuget.org/packages/Microsoft.Web.WebView2) `1.0.1150.38` (NuGet package vendored for offline builds). The WebView2 Runtime is provided by the OS.
|
|
397
|
+
- Co-authored-by DeepSeek
|
|
398
|
+
|
|
399
|
+
## License
|
|
400
|
+
|
|
401
|
+
Released under the [MIT License](./LICENSE). `vendor/webview/` is also MIT-licensed with original copyright notices retained in source files.
|