@embedpdf/plugin-zoom 1.5.0 → 2.0.0-next.1

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.
Files changed (55) hide show
  1. package/dist/hammer-DhVzwxwy.cjs +7 -0
  2. package/dist/{hammer-Bs-QCG8V.cjs.map → hammer-DhVzwxwy.cjs.map} +1 -1
  3. package/dist/hammer-e1aXHboh.js.map +1 -1
  4. package/dist/index.cjs +1 -1
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.js +341 -157
  7. package/dist/index.js.map +1 -1
  8. package/dist/lib/actions.d.ts +32 -9
  9. package/dist/lib/index.d.ts +2 -2
  10. package/dist/lib/reducer.d.ts +2 -1
  11. package/dist/lib/types.d.ts +32 -16
  12. package/dist/lib/zoom-plugin.d.ts +22 -15
  13. package/dist/preact/index.cjs +1 -1
  14. package/dist/preact/index.cjs.map +1 -1
  15. package/dist/preact/index.js +47 -26
  16. package/dist/preact/index.js.map +1 -1
  17. package/dist/react/index.cjs +1 -1
  18. package/dist/react/index.cjs.map +1 -1
  19. package/dist/react/index.js +47 -26
  20. package/dist/react/index.js.map +1 -1
  21. package/dist/shared/components/marquee-zoom.d.ts +3 -6
  22. package/dist/shared/components/pinch-wrapper.d.ts +2 -1
  23. package/dist/shared/hooks/use-pinch-zoom.d.ts +1 -1
  24. package/dist/shared/hooks/use-zoom.d.ts +8 -4
  25. package/dist/shared/utils/pinch-zoom-logic.d.ts +2 -1
  26. package/dist/shared-preact/components/marquee-zoom.d.ts +3 -6
  27. package/dist/shared-preact/components/pinch-wrapper.d.ts +2 -1
  28. package/dist/shared-preact/hooks/use-pinch-zoom.d.ts +1 -1
  29. package/dist/shared-preact/hooks/use-zoom.d.ts +8 -4
  30. package/dist/shared-preact/utils/pinch-zoom-logic.d.ts +2 -1
  31. package/dist/shared-react/components/marquee-zoom.d.ts +3 -6
  32. package/dist/shared-react/components/pinch-wrapper.d.ts +2 -1
  33. package/dist/shared-react/hooks/use-pinch-zoom.d.ts +1 -1
  34. package/dist/shared-react/hooks/use-zoom.d.ts +8 -4
  35. package/dist/shared-react/utils/pinch-zoom-logic.d.ts +2 -1
  36. package/dist/shared-svelte/utils/pinch-zoom-logic.d.ts +2 -1
  37. package/dist/shared-vue/utils/pinch-zoom-logic.d.ts +2 -1
  38. package/dist/svelte/components/MarqueeZoom.svelte.d.ts +3 -1
  39. package/dist/svelte/components/PinchWrapper.svelte.d.ts +1 -0
  40. package/dist/svelte/hooks/use-pinch-zoom.svelte.d.ts +5 -1
  41. package/dist/svelte/hooks/use-zoom.svelte.d.ts +11 -5
  42. package/dist/svelte/index.cjs +1 -1
  43. package/dist/svelte/index.cjs.map +1 -1
  44. package/dist/svelte/index.js +108 -53
  45. package/dist/svelte/index.js.map +1 -1
  46. package/dist/vue/components/marquee-zoom.vue.d.ts +5 -2
  47. package/dist/vue/components/pinch-wrapper.vue.d.ts +6 -2
  48. package/dist/vue/hooks/use-pinch-zoom.d.ts +6 -1
  49. package/dist/vue/hooks/use-zoom.d.ts +17 -10
  50. package/dist/vue/index.cjs +1 -1
  51. package/dist/vue/index.cjs.map +1 -1
  52. package/dist/vue/index.js +99 -58
  53. package/dist/vue/index.js.map +1 -1
  54. package/package.json +10 -10
  55. package/dist/hammer-Bs-QCG8V.cjs +0 -7
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/lib/types.ts","../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/handlers/marquee-zoom.handler.ts","../src/lib/zoom-plugin.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 { 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 {\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 { 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","r"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/lib/types.ts","../src/lib/manifest.ts","../src/lib/actions.ts","../src/lib/reducer.ts","../src/lib/handlers/marquee-zoom.handler.ts","../src/lib/zoom-plugin.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 { 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 {\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 { 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","r"],"mappings":";;AAQO,IAAK,6BAAAA,cAAL;AACLA,YAAA,WAAA,IAAY;AACZA,YAAA,SAAA,IAAU;AACVA,YAAA,UAAA,IAAW;AAHD,SAAAA;AAAA,GAAA,YAAA,CAAA,CAAA;AA8HL,IAAK,sCAAAC,uBAAL;AACLA,qBAAAA,mBAAA,QAAA,IAAA,CAAA,IAAA;AACAA,qBAAAA,mBAAA,KAAA,IAAA,CAAA,IAAA;AAFU,SAAAA;AAAA,GAAA,qBAAA,CAAA,CAAA;AClIL,MAAM,iBAAiB;AAEvB,MAAM,WAA6C;AAAA,EACxD,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,UAAU,CAAC,MAAM;AAAA,EACjB,UAAU,CAAC,YAAY,QAAQ;AAAA,EAC/B,UAAU,CAAC,uBAAuB,QAAQ;AAAA,EAC1C,eAAe;AAAA,IACb,SAAS;AAAA,IACT,kBAAkB,SAAS;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,YAAY;AAAA,MACV;AAAA,QACE,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM;AAAA,MAAA;AAAA,MAER;AAAA,QACE,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM;AAAA,MAAA;AAAA,MAER;AAAA,QACE,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM;AAAA,MAAA;AAAA,MAER;AAAA,QACE,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM;AAAA,MAAA;AAAA,MAER;AAAA,QACE,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM;AAAA,MAAA;AAAA,MAER;AAAA,QACE,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM;AAAA,MAAA;AAAA,MAER;AAAA,QACE,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM;AAAA,MAAA;AAAA,MAER;AAAA,QACE,KAAK;AAAA,QACL,KAAK;AAAA,QACL,MAAM;AAAA,MAAA;AAAA,IACR;AAAA,IAEF,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,OAAO,SAAS;AAAA,MAAA;AAAA,MAElB;AAAA,QACE,MAAM;AAAA,QACN,OAAO,SAAS;AAAA,MAAA;AAAA,MAElB;AAAA,QACE,MAAM;AAAA,QACN,OAAO,SAAS;AAAA,MAAA;AAAA,MAElB;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,IACT;AAAA,EACF;AAEJ;AC5GO,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAG5B,MAAM,iBAAiB;AACvB,MAAM,0BAA0B;AA8ChC,SAAS,cAAc,YAAoB,OAA+C;AAC/F,SAAO,EAAE,MAAM,iBAAiB,SAAS,EAAE,YAAY,QAAM;AAC/D;AAEO,SAAS,iBAAiB,YAA4C;AAC3E,SAAO,EAAE,MAAM,oBAAoB,SAAS,WAAA;AAC9C;AAMO,SAAS,aACd,YACA,WACA,kBACoB;AACpB,SAAO,EAAE,MAAM,gBAAgB,SAAS,EAAE,YAAY,WAAW,mBAAiB;AACpF;AAEO,SAAS,qBACd,YACA,UAC4B;AAC5B,SAAO,EAAE,MAAM,yBAAyB,SAAS,EAAE,YAAY,WAAS;AAC1E;ACtEO,MAAM,uBAA0C;AAAA,EACrD,WAAW,SAAS;AAAA,EACpB,kBAAkB;AAAA,EAClB,qBAAqB;AACvB;AAEO,MAAM,eAA0B;AAAA,EACrC,WAAW,CAAA;AAAA,EACX,kBAAkB;AACpB;AAEO,MAAM,cAA8C,CAAC,QAAQ,cAAc,WAAW;AAC3F,UAAQ,OAAO,MAAA;AAAA,IACb,KAAK,iBAAiB;AACpB,YAAM,EAAE,YAAY,OAAO,SAAA,IAAa,OAAO;AAC/C,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW;AAAA,UACT,GAAG,MAAM;AAAA,UACT,CAAC,UAAU,GAAG;AAAA,QAAA;AAAA;AAAA,QAGhB,kBAAkB,MAAM,oBAAoB;AAAA,MAAA;AAAA,IAEhD;AAAA,IAEA,KAAK,oBAAoB;AACvB,YAAM,aAAa,OAAO;AAC1B,YAAM,EAAE,CAAC,UAAU,GAAG,SAAS,GAAG,cAAA,IAAkB,MAAM;AAC1D,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW;AAAA,QACX,kBAAkB,MAAM,qBAAqB,aAAa,OAAO,MAAM;AAAA,MAAA;AAAA,IAE3E;AAAA,IAEA,KAAK,qBAAqB;AACxB,aAAO;AAAA,QACL,GAAG;AAAA,QACH,kBAAkB,OAAO;AAAA,MAAA;AAAA,IAE7B;AAAA,IAEA,KAAK,gBAAgB;AACnB,YAAM,EAAE,YAAY,WAAW,iBAAA,IAAqB,OAAO;AAC3D,YAAM,WAAW,MAAM,UAAU,UAAU;AAC3C,UAAI,CAAC,SAAU,QAAO;AAEtB,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW;AAAA,UACT,GAAG,MAAM;AAAA,UACT,CAAC,UAAU,GAAG;AAAA,YACZ,GAAG;AAAA,YACH;AAAA,YACA;AAAA,UAAA;AAAA,QACF;AAAA,MACF;AAAA,IAEJ;AAAA,IAEA,KAAK,yBAAyB;AAC5B,YAAM,EAAE,YAAY,SAAA,IAAa,OAAO;AACxC,YAAM,WAAW,MAAM,UAAU,UAAU;AAC3C,UAAI,CAAC,SAAU,QAAO;AAEtB,aAAO;AAAA,QACL,GAAG;AAAA,QACH,WAAW;AAAA,UACT,GAAG,MAAM;AAAA,UACT,CAAC,UAAU,GAAG;AAAA,YACZ,GAAG;AAAA,YACH,qBAAqB;AAAA,UAAA;AAAA,QACvB;AAAA,MACF;AAAA,IAEJ;AAAA,IAEA;AACE,aAAO;AAAA,EAAA;AAEb;ACrFO,SAAS,qBAAqB,MAOuB;AAC1D,QAAM,EAAE,UAAU,OAAO,YAAY,GAAG,WAAW,UAAU,gBAAgB;AAE7E,MAAI,QAAyB;AAC7B,MAAI,OAAoB;AAExB,SAAO;AAAA,IACL,eAAe,CAAC,KAAK,QAAQ;;AAC3B,cAAQ;AACR,aAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,EAAA,GAAK,MAAM,EAAE,OAAO,GAAG,QAAQ,IAAE;AACrE,6CAAY;AACZ,gBAAI,sBAAJ;AAAA,IACF;AAAA,IACA,eAAe,CAAC,QAAQ;AACtB,UAAI,CAAC,MAAO;AACZ,YAAM,IAAI,MAAM,IAAI,GAAG,GAAG,SAAS,KAAK;AACxC,YAAM,IAAI,MAAM,IAAI,GAAG,GAAG,SAAS,MAAM;AACzC,aAAO;AAAA,QACL,QAAQ,EAAE,GAAG,KAAK,IAAI,MAAM,GAAG,CAAC,GAAG,GAAG,KAAK,IAAI,MAAM,GAAG,CAAC,EAAA;AAAA,QACzD,MAAM,EAAE,OAAO,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,QAAQ,KAAK,IAAI,IAAI,MAAM,CAAC,EAAA;AAAA,MAAE;AAEtE,6CAAY;AAAA,IACd;AAAA,IACA,aAAa,CAAC,MAAM,QAAQ;;AAC1B,UAAI,MAAM;AACR,cAAM,SAAS,KAAK,IAAI,KAAK,KAAK,OAAO,KAAK,KAAK,MAAM,IAAI;AAC7D,YAAI,SAAS,WAAW;AACtB,+CAAW;AAAA,QACb,OAAO;AACL;AAAA,QACF;AAAA,MACF;AACA,cAAQ;AACR,aAAO;AACP,6CAAY;AACZ,gBAAI,0BAAJ;AAAA,IACF;AAAA,IACA,iBAAiB,CAAC,MAAM,QAAQ;;AAC9B,cAAQ;AACR,aAAO;AACP,6CAAY;AACZ,gBAAI,0BAAJ;AAAA,IACF;AAAA,EAAA;AAEJ;ACdO,MAAM,cAAN,MAAM,oBAAmB,WAK9B;AAAA,EAkBA,YAAY,IAAY,UAA0B,KAAuB;;AACvE,UAAM,IAAI,QAAQ;AAhBpB,SAAiB,QAAQ,cAAA;AACzB,SAAiB,SAAS,sBAAA;AAiBxB,SAAK,iBAAiB,SAAS,UAA0B,UAAU;AACnE,SAAK,WAAW,KAAK,eAAe,SAAA;AACpC,SAAK,SAAS,SAAS,UAAwB,QAAQ,EAAG,SAAA;AAC1D,UAAM,qBAAqB,SAAS,UAAoC,qBAAqB;AAC7F,SAAK,sBAAqB,yDAAoB,eAAc;AAC5D,UAAM,SAAS,SAAS,UAAwB,QAAQ;AACxD,SAAK,UAAS,iCAAQ,eAAc;AAEpC,SAAK,UAAU,IAAI,WAAW;AAC9B,SAAK,UAAU,IAAI,WAAW;AAC9B,SAAK,WAAW,IAAI,YAAY;AAChC,SAAK,mBAAmB,IAAI;AAC5B,SAAK,UAAU,IAAI,WAAW,CAAA;AAC9B,SAAK,aAAa,KAAK,gBAAgB,IAAI,cAAc,EAAE;AAG3D,SAAK,SAAS;AAAA,MACZ,CAAC,UAAU,KAAK,WAAW,MAAM,YAAY,kBAAkB,GAAG;AAAA,MAClE;AAAA,QACE,MAAM;AAAA,QACN,MAAM;AAAA,QACN,cAAc,CAAC,UAAU,MAAM;AAAA,MAAA;AAAA,IACjC;AAIF,eAAK,WAAL,mBAAa,eAAe,CAAC,UAAU;AACrC,WAAK,WAAW,MAAM,YAAY,kBAAkB,GAAG;AAAA,IACzD;AAGA,eAAK,uBAAL,mBAAyB,aAAa;AAAA,MACpC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,WAAW;AAAA,MACX,QAAQ;AAAA,IAAA;AAGV,eAAK,uBAAL,mBAAyB,aAAa,CAAC,UAAU;AAE/C,YAAM,kBAAkB,MAAM,eAAe;AAC7C,YAAM,WAAW,KAAK,iBAAiB,MAAM,UAAU;AAGvD,UAAI,YAAY,SAAS,wBAAwB,iBAAiB;AAChE,aAAK,SAAS,qBAAqB,MAAM,YAAY,eAAe,CAAC;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMmB,yBAAyB,YAA0B;AACpE,SAAK,SAAS,KAAK,QAAQ,UAAU;AAErC,UAAM,WAA8B;AAAA,MAClC,GAAG;AAAA,MACH,WAAW,KAAK;AAAA,IAAA;AAGlB,SAAK,SAAS,cAAc,YAAY,QAAQ,CAAC;AAEjD,SAAK,OAAO;AAAA,MACV;AAAA,MACA;AAAA,MACA,wCAAwC,UAAU;AAAA,IAAA;AAAA,EAEtD;AAAA,EAEmB,iBAAiB,YAA0B;AAE5D,SAAK,WAAW,YAAY,kBAAkB,GAAG;AAAA,EACnD;AAAA,EAEmB,iBAAiB,YAA0B;AAC5D,SAAK,SAAS,iBAAiB,UAAU,CAAC;AAE1C,SAAK,OAAO;AAAA,MACV;AAAA,MACA;AAAA,MACA,uCAAuC,UAAU;AAAA,IAAA;AAAA,EAErD;AAAA,EAEmB,kBAAkB,YAA0B;AAE7D,SAAK,WAAW,YAAY,kBAAkB,GAAG;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYU,kBAAkC;AAC1C,WAAO;AAAA;AAAA,MAEL,aAAa,CAAC,OAAO,MAAM,KAAK,YAAY,OAAO,CAAC;AAAA,MACpD,eAAe,CAAC,GAAG,MAAM,KAAK,cAAc,GAAG,CAAC;AAAA,MAChD,QAAQ,MAAM,KAAK,OAAA;AAAA,MACnB,SAAS,MAAM,KAAK,QAAA;AAAA,MACpB,YAAY,CAAC,WAAW,SAAS,KAAK,WAAW,WAAW,IAAI;AAAA,MAChE,mBAAmB,MAAM,KAAK,kBAAA;AAAA,MAC9B,oBAAoB,MAAM,KAAK,mBAAA;AAAA,MAC/B,mBAAmB,MAAM,KAAK,kBAAA;AAAA,MAC9B,qBAAqB,MAAM,KAAK,oBAAA;AAAA,MAChC,UAAU,MAAM,KAAK,wBAAA;AAAA;AAAA,MAGrB,aAAa,CAAC,eAAuB,KAAK,gBAAgB,UAAU;AAAA;AAAA,MAGpE,uBAAuB,CAAC,SAAS,KAAK,sBAAsB,IAAI;AAAA,MAChE,YAAY,MAAM,KAAK;AAAA;AAAA,MAGvB,cAAc,KAAK,MAAM;AAAA,MACzB,eAAe,KAAK,OAAO;AAAA,IAAA;AAAA,EAE/B;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAgB,YAA+B;AACrD,WAAO;AAAA,MACL,aAAa,CAAC,OAAO,MAAM,KAAK,YAAY,OAAO,GAAG,UAAU;AAAA,MAChE,eAAe,CAAC,GAAG,MAAM,KAAK,cAAc,GAAG,GAAG,UAAU;AAAA,MAC5D,QAAQ,MAAM,KAAK,OAAO,UAAU;AAAA,MACpC,SAAS,MAAM,KAAK,QAAQ,UAAU;AAAA,MACtC,YAAY,CAAC,WAAW,SAAS,KAAK,WAAW,WAAW,MAAM,UAAU;AAAA,MAC5E,mBAAmB,MAAM,KAAK,kBAAkB,UAAU;AAAA,MAC1D,oBAAoB,MAAM,KAAK,mBAAmB,UAAU;AAAA,MAC5D,mBAAmB,MAAM,KAAK,kBAAkB,UAAU;AAAA,MAC1D,qBAAqB,MAAM,KAAK,oBAAoB,UAAU;AAAA,MAC9D,UAAU,MAAM,KAAK,wBAAwB,UAAU;AAAA,MACvD,cAAc,CAAC,aACb,KAAK,MAAM,GAAG,CAAC,UAAU;AACvB,YAAI,MAAM,eAAe,WAAY,UAAS,KAAK;AAAA,MACrD,CAAC;AAAA,MACH,eAAe,CAAC,aACd,KAAK,OAAO,GAAG,CAAC,UAAU;AACxB,YAAI,MAAM,eAAe,WAAY,UAAS,MAAM,KAAK;AAAA,MAC3D,CAAC;AAAA,IAAA;AAAA,EAEP;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAiB,YAA+C;AACtE,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,WAAO,KAAK,MAAM,UAAU,EAAE,KAAK;AAAA,EACrC;AAAA,EAEQ,wBAAwB,YAAwC;AACtE,UAAM,QAAQ,KAAK,iBAAiB,UAAU;AAC9C,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,sCAAsC,cAAc,QAAQ,EAAE;AAAA,IAChF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,OAA0B,QAAgB,YAA2B;AACvF,SAAK,cAAc,EAAE,OAAO,OAAA,GAAU,UAAU;AAAA,EAClD;AAAA,EAEQ,cAAc,OAAe,QAAgB,YAA2B;AAC9E,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,UAAM,WAAW,KAAK,wBAAwB,EAAE;AAChD,UAAM,MAAM,SAAS;AACrB,UAAM,SAAS,KAAK,OAAO,MAAM,KAAK;AACtC,SAAK,cAAc,EAAE,OAAO,QAAQ,OAAA,GAAU,EAAE;AAAA,EAClD;AAAA,EAEQ,OAAO,YAA2B;AACxC,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,UAAM,WAAW,KAAK,wBAAwB,EAAE;AAChD,UAAM,MAAM,SAAS;AACrB,SAAK,cAAc,EAAE,OAAO,KAAK,OAAO,KAAK,QAAQ,GAAG,EAAA,GAAK,EAAE;AAAA,EACjE;AAAA,EAEQ,QAAQ,YAA2B;AACzC,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,UAAM,WAAW,KAAK,wBAAwB,EAAE;AAChD,UAAM,MAAM,SAAS;AACrB,SAAK,cAAc,EAAE,OAAO,KAAK,OAAO,CAAC,KAAK,QAAQ,GAAG,EAAA,GAAK,EAAE;AAAA,EAClE;AAAA,EAEQ,WAAW,WAAmB,MAAY,YAA2B;AAC3E,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,SAAK,iBAAiB,IAAI,WAAW,IAAI;AAAA,EAC3C;AAAA,EAEQ,kBAAkB,YAA2B;;AACnD,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,eAAK,uBAAL,mBAAyB,YAAY,IAAI,SAAS;AAAA,EACpD;AAAA,EAEQ,mBAAmB,YAA2B;;AACpD,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,eAAK,uBAAL,mBAAyB,YAAY,IAAI;AAAA,EAC3C;AAAA,EAEQ,kBAAkB,YAA2B;;AACnD,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,UAAM,SAAQ,UAAK,uBAAL,mBAAyB,YAAY;AACnD,SAAI,+BAAO,qBAAoB,eAAe;AAC5C,YAAM,oBAAA;AAAA,IACR,OAAO;AACL,qCAAO,SAAS;AAAA,IAClB;AAAA,EACF;AAAA,EAEQ,oBAAoB,YAA8B;;AACxD,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,aAAO,UAAK,uBAAL,mBAAyB,YAAY,IAAI,qBAAoB;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAMQ,cACN,EAAE,OAAO,QAAQ,GAAG,QAAQ,QAAQ,kBAAkB,QAAQ,QAAQ,OAAA,GACtE,YACA;AACA,UAAM,KAAK,cAAc,KAAK,oBAAA;AAC9B,UAAM,WAAW,KAAK,wBAAwB,EAAE;AAChD,UAAM,UAAU,KAAK,UAAU,KAAK,UAAU,EAAE;AAChD,QAAI,CAAC,QAAS;AAEd,UAAM,WAAW,KAAK,SAAS,YAAY,EAAE;AAC7C,UAAM,UAAU,SAAS,WAAA;AACzB,UAAM,UAAU,SAAS;AAEzB,QAAI,QAAQ,gBAAgB,KAAK,QAAQ,iBAAiB,GAAG;AAC3D;AAAA,IACF;AAGA,UAAM,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAK,mBAAmB,IAAI,OAAO,OAAO;AAE3F,QAAI,SAAS,MAAO;AAEpB,UAAM,YAAY,MAAM,OAAO,OAAO,KAAK,SAAS,KAAK,OAAO;AAChE,UAAM,UAAU,KAAK,MAAM,YAAY,GAAI,IAAI;AAG/C,UAAM,aAAoB,UAAU;AAAA,MAClC,IAAI,QAAQ,cAAc;AAAA,MAC1B,IAAI,UAAU,kBAAkB,MAAM,IAAI,QAAQ,eAAe;AAAA,IAAA;AAInE,UAAM,EAAE,mBAAmB,iBAAA,IAAqB,KAAK;AAAA,MACnD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAIF,QAAI,CAAC,MAAM,iBAAiB,KAAK,CAAC,MAAM,gBAAgB,GAAG;AACzD,WAAK,eAAe,yBAAyB,IAAI;AAAA,QAC/C,YAAY;AAAA,QACZ,WAAW;AAAA,MAAA,CACZ;AAAA,IACH;AAEA,SAAK,SAAS,aAAa,IAAI,OAAO,UAAU,WAAW,UAAU,OAAO,OAAO,CAAC;AACpF,SAAK,mBAAmB,SAAS,SAAS,EAAE,CAAC;AAC7C,QAAI,KAAK,SAAS,QAAQ,EAAE,GAAG;AAC7B,WAAK,SAAS,YAAY,QAAQ,EAAE;AAAA,IACtC;AAEA,aAAS,SAAS;AAAA,MAChB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,UAAU;AAAA,IAAA,CACX;AAED,UAAM,MAAuB;AAAA,MAC3B,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA,UAAU;AAAA,IAAA;AAGZ,SAAK,MAAM,KAAK,GAAG;AAAA,EACrB;AAAA,EAEQ,mBACN,YACA,MACA,IACgB;AAChB,UAAM,UAAU,KAAK,UAAU,KAAK,UAAU,UAAU;AACxD,QAAI,CAAC,QAAS,QAAO;AAErB,UAAM,cAAc,KAAK,OAAO,YAAY,UAAU;AACtD,UAAM,QAAQ,cAAc,KAAK,OAAO,eAAe;AACvD,UAAM,QAAQ,KAAK,SAAS,eAAA;AAE5B,UAAM,UAAU,YAAY,8BAAA;AAC5B,QAAI,CAAC,QAAQ,OAAQ,QAAO;AAE5B,QAAI,GAAG,gBAAgB,KAAK,GAAG,iBAAiB,EAAG,QAAO;AAE1D,UAAM,iBAAiB,GAAG,cAAc,IAAI;AAC5C,UAAM,kBAAkB,GAAG,eAAe,IAAI;AAE9C,QAAI,kBAAkB,KAAK,mBAAmB,EAAG,QAAO;AAExD,QAAI,cAAc,GAChB,cAAc;AAEhB,YAAQ,QAAQ,CAAC,WAAW;AAC1B,YAAM,WAAW,OAAO,OAAO,CAAC,GAAG,GAAG,MAAM,IAAI,EAAE,YAAY,SAAS,IAAI,QAAQ,IAAI,CAAC;AACxF,YAAM,WAAW,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,YAAY,MAAM,CAAC;AACpE,oBAAc,KAAK,IAAI,aAAa,QAAQ;AAC5C,oBAAc,KAAK,IAAI,aAAa,QAAQ;AAAA,IAC9C,CAAC;AAED,YAAQ,MAAA;AAAA,MACN,KAAK,SAAS;AACZ,eAAO,iBAAiB;AAAA,MAC1B,KAAK,SAAS;AACZ,eAAO,KAAK,IAAI,iBAAiB,aAAa,kBAAkB,WAAW;AAAA,MAC7E,KAAK,SAAS;AACZ,eAAO,KAAK,IAAI,iBAAiB,aAAa,CAAC;AAAA,MACjD;AACE,eAAO;AAAA,IAAA;AAAA,EAEb;AAAA,EAEQ,2BACN,YACA,IACA,SACA,SACA,OACA,QAA2B,QAC3B;AACA,UAAM,cAAc,KAAK,OAAO,YAAY,UAAU;AACtD,UAAM,SAAS,YAAY,UAAA;AAC3B,UAAM,QAAQ,KAAK,SAAS,eAAA;AAE5B,UAAM,WAAW,OAAO,iBAAiB;AACzC,UAAM,WAAW,OAAO,iBAAiB;AAEzC,UAAM,iBAAiB,GAAG,cAAc,IAAI;AAC5C,UAAM,kBAAkB,GAAG,eAAe,IAAI;AAE9C,UAAM,MAAM,CAAC,gBAAwB,IAAY,SAC/C,KAAK,OAAO,kBAAkB,iBAAiB,KAAK,QAAQ,IAAI;AAElE,UAAM,UAAU,IAAI,gBAAgB,UAAU,OAAO;AACrD,UAAM,UAAU,IAAI,iBAAiB,UAAU,OAAO;AAEtD,UAAM,UAAU,IAAI,gBAAgB,UAAU,OAAO;AACrD,UAAM,UAAU,IAAI,iBAAiB,UAAU,OAAO;AAEtD,UAAM,MAAM,GAAG,aAAa,MAAM,KAAK,QAAQ,WAAW;AAC1D,UAAM,MAAM,GAAG,YAAY,MAAM,KAAK,QAAQ,WAAW;AAEzD,UAAM,WAAW,KAAK,UAAU,QAAQ;AACxC,UAAM,UAAU,KAAK,UAAU,QAAQ;AAEvC,UAAM,oBACJ,UAAU,WAAW,WAAW,GAAG,cAAc,IAAI,WAAW,MAAM;AACxE,UAAM,mBACJ,UAAU,WAAW,UAAU,GAAG,eAAe,IAAI,UAAU,MAAM;AAEvE,WAAO;AAAA,MACL,mBAAmB,KAAK,IAAI,GAAG,iBAAiB;AAAA,MAChD,kBAAkB,KAAK,IAAI,GAAG,gBAAgB;AAAA,IAAA;AAAA,EAElD;AAAA,EAEQ,iBAAiB,YAAoB,WAAmB,MAAY;AAC1E,UAAM,UAAU,KAAK,UAAU,KAAK,UAAU,UAAU;AACxD,QAAI,CAAC,QAAS;AAEd,UAAM,WAAW,QAAQ;AACzB,UAAM,WAAW,KAAK,SAAS,YAAY,UAAU;AACrD,UAAM,KAAK,SAAS,WAAA;AACpB,UAAM,QAAQ,KAAK,SAAS,eAAA;AAC5B,UAAM,WAAW,KAAK,wBAAwB,UAAU;AACxD,UAAM,OAAO,SAAS;AAEtB,UAAM,aAAa,GAAG,cAAc,IAAI;AACxC,UAAM,aAAa,GAAG,eAAe,IAAI;AAEzC,UAAM,cAAc,KAAK,OAAO,YAAY,UAAU;AACtD,UAAM,SAAS,YAAY,UAAA;AAE3B,UAAM,QAAQ,OAAO,aAAa;AAAA,MAAK,CAAC,OACtC,GAAG,YAAY,KAAK,CAAC,MAAM,EAAE,cAAc,SAAS;AAAA,IAAA;AAEtD,QAAI,CAAC,MAAO;AAEZ,UAAM,UAAU,MAAM,YAAY,KAAK,CAAC,MAAM,EAAE,cAAc,SAAS;AAEvE,UAAM,cAAc;AAAA,MAClB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAA;AAAA,MACxC;AAAA,MACA;AAAA,IAAA;AAGF,UAAM,aAAa,KAAK;AAAA,MACtB,KAAK,IAAI,aAAa,YAAY,KAAK,OAAO,aAAa,YAAY,KAAK,MAAM;AAAA,IAAA;AAGpF,UAAM,WAAW,MAAM,IAAI,QAAQ;AACnC,UAAM,WAAW,MAAM,IAAI,QAAQ;AAEnC,UAAM,YAAY,WAAW,YAAY,OAAO,IAAI,YAAY,KAAK,QAAQ;AAC7E,UAAM,YAAY,WAAW,YAAY,OAAO,IAAI,YAAY,KAAK,SAAS;AAE9E,UAAM,MAAM,CAAC,OAAe,IAAY,MACtC,KAAK,IAAI,SAAS,QAAQ,KAAK,KAAK,IAAI;AAE1C,UAAM,UAAU,IAAI,YAAY,OAAO,iBAAiB,OAAO,IAAI;AACnE,UAAM,UAAU,IAAI,YAAY,OAAO,iBAAiB,QAAQ,IAAI;AAEpE,UAAM,WAAW,QAAQ,UAAU,YAAY,OAAO,GAAG;AACzD,UAAM,WAAW,QAAQ,UAAU,YAAY,OAAO,GAAG;AAEzD,SAAK;AAAA,MACH;AAAA,QACE,OAAO;AAAA,QACP,QAAQ,EAAE,IAAI,UAAU,IAAI,SAAA;AAAA,QAC5B,OAAO;AAAA,MAAA;AAAA,MAET;AAAA,IAAA;AAAA,EAEJ;AAAA,EAEQ,WAAW,YAAoB,OAA2B;AAChE,UAAM,WAAW,KAAK,iBAAiB,UAAU;AACjD,QAAI,CAAC,SAAU;AAEf,QACE,SAAS,cAAc,SAAS,aAChC,SAAS,cAAc,SAAS,WAChC,SAAS,cAAc,SAAS,UAChC;AACA,WAAK,cAAc,EAAE,OAAO,SAAS,WAAW,MAAA,GAAS,UAAU;AAAA,IACrE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAgB,QAA0C;AAChE,WAAO,CAAC,GAAG,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;AAAA,EAC5F;AAAA,EAEQ,QAAQ,MAAsB;AACpC,UAAM,IAAI,KAAK,WAAW,KAAK,CAACC,OAAM,QAAQA,GAAE,OAAO,OAAOA,GAAE,GAAG;AACnE,WAAO,IAAI,EAAE,OAAO,KAAK;AAAA,EAC3B;AAAA,EAEQ,OAAO,GAAW;AACxB,WAAO,WAAW,MAAM,GAAG,KAAK,SAAS,KAAK,OAAO,EAAE,QAAQ,CAAC,CAAC;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAMO,sBAAsB,MAAoC;AAC/D,QAAI,CAAC,KAAK,oBAAoB;AAC5B,WAAK,OAAO;AAAA,QACV;AAAA,QACA;AAAA,QACA;AAAA,MAAA;AAEF,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAEA,UAAM,UAAU,KAAK,UAAU,KAAK,UAAU,KAAK,UAAU;AAC7D,QAAI,CAAC,WAAW,CAAC,QAAQ,UAAU;AACjC,WAAK,OAAO,KAAK,cAAc,oBAAoB,oBAAoB;AACvE,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAEA,UAAM,OAAO,QAAQ,SAAS,MAAM,KAAK,SAAS;AAClD,QAAI,CAAC,MAAM;AACT,WAAK,OAAO,KAAK,cAAc,gBAAgB,QAAQ,KAAK,SAAS,YAAY;AACjF,aAAO,MAAM;AAAA,MAAC;AAAA,IAChB;AAEA,UAAM,WAAW,qBAAqB;AAAA,MACpC,UAAU,KAAK;AAAA,MACf,OAAO,KAAK;AAAA,MACZ,WAAW,KAAK,SAAS;AAAA,MACzB,UAAU,CAAC,SAAS;;AAClB,aAAK,WAAW,KAAK,WAAW,MAAM,KAAK,UAAU;AACrD,yBAAK,UAAS,aAAd,4BAAyB;AAAA,MAC3B;AAAA,MACA,aAAa,MAAM;;AACjB,aAAK,OAAO,KAAK,UAAU;AAC3B,yBAAK,UAAS,gBAAd;AAAA,MACF;AAAA,IAAA,CACD;AAED,UAAM,MAAM,KAAK,mBAAmB,iBAAiB;AAAA,MACnD,YAAY,KAAK;AAAA,MACjB,QAAQ;AAAA,MACR;AAAA,MACA,WAAW,KAAK;AAAA,IAAA,CACjB;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMS,eAAe,WAAsB,UAA2B;AAEvE,eAAW,cAAc,SAAS,WAAW;AAC3C,YAAM,UAAU,UAAU,UAAU,UAAU;AAC9C,YAAM,SAAS,SAAS,UAAU,UAAU;AAE5C,UACE,WACA,WACC,QAAQ,qBAAqB,OAAO,oBACnC,QAAQ,cAAc,OAAO,aAC7B,QAAQ,wBAAwB,OAAO,sBACzC;AACA,aAAK,OAAO,KAAK;AAAA,UACf;AAAA,UACA,OAAO;AAAA,QAAA,CACR;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aAA4B;AAChC,SAAK,OAAO,KAAK,cAAc,cAAc,yBAAyB;AAAA,EACxE;AAAA,EAEA,MAAM,UAAU;AACd,SAAK,MAAM,MAAA;AACX,SAAK,OAAO,MAAA;AACZ,UAAM,QAAA;AAAA,EACR;AACF;AAplBE,YAAgB,KAAK;AANhB,IAAM,aAAN;ACpCA,MAAM,oBACX;AAAA,EACE;AAAA,EACA,QAAQ,CAAC,UAAU,WAAW,IAAI,WAAW,gBAAgB,UAAU,MAAM;AAAA,EAC7E,SAAS;AAAA,EACT;AACF;"}
@@ -1,20 +1,43 @@
1
1
  import { Action } from '@embedpdf/core';
2
- import { ZoomLevel } from './types';
3
- export declare const SET_ZOOM_LEVEL = "SET_ZOOM_LEVEL";
4
- export declare const SET_INITIAL_ZOOM_LEVEL = "SET_INITIAL_ZOOM_LEVEL";
2
+ import { ZoomLevel, ZoomDocumentState } from './types';
3
+ export declare const INIT_ZOOM_STATE = "ZOOM/INIT_STATE";
4
+ export declare const CLEANUP_ZOOM_STATE = "ZOOM/CLEANUP_STATE";
5
+ export declare const SET_ACTIVE_DOCUMENT = "ZOOM/SET_ACTIVE_DOCUMENT";
6
+ export declare const SET_ZOOM_LEVEL = "ZOOM/SET_ZOOM_LEVEL";
7
+ export declare const SET_MARQUEE_ZOOM_ACTIVE = "ZOOM/SET_MARQUEE_ZOOM_ACTIVE";
8
+ export interface InitZoomStateAction extends Action {
9
+ type: typeof INIT_ZOOM_STATE;
10
+ payload: {
11
+ documentId: string;
12
+ state: ZoomDocumentState;
13
+ };
14
+ }
15
+ export interface CleanupZoomStateAction extends Action {
16
+ type: typeof CLEANUP_ZOOM_STATE;
17
+ payload: string;
18
+ }
19
+ export interface SetActiveDocumentAction extends Action {
20
+ type: typeof SET_ACTIVE_DOCUMENT;
21
+ payload: string | null;
22
+ }
5
23
  export interface SetZoomLevelAction extends Action {
6
24
  type: typeof SET_ZOOM_LEVEL;
7
25
  payload: {
26
+ documentId: string;
8
27
  zoomLevel: ZoomLevel;
9
28
  currentZoomLevel: number;
10
29
  };
11
30
  }
12
- export interface SetInitialZoomLevelAction extends Action {
13
- type: typeof SET_INITIAL_ZOOM_LEVEL;
31
+ export interface SetMarqueeZoomActiveAction extends Action {
32
+ type: typeof SET_MARQUEE_ZOOM_ACTIVE;
14
33
  payload: {
15
- zoomLevel: ZoomLevel;
34
+ documentId: string;
35
+ isActive: boolean;
16
36
  };
17
37
  }
18
- export type ZoomAction = SetZoomLevelAction | SetInitialZoomLevelAction;
19
- export declare function setZoomLevel(zoomLevel: ZoomLevel, currentZoomLevel: number): SetZoomLevelAction;
20
- export declare function setInitialZoomLevel(zoomLevel: ZoomLevel): SetInitialZoomLevelAction;
38
+ export type ZoomAction = InitZoomStateAction | CleanupZoomStateAction | SetActiveDocumentAction | SetZoomLevelAction | SetMarqueeZoomActiveAction;
39
+ export declare function initZoomState(documentId: string, state: ZoomDocumentState): InitZoomStateAction;
40
+ export declare function cleanupZoomState(documentId: string): CleanupZoomStateAction;
41
+ export declare function setActiveDocument(documentId: string | null): SetActiveDocumentAction;
42
+ export declare function setZoomLevel(documentId: string, zoomLevel: ZoomLevel, currentZoomLevel: number): SetZoomLevelAction;
43
+ export declare function setMarqueeZoomActive(documentId: string, isActive: boolean): SetMarqueeZoomActiveAction;
@@ -1,10 +1,10 @@
1
1
  import { PluginPackage } from '@embedpdf/core';
2
2
  import { ZoomAction } from './actions';
3
- import { initialState } from './reducer';
3
+ import { initialState, initialDocumentState } from './reducer';
4
4
  import { ZoomPluginConfig, ZoomState } from './types';
5
5
  import { ZoomPlugin } from './zoom-plugin';
6
6
  export declare const ZoomPluginPackage: PluginPackage<ZoomPlugin, ZoomPluginConfig, ZoomState, ZoomAction>;
7
7
  export * from './zoom-plugin';
8
8
  export * from './types';
9
9
  export * from './manifest';
10
- export { initialState };
10
+ export { initialState, initialDocumentState };
@@ -1,5 +1,6 @@
1
1
  import { Reducer } from '@embedpdf/core';
2
2
  import { ZoomAction } from './actions';
3
- import { ZoomState } from './types';
3
+ import { ZoomState, ZoomDocumentState } from './types';
4
+ export declare const initialDocumentState: ZoomDocumentState;
4
5
  export declare const initialState: ZoomState;
5
6
  export declare const zoomReducer: Reducer<ZoomState, ZoomAction>;
@@ -12,6 +12,7 @@ export interface Point {
12
12
  vy: number;
13
13
  }
14
14
  export interface ZoomChangeEvent {
15
+ documentId: string;
15
16
  /** old and new *actual* scale factors */
16
17
  oldZoom: number;
17
18
  newZoom: number;
@@ -22,41 +23,59 @@ export interface ZoomChangeEvent {
22
23
  /** where the viewport should scroll to after the scale change */
23
24
  desiredScrollLeft: number;
24
25
  desiredScrollTop: number;
25
- /** metrics at the moment the zoom was requested */
26
+ /** metrics at the moment the zoom was requested */
26
27
  viewport: ViewportMetrics;
27
28
  }
29
+ export interface StateChangeEvent {
30
+ documentId: string;
31
+ state: ZoomDocumentState;
32
+ }
28
33
  export interface MarqueeZoomCallback {
29
34
  onPreview?: (rect: Rect | null) => void;
30
35
  onCommit?: (rect: Rect) => void;
31
36
  onSmallDrag?: () => void;
32
37
  }
33
38
  export interface RegisterMarqueeOnPageOptions {
39
+ documentId: string;
34
40
  pageIndex: number;
35
41
  scale: number;
36
42
  callback: MarqueeZoomCallback;
37
43
  }
38
- export interface ZoomCapability {
39
- /** subscribe – returns the unsubscribe function */
44
+ export interface ZoomDocumentState {
45
+ zoomLevel: ZoomLevel;
46
+ currentZoomLevel: number;
47
+ isMarqueeZoomActive: boolean;
48
+ }
49
+ export interface ZoomScope {
50
+ requestZoom(level: ZoomLevel, center?: Point): void;
51
+ requestZoomBy(delta: number, center?: Point): void;
52
+ zoomIn(): void;
53
+ zoomOut(): void;
54
+ zoomToArea(pageIndex: number, rect: Rect): void;
55
+ enableMarqueeZoom(): void;
56
+ disableMarqueeZoom(): void;
57
+ toggleMarqueeZoom(): void;
58
+ isMarqueeZoomActive(): boolean;
59
+ getState(): ZoomDocumentState;
40
60
  onZoomChange: EventHook<ZoomChangeEvent>;
41
- /** subscribe – returns the unsubscribe function */
42
- onStateChange: EventHook<ZoomState>;
43
- /** absolute requests -------------------------------------------------- */
61
+ onStateChange: EventHook<ZoomDocumentState>;
62
+ }
63
+ export interface ZoomCapability {
44
64
  requestZoom(level: ZoomLevel, center?: Point): void;
45
- /** relative requests -------------------------------------------------- */
46
65
  requestZoomBy(delta: number, center?: Point): void;
47
- /** absolute requests -------------------------------------------------- */
48
66
  zoomIn(): void;
49
67
  zoomOut(): void;
50
68
  zoomToArea(pageIndex: number, rect: Rect): void;
51
- /** zoom in on an area -------------------------------------------------- */
52
69
  enableMarqueeZoom(): void;
53
70
  disableMarqueeZoom(): void;
54
71
  toggleMarqueeZoom(): void;
55
72
  isMarqueeZoomActive(): boolean;
56
- /** register a marquee handler on a page -------------------------------- */
73
+ getState(): ZoomDocumentState;
74
+ forDocument(documentId: string): ZoomScope;
57
75
  registerMarqueeOnPage: (opts: RegisterMarqueeOnPageOptions) => () => void;
58
- getState(): ZoomState;
59
76
  getPresets(): ZoomPreset[];
77
+ onZoomChange: EventHook<ZoomChangeEvent>;
78
+ onStateChange: EventHook<StateChangeEvent>;
60
79
  }
61
80
  export interface ZoomRangeStep {
62
81
  min: number;
@@ -77,8 +96,8 @@ export interface ZoomPluginConfig extends BasePluginConfig {
77
96
  presets?: ZoomPreset[];
78
97
  }
79
98
  export interface ZoomState {
80
- zoomLevel: ZoomLevel;
81
- currentZoomLevel: number;
99
+ documents: Record<string, ZoomDocumentState>;
100
+ activeDocumentId: string | null;
82
101
  }
83
102
  export declare enum VerticalZoomFocus {
84
103
  Center = 0,
@@ -89,8 +108,5 @@ export interface ZoomRequest {
89
108
  delta?: number;
90
109
  center?: Point;
91
110
  focus?: VerticalZoomFocus;
92
- /** Scroll so that the focal point ends up …
93
- * ▸ `"keep"` (default) at the same viewport coords
94
- * ▸ `"center"` centred in the viewport */
95
111
  align?: 'keep' | 'center';
96
112
  }
@@ -9,34 +9,41 @@ export declare class ZoomPlugin extends BasePlugin<ZoomPluginConfig, ZoomCapabil
9
9
  private readonly viewportPlugin;
10
10
  private readonly scroll;
11
11
  private readonly interactionManager;
12
+ private readonly spread;
12
13
  private readonly presets;
13
14
  private readonly zoomRanges;
15
+ private readonly defaultZoomLevel;
14
16
  private readonly minZoom;
15
17
  private readonly maxZoom;
16
18
  private readonly zoomStep;
17
19
  constructor(id: string, registry: PluginRegistry, cfg: ZoomPluginConfig);
20
+ protected onDocumentLoadingStarted(documentId: string): void;
21
+ protected onDocumentLoaded(documentId: string): void;
22
+ protected onDocumentClosed(documentId: string): void;
23
+ protected onRotationChanged(documentId: string): void;
18
24
  protected buildCapability(): ZoomCapability;
19
- private zoomOut;
25
+ private createZoomScope;
26
+ private getDocumentState;
27
+ private getDocumentStateOrThrow;
28
+ private requestZoom;
29
+ private requestZoomBy;
20
30
  private zoomIn;
31
+ private zoomOut;
21
32
  private zoomToArea;
22
- initialize(): Promise<void>;
23
- destroy(): Promise<void>;
24
- /**
25
- * Sort ranges once, make sure they are sane
26
- */
27
- private normalizeRanges;
28
- /** pick the step that applies to a given numeric zoom */
29
- private stepFor;
30
- /** clamp + round helper reused later */
31
- private toZoom;
33
+ private enableMarqueeZoom;
34
+ private disableMarqueeZoom;
35
+ private toggleMarqueeZoom;
36
+ private isMarqueeZoomActive;
32
37
  private handleRequest;
33
- /** numeric zoom for Automatic / FitPage / FitWidth */
34
38
  private computeZoomForMode;
35
- /** where to scroll so that *focus* stays stable after scaling */
36
39
  private computeScrollForZoomChange;
37
40
  private handleZoomToArea;
38
- /** recalculates Automatic / Fit* when viewport or pages change */
39
41
  private recalcAuto;
40
- onStoreUpdated(_prevState: ZoomState, newState: ZoomState): void;
42
+ private normalizeRanges;
43
+ private stepFor;
44
+ private toZoom;
41
45
  registerMarqueeOnPage(opts: RegisterMarqueeOnPageOptions): () => void;
46
+ onStoreUpdated(prevState: ZoomState, newState: ZoomState): void;
47
+ initialize(): Promise<void>;
48
+ destroy(): Promise<void>;
42
49
  }
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core/preact"),t=require("@embedpdf/plugin-zoom");require("preact");const o=require("preact/hooks"),n=require("preact/jsx-runtime"),r=()=>e.useCapability(t.ZoomPlugin.id);function i({element:e,viewportProvides:t,zoomProvides:o}){if("undefined"==typeof window)return()=>{};let n,r=0,i={x:0,y:0};const s=()=>{e.style.transform="none",e.style.transformOrigin="0 0"},a=n=>{var s;r=o.getState().currentZoomLevel;const a=t.getBoundingRect();i={x:n.center.x-a.origin.x,y:n.center.y-a.origin.y};const l=e.getBoundingClientRect();e.style.transformOrigin=`${n.center.x-l.left}px ${n.center.y-l.top}px`,(null==(s=n.srcEvent)?void 0:s.cancelable)&&(n.srcEvent.preventDefault(),n.srcEvent.stopPropagation())},l=t=>{var o,n;n=t.scale,e.style.transform=`scale(${n})`,(null==(o=t.srcEvent)?void 0:o.cancelable)&&(t.srcEvent.preventDefault(),t.srcEvent.stopPropagation())},c=e=>{const t=(e.scale-1)*r;o.requestZoomBy(t,{vx:i.x,vy:i.y}),s(),r=0};return(async()=>{try{const t=(await Promise.resolve().then((()=>require("../hammer-Bs-QCG8V.cjs"))).then((e=>e.hammer))).default,o=(()=>{const e="ontouchstart"in window||navigator.maxTouchPoints>0;return e&&/mobile|tablet|ip(ad|hone|od)|android/i.test(navigator.userAgent)?t.TouchInput:e?t.TouchMouseInput:t.MouseInput})();n=new t(e,{touchAction:"pan-x pan-y",inputClass:o}),n.get("pinch").set({enable:!0,pointers:2,threshold:.1}),n.on("pinchstart",a),n.on("pinchmove",l),n.on("pinchend",c)}catch(t){console.warn("Failed to load HammerJS:",t)}})(),()=>{null==n||n.destroy(),s()}}function s(){const{provides:t}=e.useCapability("viewport"),{provides:n}=r(),s=o.useRef(null);return o.useEffect((()=>{const e=s.current;if(e&&t&&n)return i({element:e,viewportProvides:t,zoomProvides:n})}),[t,n]),{elementRef:s}}exports.MarqueeZoom=({pageIndex:e,scale:t,className:i,stroke:s="rgba(33,150,243,0.8)",fill:a="rgba(33,150,243,0.15)"})=>{const{provides:l}=r(),[c,u]=o.useState(null);return o.useEffect((()=>{if(l)return l.registerMarqueeOnPage({pageIndex:e,scale:t,callback:{onPreview:u}})}),[l,e,t]),c?n.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:c.origin.x*t,top:c.origin.y*t,width:c.size.width*t,height:c.size.height*t,border:`1px solid ${s}`,background:a,boxSizing:"border-box"},className:i}):null},exports.PinchWrapper=function({children:e,style:t,...o}){const{elementRef:r}=s();return n.jsx("div",{ref:r,...o,style:{...t,display:"block",width:"fit-content",overflow:"visible",boxSizing:"border-box",margin:"0px auto"},children:e})},exports.usePinch=s,exports.useZoom=()=>{const{provides:e}=r(),[n,i]=o.useState(t.initialState);return o.useEffect((()=>null==e?void 0:e.onStateChange((e=>{i(e)}))),[e]),{state:n,provides:e}},exports.useZoomCapability=r,exports.useZoomPlugin=()=>e.usePlugin(t.ZoomPlugin.id),Object.keys(t).forEach((e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})}));
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core/preact"),t=require("@embedpdf/plugin-zoom");require("preact");const o=require("preact/hooks"),n=require("preact/jsx-runtime"),r=()=>e.useCapability(t.ZoomPlugin.id);function i({element:e,documentId:t,viewportProvides:o,zoomProvides:n}){if("undefined"==typeof window)return()=>{};let r,i=0,s={x:0,y:0};const a=o.forDocument(t),c=n.forDocument(t),u=()=>{e.style.transform="none",e.style.transformOrigin="0 0"},l=t=>{var o;i=c.getState().currentZoomLevel;const n=a.getBoundingRect();s={x:t.center.x-n.origin.x,y:t.center.y-n.origin.y};const r=e.getBoundingClientRect();e.style.transformOrigin=`${t.center.x-r.left}px ${t.center.y-r.top}px`,(null==(o=t.srcEvent)?void 0:o.cancelable)&&(t.srcEvent.preventDefault(),t.srcEvent.stopPropagation())},d=t=>{var o,n;n=t.scale,e.style.transform=`scale(${n})`,(null==(o=t.srcEvent)?void 0:o.cancelable)&&(t.srcEvent.preventDefault(),t.srcEvent.stopPropagation())},p=e=>{const t=(e.scale-1)*i;c.requestZoomBy(t,{vx:s.x,vy:s.y}),u(),i=0};return(async()=>{try{const t=(await Promise.resolve().then(()=>require("../hammer-DhVzwxwy.cjs")).then(e=>e.hammer)).default,o=(()=>{const e="ontouchstart"in window||navigator.maxTouchPoints>0;return e&&/mobile|tablet|ip(ad|hone|od)|android/i.test(navigator.userAgent)?t.TouchInput:e?t.TouchMouseInput:t.MouseInput})();r=new t(e,{touchAction:"pan-x pan-y",inputClass:o}),r.get("pinch").set({enable:!0,pointers:2,threshold:.1}),r.on("pinchstart",l),r.on("pinchmove",d),r.on("pinchend",p)}catch(t){console.warn("Failed to load HammerJS:",t)}})(),()=>{null==r||r.destroy(),u()}}function s(t){const{provides:n}=e.useCapability("viewport"),{provides:s}=r(),a=o.useRef(null);return o.useEffect(()=>{const e=a.current;if(e&&n&&s)return i({element:e,documentId:t,viewportProvides:n,zoomProvides:s})},[n,s,t]),{elementRef:a}}exports.MarqueeZoom=({documentId:t,pageIndex:i,scale:s,className:a,stroke:c="rgba(33,150,243,0.8)",fill:u="rgba(33,150,243,0.15)"})=>{const{provides:l}=r(),d=e.useDocumentState(t),[p,m]=o.useState(null),v=o.useMemo(()=>void 0!==s?s:(null==d?void 0:d.scale)??1,[s,null==d?void 0:d.scale]);return o.useEffect(()=>{if(l)return l.registerMarqueeOnPage({documentId:t,pageIndex:i,scale:v,callback:{onPreview:m}})},[l,t,i,v]),p?n.jsx("div",{style:{position:"absolute",pointerEvents:"none",left:p.origin.x*v,top:p.origin.y*v,width:p.size.width*v,height:p.size.height*v,border:`1px solid ${c}`,background:u,boxSizing:"border-box"},className:a}):null},exports.PinchWrapper=function({children:e,documentId:t,style:o,...r}){const{elementRef:i}=s(t);return n.jsx("div",{ref:i,...r,style:{...o,display:"block",width:"fit-content",overflow:"visible",boxSizing:"border-box",margin:"0px auto"},children:e})},exports.usePinch=s,exports.useZoom=e=>{const{provides:n}=r(),[i,s]=o.useState(t.initialDocumentState);return o.useEffect(()=>{if(!n)return;const t=n.forDocument(e);return s(t.getState()),t.onStateChange(e=>{s(e)})},[n,e]),{state:i,provides:(null==n?void 0:n.forDocument(e))??null}},exports.useZoomCapability=r,exports.useZoomPlugin=()=>e.usePlugin(t.ZoomPlugin.id),Object.keys(t).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-zoom.ts","../../src/shared/utils/pinch-zoom-logic.ts","../../src/shared/hooks/use-pinch-zoom.ts","../../src/shared/components/marquee-zoom.tsx","../../src/shared/components/pinch-wrapper.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { initialState, ZoomPlugin, ZoomState } from '@embedpdf/plugin-zoom';\nimport { useEffect, useState } from '@framework';\n\nexport const useZoomCapability = () => useCapability<ZoomPlugin>(ZoomPlugin.id);\nexport const useZoomPlugin = () => usePlugin<ZoomPlugin>(ZoomPlugin.id);\n\nexport const useZoom = () => {\n const { provides } = useZoomCapability();\n const [state, setState] = useState<ZoomState>(initialState);\n\n useEffect(() => {\n return provides?.onStateChange((action) => {\n setState(action);\n });\n }, [provides]);\n\n return {\n state,\n provides,\n };\n};\n","import type { ViewportCapability } from '@embedpdf/plugin-viewport';\nimport type { ZoomCapability, ZoomState } from '@embedpdf/plugin-zoom';\n\nexport interface PinchZoomDeps {\n element: HTMLDivElement;\n viewportProvides: ViewportCapability;\n zoomProvides: ZoomCapability;\n}\n\nexport function setupPinchZoom({ element, viewportProvides, zoomProvides }: PinchZoomDeps) {\n // Check if we're on the client side\n if (typeof window === 'undefined') {\n return () => {};\n }\n\n let hammer: any | undefined;\n let initialZoom = 0; // numeric scale at pinchstart\n let lastCenter = { x: 0, y: 0 };\n\n const getState = (): ZoomState => zoomProvides.getState();\n\n const updateTransform = (scale: number) => {\n // 1 → no scale; we only scale *relatively* to the start\n element.style.transform = `scale(${scale})`;\n };\n\n const resetTransform = () => {\n element.style.transform = 'none';\n element.style.transformOrigin = '0 0';\n };\n\n const pinchStart = (e: HammerInput) => {\n initialZoom = getState().currentZoomLevel;\n\n const contRect = viewportProvides.getBoundingRect();\n\n lastCenter = {\n x: e.center.x - contRect.origin.x,\n y: e.center.y - contRect.origin.y,\n };\n\n // put the transform-origin under the fingers so the preview feels right\n const innerRect = element.getBoundingClientRect();\n element.style.transformOrigin = `${e.center.x - innerRect.left}px ${e.center.y - innerRect.top}px`;\n\n // stop the browser's own pinch-zoom\n if (e.srcEvent?.cancelable) {\n e.srcEvent.preventDefault();\n e.srcEvent.stopPropagation();\n }\n };\n\n const pinchMove = (e: HammerInput) => {\n updateTransform(e.scale); // *only* CSS, no real zoom yet\n if (e.srcEvent?.cancelable) {\n e.srcEvent.preventDefault();\n e.srcEvent.stopPropagation();\n }\n };\n\n const pinchEnd = (e: HammerInput) => {\n // translate the relative hammer scale into a delta for requestZoomBy\n const delta = (e.scale - 1) * initialZoom;\n zoomProvides.requestZoomBy(delta, { vx: lastCenter.x, vy: lastCenter.y });\n\n resetTransform();\n initialZoom = 0;\n };\n\n // Async Hammer setup (internal)\n const setupHammer = async () => {\n try {\n const Hammer = (await import('hammerjs')).default;\n\n /* ------------------------------------------------------------------ */\n /* Hammer setup */\n /* ------------------------------------------------------------------ */\n const inputClass = (() => {\n const MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;\n const SUPPORT_TOUCH = 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n const SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);\n if (SUPPORT_ONLY_TOUCH) return Hammer.TouchInput;\n if (!SUPPORT_TOUCH) return Hammer.MouseInput;\n return Hammer.TouchMouseInput;\n })();\n\n hammer = new Hammer(element, {\n touchAction: 'pan-x pan-y', // allow scroll in every direction\n inputClass,\n });\n\n hammer.get('pinch').set({ enable: true, pointers: 2, threshold: 0.1 });\n\n hammer.on('pinchstart', pinchStart);\n hammer.on('pinchmove', pinchMove);\n hammer.on('pinchend', pinchEnd);\n } catch (error) {\n console.warn('Failed to load HammerJS:', error);\n }\n };\n\n setupHammer(); // Fire and forget\n\n // Return cleanup immediately\n return () => {\n hammer?.destroy();\n resetTransform();\n };\n}\n","import { useEffect, useRef } from '@framework';\nimport { useCapability } from '@embedpdf/core/@framework';\nimport { ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nimport { setupPinchZoom } from '../utils/pinch-zoom-logic';\nimport { useZoomCapability } from './use-zoom';\n\nexport function usePinch() {\n const { provides: viewportProvides } = useCapability<ViewportPlugin>('viewport');\n const { provides: zoomProvides } = useZoomCapability();\n const elementRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element || !viewportProvides || !zoomProvides) {\n return;\n }\n\n return setupPinchZoom({ element, viewportProvides, zoomProvides });\n }, [viewportProvides, zoomProvides]);\n\n return { elementRef };\n}\n","import { useEffect, useState } from '@framework';\nimport { Rect } from '@embedpdf/models';\n\nimport { useZoomCapability } from '../hooks/use-zoom';\n\ninterface MarqueeZoomProps {\n /** Index of the page this layer lives on */\n pageIndex: number;\n /** Scale of the page */\n scale: number;\n /** Optional CSS class applied to the marquee rectangle */\n className?: string;\n /** Stroke / fill colours (defaults below) */\n stroke?: string;\n fill?: string;\n}\n\nexport const MarqueeZoom = ({\n pageIndex,\n scale,\n className,\n stroke = 'rgba(33,150,243,0.8)',\n fill = 'rgba(33,150,243,0.15)',\n}: MarqueeZoomProps) => {\n const { provides: zoomPlugin } = useZoomCapability();\n const [rect, setRect] = useState<Rect | null>(null);\n\n useEffect(() => {\n if (!zoomPlugin) return;\n return zoomPlugin.registerMarqueeOnPage({\n pageIndex,\n scale,\n callback: {\n onPreview: setRect,\n },\n });\n }, [zoomPlugin, pageIndex, scale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * scale,\n top: rect.origin.y * scale,\n width: rect.size.width * scale,\n height: rect.size.height * scale,\n border: `1px solid ${stroke}`,\n background: fill,\n boxSizing: 'border-box',\n }}\n className={className}\n />\n );\n};\n","import { ReactNode, HTMLAttributes, CSSProperties } from '@framework';\n\nimport { usePinch } from '../hooks';\n\ntype PinchWrapperProps = Omit<HTMLAttributes<HTMLDivElement>, 'style'> & {\n children: ReactNode;\n style?: CSSProperties;\n};\n\nexport function PinchWrapper({ children, style, ...props }: PinchWrapperProps) {\n const { elementRef } = usePinch();\n\n return (\n <div\n ref={elementRef}\n {...props}\n style={{\n ...style,\n display: 'block',\n width: 'fit-content',\n overflow: 'visible',\n boxSizing: 'border-box',\n margin: '0px auto',\n }}\n >\n {children}\n </div>\n );\n}\n"],"names":["useZoomCapability","useCapability","ZoomPlugin","id","setupPinchZoom","element","viewportProvides","zoomProvides","window","hammer","initialZoom","lastCenter","x","y","resetTransform","style","transform","transformOrigin","pinchStart","e","getState","currentZoomLevel","contRect","getBoundingRect","center","origin","innerRect","getBoundingClientRect","left","top","_a","srcEvent","cancelable","preventDefault","stopPropagation","pinchMove","scale","pinchEnd","delta","requestZoomBy","vx","vy","async","Hammer","Promise","resolve","then","require","n","default","inputClass","SUPPORT_TOUCH","navigator","maxTouchPoints","test","userAgent","TouchInput","TouchMouseInput","MouseInput","touchAction","get","set","enable","pointers","threshold","on","error","console","warn","setupHammer","destroy","usePinch","provides","elementRef","useRef","useEffect","current","pageIndex","className","stroke","fill","zoomPlugin","rect","setRect","useState","registerMarqueeOnPage","callback","onPreview","jsxRuntime","jsx","position","pointerEvents","width","size","height","border","background","boxSizing","children","props","ref","display","overflow","margin","state","setState","initialState","onStateChange","action","usePlugin"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-zoom.ts","../../src/shared/utils/pinch-zoom-logic.ts","../../src/shared/hooks/use-pinch-zoom.ts","../../src/shared/components/marquee-zoom.tsx","../../src/shared/components/pinch-wrapper.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { initialDocumentState, ZoomDocumentState, ZoomPlugin } from '@embedpdf/plugin-zoom';\nimport { useEffect, useState } from '@framework';\n\nexport const useZoomCapability = () => useCapability<ZoomPlugin>(ZoomPlugin.id);\nexport const useZoomPlugin = () => usePlugin<ZoomPlugin>(ZoomPlugin.id);\n\n/**\n * Hook for zoom state for a specific document\n * @param documentId Document ID\n */\nexport const useZoom = (documentId: string) => {\n const { provides } = useZoomCapability();\n const [state, setState] = useState<ZoomDocumentState>(initialDocumentState);\n\n useEffect(() => {\n if (!provides) return;\n\n const scope = provides.forDocument(documentId);\n\n // Get initial state\n setState(scope.getState());\n\n // Subscribe to state changes\n return scope.onStateChange((newState) => {\n setState(newState);\n });\n }, [provides, documentId]);\n\n return {\n state,\n provides: provides?.forDocument(documentId) ?? null,\n };\n};\n","import type { ViewportCapability } from '@embedpdf/plugin-viewport';\nimport type { ZoomCapability } from '@embedpdf/plugin-zoom';\n\nexport interface PinchZoomDeps {\n element: HTMLDivElement;\n documentId: string;\n viewportProvides: ViewportCapability;\n zoomProvides: ZoomCapability;\n}\n\nexport function setupPinchZoom({\n element,\n documentId,\n viewportProvides,\n zoomProvides,\n}: PinchZoomDeps) {\n if (typeof window === 'undefined') {\n return () => {};\n }\n\n let hammer: any | undefined;\n let initialZoom = 0;\n let lastCenter = { x: 0, y: 0 };\n\n const viewportScope = viewportProvides.forDocument(documentId);\n const zoomScope = zoomProvides.forDocument(documentId);\n\n const getState = () => zoomScope.getState();\n\n const updateTransform = (scale: number) => {\n element.style.transform = `scale(${scale})`;\n };\n\n const resetTransform = () => {\n element.style.transform = 'none';\n element.style.transformOrigin = '0 0';\n };\n\n const pinchStart = (e: HammerInput) => {\n initialZoom = getState().currentZoomLevel;\n\n const contRect = viewportScope.getBoundingRect();\n\n lastCenter = {\n x: e.center.x - contRect.origin.x,\n y: e.center.y - contRect.origin.y,\n };\n\n const innerRect = element.getBoundingClientRect();\n element.style.transformOrigin = `${e.center.x - innerRect.left}px ${e.center.y - innerRect.top}px`;\n\n if (e.srcEvent?.cancelable) {\n e.srcEvent.preventDefault();\n e.srcEvent.stopPropagation();\n }\n };\n\n const pinchMove = (e: HammerInput) => {\n updateTransform(e.scale);\n if (e.srcEvent?.cancelable) {\n e.srcEvent.preventDefault();\n e.srcEvent.stopPropagation();\n }\n };\n\n const pinchEnd = (e: HammerInput) => {\n const delta = (e.scale - 1) * initialZoom;\n zoomScope.requestZoomBy(delta, { vx: lastCenter.x, vy: lastCenter.y });\n\n resetTransform();\n initialZoom = 0;\n };\n\n const setupHammer = async () => {\n try {\n const Hammer = (await import('hammerjs')).default;\n\n const inputClass = (() => {\n const MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;\n const SUPPORT_TOUCH = 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n const SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);\n if (SUPPORT_ONLY_TOUCH) return Hammer.TouchInput;\n if (!SUPPORT_TOUCH) return Hammer.MouseInput;\n return Hammer.TouchMouseInput;\n })();\n\n hammer = new Hammer(element, {\n touchAction: 'pan-x pan-y',\n inputClass,\n });\n\n hammer.get('pinch').set({ enable: true, pointers: 2, threshold: 0.1 });\n\n hammer.on('pinchstart', pinchStart);\n hammer.on('pinchmove', pinchMove);\n hammer.on('pinchend', pinchEnd);\n } catch (error) {\n console.warn('Failed to load HammerJS:', error);\n }\n };\n\n setupHammer();\n\n return () => {\n hammer?.destroy();\n resetTransform();\n };\n}\n","import { useEffect, useRef } from '@framework';\nimport { useCapability } from '@embedpdf/core/@framework';\nimport { ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { setupPinchZoom } from '../utils/pinch-zoom-logic';\nimport { useZoomCapability } from './use-zoom';\n\nexport function usePinch(documentId: string) {\n const { provides: viewportProvides } = useCapability<ViewportPlugin>('viewport');\n const { provides: zoomProvides } = useZoomCapability();\n const elementRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const element = elementRef.current;\n if (!element || !viewportProvides || !zoomProvides) {\n return;\n }\n\n return setupPinchZoom({\n element,\n documentId,\n viewportProvides,\n zoomProvides,\n });\n }, [viewportProvides, zoomProvides, documentId]);\n\n return { elementRef };\n}\n","import { useEffect, useMemo, useState } from '@framework';\nimport { Rect } from '@embedpdf/models';\nimport { useZoomCapability } from '../hooks/use-zoom';\nimport { useDocumentState } from '@embedpdf/core/@framework';\n\ninterface MarqueeZoomProps {\n documentId: string;\n pageIndex: number;\n scale?: number;\n className?: string;\n stroke?: string;\n fill?: string;\n}\n\nexport const MarqueeZoom = ({\n documentId,\n pageIndex,\n scale: scaleOverride,\n className,\n stroke = 'rgba(33,150,243,0.8)',\n fill = 'rgba(33,150,243,0.15)',\n}: MarqueeZoomProps) => {\n const { provides: zoomPlugin } = useZoomCapability();\n const documentState = useDocumentState(documentId);\n const [rect, setRect] = useState<Rect | null>(null);\n\n const actualScale = useMemo(() => {\n if (scaleOverride !== undefined) return scaleOverride;\n return documentState?.scale ?? 1;\n }, [scaleOverride, documentState?.scale]);\n\n useEffect(() => {\n if (!zoomPlugin) return;\n return zoomPlugin.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n callback: {\n onPreview: setRect,\n },\n });\n }, [zoomPlugin, documentId, pageIndex, actualScale]);\n\n if (!rect) return null;\n\n return (\n <div\n style={{\n position: 'absolute',\n pointerEvents: 'none',\n left: rect.origin.x * actualScale,\n top: rect.origin.y * actualScale,\n width: rect.size.width * actualScale,\n height: rect.size.height * actualScale,\n border: `1px solid ${stroke}`,\n background: fill,\n boxSizing: 'border-box',\n }}\n className={className}\n />\n );\n};\n","import { ReactNode, HTMLAttributes, CSSProperties } from '@framework';\nimport { usePinch } from '../hooks';\n\ntype PinchWrapperProps = Omit<HTMLAttributes<HTMLDivElement>, 'style'> & {\n children: ReactNode;\n documentId: string;\n style?: CSSProperties;\n};\n\nexport function PinchWrapper({ children, documentId, style, ...props }: PinchWrapperProps) {\n const { elementRef } = usePinch(documentId);\n\n return (\n <div\n ref={elementRef}\n {...props}\n style={{\n ...style,\n display: 'block',\n width: 'fit-content',\n overflow: 'visible',\n boxSizing: 'border-box',\n margin: '0px auto',\n }}\n >\n {children}\n </div>\n );\n}\n"],"names":["useZoomCapability","useCapability","ZoomPlugin","id","setupPinchZoom","element","documentId","viewportProvides","zoomProvides","window","hammer","initialZoom","lastCenter","x","y","viewportScope","forDocument","zoomScope","resetTransform","style","transform","transformOrigin","pinchStart","e","getState","currentZoomLevel","contRect","getBoundingRect","center","origin","innerRect","getBoundingClientRect","left","top","_a","srcEvent","cancelable","preventDefault","stopPropagation","pinchMove","scale","pinchEnd","delta","requestZoomBy","vx","vy","async","Hammer","Promise","resolve","then","require","n","default","inputClass","SUPPORT_TOUCH","navigator","maxTouchPoints","test","userAgent","TouchInput","TouchMouseInput","MouseInput","touchAction","get","set","enable","pointers","threshold","on","error","console","warn","setupHammer","destroy","usePinch","provides","elementRef","useRef","useEffect","current","pageIndex","scaleOverride","className","stroke","fill","zoomPlugin","documentState","useDocumentState","rect","setRect","useState","actualScale","useMemo","registerMarqueeOnPage","callback","onPreview","jsx","position","pointerEvents","width","size","height","border","background","boxSizing","children","props","ref","display","overflow","margin","state","setState","initialDocumentState","scope","onStateChange","newState","usePlugin"],"mappings":"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"}