@embedpdf/plugin-zoom 2.0.0 → 2.0.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.
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.js.map +1 -1
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/svelte/hooks/use-zoom.svelte.ts","../../src/shared/utils/zoom-gesture-logic.ts","../../src/svelte/hooks/use-zoom-gesture.svelte.ts","../../src/svelte/components/MarqueeZoom.svelte","../../src/svelte/components/ZoomGestureWrapper.svelte"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport {\n initialDocumentState,\n ZoomDocumentState,\n ZoomPlugin,\n ZoomScope,\n} from '@embedpdf/plugin-zoom';\n\nexport const useZoomCapability = () => useCapability<ZoomPlugin>(ZoomPlugin.id);\nexport const useZoomPlugin = () => usePlugin<ZoomPlugin>(ZoomPlugin.id);\n\n// Define the return type explicitly to maintain type safety\ninterface UseZoomReturn {\n provides: ZoomScope | null;\n state: ZoomDocumentState;\n}\n\n/**\n * Hook for zoom state for a specific document\n * @param getDocumentId Function that returns the document ID\n */\nexport const useZoom = (getDocumentId: () => string | null): UseZoomReturn => {\n const capability = useZoomCapability();\n\n let state = $state<ZoomDocumentState>(initialDocumentState);\n\n // Reactive documentId\n const documentId = $derived(getDocumentId());\n\n // Scoped capability for current docId\n const scopedProvides = $derived(\n capability.provides && documentId ? capability.provides.forDocument(documentId) : null,\n );\n\n $effect(() => {\n const provides = capability.provides;\n const docId = documentId;\n\n if (!provides || !docId) {\n state = initialDocumentState;\n return;\n }\n\n const scope = provides.forDocument(docId);\n\n // Get initial state\n state = scope.getState();\n\n // Subscribe to state changes for this document\n return scope.onStateChange((newState) => {\n state = newState;\n });\n });\n\n return {\n get provides() {\n return scopedProvides;\n },\n get state() {\n return state;\n },\n };\n};\n","import type { ZoomCapability } from '@embedpdf/plugin-zoom';\n\nexport interface ZoomGestureOptions {\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: boolean;\n}\n\nexport interface ZoomGestureDeps {\n element: HTMLDivElement;\n /** Viewport container element for attaching events */\n container: HTMLElement;\n documentId: string;\n zoomProvides: ZoomCapability;\n /** Viewport gap in pixels (default: 0) */\n viewportGap?: number;\n options?: ZoomGestureOptions;\n}\n\nfunction getTouchDistance(touches: TouchList): number {\n const [t1, t2] = [touches[0], touches[1]];\n const dx = t2.clientX - t1.clientX;\n const dy = t2.clientY - t1.clientY;\n return Math.hypot(dx, dy);\n}\n\nfunction getTouchCenter(touches: TouchList): { x: number; y: number } {\n const [t1, t2] = [touches[0], touches[1]];\n return {\n x: (t1.clientX + t2.clientX) / 2,\n y: (t1.clientY + t2.clientY) / 2,\n };\n}\n\nexport function setupZoomGestures({\n element,\n container,\n documentId,\n zoomProvides,\n viewportGap = 0,\n options = {},\n}: ZoomGestureDeps) {\n const { enablePinch = true, enableWheel = true } = options;\n if (typeof window === 'undefined') {\n return () => {};\n }\n\n const zoomScope = zoomProvides.forDocument(documentId);\n const getState = () => zoomScope.getState();\n\n // Shared state\n let initialZoom = 0;\n let currentScale = 1;\n let isPinching = false;\n let initialDistance = 0;\n\n // Wheel state\n let wheelZoomTimeout: ReturnType<typeof setTimeout> | null = null;\n let accumulatedWheelScale = 1;\n\n // Gesture state\n let initialElementWidth = 0;\n let initialElementHeight = 0;\n let initialElementLeft = 0;\n let initialElementTop = 0;\n\n // Container Dimensions (Bounding Box)\n let containerRectWidth = 0;\n let containerRectHeight = 0;\n\n // Layout Dimensions (Client Box from Metrics)\n let layoutWidth = 0;\n let layoutCenterX = 0;\n\n let pointerLocalY = 0;\n let pointerContainerX = 0;\n let pointerContainerY = 0;\n\n let currentGap = 0;\n let pivotLocalX = 0;\n\n const clamp = (val: number, min: number, max: number) => Math.min(Math.max(val, min), max);\n\n // --- Margin calculation ---\n const updateMargin = () => {\n const availableWidth = container.clientWidth - 2 * viewportGap;\n const elementWidth = element.offsetWidth;\n\n const newMargin = elementWidth < availableWidth ? (availableWidth - elementWidth) / 2 : 0;\n element.style.marginLeft = `${newMargin}px`;\n };\n\n const calculateTransform = (scale: number) => {\n const finalWidth = initialElementWidth * scale;\n const finalHeight = initialElementHeight * scale;\n\n let ty = pointerLocalY * (1 - scale);\n\n const targetX = layoutCenterX - finalWidth / 2;\n const txCenter = targetX - initialElementLeft;\n const txMouse = pointerContainerX - pivotLocalX * scale - initialElementLeft;\n\n const overflow = Math.max(0, finalWidth - layoutWidth);\n const blendRange = layoutWidth * 0.3;\n const blend = Math.min(1, overflow / blendRange);\n\n let tx = txCenter + (txMouse - txCenter) * blend;\n\n const safeHeight = containerRectHeight - currentGap * 2;\n if (finalHeight > safeHeight) {\n const currentTop = initialElementTop + ty;\n const maxTop = currentGap;\n const minTop = containerRectHeight - currentGap - finalHeight;\n const constrainedTop = clamp(currentTop, minTop, maxTop);\n ty = constrainedTop - initialElementTop;\n }\n\n const safeWidth = containerRectWidth - currentGap * 2;\n if (finalWidth > safeWidth) {\n const currentLeft = initialElementLeft + tx;\n const maxLeft = currentGap;\n const minLeft = containerRectWidth - currentGap - finalWidth;\n const constrainedLeft = clamp(currentLeft, minLeft, maxLeft);\n tx = constrainedLeft - initialElementLeft;\n }\n\n return { tx, ty, blend, finalWidth };\n };\n\n const updateTransform = (scale: number) => {\n currentScale = scale;\n const { tx, ty } = calculateTransform(scale);\n element.style.transformOrigin = '0 0';\n element.style.transform = `translate(${tx}px, ${ty}px) scale(${scale})`;\n };\n\n const resetTransform = () => {\n element.style.transform = 'none';\n element.style.transformOrigin = '0 0';\n currentScale = 1;\n };\n\n const commitZoom = () => {\n const { tx, finalWidth } = calculateTransform(currentScale);\n const delta = (currentScale - 1) * initialZoom;\n\n let anchorX: number;\n let anchorY: number = pointerContainerY;\n\n if (finalWidth <= layoutWidth) {\n anchorX = layoutCenterX;\n } else {\n const scaleDiff = 1 - currentScale;\n anchorX =\n Math.abs(scaleDiff) > 0.001 ? initialElementLeft + tx / scaleDiff : pointerContainerX;\n }\n\n zoomScope.requestZoomBy(delta, { vx: anchorX, vy: anchorY });\n resetTransform();\n initialZoom = 0;\n };\n\n const initializeGestureState = (clientX: number, clientY: number) => {\n const containerRect = container.getBoundingClientRect();\n const innerRect = element.getBoundingClientRect();\n\n currentGap = viewportGap;\n initialElementWidth = innerRect.width;\n initialElementHeight = innerRect.height;\n initialElementLeft = innerRect.left - containerRect.left;\n initialElementTop = innerRect.top - containerRect.top;\n\n containerRectWidth = containerRect.width;\n containerRectHeight = containerRect.height;\n\n // Layout dimensions from container's client area\n layoutWidth = container.clientWidth;\n layoutCenterX = container.clientLeft + layoutWidth / 2;\n\n const rawPointerLocalX = clientX - innerRect.left;\n pointerLocalY = clientY - innerRect.top;\n pointerContainerX = clientX - containerRect.left;\n pointerContainerY = clientY - containerRect.top;\n\n if (initialElementWidth < layoutWidth) {\n pivotLocalX = (pointerContainerX * initialElementWidth) / layoutWidth;\n } else {\n pivotLocalX = rawPointerLocalX;\n }\n };\n\n // --- Handlers ---\n const handleTouchStart = (e: TouchEvent) => {\n if (e.touches.length !== 2) return;\n isPinching = true;\n initialZoom = getState().currentZoomLevel;\n initialDistance = getTouchDistance(e.touches);\n const center = getTouchCenter(e.touches);\n initializeGestureState(center.x, center.y);\n e.preventDefault();\n };\n\n const handleTouchMove = (e: TouchEvent) => {\n if (!isPinching || e.touches.length !== 2) return;\n const currentDistance = getTouchDistance(e.touches);\n const scale = currentDistance / initialDistance;\n updateTransform(scale);\n e.preventDefault();\n };\n\n const handleTouchEnd = (e: TouchEvent) => {\n if (!isPinching) return;\n if (e.touches.length >= 2) return;\n isPinching = false;\n commitZoom();\n };\n\n const handleWheel = (e: WheelEvent) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n\n if (wheelZoomTimeout === null) {\n initialZoom = getState().currentZoomLevel;\n accumulatedWheelScale = 1;\n initializeGestureState(e.clientX, e.clientY);\n } else {\n clearTimeout(wheelZoomTimeout);\n }\n\n const zoomFactor = 1 - e.deltaY * 0.01;\n accumulatedWheelScale *= zoomFactor;\n accumulatedWheelScale = Math.max(0.1, Math.min(10, accumulatedWheelScale));\n updateTransform(accumulatedWheelScale);\n\n wheelZoomTimeout = setTimeout(() => {\n wheelZoomTimeout = null;\n commitZoom();\n accumulatedWheelScale = 1;\n }, 150);\n };\n\n // Subscribe to zoom changes to update margin\n const unsubZoom = zoomScope.onStateChange(() => updateMargin());\n\n // Use ResizeObserver to update margin when element or container size changes\n const resizeObserver = new ResizeObserver(() => updateMargin());\n resizeObserver.observe(element);\n resizeObserver.observe(container);\n\n // Initial margin calculation\n updateMargin();\n\n // Attach events to the viewport container for better UX\n // (gestures work anywhere in viewport, not just on the PDF)\n if (enablePinch) {\n container.addEventListener('touchstart', handleTouchStart, { passive: false });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd);\n container.addEventListener('touchcancel', handleTouchEnd);\n }\n if (enableWheel) {\n container.addEventListener('wheel', handleWheel, { passive: false });\n }\n\n return () => {\n if (enablePinch) {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchEnd);\n }\n if (enableWheel) {\n container.removeEventListener('wheel', handleWheel);\n }\n if (wheelZoomTimeout) {\n clearTimeout(wheelZoomTimeout);\n }\n unsubZoom();\n resizeObserver.disconnect();\n resetTransform();\n element.style.marginLeft = '';\n };\n}\n","import { getContext } from 'svelte';\nimport { useCapability } from '@embedpdf/core/svelte';\nimport type { ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { setupZoomGestures, type ZoomGestureOptions } from '../../shared/utils/zoom-gesture-logic';\nimport { useZoomCapability } from './use-zoom.svelte';\n\nexport type { ZoomGestureOptions };\n\n/** Context type for viewport element */\ntype ViewportElementContext = { readonly current: HTMLDivElement | null };\n\nexport interface UseZoomGestureOptions {\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: () => boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: () => boolean;\n}\n\n/**\n * Hook for setting up zoom gesture functionality (pinch and wheel zoom) on an element\n * @param getDocumentId Function that returns the document ID\n * @param options Optional configuration for enabling/disabling gestures\n */\nexport function useZoomGesture(\n getDocumentId: () => string | null,\n options: UseZoomGestureOptions = {},\n) {\n const viewportCapability = useCapability<ViewportPlugin>('viewport');\n const zoomCapability = useZoomCapability();\n const viewportElementCtx = getContext<ViewportElementContext | undefined>('viewport-element');\n\n let elementRef = $state<HTMLDivElement | null>(null);\n let cleanup: (() => void) | undefined;\n\n // Reactive documentId and options\n const documentId = $derived(getDocumentId());\n const enablePinch = $derived(options.enablePinch?.() ?? true);\n const enableWheel = $derived(options.enableWheel?.() ?? true);\n\n $effect(() => {\n const element = elementRef;\n const container = viewportElementCtx?.current;\n const viewport = viewportCapability.provides;\n const zoom = zoomCapability.provides;\n const docId = documentId;\n const pinchEnabled = enablePinch;\n const wheelEnabled = enableWheel;\n\n // Clean up previous setup\n if (cleanup) {\n cleanup();\n cleanup = undefined;\n }\n\n // Setup new zoom gestures if all dependencies are available\n if (!element || !container || !zoom || !docId) {\n return;\n }\n\n cleanup = setupZoomGestures({\n element,\n container,\n documentId: docId,\n zoomProvides: zoom,\n viewportGap: viewport?.getViewportGap() || 0,\n options: { enablePinch: pinchEnabled, enableWheel: wheelEnabled },\n });\n\n return () => {\n if (cleanup) {\n cleanup();\n cleanup = undefined;\n }\n };\n });\n\n return {\n get elementRef() {\n return elementRef;\n },\n set elementRef(value: HTMLDivElement | null) {\n elementRef = value;\n },\n };\n}\n","<script lang=\"ts\">\n import type { Rect } from '@embedpdf/models';\n import { useDocumentState } from '@embedpdf/core/svelte';\n import { useZoomCapability } from '../hooks/use-zoom.svelte';\n\n interface MarqueeZoomProps {\n /** The ID of the document */\n documentId: string;\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 class?: string;\n /** Stroke / fill colours (defaults below) */\n stroke?: string;\n fill?: string;\n }\n\n let {\n documentId,\n pageIndex,\n scale: scaleOverride,\n class: propsClass,\n stroke = 'rgba(33,150,243,0.8)',\n fill = 'rgba(33,150,243,0.15)',\n }: MarqueeZoomProps = $props();\n\n const zoomCapability = useZoomCapability();\n const documentState = useDocumentState(() => documentId);\n\n let rect = $state<Rect | null>(null);\n\n const actualScale = $derived(\n scaleOverride !== undefined ? scaleOverride : (documentState.current?.scale ?? 1),\n );\n\n $effect(() => {\n rect = null;\n\n if (!zoomCapability.provides) {\n return;\n }\n\n return zoomCapability.provides.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n callback: {\n onPreview: (newRect) => {\n rect = newRect;\n },\n },\n });\n });\n</script>\n\n{#if rect}\n <div\n style:position=\"absolute\"\n style:pointer-events=\"none\"\n style:left={`${rect.origin.x * actualScale}px`}\n style:top={`${rect.origin.y * actualScale}px`}\n style:width={`${rect.size.width * actualScale}px`}\n style:height={`${rect.size.height * actualScale}px`}\n style:border={`1px solid ${stroke}`}\n style:background={fill}\n style:box-sizing=\"border-box\"\n class={propsClass}\n ></div>\n{/if}\n","<script lang=\"ts\">\n import { useZoomGesture } from '../hooks';\n import type { Snippet } from 'svelte';\n import type { HTMLAttributes } from 'svelte/elements';\n\n type ZoomGestureWrapperProps = Omit<HTMLAttributes<HTMLDivElement>, 'style'> & {\n documentId: string;\n children: Snippet;\n class?: string;\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: boolean;\n };\n\n let {\n documentId,\n children,\n class: propsClass,\n enablePinch = true,\n enableWheel = true,\n ...restProps\n }: ZoomGestureWrapperProps = $props();\n\n const zoomGesture = useZoomGesture(() => documentId, {\n enablePinch: () => enablePinch,\n enableWheel: () => enableWheel,\n });\n</script>\n\n<div\n bind:this={zoomGesture.elementRef}\n {...restProps}\n style:display=\"inline-block\"\n style:overflow=\"visible\"\n style:box-sizing=\"border-box\"\n class={propsClass}\n>\n {@render children()}\n</div>\n"],"names":["useZoomCapability","useCapability","ZoomPlugin","id","getTouchDistance","touches","t1","t2","dx","clientX","dy","clientY","Math","hypot","useZoomGesture","getDocumentId","options","viewportCapability","zoomCapability","viewportElementCtx","getContext","cleanup","elementRef","documentId","enablePinch","$","derived","_a","call","enableWheel","user_effect","element","container","current","viewport","provides","zoom","docId","pinchEnabled","wheelEnabled","zoomProvides","viewportGap","window","zoomScope","forDocument","getState","initialZoom","currentScale","isPinching","initialDistance","wheelZoomTimeout","accumulatedWheelScale","initialElementWidth","initialElementHeight","initialElementLeft","initialElementTop","containerRectWidth","containerRectHeight","layoutWidth","layoutCenterX","pointerLocalY","pointerContainerX","pointerContainerY","currentGap","pivotLocalX","clamp","val","min","max","updateMargin","availableWidth","clientWidth","elementWidth","offsetWidth","newMargin","style","marginLeft","calculateTransform","scale","finalWidth","finalHeight","ty","txCenter","txMouse","overflow","blendRange","blend","tx","updateTransform","transformOrigin","transform","resetTransform","commitZoom","delta","anchorX","anchorY","scaleDiff","abs","requestZoomBy","vx","vy","initializeGestureState","containerRect","getBoundingClientRect","innerRect","width","height","left","top","clientLeft","rawPointerLocalX","handleTouchStart","e","length","currentZoomLevel","center","x","y","getTouchCenter","preventDefault","handleTouchMove","currentDistance","handleTouchEnd","handleWheel","ctrlKey","metaKey","clearTimeout","zoomFactor","deltaY","setTimeout","unsubZoom","onStateChange","resizeObserver","ResizeObserver","observe","addEventListener","passive","removeEventListener","disconnect","setupZoomGestures","getViewportGap","value","set","stroke","fill","documentState","useDocumentState","$$props","rect","actualScale","registerMarqueeOnPage","pageIndex","callback","onPreview","newRect","get","origin","size","consequent","restProps","rest_props","zoomGesture","bind_this","div","$$value","capability","state","initialDocumentState","scopedProvides","scope","newState","usePlugin"],"mappings":"whBAQaA,EAAA,IAA0BC,gBAA0BC,EAAAA,WAAWC,ICY5E,SAASC,EAAiBC,GACxB,MAAOC,EAAIC,GAAM,CAACF,EAAQ,GAAIA,EAAQ,IAChCG,EAAKD,EAAGE,QAAUH,EAAGG,QACrBC,EAAKH,EAAGI,QAAUL,EAAGK,QAC3B,OAAOC,KAAKC,MAAML,EAAIE,EACxB,CCFgB,SAAAI,EACdC,EACAC,YAEMC,EAAqBhB,EAAAA,cAA8B,YACnDiB,EAAiBlB,IACjBmB,EAAqBC,EAAAA,WAA+C,oBAEtE,IACAC,EADAC,UAA2C,MAIzC,MAAAC,YAAsBR,GACtBS,EAAAC,EAAAC,QAAA,WAAuB,OAAA,OAAAC,EAAAX,EAAQQ,kBAAR,EAAAG,EAAAC,KAAAZ,MAA2B,IAClDa,EAAAJ,EAAAC,QAAA,WAAuB,OAAA,OAAAC,EAAAX,EAAQa,kBAAR,EAAAF,EAAAC,KAAAZ,MAA2B,WAExDS,EAAAK,iBACQ,MAAAC,QAAUT,GACVU,EAAY,MAAAb,OAAA,EAAAA,EAAoBc,QAChCC,EAAWjB,EAAmBkB,SAC9BC,EAAOlB,EAAeiB,SACtBE,QAAQd,GACRe,QAAed,GACfe,QAAeV,GAShB,GANDR,IACFA,IACAA,UAIGU,GAAYC,GAAcI,GAASC,SAIxChB,EDxBG,UAA2BU,QAChCA,EAAAC,UACAA,EAAAT,WACAA,EAAAiB,aACAA,EAAAC,YACAA,EAAc,EAAAzB,QACdA,EAAU,CAAA,IAEV,MAAMQ,YAAEA,GAAc,EAAAK,YAAMA,GAAc,GAASb,EACnD,GAAsB,oBAAX0B,OACT,MAAO,OAGT,MAAMC,EAAYH,EAAaI,YAAYrB,GACrCsB,EAAW,IAAMF,EAAUE,WAGjC,IAAIC,EAAc,EACdC,EAAe,EACfC,GAAa,EACbC,EAAkB,EAGlBC,EAAyD,KACzDC,EAAwB,EAGxBC,EAAsB,EACtBC,EAAuB,EACvBC,EAAqB,EACrBC,EAAoB,EAGpBC,EAAqB,EACrBC,EAAsB,EAGtBC,EAAc,EACdC,EAAgB,EAEhBC,EAAgB,EAChBC,EAAoB,EACpBC,EAAoB,EAEpBC,EAAa,EACbC,EAAc,EAElB,MAAMC,EAAQ,CAACC,EAAaC,EAAaC,IAAgBxD,KAAKuD,IAAIvD,KAAKwD,IAAIF,EAAKC,GAAMC,GAGhFC,EAAe,KACnB,MAAMC,EAAiBtC,EAAUuC,YAAc,EAAI9B,EAC7C+B,EAAezC,EAAQ0C,YAEvBC,EAAYF,EAAeF,GAAkBA,EAAiBE,GAAgB,EAAI,EACxFzC,EAAQ4C,MAAMC,WAAa,GAAGF,OAG1BG,EAAsBC,IAC1B,MAAMC,EAAa3B,EAAsB0B,EACnCE,EAAc3B,EAAuByB,EAE3C,IAAIG,EAAKrB,GAAiB,EAAIkB,GAE9B,MACMI,EADUvB,EAAgBoB,EAAa,EAClBzB,EACrB6B,EAAUtB,EAAoBG,EAAcc,EAAQxB,EAEpD8B,EAAWxE,KAAKwD,IAAI,EAAGW,EAAarB,GACpC2B,EAA2B,GAAd3B,EACb4B,EAAQ1E,KAAKuD,IAAI,EAAGiB,EAAWC,GAErC,IAAIE,EAAKL,GAAYC,EAAUD,GAAYI,EAoB3C,OAjBIN,EADevB,EAAmC,EAAbM,IAMvCkB,EADuBhB,EAHJV,EAAoB0B,EAExBxB,EAAsBM,EAAaiB,EADnCjB,GAGOR,GAIpBwB,EADcvB,EAAkC,EAAbO,IAMrCwB,EADwBtB,EAHJX,EAAqBiC,EAEzB/B,EAAqBO,EAAagB,EADlChB,GAGOT,GAGlB,CAAEiC,KAAIN,KAAIK,QAAOP,eAGpBS,EAAmBV,IACvB/B,EAAe+B,EACf,MAAMS,GAAEA,EAAAN,GAAIA,GAAOJ,EAAmBC,GACtC/C,EAAQ4C,MAAMc,gBAAkB,MAChC1D,EAAQ4C,MAAMe,UAAY,aAAaH,QAASN,cAAeH,MAG3Da,EAAiB,KACrB5D,EAAQ4C,MAAMe,UAAY,OAC1B3D,EAAQ4C,MAAMc,gBAAkB,MAChC1C,EAAe,GAGX6C,EAAa,KACjB,MAAML,GAAEA,EAAAR,WAAIA,GAAeF,EAAmB9B,GACxC8C,GAAS9C,EAAe,GAAKD,EAEnC,IAAIgD,EACAC,EAAkBjC,EAEtB,GAAIiB,GAAcrB,EAChBoC,EAAUnC,MACL,CACL,MAAMqC,EAAY,EAAIjD,EACtB+C,EACElF,KAAKqF,IAAID,GAAa,KAAQ1C,EAAqBiC,EAAKS,EAAYnC,CACxE,CAEAlB,EAAUuD,cAAcL,EAAO,CAAEM,GAAIL,EAASM,GAAIL,IAClDJ,IACA7C,EAAc,GAGVuD,EAAyB,CAAC5F,EAAiBE,KAC/C,MAAM2F,EAAgBtE,EAAUuE,wBAC1BC,EAAYzE,EAAQwE,wBAE1BxC,EAAatB,EACbW,EAAsBoD,EAAUC,MAChCpD,EAAuBmD,EAAUE,OACjCpD,EAAqBkD,EAAUG,KAAOL,EAAcK,KACpDpD,EAAoBiD,EAAUI,IAAMN,EAAcM,IAElDpD,EAAqB8C,EAAcG,MACnChD,EAAsB6C,EAAcI,OAGpChD,EAAc1B,EAAUuC,YACxBZ,EAAgB3B,EAAU6E,WAAanD,EAAc,EAErD,MAAMoD,EAAmBrG,EAAU+F,EAAUG,KAC7C/C,EAAgBjD,EAAU6F,EAAUI,IACpC/C,EAAoBpD,EAAU6F,EAAcK,KAC5C7C,EAAoBnD,EAAU2F,EAAcM,IAG1C5C,EADEZ,EAAsBM,EACTG,EAAoBT,EAAuBM,EAE5CoD,GAKZC,EAAoBC,IACxB,GAAyB,IAArBA,EAAE3G,QAAQ4G,OAAc,OAC5BjE,GAAa,EACbF,EAAcD,IAAWqE,iBACzBjE,EAAkB7C,EAAiB4G,EAAE3G,SACrC,MAAM8G,EA3KV,SAAwB9G,GACtB,MAAOC,EAAIC,GAAM,CAACF,EAAQ,GAAIA,EAAQ,IACtC,MAAO,CACL+G,GAAI9G,EAAGG,QAAUF,EAAGE,SAAW,EAC/B4G,GAAI/G,EAAGK,QAAUJ,EAAGI,SAAW,EAEnC,CAqKmB2G,CAAeN,EAAE3G,SAChCgG,EAAuBc,EAAOC,EAAGD,EAAOE,GACxCL,EAAEO,kBAGEC,EAAmBR,IACvB,IAAKhE,GAAmC,IAArBgE,EAAE3G,QAAQ4G,OAAc,OAC3C,MAAMQ,EAAkBrH,EAAiB4G,EAAE3G,SAE3CmF,EADciC,EAAkBxE,GAEhC+D,EAAEO,kBAGEG,EAAkBV,IACjBhE,IACDgE,EAAE3G,QAAQ4G,QAAU,IACxBjE,GAAa,EACb4C,OAGI+B,EAAeX,IACnB,IAAKA,EAAEY,UAAYZ,EAAEa,QAAS,OAC9Bb,EAAEO,iBAEuB,OAArBrE,GACFJ,EAAcD,IAAWqE,iBACzB/D,EAAwB,EACxBkD,EAAuBW,EAAEvG,QAASuG,EAAErG,UAEpCmH,aAAa5E,GAGf,MAAM6E,EAAa,EAAe,IAAXf,EAAEgB,OACzB7E,GAAyB4E,EACzB5E,EAAwBvC,KAAKwD,IAAI,GAAKxD,KAAKuD,IAAI,GAAIhB,IACnDqC,EAAgBrC,GAEhBD,EAAmB+E,WAAW,KAC5B/E,EAAmB,KACnB0C,IACAzC,EAAwB,GACvB,MAIC+E,EAAYvF,EAAUwF,cAAc,IAAM9D,KAG1C+D,EAAiB,IAAIC,eAAe,IAAMhE,KAmBhD,OAlBA+D,EAAeE,QAAQvG,GACvBqG,EAAeE,QAAQtG,GAGvBqC,IAII7C,IACFQ,EAAUuG,iBAAiB,aAAcxB,EAAkB,CAAEyB,SAAS,IACtExG,EAAUuG,iBAAiB,YAAaf,EAAiB,CAAEgB,SAAS,IACpExG,EAAUuG,iBAAiB,WAAYb,GACvC1F,EAAUuG,iBAAiB,cAAeb,IAExC7F,GACFG,EAAUuG,iBAAiB,QAASZ,EAAa,CAAEa,SAAS,IAGvD,KACDhH,IACFQ,EAAUyG,oBAAoB,aAAc1B,GAC5C/E,EAAUyG,oBAAoB,YAAajB,GAC3CxF,EAAUyG,oBAAoB,WAAYf,GAC1C1F,EAAUyG,oBAAoB,cAAef,IAE3C7F,GACFG,EAAUyG,oBAAoB,QAASd,GAErCzE,GACF4E,aAAa5E,GAEfgF,IACAE,EAAeM,aACf/C,IACA5D,EAAQ4C,MAAMC,WAAa,GAE/B,CChOc+D,CAAA,CACR5G,UACAC,YACAT,WAAYc,EACZG,aAAcJ,EACdK,mBAAaP,WAAU0G,mBAAoB,EAC3C5H,SAAWQ,YAAac,EAAcT,YAAaU,UAI/ClB,IACFA,IACAA,cAMA,cAAAC,gBACKA,EACT,gBACIA,CAAWuH,GACbpH,EAAAqH,IAAAxH,EAAauH,GAAA,EACf,EAEJ,qHC5DI,IAAAE,sBAAS,wBACTC,oBAAO,yBAGH,MAAA9H,EAAiBlB,IACjBiJ,EAAgBC,EAAAA,iBAAgB,IAAAC,EAAA5H,YAElC,IAAA6H,UAA2B,YAEzBC,EAAW5H,EAAAC,QAAA,WAAA,YACG,IADHyH,EAAArE,MACYqE,EAAArE,OAAoB,OAAAnD,EAAAsH,EAAchH,kBAAS6C,QAAS,IAGjFrD,EAAAK,YAAO,QACLL,EAAAqH,IAAAM,EAAO,MAEFlI,EAAeiB,gBAIbjB,EAAeiB,SAASmH,sBAAqB,CAClD/H,WAAU4H,EAAA5H,WACVgI,UAASJ,EAAAI,UACTzE,YAAOuE,GACPG,SAAQ,CACNC,UAAYC,IACVjI,EAAAqH,IAAAM,EAAOM,GAAO,8LAWL/C,KAAAlF,EAAAkI,IAAAP,GAAKQ,OAAOxC,QAAIiC,GAAhB,KACDzC,IAAAnF,EAAAkI,IAAAP,GAAKQ,OAAOvC,QAAIgC,GAAhB,KACE5C,MAAAhF,EAAAkI,IAAAP,GAAKS,KAAKpD,YAAQ4C,GAAlB,KACC3C,OAAAjF,EAAAkI,IAAAP,GAAKS,KAAKnD,aAAS2C,GAAnB,yBACUN,iBACTC,kEATjBI,MAAIU,0BAFT,wDCpCI,IAAAtI,4BAAc,GACdK,4BAAc,GACXkI,EAAQtI,EAAAuI,WAAAb,EAAA,+FAGP,MAAAc,EAAcnJ,EAAc,IAAAqI,EAAA5H,WAAA,CAChCC,gBAAmBA,IACnBK,gBAAmBA,8CAMjBkI,2JADOtI,EAAAyI,UAAAC,EAAAC,GAAAH,EAAY3I,WAAU8I,EAAA,IAAtB,MAAAH,OAAA,EAAAA,EAAY3I,iCAHzB,kBJPwBP,IAChB,MAAAsJ,EAAarK,IAEf,IAAAsK,kBAAkCC,EAAAA,uBAGhC,MAAAhJ,YAAsBR,GAGtByJ,EAAA/I,EAAAC,QAAA,IACJ2I,EAAWlI,gBAAYZ,GAAa8I,EAAWlI,SAASS,kBAAYrB,IAAc,aAGpFE,EAAAK,uBACQK,EAAWkI,EAAWlI,SACtBE,QAAQd,OAETY,IAAaE,cAChBZ,EAAAqH,IAAAwB,EAAQC,EAAAA,sBAAA,GAIJ,MAAAE,EAAQtI,EAASS,YAAYP,GAM5B,aAHPiI,EAAQG,EAAM5H,YAAA,GAGP4H,EAAMtC,cAAeuC,IAC1BjJ,EAAAqH,IAAAwB,EAAQI,GAAA,QAKN,YAAAvI,gBACKqI,EACT,EACI,SAAAF,gBACKA,EACT,+EAnDS,IAAsBK,YAAsBzK,EAAAA,WAAWC"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/svelte/hooks/use-zoom.svelte.ts","../../src/shared/utils/zoom-gesture-logic.ts","../../src/svelte/hooks/use-zoom-gesture.svelte.ts","../../src/svelte/components/MarqueeZoom.svelte","../../src/svelte/components/ZoomGestureWrapper.svelte"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport {\n initialDocumentState,\n ZoomDocumentState,\n ZoomPlugin,\n ZoomScope,\n} from '@embedpdf/plugin-zoom';\n\nexport const useZoomCapability = () => useCapability<ZoomPlugin>(ZoomPlugin.id);\nexport const useZoomPlugin = () => usePlugin<ZoomPlugin>(ZoomPlugin.id);\n\n// Define the return type explicitly to maintain type safety\ninterface UseZoomReturn {\n provides: ZoomScope | null;\n state: ZoomDocumentState;\n}\n\n/**\n * Hook for zoom state for a specific document\n * @param getDocumentId Function that returns the document ID\n */\nexport const useZoom = (getDocumentId: () => string | null): UseZoomReturn => {\n const capability = useZoomCapability();\n\n let state = $state<ZoomDocumentState>(initialDocumentState);\n\n // Reactive documentId\n const documentId = $derived(getDocumentId());\n\n // Scoped capability for current docId\n const scopedProvides = $derived(\n capability.provides && documentId ? capability.provides.forDocument(documentId) : null,\n );\n\n $effect(() => {\n const provides = capability.provides;\n const docId = documentId;\n\n if (!provides || !docId) {\n state = initialDocumentState;\n return;\n }\n\n const scope = provides.forDocument(docId);\n\n // Get initial state\n state = scope.getState();\n\n // Subscribe to state changes for this document\n return scope.onStateChange((newState) => {\n state = newState;\n });\n });\n\n return {\n get provides() {\n return scopedProvides;\n },\n get state() {\n return state;\n },\n };\n};\n","import type { ZoomCapability } from '@embedpdf/plugin-zoom';\n\nexport interface ZoomGestureOptions {\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: boolean;\n}\n\nexport interface ZoomGestureDeps {\n element: HTMLDivElement;\n /** Viewport container element for attaching events */\n container: HTMLElement;\n documentId: string;\n zoomProvides: ZoomCapability;\n /** Viewport gap in pixels (default: 0) */\n viewportGap?: number;\n options?: ZoomGestureOptions;\n}\n\nfunction getTouchDistance(touches: TouchList): number {\n const [t1, t2] = [touches[0], touches[1]];\n const dx = t2.clientX - t1.clientX;\n const dy = t2.clientY - t1.clientY;\n return Math.hypot(dx, dy);\n}\n\nfunction getTouchCenter(touches: TouchList): { x: number; y: number } {\n const [t1, t2] = [touches[0], touches[1]];\n return {\n x: (t1.clientX + t2.clientX) / 2,\n y: (t1.clientY + t2.clientY) / 2,\n };\n}\n\nexport function setupZoomGestures({\n element,\n container,\n documentId,\n zoomProvides,\n viewportGap = 0,\n options = {},\n}: ZoomGestureDeps) {\n const { enablePinch = true, enableWheel = true } = options;\n if (typeof window === 'undefined') {\n return () => {};\n }\n\n const zoomScope = zoomProvides.forDocument(documentId);\n const getState = () => zoomScope.getState();\n\n // Shared state\n let initialZoom = 0;\n let currentScale = 1;\n let isPinching = false;\n let initialDistance = 0;\n\n // Wheel state\n let wheelZoomTimeout: ReturnType<typeof setTimeout> | null = null;\n let accumulatedWheelScale = 1;\n\n // Gesture state\n let initialElementWidth = 0;\n let initialElementHeight = 0;\n let initialElementLeft = 0;\n let initialElementTop = 0;\n\n // Container Dimensions (Bounding Box)\n let containerRectWidth = 0;\n let containerRectHeight = 0;\n\n // Layout Dimensions (Client Box from Metrics)\n let layoutWidth = 0;\n let layoutCenterX = 0;\n\n let pointerLocalY = 0;\n let pointerContainerX = 0;\n let pointerContainerY = 0;\n\n let currentGap = 0;\n let pivotLocalX = 0;\n\n const clamp = (val: number, min: number, max: number) => Math.min(Math.max(val, min), max);\n\n // --- Margin calculation ---\n const updateMargin = () => {\n const availableWidth = container.clientWidth - 2 * viewportGap;\n const elementWidth = element.offsetWidth;\n\n const newMargin = elementWidth < availableWidth ? (availableWidth - elementWidth) / 2 : 0;\n element.style.marginLeft = `${newMargin}px`;\n };\n\n const calculateTransform = (scale: number) => {\n const finalWidth = initialElementWidth * scale;\n const finalHeight = initialElementHeight * scale;\n\n let ty = pointerLocalY * (1 - scale);\n\n const targetX = layoutCenterX - finalWidth / 2;\n const txCenter = targetX - initialElementLeft;\n const txMouse = pointerContainerX - pivotLocalX * scale - initialElementLeft;\n\n const overflow = Math.max(0, finalWidth - layoutWidth);\n const blendRange = layoutWidth * 0.3;\n const blend = Math.min(1, overflow / blendRange);\n\n let tx = txCenter + (txMouse - txCenter) * blend;\n\n const safeHeight = containerRectHeight - currentGap * 2;\n if (finalHeight > safeHeight) {\n const currentTop = initialElementTop + ty;\n const maxTop = currentGap;\n const minTop = containerRectHeight - currentGap - finalHeight;\n const constrainedTop = clamp(currentTop, minTop, maxTop);\n ty = constrainedTop - initialElementTop;\n }\n\n const safeWidth = containerRectWidth - currentGap * 2;\n if (finalWidth > safeWidth) {\n const currentLeft = initialElementLeft + tx;\n const maxLeft = currentGap;\n const minLeft = containerRectWidth - currentGap - finalWidth;\n const constrainedLeft = clamp(currentLeft, minLeft, maxLeft);\n tx = constrainedLeft - initialElementLeft;\n }\n\n return { tx, ty, blend, finalWidth };\n };\n\n const updateTransform = (scale: number) => {\n currentScale = scale;\n const { tx, ty } = calculateTransform(scale);\n element.style.transformOrigin = '0 0';\n element.style.transform = `translate(${tx}px, ${ty}px) scale(${scale})`;\n };\n\n const resetTransform = () => {\n element.style.transform = 'none';\n element.style.transformOrigin = '0 0';\n currentScale = 1;\n };\n\n const commitZoom = () => {\n const { tx, finalWidth } = calculateTransform(currentScale);\n const delta = (currentScale - 1) * initialZoom;\n\n let anchorX: number;\n let anchorY: number = pointerContainerY;\n\n if (finalWidth <= layoutWidth) {\n anchorX = layoutCenterX;\n } else {\n const scaleDiff = 1 - currentScale;\n anchorX =\n Math.abs(scaleDiff) > 0.001 ? initialElementLeft + tx / scaleDiff : pointerContainerX;\n }\n\n zoomScope.requestZoomBy(delta, { vx: anchorX, vy: anchorY });\n resetTransform();\n initialZoom = 0;\n };\n\n const initializeGestureState = (clientX: number, clientY: number) => {\n const containerRect = container.getBoundingClientRect();\n const innerRect = element.getBoundingClientRect();\n\n currentGap = viewportGap;\n initialElementWidth = innerRect.width;\n initialElementHeight = innerRect.height;\n initialElementLeft = innerRect.left - containerRect.left;\n initialElementTop = innerRect.top - containerRect.top;\n\n containerRectWidth = containerRect.width;\n containerRectHeight = containerRect.height;\n\n // Layout dimensions from container's client area\n layoutWidth = container.clientWidth;\n layoutCenterX = container.clientLeft + layoutWidth / 2;\n\n const rawPointerLocalX = clientX - innerRect.left;\n pointerLocalY = clientY - innerRect.top;\n pointerContainerX = clientX - containerRect.left;\n pointerContainerY = clientY - containerRect.top;\n\n if (initialElementWidth < layoutWidth) {\n pivotLocalX = (pointerContainerX * initialElementWidth) / layoutWidth;\n } else {\n pivotLocalX = rawPointerLocalX;\n }\n };\n\n // --- Handlers ---\n const handleTouchStart = (e: TouchEvent) => {\n if (e.touches.length !== 2) return;\n isPinching = true;\n initialZoom = getState().currentZoomLevel;\n initialDistance = getTouchDistance(e.touches);\n const center = getTouchCenter(e.touches);\n initializeGestureState(center.x, center.y);\n e.preventDefault();\n };\n\n const handleTouchMove = (e: TouchEvent) => {\n if (!isPinching || e.touches.length !== 2) return;\n const currentDistance = getTouchDistance(e.touches);\n const scale = currentDistance / initialDistance;\n updateTransform(scale);\n e.preventDefault();\n };\n\n const handleTouchEnd = (e: TouchEvent) => {\n if (!isPinching) return;\n if (e.touches.length >= 2) return;\n isPinching = false;\n commitZoom();\n };\n\n const handleWheel = (e: WheelEvent) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n\n if (wheelZoomTimeout === null) {\n initialZoom = getState().currentZoomLevel;\n accumulatedWheelScale = 1;\n initializeGestureState(e.clientX, e.clientY);\n } else {\n clearTimeout(wheelZoomTimeout);\n }\n\n const zoomFactor = 1 - e.deltaY * 0.01;\n accumulatedWheelScale *= zoomFactor;\n accumulatedWheelScale = Math.max(0.1, Math.min(10, accumulatedWheelScale));\n updateTransform(accumulatedWheelScale);\n\n wheelZoomTimeout = setTimeout(() => {\n wheelZoomTimeout = null;\n commitZoom();\n accumulatedWheelScale = 1;\n }, 150);\n };\n\n // Subscribe to zoom changes to update margin\n const unsubZoom = zoomScope.onStateChange(() => updateMargin());\n\n // Use ResizeObserver to update margin when element or container size changes\n const resizeObserver = new ResizeObserver(() => updateMargin());\n resizeObserver.observe(element);\n resizeObserver.observe(container);\n\n // Initial margin calculation\n updateMargin();\n\n // Attach events to the viewport container for better UX\n // (gestures work anywhere in viewport, not just on the PDF)\n if (enablePinch) {\n container.addEventListener('touchstart', handleTouchStart, { passive: false });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd);\n container.addEventListener('touchcancel', handleTouchEnd);\n }\n if (enableWheel) {\n container.addEventListener('wheel', handleWheel, { passive: false });\n }\n\n return () => {\n if (enablePinch) {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchEnd);\n }\n if (enableWheel) {\n container.removeEventListener('wheel', handleWheel);\n }\n if (wheelZoomTimeout) {\n clearTimeout(wheelZoomTimeout);\n }\n unsubZoom();\n resizeObserver.disconnect();\n resetTransform();\n element.style.marginLeft = '';\n };\n}\n","import { getContext } from 'svelte';\nimport { useCapability } from '@embedpdf/core/svelte';\nimport type { ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { setupZoomGestures, type ZoomGestureOptions } from '../../shared/utils/zoom-gesture-logic';\nimport { useZoomCapability } from './use-zoom.svelte';\n\nexport type { ZoomGestureOptions };\n\n/** Context type for viewport element */\ntype ViewportElementContext = { readonly current: HTMLDivElement | null };\n\nexport interface UseZoomGestureOptions {\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: () => boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: () => boolean;\n}\n\n/**\n * Hook for setting up zoom gesture functionality (pinch and wheel zoom) on an element\n * @param getDocumentId Function that returns the document ID\n * @param options Optional configuration for enabling/disabling gestures\n */\nexport function useZoomGesture(\n getDocumentId: () => string | null,\n options: UseZoomGestureOptions = {},\n) {\n const viewportCapability = useCapability<ViewportPlugin>('viewport');\n const zoomCapability = useZoomCapability();\n const viewportElementCtx = getContext<ViewportElementContext | undefined>('viewport-element');\n\n let elementRef = $state<HTMLDivElement | null>(null);\n let cleanup: (() => void) | undefined;\n\n // Reactive documentId and options\n const documentId = $derived(getDocumentId());\n const enablePinch = $derived(options.enablePinch?.() ?? true);\n const enableWheel = $derived(options.enableWheel?.() ?? true);\n\n $effect(() => {\n const element = elementRef;\n const container = viewportElementCtx?.current;\n const viewport = viewportCapability.provides;\n const zoom = zoomCapability.provides;\n const docId = documentId;\n const pinchEnabled = enablePinch;\n const wheelEnabled = enableWheel;\n\n // Clean up previous setup\n if (cleanup) {\n cleanup();\n cleanup = undefined;\n }\n\n // Setup new zoom gestures if all dependencies are available\n if (!element || !container || !zoom || !docId) {\n return;\n }\n\n cleanup = setupZoomGestures({\n element,\n container,\n documentId: docId,\n zoomProvides: zoom,\n viewportGap: viewport?.getViewportGap() || 0,\n options: { enablePinch: pinchEnabled, enableWheel: wheelEnabled },\n });\n\n return () => {\n if (cleanup) {\n cleanup();\n cleanup = undefined;\n }\n };\n });\n\n return {\n get elementRef() {\n return elementRef;\n },\n set elementRef(value: HTMLDivElement | null) {\n elementRef = value;\n },\n };\n}\n","<script lang=\"ts\">\n import type { Rect } from '@embedpdf/models';\n import { useDocumentState } from '@embedpdf/core/svelte';\n import { useZoomCapability } from '../hooks/use-zoom.svelte';\n\n interface MarqueeZoomProps {\n /** The ID of the document */\n documentId: string;\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 class?: string;\n /** Stroke / fill colours (defaults below) */\n stroke?: string;\n fill?: string;\n }\n\n let {\n documentId,\n pageIndex,\n scale: scaleOverride,\n class: propsClass,\n stroke = 'rgba(33,150,243,0.8)',\n fill = 'rgba(33,150,243,0.15)',\n }: MarqueeZoomProps = $props();\n\n const zoomCapability = useZoomCapability();\n const documentState = useDocumentState(() => documentId);\n\n let rect = $state<Rect | null>(null);\n\n const actualScale = $derived(\n scaleOverride !== undefined ? scaleOverride : (documentState.current?.scale ?? 1),\n );\n\n $effect(() => {\n rect = null;\n\n if (!zoomCapability.provides) {\n return;\n }\n\n return zoomCapability.provides.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n callback: {\n onPreview: (newRect) => {\n rect = newRect;\n },\n },\n });\n });\n</script>\n\n{#if rect}\n <div\n style:position=\"absolute\"\n style:pointer-events=\"none\"\n style:left={`${rect.origin.x * actualScale}px`}\n style:top={`${rect.origin.y * actualScale}px`}\n style:width={`${rect.size.width * actualScale}px`}\n style:height={`${rect.size.height * actualScale}px`}\n style:border={`1px solid ${stroke}`}\n style:background={fill}\n style:box-sizing=\"border-box\"\n class={propsClass}\n ></div>\n{/if}\n","<script lang=\"ts\">\n import { useZoomGesture } from '../hooks';\n import type { Snippet } from 'svelte';\n import type { HTMLAttributes } from 'svelte/elements';\n\n type ZoomGestureWrapperProps = Omit<HTMLAttributes<HTMLDivElement>, 'style'> & {\n documentId: string;\n children: Snippet;\n class?: string;\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: boolean;\n };\n\n let {\n documentId,\n children,\n class: propsClass,\n enablePinch = true,\n enableWheel = true,\n ...restProps\n }: ZoomGestureWrapperProps = $props();\n\n const zoomGesture = useZoomGesture(() => documentId, {\n enablePinch: () => enablePinch,\n enableWheel: () => enableWheel,\n });\n</script>\n\n<div\n bind:this={zoomGesture.elementRef}\n {...restProps}\n style:display=\"inline-block\"\n style:overflow=\"visible\"\n style:box-sizing=\"border-box\"\n class={propsClass}\n>\n {@render children()}\n</div>\n"],"names":["useZoomCapability","useCapability","ZoomPlugin","id","getTouchDistance","touches","t1","t2","dx","clientX","dy","clientY","Math","hypot","useZoomGesture","getDocumentId","options","viewportCapability","zoomCapability","viewportElementCtx","getContext","cleanup","elementRef","$","state","documentId","enablePinch","derived","_a","call","enableWheel","user_effect","element","container","current","viewport","provides","zoom","docId","pinchEnabled","wheelEnabled","zoomProvides","viewportGap","window","zoomScope","forDocument","getState","initialZoom","currentScale","isPinching","initialDistance","wheelZoomTimeout","accumulatedWheelScale","initialElementWidth","initialElementHeight","initialElementLeft","initialElementTop","containerRectWidth","containerRectHeight","layoutWidth","layoutCenterX","pointerLocalY","pointerContainerX","pointerContainerY","currentGap","pivotLocalX","clamp","val","min","max","updateMargin","availableWidth","clientWidth","elementWidth","offsetWidth","newMargin","style","marginLeft","calculateTransform","scale","finalWidth","finalHeight","ty","txCenter","txMouse","overflow","blendRange","blend","tx","updateTransform","transformOrigin","transform","resetTransform","commitZoom","delta","anchorX","anchorY","scaleDiff","abs","requestZoomBy","vx","vy","initializeGestureState","containerRect","getBoundingClientRect","innerRect","width","height","left","top","clientLeft","rawPointerLocalX","handleTouchStart","e","length","currentZoomLevel","center","x","y","getTouchCenter","preventDefault","handleTouchMove","currentDistance","handleTouchEnd","handleWheel","ctrlKey","metaKey","clearTimeout","zoomFactor","deltaY","setTimeout","unsubZoom","onStateChange","resizeObserver","ResizeObserver","observe","addEventListener","passive","removeEventListener","disconnect","setupZoomGestures","getViewportGap","value","set","stroke","fill","documentState","useDocumentState","$$props","rect","actualScale","registerMarqueeOnPage","pageIndex","callback","onPreview","newRect","div","root_1","clsx","class","styles","get","origin","size","consequent","restProps","rest_props","zoomGesture","root","bind_this","$$value","capability","initialDocumentState","scopedProvides","scope","newState","usePlugin"],"mappings":"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"}
|
package/dist/svelte/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/svelte/hooks/use-zoom.svelte.ts","../../src/shared/utils/zoom-gesture-logic.ts","../../src/svelte/hooks/use-zoom-gesture.svelte.ts","../../src/svelte/components/MarqueeZoom.svelte","../../src/svelte/components/ZoomGestureWrapper.svelte"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport {\n initialDocumentState,\n ZoomDocumentState,\n ZoomPlugin,\n ZoomScope,\n} from '@embedpdf/plugin-zoom';\n\nexport const useZoomCapability = () => useCapability<ZoomPlugin>(ZoomPlugin.id);\nexport const useZoomPlugin = () => usePlugin<ZoomPlugin>(ZoomPlugin.id);\n\n// Define the return type explicitly to maintain type safety\ninterface UseZoomReturn {\n provides: ZoomScope | null;\n state: ZoomDocumentState;\n}\n\n/**\n * Hook for zoom state for a specific document\n * @param getDocumentId Function that returns the document ID\n */\nexport const useZoom = (getDocumentId: () => string | null): UseZoomReturn => {\n const capability = useZoomCapability();\n\n let state = $state<ZoomDocumentState>(initialDocumentState);\n\n // Reactive documentId\n const documentId = $derived(getDocumentId());\n\n // Scoped capability for current docId\n const scopedProvides = $derived(\n capability.provides && documentId ? capability.provides.forDocument(documentId) : null,\n );\n\n $effect(() => {\n const provides = capability.provides;\n const docId = documentId;\n\n if (!provides || !docId) {\n state = initialDocumentState;\n return;\n }\n\n const scope = provides.forDocument(docId);\n\n // Get initial state\n state = scope.getState();\n\n // Subscribe to state changes for this document\n return scope.onStateChange((newState) => {\n state = newState;\n });\n });\n\n return {\n get provides() {\n return scopedProvides;\n },\n get state() {\n return state;\n },\n };\n};\n","import type { ZoomCapability } from '@embedpdf/plugin-zoom';\n\nexport interface ZoomGestureOptions {\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: boolean;\n}\n\nexport interface ZoomGestureDeps {\n element: HTMLDivElement;\n /** Viewport container element for attaching events */\n container: HTMLElement;\n documentId: string;\n zoomProvides: ZoomCapability;\n /** Viewport gap in pixels (default: 0) */\n viewportGap?: number;\n options?: ZoomGestureOptions;\n}\n\nfunction getTouchDistance(touches: TouchList): number {\n const [t1, t2] = [touches[0], touches[1]];\n const dx = t2.clientX - t1.clientX;\n const dy = t2.clientY - t1.clientY;\n return Math.hypot(dx, dy);\n}\n\nfunction getTouchCenter(touches: TouchList): { x: number; y: number } {\n const [t1, t2] = [touches[0], touches[1]];\n return {\n x: (t1.clientX + t2.clientX) / 2,\n y: (t1.clientY + t2.clientY) / 2,\n };\n}\n\nexport function setupZoomGestures({\n element,\n container,\n documentId,\n zoomProvides,\n viewportGap = 0,\n options = {},\n}: ZoomGestureDeps) {\n const { enablePinch = true, enableWheel = true } = options;\n if (typeof window === 'undefined') {\n return () => {};\n }\n\n const zoomScope = zoomProvides.forDocument(documentId);\n const getState = () => zoomScope.getState();\n\n // Shared state\n let initialZoom = 0;\n let currentScale = 1;\n let isPinching = false;\n let initialDistance = 0;\n\n // Wheel state\n let wheelZoomTimeout: ReturnType<typeof setTimeout> | null = null;\n let accumulatedWheelScale = 1;\n\n // Gesture state\n let initialElementWidth = 0;\n let initialElementHeight = 0;\n let initialElementLeft = 0;\n let initialElementTop = 0;\n\n // Container Dimensions (Bounding Box)\n let containerRectWidth = 0;\n let containerRectHeight = 0;\n\n // Layout Dimensions (Client Box from Metrics)\n let layoutWidth = 0;\n let layoutCenterX = 0;\n\n let pointerLocalY = 0;\n let pointerContainerX = 0;\n let pointerContainerY = 0;\n\n let currentGap = 0;\n let pivotLocalX = 0;\n\n const clamp = (val: number, min: number, max: number) => Math.min(Math.max(val, min), max);\n\n // --- Margin calculation ---\n const updateMargin = () => {\n const availableWidth = container.clientWidth - 2 * viewportGap;\n const elementWidth = element.offsetWidth;\n\n const newMargin = elementWidth < availableWidth ? (availableWidth - elementWidth) / 2 : 0;\n element.style.marginLeft = `${newMargin}px`;\n };\n\n const calculateTransform = (scale: number) => {\n const finalWidth = initialElementWidth * scale;\n const finalHeight = initialElementHeight * scale;\n\n let ty = pointerLocalY * (1 - scale);\n\n const targetX = layoutCenterX - finalWidth / 2;\n const txCenter = targetX - initialElementLeft;\n const txMouse = pointerContainerX - pivotLocalX * scale - initialElementLeft;\n\n const overflow = Math.max(0, finalWidth - layoutWidth);\n const blendRange = layoutWidth * 0.3;\n const blend = Math.min(1, overflow / blendRange);\n\n let tx = txCenter + (txMouse - txCenter) * blend;\n\n const safeHeight = containerRectHeight - currentGap * 2;\n if (finalHeight > safeHeight) {\n const currentTop = initialElementTop + ty;\n const maxTop = currentGap;\n const minTop = containerRectHeight - currentGap - finalHeight;\n const constrainedTop = clamp(currentTop, minTop, maxTop);\n ty = constrainedTop - initialElementTop;\n }\n\n const safeWidth = containerRectWidth - currentGap * 2;\n if (finalWidth > safeWidth) {\n const currentLeft = initialElementLeft + tx;\n const maxLeft = currentGap;\n const minLeft = containerRectWidth - currentGap - finalWidth;\n const constrainedLeft = clamp(currentLeft, minLeft, maxLeft);\n tx = constrainedLeft - initialElementLeft;\n }\n\n return { tx, ty, blend, finalWidth };\n };\n\n const updateTransform = (scale: number) => {\n currentScale = scale;\n const { tx, ty } = calculateTransform(scale);\n element.style.transformOrigin = '0 0';\n element.style.transform = `translate(${tx}px, ${ty}px) scale(${scale})`;\n };\n\n const resetTransform = () => {\n element.style.transform = 'none';\n element.style.transformOrigin = '0 0';\n currentScale = 1;\n };\n\n const commitZoom = () => {\n const { tx, finalWidth } = calculateTransform(currentScale);\n const delta = (currentScale - 1) * initialZoom;\n\n let anchorX: number;\n let anchorY: number = pointerContainerY;\n\n if (finalWidth <= layoutWidth) {\n anchorX = layoutCenterX;\n } else {\n const scaleDiff = 1 - currentScale;\n anchorX =\n Math.abs(scaleDiff) > 0.001 ? initialElementLeft + tx / scaleDiff : pointerContainerX;\n }\n\n zoomScope.requestZoomBy(delta, { vx: anchorX, vy: anchorY });\n resetTransform();\n initialZoom = 0;\n };\n\n const initializeGestureState = (clientX: number, clientY: number) => {\n const containerRect = container.getBoundingClientRect();\n const innerRect = element.getBoundingClientRect();\n\n currentGap = viewportGap;\n initialElementWidth = innerRect.width;\n initialElementHeight = innerRect.height;\n initialElementLeft = innerRect.left - containerRect.left;\n initialElementTop = innerRect.top - containerRect.top;\n\n containerRectWidth = containerRect.width;\n containerRectHeight = containerRect.height;\n\n // Layout dimensions from container's client area\n layoutWidth = container.clientWidth;\n layoutCenterX = container.clientLeft + layoutWidth / 2;\n\n const rawPointerLocalX = clientX - innerRect.left;\n pointerLocalY = clientY - innerRect.top;\n pointerContainerX = clientX - containerRect.left;\n pointerContainerY = clientY - containerRect.top;\n\n if (initialElementWidth < layoutWidth) {\n pivotLocalX = (pointerContainerX * initialElementWidth) / layoutWidth;\n } else {\n pivotLocalX = rawPointerLocalX;\n }\n };\n\n // --- Handlers ---\n const handleTouchStart = (e: TouchEvent) => {\n if (e.touches.length !== 2) return;\n isPinching = true;\n initialZoom = getState().currentZoomLevel;\n initialDistance = getTouchDistance(e.touches);\n const center = getTouchCenter(e.touches);\n initializeGestureState(center.x, center.y);\n e.preventDefault();\n };\n\n const handleTouchMove = (e: TouchEvent) => {\n if (!isPinching || e.touches.length !== 2) return;\n const currentDistance = getTouchDistance(e.touches);\n const scale = currentDistance / initialDistance;\n updateTransform(scale);\n e.preventDefault();\n };\n\n const handleTouchEnd = (e: TouchEvent) => {\n if (!isPinching) return;\n if (e.touches.length >= 2) return;\n isPinching = false;\n commitZoom();\n };\n\n const handleWheel = (e: WheelEvent) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n\n if (wheelZoomTimeout === null) {\n initialZoom = getState().currentZoomLevel;\n accumulatedWheelScale = 1;\n initializeGestureState(e.clientX, e.clientY);\n } else {\n clearTimeout(wheelZoomTimeout);\n }\n\n const zoomFactor = 1 - e.deltaY * 0.01;\n accumulatedWheelScale *= zoomFactor;\n accumulatedWheelScale = Math.max(0.1, Math.min(10, accumulatedWheelScale));\n updateTransform(accumulatedWheelScale);\n\n wheelZoomTimeout = setTimeout(() => {\n wheelZoomTimeout = null;\n commitZoom();\n accumulatedWheelScale = 1;\n }, 150);\n };\n\n // Subscribe to zoom changes to update margin\n const unsubZoom = zoomScope.onStateChange(() => updateMargin());\n\n // Use ResizeObserver to update margin when element or container size changes\n const resizeObserver = new ResizeObserver(() => updateMargin());\n resizeObserver.observe(element);\n resizeObserver.observe(container);\n\n // Initial margin calculation\n updateMargin();\n\n // Attach events to the viewport container for better UX\n // (gestures work anywhere in viewport, not just on the PDF)\n if (enablePinch) {\n container.addEventListener('touchstart', handleTouchStart, { passive: false });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd);\n container.addEventListener('touchcancel', handleTouchEnd);\n }\n if (enableWheel) {\n container.addEventListener('wheel', handleWheel, { passive: false });\n }\n\n return () => {\n if (enablePinch) {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchEnd);\n }\n if (enableWheel) {\n container.removeEventListener('wheel', handleWheel);\n }\n if (wheelZoomTimeout) {\n clearTimeout(wheelZoomTimeout);\n }\n unsubZoom();\n resizeObserver.disconnect();\n resetTransform();\n element.style.marginLeft = '';\n };\n}\n","import { getContext } from 'svelte';\nimport { useCapability } from '@embedpdf/core/svelte';\nimport type { ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { setupZoomGestures, type ZoomGestureOptions } from '../../shared/utils/zoom-gesture-logic';\nimport { useZoomCapability } from './use-zoom.svelte';\n\nexport type { ZoomGestureOptions };\n\n/** Context type for viewport element */\ntype ViewportElementContext = { readonly current: HTMLDivElement | null };\n\nexport interface UseZoomGestureOptions {\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: () => boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: () => boolean;\n}\n\n/**\n * Hook for setting up zoom gesture functionality (pinch and wheel zoom) on an element\n * @param getDocumentId Function that returns the document ID\n * @param options Optional configuration for enabling/disabling gestures\n */\nexport function useZoomGesture(\n getDocumentId: () => string | null,\n options: UseZoomGestureOptions = {},\n) {\n const viewportCapability = useCapability<ViewportPlugin>('viewport');\n const zoomCapability = useZoomCapability();\n const viewportElementCtx = getContext<ViewportElementContext | undefined>('viewport-element');\n\n let elementRef = $state<HTMLDivElement | null>(null);\n let cleanup: (() => void) | undefined;\n\n // Reactive documentId and options\n const documentId = $derived(getDocumentId());\n const enablePinch = $derived(options.enablePinch?.() ?? true);\n const enableWheel = $derived(options.enableWheel?.() ?? true);\n\n $effect(() => {\n const element = elementRef;\n const container = viewportElementCtx?.current;\n const viewport = viewportCapability.provides;\n const zoom = zoomCapability.provides;\n const docId = documentId;\n const pinchEnabled = enablePinch;\n const wheelEnabled = enableWheel;\n\n // Clean up previous setup\n if (cleanup) {\n cleanup();\n cleanup = undefined;\n }\n\n // Setup new zoom gestures if all dependencies are available\n if (!element || !container || !zoom || !docId) {\n return;\n }\n\n cleanup = setupZoomGestures({\n element,\n container,\n documentId: docId,\n zoomProvides: zoom,\n viewportGap: viewport?.getViewportGap() || 0,\n options: { enablePinch: pinchEnabled, enableWheel: wheelEnabled },\n });\n\n return () => {\n if (cleanup) {\n cleanup();\n cleanup = undefined;\n }\n };\n });\n\n return {\n get elementRef() {\n return elementRef;\n },\n set elementRef(value: HTMLDivElement | null) {\n elementRef = value;\n },\n };\n}\n","<script lang=\"ts\">\n import type { Rect } from '@embedpdf/models';\n import { useDocumentState } from '@embedpdf/core/svelte';\n import { useZoomCapability } from '../hooks/use-zoom.svelte';\n\n interface MarqueeZoomProps {\n /** The ID of the document */\n documentId: string;\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 class?: string;\n /** Stroke / fill colours (defaults below) */\n stroke?: string;\n fill?: string;\n }\n\n let {\n documentId,\n pageIndex,\n scale: scaleOverride,\n class: propsClass,\n stroke = 'rgba(33,150,243,0.8)',\n fill = 'rgba(33,150,243,0.15)',\n }: MarqueeZoomProps = $props();\n\n const zoomCapability = useZoomCapability();\n const documentState = useDocumentState(() => documentId);\n\n let rect = $state<Rect | null>(null);\n\n const actualScale = $derived(\n scaleOverride !== undefined ? scaleOverride : (documentState.current?.scale ?? 1),\n );\n\n $effect(() => {\n rect = null;\n\n if (!zoomCapability.provides) {\n return;\n }\n\n return zoomCapability.provides.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n callback: {\n onPreview: (newRect) => {\n rect = newRect;\n },\n },\n });\n });\n</script>\n\n{#if rect}\n <div\n style:position=\"absolute\"\n style:pointer-events=\"none\"\n style:left={`${rect.origin.x * actualScale}px`}\n style:top={`${rect.origin.y * actualScale}px`}\n style:width={`${rect.size.width * actualScale}px`}\n style:height={`${rect.size.height * actualScale}px`}\n style:border={`1px solid ${stroke}`}\n style:background={fill}\n style:box-sizing=\"border-box\"\n class={propsClass}\n ></div>\n{/if}\n","<script lang=\"ts\">\n import { useZoomGesture } from '../hooks';\n import type { Snippet } from 'svelte';\n import type { HTMLAttributes } from 'svelte/elements';\n\n type ZoomGestureWrapperProps = Omit<HTMLAttributes<HTMLDivElement>, 'style'> & {\n documentId: string;\n children: Snippet;\n class?: string;\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: boolean;\n };\n\n let {\n documentId,\n children,\n class: propsClass,\n enablePinch = true,\n enableWheel = true,\n ...restProps\n }: ZoomGestureWrapperProps = $props();\n\n const zoomGesture = useZoomGesture(() => documentId, {\n enablePinch: () => enablePinch,\n enableWheel: () => enableWheel,\n });\n</script>\n\n<div\n bind:this={zoomGesture.elementRef}\n {...restProps}\n style:display=\"inline-block\"\n style:overflow=\"visible\"\n style:box-sizing=\"border-box\"\n class={propsClass}\n>\n {@render children()}\n</div>\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/svelte/hooks/use-zoom.svelte.ts","../../src/shared/utils/zoom-gesture-logic.ts","../../src/svelte/hooks/use-zoom-gesture.svelte.ts","../../src/svelte/components/MarqueeZoom.svelte","../../src/svelte/components/ZoomGestureWrapper.svelte"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport {\n initialDocumentState,\n ZoomDocumentState,\n ZoomPlugin,\n ZoomScope,\n} from '@embedpdf/plugin-zoom';\n\nexport const useZoomCapability = () => useCapability<ZoomPlugin>(ZoomPlugin.id);\nexport const useZoomPlugin = () => usePlugin<ZoomPlugin>(ZoomPlugin.id);\n\n// Define the return type explicitly to maintain type safety\ninterface UseZoomReturn {\n provides: ZoomScope | null;\n state: ZoomDocumentState;\n}\n\n/**\n * Hook for zoom state for a specific document\n * @param getDocumentId Function that returns the document ID\n */\nexport const useZoom = (getDocumentId: () => string | null): UseZoomReturn => {\n const capability = useZoomCapability();\n\n let state = $state<ZoomDocumentState>(initialDocumentState);\n\n // Reactive documentId\n const documentId = $derived(getDocumentId());\n\n // Scoped capability for current docId\n const scopedProvides = $derived(\n capability.provides && documentId ? capability.provides.forDocument(documentId) : null,\n );\n\n $effect(() => {\n const provides = capability.provides;\n const docId = documentId;\n\n if (!provides || !docId) {\n state = initialDocumentState;\n return;\n }\n\n const scope = provides.forDocument(docId);\n\n // Get initial state\n state = scope.getState();\n\n // Subscribe to state changes for this document\n return scope.onStateChange((newState) => {\n state = newState;\n });\n });\n\n return {\n get provides() {\n return scopedProvides;\n },\n get state() {\n return state;\n },\n };\n};\n","import type { ZoomCapability } from '@embedpdf/plugin-zoom';\n\nexport interface ZoomGestureOptions {\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: boolean;\n}\n\nexport interface ZoomGestureDeps {\n element: HTMLDivElement;\n /** Viewport container element for attaching events */\n container: HTMLElement;\n documentId: string;\n zoomProvides: ZoomCapability;\n /** Viewport gap in pixels (default: 0) */\n viewportGap?: number;\n options?: ZoomGestureOptions;\n}\n\nfunction getTouchDistance(touches: TouchList): number {\n const [t1, t2] = [touches[0], touches[1]];\n const dx = t2.clientX - t1.clientX;\n const dy = t2.clientY - t1.clientY;\n return Math.hypot(dx, dy);\n}\n\nfunction getTouchCenter(touches: TouchList): { x: number; y: number } {\n const [t1, t2] = [touches[0], touches[1]];\n return {\n x: (t1.clientX + t2.clientX) / 2,\n y: (t1.clientY + t2.clientY) / 2,\n };\n}\n\nexport function setupZoomGestures({\n element,\n container,\n documentId,\n zoomProvides,\n viewportGap = 0,\n options = {},\n}: ZoomGestureDeps) {\n const { enablePinch = true, enableWheel = true } = options;\n if (typeof window === 'undefined') {\n return () => {};\n }\n\n const zoomScope = zoomProvides.forDocument(documentId);\n const getState = () => zoomScope.getState();\n\n // Shared state\n let initialZoom = 0;\n let currentScale = 1;\n let isPinching = false;\n let initialDistance = 0;\n\n // Wheel state\n let wheelZoomTimeout: ReturnType<typeof setTimeout> | null = null;\n let accumulatedWheelScale = 1;\n\n // Gesture state\n let initialElementWidth = 0;\n let initialElementHeight = 0;\n let initialElementLeft = 0;\n let initialElementTop = 0;\n\n // Container Dimensions (Bounding Box)\n let containerRectWidth = 0;\n let containerRectHeight = 0;\n\n // Layout Dimensions (Client Box from Metrics)\n let layoutWidth = 0;\n let layoutCenterX = 0;\n\n let pointerLocalY = 0;\n let pointerContainerX = 0;\n let pointerContainerY = 0;\n\n let currentGap = 0;\n let pivotLocalX = 0;\n\n const clamp = (val: number, min: number, max: number) => Math.min(Math.max(val, min), max);\n\n // --- Margin calculation ---\n const updateMargin = () => {\n const availableWidth = container.clientWidth - 2 * viewportGap;\n const elementWidth = element.offsetWidth;\n\n const newMargin = elementWidth < availableWidth ? (availableWidth - elementWidth) / 2 : 0;\n element.style.marginLeft = `${newMargin}px`;\n };\n\n const calculateTransform = (scale: number) => {\n const finalWidth = initialElementWidth * scale;\n const finalHeight = initialElementHeight * scale;\n\n let ty = pointerLocalY * (1 - scale);\n\n const targetX = layoutCenterX - finalWidth / 2;\n const txCenter = targetX - initialElementLeft;\n const txMouse = pointerContainerX - pivotLocalX * scale - initialElementLeft;\n\n const overflow = Math.max(0, finalWidth - layoutWidth);\n const blendRange = layoutWidth * 0.3;\n const blend = Math.min(1, overflow / blendRange);\n\n let tx = txCenter + (txMouse - txCenter) * blend;\n\n const safeHeight = containerRectHeight - currentGap * 2;\n if (finalHeight > safeHeight) {\n const currentTop = initialElementTop + ty;\n const maxTop = currentGap;\n const minTop = containerRectHeight - currentGap - finalHeight;\n const constrainedTop = clamp(currentTop, minTop, maxTop);\n ty = constrainedTop - initialElementTop;\n }\n\n const safeWidth = containerRectWidth - currentGap * 2;\n if (finalWidth > safeWidth) {\n const currentLeft = initialElementLeft + tx;\n const maxLeft = currentGap;\n const minLeft = containerRectWidth - currentGap - finalWidth;\n const constrainedLeft = clamp(currentLeft, minLeft, maxLeft);\n tx = constrainedLeft - initialElementLeft;\n }\n\n return { tx, ty, blend, finalWidth };\n };\n\n const updateTransform = (scale: number) => {\n currentScale = scale;\n const { tx, ty } = calculateTransform(scale);\n element.style.transformOrigin = '0 0';\n element.style.transform = `translate(${tx}px, ${ty}px) scale(${scale})`;\n };\n\n const resetTransform = () => {\n element.style.transform = 'none';\n element.style.transformOrigin = '0 0';\n currentScale = 1;\n };\n\n const commitZoom = () => {\n const { tx, finalWidth } = calculateTransform(currentScale);\n const delta = (currentScale - 1) * initialZoom;\n\n let anchorX: number;\n let anchorY: number = pointerContainerY;\n\n if (finalWidth <= layoutWidth) {\n anchorX = layoutCenterX;\n } else {\n const scaleDiff = 1 - currentScale;\n anchorX =\n Math.abs(scaleDiff) > 0.001 ? initialElementLeft + tx / scaleDiff : pointerContainerX;\n }\n\n zoomScope.requestZoomBy(delta, { vx: anchorX, vy: anchorY });\n resetTransform();\n initialZoom = 0;\n };\n\n const initializeGestureState = (clientX: number, clientY: number) => {\n const containerRect = container.getBoundingClientRect();\n const innerRect = element.getBoundingClientRect();\n\n currentGap = viewportGap;\n initialElementWidth = innerRect.width;\n initialElementHeight = innerRect.height;\n initialElementLeft = innerRect.left - containerRect.left;\n initialElementTop = innerRect.top - containerRect.top;\n\n containerRectWidth = containerRect.width;\n containerRectHeight = containerRect.height;\n\n // Layout dimensions from container's client area\n layoutWidth = container.clientWidth;\n layoutCenterX = container.clientLeft + layoutWidth / 2;\n\n const rawPointerLocalX = clientX - innerRect.left;\n pointerLocalY = clientY - innerRect.top;\n pointerContainerX = clientX - containerRect.left;\n pointerContainerY = clientY - containerRect.top;\n\n if (initialElementWidth < layoutWidth) {\n pivotLocalX = (pointerContainerX * initialElementWidth) / layoutWidth;\n } else {\n pivotLocalX = rawPointerLocalX;\n }\n };\n\n // --- Handlers ---\n const handleTouchStart = (e: TouchEvent) => {\n if (e.touches.length !== 2) return;\n isPinching = true;\n initialZoom = getState().currentZoomLevel;\n initialDistance = getTouchDistance(e.touches);\n const center = getTouchCenter(e.touches);\n initializeGestureState(center.x, center.y);\n e.preventDefault();\n };\n\n const handleTouchMove = (e: TouchEvent) => {\n if (!isPinching || e.touches.length !== 2) return;\n const currentDistance = getTouchDistance(e.touches);\n const scale = currentDistance / initialDistance;\n updateTransform(scale);\n e.preventDefault();\n };\n\n const handleTouchEnd = (e: TouchEvent) => {\n if (!isPinching) return;\n if (e.touches.length >= 2) return;\n isPinching = false;\n commitZoom();\n };\n\n const handleWheel = (e: WheelEvent) => {\n if (!e.ctrlKey && !e.metaKey) return;\n e.preventDefault();\n\n if (wheelZoomTimeout === null) {\n initialZoom = getState().currentZoomLevel;\n accumulatedWheelScale = 1;\n initializeGestureState(e.clientX, e.clientY);\n } else {\n clearTimeout(wheelZoomTimeout);\n }\n\n const zoomFactor = 1 - e.deltaY * 0.01;\n accumulatedWheelScale *= zoomFactor;\n accumulatedWheelScale = Math.max(0.1, Math.min(10, accumulatedWheelScale));\n updateTransform(accumulatedWheelScale);\n\n wheelZoomTimeout = setTimeout(() => {\n wheelZoomTimeout = null;\n commitZoom();\n accumulatedWheelScale = 1;\n }, 150);\n };\n\n // Subscribe to zoom changes to update margin\n const unsubZoom = zoomScope.onStateChange(() => updateMargin());\n\n // Use ResizeObserver to update margin when element or container size changes\n const resizeObserver = new ResizeObserver(() => updateMargin());\n resizeObserver.observe(element);\n resizeObserver.observe(container);\n\n // Initial margin calculation\n updateMargin();\n\n // Attach events to the viewport container for better UX\n // (gestures work anywhere in viewport, not just on the PDF)\n if (enablePinch) {\n container.addEventListener('touchstart', handleTouchStart, { passive: false });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd);\n container.addEventListener('touchcancel', handleTouchEnd);\n }\n if (enableWheel) {\n container.addEventListener('wheel', handleWheel, { passive: false });\n }\n\n return () => {\n if (enablePinch) {\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchEnd);\n }\n if (enableWheel) {\n container.removeEventListener('wheel', handleWheel);\n }\n if (wheelZoomTimeout) {\n clearTimeout(wheelZoomTimeout);\n }\n unsubZoom();\n resizeObserver.disconnect();\n resetTransform();\n element.style.marginLeft = '';\n };\n}\n","import { getContext } from 'svelte';\nimport { useCapability } from '@embedpdf/core/svelte';\nimport type { ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { setupZoomGestures, type ZoomGestureOptions } from '../../shared/utils/zoom-gesture-logic';\nimport { useZoomCapability } from './use-zoom.svelte';\n\nexport type { ZoomGestureOptions };\n\n/** Context type for viewport element */\ntype ViewportElementContext = { readonly current: HTMLDivElement | null };\n\nexport interface UseZoomGestureOptions {\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: () => boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: () => boolean;\n}\n\n/**\n * Hook for setting up zoom gesture functionality (pinch and wheel zoom) on an element\n * @param getDocumentId Function that returns the document ID\n * @param options Optional configuration for enabling/disabling gestures\n */\nexport function useZoomGesture(\n getDocumentId: () => string | null,\n options: UseZoomGestureOptions = {},\n) {\n const viewportCapability = useCapability<ViewportPlugin>('viewport');\n const zoomCapability = useZoomCapability();\n const viewportElementCtx = getContext<ViewportElementContext | undefined>('viewport-element');\n\n let elementRef = $state<HTMLDivElement | null>(null);\n let cleanup: (() => void) | undefined;\n\n // Reactive documentId and options\n const documentId = $derived(getDocumentId());\n const enablePinch = $derived(options.enablePinch?.() ?? true);\n const enableWheel = $derived(options.enableWheel?.() ?? true);\n\n $effect(() => {\n const element = elementRef;\n const container = viewportElementCtx?.current;\n const viewport = viewportCapability.provides;\n const zoom = zoomCapability.provides;\n const docId = documentId;\n const pinchEnabled = enablePinch;\n const wheelEnabled = enableWheel;\n\n // Clean up previous setup\n if (cleanup) {\n cleanup();\n cleanup = undefined;\n }\n\n // Setup new zoom gestures if all dependencies are available\n if (!element || !container || !zoom || !docId) {\n return;\n }\n\n cleanup = setupZoomGestures({\n element,\n container,\n documentId: docId,\n zoomProvides: zoom,\n viewportGap: viewport?.getViewportGap() || 0,\n options: { enablePinch: pinchEnabled, enableWheel: wheelEnabled },\n });\n\n return () => {\n if (cleanup) {\n cleanup();\n cleanup = undefined;\n }\n };\n });\n\n return {\n get elementRef() {\n return elementRef;\n },\n set elementRef(value: HTMLDivElement | null) {\n elementRef = value;\n },\n };\n}\n","<script lang=\"ts\">\n import type { Rect } from '@embedpdf/models';\n import { useDocumentState } from '@embedpdf/core/svelte';\n import { useZoomCapability } from '../hooks/use-zoom.svelte';\n\n interface MarqueeZoomProps {\n /** The ID of the document */\n documentId: string;\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 class?: string;\n /** Stroke / fill colours (defaults below) */\n stroke?: string;\n fill?: string;\n }\n\n let {\n documentId,\n pageIndex,\n scale: scaleOverride,\n class: propsClass,\n stroke = 'rgba(33,150,243,0.8)',\n fill = 'rgba(33,150,243,0.15)',\n }: MarqueeZoomProps = $props();\n\n const zoomCapability = useZoomCapability();\n const documentState = useDocumentState(() => documentId);\n\n let rect = $state<Rect | null>(null);\n\n const actualScale = $derived(\n scaleOverride !== undefined ? scaleOverride : (documentState.current?.scale ?? 1),\n );\n\n $effect(() => {\n rect = null;\n\n if (!zoomCapability.provides) {\n return;\n }\n\n return zoomCapability.provides.registerMarqueeOnPage({\n documentId,\n pageIndex,\n scale: actualScale,\n callback: {\n onPreview: (newRect) => {\n rect = newRect;\n },\n },\n });\n });\n</script>\n\n{#if rect}\n <div\n style:position=\"absolute\"\n style:pointer-events=\"none\"\n style:left={`${rect.origin.x * actualScale}px`}\n style:top={`${rect.origin.y * actualScale}px`}\n style:width={`${rect.size.width * actualScale}px`}\n style:height={`${rect.size.height * actualScale}px`}\n style:border={`1px solid ${stroke}`}\n style:background={fill}\n style:box-sizing=\"border-box\"\n class={propsClass}\n ></div>\n{/if}\n","<script lang=\"ts\">\n import { useZoomGesture } from '../hooks';\n import type { Snippet } from 'svelte';\n import type { HTMLAttributes } from 'svelte/elements';\n\n type ZoomGestureWrapperProps = Omit<HTMLAttributes<HTMLDivElement>, 'style'> & {\n documentId: string;\n children: Snippet;\n class?: string;\n /** Enable pinch-to-zoom gesture (default: true) */\n enablePinch?: boolean;\n /** Enable wheel zoom with ctrl/cmd key (default: true) */\n enableWheel?: boolean;\n };\n\n let {\n documentId,\n children,\n class: propsClass,\n enablePinch = true,\n enableWheel = true,\n ...restProps\n }: ZoomGestureWrapperProps = $props();\n\n const zoomGesture = useZoomGesture(() => documentId, {\n enablePinch: () => enablePinch,\n enableWheel: () => enableWheel,\n });\n</script>\n\n<div\n bind:this={zoomGesture.elementRef}\n {...restProps}\n style:display=\"inline-block\"\n style:overflow=\"visible\"\n style:box-sizing=\"border-box\"\n class={propsClass}\n>\n {@render children()}\n</div>\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@embedpdf/plugin-zoom",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@embedpdf/models": "2.0.
|
|
38
|
+
"@embedpdf/models": "2.0.1"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@types/react": "^18.2.0",
|
|
42
42
|
"typescript": "^5.0.0",
|
|
43
|
-
"@embedpdf/core": "2.0.
|
|
44
|
-
"@embedpdf/plugin-viewport": "2.0.0",
|
|
43
|
+
"@embedpdf/core": "2.0.1",
|
|
45
44
|
"@embedpdf/build": "1.1.0",
|
|
46
|
-
"@embedpdf/plugin-
|
|
47
|
-
"@embedpdf/plugin-scroll": "2.0.
|
|
48
|
-
"@embedpdf/plugin-
|
|
45
|
+
"@embedpdf/plugin-viewport": "2.0.1",
|
|
46
|
+
"@embedpdf/plugin-scroll": "2.0.1",
|
|
47
|
+
"@embedpdf/plugin-spread": "2.0.1",
|
|
48
|
+
"@embedpdf/plugin-interaction-manager": "2.0.1"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"react": ">=16.8.0",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"preact": "^10.26.4",
|
|
54
54
|
"vue": ">=3.2.0",
|
|
55
55
|
"svelte": ">=5 <6",
|
|
56
|
-
"@embedpdf/core": "2.0.
|
|
57
|
-
"@embedpdf/plugin-
|
|
58
|
-
"@embedpdf/plugin-
|
|
56
|
+
"@embedpdf/core": "2.0.1",
|
|
57
|
+
"@embedpdf/plugin-viewport": "2.0.1",
|
|
58
|
+
"@embedpdf/plugin-scroll": "2.0.1"
|
|
59
59
|
},
|
|
60
60
|
"files": [
|
|
61
61
|
"dist",
|