@embedpdf/plugin-viewport 2.0.0-next.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +4 -21
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/types.d.ts +2 -3
  6. package/dist/lib/viewport-plugin.d.ts +0 -4
  7. package/dist/preact/adapter.d.ts +3 -3
  8. package/dist/preact/index.cjs +1 -1
  9. package/dist/preact/index.cjs.map +1 -1
  10. package/dist/preact/index.js +13 -14
  11. package/dist/preact/index.js.map +1 -1
  12. package/dist/react/adapter.d.ts +2 -2
  13. package/dist/react/index.cjs +1 -1
  14. package/dist/react/index.cjs.map +1 -1
  15. package/dist/react/index.js +12 -13
  16. package/dist/react/index.js.map +1 -1
  17. package/dist/shared/context/index.d.ts +1 -0
  18. package/dist/shared/context/viewport-element-context.d.ts +7 -0
  19. package/dist/shared/hooks/use-viewport.d.ts +6 -0
  20. package/dist/shared/index.d.ts +1 -0
  21. package/dist/shared-preact/context/index.d.ts +1 -0
  22. package/dist/shared-preact/context/viewport-element-context.d.ts +7 -0
  23. package/dist/shared-preact/hooks/use-viewport.d.ts +6 -0
  24. package/dist/shared-preact/index.d.ts +1 -0
  25. package/dist/shared-react/context/index.d.ts +1 -0
  26. package/dist/shared-react/context/viewport-element-context.d.ts +7 -0
  27. package/dist/shared-react/hooks/use-viewport.d.ts +6 -0
  28. package/dist/shared-react/index.d.ts +1 -0
  29. package/dist/svelte/index.cjs +1 -1
  30. package/dist/svelte/index.cjs.map +1 -1
  31. package/dist/svelte/index.js +9 -10
  32. package/dist/svelte/index.js.map +1 -1
  33. package/dist/vue/index.cjs +1 -1
  34. package/dist/vue/index.cjs.map +1 -1
  35. package/dist/vue/index.js +5 -11
  36. package/dist/vue/index.js.map +1 -1
  37. package/package.json +4 -4
@@ -1,5 +1,4 @@
1
1
  import { BasePluginConfig, EventHook } from '@embedpdf/core';
2
- import { Rect } from '@embedpdf/models';
3
2
  export interface ViewportState {
4
3
  viewportGap: number;
5
4
  documents: Record<string, ViewportDocumentState>;
@@ -25,6 +24,8 @@ export interface ViewportInputMetrics {
25
24
  clientHeight: number;
26
25
  scrollWidth: number;
27
26
  scrollHeight: number;
27
+ clientLeft: number;
28
+ clientTop: number;
28
29
  }
29
30
  export interface ViewportMetrics extends ViewportInputMetrics {
30
31
  relativePosition: {
@@ -85,7 +86,6 @@ export interface ViewportScope {
85
86
  getGates(): string[];
86
87
  gate(key: string): void;
87
88
  releaseGate(key: string): void;
88
- getBoundingRect(): Rect;
89
89
  onViewportChange: EventHook<ViewportMetrics>;
90
90
  onScrollChange: EventHook<ViewportScrollMetrics>;
91
91
  onScrollActivity: EventHook<ScrollActivity>;
@@ -100,7 +100,6 @@ export interface ViewportCapability {
100
100
  isGated(documentId?: string): boolean;
101
101
  hasGate(key: string, documentId?: string): boolean;
102
102
  getGates(documentId?: string): string[];
103
- getBoundingRect(): Rect;
104
103
  forDocument(documentId: string): ViewportScope;
105
104
  gate(key: string, documentId: string): void;
106
105
  releaseGate(key: string, documentId: string): void;
@@ -1,5 +1,4 @@
1
1
  import { BasePlugin, PluginRegistry, Listener } from '@embedpdf/core';
2
- import { Rect } from '@embedpdf/models';
3
2
  import { ViewportAction } from './actions';
4
3
  import { ViewportPluginConfig, ViewportState, ViewportCapability, ViewportScrollMetrics, ViewportInputMetrics, ScrollToPayload } from './types';
5
4
  export declare class ViewportPlugin extends BasePlugin<ViewportPluginConfig, ViewportCapability, ViewportState, ViewportAction> {
@@ -11,7 +10,6 @@ export declare class ViewportPlugin extends BasePlugin<ViewportPluginConfig, Vie
11
10
  private readonly scrollActivity$;
12
11
  private readonly gateState$;
13
12
  private readonly scrollRequests$;
14
- private rectProviders;
15
13
  private readonly scrollEndDelay;
16
14
  constructor(id: string, registry: PluginRegistry, config: ViewportPluginConfig);
17
15
  protected onDocumentLoadingStarted(documentId: string): void;
@@ -23,7 +21,6 @@ export declare class ViewportPlugin extends BasePlugin<ViewportPluginConfig, Vie
23
21
  setViewportResizeMetrics(documentId: string, metrics: ViewportInputMetrics): void;
24
22
  setViewportScrollMetrics(documentId: string, scrollMetrics: ViewportScrollMetrics): void;
25
23
  onScrollRequest(documentId: string, listener: Listener<ScrollToPayload>): import('@embedpdf/core').Unsubscribe;
26
- registerBoundingRectProvider(documentId: string, provider: (() => Rect) | null): void;
27
24
  gate(key: string, documentId: string): void;
28
25
  releaseGate(key: string, documentId: string): void;
29
26
  private getViewportState;
@@ -33,7 +30,6 @@ export declare class ViewportPlugin extends BasePlugin<ViewportPluginConfig, Vie
33
30
  private isGated;
34
31
  private hasGate;
35
32
  private getGates;
36
- private getBoundingRect;
37
33
  private scrollTo;
38
34
  private bumpScrollActivity;
39
35
  onStoreUpdated(prevState: ViewportState, newState: ViewportState): void;
@@ -1,5 +1,5 @@
1
- export { Fragment } from 'preact';
2
- export { useEffect, useRef, useState, useCallback, useMemo, useLayoutEffect } from 'preact/hooks';
3
- export type { ComponentChildren as ReactNode } from 'preact';
1
+ export { Fragment, createContext } from 'preact';
2
+ export { useEffect, useRef, useState, useCallback, useMemo, useLayoutEffect, useContext, } from 'preact/hooks';
3
+ export type { ComponentChildren as ReactNode, RefObject } from 'preact';
4
4
  export type CSSProperties = import('preact').JSX.CSSProperties;
5
5
  export type HTMLAttributes<T = any> = import('preact').JSX.HTMLAttributes<T extends EventTarget ? T : never>;
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("preact/jsx-runtime");require("preact");const t=require("preact/hooks"),r=require("@embedpdf/core/preact"),o=require("@embedpdf/plugin-viewport"),i=()=>r.usePlugin(o.ViewportPlugin.id),s=()=>r.useCapability(o.ViewportPlugin.id),n=e=>{const{provides:r}=s(),[o,i]=t.useState((null==r?void 0:r.isGated(e))??!1);return t.useEffect(()=>{if(r)return i(r.isGated(e)),r.onGateChange(t=>{t.documentId===e&&i(t.isGated)})},[r,e]),o};function l(e){const{plugin:r}=i(),o=t.useRef(null);return t.useLayoutEffect(()=>{if(!r)return;const t=o.current;if(!t)return;try{r.registerViewport(e)}catch(l){return void console.error(`Failed to register viewport for document ${e}:`,l)}r.registerBoundingRectProvider(e,()=>{const e=t.getBoundingClientRect();return{origin:{x:e.left,y:e.top},size:{width:e.width,height:e.height}}});const i=()=>{r.setViewportScrollMetrics(e,{scrollTop:t.scrollTop,scrollLeft:t.scrollLeft})};t.addEventListener("scroll",i);const s=new ResizeObserver(()=>{r.setViewportResizeMetrics(e,{width:t.offsetWidth,height:t.offsetHeight,clientWidth:t.clientWidth,clientHeight:t.clientHeight,scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,scrollHeight:t.scrollHeight})});s.observe(t);const n=r.onScrollRequest(e,({x:e,y:r,behavior:o="auto"})=>{requestAnimationFrame(()=>{t.scrollTo({left:e,top:r,behavior:o})})});return()=>{r.unregisterViewport(e),r.registerBoundingRectProvider(e,null),s.disconnect(),t.removeEventListener("scroll",i),n()}},[r,e]),o}exports.Viewport=function({children:r,documentId:o,...i}){const[c,u]=t.useState(0),p=l(o),{provides:d}=s(),a=n(o);t.useEffect(()=>{d&&u(d.getViewportGap())},[d]);const{style:f,...g}=i;return e.jsx("div",{...g,ref:p,style:{width:"100%",height:"100%",overflow:"auto",..."object"==typeof f?f:{},padding:`${c}px`},children:!a&&r})},exports.useIsViewportGated=n,exports.useViewportCapability=s,exports.useViewportPlugin=i,exports.useViewportRef=l,exports.useViewportScrollActivity=e=>{const{provides:r}=s(),[o,i]=t.useState({isScrolling:!1,isSmoothScrolling:!1});return t.useEffect(()=>{if(r)return r.onScrollActivity(t=>{t.documentId===e&&i(t.activity)})},[r,e]),o},Object.keys(o).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>o[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("preact/jsx-runtime"),t=require("preact"),r=require("preact/hooks"),o=require("@embedpdf/core/preact"),i=require("@embedpdf/plugin-viewport"),s=t.createContext(null),l=()=>o.usePlugin(i.ViewportPlugin.id),n=()=>o.useCapability(i.ViewportPlugin.id),c=e=>{const{provides:t}=n(),[o,i]=r.useState((null==t?void 0:t.isGated(e))??!1);return r.useEffect(()=>{if(t)return i(t.isGated(e)),t.onGateChange(t=>{t.documentId===e&&i(t.isGated)})},[t,e]),o};function u(e){const{plugin:t}=l(),o=r.useRef(null);return r.useLayoutEffect(()=>{if(!t)return;const r=o.current;if(!r)return;try{t.registerViewport(e)}catch(n){return void console.error(`Failed to register viewport for document ${e}:`,n)}const i=()=>{t.setViewportScrollMetrics(e,{scrollTop:r.scrollTop,scrollLeft:r.scrollLeft})};r.addEventListener("scroll",i);const s=new ResizeObserver(()=>{t.setViewportResizeMetrics(e,{width:r.offsetWidth,height:r.offsetHeight,clientWidth:r.clientWidth,clientHeight:r.clientHeight,scrollTop:r.scrollTop,scrollLeft:r.scrollLeft,scrollWidth:r.scrollWidth,scrollHeight:r.scrollHeight,clientLeft:r.clientLeft,clientTop:r.clientTop})});s.observe(r);const l=t.onScrollRequest(e,({x:e,y:t,behavior:o="auto"})=>{requestAnimationFrame(()=>{r.scrollTo({left:e,top:t,behavior:o})})});return()=>{t.unregisterViewport(e),s.disconnect(),r.removeEventListener("scroll",i),l()}},[t,e]),o}exports.Viewport=function({children:t,documentId:o,...i}){const[l,p]=r.useState(0),d=u(o),{provides:a}=n(),f=c(o);r.useEffect(()=>{a&&p(a.getViewportGap())},[a]);const{style:h,...g}=i;return e.jsx(s.Provider,{value:d,children:e.jsx("div",{...g,ref:d,style:{width:"100%",height:"100%",overflow:"auto",..."object"==typeof h?h:{},padding:`${l}px`},children:!f&&t})})},exports.ViewportElementContext=s,exports.useIsViewportGated=c,exports.useViewportCapability=n,exports.useViewportElement=()=>r.useContext(s),exports.useViewportPlugin=l,exports.useViewportRef=u,exports.useViewportScrollActivity=e=>{const{provides:t}=n(),[o,i]=r.useState({isScrolling:!1,isSmoothScrolling:!1});return r.useEffect(()=>{if(t)return t.onScrollActivity(t=>{t.documentId===e&&i(t.activity)})},[t,e]),o},Object.keys(i).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>i[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { useEffect, useState } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { GateChangeEvent, ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\n/**\n * Hook to get the gated state of the viewport for a specific document.\n * The viewport children are not rendered when gated.\n * @param documentId Document ID.\n */\nexport const useIsViewportGated = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [isGated, setIsGated] = useState(provides?.isGated(documentId) ?? false);\n\n useEffect(() => {\n if (!provides) return;\n\n // Set initial state\n setIsGated(provides.isGated(documentId));\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === documentId) {\n setIsGated(event.isGated);\n }\n });\n }, [provides, documentId]);\n\n return isGated;\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param documentId Document ID.\n */\nexport const useViewportScrollActivity = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId if provided\n if (event.documentId === documentId) {\n setScrollActivity(event.activity);\n }\n });\n }, [provides, documentId]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef(documentId: string) {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Register this viewport for the document\n try {\n viewportPlugin.registerViewport(documentId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${documentId}:`, error);\n return;\n }\n\n // Provide rect calculator\n const provideRect = (): Rect => {\n const r = container.getBoundingClientRect();\n return {\n origin: { x: r.left, y: r.top },\n size: { width: r.width, height: r.height },\n };\n };\n viewportPlugin.registerBoundingRectProvider(documentId, provideRect);\n\n // On scroll\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics(documentId, {\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // On resize\n const resizeObserver = new ResizeObserver(() => {\n viewportPlugin.setViewportResizeMetrics(documentId, {\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n });\n });\n resizeObserver.observe(container);\n\n // Subscribe to scroll requests for this document\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n documentId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n viewportPlugin.unregisterViewport(documentId);\n viewportPlugin.registerBoundingRectProvider(documentId, null);\n resizeObserver.disconnect();\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin, documentId]);\n\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\nimport { useIsViewportGated, useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n};\n\nexport function Viewport({ children, documentId, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef(documentId);\n const { provides: viewportProvides } = useViewportCapability();\n const isGated = useIsViewportGated(documentId);\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n return (\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {!isGated && children}\n </div>\n );\n}\n"],"names":["useViewportPlugin","usePlugin","ViewportPlugin","id","useViewportCapability","useCapability","useIsViewportGated","documentId","provides","isGated","setIsGated","useState","useEffect","onGateChange","event","useViewportRef","plugin","viewportPlugin","containerRef","useRef","useLayoutEffect","container","current","registerViewport","error","console","registerBoundingRectProvider","r","getBoundingClientRect","origin","x","left","y","top","size","width","height","onScroll","setViewportScrollMetrics","scrollTop","scrollLeft","addEventListener","resizeObserver","ResizeObserver","setViewportResizeMetrics","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","observe","unsubscribeScrollRequest","onScrollRequest","behavior","requestAnimationFrame","scrollTo","unregisterViewport","disconnect","removeEventListener","children","props","viewportGap","setViewportGap","viewportRef","viewportProvides","getViewportGap","style","restProps","jsx","ref","overflow","padding","scrollActivity","setScrollActivity","isScrolling","isSmoothScrolling","onScrollActivity","activity"],"mappings":"kPAIaA,EAAoB,IAAMC,YAA0BC,EAAAA,eAAeC,IACnEC,EAAwB,IAAMC,gBAA8BH,EAAAA,eAAeC,IAO3EG,EAAsBC,IACjC,MAAMC,SAAEA,GAAaJ,KACdK,EAASC,GAAcC,EAAAA,UAAS,MAAAH,OAAA,EAAAA,EAAUC,QAAQF,MAAe,GAgBxE,OAdAK,EAAAA,UAAU,KACR,GAAKJ,EAML,OAHAE,EAAWF,EAASC,QAAQF,IAGrBC,EAASK,aAAcC,IACxBA,EAAMP,aAAeA,GACvBG,EAAWI,EAAML,YAGpB,CAACD,EAAUD,IAEPE,GC1BF,SAASM,EAAeR,GAC7B,MAAQS,OAAQC,GAAmBjB,IAC7BkB,EAAeC,EAAAA,OAAuB,MAsE5C,OApEAC,EAAAA,gBAAgB,KACd,IAAKH,EAAgB,OAErB,MAAMI,EAAYH,EAAaI,QAC/B,IAAKD,EAAW,OAGhB,IACEJ,EAAeM,iBAAiBhB,EAClC,OAASiB,GAEP,YADAC,QAAQD,MAAM,4CAA4CjB,KAAeiB,EAE3E,CAUAP,EAAeS,6BAA6BnB,EAPxB,KAClB,MAAMoB,EAAIN,EAAUO,wBACpB,MAAO,CACLC,OAAQ,CAAEC,EAAGH,EAAEI,KAAMC,EAAGL,EAAEM,KAC1BC,KAAM,CAAEC,MAAOR,EAAEQ,MAAOC,OAAQT,EAAES,WAMtC,MAAMC,EAAW,KACfpB,EAAeqB,yBAAyB/B,EAAY,CAClDgC,UAAWlB,EAAUkB,UACrBC,WAAYnB,EAAUmB,cAG1BnB,EAAUoB,iBAAiB,SAAUJ,GAGrC,MAAMK,EAAiB,IAAIC,eAAe,KACxC1B,EAAe2B,yBAAyBrC,EAAY,CAClD4B,MAAOd,EAAUwB,YACjBT,OAAQf,EAAUyB,aAClBC,YAAa1B,EAAU0B,YACvBC,aAAc3B,EAAU2B,aACxBT,UAAWlB,EAAUkB,UACrBC,WAAYnB,EAAUmB,WACtBS,YAAa5B,EAAU4B,YACvBC,aAAc7B,EAAU6B,iBAG5BR,EAAeS,QAAQ9B,GAGvB,MAAM+B,EAA2BnC,EAAeoC,gBAC9C9C,EACA,EAAGuB,IAAGE,IAAGsB,WAAW,WAClBC,sBAAsB,KACpBlC,EAAUmC,SAAS,CAAEzB,KAAMD,EAAGG,IAAKD,EAAGsB,iBAM5C,MAAO,KACLrC,EAAewC,mBAAmBlD,GAClCU,EAAeS,6BAA6BnB,EAAY,MACxDmC,EAAegB,aACfrC,EAAUsC,oBAAoB,SAAUtB,GACxCe,MAED,CAACnC,EAAgBV,IAEbW,CACT,kBCjEO,UAAkB0C,SAAEA,EAAArD,WAAUA,KAAesD,IAClD,MAAOC,EAAaC,GAAkBpD,EAAAA,SAAS,GACzCqD,EAAcjD,EAAeR,IAC3BC,SAAUyD,GAAqB7D,IACjCK,EAAUH,EAAmBC,GAEnCK,EAAAA,UAAU,KACJqD,GACFF,EAAeE,EAAiBC,mBAEjC,CAACD,IAEJ,MAAME,MAAEA,KAAUC,GAAcP,EAChC,OACEQ,EAAAA,IAAC,MAAA,IACKD,EACJE,IAAKN,EACLG,MAAO,CACLhC,MAAO,OACPC,OAAQ,OACRmC,SAAU,UACW,iBAAVJ,EAAqBA,EAAQ,CAAA,EACxCK,QAAS,GAAGV,OAGbF,UAACnD,GAAWmD,GAGnB,sJFH0CrD,IACxC,MAAMC,SAAEA,GAAaJ,KACdqE,EAAgBC,GAAqB/D,WAAyB,CACnEgE,aAAa,EACbC,mBAAmB,IAerB,OAZAhE,EAAAA,UAAU,KACR,GAAKJ,EAGL,OAAOA,EAASqE,iBAAkB/D,IAE5BA,EAAMP,aAAeA,GACvBmE,EAAkB5D,EAAMgE,aAG3B,CAACtE,EAAUD,IAEPkE"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/context/viewport-element-context.ts","../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { createContext, RefObject } from '@framework';\n\n/**\n * Context to share the viewport DOM element reference with child components.\n * This allows child components (like ZoomGestureWrapper) to access the viewport\n * container element without DOM traversal.\n */\nexport const ViewportElementContext = createContext<RefObject<HTMLDivElement> | null>(null);\n","import { useEffect, useState, useContext, RefObject } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { GateChangeEvent, ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { ViewportElementContext } from '../context';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\n/**\n * Hook to get the viewport DOM element ref from context.\n * Must be used within a Viewport component.\n */\nexport const useViewportElement = (): RefObject<HTMLDivElement> | null => {\n return useContext(ViewportElementContext);\n};\n\n/**\n * Hook to get the gated state of the viewport for a specific document.\n * The viewport children are not rendered when gated.\n * @param documentId Document ID.\n */\nexport const useIsViewportGated = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [isGated, setIsGated] = useState(provides?.isGated(documentId) ?? false);\n\n useEffect(() => {\n if (!provides) return;\n\n // Set initial state\n setIsGated(provides.isGated(documentId));\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === documentId) {\n setIsGated(event.isGated);\n }\n });\n }, [provides, documentId]);\n\n return isGated;\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param documentId Document ID.\n */\nexport const useViewportScrollActivity = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId if provided\n if (event.documentId === documentId) {\n setScrollActivity(event.activity);\n }\n });\n }, [provides, documentId]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef(documentId: string) {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Register this viewport for the document\n try {\n viewportPlugin.registerViewport(documentId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${documentId}:`, error);\n return;\n }\n\n // On scroll\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics(documentId, {\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // On resize\n const resizeObserver = new ResizeObserver(() => {\n viewportPlugin.setViewportResizeMetrics(documentId, {\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n clientLeft: container.clientLeft,\n clientTop: container.clientTop,\n });\n });\n resizeObserver.observe(container);\n\n // Subscribe to scroll requests for this document\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n documentId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n viewportPlugin.unregisterViewport(documentId);\n resizeObserver.disconnect();\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin, documentId]);\n\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\nimport { useIsViewportGated, useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\nimport { ViewportElementContext } from '../context';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n};\n\nexport function Viewport({ children, documentId, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef(documentId);\n const { provides: viewportProvides } = useViewportCapability();\n const isGated = useIsViewportGated(documentId);\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n\n return (\n <ViewportElementContext.Provider value={viewportRef}>\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {!isGated && children}\n </div>\n </ViewportElementContext.Provider>\n );\n}\n"],"names":["ViewportElementContext","createContext","useViewportPlugin","usePlugin","ViewportPlugin","id","useViewportCapability","useCapability","useIsViewportGated","documentId","provides","isGated","setIsGated","useState","useEffect","onGateChange","event","useViewportRef","plugin","viewportPlugin","containerRef","useRef","useLayoutEffect","container","current","registerViewport","error","console","onScroll","setViewportScrollMetrics","scrollTop","scrollLeft","addEventListener","resizeObserver","ResizeObserver","setViewportResizeMetrics","width","offsetWidth","height","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","clientLeft","clientTop","observe","unsubscribeScrollRequest","onScrollRequest","x","y","behavior","requestAnimationFrame","scrollTo","left","top","unregisterViewport","disconnect","removeEventListener","children","props","viewportGap","setViewportGap","viewportRef","viewportProvides","getViewportGap","style","restProps","jsx","Provider","value","ref","overflow","padding","useContext","scrollActivity","setScrollActivity","isScrolling","isSmoothScrolling","onScrollActivity","activity"],"mappings":"8OAOaA,EAAyBC,EAAAA,cAAgD,MCFzEC,EAAoB,IAAMC,YAA0BC,EAAAA,eAAeC,IACnEC,EAAwB,IAAMC,gBAA8BH,EAAAA,eAAeC,IAe3EG,EAAsBC,IACjC,MAAMC,SAAEA,GAAaJ,KACdK,EAASC,GAAcC,EAAAA,UAAS,MAAAH,OAAA,EAAAA,EAAUC,QAAQF,MAAe,GAgBxE,OAdAK,EAAAA,UAAU,KACR,GAAKJ,EAML,OAHAE,EAAWF,EAASC,QAAQF,IAGrBC,EAASK,aAAcC,IACxBA,EAAMP,aAAeA,GACvBG,EAAWI,EAAML,YAGpB,CAACD,EAAUD,IAEPE,GCnCF,SAASM,EAAeR,GAC7B,MAAQS,OAAQC,GAAmBjB,IAC7BkB,EAAeC,EAAAA,OAAuB,MA6D5C,OA3DAC,EAAAA,gBAAgB,KACd,IAAKH,EAAgB,OAErB,MAAMI,EAAYH,EAAaI,QAC/B,IAAKD,EAAW,OAGhB,IACEJ,EAAeM,iBAAiBhB,EAClC,OAASiB,GAEP,YADAC,QAAQD,MAAM,4CAA4CjB,KAAeiB,EAE3E,CAGA,MAAME,EAAW,KACfT,EAAeU,yBAAyBpB,EAAY,CAClDqB,UAAWP,EAAUO,UACrBC,WAAYR,EAAUQ,cAG1BR,EAAUS,iBAAiB,SAAUJ,GAGrC,MAAMK,EAAiB,IAAIC,eAAe,KACxCf,EAAegB,yBAAyB1B,EAAY,CAClD2B,MAAOb,EAAUc,YACjBC,OAAQf,EAAUgB,aAClBC,YAAajB,EAAUiB,YACvBC,aAAclB,EAAUkB,aACxBX,UAAWP,EAAUO,UACrBC,WAAYR,EAAUQ,WACtBW,YAAanB,EAAUmB,YACvBC,aAAcpB,EAAUoB,aACxBC,WAAYrB,EAAUqB,WACtBC,UAAWtB,EAAUsB,cAGzBZ,EAAea,QAAQvB,GAGvB,MAAMwB,EAA2B5B,EAAe6B,gBAC9CvC,EACA,EAAGwC,IAAGC,IAAGC,WAAW,WAClBC,sBAAsB,KACpB7B,EAAU8B,SAAS,CAAEC,KAAML,EAAGM,IAAKL,EAAGC,iBAM5C,MAAO,KACLhC,EAAeqC,mBAAmB/C,GAClCwB,EAAewB,aACflC,EAAUmC,oBAAoB,SAAU9B,GACxCmB,MAED,CAAC5B,EAAgBV,IAEbW,CACT,kBCvDO,UAAkBuC,SAAEA,EAAAlD,WAAUA,KAAemD,IAClD,MAAOC,EAAaC,GAAkBjD,EAAAA,SAAS,GACzCkD,EAAc9C,EAAeR,IAC3BC,SAAUsD,GAAqB1D,IACjCK,EAAUH,EAAmBC,GAEnCK,EAAAA,UAAU,KACJkD,GACFF,EAAeE,EAAiBC,mBAEjC,CAACD,IAEJ,MAAME,MAAEA,KAAUC,GAAcP,EAEhC,OACEQ,EAAAA,IAACpE,EAAuBqE,SAAvB,CAAgCC,MAAOP,EACtCJ,SAAAS,EAAAA,IAAC,MAAA,IACKD,EACJI,IAAKR,EACLG,MAAO,CACL9B,MAAO,OACPE,OAAQ,OACRkC,SAAU,UACW,iBAAVN,EAAqBA,EAAQ,CAAA,EACxCO,QAAS,GAAGZ,OAGbF,UAAChD,GAAWgD,KAIrB,2HFhCkC,IACzBe,EAAAA,WAAW1E,0FAiCsBS,IACxC,MAAMC,SAAEA,GAAaJ,KACdqE,EAAgBC,GAAqB/D,WAAyB,CACnEgE,aAAa,EACbC,mBAAmB,IAerB,OAZAhE,EAAAA,UAAU,KACR,GAAKJ,EAGL,OAAOA,EAASqE,iBAAkB/D,IAE5BA,EAAMP,aAAeA,GACvBmE,EAAkB5D,EAAMgE,aAG3B,CAACtE,EAAUD,IAEPkE"}
@@ -1,11 +1,15 @@
1
1
  import { jsx } from "preact/jsx-runtime";
2
- import "preact";
3
- import { useState, useEffect, useRef, useLayoutEffect } from "preact/hooks";
2
+ import { createContext } from "preact";
3
+ import { useContext, useState, useEffect, useRef, useLayoutEffect } from "preact/hooks";
4
4
  import { usePlugin, useCapability } from "@embedpdf/core/preact";
5
5
  import { ViewportPlugin } from "@embedpdf/plugin-viewport";
6
6
  export * from "@embedpdf/plugin-viewport";
7
+ const ViewportElementContext = createContext(null);
7
8
  const useViewportPlugin = () => usePlugin(ViewportPlugin.id);
8
9
  const useViewportCapability = () => useCapability(ViewportPlugin.id);
10
+ const useViewportElement = () => {
11
+ return useContext(ViewportElementContext);
12
+ };
9
13
  const useIsViewportGated = (documentId) => {
10
14
  const { provides } = useViewportCapability();
11
15
  const [isGated, setIsGated] = useState((provides == null ? void 0 : provides.isGated(documentId)) ?? false);
@@ -49,14 +53,6 @@ function useViewportRef(documentId) {
49
53
  console.error(`Failed to register viewport for document ${documentId}:`, error);
50
54
  return;
51
55
  }
52
- const provideRect = () => {
53
- const r = container.getBoundingClientRect();
54
- return {
55
- origin: { x: r.left, y: r.top },
56
- size: { width: r.width, height: r.height }
57
- };
58
- };
59
- viewportPlugin.registerBoundingRectProvider(documentId, provideRect);
60
56
  const onScroll = () => {
61
57
  viewportPlugin.setViewportScrollMetrics(documentId, {
62
58
  scrollTop: container.scrollTop,
@@ -73,7 +69,9 @@ function useViewportRef(documentId) {
73
69
  scrollTop: container.scrollTop,
74
70
  scrollLeft: container.scrollLeft,
75
71
  scrollWidth: container.scrollWidth,
76
- scrollHeight: container.scrollHeight
72
+ scrollHeight: container.scrollHeight,
73
+ clientLeft: container.clientLeft,
74
+ clientTop: container.clientTop
77
75
  });
78
76
  });
79
77
  resizeObserver.observe(container);
@@ -87,7 +85,6 @@ function useViewportRef(documentId) {
87
85
  );
88
86
  return () => {
89
87
  viewportPlugin.unregisterViewport(documentId);
90
- viewportPlugin.registerBoundingRectProvider(documentId, null);
91
88
  resizeObserver.disconnect();
92
89
  container.removeEventListener("scroll", onScroll);
93
90
  unsubscribeScrollRequest();
@@ -106,7 +103,7 @@ function Viewport({ children, documentId, ...props }) {
106
103
  }
107
104
  }, [viewportProvides]);
108
105
  const { style, ...restProps } = props;
109
- return /* @__PURE__ */ jsx(
106
+ return /* @__PURE__ */ jsx(ViewportElementContext.Provider, { value: viewportRef, children: /* @__PURE__ */ jsx(
110
107
  "div",
111
108
  {
112
109
  ...restProps,
@@ -120,12 +117,14 @@ function Viewport({ children, documentId, ...props }) {
120
117
  },
121
118
  children: !isGated && children
122
119
  }
123
- );
120
+ ) });
124
121
  }
125
122
  export {
126
123
  Viewport,
124
+ ViewportElementContext,
127
125
  useIsViewportGated,
128
126
  useViewportCapability,
127
+ useViewportElement,
129
128
  useViewportPlugin,
130
129
  useViewportRef,
131
130
  useViewportScrollActivity
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { useEffect, useState } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { GateChangeEvent, ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\n/**\n * Hook to get the gated state of the viewport for a specific document.\n * The viewport children are not rendered when gated.\n * @param documentId Document ID.\n */\nexport const useIsViewportGated = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [isGated, setIsGated] = useState(provides?.isGated(documentId) ?? false);\n\n useEffect(() => {\n if (!provides) return;\n\n // Set initial state\n setIsGated(provides.isGated(documentId));\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === documentId) {\n setIsGated(event.isGated);\n }\n });\n }, [provides, documentId]);\n\n return isGated;\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param documentId Document ID.\n */\nexport const useViewportScrollActivity = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId if provided\n if (event.documentId === documentId) {\n setScrollActivity(event.activity);\n }\n });\n }, [provides, documentId]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef(documentId: string) {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Register this viewport for the document\n try {\n viewportPlugin.registerViewport(documentId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${documentId}:`, error);\n return;\n }\n\n // Provide rect calculator\n const provideRect = (): Rect => {\n const r = container.getBoundingClientRect();\n return {\n origin: { x: r.left, y: r.top },\n size: { width: r.width, height: r.height },\n };\n };\n viewportPlugin.registerBoundingRectProvider(documentId, provideRect);\n\n // On scroll\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics(documentId, {\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // On resize\n const resizeObserver = new ResizeObserver(() => {\n viewportPlugin.setViewportResizeMetrics(documentId, {\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n });\n });\n resizeObserver.observe(container);\n\n // Subscribe to scroll requests for this document\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n documentId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n viewportPlugin.unregisterViewport(documentId);\n viewportPlugin.registerBoundingRectProvider(documentId, null);\n resizeObserver.disconnect();\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin, documentId]);\n\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\nimport { useIsViewportGated, useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n};\n\nexport function Viewport({ children, documentId, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef(documentId);\n const { provides: viewportProvides } = useViewportCapability();\n const isGated = useIsViewportGated(documentId);\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n return (\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {!isGated && children}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/shared/context/viewport-element-context.ts","../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { createContext, RefObject } from '@framework';\n\n/**\n * Context to share the viewport DOM element reference with child components.\n * This allows child components (like ZoomGestureWrapper) to access the viewport\n * container element without DOM traversal.\n */\nexport const ViewportElementContext = createContext<RefObject<HTMLDivElement> | null>(null);\n","import { useEffect, useState, useContext, RefObject } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { GateChangeEvent, ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { ViewportElementContext } from '../context';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\n/**\n * Hook to get the viewport DOM element ref from context.\n * Must be used within a Viewport component.\n */\nexport const useViewportElement = (): RefObject<HTMLDivElement> | null => {\n return useContext(ViewportElementContext);\n};\n\n/**\n * Hook to get the gated state of the viewport for a specific document.\n * The viewport children are not rendered when gated.\n * @param documentId Document ID.\n */\nexport const useIsViewportGated = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [isGated, setIsGated] = useState(provides?.isGated(documentId) ?? false);\n\n useEffect(() => {\n if (!provides) return;\n\n // Set initial state\n setIsGated(provides.isGated(documentId));\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === documentId) {\n setIsGated(event.isGated);\n }\n });\n }, [provides, documentId]);\n\n return isGated;\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param documentId Document ID.\n */\nexport const useViewportScrollActivity = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId if provided\n if (event.documentId === documentId) {\n setScrollActivity(event.activity);\n }\n });\n }, [provides, documentId]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef(documentId: string) {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Register this viewport for the document\n try {\n viewportPlugin.registerViewport(documentId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${documentId}:`, error);\n return;\n }\n\n // On scroll\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics(documentId, {\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // On resize\n const resizeObserver = new ResizeObserver(() => {\n viewportPlugin.setViewportResizeMetrics(documentId, {\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n clientLeft: container.clientLeft,\n clientTop: container.clientTop,\n });\n });\n resizeObserver.observe(container);\n\n // Subscribe to scroll requests for this document\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n documentId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n viewportPlugin.unregisterViewport(documentId);\n resizeObserver.disconnect();\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin, documentId]);\n\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\nimport { useIsViewportGated, useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\nimport { ViewportElementContext } from '../context';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n};\n\nexport function Viewport({ children, documentId, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef(documentId);\n const { provides: viewportProvides } = useViewportCapability();\n const isGated = useIsViewportGated(documentId);\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n\n return (\n <ViewportElementContext.Provider value={viewportRef}>\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {!isGated && children}\n </div>\n </ViewportElementContext.Provider>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- export { Fragment, useEffect, useRef, useState, useCallback, useMemo, useLayoutEffect, } from 'react';
2
- export type { ReactNode, HTMLAttributes, CSSProperties } from 'react';
1
+ export { Fragment, useEffect, useRef, useState, useCallback, useMemo, useLayoutEffect, createContext, useContext, } from 'react';
2
+ export type { ReactNode, HTMLAttributes, CSSProperties, RefObject } from 'react';
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),t=require("react"),r=require("@embedpdf/core/react"),o=require("@embedpdf/plugin-viewport"),i=()=>r.usePlugin(o.ViewportPlugin.id),s=()=>r.useCapability(o.ViewportPlugin.id),n=e=>{const{provides:r}=s(),[o,i]=t.useState((null==r?void 0:r.isGated(e))??!1);return t.useEffect(()=>{if(r)return i(r.isGated(e)),r.onGateChange(t=>{t.documentId===e&&i(t.isGated)})},[r,e]),o};function l(e){const{plugin:r}=i(),o=t.useRef(null);return t.useLayoutEffect(()=>{if(!r)return;const t=o.current;if(!t)return;try{r.registerViewport(e)}catch(l){return void console.error(`Failed to register viewport for document ${e}:`,l)}r.registerBoundingRectProvider(e,()=>{const e=t.getBoundingClientRect();return{origin:{x:e.left,y:e.top},size:{width:e.width,height:e.height}}});const i=()=>{r.setViewportScrollMetrics(e,{scrollTop:t.scrollTop,scrollLeft:t.scrollLeft})};t.addEventListener("scroll",i);const s=new ResizeObserver(()=>{r.setViewportResizeMetrics(e,{width:t.offsetWidth,height:t.offsetHeight,clientWidth:t.clientWidth,clientHeight:t.clientHeight,scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,scrollHeight:t.scrollHeight})});s.observe(t);const n=r.onScrollRequest(e,({x:e,y:r,behavior:o="auto"})=>{requestAnimationFrame(()=>{t.scrollTo({left:e,top:r,behavior:o})})});return()=>{r.unregisterViewport(e),r.registerBoundingRectProvider(e,null),s.disconnect(),t.removeEventListener("scroll",i),n()}},[r,e]),o}exports.Viewport=function({children:r,documentId:o,...i}){const[c,u]=t.useState(0),d=l(o),{provides:p}=s(),a=n(o);t.useEffect(()=>{p&&u(p.getViewportGap())},[p]);const{style:f,...g}=i;return e.jsx("div",{...g,ref:d,style:{width:"100%",height:"100%",overflow:"auto",..."object"==typeof f?f:{},padding:`${c}px`},children:!a&&r})},exports.useIsViewportGated=n,exports.useViewportCapability=s,exports.useViewportPlugin=i,exports.useViewportRef=l,exports.useViewportScrollActivity=e=>{const{provides:r}=s(),[o,i]=t.useState({isScrolling:!1,isSmoothScrolling:!1});return t.useEffect(()=>{if(r)return r.onScrollActivity(t=>{t.documentId===e&&i(t.activity)})},[r,e]),o},Object.keys(o).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>o[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),t=require("react"),r=require("@embedpdf/core/react"),o=require("@embedpdf/plugin-viewport"),i=t.createContext(null),s=()=>r.usePlugin(o.ViewportPlugin.id),l=()=>r.useCapability(o.ViewportPlugin.id),n=e=>{const{provides:r}=l(),[o,i]=t.useState((null==r?void 0:r.isGated(e))??!1);return t.useEffect(()=>{if(r)return i(r.isGated(e)),r.onGateChange(t=>{t.documentId===e&&i(t.isGated)})},[r,e]),o};function c(e){const{plugin:r}=s(),o=t.useRef(null);return t.useLayoutEffect(()=>{if(!r)return;const t=o.current;if(!t)return;try{r.registerViewport(e)}catch(n){return void console.error(`Failed to register viewport for document ${e}:`,n)}const i=()=>{r.setViewportScrollMetrics(e,{scrollTop:t.scrollTop,scrollLeft:t.scrollLeft})};t.addEventListener("scroll",i);const s=new ResizeObserver(()=>{r.setViewportResizeMetrics(e,{width:t.offsetWidth,height:t.offsetHeight,clientWidth:t.clientWidth,clientHeight:t.clientHeight,scrollTop:t.scrollTop,scrollLeft:t.scrollLeft,scrollWidth:t.scrollWidth,scrollHeight:t.scrollHeight,clientLeft:t.clientLeft,clientTop:t.clientTop})});s.observe(t);const l=r.onScrollRequest(e,({x:e,y:r,behavior:o="auto"})=>{requestAnimationFrame(()=>{t.scrollTo({left:e,top:r,behavior:o})})});return()=>{r.unregisterViewport(e),s.disconnect(),t.removeEventListener("scroll",i),l()}},[r,e]),o}exports.Viewport=function({children:r,documentId:o,...s}){const[u,p]=t.useState(0),d=c(o),{provides:a}=l(),f=n(o);t.useEffect(()=>{a&&p(a.getViewportGap())},[a]);const{style:h,...g}=s;return e.jsx(i.Provider,{value:d,children:e.jsx("div",{...g,ref:d,style:{width:"100%",height:"100%",overflow:"auto",..."object"==typeof h?h:{},padding:`${u}px`},children:!f&&r})})},exports.ViewportElementContext=i,exports.useIsViewportGated=n,exports.useViewportCapability=l,exports.useViewportElement=()=>t.useContext(i),exports.useViewportPlugin=s,exports.useViewportRef=c,exports.useViewportScrollActivity=e=>{const{provides:r}=l(),[o,i]=t.useState({isScrolling:!1,isSmoothScrolling:!1});return t.useEffect(()=>{if(r)return r.onScrollActivity(t=>{t.documentId===e&&i(t.activity)})},[r,e]),o},Object.keys(o).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>o[e]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { useEffect, useState } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { GateChangeEvent, ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\n/**\n * Hook to get the gated state of the viewport for a specific document.\n * The viewport children are not rendered when gated.\n * @param documentId Document ID.\n */\nexport const useIsViewportGated = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [isGated, setIsGated] = useState(provides?.isGated(documentId) ?? false);\n\n useEffect(() => {\n if (!provides) return;\n\n // Set initial state\n setIsGated(provides.isGated(documentId));\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === documentId) {\n setIsGated(event.isGated);\n }\n });\n }, [provides, documentId]);\n\n return isGated;\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param documentId Document ID.\n */\nexport const useViewportScrollActivity = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId if provided\n if (event.documentId === documentId) {\n setScrollActivity(event.activity);\n }\n });\n }, [provides, documentId]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef(documentId: string) {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Register this viewport for the document\n try {\n viewportPlugin.registerViewport(documentId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${documentId}:`, error);\n return;\n }\n\n // Provide rect calculator\n const provideRect = (): Rect => {\n const r = container.getBoundingClientRect();\n return {\n origin: { x: r.left, y: r.top },\n size: { width: r.width, height: r.height },\n };\n };\n viewportPlugin.registerBoundingRectProvider(documentId, provideRect);\n\n // On scroll\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics(documentId, {\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // On resize\n const resizeObserver = new ResizeObserver(() => {\n viewportPlugin.setViewportResizeMetrics(documentId, {\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n });\n });\n resizeObserver.observe(container);\n\n // Subscribe to scroll requests for this document\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n documentId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n viewportPlugin.unregisterViewport(documentId);\n viewportPlugin.registerBoundingRectProvider(documentId, null);\n resizeObserver.disconnect();\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin, documentId]);\n\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\nimport { useIsViewportGated, useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n};\n\nexport function Viewport({ children, documentId, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef(documentId);\n const { provides: viewportProvides } = useViewportCapability();\n const isGated = useIsViewportGated(documentId);\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n return (\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {!isGated && children}\n </div>\n );\n}\n"],"names":["useViewportPlugin","usePlugin","ViewportPlugin","id","useViewportCapability","useCapability","useIsViewportGated","documentId","provides","isGated","setIsGated","useState","useEffect","onGateChange","event","useViewportRef","plugin","viewportPlugin","containerRef","useRef","useLayoutEffect","container","current","registerViewport","error","console","registerBoundingRectProvider","r","getBoundingClientRect","origin","x","left","y","top","size","width","height","onScroll","setViewportScrollMetrics","scrollTop","scrollLeft","addEventListener","resizeObserver","ResizeObserver","setViewportResizeMetrics","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","observe","unsubscribeScrollRequest","onScrollRequest","behavior","requestAnimationFrame","scrollTo","unregisterViewport","disconnect","removeEventListener","children","props","viewportGap","setViewportGap","viewportRef","viewportProvides","getViewportGap","style","restProps","jsx","ref","overflow","padding","scrollActivity","setScrollActivity","isScrolling","isSmoothScrolling","onScrollActivity","activity"],"mappings":"iNAIaA,EAAoB,IAAMC,YAA0BC,EAAAA,eAAeC,IACnEC,EAAwB,IAAMC,gBAA8BH,EAAAA,eAAeC,IAO3EG,EAAsBC,IACjC,MAAMC,SAAEA,GAAaJ,KACdK,EAASC,GAAcC,EAAAA,UAAS,MAAAH,OAAA,EAAAA,EAAUC,QAAQF,MAAe,GAgBxE,OAdAK,EAAAA,UAAU,KACR,GAAKJ,EAML,OAHAE,EAAWF,EAASC,QAAQF,IAGrBC,EAASK,aAAcC,IACxBA,EAAMP,aAAeA,GACvBG,EAAWI,EAAML,YAGpB,CAACD,EAAUD,IAEPE,GC1BF,SAASM,EAAeR,GAC7B,MAAQS,OAAQC,GAAmBjB,IAC7BkB,EAAeC,EAAAA,OAAuB,MAsE5C,OApEAC,EAAAA,gBAAgB,KACd,IAAKH,EAAgB,OAErB,MAAMI,EAAYH,EAAaI,QAC/B,IAAKD,EAAW,OAGhB,IACEJ,EAAeM,iBAAiBhB,EAClC,OAASiB,GAEP,YADAC,QAAQD,MAAM,4CAA4CjB,KAAeiB,EAE3E,CAUAP,EAAeS,6BAA6BnB,EAPxB,KAClB,MAAMoB,EAAIN,EAAUO,wBACpB,MAAO,CACLC,OAAQ,CAAEC,EAAGH,EAAEI,KAAMC,EAAGL,EAAEM,KAC1BC,KAAM,CAAEC,MAAOR,EAAEQ,MAAOC,OAAQT,EAAES,WAMtC,MAAMC,EAAW,KACfpB,EAAeqB,yBAAyB/B,EAAY,CAClDgC,UAAWlB,EAAUkB,UACrBC,WAAYnB,EAAUmB,cAG1BnB,EAAUoB,iBAAiB,SAAUJ,GAGrC,MAAMK,EAAiB,IAAIC,eAAe,KACxC1B,EAAe2B,yBAAyBrC,EAAY,CAClD4B,MAAOd,EAAUwB,YACjBT,OAAQf,EAAUyB,aAClBC,YAAa1B,EAAU0B,YACvBC,aAAc3B,EAAU2B,aACxBT,UAAWlB,EAAUkB,UACrBC,WAAYnB,EAAUmB,WACtBS,YAAa5B,EAAU4B,YACvBC,aAAc7B,EAAU6B,iBAG5BR,EAAeS,QAAQ9B,GAGvB,MAAM+B,EAA2BnC,EAAeoC,gBAC9C9C,EACA,EAAGuB,IAAGE,IAAGsB,WAAW,WAClBC,sBAAsB,KACpBlC,EAAUmC,SAAS,CAAEzB,KAAMD,EAAGG,IAAKD,EAAGsB,iBAM5C,MAAO,KACLrC,EAAewC,mBAAmBlD,GAClCU,EAAeS,6BAA6BnB,EAAY,MACxDmC,EAAegB,aACfrC,EAAUsC,oBAAoB,SAAUtB,GACxCe,MAED,CAACnC,EAAgBV,IAEbW,CACT,kBCjEO,UAAkB0C,SAAEA,EAAArD,WAAUA,KAAesD,IAClD,MAAOC,EAAaC,GAAkBpD,EAAAA,SAAS,GACzCqD,EAAcjD,EAAeR,IAC3BC,SAAUyD,GAAqB7D,IACjCK,EAAUH,EAAmBC,GAEnCK,EAAAA,UAAU,KACJqD,GACFF,EAAeE,EAAiBC,mBAEjC,CAACD,IAEJ,MAAME,MAAEA,KAAUC,GAAcP,EAChC,OACEQ,EAAAA,IAAC,MAAA,IACKD,EACJE,IAAKN,EACLG,MAAO,CACLhC,MAAO,OACPC,OAAQ,OACRmC,SAAU,UACW,iBAAVJ,EAAqBA,EAAQ,CAAA,EACxCK,QAAS,GAAGV,OAGbF,UAACnD,GAAWmD,GAGnB,sJFH0CrD,IACxC,MAAMC,SAAEA,GAAaJ,KACdqE,EAAgBC,GAAqB/D,WAAyB,CACnEgE,aAAa,EACbC,mBAAmB,IAerB,OAZAhE,EAAAA,UAAU,KACR,GAAKJ,EAGL,OAAOA,EAASqE,iBAAkB/D,IAE5BA,EAAMP,aAAeA,GACvBmE,EAAkB5D,EAAMgE,aAG3B,CAACtE,EAAUD,IAEPkE"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/shared/context/viewport-element-context.ts","../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { createContext, RefObject } from '@framework';\n\n/**\n * Context to share the viewport DOM element reference with child components.\n * This allows child components (like ZoomGestureWrapper) to access the viewport\n * container element without DOM traversal.\n */\nexport const ViewportElementContext = createContext<RefObject<HTMLDivElement> | null>(null);\n","import { useEffect, useState, useContext, RefObject } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { GateChangeEvent, ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { ViewportElementContext } from '../context';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\n/**\n * Hook to get the viewport DOM element ref from context.\n * Must be used within a Viewport component.\n */\nexport const useViewportElement = (): RefObject<HTMLDivElement> | null => {\n return useContext(ViewportElementContext);\n};\n\n/**\n * Hook to get the gated state of the viewport for a specific document.\n * The viewport children are not rendered when gated.\n * @param documentId Document ID.\n */\nexport const useIsViewportGated = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [isGated, setIsGated] = useState(provides?.isGated(documentId) ?? false);\n\n useEffect(() => {\n if (!provides) return;\n\n // Set initial state\n setIsGated(provides.isGated(documentId));\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === documentId) {\n setIsGated(event.isGated);\n }\n });\n }, [provides, documentId]);\n\n return isGated;\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param documentId Document ID.\n */\nexport const useViewportScrollActivity = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId if provided\n if (event.documentId === documentId) {\n setScrollActivity(event.activity);\n }\n });\n }, [provides, documentId]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef(documentId: string) {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Register this viewport for the document\n try {\n viewportPlugin.registerViewport(documentId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${documentId}:`, error);\n return;\n }\n\n // On scroll\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics(documentId, {\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // On resize\n const resizeObserver = new ResizeObserver(() => {\n viewportPlugin.setViewportResizeMetrics(documentId, {\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n clientLeft: container.clientLeft,\n clientTop: container.clientTop,\n });\n });\n resizeObserver.observe(container);\n\n // Subscribe to scroll requests for this document\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n documentId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n viewportPlugin.unregisterViewport(documentId);\n resizeObserver.disconnect();\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin, documentId]);\n\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\nimport { useIsViewportGated, useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\nimport { ViewportElementContext } from '../context';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n};\n\nexport function Viewport({ children, documentId, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef(documentId);\n const { provides: viewportProvides } = useViewportCapability();\n const isGated = useIsViewportGated(documentId);\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n\n return (\n <ViewportElementContext.Provider value={viewportRef}>\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {!isGated && children}\n </div>\n </ViewportElementContext.Provider>\n );\n}\n"],"names":["ViewportElementContext","createContext","useViewportPlugin","usePlugin","ViewportPlugin","id","useViewportCapability","useCapability","useIsViewportGated","documentId","provides","isGated","setIsGated","useState","useEffect","onGateChange","event","useViewportRef","plugin","viewportPlugin","containerRef","useRef","useLayoutEffect","container","current","registerViewport","error","console","onScroll","setViewportScrollMetrics","scrollTop","scrollLeft","addEventListener","resizeObserver","ResizeObserver","setViewportResizeMetrics","width","offsetWidth","height","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","clientLeft","clientTop","observe","unsubscribeScrollRequest","onScrollRequest","x","y","behavior","requestAnimationFrame","scrollTo","left","top","unregisterViewport","disconnect","removeEventListener","children","props","viewportGap","setViewportGap","viewportRef","viewportProvides","getViewportGap","style","restProps","jsx","Provider","value","ref","overflow","padding","useContext","scrollActivity","setScrollActivity","isScrolling","isSmoothScrolling","onScrollActivity","activity"],"mappings":"iNAOaA,EAAyBC,EAAAA,cAAgD,MCFzEC,EAAoB,IAAMC,YAA0BC,EAAAA,eAAeC,IACnEC,EAAwB,IAAMC,gBAA8BH,EAAAA,eAAeC,IAe3EG,EAAsBC,IACjC,MAAMC,SAAEA,GAAaJ,KACdK,EAASC,GAAcC,EAAAA,UAAS,MAAAH,OAAA,EAAAA,EAAUC,QAAQF,MAAe,GAgBxE,OAdAK,EAAAA,UAAU,KACR,GAAKJ,EAML,OAHAE,EAAWF,EAASC,QAAQF,IAGrBC,EAASK,aAAcC,IACxBA,EAAMP,aAAeA,GACvBG,EAAWI,EAAML,YAGpB,CAACD,EAAUD,IAEPE,GCnCF,SAASM,EAAeR,GAC7B,MAAQS,OAAQC,GAAmBjB,IAC7BkB,EAAeC,EAAAA,OAAuB,MA6D5C,OA3DAC,EAAAA,gBAAgB,KACd,IAAKH,EAAgB,OAErB,MAAMI,EAAYH,EAAaI,QAC/B,IAAKD,EAAW,OAGhB,IACEJ,EAAeM,iBAAiBhB,EAClC,OAASiB,GAEP,YADAC,QAAQD,MAAM,4CAA4CjB,KAAeiB,EAE3E,CAGA,MAAME,EAAW,KACfT,EAAeU,yBAAyBpB,EAAY,CAClDqB,UAAWP,EAAUO,UACrBC,WAAYR,EAAUQ,cAG1BR,EAAUS,iBAAiB,SAAUJ,GAGrC,MAAMK,EAAiB,IAAIC,eAAe,KACxCf,EAAegB,yBAAyB1B,EAAY,CAClD2B,MAAOb,EAAUc,YACjBC,OAAQf,EAAUgB,aAClBC,YAAajB,EAAUiB,YACvBC,aAAclB,EAAUkB,aACxBX,UAAWP,EAAUO,UACrBC,WAAYR,EAAUQ,WACtBW,YAAanB,EAAUmB,YACvBC,aAAcpB,EAAUoB,aACxBC,WAAYrB,EAAUqB,WACtBC,UAAWtB,EAAUsB,cAGzBZ,EAAea,QAAQvB,GAGvB,MAAMwB,EAA2B5B,EAAe6B,gBAC9CvC,EACA,EAAGwC,IAAGC,IAAGC,WAAW,WAClBC,sBAAsB,KACpB7B,EAAU8B,SAAS,CAAEC,KAAML,EAAGM,IAAKL,EAAGC,iBAM5C,MAAO,KACLhC,EAAeqC,mBAAmB/C,GAClCwB,EAAewB,aACflC,EAAUmC,oBAAoB,SAAU9B,GACxCmB,MAED,CAAC5B,EAAgBV,IAEbW,CACT,kBCvDO,UAAkBuC,SAAEA,EAAAlD,WAAUA,KAAemD,IAClD,MAAOC,EAAaC,GAAkBjD,EAAAA,SAAS,GACzCkD,EAAc9C,EAAeR,IAC3BC,SAAUsD,GAAqB1D,IACjCK,EAAUH,EAAmBC,GAEnCK,EAAAA,UAAU,KACJkD,GACFF,EAAeE,EAAiBC,mBAEjC,CAACD,IAEJ,MAAME,MAAEA,KAAUC,GAAcP,EAEhC,OACEQ,EAAAA,IAACpE,EAAuBqE,SAAvB,CAAgCC,MAAOP,EACtCJ,SAAAS,EAAAA,IAAC,MAAA,IACKD,EACJI,IAAKR,EACLG,MAAO,CACL9B,MAAO,OACPE,OAAQ,OACRkC,SAAU,UACW,iBAAVN,EAAqBA,EAAQ,CAAA,EACxCO,QAAS,GAAGZ,OAGbF,UAAChD,GAAWgD,KAIrB,2HFhCkC,IACzBe,EAAAA,WAAW1E,0FAiCsBS,IACxC,MAAMC,SAAEA,GAAaJ,KACdqE,EAAgBC,GAAqB/D,WAAyB,CACnEgE,aAAa,EACbC,mBAAmB,IAerB,OAZAhE,EAAAA,UAAU,KACR,GAAKJ,EAGL,OAAOA,EAASqE,iBAAkB/D,IAE5BA,EAAMP,aAAeA,GACvBmE,EAAkB5D,EAAMgE,aAG3B,CAACtE,EAAUD,IAEPkE"}
@@ -1,10 +1,14 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { useState, useEffect, useRef, useLayoutEffect } from "react";
2
+ import { createContext, useContext, useState, useEffect, useRef, useLayoutEffect } from "react";
3
3
  import { usePlugin, useCapability } from "@embedpdf/core/react";
4
4
  import { ViewportPlugin } from "@embedpdf/plugin-viewport";
5
5
  export * from "@embedpdf/plugin-viewport";
6
+ const ViewportElementContext = createContext(null);
6
7
  const useViewportPlugin = () => usePlugin(ViewportPlugin.id);
7
8
  const useViewportCapability = () => useCapability(ViewportPlugin.id);
9
+ const useViewportElement = () => {
10
+ return useContext(ViewportElementContext);
11
+ };
8
12
  const useIsViewportGated = (documentId) => {
9
13
  const { provides } = useViewportCapability();
10
14
  const [isGated, setIsGated] = useState((provides == null ? void 0 : provides.isGated(documentId)) ?? false);
@@ -48,14 +52,6 @@ function useViewportRef(documentId) {
48
52
  console.error(`Failed to register viewport for document ${documentId}:`, error);
49
53
  return;
50
54
  }
51
- const provideRect = () => {
52
- const r = container.getBoundingClientRect();
53
- return {
54
- origin: { x: r.left, y: r.top },
55
- size: { width: r.width, height: r.height }
56
- };
57
- };
58
- viewportPlugin.registerBoundingRectProvider(documentId, provideRect);
59
55
  const onScroll = () => {
60
56
  viewportPlugin.setViewportScrollMetrics(documentId, {
61
57
  scrollTop: container.scrollTop,
@@ -72,7 +68,9 @@ function useViewportRef(documentId) {
72
68
  scrollTop: container.scrollTop,
73
69
  scrollLeft: container.scrollLeft,
74
70
  scrollWidth: container.scrollWidth,
75
- scrollHeight: container.scrollHeight
71
+ scrollHeight: container.scrollHeight,
72
+ clientLeft: container.clientLeft,
73
+ clientTop: container.clientTop
76
74
  });
77
75
  });
78
76
  resizeObserver.observe(container);
@@ -86,7 +84,6 @@ function useViewportRef(documentId) {
86
84
  );
87
85
  return () => {
88
86
  viewportPlugin.unregisterViewport(documentId);
89
- viewportPlugin.registerBoundingRectProvider(documentId, null);
90
87
  resizeObserver.disconnect();
91
88
  container.removeEventListener("scroll", onScroll);
92
89
  unsubscribeScrollRequest();
@@ -105,7 +102,7 @@ function Viewport({ children, documentId, ...props }) {
105
102
  }
106
103
  }, [viewportProvides]);
107
104
  const { style, ...restProps } = props;
108
- return /* @__PURE__ */ jsx(
105
+ return /* @__PURE__ */ jsx(ViewportElementContext.Provider, { value: viewportRef, children: /* @__PURE__ */ jsx(
109
106
  "div",
110
107
  {
111
108
  ...restProps,
@@ -119,12 +116,14 @@ function Viewport({ children, documentId, ...props }) {
119
116
  },
120
117
  children: !isGated && children
121
118
  }
122
- );
119
+ ) });
123
120
  }
124
121
  export {
125
122
  Viewport,
123
+ ViewportElementContext,
126
124
  useIsViewportGated,
127
125
  useViewportCapability,
126
+ useViewportElement,
128
127
  useViewportPlugin,
129
128
  useViewportRef,
130
129
  useViewportScrollActivity
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { useEffect, useState } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { GateChangeEvent, ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\n/**\n * Hook to get the gated state of the viewport for a specific document.\n * The viewport children are not rendered when gated.\n * @param documentId Document ID.\n */\nexport const useIsViewportGated = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [isGated, setIsGated] = useState(provides?.isGated(documentId) ?? false);\n\n useEffect(() => {\n if (!provides) return;\n\n // Set initial state\n setIsGated(provides.isGated(documentId));\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === documentId) {\n setIsGated(event.isGated);\n }\n });\n }, [provides, documentId]);\n\n return isGated;\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param documentId Document ID.\n */\nexport const useViewportScrollActivity = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId if provided\n if (event.documentId === documentId) {\n setScrollActivity(event.activity);\n }\n });\n }, [provides, documentId]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef(documentId: string) {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Register this viewport for the document\n try {\n viewportPlugin.registerViewport(documentId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${documentId}:`, error);\n return;\n }\n\n // Provide rect calculator\n const provideRect = (): Rect => {\n const r = container.getBoundingClientRect();\n return {\n origin: { x: r.left, y: r.top },\n size: { width: r.width, height: r.height },\n };\n };\n viewportPlugin.registerBoundingRectProvider(documentId, provideRect);\n\n // On scroll\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics(documentId, {\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // On resize\n const resizeObserver = new ResizeObserver(() => {\n viewportPlugin.setViewportResizeMetrics(documentId, {\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n });\n });\n resizeObserver.observe(container);\n\n // Subscribe to scroll requests for this document\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n documentId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n viewportPlugin.unregisterViewport(documentId);\n viewportPlugin.registerBoundingRectProvider(documentId, null);\n resizeObserver.disconnect();\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin, documentId]);\n\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\nimport { useIsViewportGated, useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n};\n\nexport function Viewport({ children, documentId, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef(documentId);\n const { provides: viewportProvides } = useViewportCapability();\n const isGated = useIsViewportGated(documentId);\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n return (\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {!isGated && children}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/shared/context/viewport-element-context.ts","../../src/shared/hooks/use-viewport.ts","../../src/shared/hooks/use-viewport-ref.ts","../../src/shared/components/viewport.tsx"],"sourcesContent":["import { createContext, RefObject } from '@framework';\n\n/**\n * Context to share the viewport DOM element reference with child components.\n * This allows child components (like ZoomGestureWrapper) to access the viewport\n * container element without DOM traversal.\n */\nexport const ViewportElementContext = createContext<RefObject<HTMLDivElement> | null>(null);\n","import { useEffect, useState, useContext, RefObject } from '@framework';\nimport { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { GateChangeEvent, ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\nimport { ViewportElementContext } from '../context';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\n/**\n * Hook to get the viewport DOM element ref from context.\n * Must be used within a Viewport component.\n */\nexport const useViewportElement = (): RefObject<HTMLDivElement> | null => {\n return useContext(ViewportElementContext);\n};\n\n/**\n * Hook to get the gated state of the viewport for a specific document.\n * The viewport children are not rendered when gated.\n * @param documentId Document ID.\n */\nexport const useIsViewportGated = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [isGated, setIsGated] = useState(provides?.isGated(documentId) ?? false);\n\n useEffect(() => {\n if (!provides) return;\n\n // Set initial state\n setIsGated(provides.isGated(documentId));\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === documentId) {\n setIsGated(event.isGated);\n }\n });\n }, [provides, documentId]);\n\n return isGated;\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param documentId Document ID.\n */\nexport const useViewportScrollActivity = (documentId: string) => {\n const { provides } = useViewportCapability();\n const [scrollActivity, setScrollActivity] = useState<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n useEffect(() => {\n if (!provides) return;\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId if provided\n if (event.documentId === documentId) {\n setScrollActivity(event.activity);\n }\n });\n }, [provides, documentId]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef(documentId: string) {\n const { plugin: viewportPlugin } = useViewportPlugin();\n const containerRef = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n if (!viewportPlugin) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Register this viewport for the document\n try {\n viewportPlugin.registerViewport(documentId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${documentId}:`, error);\n return;\n }\n\n // On scroll\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics(documentId, {\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // On resize\n const resizeObserver = new ResizeObserver(() => {\n viewportPlugin.setViewportResizeMetrics(documentId, {\n width: container.offsetWidth,\n height: container.offsetHeight,\n clientWidth: container.clientWidth,\n clientHeight: container.clientHeight,\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n scrollWidth: container.scrollWidth,\n scrollHeight: container.scrollHeight,\n clientLeft: container.clientLeft,\n clientTop: container.clientTop,\n });\n });\n resizeObserver.observe(container);\n\n // Subscribe to scroll requests for this document\n const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n documentId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n viewportPlugin.unregisterViewport(documentId);\n resizeObserver.disconnect();\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin, documentId]);\n\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\nimport { useIsViewportGated, useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\nimport { ViewportElementContext } from '../context';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n};\n\nexport function Viewport({ children, documentId, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef(documentId);\n const { provides: viewportProvides } = useViewportCapability();\n const isGated = useIsViewportGated(documentId);\n\n useEffect(() => {\n if (viewportProvides) {\n setViewportGap(viewportProvides.getViewportGap());\n }\n }, [viewportProvides]);\n\n const { style, ...restProps } = props;\n\n return (\n <ViewportElementContext.Provider value={viewportRef}>\n <div\n {...restProps}\n ref={viewportRef}\n style={{\n width: '100%',\n height: '100%',\n overflow: 'auto',\n ...(typeof style === 'object' ? style : {}),\n padding: `${viewportGap}px`,\n }}\n >\n {!isGated && children}\n </div>\n </ViewportElementContext.Provider>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export * from './viewport-element-context';
@@ -0,0 +1,7 @@
1
+ import { RefObject } from '../../react/adapter.ts';
2
+ /**
3
+ * Context to share the viewport DOM element reference with child components.
4
+ * This allows child components (like ZoomGestureWrapper) to access the viewport
5
+ * container element without DOM traversal.
6
+ */
7
+ export declare const ViewportElementContext: import('react').Context<RefObject<HTMLDivElement> | null>;
@@ -1,3 +1,4 @@
1
+ import { RefObject } from '../../react/adapter.ts';
1
2
  import { ScrollActivity, ViewportPlugin } from '../../index.ts';
2
3
  export declare const useViewportPlugin: () => {
3
4
  plugin: ViewportPlugin | null;
@@ -9,6 +10,11 @@ export declare const useViewportCapability: () => {
9
10
  isLoading: boolean;
10
11
  ready: Promise<void>;
11
12
  };
13
+ /**
14
+ * Hook to get the viewport DOM element ref from context.
15
+ * Must be used within a Viewport component.
16
+ */
17
+ export declare const useViewportElement: () => RefObject<HTMLDivElement> | null;
12
18
  /**
13
19
  * Hook to get the gated state of the viewport for a specific document.
14
20
  * The viewport children are not rendered when gated.
@@ -1,3 +1,4 @@
1
1
  export * from './components';
2
2
  export * from './hooks';
3
+ export * from './context';
3
4
  export * from '../index.ts';
@@ -0,0 +1 @@
1
+ export * from './viewport-element-context';
@@ -0,0 +1,7 @@
1
+ import { RefObject } from '../../preact/adapter.ts';
2
+ /**
3
+ * Context to share the viewport DOM element reference with child components.
4
+ * This allows child components (like ZoomGestureWrapper) to access the viewport
5
+ * container element without DOM traversal.
6
+ */
7
+ export declare const ViewportElementContext: import('preact').Context<RefObject<HTMLDivElement> | null>;
@@ -1,3 +1,4 @@
1
+ import { RefObject } from '../../preact/adapter.ts';
1
2
  import { ScrollActivity, ViewportPlugin } from '../../lib/index.ts';
2
3
  export declare const useViewportPlugin: () => {
3
4
  plugin: ViewportPlugin | null;
@@ -9,6 +10,11 @@ export declare const useViewportCapability: () => {
9
10
  isLoading: boolean;
10
11
  ready: Promise<void>;
11
12
  };
13
+ /**
14
+ * Hook to get the viewport DOM element ref from context.
15
+ * Must be used within a Viewport component.
16
+ */
17
+ export declare const useViewportElement: () => RefObject<HTMLDivElement> | null;
12
18
  /**
13
19
  * Hook to get the gated state of the viewport for a specific document.
14
20
  * The viewport children are not rendered when gated.
@@ -1,3 +1,4 @@
1
1
  export * from './components';
2
2
  export * from './hooks';
3
+ export * from './context';
3
4
  export * from '../lib/index.ts';
@@ -0,0 +1 @@
1
+ export * from './viewport-element-context';
@@ -0,0 +1,7 @@
1
+ import { RefObject } from '../../react/adapter.ts';
2
+ /**
3
+ * Context to share the viewport DOM element reference with child components.
4
+ * This allows child components (like ZoomGestureWrapper) to access the viewport
5
+ * container element without DOM traversal.
6
+ */
7
+ export declare const ViewportElementContext: import('react').Context<RefObject<HTMLDivElement> | null>;
@@ -1,3 +1,4 @@
1
+ import { RefObject } from '../../react/adapter.ts';
1
2
  import { ScrollActivity, ViewportPlugin } from '../../lib/index.ts';
2
3
  export declare const useViewportPlugin: () => {
3
4
  plugin: ViewportPlugin | null;
@@ -9,6 +10,11 @@ export declare const useViewportCapability: () => {
9
10
  isLoading: boolean;
10
11
  ready: Promise<void>;
11
12
  };
13
+ /**
14
+ * Hook to get the viewport DOM element ref from context.
15
+ * Must be used within a Viewport component.
16
+ */
17
+ export declare const useViewportElement: () => RefObject<HTMLDivElement> | null;
12
18
  /**
13
19
  * Hook to get the gated state of the viewport for a specific document.
14
20
  * The viewport children are not rendered when gated.
@@ -1,3 +1,4 @@
1
1
  export * from './components';
2
2
  export * from './hooks';
3
+ export * from './context';
3
4
  export * from '../lib/index.ts';
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"}),require("svelte/internal/disclose-version");const e=require("svelte/internal/client"),t=require("@embedpdf/core/svelte"),r=require("@embedpdf/plugin-viewport");function o(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const r in e)if("default"!==r){const o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:()=>e[r]})}return t.default=e,Object.freeze(t)}const i=o(e),s=()=>t.usePlugin(r.ViewportPlugin.id),n=()=>t.useCapability(r.ViewportPlugin.id),l=e=>{const t=n();let r=i.state(!1);const o=i.derived(e);return i.user_effect(()=>{const e=t.provides,s=i.get(o);if(e&&s)return i.set(r,e.isGated(s),!0),e.onGateChange(e=>{e.documentId===s&&i.set(r,e.isGated,!0)});i.set(r,!1)}),{get current(){return i.get(r)}}};function c(e){const{plugin:t}=s();let r=i.state(null);const o=i.derived(e);return i.user_pre_effect(()=>{if(!t)return;const e=i.get(r),s=i.get(o);if(!e||!s)return;try{t.registerViewport(s)}catch(u){return void console.error(`Failed to register viewport for document ${s}:`,u)}t.registerBoundingRectProvider(s,()=>{const t=e.getBoundingClientRect();return{origin:{x:t.left,y:t.top},size:{width:t.width,height:t.height}}});const n=()=>{t.setViewportScrollMetrics(s,{scrollTop:e.scrollTop,scrollLeft:e.scrollLeft})};e.addEventListener("scroll",n);const l=new ResizeObserver(()=>{t.setViewportResizeMetrics(s,{width:e.offsetWidth,height:e.offsetHeight,clientWidth:e.clientWidth,clientHeight:e.clientHeight,scrollTop:e.scrollTop,scrollLeft:e.scrollLeft,scrollWidth:e.scrollWidth,scrollHeight:e.scrollHeight})});l.observe(e);const c=t.onScrollRequest(s,({x:t,y:r,behavior:o="auto"})=>{requestAnimationFrame(()=>{e.scrollTo({left:t,top:r,behavior:o})})});return()=>{t.unregisterViewport(s),t.registerBoundingRectProvider(s,null),e.removeEventListener("scroll",n),l.disconnect(),c()}}),{get containerRef(){return i.get(r)},set containerRef(e){i.set(r,e,!0)}}}var u=i.from_html("<div><!></div>");exports.Viewport=function(e,t){i.push(t,!0);let r=i.rest_props(t,["$$slots","$$events","$$legacy","documentId","children","class"]),o=i.state(0);const s=c(()=>t.documentId),d=n(),p=l(()=>t.documentId);i.user_effect(()=>{d.provides&&i.set(o,d.provides.getViewportGap(),!0)});var a=u();i.attribute_effect(a,()=>({...r,class:t.class,[i.STYLE]:{width:"100%",height:"100%",overflow:"auto",padding:`${i.get(o)}px`}}));var g=i.child(a),f=e=>{var r=i.comment(),o=i.first_child(r);i.snippet(o,()=>t.children),i.append(e,r)};i.if(g,e=>{p.current||e(f)}),i.reset(a),i.bind_this(a,e=>s.containerRef=e,()=>null==s?void 0:s.containerRef),i.append(e,a),i.pop()},exports.useIsViewportGated=l,exports.useViewportCapability=n,exports.useViewportPlugin=s,exports.useViewportRef=c,exports.useViewportScrollActivity=e=>{const t=n();let r=i.state(i.proxy({isScrolling:!1,isSmoothScrolling:!1}));const o=i.derived(e);return i.user_effect(()=>{const e=t.provides,s=i.get(o);if(e&&s)return e.onScrollActivity(e=>{e.documentId===s&&i.set(r,e.activity,!0)});i.set(r,{isScrolling:!1,isSmoothScrolling:!1},!0)}),{get current(){return i.get(r)}}},Object.keys(r).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>r[e]})});
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"}),require("svelte/internal/disclose-version");const e=require("svelte/internal/client"),t=require("svelte"),r=require("@embedpdf/core/svelte"),o=require("@embedpdf/plugin-viewport");function i(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const r in e)if("default"!==r){const o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:()=>e[r]})}return t.default=e,Object.freeze(t)}const s=i(e),n=()=>r.usePlugin(o.ViewportPlugin.id),l=()=>r.useCapability(o.ViewportPlugin.id),c=e=>{const t=l();let r=s.state(!1);const o=s.derived(e);return s.user_effect(()=>{const e=t.provides,i=s.get(o);if(e&&i)return s.set(r,e.isGated(i),!0),e.onGateChange(e=>{e.documentId===i&&s.set(r,e.isGated,!0)});s.set(r,!1)}),{get current(){return s.get(r)}}};function u(e){const{plugin:t}=n();let r=s.state(null);const o=s.derived(e);return s.user_pre_effect(()=>{if(!t)return;const e=s.get(r),i=s.get(o);if(!e||!i)return;try{t.registerViewport(i)}catch(u){return void console.error(`Failed to register viewport for document ${i}:`,u)}const n=()=>{t.setViewportScrollMetrics(i,{scrollTop:e.scrollTop,scrollLeft:e.scrollLeft})};e.addEventListener("scroll",n);const l=new ResizeObserver(()=>{t.setViewportResizeMetrics(i,{width:e.offsetWidth,height:e.offsetHeight,clientWidth:e.clientWidth,clientHeight:e.clientHeight,scrollTop:e.scrollTop,scrollLeft:e.scrollLeft,scrollWidth:e.scrollWidth,scrollHeight:e.scrollHeight,clientLeft:e.clientLeft,clientTop:e.clientTop})});l.observe(e);const c=t.onScrollRequest(i,({x:t,y:r,behavior:o="auto"})=>{requestAnimationFrame(()=>{e.scrollTo({left:t,top:r,behavior:o})})});return()=>{t.unregisterViewport(i),e.removeEventListener("scroll",n),l.disconnect(),c()}}),{get containerRef(){return s.get(r)},set containerRef(e){s.set(r,e,!0)}}}var p=s.from_html("<div><!></div>");exports.Viewport=function(e,r){s.push(r,!0);let o=s.rest_props(r,["$$slots","$$events","$$legacy","documentId","children","class"]),i=s.state(0);const n=u(()=>r.documentId),d=l(),a=c(()=>r.documentId);t.setContext("viewport-element",{get current(){return n.containerRef}}),s.user_effect(()=>{d.provides&&s.set(i,d.provides.getViewportGap(),!0)});var f=p();s.attribute_effect(f,()=>({...o,class:r.class,[s.STYLE]:{width:"100%",height:"100%",overflow:"auto",padding:`${s.get(i)}px`}}));var g=s.child(f),v=e=>{var t=s.comment(),o=s.first_child(t);s.snippet(o,()=>r.children),s.append(e,t)};s.if(g,e=>{a.current||e(v)}),s.reset(f),s.bind_this(f,e=>n.containerRef=e,()=>null==n?void 0:n.containerRef),s.append(e,f),s.pop()},exports.useIsViewportGated=c,exports.useViewportCapability=l,exports.useViewportPlugin=n,exports.useViewportRef=u,exports.useViewportScrollActivity=e=>{const t=l();let r=s.state(s.proxy({isScrolling:!1,isSmoothScrolling:!1}));const o=s.derived(e);return s.user_effect(()=>{const e=t.provides,i=s.get(o);if(e&&i)return e.onScrollActivity(e=>{e.documentId===i&&s.set(r,e.activity,!0)});s.set(r,{isScrolling:!1,isSmoothScrolling:!1},!0)}),{get current(){return s.get(r)}}},Object.keys(o).forEach(e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>o[e]})});
2
2
  //# sourceMappingURL=index.cjs.map