@embedpdf/plugin-thumbnail 1.0.20 → 1.0.22

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.
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core/preact"),t=require("@embedpdf/plugin-thumbnail"),r=require("preact/jsx-runtime");require("preact");const n=require("preact/hooks"),l=require("@embedpdf/models"),i=()=>e.usePlugin(t.ThumbnailPlugin.id),o=()=>e.useCapability(t.ThumbnailPlugin.id);exports.ThumbImg=function({meta:e,style:t,...s}){const{provides:u}=o(),{plugin:c}=i(),[a,d]=n.useState(),p=n.useRef(null),[f,g]=n.useState(0);return n.useEffect((()=>{if(c)return c.onRefreshPages((t=>{t.includes(e.pageIndex)&&g((e=>e+1))}))}),[c]),n.useEffect((()=>{const t=null==u?void 0:u.renderThumb(e.pageIndex,window.devicePixelRatio);return null==t||t.wait((e=>{const t=URL.createObjectURL(e);p.current=t,d(t)}),l.ignore),()=>{p.current?(URL.revokeObjectURL(p.current),p.current=null):null==t||t.abort({code:l.PdfErrorCode.Cancelled,message:"canceled render task"})}}),[u,e.pageIndex,f]),a?r.jsx("img",{src:a,onLoad:()=>{p.current&&(URL.revokeObjectURL(p.current),p.current=null)},style:t,...s}):null},exports.ThumbnailsPane=function({style:e,selectedPage:t,scrollOptions:l={behavior:"smooth",block:"nearest",inline:"nearest"},...i}){const{provides:s}=o(),u=n.useRef(null),[c,a]=n.useState(null);return n.useEffect((()=>null==s?void 0:s.onWindow(a)),[s]),n.useEffect((()=>{const e=u.current;if(!e)return;const t=()=>null==s?void 0:s.setViewport(e.scrollTop,e.clientHeight);return e.addEventListener("scroll",t),()=>e.removeEventListener("scroll",t)}),[s]),n.useEffect((()=>{const e=u.current;e&&s&&0===(null==c?void 0:c.items.length)&&s.setViewport(e.scrollTop,e.clientHeight)}),[c,s]),n.useEffect((()=>{if(!t||!c)return;const e=c.items.find((e=>e.pageIndex+1===t));if(!e)return;const r=u.current;if(!r)return;e.top<r.scrollTop+8?r.scrollTo({top:e.top,...l}):e.top+e.wrapperHeight+e.labelHeight>r.scrollTop+r.clientHeight-8&&r.scrollTo({top:e.top+e.wrapperHeight+e.labelHeight-r.clientHeight,...l})}),[t,c,l]),r.jsx("div",{ref:u,style:{overflowY:"auto",position:"relative",...e},...i,children:r.jsx("div",{style:{height:(null==c?void 0:c.totalHeight)??0,position:"relative"},children:null==c?void 0:c.items.map((e=>i.children(e)))})})},exports.useThumbnailCapability=o,exports.useThumbnailPlugin=i;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core/preact"),t=require("@embedpdf/plugin-thumbnail"),r=require("preact/jsx-runtime");require("preact");const n=require("preact/hooks"),l=require("@embedpdf/models"),o=()=>e.usePlugin(t.ThumbnailPlugin.id),i=()=>e.useCapability(t.ThumbnailPlugin.id);exports.ThumbImg=function({meta:e,style:t,...s}){const{provides:u}=i(),{plugin:c}=o(),[a,p]=n.useState(),d=n.useRef(null),[f,g]=n.useState(0);return n.useEffect((()=>{if(c)return c.onRefreshPages((t=>{t.includes(e.pageIndex)&&g((e=>e+1))}))}),[c]),n.useEffect((()=>{const t=null==u?void 0:u.renderThumb(e.pageIndex,window.devicePixelRatio);return null==t||t.wait((e=>{const t=URL.createObjectURL(e);d.current=t,p(t)}),l.ignore),()=>{d.current?(URL.revokeObjectURL(d.current),d.current=null):null==t||t.abort({code:l.PdfErrorCode.Cancelled,message:"canceled render task"})}}),[u,e.pageIndex,f]),a?r.jsx("img",{src:a,onLoad:()=>{d.current&&(URL.revokeObjectURL(d.current),d.current=null)},style:t,...s}):null},exports.ThumbnailsPane=function({style:e,selectedPage:t,scrollOptions:l={behavior:"smooth",block:"nearest",inline:"nearest"},...o}){const{provides:s}=i(),u=n.useRef(null),[c,a]=n.useState(null);return n.useEffect((()=>null==s?void 0:s.onWindow(a)),[s]),n.useEffect((()=>{const e=u.current;if(!e)return;const t=()=>null==s?void 0:s.setViewport(e.scrollTop,e.clientHeight);return e.addEventListener("scroll",t),()=>e.removeEventListener("scroll",t)}),[s]),n.useEffect((()=>{const e=u.current;e&&s&&0===(null==c?void 0:c.items.length)&&s.setViewport(e.scrollTop,e.clientHeight)}),[c,s]),n.useEffect((()=>{if(!t||!c)return;const e=c.items.find((e=>e.pageIndex+1===t));if(!e)return;const r=u.current;if(!r)return;e.top<r.scrollTop+8?r.scrollTo({top:e.top,...l}):e.top+e.wrapperHeight+e.labelHeight>r.scrollTop+r.clientHeight-8&&r.scrollTo({top:e.top+e.wrapperHeight+e.labelHeight-r.clientHeight,...l})}),[t,c,l]),r.jsx("div",{ref:u,style:{overflowY:"auto",position:"relative",...e},...o,children:r.jsx("div",{style:{height:(null==c?void 0:c.totalHeight)??0,position:"relative"},children:null==c?void 0:c.items.map((e=>o.children(e)))})})},exports.useThumbnailCapability=i,exports.useThumbnailPlugin=o,Object.keys(t).forEach((e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})}));
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1,5 +1,6 @@
1
1
  import { usePlugin, useCapability } from "@embedpdf/core/preact";
2
2
  import { ThumbnailPlugin } from "@embedpdf/plugin-thumbnail";
3
+ export * from "@embedpdf/plugin-thumbnail";
3
4
  import { jsx } from "preact/jsx-runtime";
4
5
  import "preact";
5
6
  import { useRef, useState, useEffect } from "preact/hooks";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-thumbnail.ts","../../src/shared/components/thumbnails-pane.tsx","../../src/shared/components/thumbnail-img.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { ThumbnailPlugin } from '@embedpdf/plugin-thumbnail';\n\nexport const useThumbnailPlugin = () => usePlugin<ThumbnailPlugin>(ThumbnailPlugin.id);\nexport const useThumbnailCapability = () => useCapability<ThumbnailPlugin>(ThumbnailPlugin.id);\n","import { useEffect, useRef, useState, HTMLAttributes, CSSProperties, ReactNode } from '@framework';\nimport { ThumbMeta, WindowState } from '@embedpdf/plugin-thumbnail';\nimport { useThumbnailCapability } from '../hooks';\n\ntype ThumbnailsProps = Omit<HTMLAttributes<HTMLDivElement>, 'style' | 'children'> & {\n style?: CSSProperties;\n children: (m: ThumbMeta) => ReactNode;\n selectedPage?: number;\n scrollOptions?: ScrollIntoViewOptions;\n};\n\nexport function ThumbnailsPane({\n style,\n selectedPage,\n scrollOptions = { behavior: 'smooth', block: 'nearest', inline: 'nearest' },\n ...props\n}: ThumbnailsProps) {\n const { provides: thumbs } = useThumbnailCapability();\n const viewportRef = useRef<HTMLDivElement>(null);\n\n const [window, setWindow] = useState<WindowState | null>(null);\n\n /* 1️⃣ subscribe once to window updates */\n useEffect(() => thumbs?.onWindow(setWindow), [thumbs]);\n\n /* 2️⃣ keep plugin in sync while the user scrolls */\n useEffect(() => {\n const vp = viewportRef.current;\n if (!vp) return;\n const onScroll = () => thumbs?.setViewport(vp.scrollTop, vp.clientHeight);\n vp.addEventListener('scroll', onScroll);\n return () => vp.removeEventListener('scroll', onScroll);\n }, [thumbs]);\n\n /* 3️⃣ kick-start (or re-kick) after document change */\n useEffect(() => {\n const vp = viewportRef.current;\n if (!vp || !thumbs) return;\n\n if (window?.items.length === 0) {\n thumbs.setViewport(vp.scrollTop, vp.clientHeight);\n }\n }, [window, thumbs]);\n\n /* 4️⃣ whenever selectedPage or window changes, ensure it’s visible */\n useEffect(() => {\n if (!selectedPage || !window) return;\n\n const item = window.items.find((it) => it.pageIndex + 1 === selectedPage);\n if (!item) return; // not in current window yet → wait for next update\n\n const vp = viewportRef.current;\n if (!vp) return;\n\n // Scroll only if the item is above or below the viewport “padding” zone\n const margin = 8; // px\n if (item.top < vp.scrollTop + margin) {\n vp.scrollTo({ top: item.top, ...scrollOptions });\n } else if (\n item.top + item.wrapperHeight + item.labelHeight >\n vp.scrollTop + vp.clientHeight - margin\n ) {\n vp.scrollTo({\n top: item.top + item.wrapperHeight + item.labelHeight - vp.clientHeight,\n ...scrollOptions,\n });\n }\n }, [selectedPage, window, scrollOptions]);\n\n return (\n <div ref={viewportRef} style={{ overflowY: 'auto', position: 'relative', ...style }} {...props}>\n {/* spacer keeps correct scroll height even before first window arrives */}\n <div style={{ height: window?.totalHeight ?? 0, position: 'relative' }}>\n {window?.items.map((m) => props.children(m))}\n </div>\n </div>\n );\n}\n","import { useEffect, useState, useRef, HTMLAttributes, CSSProperties, Fragment } from '@framework';\nimport { ThumbMeta } from '@embedpdf/plugin-thumbnail';\nimport { ignore, PdfErrorCode } from '@embedpdf/models';\nimport { useThumbnailCapability, useThumbnailPlugin } from '../hooks';\n\ntype ThumbnailImgProps = Omit<HTMLAttributes<HTMLImageElement>, 'style'> & {\n style?: CSSProperties;\n meta: ThumbMeta;\n};\n\nexport function ThumbImg({ meta, style, ...props }: ThumbnailImgProps) {\n const { provides: thumbs } = useThumbnailCapability();\n const { plugin: thumbnailPlugin } = useThumbnailPlugin();\n const [url, setUrl] = useState<string>();\n const urlRef = useRef<string | null>(null);\n const [refreshTick, setRefreshTick] = useState(0);\n\n useEffect(() => {\n if (!thumbnailPlugin) return;\n return thumbnailPlugin.onRefreshPages((pages) => {\n if (pages.includes(meta.pageIndex)) {\n setRefreshTick((tick) => tick + 1);\n }\n });\n }, [thumbnailPlugin]);\n\n useEffect(() => {\n const task = thumbs?.renderThumb(meta.pageIndex, window.devicePixelRatio);\n task?.wait((blob) => {\n const objectUrl = URL.createObjectURL(blob);\n urlRef.current = objectUrl;\n setUrl(objectUrl);\n }, ignore);\n\n return () => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n } else {\n task?.abort({\n code: PdfErrorCode.Cancelled,\n message: 'canceled render task',\n });\n }\n };\n }, [thumbs, meta.pageIndex, refreshTick]);\n\n const handleImageLoad = () => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n };\n\n return url ? <img src={url} onLoad={handleImageLoad} style={style} {...props} /> : null;\n}\n"],"names":["window"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-thumbnail.ts","../../src/shared/components/thumbnails-pane.tsx","../../src/shared/components/thumbnail-img.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { ThumbnailPlugin } from '@embedpdf/plugin-thumbnail';\n\nexport const useThumbnailPlugin = () => usePlugin<ThumbnailPlugin>(ThumbnailPlugin.id);\nexport const useThumbnailCapability = () => useCapability<ThumbnailPlugin>(ThumbnailPlugin.id);\n","import { useEffect, useRef, useState, HTMLAttributes, CSSProperties, ReactNode } from '@framework';\nimport { ThumbMeta, WindowState } from '@embedpdf/plugin-thumbnail';\nimport { useThumbnailCapability } from '../hooks';\n\ntype ThumbnailsProps = Omit<HTMLAttributes<HTMLDivElement>, 'style' | 'children'> & {\n style?: CSSProperties;\n children: (m: ThumbMeta) => ReactNode;\n selectedPage?: number;\n scrollOptions?: ScrollIntoViewOptions;\n};\n\nexport function ThumbnailsPane({\n style,\n selectedPage,\n scrollOptions = { behavior: 'smooth', block: 'nearest', inline: 'nearest' },\n ...props\n}: ThumbnailsProps) {\n const { provides: thumbs } = useThumbnailCapability();\n const viewportRef = useRef<HTMLDivElement>(null);\n\n const [window, setWindow] = useState<WindowState | null>(null);\n\n /* 1️⃣ subscribe once to window updates */\n useEffect(() => thumbs?.onWindow(setWindow), [thumbs]);\n\n /* 2️⃣ keep plugin in sync while the user scrolls */\n useEffect(() => {\n const vp = viewportRef.current;\n if (!vp) return;\n const onScroll = () => thumbs?.setViewport(vp.scrollTop, vp.clientHeight);\n vp.addEventListener('scroll', onScroll);\n return () => vp.removeEventListener('scroll', onScroll);\n }, [thumbs]);\n\n /* 3️⃣ kick-start (or re-kick) after document change */\n useEffect(() => {\n const vp = viewportRef.current;\n if (!vp || !thumbs) return;\n\n if (window?.items.length === 0) {\n thumbs.setViewport(vp.scrollTop, vp.clientHeight);\n }\n }, [window, thumbs]);\n\n /* 4️⃣ whenever selectedPage or window changes, ensure it’s visible */\n useEffect(() => {\n if (!selectedPage || !window) return;\n\n const item = window.items.find((it) => it.pageIndex + 1 === selectedPage);\n if (!item) return; // not in current window yet → wait for next update\n\n const vp = viewportRef.current;\n if (!vp) return;\n\n // Scroll only if the item is above or below the viewport “padding” zone\n const margin = 8; // px\n if (item.top < vp.scrollTop + margin) {\n vp.scrollTo({ top: item.top, ...scrollOptions });\n } else if (\n item.top + item.wrapperHeight + item.labelHeight >\n vp.scrollTop + vp.clientHeight - margin\n ) {\n vp.scrollTo({\n top: item.top + item.wrapperHeight + item.labelHeight - vp.clientHeight,\n ...scrollOptions,\n });\n }\n }, [selectedPage, window, scrollOptions]);\n\n return (\n <div ref={viewportRef} style={{ overflowY: 'auto', position: 'relative', ...style }} {...props}>\n {/* spacer keeps correct scroll height even before first window arrives */}\n <div style={{ height: window?.totalHeight ?? 0, position: 'relative' }}>\n {window?.items.map((m) => props.children(m))}\n </div>\n </div>\n );\n}\n","import { useEffect, useState, useRef, HTMLAttributes, CSSProperties, Fragment } from '@framework';\nimport { ThumbMeta } from '@embedpdf/plugin-thumbnail';\nimport { ignore, PdfErrorCode } from '@embedpdf/models';\nimport { useThumbnailCapability, useThumbnailPlugin } from '../hooks';\n\ntype ThumbnailImgProps = Omit<HTMLAttributes<HTMLImageElement>, 'style'> & {\n style?: CSSProperties;\n meta: ThumbMeta;\n};\n\nexport function ThumbImg({ meta, style, ...props }: ThumbnailImgProps) {\n const { provides: thumbs } = useThumbnailCapability();\n const { plugin: thumbnailPlugin } = useThumbnailPlugin();\n const [url, setUrl] = useState<string>();\n const urlRef = useRef<string | null>(null);\n const [refreshTick, setRefreshTick] = useState(0);\n\n useEffect(() => {\n if (!thumbnailPlugin) return;\n return thumbnailPlugin.onRefreshPages((pages) => {\n if (pages.includes(meta.pageIndex)) {\n setRefreshTick((tick) => tick + 1);\n }\n });\n }, [thumbnailPlugin]);\n\n useEffect(() => {\n const task = thumbs?.renderThumb(meta.pageIndex, window.devicePixelRatio);\n task?.wait((blob) => {\n const objectUrl = URL.createObjectURL(blob);\n urlRef.current = objectUrl;\n setUrl(objectUrl);\n }, ignore);\n\n return () => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n } else {\n task?.abort({\n code: PdfErrorCode.Cancelled,\n message: 'canceled render task',\n });\n }\n };\n }, [thumbs, meta.pageIndex, refreshTick]);\n\n const handleImageLoad = () => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n };\n\n return url ? <img src={url} onLoad={handleImageLoad} style={style} {...props} /> : null;\n}\n"],"names":["window"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core/react"),t=require("@embedpdf/plugin-thumbnail"),r=require("react/jsx-runtime"),n=require("react"),l=require("@embedpdf/models"),i=()=>e.usePlugin(t.ThumbnailPlugin.id),o=()=>e.useCapability(t.ThumbnailPlugin.id);exports.ThumbImg=function({meta:e,style:t,...s}){const{provides:u}=o(),{plugin:c}=i(),[a,d]=n.useState(),p=n.useRef(null),[f,g]=n.useState(0);return n.useEffect((()=>{if(c)return c.onRefreshPages((t=>{t.includes(e.pageIndex)&&g((e=>e+1))}))}),[c]),n.useEffect((()=>{const t=null==u?void 0:u.renderThumb(e.pageIndex,window.devicePixelRatio);return null==t||t.wait((e=>{const t=URL.createObjectURL(e);p.current=t,d(t)}),l.ignore),()=>{p.current?(URL.revokeObjectURL(p.current),p.current=null):null==t||t.abort({code:l.PdfErrorCode.Cancelled,message:"canceled render task"})}}),[u,e.pageIndex,f]),a?r.jsx("img",{src:a,onLoad:()=>{p.current&&(URL.revokeObjectURL(p.current),p.current=null)},style:t,...s}):null},exports.ThumbnailsPane=function({style:e,selectedPage:t,scrollOptions:l={behavior:"smooth",block:"nearest",inline:"nearest"},...i}){const{provides:s}=o(),u=n.useRef(null),[c,a]=n.useState(null);return n.useEffect((()=>null==s?void 0:s.onWindow(a)),[s]),n.useEffect((()=>{const e=u.current;if(!e)return;const t=()=>null==s?void 0:s.setViewport(e.scrollTop,e.clientHeight);return e.addEventListener("scroll",t),()=>e.removeEventListener("scroll",t)}),[s]),n.useEffect((()=>{const e=u.current;e&&s&&0===(null==c?void 0:c.items.length)&&s.setViewport(e.scrollTop,e.clientHeight)}),[c,s]),n.useEffect((()=>{if(!t||!c)return;const e=c.items.find((e=>e.pageIndex+1===t));if(!e)return;const r=u.current;if(!r)return;e.top<r.scrollTop+8?r.scrollTo({top:e.top,...l}):e.top+e.wrapperHeight+e.labelHeight>r.scrollTop+r.clientHeight-8&&r.scrollTo({top:e.top+e.wrapperHeight+e.labelHeight-r.clientHeight,...l})}),[t,c,l]),r.jsx("div",{ref:u,style:{overflowY:"auto",position:"relative",...e},...i,children:r.jsx("div",{style:{height:(null==c?void 0:c.totalHeight)??0,position:"relative"},children:null==c?void 0:c.items.map((e=>i.children(e)))})})},exports.useThumbnailCapability=o,exports.useThumbnailPlugin=i;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core/react"),t=require("@embedpdf/plugin-thumbnail"),r=require("react/jsx-runtime"),n=require("react"),l=require("@embedpdf/models"),i=()=>e.usePlugin(t.ThumbnailPlugin.id),o=()=>e.useCapability(t.ThumbnailPlugin.id);exports.ThumbImg=function({meta:e,style:t,...s}){const{provides:u}=o(),{plugin:c}=i(),[a,d]=n.useState(),p=n.useRef(null),[f,g]=n.useState(0);return n.useEffect((()=>{if(c)return c.onRefreshPages((t=>{t.includes(e.pageIndex)&&g((e=>e+1))}))}),[c]),n.useEffect((()=>{const t=null==u?void 0:u.renderThumb(e.pageIndex,window.devicePixelRatio);return null==t||t.wait((e=>{const t=URL.createObjectURL(e);p.current=t,d(t)}),l.ignore),()=>{p.current?(URL.revokeObjectURL(p.current),p.current=null):null==t||t.abort({code:l.PdfErrorCode.Cancelled,message:"canceled render task"})}}),[u,e.pageIndex,f]),a?r.jsx("img",{src:a,onLoad:()=>{p.current&&(URL.revokeObjectURL(p.current),p.current=null)},style:t,...s}):null},exports.ThumbnailsPane=function({style:e,selectedPage:t,scrollOptions:l={behavior:"smooth",block:"nearest",inline:"nearest"},...i}){const{provides:s}=o(),u=n.useRef(null),[c,a]=n.useState(null);return n.useEffect((()=>null==s?void 0:s.onWindow(a)),[s]),n.useEffect((()=>{const e=u.current;if(!e)return;const t=()=>null==s?void 0:s.setViewport(e.scrollTop,e.clientHeight);return e.addEventListener("scroll",t),()=>e.removeEventListener("scroll",t)}),[s]),n.useEffect((()=>{const e=u.current;e&&s&&0===(null==c?void 0:c.items.length)&&s.setViewport(e.scrollTop,e.clientHeight)}),[c,s]),n.useEffect((()=>{if(!t||!c)return;const e=c.items.find((e=>e.pageIndex+1===t));if(!e)return;const r=u.current;if(!r)return;e.top<r.scrollTop+8?r.scrollTo({top:e.top,...l}):e.top+e.wrapperHeight+e.labelHeight>r.scrollTop+r.clientHeight-8&&r.scrollTo({top:e.top+e.wrapperHeight+e.labelHeight-r.clientHeight,...l})}),[t,c,l]),r.jsx("div",{ref:u,style:{overflowY:"auto",position:"relative",...e},...i,children:r.jsx("div",{style:{height:(null==c?void 0:c.totalHeight)??0,position:"relative"},children:null==c?void 0:c.items.map((e=>i.children(e)))})})},exports.useThumbnailCapability=o,exports.useThumbnailPlugin=i,Object.keys(t).forEach((e=>{"default"===e||Object.prototype.hasOwnProperty.call(exports,e)||Object.defineProperty(exports,e,{enumerable:!0,get:()=>t[e]})}));
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1,5 +1,6 @@
1
1
  import { usePlugin, useCapability } from "@embedpdf/core/react";
2
2
  import { ThumbnailPlugin } from "@embedpdf/plugin-thumbnail";
3
+ export * from "@embedpdf/plugin-thumbnail";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  import { useRef, useState, useEffect } from "react";
5
6
  import { ignore, PdfErrorCode } from "@embedpdf/models";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-thumbnail.ts","../../src/shared/components/thumbnails-pane.tsx","../../src/shared/components/thumbnail-img.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { ThumbnailPlugin } from '@embedpdf/plugin-thumbnail';\n\nexport const useThumbnailPlugin = () => usePlugin<ThumbnailPlugin>(ThumbnailPlugin.id);\nexport const useThumbnailCapability = () => useCapability<ThumbnailPlugin>(ThumbnailPlugin.id);\n","import { useEffect, useRef, useState, HTMLAttributes, CSSProperties, ReactNode } from '@framework';\nimport { ThumbMeta, WindowState } from '@embedpdf/plugin-thumbnail';\nimport { useThumbnailCapability } from '../hooks';\n\ntype ThumbnailsProps = Omit<HTMLAttributes<HTMLDivElement>, 'style' | 'children'> & {\n style?: CSSProperties;\n children: (m: ThumbMeta) => ReactNode;\n selectedPage?: number;\n scrollOptions?: ScrollIntoViewOptions;\n};\n\nexport function ThumbnailsPane({\n style,\n selectedPage,\n scrollOptions = { behavior: 'smooth', block: 'nearest', inline: 'nearest' },\n ...props\n}: ThumbnailsProps) {\n const { provides: thumbs } = useThumbnailCapability();\n const viewportRef = useRef<HTMLDivElement>(null);\n\n const [window, setWindow] = useState<WindowState | null>(null);\n\n /* 1️⃣ subscribe once to window updates */\n useEffect(() => thumbs?.onWindow(setWindow), [thumbs]);\n\n /* 2️⃣ keep plugin in sync while the user scrolls */\n useEffect(() => {\n const vp = viewportRef.current;\n if (!vp) return;\n const onScroll = () => thumbs?.setViewport(vp.scrollTop, vp.clientHeight);\n vp.addEventListener('scroll', onScroll);\n return () => vp.removeEventListener('scroll', onScroll);\n }, [thumbs]);\n\n /* 3️⃣ kick-start (or re-kick) after document change */\n useEffect(() => {\n const vp = viewportRef.current;\n if (!vp || !thumbs) return;\n\n if (window?.items.length === 0) {\n thumbs.setViewport(vp.scrollTop, vp.clientHeight);\n }\n }, [window, thumbs]);\n\n /* 4️⃣ whenever selectedPage or window changes, ensure it’s visible */\n useEffect(() => {\n if (!selectedPage || !window) return;\n\n const item = window.items.find((it) => it.pageIndex + 1 === selectedPage);\n if (!item) return; // not in current window yet → wait for next update\n\n const vp = viewportRef.current;\n if (!vp) return;\n\n // Scroll only if the item is above or below the viewport “padding” zone\n const margin = 8; // px\n if (item.top < vp.scrollTop + margin) {\n vp.scrollTo({ top: item.top, ...scrollOptions });\n } else if (\n item.top + item.wrapperHeight + item.labelHeight >\n vp.scrollTop + vp.clientHeight - margin\n ) {\n vp.scrollTo({\n top: item.top + item.wrapperHeight + item.labelHeight - vp.clientHeight,\n ...scrollOptions,\n });\n }\n }, [selectedPage, window, scrollOptions]);\n\n return (\n <div ref={viewportRef} style={{ overflowY: 'auto', position: 'relative', ...style }} {...props}>\n {/* spacer keeps correct scroll height even before first window arrives */}\n <div style={{ height: window?.totalHeight ?? 0, position: 'relative' }}>\n {window?.items.map((m) => props.children(m))}\n </div>\n </div>\n );\n}\n","import { useEffect, useState, useRef, HTMLAttributes, CSSProperties, Fragment } from '@framework';\nimport { ThumbMeta } from '@embedpdf/plugin-thumbnail';\nimport { ignore, PdfErrorCode } from '@embedpdf/models';\nimport { useThumbnailCapability, useThumbnailPlugin } from '../hooks';\n\ntype ThumbnailImgProps = Omit<HTMLAttributes<HTMLImageElement>, 'style'> & {\n style?: CSSProperties;\n meta: ThumbMeta;\n};\n\nexport function ThumbImg({ meta, style, ...props }: ThumbnailImgProps) {\n const { provides: thumbs } = useThumbnailCapability();\n const { plugin: thumbnailPlugin } = useThumbnailPlugin();\n const [url, setUrl] = useState<string>();\n const urlRef = useRef<string | null>(null);\n const [refreshTick, setRefreshTick] = useState(0);\n\n useEffect(() => {\n if (!thumbnailPlugin) return;\n return thumbnailPlugin.onRefreshPages((pages) => {\n if (pages.includes(meta.pageIndex)) {\n setRefreshTick((tick) => tick + 1);\n }\n });\n }, [thumbnailPlugin]);\n\n useEffect(() => {\n const task = thumbs?.renderThumb(meta.pageIndex, window.devicePixelRatio);\n task?.wait((blob) => {\n const objectUrl = URL.createObjectURL(blob);\n urlRef.current = objectUrl;\n setUrl(objectUrl);\n }, ignore);\n\n return () => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n } else {\n task?.abort({\n code: PdfErrorCode.Cancelled,\n message: 'canceled render task',\n });\n }\n };\n }, [thumbs, meta.pageIndex, refreshTick]);\n\n const handleImageLoad = () => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n };\n\n return url ? <img src={url} onLoad={handleImageLoad} style={style} {...props} /> : null;\n}\n"],"names":["window"],"mappings":";;;;;AAGO,MAAM,qBAAqB,MAAM,UAA2B,gBAAgB,EAAE;AAC9E,MAAM,yBAAyB,MAAM,cAA+B,gBAAgB,EAAE;ACOtF,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,gBAAgB,EAAE,UAAU,UAAU,OAAO,WAAW,QAAQ,UAAU;AAAA,EAC1E,GAAG;AACL,GAAoB;AAClB,QAAM,EAAE,UAAU,OAAO,IAAI,uBAAuB;AAC9C,QAAA,cAAc,OAAuB,IAAI;AAE/C,QAAM,CAACA,SAAQ,SAAS,IAAI,SAA6B,IAAI;AAG7D,YAAU,MAAM,iCAAQ,SAAS,YAAY,CAAC,MAAM,CAAC;AAGrD,YAAU,MAAM;AACd,UAAM,KAAK,YAAY;AACvB,QAAI,CAAC,GAAI;AACT,UAAM,WAAW,MAAM,iCAAQ,YAAY,GAAG,WAAW,GAAG;AACzD,OAAA,iBAAiB,UAAU,QAAQ;AACtC,WAAO,MAAM,GAAG,oBAAoB,UAAU,QAAQ;AAAA,EAAA,GACrD,CAAC,MAAM,CAAC;AAGX,YAAU,MAAM;AACd,UAAM,KAAK,YAAY;AACnB,QAAA,CAAC,MAAM,CAAC,OAAQ;AAEhB,SAAAA,WAAA,gBAAAA,QAAQ,MAAM,YAAW,GAAG;AAC9B,aAAO,YAAY,GAAG,WAAW,GAAG,YAAY;AAAA,IAAA;AAAA,EAClD,GACC,CAACA,SAAQ,MAAM,CAAC;AAGnB,YAAU,MAAM;AACV,QAAA,CAAC,gBAAgB,CAACA,QAAQ;AAExB,UAAA,OAAOA,QAAO,MAAM,KAAK,CAAC,OAAO,GAAG,YAAY,MAAM,YAAY;AACxE,QAAI,CAAC,KAAM;AAEX,UAAM,KAAK,YAAY;AACvB,QAAI,CAAC,GAAI;AAGT,UAAM,SAAS;AACf,QAAI,KAAK,MAAM,GAAG,YAAY,QAAQ;AACpC,SAAG,SAAS,EAAE,KAAK,KAAK,KAAK,GAAG,eAAe;AAAA,IACjD,WACE,KAAK,MAAM,KAAK,gBAAgB,KAAK,cACrC,GAAG,YAAY,GAAG,eAAe,QACjC;AACA,SAAG,SAAS;AAAA,QACV,KAAK,KAAK,MAAM,KAAK,gBAAgB,KAAK,cAAc,GAAG;AAAA,QAC3D,GAAG;AAAA,MAAA,CACJ;AAAA,IAAA;AAAA,EAEF,GAAA,CAAC,cAAcA,SAAQ,aAAa,CAAC;AAExC,6BACG,OAAI,EAAA,KAAK,aAAa,OAAO,EAAE,WAAW,QAAQ,UAAU,YAAY,GAAG,SAAU,GAAG,OAEvF,8BAAC,OAAI,EAAA,OAAO,EAAE,SAAQA,WAAA,gBAAAA,QAAQ,gBAAe,GAAG,UAAU,WAAA,GACvD,UAAQA,WAAA,gBAAAA,QAAA,MAAM,IAAI,CAAC,MAAM,MAAM,SAAS,CAAC,GAC5C,CAAA,GACF;AAEJ;ACnEO,SAAS,SAAS,EAAE,MAAM,OAAO,GAAG,SAA4B;AACrE,QAAM,EAAE,UAAU,OAAO,IAAI,uBAAuB;AACpD,QAAM,EAAE,QAAQ,gBAAgB,IAAI,mBAAmB;AACvD,QAAM,CAAC,KAAK,MAAM,IAAI,SAAiB;AACjC,QAAA,SAAS,OAAsB,IAAI;AACzC,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,CAAC;AAEhD,YAAU,MAAM;AACd,QAAI,CAAC,gBAAiB;AACf,WAAA,gBAAgB,eAAe,CAAC,UAAU;AAC/C,UAAI,MAAM,SAAS,KAAK,SAAS,GAAG;AACnB,uBAAA,CAAC,SAAS,OAAO,CAAC;AAAA,MAAA;AAAA,IACnC,CACD;AAAA,EAAA,GACA,CAAC,eAAe,CAAC;AAEpB,YAAU,MAAM;AACd,UAAM,OAAO,iCAAQ,YAAY,KAAK,WAAW,OAAO;AAClD,iCAAA,KAAK,CAAC,SAAS;AACb,YAAA,YAAY,IAAI,gBAAgB,IAAI;AAC1C,aAAO,UAAU;AACjB,aAAO,SAAS;AAAA,OACf;AAEH,WAAO,MAAM;AACX,UAAI,OAAO,SAAS;AACd,YAAA,gBAAgB,OAAO,OAAO;AAClC,eAAO,UAAU;AAAA,MAAA,OACZ;AACL,qCAAM,MAAM;AAAA,UACV,MAAM,aAAa;AAAA,UACnB,SAAS;AAAA,QAAA;AAAA,MACV;AAAA,IAEL;AAAA,KACC,CAAC,QAAQ,KAAK,WAAW,WAAW,CAAC;AAExC,QAAM,kBAAkB,MAAM;AAC5B,QAAI,OAAO,SAAS;AACd,UAAA,gBAAgB,OAAO,OAAO;AAClC,aAAO,UAAU;AAAA,IAAA;AAAA,EAErB;AAEO,SAAA,MAAO,oBAAA,OAAA,EAAI,KAAK,KAAK,QAAQ,iBAAiB,OAAe,GAAG,MAAA,CAAO,IAAK;AACrF;"}
1
+ {"version":3,"file":"index.js","sources":["../../src/shared/hooks/use-thumbnail.ts","../../src/shared/components/thumbnails-pane.tsx","../../src/shared/components/thumbnail-img.tsx"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/@framework';\nimport { ThumbnailPlugin } from '@embedpdf/plugin-thumbnail';\n\nexport const useThumbnailPlugin = () => usePlugin<ThumbnailPlugin>(ThumbnailPlugin.id);\nexport const useThumbnailCapability = () => useCapability<ThumbnailPlugin>(ThumbnailPlugin.id);\n","import { useEffect, useRef, useState, HTMLAttributes, CSSProperties, ReactNode } from '@framework';\nimport { ThumbMeta, WindowState } from '@embedpdf/plugin-thumbnail';\nimport { useThumbnailCapability } from '../hooks';\n\ntype ThumbnailsProps = Omit<HTMLAttributes<HTMLDivElement>, 'style' | 'children'> & {\n style?: CSSProperties;\n children: (m: ThumbMeta) => ReactNode;\n selectedPage?: number;\n scrollOptions?: ScrollIntoViewOptions;\n};\n\nexport function ThumbnailsPane({\n style,\n selectedPage,\n scrollOptions = { behavior: 'smooth', block: 'nearest', inline: 'nearest' },\n ...props\n}: ThumbnailsProps) {\n const { provides: thumbs } = useThumbnailCapability();\n const viewportRef = useRef<HTMLDivElement>(null);\n\n const [window, setWindow] = useState<WindowState | null>(null);\n\n /* 1️⃣ subscribe once to window updates */\n useEffect(() => thumbs?.onWindow(setWindow), [thumbs]);\n\n /* 2️⃣ keep plugin in sync while the user scrolls */\n useEffect(() => {\n const vp = viewportRef.current;\n if (!vp) return;\n const onScroll = () => thumbs?.setViewport(vp.scrollTop, vp.clientHeight);\n vp.addEventListener('scroll', onScroll);\n return () => vp.removeEventListener('scroll', onScroll);\n }, [thumbs]);\n\n /* 3️⃣ kick-start (or re-kick) after document change */\n useEffect(() => {\n const vp = viewportRef.current;\n if (!vp || !thumbs) return;\n\n if (window?.items.length === 0) {\n thumbs.setViewport(vp.scrollTop, vp.clientHeight);\n }\n }, [window, thumbs]);\n\n /* 4️⃣ whenever selectedPage or window changes, ensure it’s visible */\n useEffect(() => {\n if (!selectedPage || !window) return;\n\n const item = window.items.find((it) => it.pageIndex + 1 === selectedPage);\n if (!item) return; // not in current window yet → wait for next update\n\n const vp = viewportRef.current;\n if (!vp) return;\n\n // Scroll only if the item is above or below the viewport “padding” zone\n const margin = 8; // px\n if (item.top < vp.scrollTop + margin) {\n vp.scrollTo({ top: item.top, ...scrollOptions });\n } else if (\n item.top + item.wrapperHeight + item.labelHeight >\n vp.scrollTop + vp.clientHeight - margin\n ) {\n vp.scrollTo({\n top: item.top + item.wrapperHeight + item.labelHeight - vp.clientHeight,\n ...scrollOptions,\n });\n }\n }, [selectedPage, window, scrollOptions]);\n\n return (\n <div ref={viewportRef} style={{ overflowY: 'auto', position: 'relative', ...style }} {...props}>\n {/* spacer keeps correct scroll height even before first window arrives */}\n <div style={{ height: window?.totalHeight ?? 0, position: 'relative' }}>\n {window?.items.map((m) => props.children(m))}\n </div>\n </div>\n );\n}\n","import { useEffect, useState, useRef, HTMLAttributes, CSSProperties, Fragment } from '@framework';\nimport { ThumbMeta } from '@embedpdf/plugin-thumbnail';\nimport { ignore, PdfErrorCode } from '@embedpdf/models';\nimport { useThumbnailCapability, useThumbnailPlugin } from '../hooks';\n\ntype ThumbnailImgProps = Omit<HTMLAttributes<HTMLImageElement>, 'style'> & {\n style?: CSSProperties;\n meta: ThumbMeta;\n};\n\nexport function ThumbImg({ meta, style, ...props }: ThumbnailImgProps) {\n const { provides: thumbs } = useThumbnailCapability();\n const { plugin: thumbnailPlugin } = useThumbnailPlugin();\n const [url, setUrl] = useState<string>();\n const urlRef = useRef<string | null>(null);\n const [refreshTick, setRefreshTick] = useState(0);\n\n useEffect(() => {\n if (!thumbnailPlugin) return;\n return thumbnailPlugin.onRefreshPages((pages) => {\n if (pages.includes(meta.pageIndex)) {\n setRefreshTick((tick) => tick + 1);\n }\n });\n }, [thumbnailPlugin]);\n\n useEffect(() => {\n const task = thumbs?.renderThumb(meta.pageIndex, window.devicePixelRatio);\n task?.wait((blob) => {\n const objectUrl = URL.createObjectURL(blob);\n urlRef.current = objectUrl;\n setUrl(objectUrl);\n }, ignore);\n\n return () => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n } else {\n task?.abort({\n code: PdfErrorCode.Cancelled,\n message: 'canceled render task',\n });\n }\n };\n }, [thumbs, meta.pageIndex, refreshTick]);\n\n const handleImageLoad = () => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n };\n\n return url ? <img src={url} onLoad={handleImageLoad} style={style} {...props} /> : null;\n}\n"],"names":["window"],"mappings":"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"}
@@ -1,2 +1,3 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
+ export * from '../lib/index.ts';
@@ -1,2 +1,3 @@
1
1
  export * from './hooks';
2
2
  export * from './components';
3
+ export * from '../lib/index.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-thumbnail",
3
- "version": "1.0.20",
3
+ "version": "1.0.22",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -23,21 +23,21 @@
23
23
  }
24
24
  },
25
25
  "dependencies": {
26
- "@embedpdf/models": "1.0.20"
26
+ "@embedpdf/models": "1.0.22"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/react": "^18.2.0",
30
30
  "typescript": "^5.0.0",
31
31
  "@embedpdf/build": "1.0.0",
32
- "@embedpdf/plugin-render": "1.0.20",
33
- "@embedpdf/core": "1.0.20"
32
+ "@embedpdf/core": "1.0.22",
33
+ "@embedpdf/plugin-render": "1.0.22"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "react": ">=16.8.0",
37
37
  "react-dom": ">=16.8.0",
38
38
  "preact": "^10.26.4",
39
- "@embedpdf/core": "1.0.20",
40
- "@embedpdf/plugin-render": "1.0.20"
39
+ "@embedpdf/core": "1.0.22",
40
+ "@embedpdf/plugin-render": "1.0.22"
41
41
  },
42
42
  "files": [
43
43
  "dist",