Skip to content

chore(release): v0.11.0 - #21

Merged
nprudhomme merged 4 commits into
mainfrom
chore/release-0.11.0
Aug 13, 2026
Merged

nprudhomme merged 4 commits into
mainfrom
chore/release-0.11.0

Conversation

@nprudhomme

@nprudhomme nprudhomme commented Jul 3, 2026 •

Copy link
Copy Markdown
Member

Description

Release branch for v0.11.0. Carries the version bump, the changelog, and a fix for a bug reported on 0.10.0 that made the app unusable.

The multi-window work (#22) is already on main and ships in this release — its changelog entries are added here, since that PR landed without them.

Fixed — window becoming completely unresponsive

Reported on 0.10.0: no clicks on Open Folder, no file selection in the sidebar, no scrolling, while the native menu bar kept working.

A modal backdrop (#confirm-backdrop, #prefs-backdrop) could be left in display: flex while fully transparent, covering the window at z-index: 2000. It swallowed every pointer event while staying invisible, and since the close path had already detached its listeners, there was no way to dismiss it — the app was unusable until restart.

Both backdrops were shown and hidden through deferred callbacks. WebKit suspends animation frames and timers while a window is occluded, so neither the reveal nor the hide is guaranteed to run, leaving the layer displayed but never marked visible.

The fix makes interactivity follow opacity in CSS: an overlay without .visible is click-through and removed from the tab order and the accessibility tree. That is the load-bearing guarantee — it holds whatever the reason the layer got stuck, including a keyboard user reaching a destructive button inside a dialog they cannot see.

Defence in depth on top of it:

  • reveal synchronously (forced reflow, then class) instead of from a frame callback, so a dialog opened on an occluded window is still visible and therefore dismissable
  • track an open generation so a pending hide never acts on a backdrop a newer open has claimed, in both the confirm dialog and Preferences
  • focus the trap immediately, since callers now reveal before trapping

Applied to all three full-screen overlays: modal backdrops, image lightbox and mermaid fullscreen.

Verification

  • npx tsc --noEmit, 314 tests (3 new, covering the two suspension modes that produce the observed state: frames never delivered, and timers never delivered), cargo build --release clean
  • The new tests were confirmed to fail without the fix
  • Signed and notarized build tested on macOS 26.6.1, with the multi-window work merged

Follow-up

#23 tracks a related robustness issue found during the investigation: Tauri's CSP nonce can silently drop inline style= attributes in packaged builds, which would leave those same backdrops displayed from launch. Not reproducible on macOS 26.6.1, and the CSS safety net above already neutralises the consequence.

Type of Change

  • Bug fix
  • New feature
  • Refactoring
  • Documentation

Checklist

  • I have tested my changes locally
  • I have updated the documentation if needed
  • My code follows the existing code style

https://claude.ai/code/session_01NcJuB2iR4WEfuQVLpYqWi4

Bump version to 0.11.0 and document the user-facing changes since 0.10.0:
native File/View menus with Open Recent (#19), fast document open with
in-memory cache, cloud-sync UX and a debug HUD (#18), and a search
highlight fix on document switch / 1->0 clear (#17).
A modal backdrop could be left in `display: flex` while fully transparent,
covering the whole window at z-index 2000. It swallowed every click and
scroll while staying invisible, and because the close path had already
detached its listeners, the user had no way to dismiss it — the app was
unusable until restart. Reported on 0.10.0: no clicks on Open Folder, no
file selection in the sidebar, no scrolling, while the native menu bar
still worked.

The backdrops were shown and hidden through deferred callbacks. WebKit
suspends both animation frames and timers while a window is occluded, so
neither the reveal nor the hide is guaranteed to run — leaving the layer
displayed but never marked `visible`.

Make interactivity follow opacity in CSS: an overlay without `.visible`
is now click-through and hidden from the tab order and the accessibility
tree. That is the load-bearing guarantee — it holds whatever the reason
the layer got stuck, including a keyboard user reaching a destructive
button inside an invisible dialog.

Defence in depth on top of it:
- reveal synchronously (forced reflow, then class) instead of from a
  frame callback, so a dialog opened on an occluded window is still
  visible and therefore dismissable;
- track an open generation so a pending hide never acts on a backdrop a
  newer open has claimed, in both confirm-dialog and Preferences;
- focus the trap immediately, since callers now reveal before trapping.

Tests cover the two suspension modes that produce the field state:
frames never delivered, and timers never delivered.

Claude-Session: https://claude.ai/code/session_01NcJuB2iR4WEfuQVLpYqWi4
PR #22 landed without a changelog entry. Covers the new windows, the
native Window menu, the arrangement commands, and the switch from
broadcast to frontmost-window menu delivery.

Claude-Session: https://claude.ai/code/session_01NcJuB2iR4WEfuQVLpYqWi4
The heading still carried the date the release branch was prepared.

Claude-Session: https://claude.ai/code/session_01NcJuB2iR4WEfuQVLpYqWi4
@nprudhomme
nprudhomme force-pushed the chore/release-0.11.0 branch from a604046 to 611f0f6 Compare August 13, 2026 12:04
@nprudhomme
nprudhomme merged commit 55e8ac8 into main Aug 13, 2026
4 checks passed
@nprudhomme
nprudhomme deleted the chore/release-0.11.0 branch August 13, 2026 12:13
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.

1 participant