Skip to content

Remember native window size across opens (fixes #203)#207

Merged
epeicher merged 2 commits into
trunkfrom
fix/203-remember-native-window-size
May 14, 2026
Merged

Remember native window size across opens (fixes #203)#207
epeicher merged 2 commits into
trunkfrom
fix/203-remember-native-window-size

Conversation

@epeicher

@epeicher epeicher commented May 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Native windows (Plugins, Posts, Users, Comments, Settings, …) reopened at the plugin-author defaults on every open, forcing the user to resize them every time. The Plugins window in particular ships at 1180×760 which is too narrow for the installed-plugins table on many setups.

This adds per-baseId { width, height } persistence in localStorage so each native window reopens at the size the user last resized it to.

Dashboard.WordPress.Develop.WordPress.2026-05-14.10-51-55.mp4

How it works

  • New module src/window-manager/native-window-geometry.ts — read/write a single localStorage map (desktop-mode-native-window-geometry), bounded at 64 entries with LRU eviction, with sanity checks on dimensions.
  • src/native-windows.ts:
    • openFromEntry / openNewFromEntry now resolve { width, height } from the saved map when present, falling back to the registered defaults. The stored size is clamped up to the registered min_width / min_height so raising the minimum in a plugin update never reopens at a no-longer-allowed smaller size.
    • A single WINDOW_RESIZE_END listener writes the new size back, but only when the resized window is native AND in state === 'normal'. That keeps snap-zone halves, maximized geometry, and fullscreen geometry from poisoning the stored "preferred" size. Programmatic tiles in arrange.ts / snap-zones.ts go through their own hooks and never fire resize-end, so they don't write either.

Position is intentionally NOT persisted. Cascade-on-open keeps stacked native windows visible across viewport size changes (different monitors, different zoom levels); restoring a remembered position would happily place a window off-screen.

Why not server-side session restore

Native windows are already skipped from the session snapshot because their render callback is a JS closure we can't serialize and rehydrate server-side. Persisting just { width, height } client-side is orthogonal to that constraint and needs no PHP wiring.

Tests

  • tests/vitest/native-window-geometry.test.ts (12 cases): round-trip, rounding, invalid input rejection, ceiling, corrupt-JSON tolerance, overwrite, trim, LRU move-to-end.
  • tests/vitest/native-windows-sync.test.ts (6 new cases under "remembered window size"): default fallback, stored size honored, clamp-up to current minimum, persist-on-resize-end happy path, native-only filter, normal-state-only filter.

Test plan

  • Open the Plugins window from the dock. First time: opens at the default 1180×760.
  • Drag the right edge wider so all plugin-table columns fit. Close it.
  • Open Plugins again. It opens at the new size.
  • Reload the page. Open Plugins. Still at the size you picked.
  • Try the same for any other native window (Posts, Users, Comments, Settings).
  • Snap the window to a half-screen, then close. Reopen: size should NOT be the snapped half, it should be the last floating size you picked.

Fixes #203

Open WordPress Playground Preview

Native windows (Plugins, Posts, Users, …) were always reopening at the
plugin-author defaults, forcing the user to resize them every time. We
already skip native windows from the server-side session snapshot
(their render callback is a closure that can't be rehydrated), but
"size I picked last time" doesn't need server state.

Per baseId `{ width, height }` lives in localStorage under
`desktop-mode-native-window-geometry`, written on
`WINDOW_RESIZE_END` for native windows in normal floating state and
read back in `openFromEntry` / `openNewFromEntry`. Snapped, maximized,
and fullscreen sizes are skipped so a tile layout doesn't poison the
stored "preferred" size. Stored sizes are clamped to the registered
`min_width` / `min_height` on open so raising the minimum in a plugin
update never reopens at the older smaller size. Store is capped at
64 entries with LRU eviction.
@github-actions

github-actions Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor

✅ WordPress Plugin Check Report

✅ Status: Passed

📊 Report

All checks passed! No errors or warnings found.


🤖 Generated by WordPress Plugin Check Action • Learn more about Plugin Check

Builds on the size persistence in the previous commit. The store now
records `{ x, y, width, height, state? }` per baseId in localStorage,
covering classic iframe-backed windows alongside native ones.

Save side: WINDOW_DRAG_END writes size + position (the size write
seeds the entry when there isn't one yet, so open-drag-close paths
get persisted even without a manual resize). WINDOW_RESIZE_END also
captures the post-resize x/y because a top-left corner drag moves
the window. WINDOW_MAXIMIZED / WINDOW_UNMAXIMIZED record the
maximized intent without disturbing the floating size or position.

Read side: `WindowManager.createWindow` consults the same store
whenever the caller doesn't pin `width` / `height` / `initialState`
/ `x` / `y`, falling back through saved -> cascade-from-rect default.
Position is clamped to the current desktop area so a window
remembered at x=2800 on a 3440px display doesn't open off-screen on
a smaller monitor. `manager.openNew` now computes its own cascade
slot and passes explicit x/y so duplicates always cascade off the
primary's remembered spot. Native windows used to hardcode `x: 0,
y: 0` in `openFromEntry`, which short-circuited the replay; that
hardcode is gone.

The unified maximize replay also lets the native path drop its
`.then(win.maximize())` chain; `initialState: 'maximized'` from
`createWindow` handles both window kinds the same way.
@epeicher epeicher merged commit ec895c9 into trunk May 14, 2026
5 checks passed
@epeicher epeicher deleted the fix/203-remember-native-window-size branch May 14, 2026 09:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resize new windows to fit contents

1 participant