Skip to content

Read a press's button without naming PointerEvent - #21

Merged
tjcouch-sil merged 3 commits into
mainfrom
fix-pointerdown-without-pointerevent
Sep 23, 2026
Merged

tjcouch-sil merged 3 commits into
mainfrom
fix-pointerdown-without-pointerevent

Conversation

@tjcouch-sil

@tjcouch-sil tjcouch-sil commented Sep 23, 2026 •

Copy link
Copy Markdown
Member

Fixes the paranext-core CI break from #13 (e.g. this run). Core's platform-bible-react tests all pass, but the run finishes with 18 unhandled ReferenceError: PointerEvent is not defined and exits 1.

Cause: the pointerdown listener in DecoratorBoundarySelectionPlugin checked event instanceof PointerEvent. jsdom only added a PointerEvent global in v27. This repo tests under jsdom 28, so the reference always resolved here. paranext-core tests under jsdom 26, so every press threw inside the listener.

Fix: check the button with "button" in event && event.button !== 0, which doesn't reference any global. The behavior stays the same: a secondary-button press still doesn't count as a drag, and a press with no button (a plain Event) still counts as a primary one. I didn't use a typeof PointerEvent !== "undefined" guard. It would also work, but it keeps the dependency on a realm global, and that dependency is what broke.

Tests (decoratorBoundarySelection.test.tsx):

  • treats a press as a drag in a host that defines no PointerEvent: removes the global and presses. Before the fix it fails with the same ReferenceError core CI shows.
  • writes the DOM straight away after a secondary-button press: covers the button guard, which no test covered before. It fails if the guard is removed.

The committed packages/platform/dist is rebuilt, and verify-committed-dist passes. The only dist change is the one guard line.

After merge: move platform-yalc (npm run move-platform-yalc). Core's CI builds the editor from that branch, so it stays red until then. Nothing on the paranext-core side needs to change.

AI-assisted

🤖 Generated with Claude Code


This change is Reviewable

tjcouch-sil and others added 2 commits September 23, 2026 10:40
DecoratorBoundarySelectionPlugin's pointerdown listener checked
`event instanceof PointerEvent`. jsdom before 27 defines no PointerEvent
global, so every press in such a host threw a ReferenceError from the
listener. paranext-core's platform-bible-react suite runs under jsdom 26
and ends with 18 unhandled errors, failing its CI on main and every PR.

Duck-type the button instead: a press carrying `button` is primary only
when it is 0; one carrying none (a plain Event) still counts as primary,
as it did before.

Pins both sides: a secondary-button PointerEvent writes the DOM straight
away, and a press still counts as a drag with the PointerEvent global
removed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@tjcouch-sil
tjcouch-sil enabled auto-merge (squash) September 23, 2026 16:09

@rolfheij-sil rolfheij-sil left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Claude: Approved. The "button" in event guard behaves the same in real browsers, cannot throw under jsdom, the committed dist carries exactly that one-line change, and the new test reproduces the original failure (fails on c5c4f37, passes here). A sweep of libs and packages/*/src found no other instanceof/new use of a browser-only global on a path core's suite reaches. Two optional nits inline. Reminder from the PR body: paranext-core stages from platform-yalc, so after merging, npm run move-platform-yalc is what unbreaks core CI.

…-repo claim

Save and restore the global's property descriptor rather than its value,
so the test leaves the global exactly as vitest installed it. Phrase the
no-PointerEvent host generically instead of naming another repo's jsdom.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@tjcouch-sil
tjcouch-sil merged commit 7c89922 into main Sep 23, 2026
5 checks passed
@tjcouch-sil
tjcouch-sil deleted the fix-pointerdown-without-pointerevent branch September 23, 2026 16:28
tjcouch-sil added a commit that referenced this pull request Oct 1, 2026
Brings in #13 (Standard-view copy/paste), #21, and the \periph, gutter
and font-fallback work. Conflict resolutions: node.utils.ts ours;
unknownUsfm.utils.ts both; usfmFragmentToUsj.ts main's pushTableCell
(tests: both sides); selection.utils.ts ours (subsumes main's closing
glyph fix, whose tests pass unchanged); Editor.tsx imports union and
insertNote live-resolution inside main's discrete update;
markerEdit.test-helpers.tsx both; settledGetUsj.test-helpers.tsx both
mount options; dist ours (rebuilt at the end of the round).

Details:
- usfmFragmentToUsj.ts: main's five hunks; this branch's two auto-merged
  comment hunks (the cell-marker regex doc and the para-case table
  comment) are kept. Both call-site conditions this branch pinned
  (`tableEligible && tableRow`, `!token.isNested && !note &&
  !isNoteContext && tableRow`) are present in main's code.
- usfmFragmentToUsj.test.ts: both describe blocks whole (this branch's
  default-stylesheet cell rows, main's \periph rows); no row appears on
  both sides; the doubled defaultStyleInfo import is dropped.
- Editor.tsx imports: copySelection, cutSelection and
  DecoratorBoundarySelectionPlugin added. DeltaOnChangePlugin and DeltaOp
  are not, since this branch no longer uses either.
- settledGetUsj.test-helpers.tsx: structureProtectionMode passes through
  editorWith's options next to view, isReadonly and styleInfo.
- dist: packages/platform/dist taken from this branch whole, index.d.ts
  included.
- Semantic merge fixes (this branch made the view options explicit):
  MarkersViewCopyPlugin.tsx passes its viewOptions to
  $getUsjSelectionFromEditor and the Standard view options to
  $getRangeFromUsjSelection; main's new selection.utils.test.ts row calls
  $getUsjSelectionFromEditor(undefined).
- Lockfile: main adds postcss to platform devDependencies; installed with
  `pnpm install --frozen-lockfile`.
- New annotationLocations/exactAnnotationLocations.test.tsx pins that a
  pasted copy of an annotated attribute run holds no annotation on both
  internal-paste paths that insert nodes: Lexical's rich-paste insertion
  (structure protection off), which reaches the strip through
  SELECTION_INSERT_CLIPBOARD_NODES_COMMAND (the row fails with the strip
  disabled), and the structure-protection html sanitizer, whose nodes come
  from the USFM-bytes text/html and carry no node state. The Standard-view
  external-paste claim, the attribute-context claim, the in-note line
  replay and the char-stack line replay all insert re-tokenized USFM
  text, which carries no node state, so they need no row.

Tests: shared 752 -> 778 (main +26); shared-react 1769+1 skipped ->
1786+1 (main +17); platform 2431 -> 2702+3 skipped (main +269 and 3
skipped, new pin rows +2); utilities 59, scribe 2 unchanged. This
branch's own delta over the merge base: shared +77, shared-react +115,
platform +739. nx lint 10/10, nx typecheck 10/10.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: 2c4fe30c-6a8b-42a8-ba57-9141bb0ab91f
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.

2 participants