Skip to content

Mask assignment popup floats next to the drawn box - #87

Merged
stolau merged 2 commits into
mainfrom
mask-menu-near-selection
Jul 27, 2026
Merged

Mask assignment popup floats next to the drawn box#87
stolau merged 2 commits into
mainfrom
mask-menu-near-selection

Conversation

@stolau

@stolau stolau commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

The mask assignment popup (Global / This snapshot / category buttons) rendered in the Masks
section, well below the image -- after drawing a box near the top of a tall image, the popup
asking what to do with it appeared far out of view.

Moves it into InteractiveImagePane as an absolutely-positioned popup anchored just below-left of
the drawn box, reusing the exact scaleX/scaleY math already used to place saved mask rects --
no new positioning logic. Tracks the box regardless of image size or dual/single view mode.

Test plan

  • npm run lint --workspaces clean
  • npm test --workspaces -- 55 viewer tests pass unchanged (they assert roles/testids, not DOM
    position, so this alone doesn't prove the fix -- see below)
  • Real Docker/Podman + Playwright verification, since jsdom has no layout engine and can't
    meaningfully check CSS positioning: built and ran the real stack under Podman, drove the
    actual drag-to-draw flow in a live browser, screenshotted the popup landing correctly next
    to boxes drawn both near the top and near the bottom of the image, confirmed no clipping
  • npm run test:e2e -w examples/demo-app -- 8/8, including the two tests that exercise this
    exact draw flow
  • viewer/CODEMAP.md updated

Co-Authored-By: Claude Sonnet 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01NrQeh9CXrigN1cvpJuyzy4

anssiuistola and others added 2 commits July 27, 2026 15:39
… of the page

MaskAssignmentMenu rendered in the Masks section, well below the image
-- after drawing a box near the top of a tall image, the popup asking
what to do with it appeared far out of view, disconnected from the
point of interaction.

Moves it into InteractiveImagePane as an absolutely-positioned popup
anchored just below-left of pendingRect, reusing the exact
natural-to-displayed scaleX/scaleY math already used to place saved
mask rects -- no new positioning logic, just the same established
scaling applied to one more rect. Tracks the actual on-screen box
regardless of image size or dual/single view mode.

Verified for real, not just read -- jsdom has no layout engine, so this
class of change can't be meaningfully checked by the unit suite (all 55
tests pass unchanged, since they only assert on roles/testids, never
DOM position). Built and ran the real backend+viewer under Podman,
drove the actual drag-to-draw flow in a live browser, and screenshotted
the popup landing correctly next to boxes drawn both near the top and
near the bottom of the image -- confirmed no clipping either case,
since nothing in the ancestor chain clips overflow. The real e2e suite
(which exercises this exact draw flow) also passes 8/8 against the
changed markup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NrQeh9CXrigN1cvpJuyzy4
Follow-up on the same popup this branch already repositioned:
"Save as global mask" / "Save as mask for this snapshot" / "Cancel"
were full-sentence buttons, needlessly wide now that the popup floats
directly over the image instead of sitting in its own row below it.

- "Save as global mask" -> "+global", "Save as mask for this snapshot"
  -> "+unique" -- both keep their full original text as aria-label, so
  every existing getByRole("button", {name: "Save as..."}) query (unit
  + e2e) still resolves unchanged. The "+" prefix also now matches the
  sibling "+ New category" button's own existing convention, instead of
  introducing a third distinct button-labeling style into one menu.
- Cancel becomes a small solid-red circular "x", aria-label="Cancel",
  mirroring the same icon-button pattern already used for Approve
  (aria-label + glyph) and the masks chip row's remove control.

Verified for real: all 55 unit tests pass unchanged (proving the
aria-label swap preserved every existing role-based query); real
Docker/Podman + Playwright screenshot confirms the compact row actually
renders as intended, not just that the accessible names resolve; real
e2e suite 8/8 against the changed markup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NrQeh9CXrigN1cvpJuyzy4
@stolau
stolau merged commit 4838d2f into main Jul 27, 2026
5 checks passed
stolau pushed a commit that referenced this pull request Jul 27, 2026
…flict

Three PRs landed on main after this branch forked (#86 self-hosting,
#87 mask popup, #88 six more e2e stories), two of which touched the
same examples/demo-app/CODEMAP.md paragraph this branch also edited.
index.html and style.css merged cleanly with no conflict; CODEMAP.md's
prose needed manual reconciliation -- kept main's up-to-date "fourteen
tests" description and spliced this branch's .thumbs gallery sentence
back into the site/ bullet it belongs to.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NrQeh9CXrigN1cvpJuyzy4
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