@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.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +316 -84
- package/dist/index.js.map +1 -1
- package/dist/lib/actions.d.ts +43 -0
- package/dist/lib/index.d.ts +5 -2
- package/dist/lib/reducer.d.ts +6 -0
- package/dist/lib/thumbnail-plugin.d.ts +19 -17
- package/dist/lib/types.d.ts +38 -2
- package/dist/preact/index.cjs +1 -1
- package/dist/preact/index.cjs.map +1 -1
- package/dist/preact/index.js +39 -18
- package/dist/preact/index.js.map +1 -1
- package/dist/react/index.cjs +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +39 -18
- package/dist/react/index.js.map +1 -1
- package/dist/shared/components/thumbnail-img.d.ts +5 -1
- package/dist/shared/components/thumbnails-pane.d.ts +6 -7
- package/dist/shared-preact/components/thumbnail-img.d.ts +5 -1
- package/dist/shared-preact/components/thumbnails-pane.d.ts +6 -7
- package/dist/shared-react/components/thumbnail-img.d.ts +5 -1
- package/dist/shared-react/components/thumbnails-pane.d.ts +6 -7
- package/dist/svelte/components/ThumbImg.svelte.d.ts +4 -0
- package/dist/svelte/components/ThumbnailsPane.svelte.d.ts +4 -0
- package/dist/svelte/index.cjs +1 -1
- package/dist/svelte/index.cjs.map +1 -1
- package/dist/svelte/index.js +44 -25
- package/dist/svelte/index.js.map +1 -1
- package/dist/vue/components/thumbnail-img.vue.d.ts +8 -3
- package/dist/vue/components/thumbnails-pane.vue.d.ts +9 -2
- package/dist/vue/index.cjs +1 -1
- package/dist/vue/index.cjs.map +1 -1
- package/dist/vue/index.js +135 -79
- package/dist/vue/index.js.map +1 -1
- 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,
|
|
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
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
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:
|
|
61
|
-
paddingBottom:
|
|
105
|
+
paddingTop: `${paddingY.value}px`,
|
|
106
|
+
paddingBottom: `${paddingY.value}px`,
|
|
62
107
|
height: "100%"
|
|
63
108
|
}
|
|
64
|
-
},
|
|
109
|
+
}, _ctx.$attrs), [
|
|
65
110
|
createElementVNode("div", {
|
|
66
|
-
style: normalizeStyle({ height: ((
|
|
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(((
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
() =>
|
|
127
|
-
() => {
|
|
128
|
-
|
|
129
|
-
|
|
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
|
-
},
|
|
197
|
+
}, _ctx.$attrs, { onLoad: revoke }), null, 16, _hoisted_1)) : createCommentVNode("", true);
|
|
142
198
|
};
|
|
143
199
|
}
|
|
144
200
|
});
|
package/dist/vue/index.js.map
CHANGED
|
@@ -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":";;;;;AAGO,MAAM,qBAAqB,MAAM,UAA2B,gBAAgB,EAAE;AAC9E,MAAM,yBAAyB,MAAM,cAA+B,gBAAgB,EAAE;;;;ACC7F,UAAM,QAAQ,SAAS;AAEvB,UAAM,EAAE,QAAQ,gBAAgB,IAAI,mBAAmB;AACjD,UAAA,cAAc,IAA2B,IAAI;AAC7C,UAAA,cAAc,IAAwB,IAAI;AAEhD,QAAI,YAAiC;AACrC,QAAI,cAAmC;AAEvC,gBAAY,CAAC,cAAc;AACrB,UAAA,CAAC,gBAAgB,MAAO;AAChB;AACZ,kBAAY,gBAAgB,MAAM,SAAS,CAAC,MAAO,YAAY,QAAQ,CAAE;AAC/D,gBAAA,MAAM,wCAAa;AAAA,IAAA,CAC9B;AAGD,cAAU,MAAM;AACd,YAAM,KAAK,YAAY;AACvB,UAAI,CAAC,MAAM,CAAC,gBAAgB,MAAO;AAE7B,YAAA,WAAW,MAAM,gBAAgB,MAAO,aAAa,GAAG,WAAW,GAAG,YAAY;AACrF,SAAA,iBAAiB,UAAU,QAAQ;AAGhC,YAAA,iBAAiB,IAAI,eAAe,MAAM;AAC9C,wBAAgB,MAAO,aAAa,GAAG,WAAW,GAAG,YAAY;AAAA,MAAA,CAClE;AACD,qBAAe,QAAQ,EAAE;AAGzB,sBAAgB,MAAM,aAAa,GAAG,WAAW,GAAG,YAAY;AAEhE,sBAAgB,MAAM;AACjB,WAAA,oBAAoB,UAAU,QAAQ;AACzC,uBAAe,WAAW;AAAA,MAAA,CAC3B;AAAA,IAAA,CACF;AAGD,gBAAY,CAAC,cAAc;AACzB,YAAM,KAAK,YAAY;AACvB,UAAI,CAAC,MAAM,CAAC,gBAAgB,SAAS,CAAC,YAAY,MAAO;AAEzD,oBAAc,gBAAgB,MAAM,WAAW,CAAC,EAAE,KAAK,eAAe;AAEpE,iBAAS,MAAM;AACb,aAAG,SAAS,EAAE,KAAK,SAAA,CAAU;AAAA,QAAA,CAC9B;AAAA,MAAA,CACF;AAES,gBAAA,MAAM,4CAAe;AAAA,IAAA,CAChC;AAED,oBAAgB,MAAM;AACR;AACE;AAAA,IAAA,CACf;;;AAIC,aAAAA,UAAA,GAAAC,mBAiBM,OAjBNC,WAiBM;AAAA,iBAhBA;AAAA,QAAJ,KAAI;AAAA,QACH,OAAK;AAAA;;yBAA4EC,iBAAe,eAAA,MAAfA,mBAAiB,QAAjBA,mBAAsB,aAAQ,KAAA;AAAA,4BAAqCA,iBAAe,eAAA,MAAfA,mBAAiB,QAAjBA,mBAAsB,aAAQ,KAAA;AAAA;;SAO3KA,MAAK,KAAA,CAAA,GAAA;AAAA,QAEbC,mBAKM,OAAA;AAAA,UALA,OAAKC,eAAA,EAAA,WAAa,iBAAW,UAAX,mBAAa,gBAAW,KAAA,MAAA,UAAA,WAAA,CAAA;AAAA,QAAA;WAE9CL,UAAA,IAAA,GAAAC,mBAEWK,UAFW,MAAAC,aAAA,iBAAA,UAAA,mBAAa,eAAlB,MAAC;AAChB,mBAAAC,WAAkB,KAAA,QAAA,WAAA;AAAA,cADkC,KAAA,EAAE;AAAA,cAC/C,MAAM;AAAA,YAAA;;;;;;;;;;;;;;AC1ErB,UAAM,QAAQ;AACd,UAAM,QAAQ,SAAS;AAEvB,UAAM,EAAE,UAAU,OAAO,IAAI,uBAAuB;AACpD,UAAM,EAAE,QAAQ,gBAAgB,IAAI,mBAAmB;AAEjD,UAAA,MAAM,IAAmB,IAAI;AACnC,QAAI,cAA6B;AAC3B,UAAA,cAAc,IAAI,CAAC;AAEzB,QAAI,aAAkC;AAEtC,gBAAY,CAAC,cAAc;AACrB,UAAA,CAAC,gBAAgB,MAAO;AACf;AACb,mBAAa,gBAAgB,MAAM,eAAe,CAAC,UAAU;AAC3D,YAAI,MAAM,SAAS,MAAM,KAAK,SAAS,GAAG;AAC5B,sBAAA;AAAA,QAAA;AAAA,MACd,CACD;AACS,gBAAA,MAAM,0CAAc;AAAA,IAAA,CAC/B;AAED,aAAS,SAAS;AAChB,UAAI,aAAa;AACf,YAAI,gBAAgB,WAAW;AACjB,sBAAA;AAAA,MAAA;AAAA,IAChB;AAGF,QAAI,YAAiC;AAErC,aAAS,OAAO;AACV,UAAA,CAAC,OAAO,MAAO;AAEb,YAAA,OAAO,OAAO,MAAM,YAAY,MAAM,KAAK,WAAW,OAAO,gBAAgB;AACvE,kBAAA,MACV,KAAK,MAAM;AAAA,QACT,MAAM,aAAa;AAAA,QACnB,SAAS;AAAA,MAAA,CACV;AAEE,WAAA,KAAK,CAAC,SAAS;AACX,eAAA;AACD,cAAA,YAAY,IAAI,gBAAgB,IAAI;AAC5B,sBAAA;AACd,YAAI,QAAQ;AAAA,SACX,MAAM;AAAA,IAAA;AAQX;AAAA,MACE,MAAM,CAAC,MAAM,KAAK,WAAW,YAAY,OAAO,CAAC,CAAC,OAAO,KAAK;AAAA,MAC9D,MAAM;AACQ;AACP,aAAA;AAAA,MACP;AAAA,MACA,EAAE,WAAW,KAAK;AAAA,IACpB;AAEA,oBAAgB,MAAM;AACR;AACL,aAAA;AAAA,IAAA,CACR;;aAIY,IAAG,SAAdR,UAAA,GAAAC,mBAA2D,OAA3DC,WAA2D;AAAA;QAA1C,KAAK,IAAG;AAAA,MAAU,GAAAC,MAAK,KAAA,GAAA,EAAG,QAAM,OAAM,CAAA,GAAA,MAAA,IAAA,UAAA;;;;"}
|
|
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": "
|
|
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": "
|
|
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": "
|
|
43
|
-
"@embedpdf/plugin-render": "
|
|
44
|
-
"@embedpdf/plugin-scroll": "
|
|
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/
|
|
54
|
-
"@embedpdf/
|
|
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",
|