ZenNotes 2.54.1: in the New note form that note search opens, the first click on Create now lands while a tag is still being typed in the Tags field; 2.54.0 lost that click (the tag turned into a chip, the footer moved, and the click missed), so the note was not created until a second click or Enter
Released on September 22, 2026 as v2.54.1, at 0285443b. The release branch v2.54.1 was cut from main at 0ccfa0b5 (the 2.54.0 release, after its channel commits) and fast-forwarded into main through PR #835. One fix, found the same day 2.54.0 shipped, while the phone shells were being moved onto its core. The commits: 591107e1 Fix(search), then the version bump 0285443b. Nothing else changed since 2.54.0.
🐛 Fixes
- The first click on Create lands while a tag is still typed (New note form, follow-up to #826). In 2.54.0's New note form (note search, Shift+Enter or the Create row), typing a tag in the Tags field and reaching for the Create button with the mouse lost the click. The button took focus the moment the mouse went down; that blurred the Tags field, which committed the typed word as a chip, and the suggestion row under the fields ("Add #urgent", or the vault's matching tags) disappeared, so the footer with Back and Create moved up before the mouse came back up. No click fired. In the built app the button moved 44 px, the release landed on the backdrop outside the card, and the palette closed with the typed name and tag gone; with a taller suggestion list the release lands inside the card and a second click works, which is how it was noticed. Enter was never affected. Now the footer buttons (and the "Open it" button next to the duplicate warning) do not take focus on mouse-down, the same rule the folder and tag rows under the fields already followed, so nothing moves until the click completes, and
create()counts the text still typed in Tags the way Enter does. One click creates the note with the tag under its heading. This is core, so the web client gets it with this version and the phones with the shell releases that adopt this core.
🧰 For contributors
- The fix is
591107e1, two attributes inpackages/app-core/src/components/SearchCreateForm.tsx:onMouseDown={(e) => e.preventDefault()}on the footer's button wrapper and on the collision "Open it"Button, each with a comment stating why (a blur commits the typed tag and unmounts the list under the fields). Tests inpackages/app-core/src/components/SearchPalette.test.ts, describe "the create row opens a New note form": apress(button, focusedField)helper dispatches a cancelablemousedownand blurs the field only when the event was not cancelled, since jsdom does not move focus on its own; "pressing the mouse on Create keeps the Tags field focused, so the click lands and the typed tag counts" and "pressing the mouse on Back keeps the folder list until the click" (the six folder rows are still there after the press). Both were red on the shipped code (focus went tobody, the list unmounted) and are green with the fix. - The live harness is
tools/check-create-click-typed-tag.mjs(local, in this folder): it drives the built desktop app over CDP with both stores isolated and sends the mouse press and release throughInput.dispatchMouseEvent, the only way to see the focus change and the layout shift a syntheticelement.click()skips. It reads the Create button's rectangle between press and release, so the run reports how far the button moved.
Verification
- Unit:
npx turbo run typecheck --forceclean, 7 of 7 tasks;npx turbo run test:run --forcegreen, shared-domain 59 files and 1685 tests, app-core 231 files and 2646 tests (1 skipped), desktop 59 files and 891 tests (4 skipped). Red before, green after: the two newSearchPalette.test.tscases named above. - Live, in the built desktop app over CDP with both stores isolated (
tools/check-create-click-typed-tag.mjs), run against both builds. Sources at0ccfa0b5(2.54.0): after Mod+P, "Click check", Shift+Enter, two Tabs into Tags and "urgent" typed with no Enter, one real click on Create moved focus to the button, turnedurgentinto a chip, removed the suggestion row, moved Create up by 44 px (y358 to 314), closed the palette and wrote nothing (tools/click-before.json, 3 of 10 checks failed). With the fix: the press left the Tags field focused withurgentstill text, Create did not move (movedBy0), one click closed the palette and wroteinbox/Click check.mdas# Click check\n\n#urgent\n\n(tools/click-after.json, 10 of 10). Screenshotstools/click-before-typed-tag.png(the form with the typed tag and the "Add #urgent" row above the footer) andtools/click-after-note-open.png(the new note open with its#urgentline) inspected. - How to test locally:
cd apps/desktop && npx electron-vite build, thennode docs/releases/v2.54.1/tools/check-create-click-typed-tag.mjs after. By hand: open the app, Mod+P, type a name no note has, Shift+Enter, Tab twice into Tags, type a word without pressing Enter, click Create once. Before: the word becomes a chip and the form stays open (or the palette closes with nothing created). After: the note opens with the tag under its heading. - Not exercised live: the web client (same core, same
SearchCreateForm) and the phone shells (they adopt this core; their Cancel-button fix for the same form is a shell CSS change and ships with the shell releases).
Distribution channels
- Release workflow: the tag's run 35777395102 built every platform and finished green on the first attempt, 45 minutes from tag to the last upload (20:00 to 20:45 UTC on September 22). 25 installer assets, the same set as 2.54.0; no demo clips this time. macOS is Developer ID signed and notarized. Both macOS apps carry ZenNotes CLI 0.4.0 as the bundled
zn(read fromContents/Resources/terminal/manifest.jsoninside the arm64 DMG). - AUR:
47e2e79in the separatezennotes-binclone (zennotes-bin 2.54.1-1), mirrored on desktopmainase94608fe;aur-check.ymlpassed (runs 35779082781 onmainand 35779079003 onv2.54.1). The tarball downloaded from the release has SHA-256b2e5cebb753a6d5f735741e9823b9c0519e36ae2a0da5ef00b9ab2417753ef7a, equal to GitHub's asset digest and to the pinned value. - Nix:
nix-update.ymlrun 35779112970 opened bot PR #836, lifted byte-for-byte ontomainas240f5405and closed with a one-line comment pointing at that commit;nix-build.ymlrun 35779429813 passed onmainfirst try.desktopHash(sha256-suXOu3U6bV9zV0HpgjucBRnjauKg2l7wC5qyQXdT73o=) is the same tarball digest as the AUR pin, in SRI form. - nixpkgs: PR #561418 amended in place to
zennotes-desktop: 2.45.0 -> 2.54.1(fork commitb214ff95, force-pushed tozennotes-desktop-2.46.0, body innixpkgs-pr-body.md). Onlyversion,npmDepsHash(sha256-9FDrQVckCFMke9dAUooU68MSEinxIEXCCW3yKI24ueU=) and the sourcehash(sha256-/7YK3BvjxdNwar2dLH+3PI8E1IHR4TYV1GkAEQoy1ZQ=, both lifted frompackaging/nix/release-data.json) change. The runbook's refetch of upstream master was skipped on purpose:git fetch upstream masteragainst the partial clone hung with no progress (0.5 s of CPU in 15 minutes) and was killed, so the commit sits on the base the 2.54.0 restack already had. - Homebrew:
f5d0426in the tap (zennotes 2.54.1), mirrored on desktopmainas67be33c9. The cask pins both DMG digests from the GitHub API (arm6446f3ed18da38f9a519aacf4a7e17cf4c6ec6c4e577ac16823c204c433eb35dbe, x64ec7a534f69226cc18cc7bec3072bc5ee4b3ee1119ebb32b682f07b803df88792), and both equal a localshasumof the downloaded DMGs. - Website: no docs change for a point release; the 2.54.1 releases entry (one fix, no features, no clips) merged as website PR #34 (
54db30df, a merge commit like PR #33). Laravel Cloud deployed it on its own frommain; the release page answered with 2.54.1 within four minutes of the merge (20:57 to 21:01 UTC). - Docker and the server: unchanged by this release.
npm run verify:channels -- 2.54.1: passed at 21:00 UTC: Homebrew tap, AUR, Nix, and all seven website download redirects serve 2.54.1.releases/lateston GitHub answersv2.54.1. The live release page leads with 2.54.1 (47 documented releases).
Release validation
- Release PR #835's CI run 35776341766 passed first try; the fix is core-only (
SearchCreateForm.tsxand its tests), so no packaging change was needed and the branch was fast-forwarded ontomainwithout a merge commit. - Before the cut, on the bumped branch:
npx turbo run typecheck --force7 of 7 andnpx turbo run test:run --forcegreen (shared-domain 1685, app-core 2646 with 1 skipped, desktop 891 with 4 skipped), and the fix itself checked live over CDP with real mouse events against both the shipped and the fixed build (tools/check-create-click-typed-tag.mjs: shipped code moved Create by 44 px and wrote nothing, fixed code moved it by 0 and wrote the note with its tag, 10 of 10 checks). A localnpm run packalso produceddist/mac-arm64/ZenNotes.appat 2.54.1, but the launch check was run on the released artifact (below), not on that local pack. - The release workflow's tag-push path behaved as it did for 2.54.0: each platform's installers went up one at a time and its update manifest last (Linux: assets 20:13:40 to 20:14:22,
latest-linux-arm64.yml20:14:20,latest-linux.yml20:14:23 UTC; Windows: exe 20:37:42, blockmap 20:37:43, zip 20:37:51,latest.yml20:37:52; macOS: DMGs and zips 20:44:25 to 20:45:08,latest-mac.yml20:45:09). macOS was the slowest job at 45 minutes (20:00:27 to 20:45:17). No asset was uploaded twice and nothing had to be rebuilt. - Verified by hand after the uploads: the three installers named by the manifests that
verify-installers.pycovers (ZenNotes-2.54.1-mac-arm64.dmg,ZenNotes-2.54.1-mac-x64.dmg,ZenNotes-2.54.1-win-x64.exe) were downloaded in full and match the size and SHA-512 in their manifest (verify-installers.py 2.54.1 --download, "ALL GOOD"); the arm64 macOS app is accepted by Gatekeeper asNotarized Developer ID(Lumary Labs LLC) with a valid stapled ticket (spctl -a -vvaccepted,stapler validateworked), reads version 2.54.1 and bundleszn0.4.0; the released arm64 app, copied out of its DMG, launches with both stores isolated (packaged-launch-check.mjs: CDP page target in 2.5 s, version 2.54.1, Welcome screen rendered), so the artifact users download was launch-checked, not only the local pack. The x64 app was checksum-verified but not mounted or launched. - Expected red marks, none of them about the release: runs 35779270900 (CI), 35779270988 (Nix build) and 35779271129 (CodeQL) started on the bot branch
nix/update-v2.54.1and lost their branch when PR #836 was closed (each shows no jobs at all), and CI run 35779083328 onmain(the AUR packaging commite94608fe) was cancelled by the next push, the Nix packaging commit240f5405, which CI then ran on and passed. The same pattern appeared on 2.54.0 and 2.53.0. The runs that count, onmain, passed.
Local-first and keyboard-first, as always.