Skip to content

feat(plugin-selection): add programmatic setSelection() to apply/restore selections#685

Open
simonmysun wants to merge 1 commit into
embedpdf:mainfrom
simonmysun:feat/selection-restore-api
Open

feat(plugin-selection): add programmatic setSelection() to apply/restore selections#685
simonmysun wants to merge 1 commit into
embedpdf:mainfrom
simonmysun:feat/selection-restore-api

Conversation

@simonmysun

Copy link
Copy Markdown

Summary

@embedpdf/plugin-selection could only clear() a selection — there was no way
to set or restore one programmatically. This adds setSelection() to the
public capability so consumers can persist a selection and reapply it (after
reload, tab switch, etc.) or drive selection from code (e.g. search results,
"jump to citation").

The PR and the example is majorly made by vibe coding with human reviewing.

API

Added to both SelectionCapability and the document-scoped SelectionScope:

setSelection(range: SelectionRangeX | null, documentId?: string): PdfTask<void>;

SelectionRangeX is the exact { start, end } glyph-pointer shape already
emitted by onSelectionChange, so a saved value round-trips back in:

// save
let saved: SelectionRangeX | null = null;
selection.onSelectionChange((e) => { saved = e.selection; });

// restore (task resolves once highlight rects are computed)
selection.setSelection(saved).wait(() => {/* applied */}, ignore);

// clear
selection.setSelection(null);

Scope / notes

  • Only the synthetic, glyph-range text selection has restorable state; the
    marquee (rectangular) feature is event-only and unaffected.
  • Consistent with the existing clear(), this does not touch the native
    browser selection (apps suppress that via user-select: none, as the official
    examples do).

Changes

  • packages/plugin-selection/src/lib/selection-plugin.tsapplySelection
    (wired to setSelection on capability + scope), validateRange,
    clampRangeToGeometry, normalizeRange.
  • packages/plugin-selection/src/lib/types.tssetSelection on
    SelectionCapability and SelectionScope with JSDoc.

Testing

Verified against the built dist with a headless registry + mock engine, and
with runnable React / Vue / Svelte / Preact demo apps temporarily deployed
at https://makelove.expert/tmp/sel-demo-dist/:

  • apply a selection (single page + cross-page) and confirm highlight rects + onSelectionChange
  • save → clear → restore reproduces identical rects
  • reversed range normalizes; over-large index clamps; null clears
  • invalid inputs (out-of-bounds page, negative/non-integer index, malformed object) are rejected without touching the engine
  • switching to a disjoint selection clears stale highlights on the previously selected page

No public type removals or breaking changes (additive only).

…ore selections

The selection capability only exposed clear(), so consumers could not
programmatically set or restore a text selection (e.g. persist a selection
and reapply it after reload, or drive selection from search results).

Add setSelection(range, documentId?) to both the SelectionCapability and the
document-scoped SelectionScope. It accepts a SelectionRangeX — the same
{ start, end } glyph-pointer shape emitted by onSelectionChange — so a value
captured from that event can be passed straight back in to restore a
selection. Passing null clears the selection (equivalent to clear()).

Behavior:
- Loads page geometry on demand from the engine for every page the range
  spans, so the returned PdfTask only resolves once highlight rects are
  computed (works when restoring on a freshly opened document).
- Normalizes the range so start/end may be supplied in any order.
- Validates input up front: rejects malformed ranges, non-integer or
  negative indices, and out-of-bounds pages, so a bogus page is never handed
  to the engine.
- Clamps glyph indices to the actual per-page glyph count, keeping a stale
  persisted selection usable instead of erroring.
- Repaints the union of previously-highlighted pages and the new range, so
  switching to a disjoint selection clears stale highlights on other pages.
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

@simonmysun is attempting to deploy a commit to the OpenBook Team on Vercel.

A member of the Team first needs to authorize it.

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