bun-webview2 0.3.0 → 0.3.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1 — 2026-10-13
4
+
5
+ - `minWidth`/`minHeight` window options: minimum window size in client
6
+ coordinates, enforced on user drags and programmatic `setSize` alike
7
+ (via the C library's sizing hints + `WM_GETMINMAXINFO`, with the window
8
+ frame delta compensated). One-sided limits are rejected at creation.
9
+
3
10
  ## 0.3.0 — 2026-10-13
4
11
 
5
12
  - Window layer replaced: hosts now drive the [C `webview` library](https://github.com/webview/webview) through `bun:ffi` — zero npm runtime dependencies. The DLL (~540 KB) is built once with `zig c++` (no MSVC, no cmake); sources and pinned WebView2 SDK headers live in the build workspace.
package/README.md CHANGED
@@ -84,6 +84,7 @@ Related, and also handled for you: on a never-navigated webview target, CDP comm
84
84
  |---|---|---|---|
85
85
  | `title` | `string` | `"bun-webview2"` | Window title |
86
86
  | `width` / `height` | `number` | `800` / `600` | Initial window size |
87
+ | `minWidth` / `minHeight` | `number` | — | Minimum window size (client coordinates); enforced on drags and `setSize` alike. Both must be set together. |
87
88
  | `url` | `string` | — | Initial URL to load |
88
89
  | `html` | `string` | — | Initial inline HTML (loaded as a `data:` URL) |
89
90
  | `contextMenu` | `boolean` | `false` | Allow the native Chromium right-click menu (blocked by default) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bun-webview2",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "main": "./src/index.ts",
5
5
  "module": "./src/index.ts",
6
6
  "devDependencies": {
package/src/host-ffi.ts CHANGED
@@ -21,6 +21,8 @@ interface HostConfig {
21
21
  readonly title: string;
22
22
  readonly width: number;
23
23
  readonly height: number;
24
+ readonly minWidth?: number;
25
+ readonly minHeight?: number;
24
26
  }
25
27
 
26
28
  interface HostCommand {
@@ -65,6 +67,7 @@ const advapi32 = dlopen("advapi32.dll", {
65
67
  const cstr = (s: string) => ptr(Buffer.from(`${s}\0`, "utf8"));
66
68
 
67
69
  const WEBVIEW_HINT_NONE = 0;
70
+ const WEBVIEW_HINT_MIN = 1;
68
71
  const SWP_NOSIZE = 0x0001;
69
72
  const SWP_NOMOVE = 0x0002;
70
73
  const SWP_NOZORDER = 0x0004;
@@ -232,6 +235,23 @@ const bindCallback = new JSCallback(
232
235
 
233
236
  webview.symbols.webview_set_title(handle, cstr(config.title ?? "bun-webview2"));
234
237
  webview.symbols.webview_set_size(handle, config.width ?? 800, config.height ?? 600, WEBVIEW_HINT_NONE);
238
+ if (typeof config.minWidth === "number" && typeof config.minHeight === "number") {
239
+ // WEBVIEW_HINT_MIN stores m_minsz; WM_GETMINMAXINFO enforces it on drags
240
+ // and programmatic resizes alike. The track size is in OUTER coordinates,
241
+ // so the frame delta is added to keep the minimum a CLIENT-size minimum.
242
+ const outer = Buffer.alloc(16);
243
+ const inner = Buffer.alloc(16);
244
+ user32.symbols.GetWindowRect(hwnd, ptr(outer));
245
+ user32.symbols.GetClientRect(hwnd, ptr(inner));
246
+ const frameW = outer.readInt32LE(8) - outer.readInt32LE(0) - (inner.readInt32LE(8) - inner.readInt32LE(0));
247
+ const frameH = outer.readInt32LE(12) - outer.readInt32LE(4) - (inner.readInt32LE(12) - inner.readInt32LE(4));
248
+ webview.symbols.webview_set_size(
249
+ handle,
250
+ Math.max(1, config.minWidth + frameW),
251
+ Math.max(1, config.minHeight + frameH),
252
+ WEBVIEW_HINT_MIN,
253
+ );
254
+ }
235
255
  webview.symbols.webview_bind(handle, cstr("bwv2_host_cmd"), bindCallback.ptr, null);
236
256
 
237
257
  // about:blank keeps the initial document inert; the parent drives all real
package/src/window.ts CHANGED
@@ -29,6 +29,10 @@ export interface Webview2WindowOptions extends HardeningOptions {
29
29
  readonly title?: string;
30
30
  readonly width?: number;
31
31
  readonly height?: number;
32
+ /** Minimum window size. Both must be set together — one-sided limits are rejected. */
33
+ readonly minWidth?: number;
34
+ /** @see minWidth */
35
+ readonly minHeight?: number;
32
36
  /** Initial URL to load. */
33
37
  readonly url?: string;
34
38
  /** Initial inline HTML to load (delivered as a data: URL). */
@@ -123,7 +127,9 @@ class WindowHost {
123
127
  readonly #closedWaiters: Array<() => void> = [];
124
128
  readonly #eventWaiters = new Set<(event: string, payload: unknown) => void>();
125
129
 
126
- constructor(readonly options: { title: string; width: number; height: number }) {
130
+ constructor(
131
+ readonly options: { title: string; width: number; height: number; minWidth?: number; minHeight?: number },
132
+ ) {
127
133
  const config = JSON.stringify(options);
128
134
  // Compiled executables re-run themselves instead of acting as a runtime,
129
135
  // so shipped apps point BWV2_HOST_EXE at a pre-compiled host binary.
@@ -262,11 +268,16 @@ export class Webview2Window {
262
268
  `bun-webview2: dataDir ${opts.dataDir} requested, but this app already uses ${activeDataDir}. All windows share one data folder.`,
263
269
  );
264
270
  }
271
+ if ((opts.minWidth !== undefined) !== (opts.minHeight !== undefined)) {
272
+ throw new Error("bun-webview2: minWidth and minHeight must be set together — one-sided limits are not supported.");
273
+ }
265
274
 
266
275
  const host = new WindowHost({
267
276
  title: opts.title ?? "bun-webview2",
268
277
  width: opts.width ?? 800,
269
278
  height: opts.height ?? 600,
279
+ minWidth: opts.minWidth,
280
+ minHeight: opts.minHeight,
270
281
  });
271
282
 
272
283
  const target: CdpTargetInfo = await waitForPageTarget(activePort, claimedTargets, 15_000, activeDataDir);