Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
fe0dca4
feat(overlay): exit annotate mode via a far-right X control
angusbezzina Aug 8, 2026
42de397
feat(overlay): exit annotate mode via a far-right X control (VRT-cne0.4)
angusbezzina Aug 8, 2026
00fa0de
feat(marquee): pure frame-selection resolution rule
angusbezzina Aug 8, 2026
413d56d
feat(marquee): pure frame-selection resolution rule (VRT-cne0.5)
angusbezzina Aug 8, 2026
c40a4d2
chore: ignore agent worktree directories
angusbezzina Aug 8, 2026
5e99ca6
feat(marquee): session entry point + persisted frame on notes
angusbezzina Aug 8, 2026
c221644
feat(marquee): session entry point + persisted frame on notes (VRT-cn…
angusbezzina Aug 8, 2026
997577a
fix(marquee): clear the region measuring origin when widening
angusbezzina Aug 8, 2026
7ffbba3
docs(marquee): state the click-routing caller contract on select(inAX…
angusbezzina Aug 8, 2026
53dca4f
feat(marquee): macOS adapters resolve a drawn frame to an element
angusbezzina Aug 8, 2026
c273dde
feat(marquee): macOS adapters resolve a drawn frame to an element (VR…
angusbezzina Aug 8, 2026
33d9822
test(marquee): probe sub-phase 7g pins the overlay out of every ladder
angusbezzina Aug 8, 2026
d94920d
test(marquee): probe sub-phase 7g pins the overlay out of every ladder
angusbezzina Aug 8, 2026
2ea10f5
feat(overlay): marquee drag gesture with a tested click/frame threshold
angusbezzina Aug 8, 2026
09ac045
docs: README covers frame selection
angusbezzina Aug 8, 2026
2a0c40e
feat(marquee): draw a frame on the overlay to select (VRT-cne0.7)
angusbezzina Aug 8, 2026
5da04a4
feat(ios): marquee frame selection + exclude AnnotKit's overlay window
angusbezzina Aug 8, 2026
73d0102
feat(marquee): iOS port + parity (VRT-cne0.8)
angusbezzina Aug 8, 2026
66425a2
feat(overlay): explicit point/frame selection modes with a tool selector
angusbezzina Aug 8, 2026
ecc1706
feat(overlay): explicit point/frame selection modes (VRT-cne0.11)
angusbezzina Aug 8, 2026
9f963e4
feat(overlay): Select Parent / Select Child replace the one-way Widen…
angusbezzina Aug 9, 2026
45b31bb
feat(overlay): Select Parent / Select Child navigation (VRT-mijf.1)
angusbezzina Aug 9, 2026
862a1a0
feat(frame-mode): no hover highlight, and the drawn frame is the anchor
angusbezzina Aug 9, 2026
4554f49
feat(overlay): frame mode shows only the frame and anchors to it (VRT…
angusbezzina Aug 9, 2026
d7cc0eb
fix(marquee): reject a degenerate drag before touching any state
angusbezzina Aug 9, 2026
752e9b5
docs(navigation): record selection navigation + frame anchoring, cove…
angusbezzina Aug 9, 2026
26c3d4c
docs(marquee): DECISIONS/PARITY entries + probe Phase 8 selection nav…
angusbezzina Aug 9, 2026
fd9a00a
feat(icons): real elliptical arcs in the Lucide d-string parser
angusbezzina Aug 9, 2026
61151ea
feat(escape): back out one level at a time via a local key monitor
angusbezzina Aug 9, 2026
34d5964
feat(icons): real elliptical arcs in the Lucide path parser (VRT-dp47.3)
angusbezzina Aug 9, 2026
c6d1c39
feat(overlay): Escape backs out of AnnotKit one level at a time (VRT-…
angusbezzina Aug 9, 2026
516aa11
fix(overlay): re-arm the Escape monitor when re-mounting into an anno…
angusbezzina Aug 9, 2026
fc7c701
fix(overlay): clamp the pill to the visible screen and stop swallowin…
angusbezzina Aug 9, 2026
e158ca9
fix(overlay): keep the pill on screen and forward scroll to the host …
angusbezzina Aug 9, 2026
bb92fe3
feat(cards): one icon row per note card, shared with the pill
angusbezzina Aug 9, 2026
3cb5eee
feat(overlay): inline icon action row in both note cards (VRT-dp47.4)
angusbezzina Aug 9, 2026
8d3091b
fix(overlay): stop the hover-driven relayout storm that hid the pill
angusbezzina Aug 10, 2026
3267df7
fix(overlay): re-assert the clamped panel frame after AppKit's parent…
angusbezzina Aug 10, 2026
be624b4
feat(overlay): the toolbar gets its own window, so it can never move …
angusbezzina Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
feat(overlay): the toolbar gets its own window, so it can never move …
…or vanish

The pill was drawn inside the catcher's ZStack, which made its position a
function of the catcher panel's frame. That frame changes size on every
open/close, is narrowed to the visible screen, and is dragged around by
AppKit whenever the host moves -- three ways for a control that must never
move to move -- and anything that stalled the catcher (a wedged scroll, a
rebuilt SwiftUI root) took the pill down with it.

The toolbar now has its own permanently mounted panel: fixed size, pinned
to the host's bottom-right, re-placed only when the host moves, resizes or
changes screen. Opening the menu creates a SEPARATE catcher panel over the
host and closing it tears that panel down. The menu is now genuinely just
open or closed, and the toolbar itself is untouched by the transition.

Ordering matters and is not free: re-adding an existing child window does
NOT re-stack it (measured -- childWindows still ended with the catcher, and
the catcher sat on top, eating the click that closes the menu). The toolbar
is detached and re-added, then ordered explicitly above the catcher.

Probe updated for the two-panel world: childWindows.first is no longer "the
overlay", and BOTH panels carry the AX identifier -- correctly, since the
point query must skip both -- so 7g now picks the panel that actually spans
the host rather than the first match.

191 tests, probe 11/11, iOS cross-compile clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
  • Loading branch information
angusbezzina and claude committed Aug 10, 2026
commit be624b45963db46724dc4efeb60a6e2cc60046b9
31 changes: 26 additions & 5 deletions Sources/AnnotKit/Overlay/OverlayView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ struct OverlayView: View {
editCard(note: note, anchor: anchor)
}

toolbar
}
.ignoresSafeArea()
.accessibilityHidden(true)
Expand Down Expand Up @@ -577,9 +576,29 @@ struct OverlayView: View {
)
}

/// Pins the compact pill to the host window's bottom-right corner (margin 20,
/// matching the idle child-window frame the controller sizes).
private var toolbar: some View {
}

/// The toolbar pill, in a window of its OWN.
///
/// The pill used to be drawn inside the catcher's ZStack, which meant its position
/// was a function of the catcher panel's frame — and that frame changes size on
/// every open/close, gets narrowed to the visible screen, and is dragged around by
/// AppKit whenever the host window moves. Three ways for a control that must never
/// move to move, and a fourth failure on top: anything that stalled the catcher
/// (a wedged scroll, a rebuilt SwiftUI root) took the pill down with it.
///
/// Giving it a separate, permanently mounted panel makes the guarantee structural
/// rather than incidental: the pill is always present, always at the host's
/// bottom-right corner, and the catcher's geometry and lifetime cannot touch it.
/// The menu is now genuinely just OPEN or CLOSED — the toolbar itself never moves
/// between the two.
struct ToolbarOverlayView: View {
@ObservedObject var session: AnnotationSession
let onToggle: () -> Void
let onCopy: () -> Void
let onExport: () -> Void

var body: some View {
VStack {
Spacer()
HStack {
Expand All @@ -593,6 +612,8 @@ struct OverlayView: View {
.padding(20)
}
}
.ignoresSafeArea()
.accessibilityHidden(true)
}
}

Expand Down Expand Up @@ -741,7 +762,7 @@ private struct AnnotationCard<Footer: View>: View {
/// The pill itself is rendered unconditionally and is NEVER gated on an entrance
/// flag, so it stays visible across idle<->annotate; only its contents swap as
/// annotate mode toggles.
private struct ToolbarView: View {
struct ToolbarView: View {
@ObservedObject var session: AnnotationSession
let onToggle: () -> Void
let onCopy: () -> Void
Expand Down
Loading
Loading