Block editor: one drag handle per row; Delete last in the block menu #1171

Open
opened 2026-10-06 02:07:58 +00:00 by kayg · 7 comments
Owner

Follow-ups from the #1152 visual review (orchestrator, 2026-10-06)

  1. Two drag handles on one row (block-selection-multi-1440-mono-4x.png): the last selected list item shows the block handle and the list-item handle side by side. Exactly one handle per row: for list items the list-item handle replaces the block handle, aligned to the first line.
  2. Block menu order (block-pill-menu-1440-noir-4x.png): "Copy link to note" sits after "Delete block". Group link actions together (Copy link to block, Copy link to note) near Share, and keep the destructive Delete block LAST in its own group, per the menu rules (DESIGN menu section).
## Follow-ups from the #1152 visual review (orchestrator, 2026-10-06) 1. **Two drag handles on one row** (block-selection-multi-1440-mono-4x.png): the last selected list item shows the block handle and the list-item handle side by side. Exactly one handle per row: for list items the list-item handle replaces the block handle, aligned to the first line. 2. **Block menu order** (block-pill-menu-1440-noir-4x.png): "Copy link to note" sits after "Delete block". Group link actions together (Copy link to block, Copy link to note) near Share, and keep the destructive Delete block LAST in its own group, per the menu rules (DESIGN menu section).
Author
Owner

Starting work on job/fu-1171 from base SHA f5fbced3c7. I will fix the duplicate selected-list-item drag affordance and move the two copy-link actions ahead of the final Delete block group.

Starting work on job/fu-1171 from base SHA f5fbced3c733370b5b37544d7816732628be2fd0. I will fix the duplicate selected-list-item drag affordance and move the two copy-link actions ahead of the final Delete block group.
Author
Owner

Finding: draws one cue per selected row, while keeps the singleton anchored until another in-editor target resolves. When the pointer leaves the editor, the selected list row can retain both visuals. Finding: appends Copy link to note and text-selection actions after , whose Delete action was not in an isolated final group.

Finding: draws one cue per selected row, while keeps the singleton anchored until another in-editor target resolves. When the pointer leaves the editor, the selected list row can retain both visuals. Finding: appends Copy link to note and text-selection actions after , whose Delete action was not in an isolated final group.
Author
Owner

Finding: NoteEditorSurface.svelte draws one selection cue per selected row. packages/editor/src/extensions.ts can leave the floating drag handle on the last row after the pointer leaves the editor, so that row shows both cues. NoteView.svelte appends Copy link to note and text-selection actions after blockMenuItems, so Delete was not in the final isolated group.

Finding: NoteEditorSurface.svelte draws one selection cue per selected row. packages/editor/src/extensions.ts can leave the floating drag handle on the last row after the pointer leaves the editor, so that row shows both cues. NoteView.svelte appends Copy link to note and text-selection actions after blockMenuItems, so Delete was not in the final isolated group.
Author
Owner

The first post-merge bun run check found one moved exact perf pin in contracts/perf/exceptions.json for NoteView.svelte. I will refresh the pin from the live contract entry, without changing its limit or rule.

The first post-merge bun run check found one moved exact perf pin in contracts/perf/exceptions.json for NoteView.svelte. I will refresh the pin from the live contract entry, without changing its limit or rule.
Author
Owner

The first local server build reached calternal-server but failed because its embedded frontend at apps/web/build/ was absent. I will build the production SPA first, then retry the local server build for the required real-server screenshots.

The first local server build reached calternal-server but failed because its embedded frontend at apps/web/build/ was absent. I will build the production SPA first, then retry the local server build for the required real-server screenshots.
Author
Owner

Production browser finding:

  • The selected list-row handle review passed for 390, 820 and 1440 px in Mono and Noir.
  • The menu-only production run passed those same six combinations. It checks Copy link to block and Copy link to note adjacency, and that Delete block is last.
  • The wider #1152 capsule run timed out at apps/web/e2e/notes.mjs:1229 waiting for the hover toolbar to detach after a pointer move at 1440 px in Noir. I kept that assertion unchanged and added a focused #1171 menu capture mode.

The six selected-row screenshots and six menu screenshots are attached to this issue.

Production browser finding: - The selected list-row handle review passed for 390, 820 and 1440 px in Mono and Noir. - The menu-only production run passed those same six combinations. It checks Copy link to block and Copy link to note adjacency, and that Delete block is last. - The wider #1152 capsule run timed out at apps/web/e2e/notes.mjs:1229 waiting for the hover toolbar to detach after a pointer move at 1440 px in Noir. I kept that assertion unchanged and added a focused #1171 menu capture mode. The six selected-row screenshots and six menu screenshots are attached to this issue.
Author
Owner

Final report

Implemented #1171 on job/fu-1171.

  • The block menu now puts “Copy link to block” next to “Copy link to note”. Existing selection-specific Ask actions stay before a separator, with “Delete block” last in its own destructive group.
  • dragHandle() tags the row it currently owns. The Notes selection cue hides on that row while the floating handle is active, so the row has one grip. The tag clears when the target changes, the extension becomes inactive, or it is destroyed.
  • Added production E2E assertions for the menu order and selected-row handle coverage, plus screenshot capture of the block menu at 390, 820 and 1440 px in Mono and Noir with macOS shortcut detection.
  • Extended bench/notes-editor-series.mjs with a focused list-handle profile. The local runs timed out waiting for the active row target, so no valid performance measurements were produced and docs/perf/baseline.json is unchanged. The last run also logged one Notes index warning: sqlite_code="5" pool_timeout=false. The measurements need a working target probe before they can be compared with a baseline.

Files

apps/web/e2e/notes.mjs, apps/web/src/lib/editor/blockMenu.ts, apps/web/src/lib/editor/blockMenu.test.ts, apps/web/src/lib/notes/NoteView.svelte, apps/web/src/lib/notes/NoteEditorSurface.svelte, packages/editor/src/extensions.ts, packages/editor/src/extensions.dragHandle.test.ts, bench/notes-editor-series.mjs, contracts/perf/adoption-1058.json, contracts/perf/exceptions.json.

Verification

cd apps/web && bun run check:

PASS production dependency licences: 759 locked package releases across apps/web, apps/docs and packages
perf-lint: PASS; 0 violations; 22359 scoped exceptions
svelte-check found 0 errors and 2 warnings in 2 files

The two existing Svelte warnings are empty CSS rulesets in packages/ui/src/components/calendar/AttachmentDeck.svelte:1055:3 and packages/ui/src/components/calendar/AgendaList.svelte:1277:3.

cd apps/web && bun run test:

Test Files 274 passed (274)
Tests 1909 passed (1909)
Duration 626.42s

Focused checks: blockMenu.test.ts passed 8 tests; extensions.dragHandle.test.ts passed 9 tests. node --check bench/notes-editor-series.mjs and git diff --check passed with no output. No Rust source changed, so Rust crate gates were not applicable. Production SPA build output: Compressed 905 static variants; saved 21084281 bytes. Cleanup: Removed 8634 files, 7.3GiB total from cargo clean; removed apps/web/build, apps/web/.svelte-kit/output, tests/adversarial/node_modules and target/tmp.

Production browser checks passed:

notes #1152 selection/TOC e2e: 1440, 820, 390 px in Mono/Noir and Make a note passed
CSP REPORTS notes: 0 across 1 pages
notes #1171 block menu e2e: 390, 820 and 1440 px in Mono and Noir passed
CSP REPORTS notes: 0 across 1 pages

UX gaps

Closed: menu link ordering and final Delete group; one visible grip per selected row when the floating handle owns that row; macOS-rendered screenshots across phone, tablet and desktop in both themes.

Left: the broader NOTES_E2E_BLOCK_ACTIONS_ONLY=1 run still times out waiting for the hover toolbar to detach after moving from a long paragraph to a full-width paragraph at 1440 px in Noir. Its assertion was left unchanged. The focused menu and selection screenshot paths pass. The focused performance profile also needs its active-target wait fixed before it can produce numbers.

Decisions not specified in DESIGN

The menu section does not assign a group to the existing Ask actions. I kept them immediately before the final Delete group, separated from Duplicate and Delete. The two link actions remain adjacent in the opening group.

Screenshots

Selection/TOC screenshots (macOS rendering):

Block-menu screenshots (macOS rendering):

For the merge round

Run cd apps/web && bun run test:e2e:notes. It must verify the complete Notes flow and determine whether the 1440 px Noir hover-toolbar timeout remains. No API contract changed, so no adversarial API matrix is required.

Head SHA: 14d0e639d3b0f444e4af8d5e4e888c6c387f6bd5

## Final report Implemented #1171 on `job/fu-1171`. - The block menu now puts “Copy link to block” next to “Copy link to note”. Existing selection-specific Ask actions stay before a separator, with “Delete block” last in its own destructive group. - `dragHandle()` tags the row it currently owns. The Notes selection cue hides on that row while the floating handle is active, so the row has one grip. The tag clears when the target changes, the extension becomes inactive, or it is destroyed. - Added production E2E assertions for the menu order and selected-row handle coverage, plus screenshot capture of the block menu at 390, 820 and 1440 px in Mono and Noir with macOS shortcut detection. - Extended `bench/notes-editor-series.mjs` with a focused list-handle profile. The local runs timed out waiting for the active row target, so no valid performance measurements were produced and `docs/perf/baseline.json` is unchanged. The last run also logged one Notes index warning: `sqlite_code="5" pool_timeout=false`. The measurements need a working target probe before they can be compared with a baseline. ### Files `apps/web/e2e/notes.mjs`, `apps/web/src/lib/editor/blockMenu.ts`, `apps/web/src/lib/editor/blockMenu.test.ts`, `apps/web/src/lib/notes/NoteView.svelte`, `apps/web/src/lib/notes/NoteEditorSurface.svelte`, `packages/editor/src/extensions.ts`, `packages/editor/src/extensions.dragHandle.test.ts`, `bench/notes-editor-series.mjs`, `contracts/perf/adoption-1058.json`, `contracts/perf/exceptions.json`. ### Verification `cd apps/web && bun run check`: ```text PASS production dependency licences: 759 locked package releases across apps/web, apps/docs and packages perf-lint: PASS; 0 violations; 22359 scoped exceptions svelte-check found 0 errors and 2 warnings in 2 files ``` The two existing Svelte warnings are empty CSS rulesets in `packages/ui/src/components/calendar/AttachmentDeck.svelte:1055:3` and `packages/ui/src/components/calendar/AgendaList.svelte:1277:3`. `cd apps/web && bun run test`: ```text Test Files 274 passed (274) Tests 1909 passed (1909) Duration 626.42s ``` Focused checks: `blockMenu.test.ts` passed 8 tests; `extensions.dragHandle.test.ts` passed 9 tests. `node --check bench/notes-editor-series.mjs` and `git diff --check` passed with no output. No Rust source changed, so Rust crate gates were not applicable. Production SPA build output: `Compressed 905 static variants; saved 21084281 bytes.` Cleanup: `Removed 8634 files, 7.3GiB total` from `cargo clean`; removed `apps/web/build`, `apps/web/.svelte-kit/output`, `tests/adversarial/node_modules` and `target/tmp`. Production browser checks passed: ```text notes #1152 selection/TOC e2e: 1440, 820, 390 px in Mono/Noir and Make a note passed CSP REPORTS notes: 0 across 1 pages notes #1171 block menu e2e: 390, 820 and 1440 px in Mono and Noir passed CSP REPORTS notes: 0 across 1 pages ``` ### UX gaps Closed: menu link ordering and final Delete group; one visible grip per selected row when the floating handle owns that row; macOS-rendered screenshots across phone, tablet and desktop in both themes. Left: the broader `NOTES_E2E_BLOCK_ACTIONS_ONLY=1` run still times out waiting for the hover toolbar to detach after moving from a long paragraph to a full-width paragraph at 1440 px in Noir. Its assertion was left unchanged. The focused menu and selection screenshot paths pass. The focused performance profile also needs its active-target wait fixed before it can produce numbers. ### Decisions not specified in DESIGN The menu section does not assign a group to the existing Ask actions. I kept them immediately before the final Delete group, separated from Duplicate and Delete. The two link actions remain adjacent in the opening group. ### Screenshots Selection/TOC screenshots (macOS rendering): - Mono 390: https://git.kayg.org/attachments/d3ccb82f-8975-485e-8810-faf979756a61 - Mono 820: https://git.kayg.org/attachments/1235e30b-bafd-4002-89d4-8bb96261f714 - Mono 1440: https://git.kayg.org/attachments/9c185f31-a70f-44a2-839d-b94509bc514a - Noir 390: https://git.kayg.org/attachments/72037d29-6a56-4eb1-a38b-8208ebd5c319 - Noir 820: https://git.kayg.org/attachments/cbcf25f0-75ef-4e75-b24e-b4a03b981455 - Noir 1440: https://git.kayg.org/attachments/edc5eaf7-2655-40bc-8082-16152ed29b76 Block-menu screenshots (macOS rendering): - Mono 390: https://git.kayg.org/attachments/4b9c5d37-9f5a-4135-8912-23381f7cdf23 - Mono 820: https://git.kayg.org/attachments/6a4a5ed4-93a0-4ba3-876b-9e3322854ad6 - Mono 1440: https://git.kayg.org/attachments/7a5b7e13-20e9-40d2-a3b4-c2d221a6bad4 - Noir 390: https://git.kayg.org/attachments/be08c2c7-340c-4791-8d0d-14b8a617f408 - Noir 820: https://git.kayg.org/attachments/6bbd883d-0451-4c47-bc90-dc611c0bf2b9 - Noir 1440: https://git.kayg.org/attachments/ee3efcc7-55db-4e30-9ca8-42b4042cd905 - 4x crop, 820 Mono: https://git.kayg.org/attachments/bb0bcec5-c1a4-480c-8c56-ed5525233fd9 - 4x crop, 820 Noir: https://git.kayg.org/attachments/5dcddfc1-64b8-405f-a817-3145b18fc2dd - 4x crop, 1440 Mono: https://git.kayg.org/attachments/09ea5b80-a5a0-4a7b-b172-e71fc6fbc046 ### For the merge round Run `cd apps/web && bun run test:e2e:notes`. It must verify the complete Notes flow and determine whether the 1440 px Noir hover-toolbar timeout remains. No API contract changed, so no adversarial API matrix is required. Head SHA: `14d0e639d3b0f444e4af8d5e4e888c6c387f6bd5`
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#1171
No description provided.