@embedpdf/plugin-zoom 1.5.0 → 2.0.0-next.0
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/hammer-DhVzwxwy.cjs +7 -0
- package/dist/{hammer-Bs-QCG8V.cjs.map → hammer-DhVzwxwy.cjs.map} +1 -1
- package/dist/hammer-e1aXHboh.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +341 -157
- package/dist/index.js.map +1 -1
- package/dist/lib/actions.d.ts +32 -9
- package/dist/lib/index.d.ts +2 -2
- package/dist/lib/reducer.d.ts +2 -1
- package/dist/lib/types.d.ts +32 -16
- package/dist/lib/zoom-plugin.d.ts +22 -15
- package/dist/preact/index.cjs +1 -1
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.js +47 -26
- package/dist/preact/index.js.map +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +47 -26
- package/dist/react/index.js.map +1 -1
- package/dist/shared/components/marquee-zoom.d.ts +3 -6
- package/dist/shared/components/pinch-wrapper.d.ts +2 -1
- package/dist/shared/hooks/use-pinch-zoom.d.ts +1 -1
- package/dist/shared/hooks/use-zoom.d.ts +8 -4
- package/dist/shared/utils/pinch-zoom-logic.d.ts +2 -1
- package/dist/shared-preact/components/marquee-zoom.d.ts +3 -6
- package/dist/shared-preact/components/pinch-wrapper.d.ts +2 -1
- package/dist/shared-preact/hooks/use-pinch-zoom.d.ts +1 -1
- package/dist/shared-preact/hooks/use-zoom.d.ts +8 -4
- package/dist/shared-preact/utils/pinch-zoom-logic.d.ts +2 -1
- package/dist/shared-react/components/marquee-zoom.d.ts +3 -6
- package/dist/shared-react/components/pinch-wrapper.d.ts +2 -1
- package/dist/shared-react/hooks/use-pinch-zoom.d.ts +1 -1
- package/dist/shared-react/hooks/use-zoom.d.ts +8 -4
- package/dist/shared-react/utils/pinch-zoom-logic.d.ts +2 -1
- package/dist/shared-svelte/utils/pinch-zoom-logic.d.ts +2 -1
- package/dist/shared-vue/utils/pinch-zoom-logic.d.ts +2 -1
- package/dist/svelte/components/MarqueeZoom.svelte.d.ts +3 -1
- package/dist/svelte/components/PinchWrapper.svelte.d.ts +1 -0
- package/dist/svelte/hooks/use-pinch-zoom.svelte.d.ts +5 -1
- package/dist/svelte/hooks/use-zoom.svelte.d.ts +11 -5
- package/dist/svelte/index.cjs +1 -1
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.js +108 -53
- package/dist/svelte/index.js.map +1 -1
- package/dist/vue/components/marquee-zoom.vue.d.ts +5 -2
- package/dist/vue/components/pinch-wrapper.vue.d.ts +6 -2
- package/dist/vue/hooks/use-pinch-zoom.d.ts +6 -1
- package/dist/vue/hooks/use-zoom.d.ts +17 -10
- package/dist/vue/index.cjs +1 -1
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.js +99 -58
- package/dist/vue/index.js.map +1 -1
- package/package.json +10 -10
- package/dist/hammer-Bs-QCG8V.cjs +0 -7
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/lib/types.ts","../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/zoom-plugin.ts","../src/lib/handlers/marquee-zoom.handler.ts","../src/lib/index.ts"],"sourcesContent":["import { BasePluginConfig, EventHook } from '@embedpdf/core';\nimport { Rect } from '@embedpdf/models';\nimport { ViewportMetrics } from '@embedpdf/plugin-viewport';\n\n/* ------------------------------------------------------------------ */\n/* public */\n/* ------------------------------------------------------------------ */\n\nexport enum ZoomMode {\n Automatic = 'automatic',\n FitPage = 'fit-page',\n FitWidth = 'fit-width',\n}\n\nexport type ZoomLevel = ZoomMode | number;\n\nexport interface Point {\n vx: number;\n vy: number;\n}\n\nexport interface ZoomChangeEvent {\n /** old and new *actual* scale factors */\n oldZoom: number;\n newZoom: number;\n\n /** level used to obtain the newZoom (number | mode) */\n level: ZoomLevel;\n\n /** viewport point kept under the finger / mouse‑wheel focus */\n center: Point;\n\n /** where the viewport should scroll to after the scale change */\n desiredScrollLeft: number;\n desiredScrollTop: number;\n\n /** metrics at the moment the zoom was requested */\n viewport: ViewportMetrics;\n}\n\nexport interface MarqueeZoomCallback {\n onPreview?: (rect: Rect | null) => void;\n onCommit?: (rect: Rect) => void;\n onSmallDrag?: () => void;\n}\n\nexport interface RegisterMarqueeOnPageOptions {\n pageIndex: number;\n scale: number;\n callback: MarqueeZoomCallback;\n}\n\nexport interface ZoomCapability {\n /** subscribe – returns the unsubscribe function */\n onZoomChange: EventHook<ZoomChangeEvent>;\n /** subscribe – returns the unsubscribe function */\n onStateChange: EventHook<ZoomState>;\n\n /** absolute requests -------------------------------------------------- */\n requestZoom(level: ZoomLevel, center?: Point): void;\n /** relative requests -------------------------------------------------- */\n requestZoomBy(delta: number, center?: Point): void;\n\n /** absolute requests -------------------------------------------------- */\n zoomIn(): void;\n zoomOut(): void;\n\n zoomToArea(pageIndex: number, rect: Rect): void;\n\n /** zoom in on an area -------------------------------------------------- */\n enableMarqueeZoom(): void;\n disableMarqueeZoom(): void;\n toggleMarqueeZoom(): void;\n isMarqueeZoomActive(): boolean;\n\n /** register a marquee handler on a page -------------------------------- */\n registerMarqueeOnPage: (opts: RegisterMarqueeOnPageOptions) => () => void;\n\n getState(): ZoomState;\n getPresets(): ZoomPreset[];\n}\n\n/* ------------------------------------------------------------------ */\n/* config / store */\n/* ------------------------------------------------------------------ */\n\nexport interface ZoomRangeStep {\n min: number;\n max: number;\n step: number;\n}\n\nexport interface ZoomPreset {\n name: string;\n value: ZoomLevel;\n icon?: string;\n}\n\nexport interface ZoomPluginConfig extends BasePluginConfig {\n defaultZoomLevel: ZoomLevel;\n minZoom?: number;\n maxZoom?: number;\n zoomStep?: number;\n zoomRanges?: ZoomRangeStep[]; // Define different step sizes for different zoom ranges\n presets?: ZoomPreset[]; // Preset zoom options for dropdown\n}\n\nexport interface ZoomState {\n zoomLevel: ZoomLevel; // last **requested** level\n currentZoomLevel: number; // actual numeric factor\n}\n\nexport enum VerticalZoomFocus {\n Center,\n Top,\n}\n\nexport interface ZoomRequest {\n level: ZoomLevel;\n delta?: number;\n center?: Point;\n focus?: VerticalZoomFocus;\n /** Scroll so that the focal point ends up …\n * ▸ `\"keep\"` (default) at the same viewport coords\n * ▸ `\"center\"` centred in the viewport */\n align?: 'keep' | 'center';\n}\n","import { PluginManifest } from '@embedpdf/core';\n\nimport { ZoomMode, ZoomPluginConfig } from './types';\n\nexport const ZOOM_PLUGIN_ID = 'zoom';\n\nexport const manifest: PluginManifest<ZoomPluginConfig> = {\n id: ZOOM_PLUGIN_ID,\n name: 'Zoom Plugin',\n version: '1.0.0',\n provides: ['zoom'],\n requires: ['viewport', 'scroll'],\n optional: ['interaction-manager'],\n defaultConfig: {\n enabled: true,\n defaultZoomLevel: ZoomMode.Automatic,\n minZoom: 0.2,\n maxZoom: 60,\n zoomStep: 0.1,\n zoomRanges: [\n {\n min: 0.2,\n max: 0.5,\n step: 0.05,\n },\n {\n min: 0.5,\n max: 1.0,\n step: 0.1,\n },\n {\n min: 1.0,\n max: 2.0,\n step: 0.2,\n },\n {\n min: 2.0,\n max: 4.0,\n step: 0.4,\n },\n {\n min: 4.0,\n max: 10.0,\n step: 0.8,\n },\n {\n min: 10.0,\n max: 20.0,\n step: 1.6,\n },\n {\n min: 20.0,\n max: 40.0,\n step: 3.2,\n },\n {\n min: 40.0,\n max: 60.0,\n step: 6.4,\n },\n ],\n presets: [\n {\n name: 'Fit Page',\n value: ZoomMode.FitPage,\n },\n {\n name: 'Fit Width',\n value: ZoomMode.FitWidth,\n },\n {\n name: 'Automatic',\n value: ZoomMode.Automatic,\n },\n {\n name: '25%',\n value: 0.25,\n },\n {\n name: '50%',\n value: 0.5,\n },\n {\n name: '100%',\n value: 1,\n },\n {\n name: '125%',\n value: 1.25,\n },\n {\n name: '150%',\n value: 1.5,\n },\n {\n name: '200%',\n value: 2,\n },\n {\n name: '400%',\n value: 4,\n },\n {\n name: '800%',\n value: 8,\n },\n {\n name: '1600%',\n value: 16,\n },\n ],\n },\n};\n","import { Action } from '@embedpdf/core';\n\nimport { ZoomLevel } from './types';\n\n// Action Types\nexport const SET_ZOOM_LEVEL = 'SET_ZOOM_LEVEL';\nexport const SET_INITIAL_ZOOM_LEVEL = 'SET_INITIAL_ZOOM_LEVEL';\n\n// Action Interfaces\nexport interface SetZoomLevelAction extends Action {\n type: typeof SET_ZOOM_LEVEL;\n payload: {\n zoomLevel: ZoomLevel;\n currentZoomLevel: number;\n };\n}\n\nexport interface SetInitialZoomLevelAction extends Action {\n type: typeof SET_INITIAL_ZOOM_LEVEL;\n payload: {\n zoomLevel: ZoomLevel;\n };\n}\n\n// Union Type for All Actions\nexport type ZoomAction = SetZoomLevelAction | SetInitialZoomLevelAction;\n\n// Action Creators\nexport function setZoomLevel(zoomLevel: ZoomLevel, currentZoomLevel: number): SetZoomLevelAction {\n return {\n type: SET_ZOOM_LEVEL,\n payload: { zoomLevel, currentZoomLevel },\n };\n}\n\nexport function setInitialZoomLevel(zoomLevel: ZoomLevel): SetInitialZoomLevelAction {\n return {\n type: SET_INITIAL_ZOOM_LEVEL,\n payload: { zoomLevel },\n };\n}\n","import { Reducer } from '@embedpdf/core';\n\nimport { SET_INITIAL_ZOOM_LEVEL, SET_ZOOM_LEVEL, ZoomAction } from './actions';\nimport { ZoomState, ZoomMode } from './types';\n\nexport const initialState: ZoomState = {\n zoomLevel: ZoomMode.Automatic,\n currentZoomLevel: 1,\n};\n\nexport const zoomReducer: Reducer<ZoomState, ZoomAction> = (state = initialState, action) => {\n switch (action.type) {\n case SET_ZOOM_LEVEL:\n return {\n ...state,\n zoomLevel: action.payload.zoomLevel,\n currentZoomLevel: action.payload.currentZoomLevel,\n };\n case SET_INITIAL_ZOOM_LEVEL:\n return {\n ...state,\n zoomLevel: action.payload.zoomLevel,\n };\n default:\n return state;\n }\n};\n","import {\n BasePlugin,\n PluginRegistry,\n createEmitter,\n clamp,\n setScale,\n SET_PAGES,\n SET_DOCUMENT,\n getPagesWithRotatedSize,\n SET_ROTATION,\n createBehaviorEmitter,\n} from '@embedpdf/core';\nimport { ScrollPlugin, ScrollCapability } from '@embedpdf/plugin-scroll';\nimport { ViewportPlugin, ViewportCapability, ViewportMetrics } from '@embedpdf/plugin-viewport';\n\nimport { setInitialZoomLevel, setZoomLevel, ZoomAction } from './actions';\nimport {\n ZoomPluginConfig,\n ZoomState,\n ZoomMode,\n Point,\n ZoomChangeEvent,\n ZoomCapability,\n ZoomPreset,\n ZoomRangeStep,\n VerticalZoomFocus,\n ZoomRequest,\n RegisterMarqueeOnPageOptions,\n} from './types';\nimport {\n InteractionManagerCapability,\n InteractionManagerPlugin,\n} from '@embedpdf/plugin-interaction-manager';\nimport { Rect, rotateRect } from '@embedpdf/models';\nimport { createMarqueeHandler } from './handlers';\n\nexport class ZoomPlugin extends BasePlugin<\n ZoomPluginConfig,\n ZoomCapability,\n ZoomState,\n ZoomAction\n> {\n static readonly id = 'zoom' as const;\n /* ------------------------------------------------------------------ */\n /* internals */\n /* ------------------------------------------------------------------ */\n private readonly zoom$ = createEmitter<ZoomChangeEvent>();\n private readonly state$ = createBehaviorEmitter<ZoomState>();\n private readonly viewport: ViewportCapability;\n private readonly viewportPlugin: ViewportPlugin;\n private readonly scroll: ScrollCapability;\n private readonly interactionManager: InteractionManagerCapability | null;\n private readonly presets: ZoomPreset[];\n private readonly zoomRanges: ZoomRangeStep[];\n\n private readonly minZoom: number;\n private readonly maxZoom: number;\n private readonly zoomStep: number;\n\n /* ------------------------------------------------------------------ */\n constructor(id: string, registry: PluginRegistry, cfg: ZoomPluginConfig) {\n super(id, registry);\n\n this.viewportPlugin = registry.getPlugin<ViewportPlugin>('viewport')!;\n this.viewport = this.viewportPlugin.provides();\n this.scroll = registry.getPlugin<ScrollPlugin>('scroll')!.provides();\n const interactionManager = registry.getPlugin<InteractionManagerPlugin>('interaction-manager');\n this.interactionManager = interactionManager?.provides() ?? null;\n this.minZoom = cfg.minZoom ?? 0.25;\n this.maxZoom = cfg.maxZoom ?? 10;\n this.zoomStep = cfg.zoomStep ?? 0.1;\n this.presets = cfg.presets ?? [];\n this.zoomRanges = this.normalizeRanges(cfg.zoomRanges ?? []);\n this.dispatch(setInitialZoomLevel(cfg.defaultZoomLevel));\n /* keep \"automatic\" modes up to date -------------------------------- */\n this.viewport.onViewportResize(() => this.recalcAuto(VerticalZoomFocus.Top), {\n mode: 'debounce',\n wait: 150,\n });\n this.coreStore.onAction(SET_ROTATION, () => this.recalcAuto(VerticalZoomFocus.Top));\n this.coreStore.onAction(SET_PAGES, () => this.recalcAuto(VerticalZoomFocus.Top));\n this.coreStore.onAction(SET_DOCUMENT, () => this.recalcAuto(VerticalZoomFocus.Top));\n this.interactionManager?.registerMode({\n id: 'marqueeZoom',\n scope: 'page',\n exclusive: true,\n cursor: 'zoom-in',\n });\n this.resetReady();\n }\n\n /* ------------------------------------------------------------------ */\n /* capability */\n /* ------------------------------------------------------------------ */\n protected buildCapability(): ZoomCapability {\n return {\n onZoomChange: this.zoom$.on,\n onStateChange: this.state$.on,\n zoomIn: () => this.zoomIn(),\n zoomOut: () => this.zoomOut(),\n zoomToArea: (pageIndex, rect) => this.zoomToArea(pageIndex, rect),\n requestZoom: (level, c) => this.handleRequest({ level, center: c }),\n requestZoomBy: (d, c) => {\n const cur = this.state.currentZoomLevel;\n const target = this.toZoom(cur + d);\n return this.handleRequest({ level: target, center: c });\n },\n enableMarqueeZoom: () => {\n this.interactionManager?.activate('marqueeZoom');\n },\n disableMarqueeZoom: () => {\n this.interactionManager?.activateDefaultMode();\n },\n toggleMarqueeZoom: () => {\n if (this.interactionManager?.getActiveMode() === 'marqueeZoom') {\n this.interactionManager?.activateDefaultMode();\n } else {\n this.interactionManager?.activate('marqueeZoom');\n }\n },\n isMarqueeZoomActive: () => this.interactionManager?.getActiveMode() === 'marqueeZoom',\n registerMarqueeOnPage: (opts) => this.registerMarqueeOnPage(opts),\n getState: () => this.state,\n getPresets: () => this.presets,\n };\n }\n\n private zoomOut() {\n const cur = this.state.currentZoomLevel;\n return this.handleRequest({ level: cur, delta: -this.stepFor(cur) });\n }\n\n private zoomIn() {\n const cur = this.state.currentZoomLevel;\n return this.handleRequest({ level: cur, delta: this.stepFor(cur) });\n }\n\n private zoomToArea(pageIndex: number, rect: Rect) {\n this.handleZoomToArea(pageIndex, rect);\n }\n\n /* ------------------------------------------------------------------ */\n /* plugin life‑cycle */\n /* ------------------------------------------------------------------ */\n async initialize(): Promise<void> {\n /* apply the initial zoom\n /* Mark plugin as ready - zoom will be calculated when viewport has dimensions */\n this.markReady();\n }\n\n async destroy() {\n this.zoom$.clear();\n }\n\n /**\n * Sort ranges once, make sure they are sane\n */\n private normalizeRanges(ranges: ZoomRangeStep[]): ZoomRangeStep[] {\n return [...ranges]\n .filter((r) => r.step > 0 && r.max > r.min) // basic sanity\n .sort((a, b) => a.min - b.min);\n }\n\n /** pick the step that applies to a given numeric zoom */\n private stepFor(zoom: number): number {\n const r = this.zoomRanges.find((r) => zoom >= r.min && zoom < r.max);\n return r ? r.step : this.zoomStep; // fallback\n }\n\n /** clamp + round helper reused later */\n private toZoom(v: number) {\n return parseFloat(clamp(v, this.minZoom, this.maxZoom).toFixed(2));\n }\n\n /* ------------------------------------------------------------------ */\n /* main entry – handles **every** zoom request */\n /* ------------------------------------------------------------------ */\n private handleRequest({\n level,\n delta = 0,\n center,\n focus = VerticalZoomFocus.Center,\n align = 'keep',\n }: ZoomRequest) {\n const metrics = this.viewport.getMetrics();\n const oldZoom = this.state.currentZoomLevel;\n\n if (metrics.clientWidth === 0 || metrics.clientHeight === 0) {\n return;\n }\n\n /* ------------------------------------------------------------------ */\n /* step 1 – resolve the **target numeric zoom** */\n /* ------------------------------------------------------------------ */\n const base = typeof level === 'number' ? level : this.computeZoomForMode(level, metrics);\n\n if (base === false) {\n return;\n }\n const exactZoom = clamp(base + delta, this.minZoom, this.maxZoom);\n const newZoom = Math.floor(exactZoom * 1000) / 1000;\n\n /* ------------------------------------------------------------------ */\n /* step 2 – figure out the viewport point we should keep under focus */\n /* ------------------------------------------------------------------ */\n const focusPoint: Point = center ?? {\n vx: metrics.clientWidth / 2,\n vy: focus === VerticalZoomFocus.Top ? 0 : metrics.clientHeight / 2,\n };\n\n /* ------------------------------------------------------------------ */\n /* step 3 – translate that into desired scroll offsets */\n /* ------------------------------------------------------------------ */\n const { desiredScrollLeft, desiredScrollTop } = this.computeScrollForZoomChange(\n metrics,\n oldZoom,\n newZoom,\n focusPoint,\n align,\n );\n\n /* ------------------------------------------------------------------ */\n /* step 4 – dispatch + notify */\n /* ------------------------------------------------------------------ */\n\n if (!isNaN(desiredScrollLeft) && !isNaN(desiredScrollTop)) {\n this.viewportPlugin.setViewportScrollMetrics({\n scrollLeft: desiredScrollLeft,\n scrollTop: desiredScrollTop,\n });\n }\n\n this.dispatch(setZoomLevel(typeof level === 'number' ? newZoom : level, newZoom));\n this.dispatchCoreAction(setScale(newZoom));\n this.markReady();\n\n this.viewport.scrollTo({\n x: desiredScrollLeft,\n y: desiredScrollTop,\n behavior: 'instant',\n });\n\n const evt: ZoomChangeEvent = {\n oldZoom,\n newZoom,\n level,\n center: focusPoint,\n desiredScrollLeft,\n desiredScrollTop,\n viewport: metrics,\n };\n\n this.zoom$.emit(evt);\n }\n\n /* ------------------------------------------------------------------ */\n /* helpers */\n /* ------------------------------------------------------------------ */\n\n /** numeric zoom for Automatic / FitPage / FitWidth */\n private computeZoomForMode(mode: ZoomMode, vp: ViewportMetrics): number | false {\n const spreads = getPagesWithRotatedSize(this.coreState.core);\n if (!spreads.length) return false;\n\n const pgGap = this.scroll.getPageGap();\n const vpGap = this.viewport.getViewportGap();\n\n if (vp.clientWidth === 0 || vp.clientHeight === 0) {\n return false;\n }\n\n // Available space after accounting for fixed viewport gaps\n const availableWidth = vp.clientWidth - 2 * vpGap;\n const availableHeight = vp.clientHeight - 2 * vpGap;\n\n if (availableWidth <= 0 || availableHeight <= 0) {\n return false;\n }\n\n let maxContentW = 0,\n maxContentH = 0;\n\n spreads.forEach((spread) => {\n // Only include scalable content (pages + page gaps), not viewport gaps\n const contentW = spread.reduce((s, p, i) => s + p.rotatedSize.width + (i ? pgGap : 0), 0);\n const contentH = Math.max(...spread.map((p) => p.rotatedSize.height));\n maxContentW = Math.max(maxContentW, contentW);\n maxContentH = Math.max(maxContentH, contentH);\n });\n\n switch (mode) {\n case ZoomMode.FitWidth:\n return availableWidth / maxContentW;\n case ZoomMode.FitPage:\n return Math.min(availableWidth / maxContentW, availableHeight / maxContentH);\n case ZoomMode.Automatic:\n return Math.min(availableWidth / maxContentW, 1);\n /* istanbul ignore next */\n default:\n return 1;\n }\n }\n\n /** where to scroll so that *focus* stays stable after scaling */\n private computeScrollForZoomChange(\n vp: ViewportMetrics,\n oldZoom: number,\n newZoom: number,\n focus: Point,\n align: 'keep' | 'center' = 'keep',\n ) {\n /* unscaled content size ------------------------------------------- */\n const layout = this.scroll.getLayout();\n const vpGap = this.viewport.getViewportGap();\n\n const contentW = layout.totalContentSize.width;\n const contentH = layout.totalContentSize.height;\n\n // Available space for content (excluding fixed viewport gaps)\n const availableWidth = vp.clientWidth - 2 * vpGap;\n const availableHeight = vp.clientHeight - 2 * vpGap;\n\n /* helper: offset if content is narrower than available space ------- */\n const off = (availableSpace: number, cw: number, zoom: number) =>\n cw * zoom < availableSpace ? (availableSpace - cw * zoom) / 2 : 0;\n\n const offXold = off(availableWidth, contentW, oldZoom);\n const offYold = off(availableHeight, contentH, oldZoom);\n\n const offXnew = off(availableWidth, contentW, newZoom);\n const offYnew = off(availableHeight, contentH, newZoom);\n\n /* content coords of the focal point -------------------------------- */\n // Adjust focus point to account for vpGap and centering offset\n const cx = (vp.scrollLeft + focus.vx - vpGap - offXold) / oldZoom;\n const cy = (vp.scrollTop + focus.vy - vpGap - offYold) / oldZoom;\n\n /* new scroll so that (cx,cy) appears under focus again ------------- */\n const baseLeft = cx * newZoom + vpGap + offXnew;\n const baseTop = cy * newZoom + vpGap + offYnew;\n\n const desiredScrollLeft =\n align === 'center' ? baseLeft - vp.clientWidth / 2 : baseLeft - focus.vx;\n const desiredScrollTop =\n align === 'center' ? baseTop - vp.clientHeight / 2 : baseTop - focus.vy;\n\n return {\n desiredScrollLeft: Math.max(0, desiredScrollLeft),\n desiredScrollTop: Math.max(0, desiredScrollTop),\n };\n }\n\n private handleZoomToArea(pageIndex: number, rect: Rect) {\n /* -------------------------------------------------- */\n /* 0 – rotation that applies to this page */\n /* -------------------------------------------------- */\n const rotation = this.coreState.core.rotation;\n\n /* -------------------------------------------------- */\n /* viewport + layout basics */\n /* -------------------------------------------------- */\n const vp = this.viewport.getMetrics();\n const vpGap = this.viewport.getViewportGap();\n const oldZ = this.state.currentZoomLevel;\n\n const availableW = vp.clientWidth - 2 * vpGap;\n const availableH = vp.clientHeight - 2 * vpGap;\n\n const layout = this.scroll.getLayout();\n\n /* which virtual item holds the page? */\n const vItem = layout.virtualItems.find((it) =>\n it.pageLayouts.some((p) => p.pageIndex === pageIndex),\n );\n if (!vItem) return;\n\n /* the page layout inside that virtual item */\n const pageRel = vItem.pageLayouts.find((p) => p.pageIndex === pageIndex)!;\n\n /* -------------------------------------------------- */\n /* 1 – rect → rotated‑page space */\n /* -------------------------------------------------- */\n const rotatedRect = rotateRect(\n {\n width: pageRel.width,\n height: pageRel.height,\n },\n rect,\n rotation,\n );\n\n /* -------------------------------------------------- */\n /* 2 – numeric zoom so the rect fits */\n /* -------------------------------------------------- */\n const targetZoom = this.toZoom(\n Math.min(availableW / rotatedRect.size.width, availableH / rotatedRect.size.height),\n );\n\n /* -------------------------------------------------- */\n /* 3 – centre of that rect in *content* coordinates */\n /* -------------------------------------------------- */\n const pageAbsX = vItem.x + pageRel.x;\n const pageAbsY = vItem.y + pageRel.y;\n\n const cxContent = pageAbsX + rotatedRect.origin.x + rotatedRect.size.width / 2;\n const cyContent = pageAbsY + rotatedRect.origin.y + rotatedRect.size.height / 2;\n\n /* -------------------------------------------------- */\n /* 4 – centre in *viewport* coords before zoom */\n /* -------------------------------------------------- */\n const off = (avail: number, cw: number, z: number) =>\n cw * z < avail ? (avail - cw * z) / 2 : 0;\n\n const offXold = off(availableW, layout.totalContentSize.width, oldZ);\n const offYold = off(availableH, layout.totalContentSize.height, oldZ);\n\n const centerVX = vpGap + offXold + cxContent * oldZ - vp.scrollLeft;\n const centerVY = vpGap + offYold + cyContent * oldZ - vp.scrollTop;\n\n /* -------------------------------------------------- */\n /* 5 – hand off to the generic zoom handler */\n /* -------------------------------------------------- */\n this.handleRequest({\n level: targetZoom,\n center: { vx: centerVX, vy: centerVY },\n align: 'center',\n });\n }\n\n /** recalculates Automatic / Fit* when viewport or pages change */\n private recalcAuto(focus?: VerticalZoomFocus) {\n const s = this.state;\n if (\n s.zoomLevel === ZoomMode.Automatic ||\n s.zoomLevel === ZoomMode.FitPage ||\n s.zoomLevel === ZoomMode.FitWidth\n )\n this.handleRequest({ level: s.zoomLevel, focus });\n }\n\n override onStoreUpdated(_prevState: ZoomState, newState: ZoomState): void {\n this.state$.emit(newState);\n }\n\n public registerMarqueeOnPage(opts: RegisterMarqueeOnPageOptions) {\n if (!this.interactionManager) {\n this.logger.warn(\n 'ZoomPlugin',\n 'MissingDependency',\n 'Interaction manager plugin not loaded, marquee zoom disabled',\n );\n return () => {};\n }\n\n const document = this.coreState.core.document;\n if (!document) {\n this.logger.warn('ZoomPlugin', 'DocumentNotFound', 'Document not found');\n return () => {};\n }\n\n const page = document.pages[opts.pageIndex];\n if (!page) {\n this.logger.warn('ZoomPlugin', 'PageNotFound', `Page ${opts.pageIndex} not found`);\n return () => {};\n }\n\n const handlers = createMarqueeHandler({\n pageSize: page.size,\n scale: opts.scale,\n onPreview: opts.callback.onPreview,\n onCommit: (rect) => {\n // Large drag → zoom to the selected area\n this.zoomToArea(opts.pageIndex, rect);\n opts.callback.onCommit?.(rect);\n },\n onSmallDrag: () => {\n // Small drag → simple zoom in\n this.zoomIn();\n opts.callback.onSmallDrag?.();\n },\n });\n\n const off = this.interactionManager.registerHandlers({\n modeId: 'marqueeZoom',\n handlers,\n pageIndex: opts.pageIndex,\n });\n\n return off;\n }\n}\n","import { Position, Rect, Size } from '@embedpdf/models';\nimport { clamp } from '@embedpdf/core';\nimport {\n EmbedPdfPointerEvent,\n PointerEventHandlersWithLifecycle,\n} from '@embedpdf/plugin-interaction-manager';\n\nexport function createMarqueeHandler(opts: {\n pageSize: Size;\n scale: number;\n minDragPx?: number;\n onPreview?: (rect: Rect | null) => void;\n onCommit?: (rect: Rect) => void;\n onSmallDrag?: () => void;\n}): PointerEventHandlersWithLifecycle<EmbedPdfPointerEvent> {\n const { pageSize, scale, minDragPx = 5, onPreview, onCommit, onSmallDrag } = opts;\n\n let start: Position | null = null;\n let last: Rect | null = null;\n\n return {\n onPointerDown: (pos, evt) => {\n start = pos;\n last = { origin: { x: pos.x, y: pos.y }, size: { width: 0, height: 0 } };\n onPreview?.(last);\n evt.setPointerCapture?.();\n },\n onPointerMove: (pos) => {\n if (!start) return;\n const x = clamp(pos.x, 0, pageSize.width);\n const y = clamp(pos.y, 0, pageSize.height);\n last = {\n origin: { x: Math.min(start.x, x), y: Math.min(start.y, y) },\n size: { width: Math.abs(x - start.x), height: Math.abs(y - start.y) },\n };\n onPreview?.(last);\n },\n onPointerUp: (_pos, evt) => {\n if (last) {\n const dragPx = Math.max(last.size.width, last.size.height) * scale;\n if (dragPx > minDragPx) {\n onCommit?.(last); // Large drag → zoom to area\n } else {\n onSmallDrag?.(); // Small drag → zoom in\n }\n }\n start = null;\n last = null;\n onPreview?.(null);\n evt.releasePointerCapture?.();\n },\n onPointerCancel: (_pos, evt) => {\n start = null;\n last = null;\n onPreview?.(null);\n evt.releasePointerCapture?.();\n },\n };\n}\n","import { PluginPackage } from '@embedpdf/core';\n\nimport { ZoomAction } from './actions';\nimport { manifest, ZOOM_PLUGIN_ID } from './manifest';\nimport { zoomReducer, initialState } from './reducer';\nimport { ZoomPluginConfig, ZoomState } from './types';\nimport { ZoomPlugin } from './zoom-plugin';\n\nexport const ZoomPluginPackage: PluginPackage<ZoomPlugin, ZoomPluginConfig, ZoomState, ZoomAction> =\n {\n manifest,\n create: (registry, config) => new ZoomPlugin(ZOOM_PLUGIN_ID, registry, config),\n reducer: zoomReducer,\n initialState,\n };\n\nexport * from './zoom-plugin';\nexport * from './types';\nexport * from './manifest';\nexport { initialState };\n"],"names":["ZoomMode","VerticalZoomFocus","VerticalZoomFocus2","ZOOM_PLUGIN_ID","manifest","id","name","version","provides","requires","optional","defaultConfig","enabled","defaultZoomLevel","Automatic","minZoom","maxZoom","zoomStep","zoomRanges","min","max","step","presets","value","FitPage","FitWidth","SET_ZOOM_LEVEL","SET_INITIAL_ZOOM_LEVEL","initialState","zoomLevel","currentZoomLevel","_ZoomPlugin","BasePlugin","constructor","registry","cfg","super","this","zoom$","createEmitter","state$","createBehaviorEmitter","viewportPlugin","getPlugin","viewport","scroll","interactionManager","normalizeRanges","dispatch","type","payload","onViewportResize","recalcAuto","Top","mode","wait","coreStore","onAction","SET_ROTATION","SET_PAGES","SET_DOCUMENT","_a","registerMode","scope","exclusive","cursor","resetReady","buildCapability","onZoomChange","on","onStateChange","zoomIn","zoomOut","zoomToArea","pageIndex","rect","requestZoom","level","c","handleRequest","center","requestZoomBy","d","cur","state","target","toZoom","enableMarqueeZoom","activate","disableMarqueeZoom","activateDefaultMode","toggleMarqueeZoom","getActiveMode","_b","_c","isMarqueeZoomActive","registerMarqueeOnPage","opts","getState","getPresets","delta","stepFor","handleZoomToArea","initialize","markReady","destroy","clear","ranges","filter","r","sort","a","b","zoom","find","v","parseFloat","clamp","toFixed","focus","Center","align","metrics","getMetrics","oldZoom","clientWidth","clientHeight","base","computeZoomForMode","exactZoom","newZoom","Math","floor","focusPoint","vx","vy","desiredScrollLeft","desiredScrollTop","computeScrollForZoomChange","isNaN","setViewportScrollMetrics","scrollLeft","scrollTop","dispatchCoreAction","setScale","scrollTo","x","y","behavior","evt","emit","vp","spreads","getPagesWithRotatedSize","coreState","core","length","pgGap","getPageGap","vpGap","getViewportGap","availableWidth","availableHeight","maxContentW","maxContentH","forEach","spread","contentW","reduce","s","p","i","rotatedSize","width","contentH","map","height","layout","getLayout","totalContentSize","off","availableSpace","cw","offXold","offYold","offXnew","offYnew","baseLeft","baseTop","rotation","oldZ","availableW","availableH","vItem","virtualItems","it","pageLayouts","some","pageRel","rotatedRect","rotateRect","targetZoom","size","pageAbsX","pageAbsY","cxContent","origin","cyContent","avail","z","centerVX","centerVY","onStoreUpdated","_prevState","newState","logger","warn","document","page","pages","handlers","pageSize","scale","minDragPx","onPreview","onCommit","onSmallDrag","start","last","onPointerDown","pos","setPointerCapture","call","onPointerMove","abs","onPointerUp","_pos","releasePointerCapture","onPointerCancel","createMarqueeHandler","callback","registerHandlers","modeId","ZoomPlugin","ZoomPluginPackage","create","config","reducer","action"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/lib/types.ts","../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/zoom-plugin.ts","../src/lib/handlers/marquee-zoom.handler.ts","../src/lib/index.ts"],"sourcesContent":["import { BasePluginConfig, EventHook } from '@embedpdf/core';\nimport { Rect } from '@embedpdf/models';\nimport { ViewportMetrics } from '@embedpdf/plugin-viewport';\n\n/* ------------------------------------------------------------------ */\n/* public */\n/* ------------------------------------------------------------------ */\n\nexport enum ZoomMode {\n Automatic = 'automatic',\n FitPage = 'fit-page',\n FitWidth = 'fit-width',\n}\n\nexport type ZoomLevel = ZoomMode | number;\n\nexport interface Point {\n vx: number;\n vy: number;\n}\n\nexport interface ZoomChangeEvent {\n documentId: string;\n /** old and new *actual* scale factors */\n oldZoom: number;\n newZoom: number;\n /** level used to obtain the newZoom (number | mode) */\n level: ZoomLevel;\n /** viewport point kept under the finger / mouse‑wheel focus */\n center: Point;\n /** where the viewport should scroll to after the scale change */\n desiredScrollLeft: number;\n desiredScrollTop: number;\n /** metrics at the moment the zoom was requested */\n viewport: ViewportMetrics;\n}\n\nexport interface StateChangeEvent {\n documentId: string;\n state: ZoomDocumentState;\n}\n\nexport interface MarqueeZoomCallback {\n onPreview?: (rect: Rect | null) => void;\n onCommit?: (rect: Rect) => void;\n onSmallDrag?: () => void;\n}\n\nexport interface RegisterMarqueeOnPageOptions {\n documentId: string;\n pageIndex: number;\n scale: number;\n callback: MarqueeZoomCallback;\n}\n\n// Per-document zoom state\nexport interface ZoomDocumentState {\n zoomLevel: ZoomLevel; // last **requested** level\n currentZoomLevel: number; // actual numeric factor\n isMarqueeZoomActive: boolean; // whether marquee zoom mode is active\n}\n\n// Scoped zoom capability\nexport interface ZoomScope {\n requestZoom(level: ZoomLevel, center?: Point): void;\n requestZoomBy(delta: number, center?: Point): void;\n zoomIn(): void;\n zoomOut(): void;\n zoomToArea(pageIndex: number, rect: Rect): void;\n enableMarqueeZoom(): void;\n disableMarqueeZoom(): void;\n toggleMarqueeZoom(): void;\n isMarqueeZoomActive(): boolean;\n getState(): ZoomDocumentState;\n onZoomChange: EventHook<ZoomChangeEvent>;\n onStateChange: EventHook<ZoomDocumentState>;\n}\n\nexport interface ZoomCapability {\n // Active document operations\n requestZoom(level: ZoomLevel, center?: Point): void;\n requestZoomBy(delta: number, center?: Point): void;\n zoomIn(): void;\n zoomOut(): void;\n zoomToArea(pageIndex: number, rect: Rect): void;\n enableMarqueeZoom(): void;\n disableMarqueeZoom(): void;\n toggleMarqueeZoom(): void;\n isMarqueeZoomActive(): boolean;\n getState(): ZoomDocumentState;\n\n // Document-scoped operations\n forDocument(documentId: string): ZoomScope;\n\n // Global\n registerMarqueeOnPage: (opts: RegisterMarqueeOnPageOptions) => () => void;\n getPresets(): ZoomPreset[];\n\n // Events (include documentId)\n onZoomChange: EventHook<ZoomChangeEvent>;\n onStateChange: EventHook<StateChangeEvent>;\n}\n\n/* ------------------------------------------------------------------ */\n/* config / store */\n/* ------------------------------------------------------------------ */\n\nexport interface ZoomRangeStep {\n min: number;\n max: number;\n step: number;\n}\n\nexport interface ZoomPreset {\n name: string;\n value: ZoomLevel;\n icon?: string;\n}\n\nexport interface ZoomPluginConfig extends BasePluginConfig {\n defaultZoomLevel: ZoomLevel;\n minZoom?: number;\n maxZoom?: number;\n zoomStep?: number;\n zoomRanges?: ZoomRangeStep[];\n presets?: ZoomPreset[];\n}\n\nexport interface ZoomState {\n // Per-document zoom state\n documents: Record<string, ZoomDocumentState>;\n activeDocumentId: string | null;\n}\n\nexport enum VerticalZoomFocus {\n Center,\n Top,\n}\n\nexport interface ZoomRequest {\n level: ZoomLevel;\n delta?: number;\n center?: Point;\n focus?: VerticalZoomFocus;\n align?: 'keep' | 'center';\n}\n","import { PluginManifest } from '@embedpdf/core';\n\nimport { ZoomMode, ZoomPluginConfig } from './types';\n\nexport const ZOOM_PLUGIN_ID = 'zoom';\n\nexport const manifest: PluginManifest<ZoomPluginConfig> = {\n id: ZOOM_PLUGIN_ID,\n name: 'Zoom Plugin',\n version: '1.0.0',\n provides: ['zoom'],\n requires: ['viewport', 'scroll'],\n optional: ['interaction-manager', 'spread'],\n defaultConfig: {\n enabled: true,\n defaultZoomLevel: ZoomMode.Automatic,\n minZoom: 0.2,\n maxZoom: 60,\n zoomStep: 0.1,\n zoomRanges: [\n {\n min: 0.2,\n max: 0.5,\n step: 0.05,\n },\n {\n min: 0.5,\n max: 1.0,\n step: 0.1,\n },\n {\n min: 1.0,\n max: 2.0,\n step: 0.2,\n },\n {\n min: 2.0,\n max: 4.0,\n step: 0.4,\n },\n {\n min: 4.0,\n max: 10.0,\n step: 0.8,\n },\n {\n min: 10.0,\n max: 20.0,\n step: 1.6,\n },\n {\n min: 20.0,\n max: 40.0,\n step: 3.2,\n },\n {\n min: 40.0,\n max: 60.0,\n step: 6.4,\n },\n ],\n presets: [\n {\n name: 'Fit Page',\n value: ZoomMode.FitPage,\n },\n {\n name: 'Fit Width',\n value: ZoomMode.FitWidth,\n },\n {\n name: 'Automatic',\n value: ZoomMode.Automatic,\n },\n {\n name: '25%',\n value: 0.25,\n },\n {\n name: '50%',\n value: 0.5,\n },\n {\n name: '100%',\n value: 1,\n },\n {\n name: '125%',\n value: 1.25,\n },\n {\n name: '150%',\n value: 1.5,\n },\n {\n name: '200%',\n value: 2,\n },\n {\n name: '400%',\n value: 4,\n },\n {\n name: '800%',\n value: 8,\n },\n {\n name: '1600%',\n value: 16,\n },\n ],\n },\n};\n","import { Action } from '@embedpdf/core';\nimport { ZoomLevel, ZoomDocumentState } from './types';\n\n// Document lifecycle\nexport const INIT_ZOOM_STATE = 'ZOOM/INIT_STATE';\nexport const CLEANUP_ZOOM_STATE = 'ZOOM/CLEANUP_STATE';\nexport const SET_ACTIVE_DOCUMENT = 'ZOOM/SET_ACTIVE_DOCUMENT';\n\n// Per-document actions\nexport const SET_ZOOM_LEVEL = 'ZOOM/SET_ZOOM_LEVEL';\nexport const SET_MARQUEE_ZOOM_ACTIVE = 'ZOOM/SET_MARQUEE_ZOOM_ACTIVE';\n\n// Document lifecycle actions\nexport interface InitZoomStateAction extends Action {\n type: typeof INIT_ZOOM_STATE;\n payload: {\n documentId: string;\n state: ZoomDocumentState;\n };\n}\n\nexport interface CleanupZoomStateAction extends Action {\n type: typeof CLEANUP_ZOOM_STATE;\n payload: string; // documentId\n}\n\nexport interface SetActiveDocumentAction extends Action {\n type: typeof SET_ACTIVE_DOCUMENT;\n payload: string | null; // documentId\n}\n\nexport interface SetZoomLevelAction extends Action {\n type: typeof SET_ZOOM_LEVEL;\n payload: {\n documentId: string;\n zoomLevel: ZoomLevel;\n currentZoomLevel: number;\n };\n}\n\nexport interface SetMarqueeZoomActiveAction extends Action {\n type: typeof SET_MARQUEE_ZOOM_ACTIVE;\n payload: {\n documentId: string;\n isActive: boolean;\n };\n}\n\nexport type ZoomAction =\n | InitZoomStateAction\n | CleanupZoomStateAction\n | SetActiveDocumentAction\n | SetZoomLevelAction\n | SetMarqueeZoomActiveAction;\n\n// Action Creators\nexport function initZoomState(documentId: string, state: ZoomDocumentState): InitZoomStateAction {\n return { type: INIT_ZOOM_STATE, payload: { documentId, state } };\n}\n\nexport function cleanupZoomState(documentId: string): CleanupZoomStateAction {\n return { type: CLEANUP_ZOOM_STATE, payload: documentId };\n}\n\nexport function setActiveDocument(documentId: string | null): SetActiveDocumentAction {\n return { type: SET_ACTIVE_DOCUMENT, payload: documentId };\n}\n\nexport function setZoomLevel(\n documentId: string,\n zoomLevel: ZoomLevel,\n currentZoomLevel: number,\n): SetZoomLevelAction {\n return { type: SET_ZOOM_LEVEL, payload: { documentId, zoomLevel, currentZoomLevel } };\n}\n\nexport function setMarqueeZoomActive(\n documentId: string,\n isActive: boolean,\n): SetMarqueeZoomActiveAction {\n return { type: SET_MARQUEE_ZOOM_ACTIVE, payload: { documentId, isActive } };\n}\n","import { Reducer } from '@embedpdf/core';\nimport {\n ZoomAction,\n INIT_ZOOM_STATE,\n CLEANUP_ZOOM_STATE,\n SET_ACTIVE_DOCUMENT,\n SET_ZOOM_LEVEL,\n SET_MARQUEE_ZOOM_ACTIVE,\n} from './actions';\nimport { ZoomState, ZoomDocumentState, ZoomMode } from './types';\n\nexport const initialDocumentState: ZoomDocumentState = {\n zoomLevel: ZoomMode.Automatic,\n currentZoomLevel: 1,\n isMarqueeZoomActive: false,\n};\n\nexport const initialState: ZoomState = {\n documents: {},\n activeDocumentId: null,\n};\n\nexport const zoomReducer: Reducer<ZoomState, ZoomAction> = (state = initialState, action) => {\n switch (action.type) {\n case INIT_ZOOM_STATE: {\n const { documentId, state: docState } = action.payload;\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: docState,\n },\n // Set as active if no active document\n activeDocumentId: state.activeDocumentId ?? documentId,\n };\n }\n\n case CLEANUP_ZOOM_STATE: {\n const documentId = action.payload;\n const { [documentId]: removed, ...remainingDocs } = state.documents;\n return {\n ...state,\n documents: remainingDocs,\n activeDocumentId: state.activeDocumentId === documentId ? null : state.activeDocumentId,\n };\n }\n\n case SET_ACTIVE_DOCUMENT: {\n return {\n ...state,\n activeDocumentId: action.payload,\n };\n }\n\n case SET_ZOOM_LEVEL: {\n const { documentId, zoomLevel, currentZoomLevel } = action.payload;\n const docState = state.documents[documentId];\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n zoomLevel,\n currentZoomLevel,\n },\n },\n };\n }\n\n case SET_MARQUEE_ZOOM_ACTIVE: {\n const { documentId, isActive } = action.payload;\n const docState = state.documents[documentId];\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n isMarqueeZoomActive: isActive,\n },\n },\n };\n }\n\n default:\n return state;\n }\n};\n","import {\n BasePlugin,\n PluginRegistry,\n createEmitter,\n clamp,\n setScale,\n createBehaviorEmitter,\n Listener,\n} from '@embedpdf/core';\nimport { ScrollPlugin, ScrollCapability } from '@embedpdf/plugin-scroll';\nimport { ViewportPlugin, ViewportCapability, ViewportMetrics } from '@embedpdf/plugin-viewport';\n\nimport {\n initZoomState,\n cleanupZoomState,\n setZoomLevel,\n ZoomAction,\n setMarqueeZoomActive,\n} from './actions';\nimport {\n ZoomPluginConfig,\n ZoomState,\n ZoomMode,\n Point,\n ZoomChangeEvent,\n ZoomCapability,\n ZoomPreset,\n ZoomRangeStep,\n VerticalZoomFocus,\n ZoomRequest,\n RegisterMarqueeOnPageOptions,\n ZoomScope,\n StateChangeEvent,\n ZoomDocumentState,\n} from './types';\nimport {\n InteractionManagerCapability,\n InteractionManagerPlugin,\n} from '@embedpdf/plugin-interaction-manager';\nimport { SpreadCapability, SpreadPlugin } from '@embedpdf/plugin-spread';\nimport { Rect, rotateRect } from '@embedpdf/models';\nimport { createMarqueeHandler } from './handlers';\nimport { initialDocumentState } from './reducer';\n\nexport class ZoomPlugin extends BasePlugin<\n ZoomPluginConfig,\n ZoomCapability,\n ZoomState,\n ZoomAction\n> {\n static readonly id = 'zoom' as const;\n\n private readonly zoom$ = createEmitter<ZoomChangeEvent>();\n private readonly state$ = createBehaviorEmitter<StateChangeEvent>();\n private readonly viewport: ViewportCapability;\n private readonly viewportPlugin: ViewportPlugin;\n private readonly scroll: ScrollCapability;\n private readonly interactionManager: InteractionManagerCapability | null;\n private readonly spread: SpreadCapability | null;\n private readonly presets: ZoomPreset[];\n private readonly zoomRanges: ZoomRangeStep[];\n private readonly defaultZoomLevel: ZoomMode | number;\n\n private readonly minZoom: number;\n private readonly maxZoom: number;\n private readonly zoomStep: number;\n\n constructor(id: string, registry: PluginRegistry, cfg: ZoomPluginConfig) {\n super(id, registry);\n\n this.viewportPlugin = registry.getPlugin<ViewportPlugin>('viewport')!;\n this.viewport = this.viewportPlugin.provides();\n this.scroll = registry.getPlugin<ScrollPlugin>('scroll')!.provides();\n const interactionManager = registry.getPlugin<InteractionManagerPlugin>('interaction-manager');\n this.interactionManager = interactionManager?.provides() ?? null;\n const spread = registry.getPlugin<SpreadPlugin>('spread');\n this.spread = spread?.provides() ?? null;\n\n this.minZoom = cfg.minZoom ?? 0.25;\n this.maxZoom = cfg.maxZoom ?? 10;\n this.zoomStep = cfg.zoomStep ?? 0.1;\n this.defaultZoomLevel = cfg.defaultZoomLevel;\n this.presets = cfg.presets ?? [];\n this.zoomRanges = this.normalizeRanges(cfg.zoomRanges ?? []);\n\n // Keep automatic modes up to date per document\n this.viewport.onViewportResize(\n (event) => this.recalcAuto(event.documentId, VerticalZoomFocus.Top),\n {\n mode: 'debounce',\n wait: 150,\n keyExtractor: (event) => event.documentId,\n },\n );\n\n // Subscribe to spread changes\n this.spread?.onSpreadChange((event) => {\n this.recalcAuto(event.documentId, VerticalZoomFocus.Top);\n });\n\n // Register marquee zoom mode\n this.interactionManager?.registerMode({\n id: 'marqueeZoom',\n scope: 'page',\n exclusive: true,\n cursor: 'zoom-in',\n });\n\n this.interactionManager?.onModeChange((state) => {\n // Track marquee zoom state changes for this document\n const isMarqueeActive = state.activeMode === 'marqueeZoom';\n const docState = this.getDocumentState(state.documentId);\n\n // Only dispatch if state actually changed\n if (docState && docState.isMarqueeZoomActive !== isMarqueeActive) {\n this.dispatch(setMarqueeZoomActive(state.documentId, isMarqueeActive));\n }\n });\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Lifecycle Hooks (from BasePlugin)\n // ─────────────────────────────────────────────────────────\n\n protected override onDocumentLoadingStarted(documentId: string): void {\n this.viewport.gate('zoom', documentId);\n // Initialize zoom state for this document\n const docState: ZoomDocumentState = {\n ...initialDocumentState,\n zoomLevel: this.defaultZoomLevel,\n };\n\n this.dispatch(initZoomState(documentId, docState));\n\n this.logger.debug(\n 'ZoomPlugin',\n 'DocumentOpened',\n `Initialized zoom state for document: ${documentId}`,\n );\n }\n\n protected override onDocumentLoaded(documentId: string): void {\n // Apply initial zoom after document is fully loaded\n this.recalcAuto(documentId, VerticalZoomFocus.Top);\n }\n\n protected override onDocumentClosed(documentId: string): void {\n this.dispatch(cleanupZoomState(documentId));\n\n this.logger.debug(\n 'ZoomPlugin',\n 'DocumentClosed',\n `Cleaned up zoom state for document: ${documentId}`,\n );\n }\n\n protected override onRotationChanged(documentId: string): void {\n // Recalculate auto modes when rotation changes\n this.recalcAuto(documentId, VerticalZoomFocus.Top);\n }\n\n /*\n protected override onPagesChanged(documentId: string): void {\n // Recalculate auto modes when pages change\n this.recalcAuto(documentId, VerticalZoomFocus.Top);\n }*/\n\n // ─────────────────────────────────────────────────────────\n // Capability\n // ─────────────────────────────────────────────────────────\n\n protected buildCapability(): ZoomCapability {\n return {\n // Active document operations\n requestZoom: (level, c) => this.requestZoom(level, c),\n requestZoomBy: (d, c) => this.requestZoomBy(d, c),\n zoomIn: () => this.zoomIn(),\n zoomOut: () => this.zoomOut(),\n zoomToArea: (pageIndex, rect) => this.zoomToArea(pageIndex, rect),\n enableMarqueeZoom: () => this.enableMarqueeZoom(),\n disableMarqueeZoom: () => this.disableMarqueeZoom(),\n toggleMarqueeZoom: () => this.toggleMarqueeZoom(),\n isMarqueeZoomActive: () => this.isMarqueeZoomActive(),\n getState: () => this.getDocumentStateOrThrow(),\n\n // Document-scoped operations\n forDocument: (documentId: string) => this.createZoomScope(documentId),\n\n // Global\n registerMarqueeOnPage: (opts) => this.registerMarqueeOnPage(opts),\n getPresets: () => this.presets,\n\n // Events\n onZoomChange: this.zoom$.on,\n onStateChange: this.state$.on,\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Scoping\n // ─────────────────────────────────────────────────────────\n\n private createZoomScope(documentId: string): ZoomScope {\n return {\n requestZoom: (level, c) => this.requestZoom(level, c, documentId),\n requestZoomBy: (d, c) => this.requestZoomBy(d, c, documentId),\n zoomIn: () => this.zoomIn(documentId),\n zoomOut: () => this.zoomOut(documentId),\n zoomToArea: (pageIndex, rect) => this.zoomToArea(pageIndex, rect, documentId),\n enableMarqueeZoom: () => this.enableMarqueeZoom(documentId),\n disableMarqueeZoom: () => this.disableMarqueeZoom(documentId),\n toggleMarqueeZoom: () => this.toggleMarqueeZoom(documentId),\n isMarqueeZoomActive: () => this.isMarqueeZoomActive(documentId),\n getState: () => this.getDocumentStateOrThrow(documentId),\n onZoomChange: (listener: Listener<ZoomChangeEvent>) =>\n this.zoom$.on((event) => {\n if (event.documentId === documentId) listener(event);\n }),\n onStateChange: (listener: Listener<ZoomDocumentState>) =>\n this.state$.on((event) => {\n if (event.documentId === documentId) listener(event.state);\n }),\n };\n }\n\n // ─────────────────────────────────────────────────────────\n // State Helpers\n // ─────────────────────────────────────────────────────────\n\n private getDocumentState(documentId?: string): ZoomDocumentState | null {\n const id = documentId ?? this.getActiveDocumentId();\n return this.state.documents[id] ?? null;\n }\n\n private getDocumentStateOrThrow(documentId?: string): ZoomDocumentState {\n const state = this.getDocumentState(documentId);\n if (!state) {\n throw new Error(`Zoom state not found for document: ${documentId ?? 'active'}`);\n }\n return state;\n }\n\n // ─────────────────────────────────────────────────────────\n // Core Operations\n // ─────────────────────────────────────────────────────────\n\n private requestZoom(level: ZoomMode | number, center?: Point, documentId?: string): void {\n this.handleRequest({ level, center }, documentId);\n }\n\n private requestZoomBy(delta: number, center?: Point, documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n const docState = this.getDocumentStateOrThrow(id);\n const cur = docState.currentZoomLevel;\n const target = this.toZoom(cur + delta);\n this.handleRequest({ level: target, center }, id);\n }\n\n private zoomIn(documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n const docState = this.getDocumentStateOrThrow(id);\n const cur = docState.currentZoomLevel;\n this.handleRequest({ level: cur, delta: this.stepFor(cur) }, id);\n }\n\n private zoomOut(documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n const docState = this.getDocumentStateOrThrow(id);\n const cur = docState.currentZoomLevel;\n this.handleRequest({ level: cur, delta: -this.stepFor(cur) }, id);\n }\n\n private zoomToArea(pageIndex: number, rect: Rect, documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n this.handleZoomToArea(id, pageIndex, rect);\n }\n\n private enableMarqueeZoom(documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n this.interactionManager?.forDocument(id).activate('marqueeZoom');\n }\n\n private disableMarqueeZoom(documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n this.interactionManager?.forDocument(id).activateDefaultMode();\n }\n\n private toggleMarqueeZoom(documentId?: string): void {\n const id = documentId ?? this.getActiveDocumentId();\n const scope = this.interactionManager?.forDocument(id);\n if (scope?.getActiveMode() === 'marqueeZoom') {\n scope.activateDefaultMode();\n } else {\n scope?.activate('marqueeZoom');\n }\n }\n\n private isMarqueeZoomActive(documentId?: string): boolean {\n const id = documentId ?? this.getActiveDocumentId();\n return this.interactionManager?.forDocument(id).getActiveMode() === 'marqueeZoom';\n }\n\n // ─────────────────────────────────────────────────────────\n // Main Zoom Logic\n // ─────────────────────────────────────────────────────────\n\n private handleRequest(\n { level, delta = 0, center, focus = VerticalZoomFocus.Center, align = 'keep' }: ZoomRequest,\n documentId?: string,\n ) {\n const id = documentId ?? this.getActiveDocumentId();\n const docState = this.getDocumentStateOrThrow(id);\n const coreDoc = this.coreState.core.documents[id];\n if (!coreDoc) return;\n\n const viewport = this.viewport.forDocument(id);\n const metrics = viewport.getMetrics();\n const oldZoom = docState.currentZoomLevel;\n\n if (metrics.clientWidth === 0 || metrics.clientHeight === 0) {\n return;\n }\n\n // Step 1: Resolve target numeric zoom\n const base = typeof level === 'number' ? level : this.computeZoomForMode(id, level, metrics);\n\n if (base === false) return;\n\n const exactZoom = clamp(base + delta, this.minZoom, this.maxZoom);\n const newZoom = Math.floor(exactZoom * 1000) / 1000;\n\n // Step 2: Figure out viewport point to keep under focus\n const focusPoint: Point = center ?? {\n vx: metrics.clientWidth / 2,\n vy: focus === VerticalZoomFocus.Top ? 0 : metrics.clientHeight / 2,\n };\n\n // Step 3: Compute desired scroll offsets\n const { desiredScrollLeft, desiredScrollTop } = this.computeScrollForZoomChange(\n id,\n metrics,\n oldZoom,\n newZoom,\n focusPoint,\n align,\n );\n\n // Step 4: Dispatch and notify\n if (!isNaN(desiredScrollLeft) && !isNaN(desiredScrollTop)) {\n this.viewportPlugin.setViewportScrollMetrics(id, {\n scrollLeft: desiredScrollLeft,\n scrollTop: desiredScrollTop,\n });\n }\n\n this.dispatch(setZoomLevel(id, typeof level === 'number' ? newZoom : level, newZoom));\n this.dispatchCoreAction(setScale(newZoom, id));\n if (this.viewport.isGated(id)) {\n this.viewport.releaseGate('zoom', id);\n }\n\n viewport.scrollTo({\n x: desiredScrollLeft,\n y: desiredScrollTop,\n behavior: 'instant',\n });\n\n const evt: ZoomChangeEvent = {\n documentId: id,\n oldZoom,\n newZoom,\n level,\n center: focusPoint,\n desiredScrollLeft,\n desiredScrollTop,\n viewport: metrics,\n };\n\n this.zoom$.emit(evt);\n }\n\n private computeZoomForMode(\n documentId: string,\n mode: ZoomMode,\n vp: ViewportMetrics,\n ): number | false {\n const coreDoc = this.coreState.core.documents[documentId];\n if (!coreDoc) return false;\n\n const scrollScope = this.scroll.forDocument(documentId);\n const pgGap = scrollScope ? this.scroll.getPageGap() : 0;\n const vpGap = this.viewport.getViewportGap();\n\n const spreads = scrollScope.getSpreadPagesWithRotatedSize();\n if (!spreads.length) return false;\n\n if (vp.clientWidth === 0 || vp.clientHeight === 0) return false;\n\n const availableWidth = vp.clientWidth - 2 * vpGap;\n const availableHeight = vp.clientHeight - 2 * vpGap;\n\n if (availableWidth <= 0 || availableHeight <= 0) return false;\n\n let maxContentW = 0,\n maxContentH = 0;\n\n spreads.forEach((spread) => {\n const contentW = spread.reduce((s, p, i) => s + p.rotatedSize.width + (i ? pgGap : 0), 0);\n const contentH = Math.max(...spread.map((p) => p.rotatedSize.height));\n maxContentW = Math.max(maxContentW, contentW);\n maxContentH = Math.max(maxContentH, contentH);\n });\n\n switch (mode) {\n case ZoomMode.FitWidth:\n return availableWidth / maxContentW;\n case ZoomMode.FitPage:\n return Math.min(availableWidth / maxContentW, availableHeight / maxContentH);\n case ZoomMode.Automatic:\n return Math.min(availableWidth / maxContentW, 1);\n default:\n return 1;\n }\n }\n\n private computeScrollForZoomChange(\n documentId: string,\n vp: ViewportMetrics,\n oldZoom: number,\n newZoom: number,\n focus: Point,\n align: 'keep' | 'center' = 'keep',\n ) {\n const scrollScope = this.scroll.forDocument(documentId);\n const layout = scrollScope.getLayout();\n const vpGap = this.viewport.getViewportGap();\n\n const contentW = layout.totalContentSize.width;\n const contentH = layout.totalContentSize.height;\n\n const availableWidth = vp.clientWidth - 2 * vpGap;\n const availableHeight = vp.clientHeight - 2 * vpGap;\n\n const off = (availableSpace: number, cw: number, zoom: number) =>\n cw * zoom < availableSpace ? (availableSpace - cw * zoom) / 2 : 0;\n\n const offXold = off(availableWidth, contentW, oldZoom);\n const offYold = off(availableHeight, contentH, oldZoom);\n\n const offXnew = off(availableWidth, contentW, newZoom);\n const offYnew = off(availableHeight, contentH, newZoom);\n\n const cx = (vp.scrollLeft + focus.vx - vpGap - offXold) / oldZoom;\n const cy = (vp.scrollTop + focus.vy - vpGap - offYold) / oldZoom;\n\n const baseLeft = cx * newZoom + vpGap + offXnew;\n const baseTop = cy * newZoom + vpGap + offYnew;\n\n const desiredScrollLeft =\n align === 'center' ? baseLeft - vp.clientWidth / 2 : baseLeft - focus.vx;\n const desiredScrollTop =\n align === 'center' ? baseTop - vp.clientHeight / 2 : baseTop - focus.vy;\n\n return {\n desiredScrollLeft: Math.max(0, desiredScrollLeft),\n desiredScrollTop: Math.max(0, desiredScrollTop),\n };\n }\n\n private handleZoomToArea(documentId: string, pageIndex: number, rect: Rect) {\n const coreDoc = this.coreState.core.documents[documentId];\n if (!coreDoc) return;\n\n const rotation = coreDoc.rotation;\n const viewport = this.viewport.forDocument(documentId);\n const vp = viewport.getMetrics();\n const vpGap = this.viewport.getViewportGap();\n const docState = this.getDocumentStateOrThrow(documentId);\n const oldZ = docState.currentZoomLevel;\n\n const availableW = vp.clientWidth - 2 * vpGap;\n const availableH = vp.clientHeight - 2 * vpGap;\n\n const scrollScope = this.scroll.forDocument(documentId);\n const layout = scrollScope.getLayout();\n\n const vItem = layout.virtualItems.find((it) =>\n it.pageLayouts.some((p) => p.pageIndex === pageIndex),\n );\n if (!vItem) return;\n\n const pageRel = vItem.pageLayouts.find((p) => p.pageIndex === pageIndex)!;\n\n const rotatedRect = rotateRect(\n { width: pageRel.width, height: pageRel.height },\n rect,\n rotation,\n );\n\n const targetZoom = this.toZoom(\n Math.min(availableW / rotatedRect.size.width, availableH / rotatedRect.size.height),\n );\n\n const pageAbsX = vItem.x + pageRel.x;\n const pageAbsY = vItem.y + pageRel.y;\n\n const cxContent = pageAbsX + rotatedRect.origin.x + rotatedRect.size.width / 2;\n const cyContent = pageAbsY + rotatedRect.origin.y + rotatedRect.size.height / 2;\n\n const off = (avail: number, cw: number, z: number) =>\n cw * z < avail ? (avail - cw * z) / 2 : 0;\n\n const offXold = off(availableW, layout.totalContentSize.width, oldZ);\n const offYold = off(availableH, layout.totalContentSize.height, oldZ);\n\n const centerVX = vpGap + offXold + cxContent * oldZ - vp.scrollLeft;\n const centerVY = vpGap + offYold + cyContent * oldZ - vp.scrollTop;\n\n this.handleRequest(\n {\n level: targetZoom,\n center: { vx: centerVX, vy: centerVY },\n align: 'center',\n },\n documentId,\n );\n }\n\n private recalcAuto(documentId: string, focus?: VerticalZoomFocus) {\n const docState = this.getDocumentState(documentId);\n if (!docState) return;\n\n if (\n docState.zoomLevel === ZoomMode.Automatic ||\n docState.zoomLevel === ZoomMode.FitPage ||\n docState.zoomLevel === ZoomMode.FitWidth\n ) {\n this.handleRequest({ level: docState.zoomLevel, focus }, documentId);\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Helpers\n // ─────────────────────────────────────────────────────────\n\n private normalizeRanges(ranges: ZoomRangeStep[]): ZoomRangeStep[] {\n return [...ranges].filter((r) => r.step > 0 && r.max > r.min).sort((a, b) => a.min - b.min);\n }\n\n private stepFor(zoom: number): number {\n const r = this.zoomRanges.find((r) => zoom >= r.min && zoom < r.max);\n return r ? r.step : this.zoomStep;\n }\n\n private toZoom(v: number) {\n return parseFloat(clamp(v, this.minZoom, this.maxZoom).toFixed(2));\n }\n\n // ─────────────────────────────────────────────────────────\n // Marquee Zoom\n // ─────────────────────────────────────────────────────────\n\n public registerMarqueeOnPage(opts: RegisterMarqueeOnPageOptions) {\n if (!this.interactionManager) {\n this.logger.warn(\n 'ZoomPlugin',\n 'MissingDependency',\n 'Interaction manager plugin not loaded, marquee zoom disabled',\n );\n return () => {};\n }\n\n const coreDoc = this.coreState.core.documents[opts.documentId];\n if (!coreDoc || !coreDoc.document) {\n this.logger.warn('ZoomPlugin', 'DocumentNotFound', 'Document not found');\n return () => {};\n }\n\n const page = coreDoc.document.pages[opts.pageIndex];\n if (!page) {\n this.logger.warn('ZoomPlugin', 'PageNotFound', `Page ${opts.pageIndex} not found`);\n return () => {};\n }\n\n const handlers = createMarqueeHandler({\n pageSize: page.size,\n scale: opts.scale,\n onPreview: opts.callback.onPreview,\n onCommit: (rect) => {\n this.zoomToArea(opts.pageIndex, rect, opts.documentId);\n opts.callback.onCommit?.(rect);\n },\n onSmallDrag: () => {\n this.zoomIn(opts.documentId);\n opts.callback.onSmallDrag?.();\n },\n });\n\n const off = this.interactionManager.registerHandlers({\n documentId: opts.documentId,\n modeId: 'marqueeZoom',\n handlers,\n pageIndex: opts.pageIndex,\n });\n\n return off;\n }\n\n // ─────────────────────────────────────────────────────────\n // Store Update Handlers\n // ─────────────────────────────────────────────────────────\n\n override onStoreUpdated(prevState: ZoomState, newState: ZoomState): void {\n // Emit state changes for each changed document\n for (const documentId in newState.documents) {\n const prevDoc = prevState.documents[documentId];\n const newDoc = newState.documents[documentId];\n\n if (\n prevDoc &&\n newDoc &&\n (prevDoc.currentZoomLevel !== newDoc.currentZoomLevel ||\n prevDoc.zoomLevel !== newDoc.zoomLevel ||\n prevDoc.isMarqueeZoomActive !== newDoc.isMarqueeZoomActive)\n ) {\n this.state$.emit({\n documentId,\n state: newDoc,\n });\n }\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Lifecycle\n // ─────────────────────────────────────────────────────────\n\n async initialize(): Promise<void> {\n this.logger.info('ZoomPlugin', 'Initialize', 'Zoom plugin initialized');\n }\n\n async destroy() {\n this.zoom$.clear();\n this.state$.clear();\n super.destroy();\n }\n}\n","import { Position, Rect, Size } from '@embedpdf/models';\nimport { clamp } from '@embedpdf/core';\nimport {\n EmbedPdfPointerEvent,\n PointerEventHandlersWithLifecycle,\n} from '@embedpdf/plugin-interaction-manager';\n\nexport function createMarqueeHandler(opts: {\n pageSize: Size;\n scale: number;\n minDragPx?: number;\n onPreview?: (rect: Rect | null) => void;\n onCommit?: (rect: Rect) => void;\n onSmallDrag?: () => void;\n}): PointerEventHandlersWithLifecycle<EmbedPdfPointerEvent> {\n const { pageSize, scale, minDragPx = 5, onPreview, onCommit, onSmallDrag } = opts;\n\n let start: Position | null = null;\n let last: Rect | null = null;\n\n return {\n onPointerDown: (pos, evt) => {\n start = pos;\n last = { origin: { x: pos.x, y: pos.y }, size: { width: 0, height: 0 } };\n onPreview?.(last);\n evt.setPointerCapture?.();\n },\n onPointerMove: (pos) => {\n if (!start) return;\n const x = clamp(pos.x, 0, pageSize.width);\n const y = clamp(pos.y, 0, pageSize.height);\n last = {\n origin: { x: Math.min(start.x, x), y: Math.min(start.y, y) },\n size: { width: Math.abs(x - start.x), height: Math.abs(y - start.y) },\n };\n onPreview?.(last);\n },\n onPointerUp: (_pos, evt) => {\n if (last) {\n const dragPx = Math.max(last.size.width, last.size.height) * scale;\n if (dragPx > minDragPx) {\n onCommit?.(last); // Large drag → zoom to area\n } else {\n onSmallDrag?.(); // Small drag → zoom in\n }\n }\n start = null;\n last = null;\n onPreview?.(null);\n evt.releasePointerCapture?.();\n },\n onPointerCancel: (_pos, evt) => {\n start = null;\n last = null;\n onPreview?.(null);\n evt.releasePointerCapture?.();\n },\n };\n}\n","import { PluginPackage } from '@embedpdf/core';\n\nimport { ZoomAction } from './actions';\nimport { manifest, ZOOM_PLUGIN_ID } from './manifest';\nimport { zoomReducer, initialState, initialDocumentState } from './reducer';\nimport { ZoomPluginConfig, ZoomState } from './types';\nimport { ZoomPlugin } from './zoom-plugin';\n\nexport const ZoomPluginPackage: PluginPackage<ZoomPlugin, ZoomPluginConfig, ZoomState, ZoomAction> =\n {\n manifest,\n create: (registry, config) => new ZoomPlugin(ZOOM_PLUGIN_ID, registry, config),\n reducer: zoomReducer,\n initialState,\n };\n\nexport * from './zoom-plugin';\nexport * from './types';\nexport * from './manifest';\nexport { initialState, initialDocumentState };\n"],"names":["ZoomMode","VerticalZoomFocus","ZOOM_PLUGIN_ID","manifest","id","name","version","provides","requires","optional","defaultConfig","enabled","defaultZoomLevel","Automatic","minZoom","maxZoom","zoomStep","zoomRanges","min","max","step","presets","value","FitPage","FitWidth","INIT_ZOOM_STATE","CLEANUP_ZOOM_STATE","SET_ZOOM_LEVEL","SET_MARQUEE_ZOOM_ACTIVE","initialDocumentState","zoomLevel","currentZoomLevel","isMarqueeZoomActive","initialState","documents","activeDocumentId","_ZoomPlugin","BasePlugin","constructor","registry","cfg","super","this","zoom$","createEmitter","state$","createBehaviorEmitter","viewportPlugin","getPlugin","viewport","scroll","interactionManager","spread","normalizeRanges","onViewportResize","event","recalcAuto","documentId","Top","mode","wait","keyExtractor","_a","onSpreadChange","_b","registerMode","scope","exclusive","cursor","_c","onModeChange","state","isMarqueeActive","activeMode","docState","getDocumentState","dispatch","type","payload","isActive","onDocumentLoadingStarted","gate","initZoomState","logger","debug","onDocumentLoaded","onDocumentClosed","cleanupZoomState","onRotationChanged","buildCapability","requestZoom","level","c","requestZoomBy","d","zoomIn","zoomOut","zoomToArea","pageIndex","rect","enableMarqueeZoom","disableMarqueeZoom","toggleMarqueeZoom","getState","getDocumentStateOrThrow","forDocument","createZoomScope","registerMarqueeOnPage","opts","getPresets","onZoomChange","on","onStateChange","listener","getActiveDocumentId","Error","center","handleRequest","delta","cur","target","toZoom","stepFor","handleZoomToArea","activate","activateDefaultMode","getActiveMode","focus","Center","align","coreState","core","metrics","getMetrics","oldZoom","clientWidth","clientHeight","base","computeZoomForMode","exactZoom","clamp","newZoom","Math","floor","focusPoint","vx","vy","desiredScrollLeft","desiredScrollTop","computeScrollForZoomChange","isNaN","setViewportScrollMetrics","scrollLeft","scrollTop","setZoomLevel","dispatchCoreAction","setScale","isGated","releaseGate","scrollTo","x","y","behavior","evt","emit","vp","scrollScope","pgGap","getPageGap","vpGap","getViewportGap","spreads","getSpreadPagesWithRotatedSize","length","availableWidth","availableHeight","maxContentW","maxContentH","forEach","contentW","reduce","s","p","i","rotatedSize","width","contentH","map","height","layout","getLayout","totalContentSize","off","availableSpace","cw","zoom","offXold","offYold","offXnew","offYnew","baseLeft","baseTop","coreDoc","rotation","oldZ","availableW","availableH","vItem","virtualItems","find","it","pageLayouts","some","pageRel","rotatedRect","rotateRect","targetZoom","size","pageAbsX","pageAbsY","cxContent","origin","cyContent","avail","z","centerVX","centerVY","ranges","filter","r","sort","a","b","v","parseFloat","toFixed","warn","document","page","pages","handlers","pageSize","scale","minDragPx","onPreview","onCommit","onSmallDrag","start","last","onPointerDown","pos","setPointerCapture","call","onPointerMove","abs","onPointerUp","_pos","releasePointerCapture","onPointerCancel","createMarqueeHandler","callback","registerHandlers","modeId","onStoreUpdated","prevState","newState","prevDoc","newDoc","initialize","info","destroy","clear","ZoomPlugin","ZoomPluginPackage","create","config","reducer","action","removed","remainingDocs"],"mappings":"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"}
|