feat(web): highlight extent adjustment — draggable handles with word/punctuation snap

Objective 9 (web half). The selection popover's edit mode gains an
Adjust button: the overlay's show-annotation event stashes the live DOM
range, start/end teardrop handles render over it (host layer above the
iframe), and pointer drags map into the iframe's caretRangeFromPoint.
Snapping: land next to punctuation → the boundary sits exactly there;
land inside a word → the word's edge in the drag direction; whitespace
trims toward the adjacent word. A live preview repaints through the
overlayer under a scratch key; relocation (page turn) cancels safely.

Release recomputes the range CFI + collapsed-end CFI (view.getCFI) and
saves through the popover's own saveHighlightChanges path (PUT +
remove-old/add-new overlay dance), keeping selection_text and the
anchors in lockstep.

Verified live E2E in Brave: extent extended by one word with the
comma/space snap behavior, saved to the server row, handles cleaned;
all snap paths unit-exercised in-page (word end/start, punctuation
exact on both sides, whitespace trim); the test highlight was restored
to its original extent through the same adjust flow (punctuation-precision
drag back to the comma).
This commit is contained in:
John O'Keefe committed 2026-10-05 16:50:27 -04:00
1 parent f45adc6362
commit c8e85817aa
4 files changed
+298 -1

No files matched your search

+10
View File
@@ -161,6 +161,16 @@ templ Reader(user User, metadata ReaderMetadata) {
>
<svg class="reader-icon" width="16" height="16" aria-hidden="true"><path d="M 6 6 V 3 H 16 V 13 H 13 M 3 6 H 13 V 16 H 3 Z"></path></svg>
</button>
<template x-if="selectionPopover.mode === 'edit'">
<button
type="button"
class="reader-popover-btn"
title="Adjust highlight extent"
@click="startAdjust()"
>
<svg class="reader-icon" width="16" height="16" aria-hidden="true"><path d="M 5 3 v 18 M 19 3 v 18 M 5 8 h 14 M 5 16 h 14"></path></svg>
</button>
</template>
<template x-if="selectionPopover.mode === 'edit'">
<button
type="button"