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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +499 -111
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/actions.d.ts +77 -9
  6. package/dist/lib/types.d.ts +55 -12
  7. package/dist/lib/viewport-plugin.d.ts +24 -9
  8. package/dist/preact/index.cjs +1 -1
  9. package/dist/preact/index.cjs.map +1 -1
  10. package/dist/preact/index.js +40 -15
  11. package/dist/preact/index.js.map +1 -1
  12. package/dist/react/index.cjs +1 -1
  13. package/dist/react/index.cjs.map +1 -1
  14. package/dist/react/index.js +40 -15
  15. package/dist/react/index.js.map +1 -1
  16. package/dist/shared/components/viewport.d.ts +5 -1
  17. package/dist/shared/hooks/use-viewport-ref.d.ts +1 -1
  18. package/dist/shared/hooks/use-viewport.d.ts +11 -1
  19. package/dist/shared-preact/components/viewport.d.ts +5 -1
  20. package/dist/shared-preact/hooks/use-viewport-ref.d.ts +1 -1
  21. package/dist/shared-preact/hooks/use-viewport.d.ts +11 -1
  22. package/dist/shared-react/components/viewport.d.ts +5 -1
  23. package/dist/shared-react/hooks/use-viewport-ref.d.ts +1 -1
  24. package/dist/shared-react/hooks/use-viewport.d.ts +11 -1
  25. package/dist/svelte/components/Viewport.svelte.d.ts +4 -0
  26. package/dist/svelte/hooks/use-viewport-ref.svelte.d.ts +5 -1
  27. package/dist/svelte/hooks/use-viewport.svelte.d.ts +15 -4
  28. package/dist/svelte/index.cjs +1 -1
  29. package/dist/svelte/index.cjs.map +1 -1
  30. package/dist/svelte/index.js +86 -21
  31. package/dist/svelte/index.js.map +1 -1
  32. package/dist/vue/components/viewport.vue.d.ts +9 -2
  33. package/dist/vue/hooks/use-viewport-ref.d.ts +6 -1
  34. package/dist/vue/hooks/use-viewport.d.ts +12 -1
  35. package/dist/vue/index.cjs +1 -1
  36. package/dist/vue/index.cjs.map +1 -1
  37. package/dist/vue/index.js +66 -38
  38. package/dist/vue/index.js.map +1 -1
  39. package/package.json +5 -5
@@ -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 { ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\nexport const useViewportScrollActivity = () => {\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 return provides.onScrollActivity(setScrollActivity);\n }, [provides]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\n\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef() {\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 let cleanedUp = false;\n\n /* ---------- live rect provider --------------------------------- */\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(provideRect);\n\n // Example: On scroll, call setMetrics\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics({\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // Example: On resize, call setMetrics\n const resizeObserver = new ResizeObserver(() => {\n if (cleanedUp) return;\n viewportPlugin.setViewportResizeMetrics({\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 const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n cleanedUp = true;\n resizeObserver.disconnect();\n viewportPlugin.registerBoundingRectProvider(null);\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin]);\n\n // Return the ref so your React code can attach it to a div\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\n\nimport { useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n};\n\nexport function Viewport({ children, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef();\n const { provides: viewportProvides } = useViewportCapability();\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 {children}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;;AAIO,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAC3E,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AAEnF,MAAM,4BAA4B,MAAM;AACvC,QAAA,EAAE,SAAS,IAAI,sBAAsB;AAC3C,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAyB;AAAA,IACnE,aAAa;AAAA,IACb,mBAAmB;AAAA,EAAA,CACpB;AAED,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAER,WAAA,SAAS,iBAAiB,iBAAiB;AAAA,EAAA,GACjD,CAAC,QAAQ,CAAC;AAEN,SAAA;AACT;AChBO,SAAS,iBAAiB;AAC/B,QAAM,EAAE,QAAQ,eAAe,IAAI,kBAAkB;AAC/C,QAAA,eAAe,OAAuB,IAAI;AAEhD,kBAAgB,MAAM;AACpB,QAAI,CAAC,eAAgB;AAErB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,UAAW;AAEhB,QAAI,YAAY;AAGhB,UAAM,cAAc,MAAY;AACxB,YAAA,IAAI,UAAU,sBAAsB;AACnC,aAAA;AAAA,QACL,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,IAAI;AAAA,QAC9B,MAAM,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,OAAO;AAAA,MAC3C;AAAA,IACF;AACA,mBAAe,6BAA6B,WAAW;AAGvD,UAAM,WAAW,MAAM;AACrB,qBAAe,yBAAyB;AAAA,QACtC,WAAW,UAAU;AAAA,QACrB,YAAY,UAAU;AAAA,MAAA,CACvB;AAAA,IACH;AACU,cAAA,iBAAiB,UAAU,QAAQ;AAGvC,UAAA,iBAAiB,IAAI,eAAe,MAAM;AAC9C,UAAI,UAAW;AACf,qBAAe,yBAAyB;AAAA,QACtC,OAAO,UAAU;AAAA,QACjB,QAAQ,UAAU;AAAA,QAClB,aAAa,UAAU;AAAA,QACvB,cAAc,UAAU;AAAA,QACxB,WAAW,UAAU;AAAA,QACrB,YAAY,UAAU;AAAA,QACtB,aAAa,UAAU;AAAA,QACvB,cAAc,UAAU;AAAA,MAAA,CACzB;AAAA,IAAA,CACF;AACD,mBAAe,QAAQ,SAAS;AAEhC,UAAM,2BAA2B,eAAe;AAAA,MAC9C,CAAC,EAAE,GAAG,GAAG,WAAW,aAAa;AAC/B,8BAAsB,MAAM;AAC1B,oBAAU,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU;AAAA,QAAA,CACjD;AAAA,MAAA;AAAA,IAEL;AAGA,WAAO,MAAM;AACC,kBAAA;AACZ,qBAAe,WAAW;AAC1B,qBAAe,6BAA6B,IAAI;AACtC,gBAAA,oBAAoB,UAAU,QAAQ;AACvB,+BAAA;AAAA,IAC3B;AAAA,EAAA,GACC,CAAC,cAAc,CAAC;AAGZ,SAAA;AACT;AC/DO,SAAS,SAAS,EAAE,UAAU,GAAG,SAAwB;AAC9D,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,CAAC;AAChD,QAAM,cAAc,eAAe;AACnC,QAAM,EAAE,UAAU,iBAAiB,IAAI,sBAAsB;AAE7D,YAAU,MAAM;AACd,QAAI,kBAAkB;AACL,qBAAA,iBAAiB,gBAAgB;AAAA,IAAA;AAAA,EAClD,GACC,CAAC,gBAAgB,CAAC;AAErB,QAAM,EAAE,OAAO,GAAG,UAAA,IAAc;AAE9B,SAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ,KAAK;AAAA,MACL,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,GAAI,OAAO,UAAU,WAAW,QAAQ,CAAC;AAAA,QACzC,SAAS,GAAG,WAAW;AAAA,MACzB;AAAA,MAEC;AAAA,IAAA;AAAA,EACH;AAEJ;"}
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,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);function l(){const{plugin:e}=i(),r=t.useRef(null);return t.useLayoutEffect((()=>{if(!e)return;const t=r.current;if(!t)return;let o=!1;e.registerBoundingRectProvider((()=>{const e=t.getBoundingClientRect();return{origin:{x:e.left,y:e.top},size:{width:e.width,height:e.height}}}));const i=()=>{e.setViewportScrollMetrics({scrollTop:t.scrollTop,scrollLeft:t.scrollLeft})};t.addEventListener("scroll",i);const s=new ResizeObserver((()=>{o||e.setViewportResizeMetrics({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 l=e.onScrollRequest((({x:e,y:r,behavior:o="auto"})=>{requestAnimationFrame((()=>{t.scrollTo({left:e,top:r,behavior:o})}))}));return()=>{o=!0,s.disconnect(),e.registerBoundingRectProvider(null),t.removeEventListener("scroll",i),l()}}),[e]),r}exports.Viewport=function({children:r,...o}){const[i,n]=t.useState(0),c=l(),{provides:u}=s();t.useEffect((()=>{u&&n(u.getViewportGap())}),[u]);const{style:p,...d}=o;return e.jsx("div",{...d,ref:c,style:{width:"100%",height:"100%",overflow:"auto",..."object"==typeof p?p:{},padding:`${i}px`},children:r})},exports.useViewportCapability=s,exports.useViewportPlugin=i,exports.useViewportRef=l,exports.useViewportScrollActivity=()=>{const{provides:e}=s(),[r,o]=t.useState({isScrolling:!1,isSmoothScrolling:!1});return t.useEffect((()=>{if(e)return e.onScrollActivity(o)}),[e]),r},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=()=>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]})});
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 { ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\nexport const useViewportScrollActivity = () => {\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 return provides.onScrollActivity(setScrollActivity);\n }, [provides]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\n\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef() {\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 let cleanedUp = false;\n\n /* ---------- live rect provider --------------------------------- */\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(provideRect);\n\n // Example: On scroll, call setMetrics\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics({\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // Example: On resize, call setMetrics\n const resizeObserver = new ResizeObserver(() => {\n if (cleanedUp) return;\n viewportPlugin.setViewportResizeMetrics({\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 const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n cleanedUp = true;\n resizeObserver.disconnect();\n viewportPlugin.registerBoundingRectProvider(null);\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin]);\n\n // Return the ref so your React code can attach it to a div\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\n\nimport { useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n};\n\nexport function Viewport({ children, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef();\n const { provides: viewportProvides } = useViewportCapability();\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 {children}\n </div>\n );\n}\n"],"names":["useViewportPlugin","usePlugin","ViewportPlugin","id","useViewportCapability","useCapability","useViewportRef","plugin","viewportPlugin","containerRef","useRef","useLayoutEffect","container","current","cleanedUp","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","disconnect","removeEventListener","children","props","viewportGap","setViewportGap","useState","viewportRef","provides","viewportProvides","useEffect","getViewportGap","style","restProps","jsxRuntime","jsx","ref","overflow","padding","scrollActivity","setScrollActivity","isScrolling","isSmoothScrolling","onScrollActivity"],"mappings":"iNAIaA,EAAoB,IAAMC,YAA0BC,EAAAA,eAAeC,IACnEC,EAAwB,IAAMC,gBAA8BH,EAAAA,eAAeC,ICAjF,SAASG,IACd,MAAQC,OAAQC,GAAmBR,IAC7BS,EAAeC,SAAuB,MAgErC,OA9DPC,EAAAA,iBAAgB,KACd,IAAKH,EAAgB,OAErB,MAAMI,EAAYH,EAAaI,QAC/B,IAAKD,EAAW,OAEhB,IAAIE,GAAY,EAUhBN,EAAeO,8BAPK,KACZ,MAAAC,EAAIJ,EAAUK,wBACb,MAAA,CACLC,OAAQ,CAAEC,EAAGH,EAAEI,KAAMC,EAAGL,EAAEM,KAC1BC,KAAM,CAAEC,MAAOR,EAAEQ,MAAOC,OAAQT,EAAES,QACpC,IAKF,MAAMC,EAAW,KACflB,EAAemB,yBAAyB,CACtCC,UAAWhB,EAAUgB,UACrBC,WAAYjB,EAAUiB,YACvB,EAEOjB,EAAAkB,iBAAiB,SAAUJ,GAG/B,MAAAK,EAAiB,IAAIC,gBAAe,KACpClB,GACJN,EAAeyB,yBAAyB,CACtCT,MAAOZ,EAAUsB,YACjBT,OAAQb,EAAUuB,aAClBC,YAAaxB,EAAUwB,YACvBC,aAAczB,EAAUyB,aACxBT,UAAWhB,EAAUgB,UACrBC,WAAYjB,EAAUiB,WACtBS,YAAa1B,EAAU0B,YACvBC,aAAc3B,EAAU2B,cACzB,IAEHR,EAAeS,QAAQ5B,GAEvB,MAAM6B,EAA2BjC,EAAekC,iBAC9C,EAAGvB,IAAGE,IAAGsB,WAAW,WAClBC,uBAAsB,KACpBhC,EAAUiC,SAAS,CAAEzB,KAAMD,EAAGG,IAAKD,EAAGsB,YAAU,GACjD,IAKL,MAAO,KACO7B,GAAA,EACZiB,EAAee,aACftC,EAAeO,6BAA6B,MAClCH,EAAAmC,oBAAoB,SAAUrB,GACfe,GAAA,CAC3B,GACC,CAACjC,IAGGC,CACT,kBC/DO,UAAkBuC,SAAEA,KAAaC,IACtC,MAAOC,EAAaC,GAAkBC,EAAAA,SAAS,GACzCC,EAAc/C,KACZgD,SAAUC,GAAqBnD,IAEvCoD,EAAAA,WAAU,KACJD,GACaJ,EAAAI,EAAiBE,iBAAgB,GAEjD,CAACF,IAEJ,MAAMG,MAAEA,KAAUC,GAAcV,EAE9B,OAAAW,EAAAC,IAAC,MAAA,IACKF,EACJG,IAAKT,EACLK,MAAO,CACLlC,MAAO,OACPC,OAAQ,OACRsC,SAAU,UACW,iBAAVL,EAAqBA,EAAQ,CAAC,EACzCM,QAAS,GAAGd,OAGbF,YAGP,yHF7ByC,KACjC,MAAAM,SAAEA,GAAalD,KACd6D,EAAgBC,GAAqBd,WAAyB,CACnEe,aAAa,EACbC,mBAAmB,IASd,OANPZ,EAAAA,WAAU,KACR,GAAKF,EAEE,OAAAA,EAASe,iBAAiBH,EAAiB,GACjD,CAACZ,IAEGW,CAAA"}
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"}
@@ -5,7 +5,21 @@ import { ViewportPlugin } from "@embedpdf/plugin-viewport";
5
5
  export * from "@embedpdf/plugin-viewport";
6
6
  const useViewportPlugin = () => usePlugin(ViewportPlugin.id);
7
7
  const useViewportCapability = () => useCapability(ViewportPlugin.id);
8
- const useViewportScrollActivity = () => {
8
+ const useIsViewportGated = (documentId) => {
9
+ const { provides } = useViewportCapability();
10
+ const [isGated, setIsGated] = useState((provides == null ? void 0 : provides.isGated(documentId)) ?? false);
11
+ useEffect(() => {
12
+ if (!provides) return;
13
+ setIsGated(provides.isGated(documentId));
14
+ return provides.onGateChange((event) => {
15
+ if (event.documentId === documentId) {
16
+ setIsGated(event.isGated);
17
+ }
18
+ });
19
+ }, [provides, documentId]);
20
+ return isGated;
21
+ };
22
+ const useViewportScrollActivity = (documentId) => {
9
23
  const { provides } = useViewportCapability();
10
24
  const [scrollActivity, setScrollActivity] = useState({
11
25
  isScrolling: false,
@@ -13,18 +27,27 @@ const useViewportScrollActivity = () => {
13
27
  });
14
28
  useEffect(() => {
15
29
  if (!provides) return;
16
- return provides.onScrollActivity(setScrollActivity);
17
- }, [provides]);
30
+ return provides.onScrollActivity((event) => {
31
+ if (event.documentId === documentId) {
32
+ setScrollActivity(event.activity);
33
+ }
34
+ });
35
+ }, [provides, documentId]);
18
36
  return scrollActivity;
19
37
  };
20
- function useViewportRef() {
38
+ function useViewportRef(documentId) {
21
39
  const { plugin: viewportPlugin } = useViewportPlugin();
22
40
  const containerRef = useRef(null);
23
41
  useLayoutEffect(() => {
24
42
  if (!viewportPlugin) return;
25
43
  const container = containerRef.current;
26
44
  if (!container) return;
27
- let cleanedUp = false;
45
+ try {
46
+ viewportPlugin.registerViewport(documentId);
47
+ } catch (error) {
48
+ console.error(`Failed to register viewport for document ${documentId}:`, error);
49
+ return;
50
+ }
28
51
  const provideRect = () => {
29
52
  const r = container.getBoundingClientRect();
30
53
  return {
@@ -32,17 +55,16 @@ function useViewportRef() {
32
55
  size: { width: r.width, height: r.height }
33
56
  };
34
57
  };
35
- viewportPlugin.registerBoundingRectProvider(provideRect);
58
+ viewportPlugin.registerBoundingRectProvider(documentId, provideRect);
36
59
  const onScroll = () => {
37
- viewportPlugin.setViewportScrollMetrics({
60
+ viewportPlugin.setViewportScrollMetrics(documentId, {
38
61
  scrollTop: container.scrollTop,
39
62
  scrollLeft: container.scrollLeft
40
63
  });
41
64
  };
42
65
  container.addEventListener("scroll", onScroll);
43
66
  const resizeObserver = new ResizeObserver(() => {
44
- if (cleanedUp) return;
45
- viewportPlugin.setViewportResizeMetrics({
67
+ viewportPlugin.setViewportResizeMetrics(documentId, {
46
68
  width: container.offsetWidth,
47
69
  height: container.offsetHeight,
48
70
  clientWidth: container.clientWidth,
@@ -55,6 +77,7 @@ function useViewportRef() {
55
77
  });
56
78
  resizeObserver.observe(container);
57
79
  const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(
80
+ documentId,
58
81
  ({ x, y, behavior = "auto" }) => {
59
82
  requestAnimationFrame(() => {
60
83
  container.scrollTo({ left: x, top: y, behavior });
@@ -62,19 +85,20 @@ function useViewportRef() {
62
85
  }
63
86
  );
64
87
  return () => {
65
- cleanedUp = true;
88
+ viewportPlugin.unregisterViewport(documentId);
89
+ viewportPlugin.registerBoundingRectProvider(documentId, null);
66
90
  resizeObserver.disconnect();
67
- viewportPlugin.registerBoundingRectProvider(null);
68
91
  container.removeEventListener("scroll", onScroll);
69
92
  unsubscribeScrollRequest();
70
93
  };
71
- }, [viewportPlugin]);
94
+ }, [viewportPlugin, documentId]);
72
95
  return containerRef;
73
96
  }
74
- function Viewport({ children, ...props }) {
97
+ function Viewport({ children, documentId, ...props }) {
75
98
  const [viewportGap, setViewportGap] = useState(0);
76
- const viewportRef = useViewportRef();
99
+ const viewportRef = useViewportRef(documentId);
77
100
  const { provides: viewportProvides } = useViewportCapability();
101
+ const isGated = useIsViewportGated(documentId);
78
102
  useEffect(() => {
79
103
  if (viewportProvides) {
80
104
  setViewportGap(viewportProvides.getViewportGap());
@@ -93,12 +117,13 @@ function Viewport({ children, ...props }) {
93
117
  ...typeof style === "object" ? style : {},
94
118
  padding: `${viewportGap}px`
95
119
  },
96
- children
120
+ children: !isGated && children
97
121
  }
98
122
  );
99
123
  }
100
124
  export {
101
125
  Viewport,
126
+ useIsViewportGated,
102
127
  useViewportCapability,
103
128
  useViewportPlugin,
104
129
  useViewportRef,
@@ -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 { ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\nexport const useViewportScrollActivity = () => {\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 return provides.onScrollActivity(setScrollActivity);\n }, [provides]);\n\n return scrollActivity;\n};\n","import { Rect } from '@embedpdf/models';\nimport { useLayoutEffect, useRef } from '@framework';\n\nimport { useViewportPlugin } from './use-viewport';\n\nexport function useViewportRef() {\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 let cleanedUp = false;\n\n /* ---------- live rect provider --------------------------------- */\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(provideRect);\n\n // Example: On scroll, call setMetrics\n const onScroll = () => {\n viewportPlugin.setViewportScrollMetrics({\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // Example: On resize, call setMetrics\n const resizeObserver = new ResizeObserver(() => {\n if (cleanedUp) return;\n viewportPlugin.setViewportResizeMetrics({\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 const unsubscribeScrollRequest = viewportPlugin.onScrollRequest(\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Cleanup\n return () => {\n cleanedUp = true;\n resizeObserver.disconnect();\n viewportPlugin.registerBoundingRectProvider(null);\n container.removeEventListener('scroll', onScroll);\n unsubscribeScrollRequest();\n };\n }, [viewportPlugin]);\n\n // Return the ref so your React code can attach it to a div\n return containerRef;\n}\n","import { ReactNode, useEffect, useState, HTMLAttributes } from '@framework';\n\nimport { useViewportCapability } from '../hooks';\nimport { useViewportRef } from '../hooks/use-viewport-ref';\n\ntype ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: ReactNode;\n};\n\nexport function Viewport({ children, ...props }: ViewportProps) {\n const [viewportGap, setViewportGap] = useState(0);\n const viewportRef = useViewportRef();\n const { provides: viewportProvides } = useViewportCapability();\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 {children}\n </div>\n );\n}\n"],"names":[],"mappings":";;;;;AAIO,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAC3E,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AAEnF,MAAM,4BAA4B,MAAM;AACvC,QAAA,EAAE,SAAS,IAAI,sBAAsB;AAC3C,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAyB;AAAA,IACnE,aAAa;AAAA,IACb,mBAAmB;AAAA,EAAA,CACpB;AAED,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAER,WAAA,SAAS,iBAAiB,iBAAiB;AAAA,EAAA,GACjD,CAAC,QAAQ,CAAC;AAEN,SAAA;AACT;AChBO,SAAS,iBAAiB;AAC/B,QAAM,EAAE,QAAQ,eAAe,IAAI,kBAAkB;AAC/C,QAAA,eAAe,OAAuB,IAAI;AAEhD,kBAAgB,MAAM;AACpB,QAAI,CAAC,eAAgB;AAErB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,UAAW;AAEhB,QAAI,YAAY;AAGhB,UAAM,cAAc,MAAY;AACxB,YAAA,IAAI,UAAU,sBAAsB;AACnC,aAAA;AAAA,QACL,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,IAAI;AAAA,QAC9B,MAAM,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,OAAO;AAAA,MAC3C;AAAA,IACF;AACA,mBAAe,6BAA6B,WAAW;AAGvD,UAAM,WAAW,MAAM;AACrB,qBAAe,yBAAyB;AAAA,QACtC,WAAW,UAAU;AAAA,QACrB,YAAY,UAAU;AAAA,MAAA,CACvB;AAAA,IACH;AACU,cAAA,iBAAiB,UAAU,QAAQ;AAGvC,UAAA,iBAAiB,IAAI,eAAe,MAAM;AAC9C,UAAI,UAAW;AACf,qBAAe,yBAAyB;AAAA,QACtC,OAAO,UAAU;AAAA,QACjB,QAAQ,UAAU;AAAA,QAClB,aAAa,UAAU;AAAA,QACvB,cAAc,UAAU;AAAA,QACxB,WAAW,UAAU;AAAA,QACrB,YAAY,UAAU;AAAA,QACtB,aAAa,UAAU;AAAA,QACvB,cAAc,UAAU;AAAA,MAAA,CACzB;AAAA,IAAA,CACF;AACD,mBAAe,QAAQ,SAAS;AAEhC,UAAM,2BAA2B,eAAe;AAAA,MAC9C,CAAC,EAAE,GAAG,GAAG,WAAW,aAAa;AAC/B,8BAAsB,MAAM;AAC1B,oBAAU,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU;AAAA,QAAA,CACjD;AAAA,MAAA;AAAA,IAEL;AAGA,WAAO,MAAM;AACC,kBAAA;AACZ,qBAAe,WAAW;AAC1B,qBAAe,6BAA6B,IAAI;AACtC,gBAAA,oBAAoB,UAAU,QAAQ;AACvB,+BAAA;AAAA,IAC3B;AAAA,EAAA,GACC,CAAC,cAAc,CAAC;AAGZ,SAAA;AACT;AC/DO,SAAS,SAAS,EAAE,UAAU,GAAG,SAAwB;AAC9D,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,CAAC;AAChD,QAAM,cAAc,eAAe;AACnC,QAAM,EAAE,UAAU,iBAAiB,IAAI,sBAAsB;AAE7D,YAAU,MAAM;AACd,QAAI,kBAAkB;AACL,qBAAA,iBAAiB,gBAAgB;AAAA,IAAA;AAAA,EAClD,GACC,CAAC,gBAAgB,CAAC;AAErB,QAAM,EAAE,OAAO,GAAG,UAAA,IAAc;AAE9B,SAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ,KAAK;AAAA,MACL,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,GAAI,OAAO,UAAU,WAAW,QAAQ,CAAC;AAAA,QACzC,SAAS,GAAG,WAAW;AAAA,MACzB;AAAA,MAEC;AAAA,IAAA;AAAA,EACH;AAEJ;"}
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":";;;;;AAIO,MAAM,oBAAoB,MAAM,UAA0B,eAAe,EAAE;AAC3E,MAAM,wBAAwB,MAAM,cAA8B,eAAe,EAAE;AAOnF,MAAM,qBAAqB,CAAC,eAAuB;AACxD,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,CAAC,SAAS,UAAU,IAAI,UAAS,qCAAU,QAAQ,gBAAe,KAAK;AAE7E,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAGf,eAAW,SAAS,QAAQ,UAAU,CAAC;AAGvC,WAAO,SAAS,aAAa,CAAC,UAA2B;AACvD,UAAI,MAAM,eAAe,YAAY;AACnC,mBAAW,MAAM,OAAO;AAAA,MAC1B;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,UAAU,CAAC;AAEzB,SAAO;AACT;AAMO,MAAM,4BAA4B,CAAC,eAAuB;AAC/D,QAAM,EAAE,SAAA,IAAa,sBAAA;AACrB,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAyB;AAAA,IACnE,aAAa;AAAA,IACb,mBAAmB;AAAA,EAAA,CACpB;AAED,YAAU,MAAM;AACd,QAAI,CAAC,SAAU;AAGf,WAAO,SAAS,iBAAiB,CAAC,UAAU;AAE1C,UAAI,MAAM,eAAe,YAAY;AACnC,0BAAkB,MAAM,QAAQ;AAAA,MAClC;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,UAAU,UAAU,CAAC;AAEzB,SAAO;AACT;ACrDO,SAAS,eAAe,YAAoB;AACjD,QAAM,EAAE,QAAQ,eAAA,IAAmB,kBAAA;AACnC,QAAM,eAAe,OAAuB,IAAI;AAEhD,kBAAgB,MAAM;AACpB,QAAI,CAAC,eAAgB;AAErB,UAAM,YAAY,aAAa;AAC/B,QAAI,CAAC,UAAW;AAGhB,QAAI;AACF,qBAAe,iBAAiB,UAAU;AAAA,IAC5C,SAAS,OAAO;AACd,cAAQ,MAAM,4CAA4C,UAAU,KAAK,KAAK;AAC9E;AAAA,IACF;AAGA,UAAM,cAAc,MAAY;AAC9B,YAAM,IAAI,UAAU,sBAAA;AACpB,aAAO;AAAA,QACL,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,IAAA;AAAA,QAC1B,MAAM,EAAE,OAAO,EAAE,OAAO,QAAQ,EAAE,OAAA;AAAA,MAAO;AAAA,IAE7C;AACA,mBAAe,6BAA6B,YAAY,WAAW;AAGnE,UAAM,WAAW,MAAM;AACrB,qBAAe,yBAAyB,YAAY;AAAA,QAClD,WAAW,UAAU;AAAA,QACrB,YAAY,UAAU;AAAA,MAAA,CACvB;AAAA,IACH;AACA,cAAU,iBAAiB,UAAU,QAAQ;AAG7C,UAAM,iBAAiB,IAAI,eAAe,MAAM;AAC9C,qBAAe,yBAAyB,YAAY;AAAA,QAClD,OAAO,UAAU;AAAA,QACjB,QAAQ,UAAU;AAAA,QAClB,aAAa,UAAU;AAAA,QACvB,cAAc,UAAU;AAAA,QACxB,WAAW,UAAU;AAAA,QACrB,YAAY,UAAU;AAAA,QACtB,aAAa,UAAU;AAAA,QACvB,cAAc,UAAU;AAAA,MAAA,CACzB;AAAA,IACH,CAAC;AACD,mBAAe,QAAQ,SAAS;AAGhC,UAAM,2BAA2B,eAAe;AAAA,MAC9C;AAAA,MACA,CAAC,EAAE,GAAG,GAAG,WAAW,aAAa;AAC/B,8BAAsB,MAAM;AAC1B,oBAAU,SAAS,EAAE,MAAM,GAAG,KAAK,GAAG,UAAU;AAAA,QAClD,CAAC;AAAA,MACH;AAAA,IAAA;AAIF,WAAO,MAAM;AACX,qBAAe,mBAAmB,UAAU;AAC5C,qBAAe,6BAA6B,YAAY,IAAI;AAC5D,qBAAe,WAAA;AACf,gBAAU,oBAAoB,UAAU,QAAQ;AAChD,+BAAA;AAAA,IACF;AAAA,EACF,GAAG,CAAC,gBAAgB,UAAU,CAAC;AAE/B,SAAO;AACT;ACjEO,SAAS,SAAS,EAAE,UAAU,YAAY,GAAG,SAAwB;AAC1E,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,CAAC;AAChD,QAAM,cAAc,eAAe,UAAU;AAC7C,QAAM,EAAE,UAAU,iBAAA,IAAqB,sBAAA;AACvC,QAAM,UAAU,mBAAmB,UAAU;AAE7C,YAAU,MAAM;AACd,QAAI,kBAAkB;AACpB,qBAAe,iBAAiB,gBAAgB;AAAA,IAClD;AAAA,EACF,GAAG,CAAC,gBAAgB,CAAC;AAErB,QAAM,EAAE,OAAO,GAAG,UAAA,IAAc;AAChC,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ,KAAK;AAAA,MACL,OAAO;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,GAAI,OAAO,UAAU,WAAW,QAAQ,CAAA;AAAA,QACxC,SAAS,GAAG,WAAW;AAAA,MAAA;AAAA,MAGxB,WAAC,WAAW;AAAA,IAAA;AAAA,EAAA;AAGnB;"}
@@ -1,6 +1,10 @@
1
1
  import { ReactNode, HTMLAttributes } from '../../react/adapter.ts';
2
2
  type ViewportProps = HTMLAttributes<HTMLDivElement> & {
3
3
  children: ReactNode;
4
+ /**
5
+ * The ID of the document that this viewport displays
6
+ */
7
+ documentId: string;
4
8
  };
5
- export declare function Viewport({ children, ...props }: ViewportProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function Viewport({ children, documentId, ...props }: ViewportProps): import("react/jsx-runtime").JSX.Element;
6
10
  export {};
@@ -1 +1 @@
1
- export declare function useViewportRef(): import('react').RefObject<HTMLDivElement>;
1
+ export declare function useViewportRef(documentId: string): import('react').RefObject<HTMLDivElement>;
@@ -9,4 +9,14 @@ export declare const useViewportCapability: () => {
9
9
  isLoading: boolean;
10
10
  ready: Promise<void>;
11
11
  };
12
- export declare const useViewportScrollActivity: () => ScrollActivity;
12
+ /**
13
+ * Hook to get the gated state of the viewport for a specific document.
14
+ * The viewport children are not rendered when gated.
15
+ * @param documentId Document ID.
16
+ */
17
+ export declare const useIsViewportGated: (documentId: string) => boolean;
18
+ /**
19
+ * Hook to get scroll activity for a specific document
20
+ * @param documentId Document ID.
21
+ */
22
+ export declare const useViewportScrollActivity: (documentId: string) => ScrollActivity;
@@ -1,6 +1,10 @@
1
1
  import { ReactNode, HTMLAttributes } from '../../preact/adapter.ts';
2
2
  type ViewportProps = HTMLAttributes<HTMLDivElement> & {
3
3
  children: ReactNode;
4
+ /**
5
+ * The ID of the document that this viewport displays
6
+ */
7
+ documentId: string;
4
8
  };
5
- export declare function Viewport({ children, ...props }: ViewportProps): import("preact").JSX.Element;
9
+ export declare function Viewport({ children, documentId, ...props }: ViewportProps): import("preact").JSX.Element;
6
10
  export {};
@@ -1 +1 @@
1
- export declare function useViewportRef(): import('preact').RefObject<HTMLDivElement>;
1
+ export declare function useViewportRef(documentId: string): import('preact').RefObject<HTMLDivElement>;
@@ -9,4 +9,14 @@ export declare const useViewportCapability: () => {
9
9
  isLoading: boolean;
10
10
  ready: Promise<void>;
11
11
  };
12
- export declare const useViewportScrollActivity: () => ScrollActivity;
12
+ /**
13
+ * Hook to get the gated state of the viewport for a specific document.
14
+ * The viewport children are not rendered when gated.
15
+ * @param documentId Document ID.
16
+ */
17
+ export declare const useIsViewportGated: (documentId: string) => boolean;
18
+ /**
19
+ * Hook to get scroll activity for a specific document
20
+ * @param documentId Document ID.
21
+ */
22
+ export declare const useViewportScrollActivity: (documentId: string) => ScrollActivity;
@@ -1,6 +1,10 @@
1
1
  import { ReactNode, HTMLAttributes } from '../../react/adapter.ts';
2
2
  type ViewportProps = HTMLAttributes<HTMLDivElement> & {
3
3
  children: ReactNode;
4
+ /**
5
+ * The ID of the document that this viewport displays
6
+ */
7
+ documentId: string;
4
8
  };
5
- export declare function Viewport({ children, ...props }: ViewportProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function Viewport({ children, documentId, ...props }: ViewportProps): import("react/jsx-runtime").JSX.Element;
6
10
  export {};
@@ -1 +1 @@
1
- export declare function useViewportRef(): import('react').RefObject<HTMLDivElement>;
1
+ export declare function useViewportRef(documentId: string): import('react').RefObject<HTMLDivElement>;
@@ -9,4 +9,14 @@ export declare const useViewportCapability: () => {
9
9
  isLoading: boolean;
10
10
  ready: Promise<void>;
11
11
  };
12
- export declare const useViewportScrollActivity: () => ScrollActivity;
12
+ /**
13
+ * Hook to get the gated state of the viewport for a specific document.
14
+ * The viewport children are not rendered when gated.
15
+ * @param documentId Document ID.
16
+ */
17
+ export declare const useIsViewportGated: (documentId: string) => boolean;
18
+ /**
19
+ * Hook to get scroll activity for a specific document
20
+ * @param documentId Document ID.
21
+ */
22
+ export declare const useViewportScrollActivity: (documentId: string) => ScrollActivity;
@@ -1,6 +1,10 @@
1
1
  import { HTMLAttributes } from 'svelte/elements';
2
2
  import { Snippet } from 'svelte';
3
3
  type ViewportProps = HTMLAttributes<HTMLDivElement> & {
4
+ /**
5
+ * The ID of the document that this viewport displays
6
+ */
7
+ documentId: string;
4
8
  children: Snippet;
5
9
  class?: string;
6
10
  };
@@ -1,3 +1,7 @@
1
- export declare function useViewportRef(): {
1
+ /**
2
+ * Hook to get a ref for the viewport container element with automatic setup/teardown
3
+ * @param getDocumentId Function that returns the document ID
4
+ */
5
+ export declare function useViewportRef(getDocumentId: () => string | null): {
2
6
  containerRef: HTMLDivElement | null;
3
7
  };
@@ -1,4 +1,4 @@
1
- import { ViewportPlugin } from '../../lib/index.ts';
1
+ import { ScrollActivity, ViewportPlugin } from '../../lib/index.ts';
2
2
  export declare const useViewportPlugin: () => {
3
3
  plugin: ViewportPlugin | null;
4
4
  isLoading: boolean;
@@ -9,7 +9,18 @@ export declare const useViewportCapability: () => {
9
9
  isLoading: boolean;
10
10
  ready: Promise<void>;
11
11
  };
12
- export declare const useViewportScrollActivity: () => {
13
- isScrolling: boolean;
14
- isSmoothScrolling: boolean;
12
+ /**
13
+ * Hook to get the gated state of the viewport for a specific document.
14
+ * The viewport children are not rendered when gated.
15
+ * @param getDocumentId Function that returns the document ID
16
+ */
17
+ export declare const useIsViewportGated: (getDocumentId: () => string | null) => {
18
+ readonly current: boolean;
19
+ };
20
+ /**
21
+ * Hook to get scroll activity for a specific document
22
+ * @param getDocumentId Function that returns the document ID
23
+ */
24
+ export declare const useViewportScrollActivity: (getDocumentId: () => string | null) => {
25
+ readonly current: ScrollActivity;
15
26
  };
@@ -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 i(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const r in e)if("default"!==r){const i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:()=>e[r]})}return t.default=e,Object.freeze(t)}const o=i(e),l=()=>t.usePlugin(r.ViewportPlugin.id),s=()=>t.useCapability(r.ViewportPlugin.id);function n(){const{plugin:e}=l();let t=o.state(null);return o.user_pre_effect((()=>{if(!e)return;const r=o.get(t);if(!r)return;e.registerBoundingRectProvider((()=>{const e=r.getBoundingClientRect();return{origin:{x:e.left,y:e.top},size:{width:e.width,height:e.height}}}));const i=()=>{null==e||e.setViewportScrollMetrics({scrollTop:r.scrollTop,scrollLeft:r.scrollLeft})};r.addEventListener("scroll",i);const l=new ResizeObserver((()=>{null==e||e.setViewportResizeMetrics({width:r.offsetWidth,height:r.offsetHeight,clientWidth:r.clientWidth,clientHeight:r.clientHeight,scrollTop:r.scrollTop,scrollLeft:r.scrollLeft,scrollWidth:r.scrollWidth,scrollHeight:r.scrollHeight})}));l.observe(r);const s=e.onScrollRequest((({x:e,y:t,behavior:i="auto"})=>{requestAnimationFrame((()=>{r.scrollTo({left:e,top:t,behavior:i})}))}));return()=>{null==e||e.registerBoundingRectProvider(null),r.removeEventListener("scroll",i),l.disconnect(),s()}})),{get containerRef(){return o.get(t)},set containerRef(e){o.set(t,e,!0)}}}var c=o.from_html("<div><!></div>");exports.Viewport=function(e,t){o.push(t,!0);let r=o.rest_props(t,["$$slots","$$events","$$legacy","children","class"]),i=o.state(0),l=n();const p=s();o.user_effect((()=>{p.provides&&o.set(i,p.provides.getViewportGap(),!0)}));var u=c();o.attribute_effect(u,(e=>({...r,class:t.class,[o.STYLE]:e})),[()=>({width:"100%",height:"100%",overflow:"auto",padding:`${o.get(i)}px`})]);var d=o.child(u);o.snippet(d,(()=>t.children)),o.reset(u),o.bind_this(u,(e=>l.containerRef=e),(()=>null==l?void 0:l.containerRef)),o.append(e,u),o.pop()},exports.useViewportCapability=s,exports.useViewportPlugin=l,exports.useViewportRef=n,exports.useViewportScrollActivity=()=>{const e=s(),t=o.proxy({isScrolling:!1,isSmoothScrolling:!1});return o.user_effect((()=>{if(e.provides)return e.provides.onScrollActivity((e=>{t.isScrolling=e.isScrolling,t.isSmoothScrolling=e.isSmoothScrolling}))})),t},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("@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]})});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/svelte/hooks/use-viewport.svelte.ts","../../src/svelte/hooks/use-viewport-ref.svelte.ts","../../src/svelte/components/Viewport.svelte"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\nimport { ScrollActivity, ViewportPlugin } from '@embedpdf/plugin-viewport';\n\nexport const useViewportPlugin = () => usePlugin<ViewportPlugin>(ViewportPlugin.id);\nexport const useViewportCapability = () => useCapability<ViewportPlugin>(ViewportPlugin.id);\n\nexport const useViewportScrollActivity = () => {\n const capability = useViewportCapability();\n\n const state = $state({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n $effect(() => {\n if (!capability.provides) return;\n\n return capability.provides.onScrollActivity((activity: ScrollActivity) => {\n state.isScrolling = activity.isScrolling;\n state.isSmoothScrolling = activity.isSmoothScrolling;\n });\n });\n\n return state;\n};\n","import { type Rect } from '@embedpdf/models';\nimport { useViewportPlugin } from './use-viewport.svelte';\n\nexport function useViewportRef() {\n const { plugin } = useViewportPlugin();\n let containerRef = $state<HTMLDivElement | null>(null);\n\n $effect.pre(() => {\n if (!plugin) return;\n\n const container = containerRef;\n if (!container) return;\n\n /* ---------- live rect provider --------------------------------- */\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 plugin.registerBoundingRectProvider(provideRect);\n\n // Example: On scroll, call setMetrics\n const onScroll = () => {\n plugin?.setViewportScrollMetrics({\n scrollTop: container.scrollTop,\n scrollLeft: container.scrollLeft,\n });\n };\n container.addEventListener('scroll', onScroll);\n\n // Example: On resize, call setMetrics\n const resizeObserver = new ResizeObserver(() => {\n plugin?.setViewportResizeMetrics({\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 const unsubscribeScrollRequest = plugin.onScrollRequest(({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n });\n\n // Cleanup\n return () => {\n plugin?.registerBoundingRectProvider(null);\n container.removeEventListener('scroll', onScroll);\n resizeObserver.disconnect();\n unsubscribeScrollRequest();\n };\n });\n\n // Return the ref so your Svelte code can attach it to a div\n return {\n get containerRef() {\n return containerRef;\n },\n set containerRef(el: HTMLDivElement | null) {\n containerRef = el;\n },\n };\n}\n","<script lang=\"ts\">\n import { useViewportCapability, useViewportRef } from '../hooks';\n import type { HTMLAttributes } from 'svelte/elements';\n import type { Snippet } from 'svelte';\n\n type ViewportProps = HTMLAttributes<HTMLDivElement> & {\n children: Snippet;\n class?: string;\n };\n\n let { children, class: propsClass, ...restProps }: ViewportProps = $props();\n\n let viewportGap = $state(0);\n\n let viewportRef = useViewportRef();\n\n const viewportCapability = useViewportCapability();\n\n $effect(() => {\n if (viewportCapability.provides) {\n viewportGap = viewportCapability.provides.getViewportGap();\n }\n });\n</script>\n\n<div\n {...restProps}\n bind:this={viewportRef.containerRef}\n style:width=\"100%\"\n style:height=\"100%\"\n style:overflow=\"auto\"\n style:padding={`${viewportGap}px`}\n class={propsClass}\n>\n {@render children()}\n</div>\n"],"names":["useViewportPlugin","usePlugin","ViewportPlugin","id","useViewportCapability","useCapability","useViewportRef","plugin","containerRef","$","user_pre_effect","container","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","removeEventListener","disconnect","el","$__namespace","set","restProps","rest_props","$$props","viewportGap","viewportRef","viewportCapability","user_effect","provides","getViewportGap","class","STYLE","$0","bind_this","div","$$value","capability","state","isScrolling","isSmoothScrolling","onScrollActivity","activity"],"mappings":"wgBAGaA,EAA0B,IAAAC,YAA0BC,EAAAA,eAAeC,IACnEC,EAA8B,IAAAC,gBAA8BH,EAAAA,eAAeC,ICDxE,SAAAG,IACN,MAAAC,OAAAA,GAAWP,IACf,IAAAQ,UAA6C,aAEjDC,EAAAC,0BACOH,EAAQ,OAEP,MAAAI,QAAYH,OACbG,EAAW,OAUhBJ,EAAOK,mCANC,MAAAC,EAAIF,EAAUG,+BAElBC,QAAUC,EAAGH,EAAEI,KAAMC,EAAGL,EAAEM,KAC1BC,MAAQC,MAAOR,EAAEQ,MAAOC,OAAQT,EAAES,YAMhC,MAAAC,OACJ,MAAAhB,GAAAA,EAAQiB,yBAAyB,CAC/BC,UAAWd,EAAUc,UACrBC,WAAYf,EAAUe,cAGhBf,EAAAgB,iBAAiB,SAAUJ,GAG/B,MAAAK,EAAA,IAAqBC,gBAAA,KACzB,MAAAtB,GAAAA,EAAQuB,yBAAyB,CAC/BT,MAAOV,EAAUoB,YACjBT,OAAQX,EAAUqB,aAClBC,YAAatB,EAAUsB,YACvBC,aAAcvB,EAAUuB,aACxBT,UAAWd,EAAUc,UACrBC,WAAYf,EAAUe,WACtBS,YAAaxB,EAAUwB,YACvBC,aAAczB,EAAUyB,kBAG5BR,EAAeS,QAAQ1B,GAEjB,MAAA2B,EAA2B/B,EAAOgC,iBAAmB,EAAAvB,IAAGE,IAAGsB,WAAW,WAC1EC,4BACE9B,EAAU+B,UAAWzB,KAAMD,EAAGG,IAAKD,EAAGsB,eACvC,eAKD,MAAAjC,GAAAA,EAAQK,6BAA6B,MAC3BD,EAAAgC,oBAAoB,SAAUpB,GACxCK,EAAegB,aACUN,GAAA,CAC3B,KAKI,gBAAA9B,gBACKA,EACT,kBACIA,CAAaqC,GACAC,EAAAC,IAAAvC,EAAAqC,GAAA,IAGrB,iFC7DwC,IAAAG,EAASvC,EAAAwC,WAAAC,EAAA,CAAA,UAAA,WAAA,WAAA,WAAA,UAE3CC,UAAqB,GAErBC,EAAc9C,IAEZ,MAAA+C,EAAqBjD,IAE3BK,EAAA6C,aAAc,KACRD,EAAmBE,UACrB9C,EAAAsC,IAAAI,EAAcE,EAAmBE,SAASC,kBAAc,EAC1D,4CAKER,EAASS,MAAAP,EAAAO,MAAA,CAAAhD,EAAAiD,OAAAC,KAAA,mEAKKR,qEAJPL,EAAAc,UAAAC,GAAAC,GAAAV,EAAY5C,aAAZsD,IAAA,IAAA,MAAAV,OAAA,EAAAA,EAAY5C,oCAJzB,8HFhBQ,MAAAuD,EAAa3D,IAEb4D,WACJC,aAAa,EACbC,mBAAmB,IAYd,OATPzD,EAAA6C,kBACO,GAAAS,EAAWR,SAET,OAAAQ,EAAWR,SAASY,kBAAkBC,IAC3CJ,EAAMC,YAAcG,EAASH,YAC7BD,EAAME,kBAAoBE,EAASF,iBAAA,GACpC,IAGIF,CAAA"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/svelte/hooks/use-viewport.svelte.ts","../../src/svelte/hooks/use-viewport-ref.svelte.ts","../../src/svelte/components/Viewport.svelte"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/svelte';\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 getDocumentId Function that returns the document ID\n */\nexport const useIsViewportGated = (getDocumentId: () => string | null) => {\n const capability = useViewportCapability();\n\n let isGated = $state(false);\n\n // Reactive documentId\n const documentId = $derived(getDocumentId());\n\n $effect(() => {\n const provides = capability.provides;\n const docId = documentId;\n\n if (!provides || !docId) {\n isGated = false;\n return;\n }\n\n // Set initial state\n isGated = provides.isGated(docId);\n\n // Subscribe to gate state changes\n return provides.onGateChange((event: GateChangeEvent) => {\n if (event.documentId === docId) {\n isGated = event.isGated;\n }\n });\n });\n\n return {\n get current() {\n return isGated;\n },\n };\n};\n\n/**\n * Hook to get scroll activity for a specific document\n * @param getDocumentId Function that returns the document ID\n */\nexport const useViewportScrollActivity = (getDocumentId: () => string | null) => {\n const capability = useViewportCapability();\n\n let scrollActivity = $state<ScrollActivity>({\n isScrolling: false,\n isSmoothScrolling: false,\n });\n\n // Reactive documentId\n const documentId = $derived(getDocumentId());\n\n $effect(() => {\n const provides = capability.provides;\n const docId = documentId;\n\n if (!provides || !docId) {\n scrollActivity = {\n isScrolling: false,\n isSmoothScrolling: false,\n };\n return;\n }\n\n // Subscribe to scroll activity events\n return provides.onScrollActivity((event) => {\n // Filter by documentId\n if (event.documentId === docId) {\n scrollActivity = event.activity;\n }\n });\n });\n\n return {\n get current() {\n return scrollActivity;\n },\n };\n};\n","import { type Rect } from '@embedpdf/models';\nimport { useViewportPlugin } from './use-viewport.svelte';\n\n/**\n * Hook to get a ref for the viewport container element with automatic setup/teardown\n * @param getDocumentId Function that returns the document ID\n */\nexport function useViewportRef(getDocumentId: () => string | null) {\n const { plugin } = useViewportPlugin();\n\n let containerRef = $state<HTMLDivElement | null>(null);\n\n // Reactive documentId\n const documentId = $derived(getDocumentId());\n\n $effect.pre(() => {\n if (!plugin) return;\n\n const container = containerRef;\n const docId = documentId;\n if (!container || !docId) return;\n\n // Register this viewport for the document\n try {\n plugin.registerViewport(docId);\n } catch (error) {\n console.error(`Failed to register viewport for document ${docId}:`, 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 plugin.registerBoundingRectProvider(docId, provideRect);\n\n // On scroll\n const onScroll = () => {\n plugin.setViewportScrollMetrics(docId, {\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 plugin.setViewportResizeMetrics(docId, {\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 = plugin.onScrollRequest(\n docId,\n ({ x, y, behavior = 'auto' }) => {\n requestAnimationFrame(() => {\n container.scrollTo({ left: x, top: y, behavior });\n });\n },\n );\n\n // Store cleanup function\n return () => {\n plugin.unregisterViewport(docId);\n plugin.registerBoundingRectProvider(docId, null);\n container.removeEventListener('scroll', onScroll);\n resizeObserver.disconnect();\n unsubscribeScrollRequest();\n };\n });\n\n return {\n get containerRef() {\n return containerRef;\n },\n set containerRef(el: HTMLDivElement | null) {\n containerRef = el;\n },\n };\n}\n","<script lang=\"ts\">\n import { useIsViewportGated, useViewportCapability, useViewportRef } from '../hooks';\n import type { HTMLAttributes } from 'svelte/elements';\n import type { Snippet } from 'svelte';\n\n type ViewportProps = HTMLAttributes<HTMLDivElement> & {\n /**\n * The ID of the document that this viewport displays\n */\n documentId: string;\n children: Snippet;\n class?: string;\n };\n\n let { documentId, children, class: propsClass, ...restProps }: ViewportProps = $props();\n\n let viewportGap = $state(0);\n\n const viewportRef = useViewportRef(() => documentId);\n const viewportCapability = useViewportCapability();\n const isGated = useIsViewportGated(() => documentId);\n\n $effect(() => {\n if (viewportCapability.provides) {\n viewportGap = viewportCapability.provides.getViewportGap();\n }\n });\n</script>\n\n<div\n {...restProps}\n bind:this={viewportRef.containerRef}\n style:width=\"100%\"\n style:height=\"100%\"\n style:overflow=\"auto\"\n style:padding={`${viewportGap}px`}\n class={propsClass}\n>\n {#if !isGated.current}\n {@render children()}\n {/if}\n</div>\n"],"names":["useViewportPlugin","usePlugin","ViewportPlugin","id","useViewportCapability","useCapability","useIsViewportGated","getDocumentId","capability","isGated","documentId","$","user_effect","provides","docId","set","onGateChange","event","current","useViewportRef","plugin","containerRef","user_pre_effect","container","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","removeEventListener","disconnect","el","restProps","rest_props","$$props","viewportGap","viewportRef","viewportCapability","getViewportGap","$$render","consequent","bind_this","div","$$value","scrollActivity","isScrolling","isSmoothScrolling","onScrollActivity","activity"],"mappings":"wgBAGaA,EAAA,IAA0BC,YAA0BC,EAAAA,eAAeC,IACnEC,EAAA,IAA8BC,gBAA8BH,EAAAA,eAAeC,IAO3EG,EAAsBC,IAC3B,MAAAC,EAAaJ,IAEf,IAAAK,WAAiB,GAGf,MAAAC,YAAsBH,UAE5BI,EAAAC,uBACQC,EAAWL,EAAWK,SACtBC,QAAQJ,MAETG,GAAaC,EASX,OAHPH,EAAAI,IAAAN,EAAUI,EAASJ,QAAQK,IAAK,GAGzBD,EAASG,aAAcC,IACxBA,EAAMP,aAAeI,SACvBL,EAAUQ,EAAMR,SAAA,KAVlBE,EAAAI,IAAAN,GAAU,MAgBR,WAAAS,gBACKT,EACT,aCnCYU,EAAeZ,GACrB,MAAAa,OAAAA,GAAWpB,IAEf,IAAAqB,UAA6C,MAG3C,MAAAX,YAAsBH,UAE5BI,EAAAW,yBACOF,EAAA,OAEC,MAAAG,QAAYF,GACZP,QAAQJ,GACT,IAAAa,IAAcT,EAAA,WAIjBM,EAAOI,iBAAiBV,EAC1B,OAASW,eACPC,QAAQD,MAAA,4CAAkDX,KAAUW,EAEtE,CAUAL,EAAOO,6BAA6Bb,aAN5Bc,EAAIL,EAAUM,+BAElBC,QAAUC,EAAGH,EAAEI,KAAMC,EAAGL,EAAEM,KAC1BC,MAAQC,MAAOR,EAAEQ,MAAOC,OAAQT,EAAES,WAMhC,MAAAC,OACJlB,EAAOmB,yBAAyBzB,EAAA,CAC9B0B,UAAWjB,EAAUiB,UACrBC,WAAYlB,EAAUkB,cAG1BlB,EAAUmB,iBAAiB,SAAUJ,SAG/BK,EAAA,IAAqBC,eAAA,KACzBxB,EAAOyB,yBAAyB/B,EAAA,CAC9BsB,MAAOb,EAAUuB,YACjBT,OAAQd,EAAUwB,aAClBC,YAAazB,EAAUyB,YACvBC,aAAc1B,EAAU0B,aACxBT,UAAWjB,EAAUiB,UACrBC,WAAYlB,EAAUkB,WACtBS,YAAa3B,EAAU2B,YACvBC,aAAc5B,EAAU4B,iBAG5BR,EAAeS,QAAQ7B,GAGjB,MAAA8B,EAA2BjC,EAAOkC,gBACtCxC,EAAA,EACGiB,IAAGE,IAAGsB,WAAW,WAClBC,2BACEjC,EAAUkC,UAAWzB,KAAMD,EAAGG,IAAKD,EAAGsB,4BAO1CnC,EAAOsC,mBAAmB5C,GAC1BM,EAAOO,6BAA6Bb,EAAO,MAC3CS,EAAUoC,oBAAoB,SAAUrB,GACxCK,EAAeiB,aACfP,QAKE,gBAAAhC,gBACKA,EACT,kBACIA,CAAawC,GACflD,EAAAI,IAAAM,EAAewC,GAAA,EACjB,EAEJ,qFC9EoDC,EAASnD,EAAAoD,WAAAC,EAAA,mEAEvDC,UAAqB,GAEnB,MAAAC,EAAc/C,EAAc,IAAA6C,EAAAtD,YAC5ByD,EAAqB/D,IACrBK,EAAUH,EAAkB,IAAA0D,EAAAtD,YAElCC,EAAAC,YAAO,KACDuD,EAAmBtD,UACrBF,EAAAI,IAAAkD,EAAcE,EAAmBtD,SAASuD,kBAAc,6CAMxDN,uFAKcG,6HAGZxD,EAAQS,SAAOmD,EAAAC,gBAPV3D,EAAA4D,UAAAC,EAAAC,GAAAP,EAAY7C,aAAYoD,EAAA,IAAxB,MAAAP,OAAA,EAAAA,EAAY7C,mCAJzB,sJFuB0Cd,IAClC,MAAAC,EAAaJ,IAEf,IAAAsE,mBACFC,aAAa,EACbC,mBAAmB,KAIf,MAAAlE,YAAsBH,UAE5BI,EAAAC,uBACQC,EAAWL,EAAWK,SACtBC,QAAQJ,MAETG,GAAaC,EASX,OAAAD,EAASgE,iBAAkB5D,IAE5BA,EAAMP,aAAeI,SACvB4D,EAAiBzD,EAAM6D,UAAA,KAXzBnE,EAAAI,IAAA2D,GACEC,aAAa,EACbC,mBAAmB,IAAA,MAenB,WAAA1D,gBACKwD,EACT"}