@embedpdf/react 3.0.0-next.7 → 3.0.0-next.8
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/stage.cjs +1 -1
- package/dist/stage.cjs.map +1 -1
- package/dist/stage.js +2 -2
- package/dist/stage.js.map +1 -1
- package/package.json +23 -23
package/dist/stage.cjs
CHANGED
|
@@ -117,7 +117,7 @@ function Stage({ children, pageChrome, overlay, interaction = true, panFallback
|
|
|
117
117
|
projector,
|
|
118
118
|
revision: pages
|
|
119
119
|
}), [projector, pages]);
|
|
120
|
-
(0, react.
|
|
120
|
+
(0, react.useLayoutEffect)(() => {
|
|
121
121
|
const el = ref.current;
|
|
122
122
|
const detachSurface = (0, _embedpdf_web.createStageSurface)(el, stage, {
|
|
123
123
|
hub: useHub ? ix : null,
|
package/dist/stage.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage.cjs","names":["makePageContext","PageProvider","StageToken","useCapability","useOptionalCapability","InteractionToken","useKernelValue","useDocumentId","useSelector","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, createScrollHandler, settingsEqual } 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 { createStageSurface } from '@embedpdf/web';\nimport { ProjectorProvider, type ProjectorBinding, type ViewProjector } from './anchored';\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 // the hosting lens — per-view raster planning keys tile state by it,\n // so a thumbnail rail and the main view never fight over one plan\n stage.lensId(),\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 // themeable: override via the CSS variable (app stylesheet), no props\n boxShadow: 'var(--epdf-page-shadow, 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`) — AND register this lens's tool-gated pan-scroll handler with it\n * (lens-scoped, so multiple stages on one document never pan each other).\n * Pan is then the `pan` tool's job and dragging in `pointer` mode selects\n * text (incl. across pages).\n *\n * Default TRUE: registering `interactionPlugin()` is the one opt-in — tools\n * just work; without the hub this is inert and the stage falls back to\n * built-in drag-to-pan, so a hub-less setup costs nothing. Set `false` on\n * SECONDARY lenses (a thumbnail rail) that should stay click-to-navigate\n * instead of feeding the document's tools.\n */\n interaction?: boolean;\n /**\n * With {@link interaction}: let drags over page GAPS pan regardless of the\n * active tool (and show a grab cursor there) — the gutter always pans; there\n * is nothing to draw/select outside a page. Default true.\n */\n panFallback?: 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 = true,\n panFallback = true,\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 // The WHOLE browser binding — viewport/DPR reporting, sample normalization,\n // gesture controller — is the shared @embedpdf/web surface, so every\n // framework adapter has one feel. This component keeps only React glue.\n const detachSurface = createStageSurface(el, stage, {\n hub: useHub ? ix : null,\n source: stage.lensId(),\n zoomGestures,\n });\n // Interaction opt-in lives WITH the sample source: the same knob that\n // forwards this lens's samples also registers its pan-scroll handler,\n // lens-scoped — two stages on one document can never pan each other.\n const offScroll =\n useHub && ix\n ? ix.registerHandler(createScrollHandler(stage, ix, { panFallback }), {\n source: stage.lensId(),\n })\n : null;\n\n return () => {\n offScroll?.();\n detachSurface();\n };\n }, [stage, ix, useHub, zoomGestures, panFallback]);\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.pon} // durable page identity — survives move/delete (matches Angular's `track p.pon`)\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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"}
|
|
1
|
+
{"version":3,"file":"stage.cjs","names":["makePageContext","PageProvider","StageToken","useCapability","useOptionalCapability","InteractionToken","useKernelValue","useDocumentId","useSelector","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 { useLayoutEffect, useMemo, useRef } from 'react';\nimport { StageToken, createScrollHandler, settingsEqual } 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 { createStageSurface } from '@embedpdf/web';\nimport { ProjectorProvider, type ProjectorBinding, type ViewProjector } from './anchored';\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 // the hosting lens — per-view raster planning keys tile state by it,\n // so a thumbnail rail and the main view never fight over one plan\n stage.lensId(),\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 // themeable: override via the CSS variable (app stylesheet), no props\n boxShadow: 'var(--epdf-page-shadow, 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`) — AND register this lens's tool-gated pan-scroll handler with it\n * (lens-scoped, so multiple stages on one document never pan each other).\n * Pan is then the `pan` tool's job and dragging in `pointer` mode selects\n * text (incl. across pages).\n *\n * Default TRUE: registering `interactionPlugin()` is the one opt-in — tools\n * just work; without the hub this is inert and the stage falls back to\n * built-in drag-to-pan, so a hub-less setup costs nothing. Set `false` on\n * SECONDARY lenses (a thumbnail rail) that should stay click-to-navigate\n * instead of feeding the document's tools.\n */\n interaction?: boolean;\n /**\n * With {@link interaction}: let drags over page GAPS pan regardless of the\n * active tool (and show a grab cursor there) — the gutter always pans; there\n * is nothing to draw/select outside a page. Default true.\n */\n panFallback?: 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 = true,\n panFallback = true,\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 useLayoutEffect(() => {\n const el = ref.current!;\n // The WHOLE browser binding — viewport/DPR reporting, sample normalization,\n // gesture controller — is the shared @embedpdf/web surface, so every\n // framework adapter has one feel. This component keeps only React glue.\n const detachSurface = createStageSurface(el, stage, {\n hub: useHub ? ix : null,\n source: stage.lensId(),\n zoomGestures,\n });\n // Interaction opt-in lives WITH the sample source: the same knob that\n // forwards this lens's samples also registers its pan-scroll handler,\n // lens-scoped — two stages on one document can never pan each other.\n const offScroll =\n useHub && ix\n ? ix.registerHandler(createScrollHandler(stage, ix, { panFallback }), {\n source: stage.lensId(),\n })\n : null;\n\n return () => {\n offScroll?.();\n detachSurface();\n };\n }, [stage, ix, useHub, zoomGestures, panFallback]);\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.pon} // durable page identity — survives move/delete (matches Angular's `track p.pon`)\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,7 +1,7 @@
|
|
|
1
1
|
import { PageProvider, makePageContext, useCapability, useDocumentId, useKernelValue, useOptionalCapability, useSelector } from "./runtime.js";
|
|
2
2
|
import { ProjectorProvider } from "./anchored.js";
|
|
3
3
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
-
import {
|
|
4
|
+
import { useLayoutEffect, useMemo, useRef } from "react";
|
|
5
5
|
import { createStageSurface } from "@embedpdf/web";
|
|
6
6
|
import { StageToken, createScrollHandler, settingsEqual } from "@embedpdf/plugin-stage";
|
|
7
7
|
import { InteractionToken } from "@embedpdf/plugin-interaction";
|
|
@@ -115,7 +115,7 @@ function Stage({ children, pageChrome, overlay, interaction = true, panFallback
|
|
|
115
115
|
projector,
|
|
116
116
|
revision: pages
|
|
117
117
|
}), [projector, pages]);
|
|
118
|
-
|
|
118
|
+
useLayoutEffect(() => {
|
|
119
119
|
const el = ref.current;
|
|
120
120
|
const detachSurface = createStageSurface(el, stage, {
|
|
121
121
|
hub: useHub ? ix : null,
|
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, createScrollHandler, settingsEqual } 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 { createStageSurface } from '@embedpdf/web';\nimport { ProjectorProvider, type ProjectorBinding, type ViewProjector } from './anchored';\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 // the hosting lens — per-view raster planning keys tile state by it,\n // so a thumbnail rail and the main view never fight over one plan\n stage.lensId(),\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 // themeable: override via the CSS variable (app stylesheet), no props\n boxShadow: 'var(--epdf-page-shadow, 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`) — AND register this lens's tool-gated pan-scroll handler with it\n * (lens-scoped, so multiple stages on one document never pan each other).\n * Pan is then the `pan` tool's job and dragging in `pointer` mode selects\n * text (incl. across pages).\n *\n * Default TRUE: registering `interactionPlugin()` is the one opt-in — tools\n * just work; without the hub this is inert and the stage falls back to\n * built-in drag-to-pan, so a hub-less setup costs nothing. Set `false` on\n * SECONDARY lenses (a thumbnail rail) that should stay click-to-navigate\n * instead of feeding the document's tools.\n */\n interaction?: boolean;\n /**\n * With {@link interaction}: let drags over page GAPS pan regardless of the\n * active tool (and show a grab cursor there) — the gutter always pans; there\n * is nothing to draw/select outside a page. Default true.\n */\n panFallback?: 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 = true,\n panFallback = true,\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 // The WHOLE browser binding — viewport/DPR reporting, sample normalization,\n // gesture controller — is the shared @embedpdf/web surface, so every\n // framework adapter has one feel. This component keeps only React glue.\n const detachSurface = createStageSurface(el, stage, {\n hub: useHub ? ix : null,\n source: stage.lensId(),\n zoomGestures,\n });\n // Interaction opt-in lives WITH the sample source: the same knob that\n // forwards this lens's samples also registers its pan-scroll handler,\n // lens-scoped — two stages on one document can never pan each other.\n const offScroll =\n useHub && ix\n ? ix.registerHandler(createScrollHandler(stage, ix, { panFallback }), {\n source: stage.lensId(),\n })\n : null;\n\n return () => {\n offScroll?.();\n detachSurface();\n };\n }, [stage, ix, useHub, zoomGestures, panFallback]);\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.pon} // durable page identity — survives move/delete (matches Angular's `track p.pon`)\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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"}
|
|
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 { useLayoutEffect, useMemo, useRef } from 'react';\nimport { StageToken, createScrollHandler, settingsEqual } 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 { createStageSurface } from '@embedpdf/web';\nimport { ProjectorProvider, type ProjectorBinding, type ViewProjector } from './anchored';\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 // the hosting lens — per-view raster planning keys tile state by it,\n // so a thumbnail rail and the main view never fight over one plan\n stage.lensId(),\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 // themeable: override via the CSS variable (app stylesheet), no props\n boxShadow: 'var(--epdf-page-shadow, 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`) — AND register this lens's tool-gated pan-scroll handler with it\n * (lens-scoped, so multiple stages on one document never pan each other).\n * Pan is then the `pan` tool's job and dragging in `pointer` mode selects\n * text (incl. across pages).\n *\n * Default TRUE: registering `interactionPlugin()` is the one opt-in — tools\n * just work; without the hub this is inert and the stage falls back to\n * built-in drag-to-pan, so a hub-less setup costs nothing. Set `false` on\n * SECONDARY lenses (a thumbnail rail) that should stay click-to-navigate\n * instead of feeding the document's tools.\n */\n interaction?: boolean;\n /**\n * With {@link interaction}: let drags over page GAPS pan regardless of the\n * active tool (and show a grab cursor there) — the gutter always pans; there\n * is nothing to draw/select outside a page. Default true.\n */\n panFallback?: 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 = true,\n panFallback = true,\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 useLayoutEffect(() => {\n const el = ref.current!;\n // The WHOLE browser binding — viewport/DPR reporting, sample normalization,\n // gesture controller — is the shared @embedpdf/web surface, so every\n // framework adapter has one feel. This component keeps only React glue.\n const detachSurface = createStageSurface(el, stage, {\n hub: useHub ? ix : null,\n source: stage.lensId(),\n zoomGestures,\n });\n // Interaction opt-in lives WITH the sample source: the same knob that\n // forwards this lens's samples also registers its pan-scroll handler,\n // lens-scoped — two stages on one document can never pan each other.\n const offScroll =\n useHub && ix\n ? ix.registerHandler(createScrollHandler(stage, ix, { panFallback }), {\n source: stage.lensId(),\n })\n : null;\n\n return () => {\n offScroll?.();\n detachSurface();\n };\n }, [stage, ix, useHub, zoomGestures, panFallback]);\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.pon} // durable page identity — survives move/delete (matches Angular's `track p.pon`)\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.8",
|
|
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",
|
|
@@ -107,28 +107,28 @@
|
|
|
107
107
|
"dist"
|
|
108
108
|
],
|
|
109
109
|
"dependencies": {
|
|
110
|
-
"@embedpdf/core-
|
|
111
|
-
"@embedpdf/
|
|
112
|
-
"@embedpdf/
|
|
113
|
-
"@embedpdf/
|
|
114
|
-
"@embedpdf/
|
|
115
|
-
"@embedpdf/plugin-
|
|
116
|
-
"@embedpdf/plugin-
|
|
117
|
-
"@embedpdf/plugin-
|
|
118
|
-
"@embedpdf/plugin-
|
|
119
|
-
"@embedpdf/plugin-link": "3.0.0-next.
|
|
120
|
-
"@embedpdf/plugin-page-edit": "3.0.0-next.
|
|
121
|
-
"@embedpdf/plugin-
|
|
122
|
-
"@embedpdf/plugin-
|
|
123
|
-
"@embedpdf/plugin-
|
|
124
|
-
"@embedpdf/plugin-selection": "3.0.0-next.
|
|
125
|
-
"@embedpdf/plugin-stage": "3.0.0-next.
|
|
126
|
-
"@embedpdf/plugin-
|
|
127
|
-
"@embedpdf/plugin-stamp": "3.0.0-next.
|
|
128
|
-
"@embedpdf/plugin-view-manager": "3.0.0-next.
|
|
129
|
-
"@embedpdf/core-ui": "3.0.0-next.
|
|
130
|
-
"@embedpdf/
|
|
131
|
-
"@embedpdf/
|
|
110
|
+
"@embedpdf/core-annotation": "3.0.0-next.8",
|
|
111
|
+
"@embedpdf/core-geometry": "3.0.0-next.8",
|
|
112
|
+
"@embedpdf/core": "3.0.0-next.8",
|
|
113
|
+
"@embedpdf/plugin-annotation": "3.0.0-next.8",
|
|
114
|
+
"@embedpdf/plugin-form": "3.0.0-next.8",
|
|
115
|
+
"@embedpdf/plugin-interaction": "3.0.0-next.8",
|
|
116
|
+
"@embedpdf/plugin-i18n": "3.0.0-next.8",
|
|
117
|
+
"@embedpdf/plugin-commands": "3.0.0-next.8",
|
|
118
|
+
"@embedpdf/plugin-metadata": "3.0.0-next.8",
|
|
119
|
+
"@embedpdf/plugin-link": "3.0.0-next.8",
|
|
120
|
+
"@embedpdf/plugin-page-edit": "3.0.0-next.8",
|
|
121
|
+
"@embedpdf/plugin-render": "3.0.0-next.8",
|
|
122
|
+
"@embedpdf/plugin-redaction": "3.0.0-next.8",
|
|
123
|
+
"@embedpdf/plugin-shell": "3.0.0-next.8",
|
|
124
|
+
"@embedpdf/plugin-selection": "3.0.0-next.8",
|
|
125
|
+
"@embedpdf/plugin-stage": "3.0.0-next.8",
|
|
126
|
+
"@embedpdf/plugin-search": "3.0.0-next.8",
|
|
127
|
+
"@embedpdf/plugin-stamp": "3.0.0-next.8",
|
|
128
|
+
"@embedpdf/plugin-view-manager": "3.0.0-next.8",
|
|
129
|
+
"@embedpdf/core-ui": "3.0.0-next.8",
|
|
130
|
+
"@embedpdf/core-stage": "3.0.0-next.8",
|
|
131
|
+
"@embedpdf/web": "3.0.0-next.8"
|
|
132
132
|
},
|
|
133
133
|
"peerDependencies": {
|
|
134
134
|
"react": ">=18",
|