@embedpdf/react 3.0.0-next.4 → 3.0.0-next.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AnnotationListSnapshot-_Z600IzD-DYoq1Iu1.d.cts → AnnotationListSnapshot-CHjkcIaL-CMHGL8-D.d.cts} +2 -2
- package/dist/{AnnotationListSnapshot-_Z600IzD-DYoq1Iu1.d.ts → AnnotationListSnapshot-CHjkcIaL-CMHGL8-D.d.ts} +2 -2
- package/dist/anchored.cjs +89 -0
- package/dist/anchored.cjs.map +1 -0
- package/dist/anchored.d.cts +45 -0
- package/dist/anchored.d.ts +45 -0
- package/dist/anchored.js +60 -0
- package/dist/anchored.js.map +1 -0
- package/dist/annotation-menu.cjs +33 -84
- package/dist/annotation-menu.cjs.map +1 -1
- package/dist/annotation-menu.d.cts +28 -2
- package/dist/annotation-menu.d.ts +28 -2
- package/dist/annotation-menu.js +27 -78
- package/dist/annotation-menu.js.map +1 -1
- package/dist/annotation.cjs +689 -16
- package/dist/annotation.cjs.map +1 -0
- package/dist/annotation.d.cts +119 -2
- package/dist/annotation.d.ts +119 -2
- package/dist/annotation.js +678 -3
- package/dist/annotation.js.map +1 -0
- package/dist/form.cjs +1 -1
- package/dist/form.d.cts +2 -2
- package/dist/form.d.ts +2 -2
- package/dist/form.js +1 -1
- package/dist/index.cjs +14 -3
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +4 -3
- package/dist/interaction.cjs +1 -1
- package/dist/interaction.js +1 -1
- package/dist/page-view.cjs +58 -36
- package/dist/page-view.cjs.map +1 -1
- package/dist/page-view.js +54 -34
- package/dist/page-view.js.map +1 -1
- package/dist/search.d.cts +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/selection.cjs +59 -4
- package/dist/selection.cjs.map +1 -1
- package/dist/selection.d.cts +35 -2
- package/dist/selection.d.ts +35 -2
- package/dist/selection.js +52 -5
- package/dist/selection.js.map +1 -1
- package/dist/stage.cjs +33 -1
- package/dist/stage.cjs.map +1 -1
- package/dist/stage.js +33 -1
- package/dist/stage.js.map +1 -1
- package/package.json +27 -23
- package/dist/annotation-BTlcOjcK.js +0 -829
- package/dist/annotation-BTlcOjcK.js.map +0 -1
- package/dist/annotation-BvNPtcxN.d.cts +0 -173
- package/dist/annotation-CPbPvbKa.d.ts +0 -173
- package/dist/annotation-DVwYpWyP.cjs +0 -913
- package/dist/annotation-DVwYpWyP.cjs.map +0 -1
package/dist/stage.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage.cjs","names":["makePageContext","PageProvider","StageToken","useCapability","useOptionalCapability","InteractionToken","useKernelValue","useDocumentId","useSelector","createClickCounter","settingsEqual"],"sources":["../src/stage.tsx"],"sourcesContent":["/**\n * Stage / RenderLayer + facade hooks.\n *\n * <Stage> virtualizes and positions page surfaces by the camera, and hands each\n * one to YOUR render prop — you bring the layers. (The standalone, Stage-free\n * single-page surface lives in `./page-view` so it never pulls the stage plugin.)\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-stage';\nimport * as React from 'react';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { StageToken, settingsEqual, wheelZoomFactor } from '@embedpdf/plugin-stage';\nimport type { StageCapability, VisiblePage } from '@embedpdf/plugin-stage';\nimport type { CapabilityToken } from '@embedpdf/core';\n\n/** Which stage lens to bind to. Defaults to the main StageToken — pass a custom\n * token to drive an additional lens (e.g. a wrapped thumbnail sidebar). */\nexport type StageTokenProp = CapabilityToken<StageCapability>;\nimport type { PageFrame } from '@embedpdf/core-geometry';\nimport { InteractionToken } from '@embedpdf/plugin-interaction';\nimport type { PointerSample } from '@embedpdf/plugin-interaction';\nimport { createClickCounter } from './interaction';\nimport {\n makePageContext,\n PageProvider,\n useCapability,\n useDocumentId,\n useKernelValue,\n useOptionalCapability,\n useSelector,\n} from './runtime';\nimport type { PageContextValue } from './runtime';\n\nfunction PageSurface({\n documentId,\n page,\n frame,\n stage,\n render,\n chrome,\n}: {\n documentId: string;\n page: VisiblePage;\n /** Reserved chrome bands around the page (screen px); the layout reserved the\n * matching space, so the outer box tiles into it. */\n frame: PageFrame;\n /** The stage capability — the demand getter reads visibility LIVE off it. */\n stage: StageCapability;\n render: (page: PageContextValue) => React.ReactNode;\n chrome?: (page: PageContextValue) => React.ReactNode;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const t = page.transform;\n const rotation = page.rotation;\n // All geometry comes from the transform: the DISPLAY footprint (viewWidth/Height,\n // already w↔h-swapped + device-snapped) and the UN-rotated content box\n // (contentWidth/Height). The shell never re-derives `* zoom` / `* dpr` / snapping.\n const outerW = t.viewWidth + frame.left + frame.right;\n const outerH = t.viewHeight + frame.top + frame.bottom;\n // page.screenX/screenY are the device-snapped footprint top-left; the outer box\n // sits one frame further out so the content keeps its scene position.\n const left = page.screenX - frame.left;\n const top = page.screenY - frame.top;\n // Center the (possibly rotated) content box on the display box and rotate about\n // its center — NO translate(), so rotation 0 carries no transform and pixel-snaps\n // like the axis-aligned shadow behind it (no hairline seam).\n const contentLeft = frame.left + (t.viewWidth - t.contentWidth) / 2;\n const contentTop = frame.top + (t.viewHeight - t.contentHeight) / 2;\n // The page-view DEMAND is a PULL: the getter closes over\n // stable references (capability + pon) and reads the stage's live state at\n // call time — visibility is the STAGE's data (`VisiblePage.visibleRect`),\n // not something an adapter re-derives or caches. Absent from the visible\n // set = zero rect (\"want nothing\"), distinct from PageView's undefined\n // getter (\"whole page\").\n const ctx = useMemo(\n () =>\n makePageContext(\n documentId,\n page.pon,\n page.pageIndex,\n frame,\n t,\n () => ref.current!.getBoundingClientRect(),\n () => {\n const live = stage.visiblePages().find((p) => p.pon === page.pon);\n return live\n ? { desiredDeviceWidth: live.transform.deviceWidth, visibleRect: live.visibleRect }\n : {\n desiredDeviceWidth: t.deviceWidth,\n visibleRect: { x: 0, y: 0, width: 0, height: 0 },\n };\n },\n ),\n [documentId, page.pon, page.pageIndex, frame, t, stage],\n );\n return (\n <div style={{ position: 'absolute', left, top, width: outerW, height: outerH }}>\n <PageProvider value={ctx}>\n {/* drop shadow ONLY — axis-aligned at the content box (inset by the frame),\n transparent fill so it can never peek out behind the bitmap, and it\n stays put under rotation. */}\n <div\n style={{\n position: 'absolute',\n left: frame.left,\n top: frame.top,\n width: t.viewWidth,\n height: t.viewHeight,\n boxShadow: '0 6px 18px rgba(0,0,0,.18)',\n }}\n />\n {/* the page: white backing + bitmap as ONE rasterized box, so there is no\n seam between them and nothing white larger than the bitmap to leak.\n The ONLY thing rotation turns; markers/annotations ride it in content\n coordinates. Rotation 0 carries no transform → pixel-snaps cleanly. */}\n <div\n ref={ref}\n style={{\n position: 'absolute',\n left: contentLeft,\n top: contentTop,\n width: t.contentWidth,\n height: t.contentHeight,\n background: '#fff',\n transform: rotation ? `rotate(${rotation}deg)` : undefined,\n // We render our own selection highlights — suppress native text/image\n // selection (and the double-click image grab) on the whole page subtree.\n userSelect: 'none',\n WebkitUserSelect: 'none',\n }}\n >\n {render(ctx)}\n </div>\n {/* box-space chrome — labels, selection border, per-page buttons — fills\n the outer box, NEVER rotates. Bands are plain regions: a label is\n `bottom:0; height: frame.bottom`, a button row `top:0; height: frame.top`. */}\n {chrome?.(ctx)}\n </PageProvider>\n </div>\n );\n}\n\nexport interface StageProps {\n /**\n * PAGE-SPACE content for each visible page (RenderLayer, annotations,\n * markers). Rendered inside the page's content frame, so it ROTATES with the\n * page's display rotation — coordinates are plain PDF points.\n */\n children: (page: PageContextValue) => React.ReactNode;\n /**\n * BOX-SPACE chrome for each visible page (page-number label, selection\n * border, a per-page rotate/delete button). Rendered into the OUTER box\n * (content + reserved `pageFrame`), so it does NOT rotate and the reserved\n * bands are plain regions (`bottom:0; height: page.frame.bottom`). The three\n * coordinate spaces: `children` (page content), `pageChrome` (page box +\n * frame), `overlay` (viewport).\n */\n pageChrome?: (page: PageContextValue) => React.ReactNode;\n /** Viewport-space UI (menus, controls) rendered above the pages. */\n overlay?: React.ReactNode;\n /**\n * Route this Stage's pointer events to the interaction hub (page-resolved via\n * `pageAt`) instead of the built-in drag-to-pan. Pan then becomes the `pan`\n * tool's job and dragging in `pointer` mode selects text (incl. across pages).\n * Pair with `stagePlugin({ interaction: true })`. Default false (built-in pan).\n */\n interaction?: boolean;\n /**\n * Ambient ZOOM gestures on this stage: ctrl/cmd+wheel and trackpad pinch\n * (Safari gesture events included). Default true. Turn OFF for follower\n * lenses with a fixed magnification — a thumbnail rail should scroll under\n * cmd+wheel, not zoom — so a zoom-wheel falls through to ordinary wheel\n * pan, and pinches are still swallowed (they never page-zoom the browser).\n */\n zoomGestures?: boolean;\n /** The stage lens to drive (default: the main StageToken). */\n token?: StageTokenProp;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport function Stage({\n children,\n pageChrome,\n overlay,\n interaction = false,\n zoomGestures = true,\n token = StageToken,\n className,\n style,\n}: StageProps) {\n const stage = useCapability(token);\n const ix = useOptionalCapability(InteractionToken);\n const useHub = interaction && !!ix;\n // The hub's resolved cursor (text/grab/…), applied to the viewport when driving.\n const hubCursor = useKernelValue(() => ix?.cursor() ?? 'default');\n const ref = useRef<HTMLDivElement>(null);\n const docId = useDocumentId();\n // visiblePages already folds in the camera (each page carries its device-snapped\n // screenX/screenY + transform), so panning re-emits the list — no separate\n // camera subscription needed for positioning.\n const pages = useSelector(token, (c) => c.visiblePages()); // memoized -> stable ref\n // Reserved chrome bands (screen px), uniform across pages — the frame the\n // outer box reserves and `pageChrome` paints into.\n const frame = useSelector(\n token,\n (c) => c.pageFrame(),\n (a, b) => a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left,\n );\n\n useEffect(() => {\n const el = ref.current!;\n // Only report the viewport size. Initial placement (home) is the Stage plugin's\n // job — it watches the viewport and homes once it's ready (and a higher-priority\n // initial-view provider can override that). The shell stays dumb.\n const setVp = () => stage.setViewport({ width: el.clientWidth, height: el.clientHeight });\n const ro = new ResizeObserver(setVp);\n ro.observe(el);\n setVp();\n\n // Report the device pixel ratio so page transforms render crisp. dppx changes\n // (zoom, dragging between monitors) fire the media query; re-subscribe each\n // time since the query value itself moves.\n let mq: MediaQueryList | null = null;\n const reportDpr = () => {\n stage.setDevicePixelRatio(window.devicePixelRatio || 1);\n mq?.removeEventListener('change', reportDpr);\n mq = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);\n mq.addEventListener('change', reportDpr);\n };\n reportDpr();\n\n // Wheel is ambient navigation in BOTH modes: ctrl/meta zooms (classified\n // per input — synthesized pinch, mouse notch, cmd-scroll scrub — by\n // wheelZoomFactor), else scrolls. With zoom gestures off, a zoom-wheel\n // falls through to ordinary pan (a cmd+scroll over a thumbnail rail\n // scrolls the rail).\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const r = el.getBoundingClientRect();\n if (zoomGestures && (e.ctrlKey || e.metaKey)) {\n stage.zoomAround({ x: e.clientX - r.left, y: e.clientY - r.top }, wheelZoomFactor(e));\n } else {\n const dx = e.shiftKey ? e.deltaY : e.deltaX;\n const dy = e.shiftKey ? e.deltaX : e.deltaY;\n stage.panBy(-dx, -dy);\n }\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n\n // Safari never synthesizes ctrl+wheel for trackpad pinch — it fires\n // proprietary gesture events carrying an ABSOLUTE scale; convert to the\n // per-event ratio the camera physics wants. Feature-detected: Chrome and\n // Firefox don't have GestureEvent, so this wiring costs them nothing.\n // preventDefault runs even with zoom gestures off — a pinch over the\n // stage must never zoom the page itself.\n let lastScale = 1;\n const onGestureStart = (e: Event) => {\n e.preventDefault();\n lastScale = (e as unknown as { scale?: number }).scale ?? 1;\n };\n const onGestureChange = (e: Event) => {\n e.preventDefault();\n const g = e as unknown as { scale?: number; clientX: number; clientY: number };\n const scale = g.scale ?? 1;\n if (zoomGestures && scale > 0) {\n const r = el.getBoundingClientRect();\n stage.zoomAround({ x: g.clientX - r.left, y: g.clientY - r.top }, scale / lastScale);\n }\n lastScale = scale;\n };\n const hasGestureEvents = 'GestureEvent' in window;\n if (hasGestureEvents) {\n el.addEventListener('gesturestart', onGestureStart);\n el.addEventListener('gesturechange', onGestureChange);\n el.addEventListener('gestureend', onGestureStart); // reset the base\n }\n\n const cleanups: Array<() => void> = [];\n if (useHub && ix) {\n // Forward to the hub: pan/select/etc. become tool-gated handlers. `pageAt`\n // resolves the page per event, so a drag can cross pages (text selection).\n const clicks = createClickCounter();\n const forward = (phase: PointerSample['phase'], e: PointerEvent, clickCount = 1) => {\n const r = el.getBoundingClientRect();\n const vpt = { x: e.clientX - r.left, y: e.clientY - r.top };\n ix.dispatch({\n phase,\n viewport: vpt,\n page: stage.pageAt(vpt) ?? undefined,\n // Page-anchored gestures (annotation move/resize) track the origin\n // page's frame through this even when the cursor is off that page.\n project: (pon) => stage.pointOnPage(pon, vpt),\n modifiers: { shift: e.shiftKey, alt: e.altKey, ctrl: e.ctrlKey, meta: e.metaKey },\n clickCount,\n });\n };\n let dragging = false;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n forward('down', e, clicks(Date.now(), e.clientX, e.clientY));\n };\n const hover = (e: PointerEvent) => {\n if (!dragging) forward('move', e); // cursor feedback, no gesture\n };\n const winMove = (e: PointerEvent) => {\n if (dragging) forward('move', e);\n };\n const up = (e: PointerEvent) => {\n if (!dragging) return;\n dragging = false;\n forward('up', e);\n };\n el.addEventListener('pointerdown', down);\n el.addEventListener('pointermove', hover);\n window.addEventListener('pointermove', winMove);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n el.removeEventListener('pointermove', hover);\n window.removeEventListener('pointermove', winMove);\n window.removeEventListener('pointerup', up);\n });\n } else {\n // Built-in drag-to-pan (no interaction hub) — unchanged behaviour.\n let dragging = false;\n let lx = 0;\n let ly = 0;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n lx = e.clientX;\n ly = e.clientY;\n };\n const move = (e: PointerEvent) => {\n if (!dragging) return;\n stage.panBy(e.clientX - lx, e.clientY - ly);\n lx = e.clientX;\n ly = e.clientY;\n };\n const up = () => {\n dragging = false;\n };\n el.addEventListener('pointerdown', down);\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n });\n }\n\n return () => {\n ro.disconnect();\n mq?.removeEventListener('change', reportDpr);\n el.removeEventListener('wheel', onWheel);\n if (hasGestureEvents) {\n el.removeEventListener('gesturestart', onGestureStart);\n el.removeEventListener('gesturechange', onGestureChange);\n el.removeEventListener('gestureend', onGestureStart);\n }\n cleanups.forEach((fn) => fn());\n };\n }, [stage, ix, useHub, zoomGestures]);\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'relative',\n overflow: 'hidden',\n touchAction: 'none',\n ...(useHub ? { cursor: hubCursor } : null),\n ...style,\n }}\n >\n {pages.map((p) => (\n <PageSurface\n key={p.pageIndex}\n documentId={docId ?? ''}\n page={p}\n frame={frame}\n stage={stage}\n render={children}\n chrome={pageChrome}\n />\n ))}\n {overlay}\n </div>\n );\n}\n\n// ── Facade hooks — thin sugar over the capability + generic binding ───────────\nexport function useStage(token: StageTokenProp = StageToken) {\n return useCapability(token);\n}\nexport function useZoom(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const zoom = useSelector(token, (c) => c.zoomLevel());\n const mode = useSelector(token, (c) => c.zoomMode());\n return {\n zoom,\n /** Active zoom intent: 'automatic' | 'fit-page' | 'fit-width' | 'fit-all' | 'custom'. */\n mode,\n zoomIn: s.zoomIn,\n zoomOut: s.zoomOut,\n fitWidth: s.fitWidth,\n fitPage: s.fitPage,\n fitAll: s.fitAll,\n automatic: s.automatic,\n zoomTo: s.zoomTo,\n };\n}\nexport function usePages(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const currentPage = useSelector(token, (c) => c.currentPage());\n const pageCount = useSelector(token, (c) => c.pageCount());\n return {\n currentPage,\n pageCount,\n goToPage: s.goToPage,\n next: s.next,\n prev: s.prev,\n reveal: s.reveal,\n };\n}\nexport function useLayout(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const flow = useSelector(token, (c) => c.flow());\n const layout = useSelector(token, (c) => c.layout());\n const spread = useSelector(token, (c) => c.spread());\n const sizing = useSelector(token, (c) => c.sizing());\n const bounded = useSelector(token, (c) => c.bounded());\n return {\n flow,\n layout,\n spread,\n sizing,\n bounded,\n setFlow: s.setFlow,\n setLayout: s.setLayout,\n setSpread: s.setSpread,\n setSizing: s.setSizing,\n setBounded: s.setBounded,\n };\n}\n\n/** The document's page list (with PDF labels) + the current item's pages — the\n * data for page thumbnails / worksheet-style page tabs. */\nexport function usePageList(token: StageTokenProp = StageToken) {\n const pages = useSelector(\n token,\n (c) => c.pages(),\n (a, b) =>\n a.length === b.length && a.every((p, i) => p.pon === b[i].pon && p.label === b[i].label),\n );\n const current = useSelector(\n token,\n (c) => c.currentItemPages(),\n (a, b) => a.length === b.length && a.every((x, i) => x === b[i]),\n );\n return { pages, currentItemPages: current };\n}\n\n/**\n * All Stage settings + the batch `update`. This is the seam for \"presets are a\n * customer concern\": keep your own `Partial<StageSettings>` objects and apply them\n * with `update(preset)` (one anchor-preserving change).\n */\nexport function useStageSettings(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n // settingsEqual derives from the plugin's settings registry — a new setting is\n // covered here automatically, without this package spelling out the shape.\n const settings = useSelector(token, (c) => c.settings(), settingsEqual);\n return { settings, update: s.update, reset: s.resetView };\n}\n"],"mappings":";;;;;;;;;;AAkCA,SAAS,YAAY,EACnB,YACA,MACA,OACA,OACA,QACA,UAWC;CACD,MAAM,OAAA,GAAA,MAAA,OAAA,CAA6B,IAAI;CACvC,MAAM,IAAI,KAAK;CACf,MAAM,WAAW,KAAK;CAItB,MAAM,SAAS,EAAE,YAAY,MAAM,OAAO,MAAM;CAChD,MAAM,SAAS,EAAE,aAAa,MAAM,MAAM,MAAM;CAGhD,MAAM,OAAO,KAAK,UAAU,MAAM;CAClC,MAAM,MAAM,KAAK,UAAU,MAAM;CAIjC,MAAM,cAAc,MAAM,QAAQ,EAAE,YAAY,EAAE,gBAAgB;CAClE,MAAM,aAAa,MAAM,OAAO,EAAE,aAAa,EAAE,iBAAiB;CAOlE,MAAM,OAAA,GAAA,MAAA,QAAA,OAEFA,gBAAAA,gBACE,YACA,KAAK,KACL,KAAK,WACL,OACA,SACM,IAAI,QAAS,sBAAsB,SACnC;EACJ,MAAM,OAAO,MAAM,aAAa,CAAC,CAAC,MAAM,MAAM,EAAE,QAAQ,KAAK,GAAG;EAChE,OAAO,OACH;GAAE,oBAAoB,KAAK,UAAU;GAAa,aAAa,KAAK;EAAY,IAChF;GACE,oBAAoB,EAAE;GACtB,aAAa;IAAE,GAAG;IAAG,GAAG;IAAG,OAAO;IAAG,QAAQ;GAAE;EACjD;CACN,CACF,GACF;EAAC;EAAY,KAAK;EAAK,KAAK;EAAW;EAAO;EAAG;CAAK,CACxD;CACA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,OAAO;GAAE,UAAU;GAAY;GAAM;GAAK,OAAO;GAAQ,QAAQ;EAAO;EAC3E,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAACC,gBAAAA,cAAD;GAAc,OAAO;GAArB,UAAA;IAIE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EACE,OAAO;KACL,UAAU;KACV,MAAM,MAAM;KACZ,KAAK,MAAM;KACX,OAAO,EAAE;KACT,QAAQ,EAAE;KACV,WAAW;IACb,EACD,CAAA;IAKD,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KACO;KACL,OAAO;MACL,UAAU;MACV,MAAM;MACN,KAAK;MACL,OAAO,EAAE;MACT,QAAQ,EAAE;MACV,YAAY;MACZ,WAAW,WAAW,UAAU,SAAS,QAAQ,KAAA;MAGjD,YAAY;MACZ,kBAAkB;KACpB;KAEC,UAAA,OAAO,GAAG;IACR,CAAA;IAIJ,SAAS,GAAG;GACD;;CACX,CAAA;AAET;AAyCA,SAAgB,MAAM,EACpB,UACA,YACA,SACA,cAAc,OACd,eAAe,MACf,QAAQC,uBAAAA,YACR,WACA,SACa;CACb,MAAM,QAAQC,gBAAAA,cAAc,KAAK;CACjC,MAAM,KAAKC,gBAAAA,sBAAsBC,6BAAAA,gBAAgB;CACjD,MAAM,SAAS,eAAe,CAAC,CAAC;CAEhC,MAAM,YAAYC,gBAAAA,qBAAqB,IAAI,OAAO,KAAK,SAAS;CAChE,MAAM,OAAA,GAAA,MAAA,OAAA,CAA6B,IAAI;CACvC,MAAM,QAAQC,gBAAAA,cAAc;CAI5B,MAAM,QAAQC,gBAAAA,YAAY,QAAQ,MAAM,EAAE,aAAa,CAAC;CAGxD,MAAM,QAAQA,gBAAAA,YACZ,QACC,MAAM,EAAE,UAAU,IAClB,GAAG,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,IAC5F;CAEA,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,MAAM,KAAK,IAAI;EAIf,MAAM,cAAc,MAAM,YAAY;GAAE,OAAO,GAAG;GAAa,QAAQ,GAAG;EAAa,CAAC;EACxF,MAAM,KAAK,IAAI,eAAe,KAAK;EACnC,GAAG,QAAQ,EAAE;EACb,MAAM;EAKN,IAAI,KAA4B;EAChC,MAAM,kBAAkB;GACtB,MAAM,oBAAoB,OAAO,oBAAoB,CAAC;GACtD,IAAI,oBAAoB,UAAU,SAAS;GAC3C,KAAK,OAAO,WAAW,gBAAgB,OAAO,iBAAiB,MAAM;GACrE,GAAG,iBAAiB,UAAU,SAAS;EACzC;EACA,UAAU;EAOV,MAAM,WAAW,MAAkB;GACjC,EAAE,eAAe;GACjB,MAAM,IAAI,GAAG,sBAAsB;GACnC,IAAI,iBAAiB,EAAE,WAAW,EAAE,UAClC,MAAM,WAAW;IAAE,GAAG,EAAE,UAAU,EAAE;IAAM,GAAG,EAAE,UAAU,EAAE;GAAI,IAAA,GAAA,uBAAA,gBAAA,CAAmB,CAAC,CAAC;QAC/E;IACL,MAAM,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE;IACrC,MAAM,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE;IACrC,MAAM,MAAM,CAAC,IAAI,CAAC,EAAE;GACtB;EACF;EACA,GAAG,iBAAiB,SAAS,SAAS,EAAE,SAAS,MAAM,CAAC;EAQxD,IAAI,YAAY;EAChB,MAAM,kBAAkB,MAAa;GACnC,EAAE,eAAe;GACjB,YAAa,EAAoC,SAAS;EAC5D;EACA,MAAM,mBAAmB,MAAa;GACpC,EAAE,eAAe;GACjB,MAAM,IAAI;GACV,MAAM,QAAQ,EAAE,SAAS;GACzB,IAAI,gBAAgB,QAAQ,GAAG;IAC7B,MAAM,IAAI,GAAG,sBAAsB;IACnC,MAAM,WAAW;KAAE,GAAG,EAAE,UAAU,EAAE;KAAM,GAAG,EAAE,UAAU,EAAE;IAAI,GAAG,QAAQ,SAAS;GACrF;GACA,YAAY;EACd;EACA,MAAM,mBAAmB,kBAAkB;EAC3C,IAAI,kBAAkB;GACpB,GAAG,iBAAiB,gBAAgB,cAAc;GAClD,GAAG,iBAAiB,iBAAiB,eAAe;GACpD,GAAG,iBAAiB,cAAc,cAAc;EAClD;EAEA,MAAM,WAA8B,CAAC;EACrC,IAAI,UAAU,IAAI;GAGhB,MAAM,SAASC,oBAAAA,mBAAmB;GAClC,MAAM,WAAW,OAA+B,GAAiB,aAAa,MAAM;IAClF,MAAM,IAAI,GAAG,sBAAsB;IACnC,MAAM,MAAM;KAAE,GAAG,EAAE,UAAU,EAAE;KAAM,GAAG,EAAE,UAAU,EAAE;IAAI;IAC1D,GAAG,SAAS;KACV;KACA,UAAU;KACV,MAAM,MAAM,OAAO,GAAG,KAAK,KAAA;KAG3B,UAAU,QAAQ,MAAM,YAAY,KAAK,GAAG;KAC5C,WAAW;MAAE,OAAO,EAAE;MAAU,KAAK,EAAE;MAAQ,MAAM,EAAE;MAAS,MAAM,EAAE;KAAQ;KAChF;IACF,CAAC;GACH;GACA,IAAI,WAAW;GACf,MAAM,QAAQ,MAAoB;IAChC,IAAI,EAAE,WAAW,GAAG;IACpB,WAAW;IACX,QAAQ,QAAQ,GAAG,OAAO,KAAK,IAAI,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC;GAC7D;GACA,MAAM,SAAS,MAAoB;IACjC,IAAI,CAAC,UAAU,QAAQ,QAAQ,CAAC;GAClC;GACA,MAAM,WAAW,MAAoB;IACnC,IAAI,UAAU,QAAQ,QAAQ,CAAC;GACjC;GACA,MAAM,MAAM,MAAoB;IAC9B,IAAI,CAAC,UAAU;IACf,WAAW;IACX,QAAQ,MAAM,CAAC;GACjB;GACA,GAAG,iBAAiB,eAAe,IAAI;GACvC,GAAG,iBAAiB,eAAe,KAAK;GACxC,OAAO,iBAAiB,eAAe,OAAO;GAC9C,OAAO,iBAAiB,aAAa,EAAE;GACvC,SAAS,WAAW;IAClB,GAAG,oBAAoB,eAAe,IAAI;IAC1C,GAAG,oBAAoB,eAAe,KAAK;IAC3C,OAAO,oBAAoB,eAAe,OAAO;IACjD,OAAO,oBAAoB,aAAa,EAAE;GAC5C,CAAC;EACH,OAAO;GAEL,IAAI,WAAW;GACf,IAAI,KAAK;GACT,IAAI,KAAK;GACT,MAAM,QAAQ,MAAoB;IAChC,IAAI,EAAE,WAAW,GAAG;IACpB,WAAW;IACX,KAAK,EAAE;IACP,KAAK,EAAE;GACT;GACA,MAAM,QAAQ,MAAoB;IAChC,IAAI,CAAC,UAAU;IACf,MAAM,MAAM,EAAE,UAAU,IAAI,EAAE,UAAU,EAAE;IAC1C,KAAK,EAAE;IACP,KAAK,EAAE;GACT;GACA,MAAM,WAAW;IACf,WAAW;GACb;GACA,GAAG,iBAAiB,eAAe,IAAI;GACvC,OAAO,iBAAiB,eAAe,IAAI;GAC3C,OAAO,iBAAiB,aAAa,EAAE;GACvC,SAAS,WAAW;IAClB,GAAG,oBAAoB,eAAe,IAAI;IAC1C,OAAO,oBAAoB,eAAe,IAAI;IAC9C,OAAO,oBAAoB,aAAa,EAAE;GAC5C,CAAC;EACH;EAEA,aAAa;GACX,GAAG,WAAW;GACd,IAAI,oBAAoB,UAAU,SAAS;GAC3C,GAAG,oBAAoB,SAAS,OAAO;GACvC,IAAI,kBAAkB;IACpB,GAAG,oBAAoB,gBAAgB,cAAc;IACrD,GAAG,oBAAoB,iBAAiB,eAAe;IACvD,GAAG,oBAAoB,cAAc,cAAc;GACrD;GACA,SAAS,SAAS,OAAO,GAAG,CAAC;EAC/B;CACF,GAAG;EAAC;EAAO;EAAI;EAAQ;CAAY,CAAC;CAEpC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EACO;EACM;EACX,OAAO;GACL,UAAU;GACV,UAAU;GACV,aAAa;GACb,GAAI,SAAS,EAAE,QAAQ,UAAU,IAAI;GACrC,GAAG;EACL;EATF,UAAA,CAWG,MAAM,KAAK,MACV,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAD;GAEE,YAAY,SAAS;GACrB,MAAM;GACC;GACA;GACP,QAAQ;GACR,QAAQ;EACT,GAPM,EAAE,SAOR,CACF,GACA,OACE;;AAET;AAGA,SAAgB,SAAS,QAAwBP,uBAAAA,YAAY;CAC3D,OAAOC,gBAAAA,cAAc,KAAK;AAC5B;AACA,SAAgB,QAAQ,QAAwBD,uBAAAA,YAAY;CAC1D,MAAM,IAAIC,gBAAAA,cAAc,KAAK;CAG7B,OAAO;EACL,MAHWK,gBAAAA,YAAY,QAAQ,MAAM,EAAE,UAAU,CAG9C;;EAEH,MAJWA,gBAAAA,YAAY,QAAQ,MAAM,EAAE,SAAS,CAI7C;EACH,QAAQ,EAAE;EACV,SAAS,EAAE;EACX,UAAU,EAAE;EACZ,SAAS,EAAE;EACX,QAAQ,EAAE;EACV,WAAW,EAAE;EACb,QAAQ,EAAE;CACZ;AACF;AACA,SAAgB,SAAS,QAAwBN,uBAAAA,YAAY;CAC3D,MAAM,IAAIC,gBAAAA,cAAc,KAAK;CAG7B,OAAO;EACL,aAHkBK,gBAAAA,YAAY,QAAQ,MAAM,EAAE,YAAY,CAGhD;EACV,WAHgBA,gBAAAA,YAAY,QAAQ,MAAM,EAAE,UAAU,CAG9C;EACR,UAAU,EAAE;EACZ,MAAM,EAAE;EACR,MAAM,EAAE;EACR,QAAQ,EAAE;CACZ;AACF;AACA,SAAgB,UAAU,QAAwBN,uBAAAA,YAAY;CAC5D,MAAM,IAAIC,gBAAAA,cAAc,KAAK;CAM7B,OAAO;EACL,MANWK,gBAAAA,YAAY,QAAQ,MAAM,EAAE,KAAK,CAMzC;EACH,QANaA,gBAAAA,YAAY,QAAQ,MAAM,EAAE,OAAO,CAM3C;EACL,QANaA,gBAAAA,YAAY,QAAQ,MAAM,EAAE,OAAO,CAM3C;EACL,QANaA,gBAAAA,YAAY,QAAQ,MAAM,EAAE,OAAO,CAM3C;EACL,SANcA,gBAAAA,YAAY,QAAQ,MAAM,EAAE,QAAQ,CAM5C;EACN,SAAS,EAAE;EACX,WAAW,EAAE;EACb,WAAW,EAAE;EACb,WAAW,EAAE;EACb,YAAY,EAAE;CAChB;AACF;;;AAIA,SAAgB,YAAY,QAAwBN,uBAAAA,YAAY;CAY9D,OAAO;EAAE,OAXKM,gBAAAA,YACZ,QACC,MAAM,EAAE,MAAM,IACd,GAAG,MACF,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,KAAK,CAO9E;EAAG,kBALAA,gBAAAA,YACd,QACC,MAAM,EAAE,iBAAiB,IACzB,GAAG,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,MAAM,EAAE,EAAE,CAEzB;CAAE;AAC5C;;;;;;AAOA,SAAgB,iBAAiB,QAAwBN,uBAAAA,YAAY;CACnE,MAAM,IAAIC,gBAAAA,cAAc,KAAK;CAI7B,OAAO;EAAE,UADQK,gBAAAA,YAAY,QAAQ,MAAM,EAAE,SAAS,GAAGE,uBAAAA,aACzC;EAAG,QAAQ,EAAE;EAAQ,OAAO,EAAE;CAAU;AAC1D"}
|
|
1
|
+
{"version":3,"file":"stage.cjs","names":["makePageContext","PageProvider","StageToken","useCapability","useOptionalCapability","InteractionToken","useKernelValue","useDocumentId","useSelector","createClickCounter","ProjectorProvider","settingsEqual"],"sources":["../src/stage.tsx"],"sourcesContent":["/**\n * Stage / RenderLayer + facade hooks.\n *\n * <Stage> virtualizes and positions page surfaces by the camera, and hands each\n * one to YOUR render prop — you bring the layers. (The standalone, Stage-free\n * single-page surface lives in `./page-view` so it never pulls the stage plugin.)\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-stage';\nimport * as React from 'react';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { StageToken, settingsEqual, wheelZoomFactor } from '@embedpdf/plugin-stage';\nimport type { StageCapability, VisiblePage } from '@embedpdf/plugin-stage';\nimport type { CapabilityToken } from '@embedpdf/core';\n\n/** Which stage lens to bind to. Defaults to the main StageToken — pass a custom\n * token to drive an additional lens (e.g. a wrapped thumbnail sidebar). */\nexport type StageTokenProp = CapabilityToken<StageCapability>;\nimport type { PageFrame } from '@embedpdf/core-geometry';\nimport { InteractionToken } from '@embedpdf/plugin-interaction';\nimport type { PointerSample } from '@embedpdf/plugin-interaction';\nimport { ProjectorProvider, type ProjectorBinding, type ViewProjector } from './anchored';\nimport { createClickCounter } from './interaction';\nimport {\n makePageContext,\n PageProvider,\n useCapability,\n useDocumentId,\n useKernelValue,\n useOptionalCapability,\n useSelector,\n} from './runtime';\nimport type { PageContextValue } from './runtime';\n\nfunction PageSurface({\n documentId,\n page,\n frame,\n stage,\n render,\n chrome,\n}: {\n documentId: string;\n page: VisiblePage;\n /** Reserved chrome bands around the page (screen px); the layout reserved the\n * matching space, so the outer box tiles into it. */\n frame: PageFrame;\n /** The stage capability — the demand getter reads visibility LIVE off it. */\n stage: StageCapability;\n render: (page: PageContextValue) => React.ReactNode;\n chrome?: (page: PageContextValue) => React.ReactNode;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const t = page.transform;\n const rotation = page.rotation;\n // All geometry comes from the transform: the DISPLAY footprint (viewWidth/Height,\n // already w↔h-swapped + device-snapped) and the UN-rotated content box\n // (contentWidth/Height). The shell never re-derives `* zoom` / `* dpr` / snapping.\n const outerW = t.viewWidth + frame.left + frame.right;\n const outerH = t.viewHeight + frame.top + frame.bottom;\n // page.screenX/screenY are the device-snapped footprint top-left; the outer box\n // sits one frame further out so the content keeps its scene position.\n const left = page.screenX - frame.left;\n const top = page.screenY - frame.top;\n // Center the (possibly rotated) content box on the display box and rotate about\n // its center — NO translate(), so rotation 0 carries no transform and pixel-snaps\n // like the axis-aligned shadow behind it (no hairline seam).\n const contentLeft = frame.left + (t.viewWidth - t.contentWidth) / 2;\n const contentTop = frame.top + (t.viewHeight - t.contentHeight) / 2;\n // The page-view DEMAND is a PULL: the getter closes over\n // stable references (capability + pon) and reads the stage's live state at\n // call time — visibility is the STAGE's data (`VisiblePage.visibleRect`),\n // not something an adapter re-derives or caches. Absent from the visible\n // set = zero rect (\"want nothing\"), distinct from PageView's undefined\n // getter (\"whole page\").\n const ctx = useMemo(\n () =>\n makePageContext(\n documentId,\n page.pon,\n page.pageIndex,\n frame,\n t,\n () => ref.current!.getBoundingClientRect(),\n () => {\n const live = stage.visiblePages().find((p) => p.pon === page.pon);\n return live\n ? { desiredDeviceWidth: live.transform.deviceWidth, visibleRect: live.visibleRect }\n : {\n desiredDeviceWidth: t.deviceWidth,\n visibleRect: { x: 0, y: 0, width: 0, height: 0 },\n };\n },\n ),\n [documentId, page.pon, page.pageIndex, frame, t, stage],\n );\n return (\n <div style={{ position: 'absolute', left, top, width: outerW, height: outerH }}>\n <PageProvider value={ctx}>\n {/* drop shadow ONLY — axis-aligned at the content box (inset by the frame),\n transparent fill so it can never peek out behind the bitmap, and it\n stays put under rotation. */}\n <div\n style={{\n position: 'absolute',\n left: frame.left,\n top: frame.top,\n width: t.viewWidth,\n height: t.viewHeight,\n boxShadow: '0 6px 18px rgba(0,0,0,.18)',\n }}\n />\n {/* the page: white backing + bitmap as ONE rasterized box, so there is no\n seam between them and nothing white larger than the bitmap to leak.\n The ONLY thing rotation turns; markers/annotations ride it in content\n coordinates. Rotation 0 carries no transform → pixel-snaps cleanly. */}\n <div\n ref={ref}\n style={{\n position: 'absolute',\n left: contentLeft,\n top: contentTop,\n width: t.contentWidth,\n height: t.contentHeight,\n background: '#fff',\n transform: rotation ? `rotate(${rotation}deg)` : undefined,\n // We render our own selection highlights — suppress native text/image\n // selection (and the double-click image grab) on the whole page subtree.\n userSelect: 'none',\n WebkitUserSelect: 'none',\n }}\n >\n {render(ctx)}\n </div>\n {/* box-space chrome — labels, selection border, per-page buttons — fills\n the outer box, NEVER rotates. Bands are plain regions: a label is\n `bottom:0; height: frame.bottom`, a button row `top:0; height: frame.top`. */}\n {chrome?.(ctx)}\n </PageProvider>\n </div>\n );\n}\n\nexport interface StageProps {\n /**\n * PAGE-SPACE content for each visible page (RenderLayer, annotations,\n * markers). Rendered inside the page's content frame, so it ROTATES with the\n * page's display rotation — coordinates are plain PDF points.\n */\n children: (page: PageContextValue) => React.ReactNode;\n /**\n * BOX-SPACE chrome for each visible page (page-number label, selection\n * border, a per-page rotate/delete button). Rendered into the OUTER box\n * (content + reserved `pageFrame`), so it does NOT rotate and the reserved\n * bands are plain regions (`bottom:0; height: page.frame.bottom`). The three\n * coordinate spaces: `children` (page content), `pageChrome` (page box +\n * frame), `overlay` (viewport).\n */\n pageChrome?: (page: PageContextValue) => React.ReactNode;\n /** Viewport-space UI (menus, controls) rendered above the pages. */\n overlay?: React.ReactNode;\n /**\n * Route this Stage's pointer events to the interaction hub (page-resolved via\n * `pageAt`) instead of the built-in drag-to-pan. Pan then becomes the `pan`\n * tool's job and dragging in `pointer` mode selects text (incl. across pages).\n * Pair with `stagePlugin({ interaction: true })`. Default false (built-in pan).\n */\n interaction?: boolean;\n /**\n * Ambient ZOOM gestures on this stage: ctrl/cmd+wheel and trackpad pinch\n * (Safari gesture events included). Default true. Turn OFF for follower\n * lenses with a fixed magnification — a thumbnail rail should scroll under\n * cmd+wheel, not zoom — so a zoom-wheel falls through to ordinary wheel\n * pan, and pinches are still swallowed (they never page-zoom the browser).\n */\n zoomGestures?: boolean;\n /** The stage lens to drive (default: the main StageToken). */\n token?: StageTokenProp;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport function Stage({\n children,\n pageChrome,\n overlay,\n interaction = false,\n zoomGestures = true,\n token = StageToken,\n className,\n style,\n}: StageProps) {\n const stage = useCapability(token);\n const ix = useOptionalCapability(InteractionToken);\n const useHub = interaction && !!ix;\n // The hub's resolved cursor (text/grab/…), applied to the viewport when driving.\n const hubCursor = useKernelValue(() => ix?.cursor() ?? 'default');\n const ref = useRef<HTMLDivElement>(null);\n const docId = useDocumentId();\n // visiblePages already folds in the camera (each page carries its device-snapped\n // screenX/screenY + transform), so panning re-emits the list — no separate\n // camera subscription needed for positioning.\n const pages = useSelector(token, (c) => c.visiblePages()); // memoized -> stable ref\n // Reserved chrome bands (screen px), uniform across pages — the frame the\n // outer box reserves and `pageChrome` paints into.\n const frame = useSelector(\n token,\n (c) => c.pageFrame(),\n (a, b) => a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left,\n );\n\n // The Stage's ViewProjector: anchored UI (menus, popovers) positions through\n // the CAMERA — pure state, no DOM reads, no portal, and NO subscription:\n // `pages` (visiblePages) is the binding's revision, so a camera change\n // re-renders the pages AND every anchored consumer in the SAME React\n // commit — surface and overlay can never paint a frame apart.\n const projector = useMemo<ViewProjector>(\n () => ({\n space: 'overlay',\n toScreen: (pon, rect) => stage.pageRectToScreen(pon, rect),\n toScreenPoint: (pon, at) => {\n const r = stage.pageRectToScreen(pon, { x: at.x, y: at.y, width: 0, height: 0 });\n return r ? { x: r.x, y: r.y } : null;\n },\n viewEnv: (pon) => {\n const t = stage.pageRect(pon)?.transform;\n return t ? { scale: t.viewScale, rotation: t.rotation, zoom: t.zoom } : null;\n },\n }),\n [stage],\n );\n const projectorBinding = useMemo<ProjectorBinding>(\n () => ({ projector, revision: pages }),\n [projector, pages],\n );\n\n useEffect(() => {\n const el = ref.current!;\n // Only report the viewport size. Initial placement (home) is the Stage plugin's\n // job — it watches the viewport and homes once it's ready (and a higher-priority\n // initial-view provider can override that). The shell stays dumb.\n const setVp = () => stage.setViewport({ width: el.clientWidth, height: el.clientHeight });\n const ro = new ResizeObserver(setVp);\n ro.observe(el);\n setVp();\n\n // Report the device pixel ratio so page transforms render crisp. dppx changes\n // (zoom, dragging between monitors) fire the media query; re-subscribe each\n // time since the query value itself moves.\n let mq: MediaQueryList | null = null;\n const reportDpr = () => {\n stage.setDevicePixelRatio(window.devicePixelRatio || 1);\n mq?.removeEventListener('change', reportDpr);\n mq = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);\n mq.addEventListener('change', reportDpr);\n };\n reportDpr();\n\n // Wheel is ambient navigation in BOTH modes: ctrl/meta zooms (classified\n // per input — synthesized pinch, mouse notch, cmd-scroll scrub — by\n // wheelZoomFactor), else scrolls. With zoom gestures off, a zoom-wheel\n // falls through to ordinary pan (a cmd+scroll over a thumbnail rail\n // scrolls the rail).\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const r = el.getBoundingClientRect();\n if (zoomGestures && (e.ctrlKey || e.metaKey)) {\n stage.zoomAround({ x: e.clientX - r.left, y: e.clientY - r.top }, wheelZoomFactor(e));\n } else {\n const dx = e.shiftKey ? e.deltaY : e.deltaX;\n const dy = e.shiftKey ? e.deltaX : e.deltaY;\n stage.panBy(-dx, -dy);\n }\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n\n // Safari never synthesizes ctrl+wheel for trackpad pinch — it fires\n // proprietary gesture events carrying an ABSOLUTE scale; convert to the\n // per-event ratio the camera physics wants. Feature-detected: Chrome and\n // Firefox don't have GestureEvent, so this wiring costs them nothing.\n // preventDefault runs even with zoom gestures off — a pinch over the\n // stage must never zoom the page itself.\n let lastScale = 1;\n const onGestureStart = (e: Event) => {\n e.preventDefault();\n lastScale = (e as unknown as { scale?: number }).scale ?? 1;\n };\n const onGestureChange = (e: Event) => {\n e.preventDefault();\n const g = e as unknown as { scale?: number; clientX: number; clientY: number };\n const scale = g.scale ?? 1;\n if (zoomGestures && scale > 0) {\n const r = el.getBoundingClientRect();\n stage.zoomAround({ x: g.clientX - r.left, y: g.clientY - r.top }, scale / lastScale);\n }\n lastScale = scale;\n };\n const hasGestureEvents = 'GestureEvent' in window;\n if (hasGestureEvents) {\n el.addEventListener('gesturestart', onGestureStart);\n el.addEventListener('gesturechange', onGestureChange);\n el.addEventListener('gestureend', onGestureStart); // reset the base\n }\n\n const cleanups: Array<() => void> = [];\n if (useHub && ix) {\n // Forward to the hub: pan/select/etc. become tool-gated handlers. `pageAt`\n // resolves the page per event, so a drag can cross pages (text selection).\n const clicks = createClickCounter();\n const forward = (phase: PointerSample['phase'], e: PointerEvent, clickCount = 1) => {\n const r = el.getBoundingClientRect();\n const vpt = { x: e.clientX - r.left, y: e.clientY - r.top };\n ix.dispatch({\n phase,\n viewport: vpt,\n page: stage.pageAt(vpt) ?? undefined,\n // Page-anchored gestures (annotation move/resize) track the origin\n // page's frame through this even when the cursor is off that page.\n project: (pon) => stage.pointOnPage(pon, vpt),\n modifiers: { shift: e.shiftKey, alt: e.altKey, ctrl: e.ctrlKey, meta: e.metaKey },\n clickCount,\n });\n };\n let dragging = false;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n forward('down', e, clicks(Date.now(), e.clientX, e.clientY));\n };\n const hover = (e: PointerEvent) => {\n if (!dragging) forward('move', e); // cursor feedback, no gesture\n };\n const winMove = (e: PointerEvent) => {\n if (dragging) forward('move', e);\n };\n const up = (e: PointerEvent) => {\n if (!dragging) return;\n dragging = false;\n forward('up', e);\n };\n el.addEventListener('pointerdown', down);\n el.addEventListener('pointermove', hover);\n window.addEventListener('pointermove', winMove);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n el.removeEventListener('pointermove', hover);\n window.removeEventListener('pointermove', winMove);\n window.removeEventListener('pointerup', up);\n });\n } else {\n // Built-in drag-to-pan (no interaction hub) — unchanged behaviour.\n let dragging = false;\n let lx = 0;\n let ly = 0;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n lx = e.clientX;\n ly = e.clientY;\n };\n const move = (e: PointerEvent) => {\n if (!dragging) return;\n stage.panBy(e.clientX - lx, e.clientY - ly);\n lx = e.clientX;\n ly = e.clientY;\n };\n const up = () => {\n dragging = false;\n };\n el.addEventListener('pointerdown', down);\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n });\n }\n\n return () => {\n ro.disconnect();\n mq?.removeEventListener('change', reportDpr);\n el.removeEventListener('wheel', onWheel);\n if (hasGestureEvents) {\n el.removeEventListener('gesturestart', onGestureStart);\n el.removeEventListener('gesturechange', onGestureChange);\n el.removeEventListener('gestureend', onGestureStart);\n }\n cleanups.forEach((fn) => fn());\n };\n }, [stage, ix, useHub, zoomGestures]);\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'relative',\n overflow: 'hidden',\n touchAction: 'none',\n ...(useHub ? { cursor: hubCursor } : null),\n ...style,\n }}\n >\n {pages.map((p) => (\n <PageSurface\n key={p.pageIndex}\n documentId={docId ?? ''}\n page={p}\n frame={frame}\n stage={stage}\n render={children}\n chrome={pageChrome}\n />\n ))}\n {/* Anchored UI mounts in the overlay: absolute coords here are the\n projector's overlay space (the stage container). */}\n <ProjectorProvider value={projectorBinding}>{overlay}</ProjectorProvider>\n </div>\n );\n}\n\n// ── Facade hooks — thin sugar over the capability + generic binding ───────────\nexport function useStage(token: StageTokenProp = StageToken) {\n return useCapability(token);\n}\nexport function useZoom(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const zoom = useSelector(token, (c) => c.zoomLevel());\n const mode = useSelector(token, (c) => c.zoomMode());\n return {\n zoom,\n /** Active zoom intent: 'automatic' | 'fit-page' | 'fit-width' | 'fit-all' | 'custom'. */\n mode,\n zoomIn: s.zoomIn,\n zoomOut: s.zoomOut,\n fitWidth: s.fitWidth,\n fitPage: s.fitPage,\n fitAll: s.fitAll,\n automatic: s.automatic,\n zoomTo: s.zoomTo,\n };\n}\nexport function usePages(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const currentPage = useSelector(token, (c) => c.currentPage());\n const pageCount = useSelector(token, (c) => c.pageCount());\n return {\n currentPage,\n pageCount,\n goToPage: s.goToPage,\n next: s.next,\n prev: s.prev,\n reveal: s.reveal,\n };\n}\nexport function useLayout(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const flow = useSelector(token, (c) => c.flow());\n const layout = useSelector(token, (c) => c.layout());\n const spread = useSelector(token, (c) => c.spread());\n const sizing = useSelector(token, (c) => c.sizing());\n const bounded = useSelector(token, (c) => c.bounded());\n return {\n flow,\n layout,\n spread,\n sizing,\n bounded,\n setFlow: s.setFlow,\n setLayout: s.setLayout,\n setSpread: s.setSpread,\n setSizing: s.setSizing,\n setBounded: s.setBounded,\n };\n}\n\n/** The document's page list (with PDF labels) + the current item's pages — the\n * data for page thumbnails / worksheet-style page tabs. */\nexport function usePageList(token: StageTokenProp = StageToken) {\n const pages = useSelector(\n token,\n (c) => c.pages(),\n (a, b) =>\n a.length === b.length && a.every((p, i) => p.pon === b[i].pon && p.label === b[i].label),\n );\n const current = useSelector(\n token,\n (c) => c.currentItemPages(),\n (a, b) => a.length === b.length && a.every((x, i) => x === b[i]),\n );\n return { pages, currentItemPages: current };\n}\n\n/**\n * All Stage settings + the batch `update`. This is the seam for \"presets are a\n * customer concern\": keep your own `Partial<StageSettings>` objects and apply them\n * with `update(preset)` (one anchor-preserving change).\n */\nexport function useStageSettings(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n // settingsEqual derives from the plugin's settings registry — a new setting is\n // covered here automatically, without this package spelling out the shape.\n const settings = useSelector(token, (c) => c.settings(), settingsEqual);\n return { settings, update: s.update, reset: s.resetView };\n}\n"],"mappings":"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"}
|
package/dist/stage.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PageProvider, makePageContext, useCapability, useDocumentId, useKernelValue, useOptionalCapability, useSelector } from "./runtime.js";
|
|
2
|
+
import { ProjectorProvider } from "./anchored.js";
|
|
2
3
|
import { createClickCounter } from "./interaction.js";
|
|
3
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
5
|
import { useEffect, useMemo, useRef } from "react";
|
|
@@ -86,6 +87,34 @@ function Stage({ children, pageChrome, overlay, interaction = false, zoomGesture
|
|
|
86
87
|
const docId = useDocumentId();
|
|
87
88
|
const pages = useSelector(token, (c) => c.visiblePages());
|
|
88
89
|
const frame = useSelector(token, (c) => c.pageFrame(), (a, b) => a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left);
|
|
90
|
+
const projector = useMemo(() => ({
|
|
91
|
+
space: "overlay",
|
|
92
|
+
toScreen: (pon, rect) => stage.pageRectToScreen(pon, rect),
|
|
93
|
+
toScreenPoint: (pon, at) => {
|
|
94
|
+
const r = stage.pageRectToScreen(pon, {
|
|
95
|
+
x: at.x,
|
|
96
|
+
y: at.y,
|
|
97
|
+
width: 0,
|
|
98
|
+
height: 0
|
|
99
|
+
});
|
|
100
|
+
return r ? {
|
|
101
|
+
x: r.x,
|
|
102
|
+
y: r.y
|
|
103
|
+
} : null;
|
|
104
|
+
},
|
|
105
|
+
viewEnv: (pon) => {
|
|
106
|
+
const t = stage.pageRect(pon)?.transform;
|
|
107
|
+
return t ? {
|
|
108
|
+
scale: t.viewScale,
|
|
109
|
+
rotation: t.rotation,
|
|
110
|
+
zoom: t.zoom
|
|
111
|
+
} : null;
|
|
112
|
+
}
|
|
113
|
+
}), [stage]);
|
|
114
|
+
const projectorBinding = useMemo(() => ({
|
|
115
|
+
projector,
|
|
116
|
+
revision: pages
|
|
117
|
+
}), [projector, pages]);
|
|
89
118
|
useEffect(() => {
|
|
90
119
|
const el = ref.current;
|
|
91
120
|
const setVp = () => stage.setViewport({
|
|
@@ -253,7 +282,10 @@ function Stage({ children, pageChrome, overlay, interaction = false, zoomGesture
|
|
|
253
282
|
stage,
|
|
254
283
|
render: children,
|
|
255
284
|
chrome: pageChrome
|
|
256
|
-
}, p.pageIndex)),
|
|
285
|
+
}, p.pageIndex)), /* @__PURE__ */ jsx(ProjectorProvider, {
|
|
286
|
+
value: projectorBinding,
|
|
287
|
+
children: overlay
|
|
288
|
+
})]
|
|
257
289
|
});
|
|
258
290
|
}
|
|
259
291
|
function useStage(token = StageToken) {
|
package/dist/stage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage.js","names":[],"sources":["../src/stage.tsx"],"sourcesContent":["/**\n * Stage / RenderLayer + facade hooks.\n *\n * <Stage> virtualizes and positions page surfaces by the camera, and hands each\n * one to YOUR render prop — you bring the layers. (The standalone, Stage-free\n * single-page surface lives in `./page-view` so it never pulls the stage plugin.)\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-stage';\nimport * as React from 'react';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { StageToken, settingsEqual, wheelZoomFactor } from '@embedpdf/plugin-stage';\nimport type { StageCapability, VisiblePage } from '@embedpdf/plugin-stage';\nimport type { CapabilityToken } from '@embedpdf/core';\n\n/** Which stage lens to bind to. Defaults to the main StageToken — pass a custom\n * token to drive an additional lens (e.g. a wrapped thumbnail sidebar). */\nexport type StageTokenProp = CapabilityToken<StageCapability>;\nimport type { PageFrame } from '@embedpdf/core-geometry';\nimport { InteractionToken } from '@embedpdf/plugin-interaction';\nimport type { PointerSample } from '@embedpdf/plugin-interaction';\nimport { createClickCounter } from './interaction';\nimport {\n makePageContext,\n PageProvider,\n useCapability,\n useDocumentId,\n useKernelValue,\n useOptionalCapability,\n useSelector,\n} from './runtime';\nimport type { PageContextValue } from './runtime';\n\nfunction PageSurface({\n documentId,\n page,\n frame,\n stage,\n render,\n chrome,\n}: {\n documentId: string;\n page: VisiblePage;\n /** Reserved chrome bands around the page (screen px); the layout reserved the\n * matching space, so the outer box tiles into it. */\n frame: PageFrame;\n /** The stage capability — the demand getter reads visibility LIVE off it. */\n stage: StageCapability;\n render: (page: PageContextValue) => React.ReactNode;\n chrome?: (page: PageContextValue) => React.ReactNode;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const t = page.transform;\n const rotation = page.rotation;\n // All geometry comes from the transform: the DISPLAY footprint (viewWidth/Height,\n // already w↔h-swapped + device-snapped) and the UN-rotated content box\n // (contentWidth/Height). The shell never re-derives `* zoom` / `* dpr` / snapping.\n const outerW = t.viewWidth + frame.left + frame.right;\n const outerH = t.viewHeight + frame.top + frame.bottom;\n // page.screenX/screenY are the device-snapped footprint top-left; the outer box\n // sits one frame further out so the content keeps its scene position.\n const left = page.screenX - frame.left;\n const top = page.screenY - frame.top;\n // Center the (possibly rotated) content box on the display box and rotate about\n // its center — NO translate(), so rotation 0 carries no transform and pixel-snaps\n // like the axis-aligned shadow behind it (no hairline seam).\n const contentLeft = frame.left + (t.viewWidth - t.contentWidth) / 2;\n const contentTop = frame.top + (t.viewHeight - t.contentHeight) / 2;\n // The page-view DEMAND is a PULL: the getter closes over\n // stable references (capability + pon) and reads the stage's live state at\n // call time — visibility is the STAGE's data (`VisiblePage.visibleRect`),\n // not something an adapter re-derives or caches. Absent from the visible\n // set = zero rect (\"want nothing\"), distinct from PageView's undefined\n // getter (\"whole page\").\n const ctx = useMemo(\n () =>\n makePageContext(\n documentId,\n page.pon,\n page.pageIndex,\n frame,\n t,\n () => ref.current!.getBoundingClientRect(),\n () => {\n const live = stage.visiblePages().find((p) => p.pon === page.pon);\n return live\n ? { desiredDeviceWidth: live.transform.deviceWidth, visibleRect: live.visibleRect }\n : {\n desiredDeviceWidth: t.deviceWidth,\n visibleRect: { x: 0, y: 0, width: 0, height: 0 },\n };\n },\n ),\n [documentId, page.pon, page.pageIndex, frame, t, stage],\n );\n return (\n <div style={{ position: 'absolute', left, top, width: outerW, height: outerH }}>\n <PageProvider value={ctx}>\n {/* drop shadow ONLY — axis-aligned at the content box (inset by the frame),\n transparent fill so it can never peek out behind the bitmap, and it\n stays put under rotation. */}\n <div\n style={{\n position: 'absolute',\n left: frame.left,\n top: frame.top,\n width: t.viewWidth,\n height: t.viewHeight,\n boxShadow: '0 6px 18px rgba(0,0,0,.18)',\n }}\n />\n {/* the page: white backing + bitmap as ONE rasterized box, so there is no\n seam between them and nothing white larger than the bitmap to leak.\n The ONLY thing rotation turns; markers/annotations ride it in content\n coordinates. Rotation 0 carries no transform → pixel-snaps cleanly. */}\n <div\n ref={ref}\n style={{\n position: 'absolute',\n left: contentLeft,\n top: contentTop,\n width: t.contentWidth,\n height: t.contentHeight,\n background: '#fff',\n transform: rotation ? `rotate(${rotation}deg)` : undefined,\n // We render our own selection highlights — suppress native text/image\n // selection (and the double-click image grab) on the whole page subtree.\n userSelect: 'none',\n WebkitUserSelect: 'none',\n }}\n >\n {render(ctx)}\n </div>\n {/* box-space chrome — labels, selection border, per-page buttons — fills\n the outer box, NEVER rotates. Bands are plain regions: a label is\n `bottom:0; height: frame.bottom`, a button row `top:0; height: frame.top`. */}\n {chrome?.(ctx)}\n </PageProvider>\n </div>\n );\n}\n\nexport interface StageProps {\n /**\n * PAGE-SPACE content for each visible page (RenderLayer, annotations,\n * markers). Rendered inside the page's content frame, so it ROTATES with the\n * page's display rotation — coordinates are plain PDF points.\n */\n children: (page: PageContextValue) => React.ReactNode;\n /**\n * BOX-SPACE chrome for each visible page (page-number label, selection\n * border, a per-page rotate/delete button). Rendered into the OUTER box\n * (content + reserved `pageFrame`), so it does NOT rotate and the reserved\n * bands are plain regions (`bottom:0; height: page.frame.bottom`). The three\n * coordinate spaces: `children` (page content), `pageChrome` (page box +\n * frame), `overlay` (viewport).\n */\n pageChrome?: (page: PageContextValue) => React.ReactNode;\n /** Viewport-space UI (menus, controls) rendered above the pages. */\n overlay?: React.ReactNode;\n /**\n * Route this Stage's pointer events to the interaction hub (page-resolved via\n * `pageAt`) instead of the built-in drag-to-pan. Pan then becomes the `pan`\n * tool's job and dragging in `pointer` mode selects text (incl. across pages).\n * Pair with `stagePlugin({ interaction: true })`. Default false (built-in pan).\n */\n interaction?: boolean;\n /**\n * Ambient ZOOM gestures on this stage: ctrl/cmd+wheel and trackpad pinch\n * (Safari gesture events included). Default true. Turn OFF for follower\n * lenses with a fixed magnification — a thumbnail rail should scroll under\n * cmd+wheel, not zoom — so a zoom-wheel falls through to ordinary wheel\n * pan, and pinches are still swallowed (they never page-zoom the browser).\n */\n zoomGestures?: boolean;\n /** The stage lens to drive (default: the main StageToken). */\n token?: StageTokenProp;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport function Stage({\n children,\n pageChrome,\n overlay,\n interaction = false,\n zoomGestures = true,\n token = StageToken,\n className,\n style,\n}: StageProps) {\n const stage = useCapability(token);\n const ix = useOptionalCapability(InteractionToken);\n const useHub = interaction && !!ix;\n // The hub's resolved cursor (text/grab/…), applied to the viewport when driving.\n const hubCursor = useKernelValue(() => ix?.cursor() ?? 'default');\n const ref = useRef<HTMLDivElement>(null);\n const docId = useDocumentId();\n // visiblePages already folds in the camera (each page carries its device-snapped\n // screenX/screenY + transform), so panning re-emits the list — no separate\n // camera subscription needed for positioning.\n const pages = useSelector(token, (c) => c.visiblePages()); // memoized -> stable ref\n // Reserved chrome bands (screen px), uniform across pages — the frame the\n // outer box reserves and `pageChrome` paints into.\n const frame = useSelector(\n token,\n (c) => c.pageFrame(),\n (a, b) => a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left,\n );\n\n useEffect(() => {\n const el = ref.current!;\n // Only report the viewport size. Initial placement (home) is the Stage plugin's\n // job — it watches the viewport and homes once it's ready (and a higher-priority\n // initial-view provider can override that). The shell stays dumb.\n const setVp = () => stage.setViewport({ width: el.clientWidth, height: el.clientHeight });\n const ro = new ResizeObserver(setVp);\n ro.observe(el);\n setVp();\n\n // Report the device pixel ratio so page transforms render crisp. dppx changes\n // (zoom, dragging between monitors) fire the media query; re-subscribe each\n // time since the query value itself moves.\n let mq: MediaQueryList | null = null;\n const reportDpr = () => {\n stage.setDevicePixelRatio(window.devicePixelRatio || 1);\n mq?.removeEventListener('change', reportDpr);\n mq = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);\n mq.addEventListener('change', reportDpr);\n };\n reportDpr();\n\n // Wheel is ambient navigation in BOTH modes: ctrl/meta zooms (classified\n // per input — synthesized pinch, mouse notch, cmd-scroll scrub — by\n // wheelZoomFactor), else scrolls. With zoom gestures off, a zoom-wheel\n // falls through to ordinary pan (a cmd+scroll over a thumbnail rail\n // scrolls the rail).\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const r = el.getBoundingClientRect();\n if (zoomGestures && (e.ctrlKey || e.metaKey)) {\n stage.zoomAround({ x: e.clientX - r.left, y: e.clientY - r.top }, wheelZoomFactor(e));\n } else {\n const dx = e.shiftKey ? e.deltaY : e.deltaX;\n const dy = e.shiftKey ? e.deltaX : e.deltaY;\n stage.panBy(-dx, -dy);\n }\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n\n // Safari never synthesizes ctrl+wheel for trackpad pinch — it fires\n // proprietary gesture events carrying an ABSOLUTE scale; convert to the\n // per-event ratio the camera physics wants. Feature-detected: Chrome and\n // Firefox don't have GestureEvent, so this wiring costs them nothing.\n // preventDefault runs even with zoom gestures off — a pinch over the\n // stage must never zoom the page itself.\n let lastScale = 1;\n const onGestureStart = (e: Event) => {\n e.preventDefault();\n lastScale = (e as unknown as { scale?: number }).scale ?? 1;\n };\n const onGestureChange = (e: Event) => {\n e.preventDefault();\n const g = e as unknown as { scale?: number; clientX: number; clientY: number };\n const scale = g.scale ?? 1;\n if (zoomGestures && scale > 0) {\n const r = el.getBoundingClientRect();\n stage.zoomAround({ x: g.clientX - r.left, y: g.clientY - r.top }, scale / lastScale);\n }\n lastScale = scale;\n };\n const hasGestureEvents = 'GestureEvent' in window;\n if (hasGestureEvents) {\n el.addEventListener('gesturestart', onGestureStart);\n el.addEventListener('gesturechange', onGestureChange);\n el.addEventListener('gestureend', onGestureStart); // reset the base\n }\n\n const cleanups: Array<() => void> = [];\n if (useHub && ix) {\n // Forward to the hub: pan/select/etc. become tool-gated handlers. `pageAt`\n // resolves the page per event, so a drag can cross pages (text selection).\n const clicks = createClickCounter();\n const forward = (phase: PointerSample['phase'], e: PointerEvent, clickCount = 1) => {\n const r = el.getBoundingClientRect();\n const vpt = { x: e.clientX - r.left, y: e.clientY - r.top };\n ix.dispatch({\n phase,\n viewport: vpt,\n page: stage.pageAt(vpt) ?? undefined,\n // Page-anchored gestures (annotation move/resize) track the origin\n // page's frame through this even when the cursor is off that page.\n project: (pon) => stage.pointOnPage(pon, vpt),\n modifiers: { shift: e.shiftKey, alt: e.altKey, ctrl: e.ctrlKey, meta: e.metaKey },\n clickCount,\n });\n };\n let dragging = false;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n forward('down', e, clicks(Date.now(), e.clientX, e.clientY));\n };\n const hover = (e: PointerEvent) => {\n if (!dragging) forward('move', e); // cursor feedback, no gesture\n };\n const winMove = (e: PointerEvent) => {\n if (dragging) forward('move', e);\n };\n const up = (e: PointerEvent) => {\n if (!dragging) return;\n dragging = false;\n forward('up', e);\n };\n el.addEventListener('pointerdown', down);\n el.addEventListener('pointermove', hover);\n window.addEventListener('pointermove', winMove);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n el.removeEventListener('pointermove', hover);\n window.removeEventListener('pointermove', winMove);\n window.removeEventListener('pointerup', up);\n });\n } else {\n // Built-in drag-to-pan (no interaction hub) — unchanged behaviour.\n let dragging = false;\n let lx = 0;\n let ly = 0;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n lx = e.clientX;\n ly = e.clientY;\n };\n const move = (e: PointerEvent) => {\n if (!dragging) return;\n stage.panBy(e.clientX - lx, e.clientY - ly);\n lx = e.clientX;\n ly = e.clientY;\n };\n const up = () => {\n dragging = false;\n };\n el.addEventListener('pointerdown', down);\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n });\n }\n\n return () => {\n ro.disconnect();\n mq?.removeEventListener('change', reportDpr);\n el.removeEventListener('wheel', onWheel);\n if (hasGestureEvents) {\n el.removeEventListener('gesturestart', onGestureStart);\n el.removeEventListener('gesturechange', onGestureChange);\n el.removeEventListener('gestureend', onGestureStart);\n }\n cleanups.forEach((fn) => fn());\n };\n }, [stage, ix, useHub, zoomGestures]);\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'relative',\n overflow: 'hidden',\n touchAction: 'none',\n ...(useHub ? { cursor: hubCursor } : null),\n ...style,\n }}\n >\n {pages.map((p) => (\n <PageSurface\n key={p.pageIndex}\n documentId={docId ?? ''}\n page={p}\n frame={frame}\n stage={stage}\n render={children}\n chrome={pageChrome}\n />\n ))}\n {overlay}\n </div>\n );\n}\n\n// ── Facade hooks — thin sugar over the capability + generic binding ───────────\nexport function useStage(token: StageTokenProp = StageToken) {\n return useCapability(token);\n}\nexport function useZoom(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const zoom = useSelector(token, (c) => c.zoomLevel());\n const mode = useSelector(token, (c) => c.zoomMode());\n return {\n zoom,\n /** Active zoom intent: 'automatic' | 'fit-page' | 'fit-width' | 'fit-all' | 'custom'. */\n mode,\n zoomIn: s.zoomIn,\n zoomOut: s.zoomOut,\n fitWidth: s.fitWidth,\n fitPage: s.fitPage,\n fitAll: s.fitAll,\n automatic: s.automatic,\n zoomTo: s.zoomTo,\n };\n}\nexport function usePages(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const currentPage = useSelector(token, (c) => c.currentPage());\n const pageCount = useSelector(token, (c) => c.pageCount());\n return {\n currentPage,\n pageCount,\n goToPage: s.goToPage,\n next: s.next,\n prev: s.prev,\n reveal: s.reveal,\n };\n}\nexport function useLayout(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const flow = useSelector(token, (c) => c.flow());\n const layout = useSelector(token, (c) => c.layout());\n const spread = useSelector(token, (c) => c.spread());\n const sizing = useSelector(token, (c) => c.sizing());\n const bounded = useSelector(token, (c) => c.bounded());\n return {\n flow,\n layout,\n spread,\n sizing,\n bounded,\n setFlow: s.setFlow,\n setLayout: s.setLayout,\n setSpread: s.setSpread,\n setSizing: s.setSizing,\n setBounded: s.setBounded,\n };\n}\n\n/** The document's page list (with PDF labels) + the current item's pages — the\n * data for page thumbnails / worksheet-style page tabs. */\nexport function usePageList(token: StageTokenProp = StageToken) {\n const pages = useSelector(\n token,\n (c) => c.pages(),\n (a, b) =>\n a.length === b.length && a.every((p, i) => p.pon === b[i].pon && p.label === b[i].label),\n );\n const current = useSelector(\n token,\n (c) => c.currentItemPages(),\n (a, b) => a.length === b.length && a.every((x, i) => x === b[i]),\n );\n return { pages, currentItemPages: current };\n}\n\n/**\n * All Stage settings + the batch `update`. This is the seam for \"presets are a\n * customer concern\": keep your own `Partial<StageSettings>` objects and apply them\n * with `update(preset)` (one anchor-preserving change).\n */\nexport function useStageSettings(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n // settingsEqual derives from the plugin's settings registry — a new setting is\n // covered here automatically, without this package spelling out the shape.\n const settings = useSelector(token, (c) => c.settings(), settingsEqual);\n return { settings, update: s.update, reset: s.resetView };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"stage.js","names":[],"sources":["../src/stage.tsx"],"sourcesContent":["/**\n * Stage / RenderLayer + facade hooks.\n *\n * <Stage> virtualizes and positions page surfaces by the camera, and hands each\n * one to YOUR render prop — you bring the layers. (The standalone, Stage-free\n * single-page surface lives in `./page-view` so it never pulls the stage plugin.)\n */\n\n// One-line-per-feature: registration travels with the UI.\nexport * from '@embedpdf/plugin-stage';\nimport * as React from 'react';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { StageToken, settingsEqual, wheelZoomFactor } from '@embedpdf/plugin-stage';\nimport type { StageCapability, VisiblePage } from '@embedpdf/plugin-stage';\nimport type { CapabilityToken } from '@embedpdf/core';\n\n/** Which stage lens to bind to. Defaults to the main StageToken — pass a custom\n * token to drive an additional lens (e.g. a wrapped thumbnail sidebar). */\nexport type StageTokenProp = CapabilityToken<StageCapability>;\nimport type { PageFrame } from '@embedpdf/core-geometry';\nimport { InteractionToken } from '@embedpdf/plugin-interaction';\nimport type { PointerSample } from '@embedpdf/plugin-interaction';\nimport { ProjectorProvider, type ProjectorBinding, type ViewProjector } from './anchored';\nimport { createClickCounter } from './interaction';\nimport {\n makePageContext,\n PageProvider,\n useCapability,\n useDocumentId,\n useKernelValue,\n useOptionalCapability,\n useSelector,\n} from './runtime';\nimport type { PageContextValue } from './runtime';\n\nfunction PageSurface({\n documentId,\n page,\n frame,\n stage,\n render,\n chrome,\n}: {\n documentId: string;\n page: VisiblePage;\n /** Reserved chrome bands around the page (screen px); the layout reserved the\n * matching space, so the outer box tiles into it. */\n frame: PageFrame;\n /** The stage capability — the demand getter reads visibility LIVE off it. */\n stage: StageCapability;\n render: (page: PageContextValue) => React.ReactNode;\n chrome?: (page: PageContextValue) => React.ReactNode;\n}) {\n const ref = useRef<HTMLDivElement>(null);\n const t = page.transform;\n const rotation = page.rotation;\n // All geometry comes from the transform: the DISPLAY footprint (viewWidth/Height,\n // already w↔h-swapped + device-snapped) and the UN-rotated content box\n // (contentWidth/Height). The shell never re-derives `* zoom` / `* dpr` / snapping.\n const outerW = t.viewWidth + frame.left + frame.right;\n const outerH = t.viewHeight + frame.top + frame.bottom;\n // page.screenX/screenY are the device-snapped footprint top-left; the outer box\n // sits one frame further out so the content keeps its scene position.\n const left = page.screenX - frame.left;\n const top = page.screenY - frame.top;\n // Center the (possibly rotated) content box on the display box and rotate about\n // its center — NO translate(), so rotation 0 carries no transform and pixel-snaps\n // like the axis-aligned shadow behind it (no hairline seam).\n const contentLeft = frame.left + (t.viewWidth - t.contentWidth) / 2;\n const contentTop = frame.top + (t.viewHeight - t.contentHeight) / 2;\n // The page-view DEMAND is a PULL: the getter closes over\n // stable references (capability + pon) and reads the stage's live state at\n // call time — visibility is the STAGE's data (`VisiblePage.visibleRect`),\n // not something an adapter re-derives or caches. Absent from the visible\n // set = zero rect (\"want nothing\"), distinct from PageView's undefined\n // getter (\"whole page\").\n const ctx = useMemo(\n () =>\n makePageContext(\n documentId,\n page.pon,\n page.pageIndex,\n frame,\n t,\n () => ref.current!.getBoundingClientRect(),\n () => {\n const live = stage.visiblePages().find((p) => p.pon === page.pon);\n return live\n ? { desiredDeviceWidth: live.transform.deviceWidth, visibleRect: live.visibleRect }\n : {\n desiredDeviceWidth: t.deviceWidth,\n visibleRect: { x: 0, y: 0, width: 0, height: 0 },\n };\n },\n ),\n [documentId, page.pon, page.pageIndex, frame, t, stage],\n );\n return (\n <div style={{ position: 'absolute', left, top, width: outerW, height: outerH }}>\n <PageProvider value={ctx}>\n {/* drop shadow ONLY — axis-aligned at the content box (inset by the frame),\n transparent fill so it can never peek out behind the bitmap, and it\n stays put under rotation. */}\n <div\n style={{\n position: 'absolute',\n left: frame.left,\n top: frame.top,\n width: t.viewWidth,\n height: t.viewHeight,\n boxShadow: '0 6px 18px rgba(0,0,0,.18)',\n }}\n />\n {/* the page: white backing + bitmap as ONE rasterized box, so there is no\n seam between them and nothing white larger than the bitmap to leak.\n The ONLY thing rotation turns; markers/annotations ride it in content\n coordinates. Rotation 0 carries no transform → pixel-snaps cleanly. */}\n <div\n ref={ref}\n style={{\n position: 'absolute',\n left: contentLeft,\n top: contentTop,\n width: t.contentWidth,\n height: t.contentHeight,\n background: '#fff',\n transform: rotation ? `rotate(${rotation}deg)` : undefined,\n // We render our own selection highlights — suppress native text/image\n // selection (and the double-click image grab) on the whole page subtree.\n userSelect: 'none',\n WebkitUserSelect: 'none',\n }}\n >\n {render(ctx)}\n </div>\n {/* box-space chrome — labels, selection border, per-page buttons — fills\n the outer box, NEVER rotates. Bands are plain regions: a label is\n `bottom:0; height: frame.bottom`, a button row `top:0; height: frame.top`. */}\n {chrome?.(ctx)}\n </PageProvider>\n </div>\n );\n}\n\nexport interface StageProps {\n /**\n * PAGE-SPACE content for each visible page (RenderLayer, annotations,\n * markers). Rendered inside the page's content frame, so it ROTATES with the\n * page's display rotation — coordinates are plain PDF points.\n */\n children: (page: PageContextValue) => React.ReactNode;\n /**\n * BOX-SPACE chrome for each visible page (page-number label, selection\n * border, a per-page rotate/delete button). Rendered into the OUTER box\n * (content + reserved `pageFrame`), so it does NOT rotate and the reserved\n * bands are plain regions (`bottom:0; height: page.frame.bottom`). The three\n * coordinate spaces: `children` (page content), `pageChrome` (page box +\n * frame), `overlay` (viewport).\n */\n pageChrome?: (page: PageContextValue) => React.ReactNode;\n /** Viewport-space UI (menus, controls) rendered above the pages. */\n overlay?: React.ReactNode;\n /**\n * Route this Stage's pointer events to the interaction hub (page-resolved via\n * `pageAt`) instead of the built-in drag-to-pan. Pan then becomes the `pan`\n * tool's job and dragging in `pointer` mode selects text (incl. across pages).\n * Pair with `stagePlugin({ interaction: true })`. Default false (built-in pan).\n */\n interaction?: boolean;\n /**\n * Ambient ZOOM gestures on this stage: ctrl/cmd+wheel and trackpad pinch\n * (Safari gesture events included). Default true. Turn OFF for follower\n * lenses with a fixed magnification — a thumbnail rail should scroll under\n * cmd+wheel, not zoom — so a zoom-wheel falls through to ordinary wheel\n * pan, and pinches are still swallowed (they never page-zoom the browser).\n */\n zoomGestures?: boolean;\n /** The stage lens to drive (default: the main StageToken). */\n token?: StageTokenProp;\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport function Stage({\n children,\n pageChrome,\n overlay,\n interaction = false,\n zoomGestures = true,\n token = StageToken,\n className,\n style,\n}: StageProps) {\n const stage = useCapability(token);\n const ix = useOptionalCapability(InteractionToken);\n const useHub = interaction && !!ix;\n // The hub's resolved cursor (text/grab/…), applied to the viewport when driving.\n const hubCursor = useKernelValue(() => ix?.cursor() ?? 'default');\n const ref = useRef<HTMLDivElement>(null);\n const docId = useDocumentId();\n // visiblePages already folds in the camera (each page carries its device-snapped\n // screenX/screenY + transform), so panning re-emits the list — no separate\n // camera subscription needed for positioning.\n const pages = useSelector(token, (c) => c.visiblePages()); // memoized -> stable ref\n // Reserved chrome bands (screen px), uniform across pages — the frame the\n // outer box reserves and `pageChrome` paints into.\n const frame = useSelector(\n token,\n (c) => c.pageFrame(),\n (a, b) => a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left,\n );\n\n // The Stage's ViewProjector: anchored UI (menus, popovers) positions through\n // the CAMERA — pure state, no DOM reads, no portal, and NO subscription:\n // `pages` (visiblePages) is the binding's revision, so a camera change\n // re-renders the pages AND every anchored consumer in the SAME React\n // commit — surface and overlay can never paint a frame apart.\n const projector = useMemo<ViewProjector>(\n () => ({\n space: 'overlay',\n toScreen: (pon, rect) => stage.pageRectToScreen(pon, rect),\n toScreenPoint: (pon, at) => {\n const r = stage.pageRectToScreen(pon, { x: at.x, y: at.y, width: 0, height: 0 });\n return r ? { x: r.x, y: r.y } : null;\n },\n viewEnv: (pon) => {\n const t = stage.pageRect(pon)?.transform;\n return t ? { scale: t.viewScale, rotation: t.rotation, zoom: t.zoom } : null;\n },\n }),\n [stage],\n );\n const projectorBinding = useMemo<ProjectorBinding>(\n () => ({ projector, revision: pages }),\n [projector, pages],\n );\n\n useEffect(() => {\n const el = ref.current!;\n // Only report the viewport size. Initial placement (home) is the Stage plugin's\n // job — it watches the viewport and homes once it's ready (and a higher-priority\n // initial-view provider can override that). The shell stays dumb.\n const setVp = () => stage.setViewport({ width: el.clientWidth, height: el.clientHeight });\n const ro = new ResizeObserver(setVp);\n ro.observe(el);\n setVp();\n\n // Report the device pixel ratio so page transforms render crisp. dppx changes\n // (zoom, dragging between monitors) fire the media query; re-subscribe each\n // time since the query value itself moves.\n let mq: MediaQueryList | null = null;\n const reportDpr = () => {\n stage.setDevicePixelRatio(window.devicePixelRatio || 1);\n mq?.removeEventListener('change', reportDpr);\n mq = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);\n mq.addEventListener('change', reportDpr);\n };\n reportDpr();\n\n // Wheel is ambient navigation in BOTH modes: ctrl/meta zooms (classified\n // per input — synthesized pinch, mouse notch, cmd-scroll scrub — by\n // wheelZoomFactor), else scrolls. With zoom gestures off, a zoom-wheel\n // falls through to ordinary pan (a cmd+scroll over a thumbnail rail\n // scrolls the rail).\n const onWheel = (e: WheelEvent) => {\n e.preventDefault();\n const r = el.getBoundingClientRect();\n if (zoomGestures && (e.ctrlKey || e.metaKey)) {\n stage.zoomAround({ x: e.clientX - r.left, y: e.clientY - r.top }, wheelZoomFactor(e));\n } else {\n const dx = e.shiftKey ? e.deltaY : e.deltaX;\n const dy = e.shiftKey ? e.deltaX : e.deltaY;\n stage.panBy(-dx, -dy);\n }\n };\n el.addEventListener('wheel', onWheel, { passive: false });\n\n // Safari never synthesizes ctrl+wheel for trackpad pinch — it fires\n // proprietary gesture events carrying an ABSOLUTE scale; convert to the\n // per-event ratio the camera physics wants. Feature-detected: Chrome and\n // Firefox don't have GestureEvent, so this wiring costs them nothing.\n // preventDefault runs even with zoom gestures off — a pinch over the\n // stage must never zoom the page itself.\n let lastScale = 1;\n const onGestureStart = (e: Event) => {\n e.preventDefault();\n lastScale = (e as unknown as { scale?: number }).scale ?? 1;\n };\n const onGestureChange = (e: Event) => {\n e.preventDefault();\n const g = e as unknown as { scale?: number; clientX: number; clientY: number };\n const scale = g.scale ?? 1;\n if (zoomGestures && scale > 0) {\n const r = el.getBoundingClientRect();\n stage.zoomAround({ x: g.clientX - r.left, y: g.clientY - r.top }, scale / lastScale);\n }\n lastScale = scale;\n };\n const hasGestureEvents = 'GestureEvent' in window;\n if (hasGestureEvents) {\n el.addEventListener('gesturestart', onGestureStart);\n el.addEventListener('gesturechange', onGestureChange);\n el.addEventListener('gestureend', onGestureStart); // reset the base\n }\n\n const cleanups: Array<() => void> = [];\n if (useHub && ix) {\n // Forward to the hub: pan/select/etc. become tool-gated handlers. `pageAt`\n // resolves the page per event, so a drag can cross pages (text selection).\n const clicks = createClickCounter();\n const forward = (phase: PointerSample['phase'], e: PointerEvent, clickCount = 1) => {\n const r = el.getBoundingClientRect();\n const vpt = { x: e.clientX - r.left, y: e.clientY - r.top };\n ix.dispatch({\n phase,\n viewport: vpt,\n page: stage.pageAt(vpt) ?? undefined,\n // Page-anchored gestures (annotation move/resize) track the origin\n // page's frame through this even when the cursor is off that page.\n project: (pon) => stage.pointOnPage(pon, vpt),\n modifiers: { shift: e.shiftKey, alt: e.altKey, ctrl: e.ctrlKey, meta: e.metaKey },\n clickCount,\n });\n };\n let dragging = false;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n forward('down', e, clicks(Date.now(), e.clientX, e.clientY));\n };\n const hover = (e: PointerEvent) => {\n if (!dragging) forward('move', e); // cursor feedback, no gesture\n };\n const winMove = (e: PointerEvent) => {\n if (dragging) forward('move', e);\n };\n const up = (e: PointerEvent) => {\n if (!dragging) return;\n dragging = false;\n forward('up', e);\n };\n el.addEventListener('pointerdown', down);\n el.addEventListener('pointermove', hover);\n window.addEventListener('pointermove', winMove);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n el.removeEventListener('pointermove', hover);\n window.removeEventListener('pointermove', winMove);\n window.removeEventListener('pointerup', up);\n });\n } else {\n // Built-in drag-to-pan (no interaction hub) — unchanged behaviour.\n let dragging = false;\n let lx = 0;\n let ly = 0;\n const down = (e: PointerEvent) => {\n if (e.button !== 0) return;\n dragging = true;\n lx = e.clientX;\n ly = e.clientY;\n };\n const move = (e: PointerEvent) => {\n if (!dragging) return;\n stage.panBy(e.clientX - lx, e.clientY - ly);\n lx = e.clientX;\n ly = e.clientY;\n };\n const up = () => {\n dragging = false;\n };\n el.addEventListener('pointerdown', down);\n window.addEventListener('pointermove', move);\n window.addEventListener('pointerup', up);\n cleanups.push(() => {\n el.removeEventListener('pointerdown', down);\n window.removeEventListener('pointermove', move);\n window.removeEventListener('pointerup', up);\n });\n }\n\n return () => {\n ro.disconnect();\n mq?.removeEventListener('change', reportDpr);\n el.removeEventListener('wheel', onWheel);\n if (hasGestureEvents) {\n el.removeEventListener('gesturestart', onGestureStart);\n el.removeEventListener('gesturechange', onGestureChange);\n el.removeEventListener('gestureend', onGestureStart);\n }\n cleanups.forEach((fn) => fn());\n };\n }, [stage, ix, useHub, zoomGestures]);\n\n return (\n <div\n ref={ref}\n className={className}\n style={{\n position: 'relative',\n overflow: 'hidden',\n touchAction: 'none',\n ...(useHub ? { cursor: hubCursor } : null),\n ...style,\n }}\n >\n {pages.map((p) => (\n <PageSurface\n key={p.pageIndex}\n documentId={docId ?? ''}\n page={p}\n frame={frame}\n stage={stage}\n render={children}\n chrome={pageChrome}\n />\n ))}\n {/* Anchored UI mounts in the overlay: absolute coords here are the\n projector's overlay space (the stage container). */}\n <ProjectorProvider value={projectorBinding}>{overlay}</ProjectorProvider>\n </div>\n );\n}\n\n// ── Facade hooks — thin sugar over the capability + generic binding ───────────\nexport function useStage(token: StageTokenProp = StageToken) {\n return useCapability(token);\n}\nexport function useZoom(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const zoom = useSelector(token, (c) => c.zoomLevel());\n const mode = useSelector(token, (c) => c.zoomMode());\n return {\n zoom,\n /** Active zoom intent: 'automatic' | 'fit-page' | 'fit-width' | 'fit-all' | 'custom'. */\n mode,\n zoomIn: s.zoomIn,\n zoomOut: s.zoomOut,\n fitWidth: s.fitWidth,\n fitPage: s.fitPage,\n fitAll: s.fitAll,\n automatic: s.automatic,\n zoomTo: s.zoomTo,\n };\n}\nexport function usePages(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const currentPage = useSelector(token, (c) => c.currentPage());\n const pageCount = useSelector(token, (c) => c.pageCount());\n return {\n currentPage,\n pageCount,\n goToPage: s.goToPage,\n next: s.next,\n prev: s.prev,\n reveal: s.reveal,\n };\n}\nexport function useLayout(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n const flow = useSelector(token, (c) => c.flow());\n const layout = useSelector(token, (c) => c.layout());\n const spread = useSelector(token, (c) => c.spread());\n const sizing = useSelector(token, (c) => c.sizing());\n const bounded = useSelector(token, (c) => c.bounded());\n return {\n flow,\n layout,\n spread,\n sizing,\n bounded,\n setFlow: s.setFlow,\n setLayout: s.setLayout,\n setSpread: s.setSpread,\n setSizing: s.setSizing,\n setBounded: s.setBounded,\n };\n}\n\n/** The document's page list (with PDF labels) + the current item's pages — the\n * data for page thumbnails / worksheet-style page tabs. */\nexport function usePageList(token: StageTokenProp = StageToken) {\n const pages = useSelector(\n token,\n (c) => c.pages(),\n (a, b) =>\n a.length === b.length && a.every((p, i) => p.pon === b[i].pon && p.label === b[i].label),\n );\n const current = useSelector(\n token,\n (c) => c.currentItemPages(),\n (a, b) => a.length === b.length && a.every((x, i) => x === b[i]),\n );\n return { pages, currentItemPages: current };\n}\n\n/**\n * All Stage settings + the batch `update`. This is the seam for \"presets are a\n * customer concern\": keep your own `Partial<StageSettings>` objects and apply them\n * with `update(preset)` (one anchor-preserving change).\n */\nexport function useStageSettings(token: StageTokenProp = StageToken) {\n const s = useCapability(token);\n // settingsEqual derives from the plugin's settings registry — a new setting is\n // covered here automatically, without this package spelling out the shape.\n const settings = useSelector(token, (c) => c.settings(), settingsEqual);\n return { settings, update: s.update, reset: s.resetView };\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@embedpdf/react",
|
|
3
|
-
"version": "3.0.0-next.
|
|
3
|
+
"version": "3.0.0-next.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "React adapter for EmbedPDF v3: one generic reactive binding + structural components (Viewer, Stage, PageView) + headless layers & hooks. The whole framework surface.",
|
|
6
6
|
"type": "module",
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
"import": "./dist/index.js",
|
|
14
14
|
"require": "./dist/index.cjs"
|
|
15
15
|
},
|
|
16
|
+
"./anchored": {
|
|
17
|
+
"import": "./dist/anchored.js",
|
|
18
|
+
"require": "./dist/anchored.cjs"
|
|
19
|
+
},
|
|
16
20
|
"./annotation": {
|
|
17
21
|
"import": "./dist/annotation.js",
|
|
18
22
|
"require": "./dist/annotation.cjs"
|
|
@@ -103,28 +107,28 @@
|
|
|
103
107
|
"dist"
|
|
104
108
|
],
|
|
105
109
|
"dependencies": {
|
|
106
|
-
"@embedpdf/core-annotation": "3.0.0-next.
|
|
107
|
-
"@embedpdf/core-geometry": "3.0.0-next.
|
|
108
|
-
"@embedpdf/
|
|
109
|
-
"@embedpdf/plugin-
|
|
110
|
-
"@embedpdf/plugin-form": "3.0.0-next.
|
|
111
|
-
"@embedpdf/
|
|
112
|
-
"@embedpdf/plugin-
|
|
113
|
-
"@embedpdf/plugin-
|
|
114
|
-
"@embedpdf/plugin-link": "3.0.0-next.
|
|
115
|
-
"@embedpdf/plugin-metadata": "3.0.0-next.
|
|
116
|
-
"@embedpdf/plugin-
|
|
117
|
-
"@embedpdf/plugin-
|
|
118
|
-
"@embedpdf/plugin-
|
|
119
|
-
"@embedpdf/plugin-
|
|
120
|
-
"@embedpdf/plugin-
|
|
121
|
-
"@embedpdf/plugin-
|
|
122
|
-
"@embedpdf/plugin-stage": "3.0.0-next.
|
|
123
|
-
"@embedpdf/plugin-stamp": "3.0.0-next.
|
|
124
|
-
"@embedpdf/core-stage": "3.0.0-next.
|
|
125
|
-
"@embedpdf/plugin-view-manager": "3.0.0-next.
|
|
126
|
-
"@embedpdf/core-ui": "3.0.0-next.
|
|
127
|
-
"@embedpdf/web": "3.0.0-next.
|
|
110
|
+
"@embedpdf/core-annotation": "3.0.0-next.5",
|
|
111
|
+
"@embedpdf/core-geometry": "3.0.0-next.5",
|
|
112
|
+
"@embedpdf/plugin-commands": "3.0.0-next.5",
|
|
113
|
+
"@embedpdf/plugin-annotation": "3.0.0-next.5",
|
|
114
|
+
"@embedpdf/plugin-form": "3.0.0-next.5",
|
|
115
|
+
"@embedpdf/core": "3.0.0-next.5",
|
|
116
|
+
"@embedpdf/plugin-interaction": "3.0.0-next.5",
|
|
117
|
+
"@embedpdf/plugin-i18n": "3.0.0-next.5",
|
|
118
|
+
"@embedpdf/plugin-link": "3.0.0-next.5",
|
|
119
|
+
"@embedpdf/plugin-metadata": "3.0.0-next.5",
|
|
120
|
+
"@embedpdf/plugin-render": "3.0.0-next.5",
|
|
121
|
+
"@embedpdf/plugin-page-edit": "3.0.0-next.5",
|
|
122
|
+
"@embedpdf/plugin-selection": "3.0.0-next.5",
|
|
123
|
+
"@embedpdf/plugin-redaction": "3.0.0-next.5",
|
|
124
|
+
"@embedpdf/plugin-search": "3.0.0-next.5",
|
|
125
|
+
"@embedpdf/plugin-shell": "3.0.0-next.5",
|
|
126
|
+
"@embedpdf/plugin-stage": "3.0.0-next.5",
|
|
127
|
+
"@embedpdf/plugin-stamp": "3.0.0-next.5",
|
|
128
|
+
"@embedpdf/core-stage": "3.0.0-next.5",
|
|
129
|
+
"@embedpdf/plugin-view-manager": "3.0.0-next.5",
|
|
130
|
+
"@embedpdf/core-ui": "3.0.0-next.5",
|
|
131
|
+
"@embedpdf/web": "3.0.0-next.5"
|
|
128
132
|
},
|
|
129
133
|
"peerDependencies": {
|
|
130
134
|
"react": ">=18",
|