@embedpdf/plugin-thumbnail 1.5.0 → 2.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +316 -84
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/actions.d.ts +43 -0
  6. package/dist/lib/index.d.ts +5 -2
  7. package/dist/lib/reducer.d.ts +6 -0
  8. package/dist/lib/thumbnail-plugin.d.ts +19 -17
  9. package/dist/lib/types.d.ts +38 -2
  10. package/dist/preact/index.cjs +1 -1
  11. package/dist/preact/index.cjs.map +1 -1
  12. package/dist/preact/index.js +39 -18
  13. package/dist/preact/index.js.map +1 -1
  14. package/dist/react/index.cjs +1 -1
  15. package/dist/react/index.cjs.map +1 -1
  16. package/dist/react/index.js +39 -18
  17. package/dist/react/index.js.map +1 -1
  18. package/dist/shared/components/thumbnail-img.d.ts +5 -1
  19. package/dist/shared/components/thumbnails-pane.d.ts +6 -7
  20. package/dist/shared-preact/components/thumbnail-img.d.ts +5 -1
  21. package/dist/shared-preact/components/thumbnails-pane.d.ts +6 -7
  22. package/dist/shared-react/components/thumbnail-img.d.ts +5 -1
  23. package/dist/shared-react/components/thumbnails-pane.d.ts +6 -7
  24. package/dist/svelte/components/ThumbImg.svelte.d.ts +4 -0
  25. package/dist/svelte/components/ThumbnailsPane.svelte.d.ts +4 -0
  26. package/dist/svelte/index.cjs +1 -1
  27. package/dist/svelte/index.cjs.map +1 -1
  28. package/dist/svelte/index.js +44 -25
  29. package/dist/svelte/index.js.map +1 -1
  30. package/dist/vue/components/thumbnail-img.vue.d.ts +8 -3
  31. package/dist/vue/components/thumbnails-pane.vue.d.ts +9 -2
  32. package/dist/vue/index.cjs +1 -1
  33. package/dist/vue/index.cjs.map +1 -1
  34. package/dist/vue/index.js +135 -79
  35. package/dist/vue/index.js.map +1 -1
  36. package/package.json +7 -7
package/dist/vue/index.js CHANGED
@@ -1,71 +1,116 @@
1
1
  import { usePlugin, useCapability } from "@embedpdf/core/vue";
2
2
  import { ThumbnailPlugin } from "@embedpdf/plugin-thumbnail";
3
3
  export * from "@embedpdf/plugin-thumbnail";
4
- import { defineComponent, useAttrs, ref, watchEffect, onMounted, onBeforeUnmount, nextTick, createElementBlock, openBlock, mergeProps, unref, createElementVNode, normalizeStyle, Fragment, renderList, renderSlot, watch, createCommentVNode } from "vue";
4
+ import { defineComponent, ref, watch, nextTick, createElementBlock, openBlock, mergeProps, createElementVNode, normalizeStyle, Fragment, renderList, renderSlot, createCommentVNode } from "vue";
5
5
  import { ignore, PdfErrorCode } from "@embedpdf/models";
6
6
  const useThumbnailPlugin = () => usePlugin(ThumbnailPlugin.id);
7
7
  const useThumbnailCapability = () => useCapability(ThumbnailPlugin.id);
8
8
  const _sfc_main$1 = /* @__PURE__ */ defineComponent({
9
9
  __name: "thumbnails-pane",
10
+ props: {
11
+ documentId: {}
12
+ },
10
13
  setup(__props) {
11
- const attrs = useAttrs();
14
+ const props = __props;
12
15
  const { plugin: thumbnailPlugin } = useThumbnailPlugin();
13
16
  const viewportRef = ref(null);
17
+ const windowData = ref({ window: null, docId: null });
14
18
  const windowState = ref(null);
15
- let offWindow = null;
16
- let offScrollTo = null;
17
- watchEffect((onCleanup) => {
18
- if (!thumbnailPlugin.value) return;
19
- offWindow == null ? void 0 : offWindow();
20
- offWindow = thumbnailPlugin.value.onWindow((w) => windowState.value = w);
21
- onCleanup(() => offWindow == null ? void 0 : offWindow());
22
- });
23
- onMounted(() => {
24
- const vp = viewportRef.value;
25
- if (!vp || !thumbnailPlugin.value) return;
26
- const onScroll = () => thumbnailPlugin.value.updateWindow(vp.scrollTop, vp.clientHeight);
27
- vp.addEventListener("scroll", onScroll);
28
- const resizeObserver = new ResizeObserver(() => {
29
- thumbnailPlugin.value.updateWindow(vp.scrollTop, vp.clientHeight);
30
- });
31
- resizeObserver.observe(vp);
32
- thumbnailPlugin.value.updateWindow(vp.scrollTop, vp.clientHeight);
33
- onBeforeUnmount(() => {
34
- vp.removeEventListener("scroll", onScroll);
35
- resizeObserver.disconnect();
36
- });
37
- });
38
- watchEffect((onCleanup) => {
39
- const vp = viewportRef.value;
40
- if (!vp || !thumbnailPlugin.value || !windowState.value) return;
41
- offScrollTo = thumbnailPlugin.value.onScrollTo(({ top, behavior }) => {
42
- nextTick(() => {
43
- vp.scrollTo({ top, behavior });
19
+ watch(
20
+ windowData,
21
+ (data) => {
22
+ windowState.value = data.docId === props.documentId ? data.window : null;
23
+ },
24
+ { deep: true }
25
+ );
26
+ watch(
27
+ [() => thumbnailPlugin.value, () => props.documentId],
28
+ ([plugin, docId], _, onCleanup) => {
29
+ if (!plugin) {
30
+ windowData.value = { window: null, docId: null };
31
+ return;
32
+ }
33
+ const scope = plugin.provides().forDocument(docId);
34
+ const initialWindow = scope.getWindow();
35
+ if (initialWindow) {
36
+ windowData.value = { window: initialWindow, docId };
37
+ }
38
+ const unsubscribe = scope.onWindow((newWindow) => {
39
+ windowData.value = { window: newWindow, docId };
40
+ });
41
+ onCleanup(() => {
42
+ unsubscribe();
43
+ windowData.value = { window: null, docId: null };
44
+ });
45
+ },
46
+ { immediate: true }
47
+ );
48
+ watch(
49
+ [viewportRef, () => thumbnailPlugin.value, () => props.documentId],
50
+ ([vp, plugin, docId], _, onCleanup) => {
51
+ if (!vp || !plugin) return;
52
+ const scope = plugin.provides().forDocument(docId);
53
+ const onScroll = () => scope.updateWindow(vp.scrollTop, vp.clientHeight);
54
+ vp.addEventListener("scroll", onScroll);
55
+ const resizeObserver = new ResizeObserver(() => {
56
+ scope.updateWindow(vp.scrollTop, vp.clientHeight);
57
+ });
58
+ resizeObserver.observe(vp);
59
+ scope.updateWindow(vp.scrollTop, vp.clientHeight);
60
+ onCleanup(() => {
61
+ vp.removeEventListener("scroll", onScroll);
62
+ resizeObserver.disconnect();
63
+ });
64
+ },
65
+ { immediate: true }
66
+ );
67
+ watch(
68
+ [viewportRef, () => thumbnailPlugin.value, () => props.documentId, windowState],
69
+ ([vp, plugin, docId]) => {
70
+ if (!vp || !plugin) return;
71
+ const scope = plugin.provides().forDocument(docId);
72
+ scope.updateWindow(vp.scrollTop, vp.clientHeight);
73
+ }
74
+ );
75
+ watch(
76
+ [viewportRef, () => thumbnailPlugin.value, () => props.documentId, () => !!windowState.value],
77
+ ([vp, plugin, docId, window2], _, onCleanup) => {
78
+ if (!vp || !plugin || !window2) return;
79
+ const scope = plugin.provides().forDocument(docId);
80
+ const unsubscribe = scope.onScrollTo(({ top, behavior }) => {
81
+ nextTick(() => {
82
+ vp.scrollTo({ top, behavior });
83
+ });
44
84
  });
45
- });
46
- onCleanup(() => offScrollTo == null ? void 0 : offScrollTo());
47
- });
48
- onBeforeUnmount(() => {
49
- offWindow == null ? void 0 : offWindow();
50
- offScrollTo == null ? void 0 : offScrollTo();
51
- });
85
+ onCleanup(unsubscribe);
86
+ },
87
+ { immediate: true }
88
+ );
89
+ const paddingY = ref(0);
90
+ watch(
91
+ () => thumbnailPlugin.value,
92
+ (plugin) => {
93
+ paddingY.value = (plugin == null ? void 0 : plugin.cfg.paddingY) ?? 0;
94
+ },
95
+ { immediate: true }
96
+ );
52
97
  return (_ctx, _cache) => {
53
- var _a, _b, _c, _d, _e, _f;
98
+ var _a, _b;
54
99
  return openBlock(), createElementBlock("div", mergeProps({
55
100
  ref_key: "viewportRef",
56
101
  ref: viewportRef,
57
102
  style: {
58
103
  overflowY: "auto",
59
104
  position: "relative",
60
- paddingTop: (((_b = (_a = unref(thumbnailPlugin)) == null ? void 0 : _a.cfg) == null ? void 0 : _b.paddingY) ?? 0) + "px",
61
- paddingBottom: (((_d = (_c = unref(thumbnailPlugin)) == null ? void 0 : _c.cfg) == null ? void 0 : _d.paddingY) ?? 0) + "px",
105
+ paddingTop: `${paddingY.value}px`,
106
+ paddingBottom: `${paddingY.value}px`,
62
107
  height: "100%"
63
108
  }
64
- }, unref(attrs)), [
109
+ }, _ctx.$attrs), [
65
110
  createElementVNode("div", {
66
- style: normalizeStyle({ height: (((_e = windowState.value) == null ? void 0 : _e.totalHeight) ?? 0) + "px", position: "relative" })
111
+ style: normalizeStyle({ height: `${((_a = windowState.value) == null ? void 0 : _a.totalHeight) ?? 0}px`, position: "relative" })
67
112
  }, [
68
- (openBlock(true), createElementBlock(Fragment, null, renderList(((_f = windowState.value) == null ? void 0 : _f.items) ?? [], (m) => {
113
+ (openBlock(true), createElementBlock(Fragment, null, renderList(((_b = windowState.value) == null ? void 0 : _b.items) ?? [], (m) => {
69
114
  return renderSlot(_ctx.$slots, "default", {
70
115
  key: m.pageIndex,
71
116
  meta: m
@@ -80,27 +125,30 @@ const _hoisted_1 = ["src"];
80
125
  const _sfc_main = /* @__PURE__ */ defineComponent({
81
126
  __name: "thumbnail-img",
82
127
  props: {
128
+ documentId: {},
83
129
  meta: {}
84
130
  },
85
131
  setup(__props) {
86
132
  const props = __props;
87
- const attrs = useAttrs();
88
133
  const { provides: thumbs } = useThumbnailCapability();
89
134
  const { plugin: thumbnailPlugin } = useThumbnailPlugin();
90
135
  const url = ref(null);
91
136
  let urlToRevoke = null;
92
137
  const refreshTick = ref(0);
93
- let offRefresh = null;
94
- watchEffect((onCleanup) => {
95
- if (!thumbnailPlugin.value) return;
96
- offRefresh == null ? void 0 : offRefresh();
97
- offRefresh = thumbnailPlugin.value.onRefreshPages((pages) => {
98
- if (pages.includes(props.meta.pageIndex)) {
99
- refreshTick.value++;
100
- }
101
- });
102
- onCleanup(() => offRefresh == null ? void 0 : offRefresh());
103
- });
138
+ watch(
139
+ [() => thumbnailPlugin.value, () => props.documentId, () => props.meta.pageIndex],
140
+ ([plugin, docId, pageIdx], _, onCleanup) => {
141
+ if (!plugin) return;
142
+ const scope = plugin.provides().forDocument(docId);
143
+ const unsubscribe = scope.onRefreshPages((pages) => {
144
+ if (pages.includes(pageIdx)) {
145
+ refreshTick.value++;
146
+ }
147
+ });
148
+ onCleanup(unsubscribe);
149
+ },
150
+ { immediate: true }
151
+ );
104
152
  function revoke() {
105
153
  if (urlToRevoke) {
106
154
  URL.revokeObjectURL(urlToRevoke);
@@ -108,37 +156,45 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
108
156
  }
109
157
  }
110
158
  let abortTask = null;
111
- function load() {
112
- if (!thumbs.value) return;
113
- const task = thumbs.value.renderThumb(props.meta.pageIndex, window.devicePixelRatio);
114
- abortTask = () => task.abort({
115
- code: PdfErrorCode.Cancelled,
116
- message: "canceled render task"
117
- });
118
- task.wait((blob) => {
119
- revoke();
120
- const objectUrl = URL.createObjectURL(blob);
121
- urlToRevoke = objectUrl;
122
- url.value = objectUrl;
123
- }, ignore);
124
- }
125
159
  watch(
126
- () => [props.meta.pageIndex, refreshTick.value, !!thumbs.value],
127
- () => {
128
- abortTask == null ? void 0 : abortTask();
129
- load();
160
+ [() => thumbs.value, () => props.documentId, () => props.meta.pageIndex, refreshTick],
161
+ ([capability, docId, pageIdx], _, onCleanup) => {
162
+ if (abortTask) {
163
+ abortTask();
164
+ abortTask = null;
165
+ }
166
+ if (!capability) {
167
+ url.value = null;
168
+ return;
169
+ }
170
+ const scope = capability.forDocument(docId);
171
+ const task = scope.renderThumb(pageIdx, window.devicePixelRatio);
172
+ abortTask = () => task.abort({
173
+ code: PdfErrorCode.Cancelled,
174
+ message: "canceled render task"
175
+ });
176
+ task.wait((blob) => {
177
+ revoke();
178
+ const objectUrl = URL.createObjectURL(blob);
179
+ urlToRevoke = objectUrl;
180
+ url.value = objectUrl;
181
+ abortTask = null;
182
+ }, ignore);
183
+ onCleanup(() => {
184
+ if (abortTask) {
185
+ abortTask();
186
+ abortTask = null;
187
+ }
188
+ revoke();
189
+ });
130
190
  },
131
191
  { immediate: true }
132
192
  );
133
- onBeforeUnmount(() => {
134
- abortTask == null ? void 0 : abortTask();
135
- revoke();
136
- });
137
193
  return (_ctx, _cache) => {
138
194
  return url.value ? (openBlock(), createElementBlock("img", mergeProps({
139
195
  key: 0,
140
196
  src: url.value
141
- }, unref(attrs), { onLoad: revoke }), null, 16, _hoisted_1)) : createCommentVNode("", true);
197
+ }, _ctx.$attrs, { onLoad: revoke }), null, 16, _hoisted_1)) : createCommentVNode("", true);
142
198
  };
143
199
  }
144
200
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/vue/hooks/use-thumbnail.ts","../../src/vue/components/thumbnails-pane.vue","../../src/vue/components/thumbnail-img.vue"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/vue';\nimport { ThumbnailPlugin } from '@embedpdf/plugin-thumbnail';\n\nexport const useThumbnailPlugin = () => usePlugin<ThumbnailPlugin>(ThumbnailPlugin.id);\nexport const useThumbnailCapability = () => useCapability<ThumbnailPlugin>(ThumbnailPlugin.id);\n","<script setup lang=\"ts\">\nimport { onMounted, onBeforeUnmount, ref, watchEffect, nextTick, useAttrs } from 'vue';\nimport { useThumbnailPlugin } from '../hooks';\nimport type { WindowState } from '@embedpdf/plugin-thumbnail';\n\nconst attrs = useAttrs();\n\nconst { plugin: thumbnailPlugin } = useThumbnailPlugin();\nconst viewportRef = ref<HTMLDivElement | null>(null);\nconst windowState = ref<WindowState | null>(null);\n\nlet offWindow: (() => void) | null = null;\nlet offScrollTo: (() => void) | null = null;\n\nwatchEffect((onCleanup) => {\n if (!thumbnailPlugin.value) return;\n offWindow?.();\n offWindow = thumbnailPlugin.value.onWindow((w) => (windowState.value = w));\n onCleanup(() => offWindow?.());\n});\n\n// Setup scroll listener on mount\nonMounted(() => {\n const vp = viewportRef.value;\n if (!vp || !thumbnailPlugin.value) return;\n\n const onScroll = () => thumbnailPlugin.value!.updateWindow(vp.scrollTop, vp.clientHeight);\n vp.addEventListener('scroll', onScroll);\n\n // Setup resize observer for viewport changes\n const resizeObserver = new ResizeObserver(() => {\n thumbnailPlugin.value!.updateWindow(vp.scrollTop, vp.clientHeight);\n });\n resizeObserver.observe(vp);\n\n // initial push\n thumbnailPlugin.value.updateWindow(vp.scrollTop, vp.clientHeight);\n\n onBeforeUnmount(() => {\n vp.removeEventListener('scroll', onScroll);\n resizeObserver.disconnect();\n });\n});\n\n// Setup scrollTo subscription only after window is ready\nwatchEffect((onCleanup) => {\n const vp = viewportRef.value;\n if (!vp || !thumbnailPlugin.value || !windowState.value) return;\n\n offScrollTo = thumbnailPlugin.value.onScrollTo(({ top, behavior }) => {\n // Wait for Vue to finish rendering the content before scrolling\n nextTick(() => {\n vp.scrollTo({ top, behavior });\n });\n });\n\n onCleanup(() => offScrollTo?.());\n});\n\nonBeforeUnmount(() => {\n offWindow?.();\n offScrollTo?.();\n});\n</script>\n\n<template>\n <div\n ref=\"viewportRef\"\n :style=\"{\n overflowY: 'auto',\n position: 'relative',\n paddingTop: (thumbnailPlugin?.cfg?.paddingY ?? 0) + 'px',\n paddingBottom: (thumbnailPlugin?.cfg?.paddingY ?? 0) + 'px',\n height: '100%',\n }\"\n v-bind=\"attrs\"\n >\n <div :style=\"{ height: (windowState?.totalHeight ?? 0) + 'px', position: 'relative' }\">\n <!-- ✅ Use a template v-for to render the default scoped slot -->\n <template v-for=\"m in windowState?.items ?? []\" :key=\"m.pageIndex\">\n <slot :meta=\"m\" />\n </template>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { onBeforeUnmount, ref, watch, watchEffect, useAttrs } from 'vue';\nimport { useThumbnailCapability, useThumbnailPlugin } from '../hooks';\nimport type { ThumbMeta } from '@embedpdf/plugin-thumbnail';\nimport { ignore, PdfErrorCode } from '@embedpdf/models';\n\nconst props = defineProps<{ meta: ThumbMeta }>();\nconst attrs = useAttrs();\n\nconst { provides: thumbs } = useThumbnailCapability();\nconst { plugin: thumbnailPlugin } = useThumbnailPlugin();\n\nconst url = ref<string | null>(null);\nlet urlToRevoke: string | null = null;\nconst refreshTick = ref(0);\n\nlet offRefresh: (() => void) | null = null;\n\nwatchEffect((onCleanup) => {\n if (!thumbnailPlugin.value) return;\n offRefresh?.();\n offRefresh = thumbnailPlugin.value.onRefreshPages((pages) => {\n if (pages.includes(props.meta.pageIndex)) {\n refreshTick.value++;\n }\n });\n onCleanup(() => offRefresh?.());\n});\n\nfunction revoke() {\n if (urlToRevoke) {\n URL.revokeObjectURL(urlToRevoke);\n urlToRevoke = null;\n }\n}\n\nlet abortTask: (() => void) | null = null;\n\nfunction load() {\n if (!thumbs.value) return; // wait until capability exists\n\n const task = thumbs.value.renderThumb(props.meta.pageIndex, window.devicePixelRatio);\n abortTask = () =>\n task.abort({\n code: PdfErrorCode.Cancelled,\n message: 'canceled render task',\n });\n\n task.wait((blob) => {\n revoke();\n const objectUrl = URL.createObjectURL(blob);\n urlToRevoke = objectUrl;\n url.value = objectUrl;\n }, ignore);\n}\n\n/* 🔧 Re-run when:\n - page changes,\n - the plugin tells us to refresh,\n - OR the capability becomes available later.\n*/\nwatch(\n () => [props.meta.pageIndex, refreshTick.value, !!thumbs.value],\n () => {\n abortTask?.();\n load();\n },\n { immediate: true },\n);\n\nonBeforeUnmount(() => {\n abortTask?.();\n revoke();\n});\n</script>\n\n<template>\n <img v-if=\"url\" :src=\"url\" v-bind=\"attrs\" @load=\"revoke\" />\n</template>\n"],"names":["_openBlock","_createElementBlock","_mergeProps","_unref","_createElementVNode","_normalizeStyle","_Fragment","_renderList","_renderSlot"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/vue/hooks/use-thumbnail.ts","../../src/vue/components/thumbnails-pane.vue","../../src/vue/components/thumbnail-img.vue"],"sourcesContent":["import { useCapability, usePlugin } from '@embedpdf/core/vue';\nimport { ThumbnailPlugin } from '@embedpdf/plugin-thumbnail';\n\nexport const useThumbnailPlugin = () => usePlugin<ThumbnailPlugin>(ThumbnailPlugin.id);\nexport const useThumbnailCapability = () => useCapability<ThumbnailPlugin>(ThumbnailPlugin.id);\n","<script setup lang=\"ts\">\nimport { ref, watch, nextTick } from 'vue';\nimport { useThumbnailPlugin } from '../hooks';\nimport type { WindowState } from '@embedpdf/plugin-thumbnail';\n\ninterface ThumbnailsPaneProps {\n /**\n * The ID of the document that this thumbnail pane displays\n */\n documentId: string;\n}\n\nconst props = defineProps<ThumbnailsPaneProps>();\n\nconst { plugin: thumbnailPlugin } = useThumbnailPlugin();\nconst viewportRef = ref<HTMLDivElement | null>(null);\n\n// Store window data along with the documentId it came from\nconst windowData = ref<{\n window: WindowState | null;\n docId: string | null;\n}>({ window: null, docId: null });\n\n// Only use the window if it matches the current documentId\nconst windowState = ref<WindowState | null>(null);\n\nwatch(\n windowData,\n (data) => {\n windowState.value = data.docId === props.documentId ? data.window : null;\n },\n { deep: true },\n);\n\n// Subscribe to window updates for this document\nwatch(\n [() => thumbnailPlugin.value, () => props.documentId],\n ([plugin, docId], _, onCleanup) => {\n if (!plugin) {\n windowData.value = { window: null, docId: null };\n return;\n }\n\n const scope = plugin.provides().forDocument(docId);\n\n // Get initial window state immediately\n const initialWindow = scope.getWindow();\n if (initialWindow) {\n windowData.value = { window: initialWindow, docId };\n }\n\n // Subscribe to future updates\n const unsubscribe = scope.onWindow((newWindow) => {\n windowData.value = { window: newWindow, docId };\n });\n\n // Clear state when documentId changes or component unmounts\n onCleanup(() => {\n unsubscribe();\n windowData.value = { window: null, docId: null };\n });\n },\n { immediate: true },\n);\n\n// Setup scroll listener\nwatch(\n [viewportRef, () => thumbnailPlugin.value, () => props.documentId],\n ([vp, plugin, docId], _, onCleanup) => {\n if (!vp || !plugin) return;\n\n const scope = plugin.provides().forDocument(docId);\n\n const onScroll = () => scope.updateWindow(vp.scrollTop, vp.clientHeight);\n vp.addEventListener('scroll', onScroll);\n\n // Setup resize observer for viewport changes\n const resizeObserver = new ResizeObserver(() => {\n scope.updateWindow(vp.scrollTop, vp.clientHeight);\n });\n resizeObserver.observe(vp);\n\n // Initial update\n scope.updateWindow(vp.scrollTop, vp.clientHeight);\n\n onCleanup(() => {\n vp.removeEventListener('scroll', onScroll);\n resizeObserver.disconnect();\n });\n },\n { immediate: true },\n);\n\n// Kick-start after window state changes\nwatch(\n [viewportRef, () => thumbnailPlugin.value, () => props.documentId, windowState],\n ([vp, plugin, docId]) => {\n if (!vp || !plugin) return;\n\n const scope = plugin.provides().forDocument(docId);\n scope.updateWindow(vp.scrollTop, vp.clientHeight);\n },\n);\n\n// Setup scrollTo subscription\nwatch(\n [viewportRef, () => thumbnailPlugin.value, () => props.documentId, () => !!windowState.value],\n ([vp, plugin, docId, window], _, onCleanup) => {\n if (!vp || !plugin || !window) return;\n\n const scope = plugin.provides().forDocument(docId);\n const unsubscribe = scope.onScrollTo(({ top, behavior }) => {\n // Wait for Vue to finish rendering the content before scrolling\n nextTick(() => {\n vp.scrollTo({ top, behavior });\n });\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n);\n\nconst paddingY = ref(0);\n\nwatch(\n () => thumbnailPlugin.value,\n (plugin) => {\n paddingY.value = plugin?.cfg.paddingY ?? 0;\n },\n { immediate: true },\n);\n</script>\n\n<template>\n <div\n ref=\"viewportRef\"\n :style=\"{\n overflowY: 'auto',\n position: 'relative',\n paddingTop: `${paddingY}px`,\n paddingBottom: `${paddingY}px`,\n height: '100%',\n }\"\n v-bind=\"$attrs\"\n >\n <div :style=\"{ height: `${windowState?.totalHeight ?? 0}px`, position: 'relative' }\">\n <template v-for=\"m in windowState?.items ?? []\" :key=\"m.pageIndex\">\n <slot :meta=\"m\" />\n </template>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { ref, watch } from 'vue';\nimport { useThumbnailCapability, useThumbnailPlugin } from '../hooks';\nimport type { ThumbMeta } from '@embedpdf/plugin-thumbnail';\nimport { ignore, PdfErrorCode } from '@embedpdf/models';\n\ninterface ThumbImgProps {\n /**\n * The ID of the document that this thumbnail belongs to\n */\n documentId: string;\n meta: ThumbMeta;\n}\n\nconst props = defineProps<ThumbImgProps>();\n\nconst { provides: thumbs } = useThumbnailCapability();\nconst { plugin: thumbnailPlugin } = useThumbnailPlugin();\n\nconst url = ref<string | null>(null);\nlet urlToRevoke: string | null = null;\nconst refreshTick = ref(0);\n\n// Watch for refresh events for this specific document\nwatch(\n [() => thumbnailPlugin.value, () => props.documentId, () => props.meta.pageIndex],\n ([plugin, docId, pageIdx], _, onCleanup) => {\n if (!plugin) return;\n\n const scope = plugin.provides().forDocument(docId);\n const unsubscribe = scope.onRefreshPages((pages) => {\n if (pages.includes(pageIdx)) {\n refreshTick.value++;\n }\n });\n\n onCleanup(unsubscribe);\n },\n { immediate: true },\n);\n\nfunction revoke() {\n if (urlToRevoke) {\n URL.revokeObjectURL(urlToRevoke);\n urlToRevoke = null;\n }\n}\n\nlet abortTask: (() => void) | null = null;\n\n// Render thumbnail when dependencies change\nwatch(\n [() => thumbs.value, () => props.documentId, () => props.meta.pageIndex, refreshTick],\n ([capability, docId, pageIdx], _, onCleanup) => {\n // Cancel previous task\n if (abortTask) {\n abortTask();\n abortTask = null;\n }\n\n if (!capability) {\n url.value = null;\n return;\n }\n\n const scope = capability.forDocument(docId);\n const task = scope.renderThumb(pageIdx, window.devicePixelRatio);\n\n abortTask = () =>\n task.abort({\n code: PdfErrorCode.Cancelled,\n message: 'canceled render task',\n });\n\n task.wait((blob) => {\n revoke();\n const objectUrl = URL.createObjectURL(blob);\n urlToRevoke = objectUrl;\n url.value = objectUrl;\n abortTask = null;\n }, ignore);\n\n onCleanup(() => {\n if (abortTask) {\n abortTask();\n abortTask = null;\n }\n revoke();\n });\n },\n { immediate: true },\n);\n</script>\n\n<template>\n <img v-if=\"url\" :src=\"url\" v-bind=\"$attrs\" @load=\"revoke\" />\n</template>\n"],"names":["window","_openBlock","_createElementBlock","_mergeProps","$attrs","_createElementVNode","_normalizeStyle","_Fragment","_renderList","_renderSlot"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-thumbnail",
3
- "version": "1.5.0",
3
+ "version": "2.0.0-next.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.cjs",
@@ -34,14 +34,14 @@
34
34
  }
35
35
  },
36
36
  "dependencies": {
37
- "@embedpdf/models": "1.5.0"
37
+ "@embedpdf/models": "2.0.0-next.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/react": "^18.2.0",
41
41
  "typescript": "^5.0.0",
42
- "@embedpdf/core": "1.5.0",
43
- "@embedpdf/plugin-render": "1.5.0",
44
- "@embedpdf/plugin-scroll": "1.5.0",
42
+ "@embedpdf/core": "2.0.0-next.0",
43
+ "@embedpdf/plugin-render": "2.0.0-next.0",
44
+ "@embedpdf/plugin-scroll": "2.0.0-next.0",
45
45
  "@embedpdf/build": "1.1.0"
46
46
  },
47
47
  "peerDependencies": {
@@ -50,8 +50,8 @@
50
50
  "preact": "^10.26.4",
51
51
  "vue": ">=3.2.0",
52
52
  "svelte": ">=5 <6",
53
- "@embedpdf/plugin-render": "1.5.0",
54
- "@embedpdf/core": "1.5.0"
53
+ "@embedpdf/core": "2.0.0-next.0",
54
+ "@embedpdf/plugin-render": "2.0.0-next.0"
55
55
  },
56
56
  "files": [
57
57
  "dist",