@veltra/desktop 1.1.11 → 1.1.13

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 (44) hide show
  1. package/dist/components/action/action-group.vue.d.ts +1 -1
  2. package/dist/components/checkbox/checkbox-button.vue.d.ts +1 -1
  3. package/dist/components/collapse/style2.css +4 -4
  4. package/dist/components/date-picker/date-picker.vue.d.ts +1 -1
  5. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +1 -1
  6. package/dist/components/drawer/drawer.vue.d.ts +2 -2
  7. package/dist/components/file-viewer/file-viewer.js +62 -19
  8. package/dist/components/file-viewer/file-viewer.js.map +1 -1
  9. package/dist/components/file-viewer/file-viewer.vue.d.ts +1 -1
  10. package/dist/components/file-viewer/previewers/image-previewer.js +3 -2
  11. package/dist/components/file-viewer/previewers/image-previewer.js.map +1 -1
  12. package/dist/components/file-viewer/previewers/pdf-previewer.js +60 -17
  13. package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -1
  14. package/dist/components/file-viewer/previewers/pdf-viewport-scroll.js +83 -0
  15. package/dist/components/file-viewer/previewers/pdf-viewport-scroll.js.map +1 -0
  16. package/dist/components/file-viewer/previewers/pdf-zoom-bridge.js +32 -0
  17. package/dist/components/file-viewer/previewers/pdf-zoom-bridge.js.map +1 -0
  18. package/dist/components/file-viewer/style2.css +14 -1
  19. package/dist/components/multi-select/multi-select.vue.d.ts +1 -1
  20. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +1 -1
  21. package/dist/components/number/number.vue.d.ts +1 -1
  22. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  23. package/dist/components/progress-nodes/progress-nodes.vue.d.ts +2 -2
  24. package/dist/components/scroll/scroll.js +94 -30
  25. package/dist/components/scroll/scroll.js.map +1 -1
  26. package/dist/components/scroll/style2.css +22 -0
  27. package/dist/components/steps/steps.vue.d.ts +1 -1
  28. package/dist/components/tabs/tabs-horizontal.vue.d.ts +3 -3
  29. package/dist/components/tabs/tabs-vertical.vue.d.ts +2 -2
  30. package/dist/components/tabs/tabs.vue.d.ts +3 -3
  31. package/dist/components/tip/tip.vue.d.ts +1 -1
  32. package/dist/components/tree-select/tree-select.vue.d.ts +1 -1
  33. package/dist/types/scroll.d.ts +6 -1
  34. package/package.json +12 -11
  35. package/src/components/collapse/style.scss +2 -2
  36. package/src/components/file-viewer/file-viewer.vue +73 -16
  37. package/src/components/file-viewer/previewers/image-previewer.vue +1 -0
  38. package/src/components/file-viewer/previewers/pdf-previewer.vue +67 -14
  39. package/src/components/file-viewer/previewers/pdf-viewport-scroll.vue +112 -0
  40. package/src/components/file-viewer/previewers/pdf-zoom-bridge.vue +33 -0
  41. package/src/components/file-viewer/style.scss +16 -1
  42. package/src/components/scroll/scroll.vue +124 -75
  43. package/src/components/scroll/style.scss +22 -0
  44. package/src/types/scroll.ts +7 -1
@@ -11,8 +11,8 @@ declare const __VLS_base: _$vue.DefineComponent<ActionGroupProps, _ActionGroupEx
11
11
  type: _$_veltra_utils0.ColorType;
12
12
  size: "small" | "default" | "large";
13
13
  text: boolean;
14
- max: number;
15
14
  circle: boolean;
15
+ max: number;
16
16
  loading: boolean;
17
17
  }, {}, {}, {}, string, _$vue.ComponentProvideOptions, false, {}, any>;
18
18
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
@@ -20,8 +20,8 @@ declare const __VLS_base: _$vue.DefineComponent<__VLS_PublicProps, {}, {}, {}, {
20
20
  "onUpdate:modelValue"?: ((checked: boolean) => any) | undefined;
21
21
  onChange?: ((checked: boolean) => any) | undefined;
22
22
  }>, {
23
- disabled: boolean;
24
23
  type: _$_veltra_utils0.ColorType;
24
+ disabled: boolean;
25
25
  readonly: boolean;
26
26
  round: boolean;
27
27
  }, {}, {}, {}, string, _$vue.ComponentProvideOptions, false, {}, any>;
@@ -46,7 +46,7 @@
46
46
  cursor: pointer;
47
47
  font-weight: 500;
48
48
  letter-spacing: 0.01em;
49
- color: var(--u-text-color-title);
49
+ color: var(--u-collapse-title-color, var(--u-text-color-main));
50
50
  user-select: none;
51
51
  outline: none;
52
52
  transition: color 0.18s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.18s cubic-bezier(0.4, 0, 0.2, 1);
@@ -94,7 +94,7 @@
94
94
  }
95
95
  .u-collapse--small .u-collapse__header {
96
96
  padding: calc(var(--u-gap-small) - 2px) var(--u-gap-small);
97
- font-size: var(--u-font-size-title-small);
97
+ font-size: var(--u-font-size-main-small);
98
98
  }
99
99
  .u-collapse--small .u-collapse__content {
100
100
  font-size: var(--u-font-size-main-small);
@@ -111,7 +111,7 @@
111
111
  }
112
112
  .u-collapse--default .u-collapse__header {
113
113
  padding: calc(var(--u-gap-default) - 2px) var(--u-gap-default);
114
- font-size: var(--u-font-size-title-default);
114
+ font-size: var(--u-font-size-main-default);
115
115
  }
116
116
  .u-collapse--default .u-collapse__content {
117
117
  font-size: var(--u-font-size-main-default);
@@ -128,7 +128,7 @@
128
128
  }
129
129
  .u-collapse--large .u-collapse__header {
130
130
  padding: calc(var(--u-gap-large) - 2px) var(--u-gap-large);
131
- font-size: var(--u-font-size-title-large);
131
+ font-size: var(--u-font-size-main-large);
132
132
  }
133
133
  .u-collapse--large .u-collapse__content {
134
134
  font-size: var(--u-font-size-main-large);
@@ -7,8 +7,8 @@ declare const __VLS_export: _$vue.DefineComponent<DatePickerProps, {}, {}, {}, {
7
7
  }, string, _$vue.PublicProps, Readonly<DatePickerProps> & Readonly<{
8
8
  "onUpdate:modelValue"?: ((value?: string | number | Date | undefined) => any) | undefined;
9
9
  }>, {
10
- disabled: boolean;
11
10
  type: "date" | "month" | "year";
11
+ disabled: boolean;
12
12
  readonly: boolean;
13
13
  placeholder: string;
14
14
  clearable: boolean;
@@ -7,8 +7,8 @@ declare const __VLS_export: _$vue.DefineComponent<DateRangePickerProps, {}, {},
7
7
  }, string, _$vue.PublicProps, Readonly<DateRangePickerProps> & Readonly<{
8
8
  "onUpdate:modelValue"?: ((value?: [string, string] | undefined) => any) | undefined;
9
9
  }>, {
10
- disabled: boolean;
11
10
  type: "date" | "month" | "year";
11
+ disabled: boolean;
12
12
  readonly: boolean;
13
13
  placeholder: [string, string];
14
14
  clearable: boolean;
@@ -14,12 +14,12 @@ type __VLS_Slots = {} & {
14
14
  declare const __VLS_base: _$vue.DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, _$vue.ComponentOptionsMixin, _$vue.ComponentOptionsMixin, {
15
15
  "update:modelValue": (value: boolean) => any;
16
16
  } & {
17
- close: () => any;
18
17
  "update:modelValue": (value: boolean) => any;
18
+ close: () => any;
19
19
  closed: () => any;
20
20
  }, string, _$vue.PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
21
- onClose?: (() => any) | undefined;
22
21
  "onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
22
+ onClose?: (() => any) | undefined;
23
23
  onClosed?: (() => any) | undefined;
24
24
  }>, {
25
25
  direction: DrawerDirection;
@@ -18,7 +18,8 @@ const _hoisted_9 = ["disabled"];
18
18
  const _hoisted_10 = ["disabled"];
19
19
  const MIN_SCALE = .5;
20
20
  const MAX_SCALE = 3;
21
- const SCALE_STEP = .25;
21
+ /** 每次缩放固定增减 10% */
22
+ const SCALE_STEP = .1;
22
23
  const _sfc_main = /* @__PURE__ */ defineComponent({
23
24
  name: "FileViewer",
24
25
  inheritAttrs: false,
@@ -70,15 +71,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
70
71
  const props = __props;
71
72
  const emit = __emit;
72
73
  const cls = bem("file-viewer");
73
- const TRANSFORMABLE_KINDS = new Set([
74
- "image",
75
- "pdf",
76
- "docx"
77
- ]);
74
+ const TRANSFORMABLE_KINDS = new Set(["image"]);
75
+ /** 工具栏显示缩放控件的类型 */
76
+ const ZOOMABLE_KINDS = new Set(["image", "pdf"]);
78
77
  const activeId = useModel(__props, "modelValue");
79
78
  const openModel = useModel(__props, "open");
80
79
  const rootRef = shallowRef();
80
+ const previewerRef = shallowRef();
81
81
  const scale = ref(1);
82
+ const pdfZoomLevel = ref(1);
82
83
  const offsetX = ref(0);
83
84
  const offsetY = ref(0);
84
85
  const isDragging = ref(false);
@@ -110,11 +111,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
110
111
  const isModal = computed(() => openModel.value !== void 0);
111
112
  const activeIndexLabel = computed(() => activeIndex.value >= 0 ? `${activeIndex.value + 1} / ${normalizedFiles.value.length}` : "");
112
113
  const isTransformable = computed(() => !!activeFile.value && TRANSFORMABLE_KINDS.has(activeFile.value.kind));
114
+ const isZoomable = computed(() => !!activeFile.value && ZOOMABLE_KINDS.has(activeFile.value.kind));
115
+ const isPdfActive = computed(() => activeFile.value?.kind === "pdf");
113
116
  const canPan = computed(() => isTransformable.value && scale.value > 1);
114
- const zoomPercent = computed(() => `${Math.round(scale.value * 100)}%`);
115
- const zoomInDisabled = computed(() => !isTransformable.value || scale.value >= MAX_SCALE);
116
- const zoomOutDisabled = computed(() => !isTransformable.value || scale.value <= MIN_SCALE);
117
- const isTransformReset = computed(() => scale.value === 1 && offsetX.value === 0 && offsetY.value === 0);
117
+ const displayZoomLevel = computed(() => isPdfActive.value ? pdfZoomLevel.value : scale.value);
118
+ const zoomPercent = computed(() => `${Math.round(displayZoomLevel.value * 100)}%`);
119
+ const zoomInDisabled = computed(() => !isZoomable.value || displayZoomLevel.value >= MAX_SCALE);
120
+ const zoomOutDisabled = computed(() => !isZoomable.value || displayZoomLevel.value <= MIN_SCALE);
121
+ const isTransformReset = computed(() => {
122
+ if (isPdfActive.value) return Math.abs(pdfZoomLevel.value - 1) < .02;
123
+ return scale.value === 1 && offsetX.value === 0 && offsetY.value === 0;
124
+ });
118
125
  const previewerStyle = computed(() => {
119
126
  if (!isTransformable.value) return void 0;
120
127
  return { transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value})` };
@@ -151,20 +158,47 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
151
158
  }
152
159
  }
153
160
  function zoomIn() {
154
- if (!isTransformable.value) return;
161
+ if (!isZoomable.value) return;
162
+ if (isPdfActive.value) {
163
+ previewerRef.value?.zoomIn?.();
164
+ return;
165
+ }
155
166
  setScale(scale.value + SCALE_STEP);
156
167
  }
157
168
  function zoomOut() {
158
- if (!isTransformable.value) return;
169
+ if (!isZoomable.value) return;
170
+ if (isPdfActive.value) {
171
+ previewerRef.value?.zoomOut?.();
172
+ return;
173
+ }
159
174
  setScale(scale.value - SCALE_STEP);
160
175
  }
161
176
  function resetTransform() {
177
+ if (isPdfActive.value) {
178
+ previewerRef.value?.resetZoom?.();
179
+ pdfZoomLevel.value = 1;
180
+ return;
181
+ }
162
182
  scale.value = 1;
163
183
  offsetX.value = 0;
164
184
  offsetY.value = 0;
165
185
  dragState = void 0;
166
186
  isDragging.value = false;
167
187
  }
188
+ function handlePdfZoomChange(level) {
189
+ pdfZoomLevel.value = level;
190
+ }
191
+ function isZoomWheel(e) {
192
+ return e.ctrlKey || e.metaKey;
193
+ }
194
+ function handleViewportWheel(e) {
195
+ if (!activeFile.value || activeFile.value.kind !== "image") return;
196
+ if (!isZoomWheel(e)) return;
197
+ if (isInteractiveTarget(e.target)) return;
198
+ e.preventDefault();
199
+ const delta = e.deltaY > 0 ? -SCALE_STEP : SCALE_STEP;
200
+ setScale(scale.value + delta);
201
+ }
168
202
  function isInteractiveTarget(target) {
169
203
  if (!(target instanceof HTMLElement)) return false;
170
204
  return !!target.closest("button, a, input, textarea, select, video, [contenteditable=\"true\"]");
@@ -195,6 +229,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
195
229
  isDragging.value = false;
196
230
  }
197
231
  function handleViewportDblclick() {
232
+ if (isPdfActive.value) return;
198
233
  if (!isTransformable.value) return;
199
234
  if (scale.value === 1) setScale(2);
200
235
  else resetTransform();
@@ -240,7 +275,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
240
275
  }
241
276
  if (!activeId.value || !files.some((f) => f.id === activeId.value)) activeId.value = files[0].id;
242
277
  }, { immediate: true });
243
- watch(() => activeFile.value?.id, () => resetTransform());
278
+ watch(() => activeFile.value?.id, async () => {
279
+ pdfZoomLevel.value = 1;
280
+ await nextTick();
281
+ resetTransform();
282
+ });
244
283
  let previousBodyOverflow = "";
245
284
  let isBodyLocked = false;
246
285
  function lockBody() {
@@ -349,7 +388,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
349
388
  default: withCtx(() => [createVNode(unref(ArrowRight))]),
350
389
  _: 1
351
390
  })], 10, _hoisted_7)], 2),
352
- isTransformable.value ? (openBlock(), createElementBlock("span", {
391
+ isZoomable.value ? (openBlock(), createElementBlock("span", {
353
392
  key: 0,
354
393
  class: normalizeClass(unref(cls).e("action-group"))
355
394
  }, [
@@ -426,17 +465,21 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
426
465
  unref(bem).is("pannable", canPan.value),
427
466
  unref(bem).is("dragging", isDragging.value)
428
467
  ]),
429
- onPointerdown: handleViewportPointerDown,
430
- onPointermove: handleViewportPointerMove,
431
- onPointerup: handleViewportPointerEnd,
432
- onPointercancel: handleViewportPointerEnd,
468
+ onPointerdownCapture: handleViewportPointerDown,
469
+ onPointermoveCapture: handleViewportPointerMove,
470
+ onPointerupCapture: handleViewportPointerEnd,
471
+ onPointercancelCapture: handleViewportPointerEnd,
472
+ onWheel: handleViewportWheel,
433
473
  onDblclick: handleViewportDblclick
434
474
  }, [(openBlock(), createBlock(resolveDynamicComponent(PreviewerMap[activeFile.value.kind]), {
475
+ ref_key: "previewerRef",
476
+ ref: previewerRef,
435
477
  file: activeFile.value,
436
478
  "max-rows": __props.sheetMaxRows,
437
479
  class: normalizeClass(isTransformable.value ? unref(cls).e("previewer") : void 0),
438
480
  style: normalizeStyle(previewerStyle.value),
439
- onError: handleChildError
481
+ onError: handleChildError,
482
+ onZoomChange: handlePdfZoomChange
440
483
  }, null, 40, [
441
484
  "file",
442
485
  "max-rows",
@@ -1 +1 @@
1
- {"version":3,"file":"file-viewer.js","names":[],"sources":["../../../src/components/file-viewer/file-viewer.vue"],"sourcesContent":["<template>\n <Teleport to=\"body\" :disabled=\"!isModal\">\n <transition :name=\"isModal ? 'u-file-viewer-modal' : ''\">\n <div\n v-if=\"!isModal || openModel\"\n :class=\"[cls.b, bem.is('modal', isModal)]\"\n :tabindex=\"isModal ? -1 : undefined\"\n ref=\"rootRef\"\n @mousedown.self=\"handleBackdropMousedown\"\n >\n <div v-if=\"isModal\" :class=\"cls.e('backdrop')\" @mousedown.self=\"handleBackdropMousedown\" />\n <div :class=\"cls.e('inner')\">\n <aside v-if=\"showSidebar\" :class=\"cls.e('sidebar')\" :style=\"{ width: sidebarWidthCss }\">\n <header :class=\"cls.e('sidebar-head')\">\n <span :class=\"cls.e('sidebar-title')\">文件</span>\n <span :class=\"cls.e('sidebar-count')\">{{ normalizedFiles.length }}</span>\n </header>\n <u-scroll tag=\"ul\" :class=\"cls.e('list')\">\n <li\n v-for=\"f in normalizedFiles\"\n :key=\"f.id\"\n :class=\"[cls.e('item'), bem.is('active', f.id === activeId)]\"\n :title=\"f.name\"\n @click=\"activate(f.id)\"\n >\n <span :class=\"cls.e('item-meta')\">\n <span :class=\"cls.e('item-name')\" :title=\"f.name\">{{ f.name }}</span>\n <span :class=\"cls.e('item-size')\">{{ formatBytes(f.size) }}</span>\n </span>\n <span :class=\"cls.e('item-kind')\">{{ label(f.kind) }}</span>\n </li>\n <li v-if=\"!normalizedFiles.length\" :class=\"cls.e('list-empty')\">\n <u-empty text=\"暂无文件\" :size=\"32\" />\n </li>\n </u-scroll>\n </aside>\n\n <section :class=\"cls.e('stage')\">\n <header :class=\"cls.e('stage-head')\">\n <div :class=\"cls.e('stage-title')\">\n <span v-if=\"activeFile\" :class=\"[cls.e('badge'), cls.em('badge', activeFile.kind)]\">\n {{ label(activeFile.kind) }}\n </span>\n <span :class=\"cls.e('stage-copy')\">\n <span :class=\"cls.e('stage-name')\" :title=\"activeFile?.name\">\n {{ activeFile?.name ?? '—' }}\n </span>\n <span v-if=\"activeFile\" :class=\"cls.e('stage-sub')\">\n <span>{{ activeIndexLabel }}</span>\n <span v-if=\"activeFile.size\">{{ formatBytes(activeFile.size) }}</span>\n </span>\n </span>\n </div>\n <div :class=\"cls.e('stage-actions')\">\n <span :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasPrev\"\n type=\"button\"\n aria-label=\"上一个\"\n title=\"上一个\"\n @click=\"prev\"\n >\n <u-icon :size=\"15\">\n <ArrowLeft />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasNext\"\n type=\"button\"\n aria-label=\"下一个\"\n title=\"下一个\"\n @click=\"next\"\n >\n <u-icon :size=\"15\">\n <ArrowRight />\n </u-icon>\n </button>\n </span>\n <span v-if=\"isTransformable\" :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomOutDisabled\"\n type=\"button\"\n aria-label=\"缩小\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n <u-icon :size=\"15\">\n <ZoomOut />\n </u-icon>\n </button>\n <span :class=\"cls.e('zoom-value')\">{{ zoomPercent }}</span>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomInDisabled\"\n type=\"button\"\n aria-label=\"放大\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n <u-icon :size=\"15\">\n <ZoomIn />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"isTransformReset\"\n type=\"button\"\n aria-label=\"重置视图\"\n title=\"重置视图\"\n @click=\"resetTransform\"\n >\n <u-icon :size=\"15\">\n <Refresh />\n </u-icon>\n </button>\n </span>\n <button\n v-if=\"downloadable && activeFile\"\n :class=\"[cls.e('action'), cls.em('action', 'primary'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"下载\"\n title=\"下载\"\n @click=\"download\"\n >\n <u-icon :size=\"15\">\n <Download />\n </u-icon>\n </button>\n <button\n v-if=\"isModal\"\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"关闭预览\"\n title=\"关闭\"\n @click=\"handleClose\"\n >\n <u-icon :size=\"16\">\n <Close />\n </u-icon>\n </button>\n </div>\n </header>\n <div :class=\"cls.e('body')\">\n <transition name=\"u-file-viewer-fade\" mode=\"out-in\">\n <div\n v-if=\"activeFile\"\n :key=\"activeFile.id\"\n :class=\"[\n cls.e('viewport'),\n bem.is('transformable', isTransformable),\n bem.is('pannable', canPan),\n bem.is('dragging', isDragging)\n ]\"\n @pointerdown=\"handleViewportPointerDown\"\n @pointermove=\"handleViewportPointerMove\"\n @pointerup=\"handleViewportPointerEnd\"\n @pointercancel=\"handleViewportPointerEnd\"\n @dblclick=\"handleViewportDblclick\"\n >\n <component\n :is=\"PreviewerMap[activeFile.kind]\"\n :file=\"activeFile\"\n :max-rows=\"sheetMaxRows\"\n :class=\"isTransformable ? cls.e('previewer') : undefined\"\n :style=\"previewerStyle\"\n @error=\"handleChildError\"\n />\n </div>\n <div v-else :class=\"cls.e('empty')\">\n <u-empty text=\"暂无可预览文件\" />\n </div>\n </transition>\n </div>\n </section>\n </div>\n </div>\n </transition>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport {\n ArrowLeft,\n ArrowRight,\n Close,\n Download,\n Refresh,\n ZoomIn,\n ZoomOut\n} from '@veltra/icons/normal'\nimport { bem, withUnit } from '@veltra/utils'\nimport {\n computed,\n defineAsyncComponent,\n nextTick,\n onBeforeUnmount,\n ref,\n shallowRef,\n watch\n} from 'vue'\nimport type { CSSProperties } from 'vue'\n\nimport type {\n _FileViewerExposed,\n FileViewerEmits,\n FileViewerItem,\n FileViewerKind,\n FileViewerProps\n} from '../../types/file-viewer'\nimport { UEmpty } from '../empty'\nimport { UIcon } from '../icon'\nimport { UScroll } from '../scroll'\nimport { FILE_VIEWER_KIND_LABEL, downloadFile, formatBytes, inferKind } from './helper'\n\ndefineOptions({\n name: 'FileViewer',\n inheritAttrs: false\n})\n\nconst props = withDefaults(defineProps<FileViewerProps>(), {\n modelValue: undefined,\n sidebarWidth: '280px',\n sheetMaxRows: 50_000,\n downloadable: true,\n open: undefined,\n closeOnClickBackdrop: true,\n closeOnEsc: true\n})\n\nconst emit = defineEmits<FileViewerEmits>()\n\nconst cls = bem('file-viewer')\n\nconst MIN_SCALE = 0.5\nconst MAX_SCALE = 3\nconst SCALE_STEP = 0.25\nconst TRANSFORMABLE_KINDS = new Set<FileViewerKind>(['image', 'pdf', 'docx'])\n\nconst activeId = defineModel<string | undefined>('modelValue', { default: undefined })\nconst openModel = defineModel<boolean | undefined>('open', { default: undefined })\n\nconst rootRef = shallowRef<HTMLDivElement>()\nconst scale = ref(1)\nconst offsetX = ref(0)\nconst offsetY = ref(0)\nconst isDragging = ref(false)\n\nlet dragState:\n | {\n pointerId: number\n startX: number\n startY: number\n originX: number\n originY: number\n }\n | undefined\n\nconst PreviewerMap: Record<FileViewerKind, ReturnType<typeof defineAsyncComponent>> = {\n image: defineAsyncComponent(() => import('./previewers/image-previewer.vue')),\n video: defineAsyncComponent(() => import('./previewers/video-previewer.vue')),\n pdf: defineAsyncComponent(() => import('./previewers/pdf-previewer.vue')),\n sheet: defineAsyncComponent(() => import('./previewers/sheet-previewer.vue')),\n docx: defineAsyncComponent(() => import('./previewers/docx-previewer.vue')),\n text: defineAsyncComponent(() => import('./previewers/text-previewer.vue'))\n}\n\ninterface NormalizedFile extends FileViewerItem {\n id: string\n kind: FileViewerKind\n}\n\nconst normalizedFiles = computed<NormalizedFile[]>(() =>\n props.files.map((f, i) => ({\n ...f,\n id: f.id ?? `file-${i}`,\n kind: inferKind(f.name, f.kind)\n }))\n)\n\nconst activeFile = computed<NormalizedFile | undefined>(() =>\n normalizedFiles.value.find((f) => f.id === activeId.value)\n)\n\nconst activeIndex = computed(() => normalizedFiles.value.findIndex((f) => f.id === activeId.value))\n\nconst hasPrev = computed(() => activeIndex.value > 0)\nconst hasNext = computed(\n () => activeIndex.value >= 0 && activeIndex.value < normalizedFiles.value.length - 1\n)\n\nconst showSidebar = computed(() => props.sidebarWidth !== false && props.sidebarWidth !== 0)\n\nconst sidebarWidthCss = computed(() => {\n const w = props.sidebarWidth\n if (w === false || w === 0) return undefined\n return withUnit(w ?? '280px', 'px')\n})\n\n/** 是否启用模态模式:只要父组件显式传入 open(含 v-model:open),即进入模态 */\nconst isModal = computed(() => openModel.value !== undefined)\n\nconst activeIndexLabel = computed(() =>\n activeIndex.value >= 0 ? `${activeIndex.value + 1} / ${normalizedFiles.value.length}` : ''\n)\n\nconst isTransformable = computed(\n () => !!activeFile.value && TRANSFORMABLE_KINDS.has(activeFile.value.kind)\n)\n\nconst canPan = computed(() => isTransformable.value && scale.value > 1)\n\nconst zoomPercent = computed(() => `${Math.round(scale.value * 100)}%`)\n\nconst zoomInDisabled = computed(() => !isTransformable.value || scale.value >= MAX_SCALE)\n\nconst zoomOutDisabled = computed(() => !isTransformable.value || scale.value <= MIN_SCALE)\n\nconst isTransformReset = computed(\n () => scale.value === 1 && offsetX.value === 0 && offsetY.value === 0\n)\n\nconst previewerStyle = computed<CSSProperties | undefined>(() => {\n if (!isTransformable.value) return undefined\n return {\n transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value})`\n }\n})\n\nfunction label(kind: FileViewerKind): string {\n return FILE_VIEWER_KIND_LABEL[kind]\n}\n\nfunction activate(id: string) {\n if (activeId.value === id) return\n activeId.value = id\n const f = normalizedFiles.value.find((x) => x.id === id)\n if (f) emit('change', f)\n}\n\nfunction prev() {\n const i = activeIndex.value\n if (i <= 0) return\n const target = normalizedFiles.value[i - 1]\n if (target) activate(target.id)\n}\n\nfunction next() {\n const i = activeIndex.value\n if (i < 0 || i >= normalizedFiles.value.length - 1) return\n const target = normalizedFiles.value[i + 1]\n if (target) activate(target.id)\n}\n\nfunction normalizeScale(value: number): number {\n const clamped = Math.min(MAX_SCALE, Math.max(MIN_SCALE, value))\n return Math.round(clamped * 100) / 100\n}\n\nfunction setScale(value: number) {\n scale.value = normalizeScale(value)\n if (scale.value <= 1) {\n offsetX.value = 0\n offsetY.value = 0\n }\n}\n\nfunction zoomIn() {\n if (!isTransformable.value) return\n setScale(scale.value + SCALE_STEP)\n}\n\nfunction zoomOut() {\n if (!isTransformable.value) return\n setScale(scale.value - SCALE_STEP)\n}\n\nfunction resetTransform() {\n scale.value = 1\n offsetX.value = 0\n offsetY.value = 0\n dragState = undefined\n isDragging.value = false\n}\n\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return !!target.closest('button, a, input, textarea, select, video, [contenteditable=\"true\"]')\n}\n\nfunction handleViewportPointerDown(e: PointerEvent) {\n if (!canPan.value || e.button !== 0 || isInteractiveTarget(e.target)) return\n\n dragState = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n originX: offsetX.value,\n originY: offsetY.value\n }\n isDragging.value = true\n const el = e.currentTarget as HTMLElement\n el.setPointerCapture(e.pointerId)\n e.preventDefault()\n}\n\nfunction handleViewportPointerMove(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n offsetX.value = dragState.originX + e.clientX - dragState.startX\n offsetY.value = dragState.originY + e.clientY - dragState.startY\n}\n\nfunction handleViewportPointerEnd(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n const el = e.currentTarget as HTMLElement\n if (el.hasPointerCapture(e.pointerId)) {\n el.releasePointerCapture(e.pointerId)\n }\n dragState = undefined\n isDragging.value = false\n}\n\nfunction handleViewportDblclick() {\n if (!isTransformable.value) return\n if (scale.value === 1) {\n setScale(2)\n } else {\n resetTransform()\n }\n}\n\nasync function download() {\n if (!activeFile.value) return\n try {\n await downloadFile(activeFile.value)\n } catch (err) {\n emit('error', { file: activeFile.value, error: err })\n }\n}\n\nfunction handleChildError(err: unknown) {\n if (!activeFile.value) return\n emit('error', { file: activeFile.value, error: err })\n}\n\nfunction handleClose() {\n if (!isModal.value) return\n openModel.value = false\n}\n\nfunction handleWindowKeydown(e: KeyboardEvent) {\n if (e.key !== 'Escape') return\n if (!isModal.value || !openModel.value) return\n if (props.closeOnEsc === false) return\n e.stopPropagation()\n handleClose()\n}\n\nfunction handleBackdropMousedown() {\n if (!isModal.value) return\n if (props.closeOnClickBackdrop === false) return\n handleClose()\n}\n\nwatch(\n normalizedFiles,\n (files) => {\n if (!files.length) {\n activeId.value = undefined\n return\n }\n if (!activeId.value || !files.some((f) => f.id === activeId.value)) {\n activeId.value = files[0]!.id\n }\n },\n { immediate: true }\n)\n\nwatch(\n () => activeFile.value?.id,\n () => resetTransform()\n)\n\n// 模态打开时:锁定 body 滚动 + 让容器获得焦点以便接收 ESC\nlet previousBodyOverflow = ''\nlet isBodyLocked = false\n\nfunction lockBody() {\n if (isBodyLocked || typeof document === 'undefined') return\n previousBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n isBodyLocked = true\n}\n\nfunction unlockBody() {\n if (!isBodyLocked || typeof document === 'undefined') return\n document.body.style.overflow = previousBodyOverflow\n isBodyLocked = false\n}\n\nwatch(\n [isModal, openModel],\n ([modal, open]) => {\n if (modal && open) {\n lockBody()\n nextTick(() => {\n rootRef.value?.focus()\n })\n if (typeof window !== 'undefined') {\n window.addEventListener('keydown', handleWindowKeydown, true)\n }\n } else {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n }\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n})\n\ndefineExpose<_FileViewerExposed>({\n activeId,\n activate,\n next,\n prev\n})\n</script>\n"],"mappings":"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"}
1
+ {"version":3,"file":"file-viewer.js","names":[],"sources":["../../../src/components/file-viewer/file-viewer.vue"],"sourcesContent":["<template>\n <Teleport to=\"body\" :disabled=\"!isModal\">\n <transition :name=\"isModal ? 'u-file-viewer-modal' : ''\">\n <div\n v-if=\"!isModal || openModel\"\n :class=\"[cls.b, bem.is('modal', isModal)]\"\n :tabindex=\"isModal ? -1 : undefined\"\n ref=\"rootRef\"\n @mousedown.self=\"handleBackdropMousedown\"\n >\n <div v-if=\"isModal\" :class=\"cls.e('backdrop')\" @mousedown.self=\"handleBackdropMousedown\" />\n <div :class=\"cls.e('inner')\">\n <aside v-if=\"showSidebar\" :class=\"cls.e('sidebar')\" :style=\"{ width: sidebarWidthCss }\">\n <header :class=\"cls.e('sidebar-head')\">\n <span :class=\"cls.e('sidebar-title')\">文件</span>\n <span :class=\"cls.e('sidebar-count')\">{{ normalizedFiles.length }}</span>\n </header>\n <u-scroll tag=\"ul\" :class=\"cls.e('list')\">\n <li\n v-for=\"f in normalizedFiles\"\n :key=\"f.id\"\n :class=\"[cls.e('item'), bem.is('active', f.id === activeId)]\"\n :title=\"f.name\"\n @click=\"activate(f.id)\"\n >\n <span :class=\"cls.e('item-meta')\">\n <span :class=\"cls.e('item-name')\" :title=\"f.name\">{{ f.name }}</span>\n <span :class=\"cls.e('item-size')\">{{ formatBytes(f.size) }}</span>\n </span>\n <span :class=\"cls.e('item-kind')\">{{ label(f.kind) }}</span>\n </li>\n <li v-if=\"!normalizedFiles.length\" :class=\"cls.e('list-empty')\">\n <u-empty text=\"暂无文件\" :size=\"32\" />\n </li>\n </u-scroll>\n </aside>\n\n <section :class=\"cls.e('stage')\">\n <header :class=\"cls.e('stage-head')\">\n <div :class=\"cls.e('stage-title')\">\n <span v-if=\"activeFile\" :class=\"[cls.e('badge'), cls.em('badge', activeFile.kind)]\">\n {{ label(activeFile.kind) }}\n </span>\n <span :class=\"cls.e('stage-copy')\">\n <span :class=\"cls.e('stage-name')\" :title=\"activeFile?.name\">\n {{ activeFile?.name ?? '—' }}\n </span>\n <span v-if=\"activeFile\" :class=\"cls.e('stage-sub')\">\n <span>{{ activeIndexLabel }}</span>\n <span v-if=\"activeFile.size\">{{ formatBytes(activeFile.size) }}</span>\n </span>\n </span>\n </div>\n <div :class=\"cls.e('stage-actions')\">\n <span :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasPrev\"\n type=\"button\"\n aria-label=\"上一个\"\n title=\"上一个\"\n @click=\"prev\"\n >\n <u-icon :size=\"15\">\n <ArrowLeft />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"!hasNext\"\n type=\"button\"\n aria-label=\"下一个\"\n title=\"下一个\"\n @click=\"next\"\n >\n <u-icon :size=\"15\">\n <ArrowRight />\n </u-icon>\n </button>\n </span>\n <span v-if=\"isZoomable\" :class=\"cls.e('action-group')\">\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomOutDisabled\"\n type=\"button\"\n aria-label=\"缩小\"\n title=\"缩小\"\n @click=\"zoomOut\"\n >\n <u-icon :size=\"15\">\n <ZoomOut />\n </u-icon>\n </button>\n <span :class=\"cls.e('zoom-value')\">{{ zoomPercent }}</span>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"zoomInDisabled\"\n type=\"button\"\n aria-label=\"放大\"\n title=\"放大\"\n @click=\"zoomIn\"\n >\n <u-icon :size=\"15\">\n <ZoomIn />\n </u-icon>\n </button>\n <button\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n :disabled=\"isTransformReset\"\n type=\"button\"\n aria-label=\"重置视图\"\n title=\"重置视图\"\n @click=\"resetTransform\"\n >\n <u-icon :size=\"15\">\n <Refresh />\n </u-icon>\n </button>\n </span>\n <button\n v-if=\"downloadable && activeFile\"\n :class=\"[cls.e('action'), cls.em('action', 'primary'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"下载\"\n title=\"下载\"\n @click=\"download\"\n >\n <u-icon :size=\"15\">\n <Download />\n </u-icon>\n </button>\n <button\n v-if=\"isModal\"\n :class=\"[cls.e('action'), cls.em('action', 'icon')]\"\n type=\"button\"\n aria-label=\"关闭预览\"\n title=\"关闭\"\n @click=\"handleClose\"\n >\n <u-icon :size=\"16\">\n <Close />\n </u-icon>\n </button>\n </div>\n </header>\n <div :class=\"cls.e('body')\">\n <transition name=\"u-file-viewer-fade\" mode=\"out-in\">\n <div\n v-if=\"activeFile\"\n :key=\"activeFile.id\"\n :class=\"[\n cls.e('viewport'),\n bem.is('transformable', isTransformable),\n bem.is('pannable', canPan),\n bem.is('dragging', isDragging)\n ]\"\n @pointerdown.capture=\"handleViewportPointerDown\"\n @pointermove.capture=\"handleViewportPointerMove\"\n @pointerup.capture=\"handleViewportPointerEnd\"\n @pointercancel.capture=\"handleViewportPointerEnd\"\n @wheel=\"handleViewportWheel\"\n @dblclick=\"handleViewportDblclick\"\n >\n <component\n :is=\"PreviewerMap[activeFile.kind]\"\n ref=\"previewerRef\"\n :file=\"activeFile\"\n :max-rows=\"sheetMaxRows\"\n :class=\"isTransformable ? cls.e('previewer') : undefined\"\n :style=\"previewerStyle\"\n @error=\"handleChildError\"\n @zoom-change=\"handlePdfZoomChange\"\n />\n </div>\n <div v-else :class=\"cls.e('empty')\">\n <u-empty text=\"暂无可预览文件\" />\n </div>\n </transition>\n </div>\n </section>\n </div>\n </div>\n </transition>\n </Teleport>\n</template>\n\n<script lang=\"ts\" setup>\nimport {\n ArrowLeft,\n ArrowRight,\n Close,\n Download,\n Refresh,\n ZoomIn,\n ZoomOut\n} from '@veltra/icons/normal'\nimport { bem, withUnit } from '@veltra/utils'\nimport {\n computed,\n defineAsyncComponent,\n nextTick,\n onBeforeUnmount,\n ref,\n shallowRef,\n watch\n} from 'vue'\nimport type { CSSProperties } from 'vue'\n\nimport type {\n _FileViewerExposed,\n FileViewerEmits,\n FileViewerItem,\n FileViewerKind,\n FileViewerProps\n} from '../../types/file-viewer'\nimport { UEmpty } from '../empty'\nimport { UIcon } from '../icon'\nimport { UScroll } from '../scroll'\nimport { FILE_VIEWER_KIND_LABEL, downloadFile, formatBytes, inferKind } from './helper'\n\ndefineOptions({\n name: 'FileViewer',\n inheritAttrs: false\n})\n\nconst props = withDefaults(defineProps<FileViewerProps>(), {\n modelValue: undefined,\n sidebarWidth: '280px',\n sheetMaxRows: 50_000,\n downloadable: true,\n open: undefined,\n closeOnClickBackdrop: true,\n closeOnEsc: true\n})\n\nconst emit = defineEmits<FileViewerEmits>()\n\nconst cls = bem('file-viewer')\n\nconst MIN_SCALE = 0.5\nconst MAX_SCALE = 3\n/** 每次缩放固定增减 10% */\nconst SCALE_STEP = 0.1\n/** 使用 CSS transform 缩放的类型(PDF 由 EmbedPDF zoom 插件处理) */\nconst TRANSFORMABLE_KINDS = new Set<FileViewerKind>(['image'])\n/** 工具栏显示缩放控件的类型 */\nconst ZOOMABLE_KINDS = new Set<FileViewerKind>(['image', 'pdf'])\n\nconst activeId = defineModel<string | undefined>('modelValue', { default: undefined })\nconst openModel = defineModel<boolean | undefined>('open', { default: undefined })\n\nconst rootRef = shallowRef<HTMLDivElement>()\nconst previewerRef = shallowRef<{\n zoomIn?: () => void\n zoomOut?: () => void\n resetZoom?: () => void\n}>()\nconst scale = ref(1)\nconst pdfZoomLevel = ref(1)\nconst offsetX = ref(0)\nconst offsetY = ref(0)\nconst isDragging = ref(false)\n\nlet dragState:\n | {\n pointerId: number\n startX: number\n startY: number\n originX: number\n originY: number\n }\n | undefined\n\nconst PreviewerMap: Record<FileViewerKind, ReturnType<typeof defineAsyncComponent>> = {\n image: defineAsyncComponent(() => import('./previewers/image-previewer.vue')),\n video: defineAsyncComponent(() => import('./previewers/video-previewer.vue')),\n pdf: defineAsyncComponent(() => import('./previewers/pdf-previewer.vue')),\n sheet: defineAsyncComponent(() => import('./previewers/sheet-previewer.vue')),\n docx: defineAsyncComponent(() => import('./previewers/docx-previewer.vue')),\n text: defineAsyncComponent(() => import('./previewers/text-previewer.vue'))\n}\n\ninterface NormalizedFile extends FileViewerItem {\n id: string\n kind: FileViewerKind\n}\n\nconst normalizedFiles = computed<NormalizedFile[]>(() =>\n props.files.map((f, i) => ({\n ...f,\n id: f.id ?? `file-${i}`,\n kind: inferKind(f.name, f.kind)\n }))\n)\n\nconst activeFile = computed<NormalizedFile | undefined>(() =>\n normalizedFiles.value.find((f) => f.id === activeId.value)\n)\n\nconst activeIndex = computed(() => normalizedFiles.value.findIndex((f) => f.id === activeId.value))\n\nconst hasPrev = computed(() => activeIndex.value > 0)\nconst hasNext = computed(\n () => activeIndex.value >= 0 && activeIndex.value < normalizedFiles.value.length - 1\n)\n\nconst showSidebar = computed(() => props.sidebarWidth !== false && props.sidebarWidth !== 0)\n\nconst sidebarWidthCss = computed(() => {\n const w = props.sidebarWidth\n if (w === false || w === 0) return undefined\n return withUnit(w ?? '280px', 'px')\n})\n\n/** 是否启用模态模式:只要父组件显式传入 open(含 v-model:open),即进入模态 */\nconst isModal = computed(() => openModel.value !== undefined)\n\nconst activeIndexLabel = computed(() =>\n activeIndex.value >= 0 ? `${activeIndex.value + 1} / ${normalizedFiles.value.length}` : ''\n)\n\nconst isTransformable = computed(\n () => !!activeFile.value && TRANSFORMABLE_KINDS.has(activeFile.value.kind)\n)\n\nconst isZoomable = computed(() => !!activeFile.value && ZOOMABLE_KINDS.has(activeFile.value.kind))\n\nconst isPdfActive = computed(() => activeFile.value?.kind === 'pdf')\n\nconst canPan = computed(() => isTransformable.value && scale.value > 1)\n\nconst displayZoomLevel = computed(() => (isPdfActive.value ? pdfZoomLevel.value : scale.value))\n\nconst zoomPercent = computed(() => `${Math.round(displayZoomLevel.value * 100)}%`)\n\nconst zoomInDisabled = computed(() => !isZoomable.value || displayZoomLevel.value >= MAX_SCALE)\n\nconst zoomOutDisabled = computed(() => !isZoomable.value || displayZoomLevel.value <= MIN_SCALE)\n\nconst isTransformReset = computed(() => {\n if (isPdfActive.value) {\n return Math.abs(pdfZoomLevel.value - 1) < 0.02\n }\n return scale.value === 1 && offsetX.value === 0 && offsetY.value === 0\n})\n\nconst previewerStyle = computed<CSSProperties | undefined>(() => {\n if (!isTransformable.value) return undefined\n return {\n transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value})`\n }\n})\n\nfunction label(kind: FileViewerKind): string {\n return FILE_VIEWER_KIND_LABEL[kind]\n}\n\nfunction activate(id: string) {\n if (activeId.value === id) return\n activeId.value = id\n const f = normalizedFiles.value.find((x) => x.id === id)\n if (f) emit('change', f)\n}\n\nfunction prev() {\n const i = activeIndex.value\n if (i <= 0) return\n const target = normalizedFiles.value[i - 1]\n if (target) activate(target.id)\n}\n\nfunction next() {\n const i = activeIndex.value\n if (i < 0 || i >= normalizedFiles.value.length - 1) return\n const target = normalizedFiles.value[i + 1]\n if (target) activate(target.id)\n}\n\nfunction normalizeScale(value: number): number {\n const clamped = Math.min(MAX_SCALE, Math.max(MIN_SCALE, value))\n return Math.round(clamped * 100) / 100\n}\n\nfunction setScale(value: number) {\n scale.value = normalizeScale(value)\n if (scale.value <= 1) {\n offsetX.value = 0\n offsetY.value = 0\n }\n}\n\nfunction zoomIn() {\n if (!isZoomable.value) return\n if (isPdfActive.value) {\n previewerRef.value?.zoomIn?.()\n return\n }\n setScale(scale.value + SCALE_STEP)\n}\n\nfunction zoomOut() {\n if (!isZoomable.value) return\n if (isPdfActive.value) {\n previewerRef.value?.zoomOut?.()\n return\n }\n setScale(scale.value - SCALE_STEP)\n}\n\nfunction resetTransform() {\n if (isPdfActive.value) {\n previewerRef.value?.resetZoom?.()\n pdfZoomLevel.value = 1\n return\n }\n scale.value = 1\n offsetX.value = 0\n offsetY.value = 0\n dragState = undefined\n isDragging.value = false\n}\n\nfunction handlePdfZoomChange(level: number) {\n pdfZoomLevel.value = level\n}\n\nfunction isZoomWheel(e: WheelEvent): boolean {\n return e.ctrlKey || e.metaKey\n}\n\nfunction handleViewportWheel(e: WheelEvent) {\n if (!activeFile.value || activeFile.value.kind !== 'image') return\n if (!isZoomWheel(e)) return\n if (isInteractiveTarget(e.target)) return\n e.preventDefault()\n const delta = e.deltaY > 0 ? -SCALE_STEP : SCALE_STEP\n setScale(scale.value + delta)\n}\n\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false\n return !!target.closest('button, a, input, textarea, select, video, [contenteditable=\"true\"]')\n}\n\nfunction handleViewportPointerDown(e: PointerEvent) {\n if (!canPan.value || e.button !== 0 || isInteractiveTarget(e.target)) return\n\n dragState = {\n pointerId: e.pointerId,\n startX: e.clientX,\n startY: e.clientY,\n originX: offsetX.value,\n originY: offsetY.value\n }\n isDragging.value = true\n const el = e.currentTarget as HTMLElement\n el.setPointerCapture(e.pointerId)\n e.preventDefault()\n}\n\nfunction handleViewportPointerMove(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n offsetX.value = dragState.originX + e.clientX - dragState.startX\n offsetY.value = dragState.originY + e.clientY - dragState.startY\n}\n\nfunction handleViewportPointerEnd(e: PointerEvent) {\n if (!dragState || dragState.pointerId !== e.pointerId) return\n const el = e.currentTarget as HTMLElement\n if (el.hasPointerCapture(e.pointerId)) {\n el.releasePointerCapture(e.pointerId)\n }\n dragState = undefined\n isDragging.value = false\n}\n\nfunction handleViewportDblclick() {\n if (isPdfActive.value) return\n if (!isTransformable.value) return\n if (scale.value === 1) {\n setScale(2)\n } else {\n resetTransform()\n }\n}\n\nasync function download() {\n if (!activeFile.value) return\n try {\n await downloadFile(activeFile.value)\n } catch (err) {\n emit('error', { file: activeFile.value, error: err })\n }\n}\n\nfunction handleChildError(err: unknown) {\n if (!activeFile.value) return\n emit('error', { file: activeFile.value, error: err })\n}\n\nfunction handleClose() {\n if (!isModal.value) return\n openModel.value = false\n}\n\nfunction handleWindowKeydown(e: KeyboardEvent) {\n if (e.key !== 'Escape') return\n if (!isModal.value || !openModel.value) return\n if (props.closeOnEsc === false) return\n e.stopPropagation()\n handleClose()\n}\n\nfunction handleBackdropMousedown() {\n if (!isModal.value) return\n if (props.closeOnClickBackdrop === false) return\n handleClose()\n}\n\nwatch(\n normalizedFiles,\n (files) => {\n if (!files.length) {\n activeId.value = undefined\n return\n }\n if (!activeId.value || !files.some((f) => f.id === activeId.value)) {\n activeId.value = files[0]!.id\n }\n },\n { immediate: true }\n)\n\nwatch(\n () => activeFile.value?.id,\n async () => {\n pdfZoomLevel.value = 1\n await nextTick()\n resetTransform()\n }\n)\n\n// 模态打开时:锁定 body 滚动 + 让容器获得焦点以便接收 ESC\nlet previousBodyOverflow = ''\nlet isBodyLocked = false\n\nfunction lockBody() {\n if (isBodyLocked || typeof document === 'undefined') return\n previousBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n isBodyLocked = true\n}\n\nfunction unlockBody() {\n if (!isBodyLocked || typeof document === 'undefined') return\n document.body.style.overflow = previousBodyOverflow\n isBodyLocked = false\n}\n\nwatch(\n [isModal, openModel],\n ([modal, open]) => {\n if (modal && open) {\n lockBody()\n nextTick(() => {\n rootRef.value?.focus()\n })\n if (typeof window !== 'undefined') {\n window.addEventListener('keydown', handleWindowKeydown, true)\n }\n } else {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n }\n },\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n unlockBody()\n if (typeof window !== 'undefined') {\n window.removeEventListener('keydown', handleWindowKeydown, true)\n }\n})\n\ndefineExpose<_FileViewerExposed>({\n activeId,\n activate,\n next,\n prev\n})\n</script>\n"],"mappings":"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"}
@@ -28,8 +28,8 @@ declare const __VLS_export: _$vue.DefineComponent<__VLS_PublicProps, _FileViewer
28
28
  }) => any) | undefined;
29
29
  "onUpdate:open"?: ((value: boolean) => any) | undefined;
30
30
  }>, {
31
- open: boolean;
32
31
  modelValue: string;
32
+ open: boolean;
33
33
  sidebarWidth: string | number | false;
34
34
  sheetMaxRows: number;
35
35
  downloadable: boolean;
@@ -1,5 +1,5 @@
1
1
  import { toBlobUrl } from "../helper.js";
2
- import { createCommentVNode, createElementBlock, defineComponent, mergeProps, normalizeClass, onBeforeUnmount, openBlock, ref, shallowRef, unref, useAttrs, watch } from "vue";
2
+ import { createCommentVNode, createElementBlock, defineComponent, mergeProps, normalizeClass, onBeforeUnmount, openBlock, ref, shallowRef, unref, useAttrs, watch, withModifiers } from "vue";
3
3
  import { bem } from "@veltra/utils";
4
4
  //#region src/components/file-viewer/previewers/image-previewer.vue
5
5
  const _hoisted_1 = ["src", "alt"];
@@ -43,7 +43,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
43
43
  src: url.value,
44
44
  alt: __props.file.name,
45
45
  draggable: "false",
46
- onLoad: _cache[0] || (_cache[0] = ($event) => loading.value = false),
46
+ onDragstart: _cache[0] || (_cache[0] = withModifiers(() => {}, ["prevent"])),
47
+ onLoad: _cache[1] || (_cache[1] = ($event) => loading.value = false),
47
48
  onError: onImgError
48
49
  }, null, 40, _hoisted_1)) : createCommentVNode("v-if", true),
49
50
  loading.value ? (openBlock(), createElementBlock("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"image-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/image-previewer.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('image')\" v-bind=\"attrs\">\n <img\n v-if=\"url\"\n :src=\"url\"\n :alt=\"file.name\"\n draggable=\"false\"\n @load=\"loading = false\"\n @error=\"onImgError\"\n />\n <div v-if=\"loading\" :class=\"cls.e('loading')\">加载中…</div>\n <div v-if=\"failed\" :class=\"cls.e('loading')\">图片加载失败</div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { onBeforeUnmount, ref, shallowRef, useAttrs, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\nimport { toBlobUrl } from '../helper'\n\ndefineOptions({ name: 'FileViewerImagePreviewer', inheritAttrs: false })\n\nconst props = defineProps<{ file: FileViewerItem }>()\n\nconst emit = defineEmits<{ (e: 'error', err: unknown): void }>()\n\nconst cls = bem('file-viewer')\nconst attrs = useAttrs()\n\nconst url = shallowRef<string>('')\nconst loading = ref(true)\nconst failed = ref(false)\n\nlet revoke: (() => void) | undefined\n\nfunction load() {\n loading.value = true\n failed.value = false\n revoke?.()\n const r = toBlobUrl(props.file.src, props.file.mime)\n url.value = r.url\n revoke = r.revoke\n}\n\nfunction onImgError(e: Event) {\n loading.value = false\n failed.value = true\n emit('error', e)\n}\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n revoke?.()\n url.value = ''\n})\n</script>\n"],"mappings":";;;;;;;;;;;;EAwBA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,cAAa;EAC7B,MAAM,QAAQ,UAAS;EAEvB,MAAM,MAAM,WAAmB,GAAE;EACjC,MAAM,UAAU,IAAI,KAAI;EACxB,MAAM,SAAS,IAAI,MAAK;EAExB,IAAI;EAEJ,SAAS,OAAO;AACd,WAAQ,QAAQ;AAChB,UAAO,QAAQ;AACf,aAAS;GACT,MAAM,IAAI,UAAU,MAAM,KAAK,KAAK,MAAM,KAAK,KAAI;AACnD,OAAI,QAAQ,EAAE;AACd,YAAS,EAAE;;EAGb,SAAS,WAAW,GAAU;AAC5B,WAAQ,QAAQ;AAChB,UAAO,QAAQ;AACf,QAAK,SAAS,EAAC;;AAGjB,cACQ,MAAM,YACN,MAAM,EACZ,EAAE,WAAW,MAAK,CACpB;AAEA,wBAAsB;AACpB,aAAS;AACT,OAAI,QAAQ;IACb;;uBA5DC,mBAWM,OAXN,WAWM,EAXA,OAAO,MAAA,IAAG,CAAC,EAAC,QAAA,EAAA,EAAmB,MAAA,MAAK,CAAA,EAAA;IAEhC,IAAA,SAAA,WAAA,EADR,mBAOE,OAAA;;KALC,KAAK,IAAA;KACL,KAAK,QAAA,KAAK;KACX,WAAU;KACT,QAAI,OAAA,OAAA,OAAA,MAAA,WAAE,QAAA,QAAO;KACb,SAAO;;IAEC,QAAA,SAAA,WAAA,EAAX,mBAAwD,OAAA;;KAAnC,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,UAAA,CAAA;OAAa,QAAI,EAAA,IAAA,mBAAA,QAAA,KAAA;IACvC,OAAA,SAAA,WAAA,EAAX,mBAAyD,OAAA;;KAArC,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,UAAA,CAAA;OAAa,UAAM,EAAA,IAAA,mBAAA,QAAA,KAAA"}
1
+ {"version":3,"file":"image-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/image-previewer.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('image')\" v-bind=\"attrs\">\n <img\n v-if=\"url\"\n :src=\"url\"\n :alt=\"file.name\"\n draggable=\"false\"\n @dragstart.prevent\n @load=\"loading = false\"\n @error=\"onImgError\"\n />\n <div v-if=\"loading\" :class=\"cls.e('loading')\">加载中…</div>\n <div v-if=\"failed\" :class=\"cls.e('loading')\">图片加载失败</div>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { bem } from '@veltra/utils'\nimport { onBeforeUnmount, ref, shallowRef, useAttrs, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\nimport { toBlobUrl } from '../helper'\n\ndefineOptions({ name: 'FileViewerImagePreviewer', inheritAttrs: false })\n\nconst props = defineProps<{ file: FileViewerItem }>()\n\nconst emit = defineEmits<{ (e: 'error', err: unknown): void }>()\n\nconst cls = bem('file-viewer')\nconst attrs = useAttrs()\n\nconst url = shallowRef<string>('')\nconst loading = ref(true)\nconst failed = ref(false)\n\nlet revoke: (() => void) | undefined\n\nfunction load() {\n loading.value = true\n failed.value = false\n revoke?.()\n const r = toBlobUrl(props.file.src, props.file.mime)\n url.value = r.url\n revoke = r.revoke\n}\n\nfunction onImgError(e: Event) {\n loading.value = false\n failed.value = true\n emit('error', e)\n}\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nonBeforeUnmount(() => {\n revoke?.()\n url.value = ''\n})\n</script>\n"],"mappings":";;;;;;;;;;;;EAyBA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,cAAa;EAC7B,MAAM,QAAQ,UAAS;EAEvB,MAAM,MAAM,WAAmB,GAAE;EACjC,MAAM,UAAU,IAAI,KAAI;EACxB,MAAM,SAAS,IAAI,MAAK;EAExB,IAAI;EAEJ,SAAS,OAAO;AACd,WAAQ,QAAQ;AAChB,UAAO,QAAQ;AACf,aAAS;GACT,MAAM,IAAI,UAAU,MAAM,KAAK,KAAK,MAAM,KAAK,KAAI;AACnD,OAAI,QAAQ,EAAE;AACd,YAAS,EAAE;;EAGb,SAAS,WAAW,GAAU;AAC5B,WAAQ,QAAQ;AAChB,UAAO,QAAQ;AACf,QAAK,SAAS,EAAC;;AAGjB,cACQ,MAAM,YACN,MAAM,EACZ,EAAE,WAAW,MAAK,CACpB;AAEA,wBAAsB;AACpB,aAAS;AACT,OAAI,QAAQ;IACb;;uBA7DC,mBAYM,OAZN,WAYM,EAZA,OAAO,MAAA,IAAG,CAAC,EAAC,QAAA,EAAA,EAAmB,MAAA,MAAK,CAAA,EAAA;IAEhC,IAAA,SAAA,WAAA,EADR,mBAQE,OAAA;;KANC,KAAK,IAAA;KACL,KAAK,QAAA,KAAK;KACX,WAAU;KACT,aAAS,OAAA,OAAA,OAAA,KAAA,oBAAV,IAAkB,CAAA,UAAA,CAAA;KACjB,QAAI,OAAA,OAAA,OAAA,MAAA,WAAE,QAAA,QAAO;KACb,SAAO;;IAEC,QAAA,SAAA,WAAA,EAAX,mBAAwD,OAAA;;KAAnC,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,UAAA,CAAA;OAAa,QAAI,EAAA,IAAA,mBAAA,QAAA,KAAA;IACvC,OAAA,SAAA,WAAA,EAAX,mBAAyD,OAAA;;KAArC,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,UAAA,CAAA;OAAa,UAAM,EAAA,IAAA,mBAAA,QAAA,KAAA"}
@@ -1,4 +1,6 @@
1
1
  import { toBlobUrl } from "../helper.js";
2
+ import _sfc_main$1 from "./pdf-viewport-scroll.js";
3
+ import _sfc_main$2 from "./pdf-zoom-bridge.js";
2
4
  import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, mergeProps, normalizeClass, normalizeStyle, onBeforeUnmount, openBlock, shallowRef, unref, useAttrs, watch, withCtx } from "vue";
3
5
  import { bem } from "@veltra/utils";
4
6
  import { createPluginRegistration } from "@embedpdf/core";
@@ -8,14 +10,15 @@ import { DocumentContent, DocumentManagerPluginPackage } from "@embedpdf/plugin-
8
10
  import { RenderLayer, RenderPluginPackage } from "@embedpdf/plugin-render/vue";
9
11
  import { ScrollPluginPackage, Scroller } from "@embedpdf/plugin-scroll/vue";
10
12
  import { Viewport, ViewportPluginPackage } from "@embedpdf/plugin-viewport/vue";
13
+ import { ZoomGestureWrapper, ZoomMode, ZoomPluginPackage } from "@embedpdf/plugin-zoom/vue";
11
14
  //#region src/components/file-viewer/previewers/pdf-previewer.vue
12
15
  const _sfc_main = /* @__PURE__ */ defineComponent({
13
16
  name: "FileViewerPdfPreviewer",
14
17
  inheritAttrs: false,
15
18
  __name: "pdf-previewer",
16
19
  props: { file: {} },
17
- emits: ["error"],
18
- setup(__props, { emit: __emit }) {
20
+ emits: ["error", "zoom-change"],
21
+ setup(__props, { expose: __expose, emit: __emit }) {
19
22
  const props = __props;
20
23
  const emit = __emit;
21
24
  const cls = bem("file-viewer");
@@ -23,6 +26,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
23
26
  const { engine, isLoading, error } = usePdfiumEngine();
24
27
  const pdfUrl = shallowRef("");
25
28
  let revoke;
29
+ /** 当前文档的 zoom API(由 PdfZoomBridge 注入) */
30
+ let zoomScope = null;
26
31
  function load() {
27
32
  revoke?.();
28
33
  const r = toBlobUrl(props.file.src, props.file.mime ?? "application/pdf");
@@ -33,11 +38,30 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
33
38
  if (!pdfUrl.value) return [];
34
39
  return [
35
40
  createPluginRegistration(DocumentManagerPluginPackage, { initialDocuments: [{ url: pdfUrl.value }] }),
36
- createPluginRegistration(ViewportPluginPackage),
37
- createPluginRegistration(ScrollPluginPackage),
38
- createPluginRegistration(RenderPluginPackage)
41
+ createPluginRegistration(ViewportPluginPackage, { viewportGap: 0 }),
42
+ createPluginRegistration(ScrollPluginPackage, { defaultBufferSize: 2 }),
43
+ createPluginRegistration(RenderPluginPackage),
44
+ createPluginRegistration(ZoomPluginPackage, {
45
+ defaultZoomLevel: ZoomMode.FitPage,
46
+ minZoom: .5,
47
+ maxZoom: 3,
48
+ zoomStep: .1
49
+ })
39
50
  ];
40
51
  });
52
+ function onZoomChange(payload) {
53
+ zoomScope = payload.scope;
54
+ emit("zoom-change", payload.level);
55
+ }
56
+ function zoomIn() {
57
+ zoomScope?.zoomIn();
58
+ }
59
+ function zoomOut() {
60
+ zoomScope?.zoomOut();
61
+ }
62
+ function resetZoom() {
63
+ zoomScope?.requestZoom(ZoomMode.FitPage);
64
+ }
41
65
  watch(() => props.file, () => load(), { immediate: true });
42
66
  watch(error, (err) => {
43
67
  if (err) emit("error", err);
@@ -45,6 +69,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
45
69
  onBeforeUnmount(() => {
46
70
  revoke?.();
47
71
  pdfUrl.value = "";
72
+ zoomScope = null;
73
+ });
74
+ __expose({
75
+ zoomIn,
76
+ zoomOut,
77
+ resetZoom
48
78
  });
49
79
  return (_ctx, _cache) => {
50
80
  return openBlock(), createElementBlock("div", mergeProps({ class: unref(cls).e("pdf") }, unref(attrs)), [!unref(engine) || unref(isLoading) ? (openBlock(), createElementBlock("div", {
@@ -55,8 +85,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
55
85
  engine: unref(engine),
56
86
  plugins: plugins.value
57
87
  }, {
58
- default: withCtx(({ activeDocumentId }) => [activeDocumentId ? (openBlock(), createBlock(unref(DocumentContent), {
88
+ default: withCtx(({ activeDocumentId }) => [activeDocumentId ? (openBlock(), createBlock(_sfc_main$2, {
59
89
  key: 0,
90
+ "document-id": activeDocumentId,
91
+ onZoomChange
92
+ }, null, 8, ["document-id"])) : createCommentVNode("v-if", true), activeDocumentId ? (openBlock(), createBlock(unref(DocumentContent), {
93
+ key: 1,
60
94
  "document-id": activeDocumentId
61
95
  }, {
62
96
  default: withCtx(({ isLoaded }) => [isLoaded ? (openBlock(), createBlock(unref(Viewport), {
@@ -64,19 +98,28 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
64
98
  "document-id": activeDocumentId,
65
99
  class: normalizeClass(unref(cls).e("pdf-viewport"))
66
100
  }, {
67
- default: withCtx(() => [createVNode(unref(Scroller), { "document-id": activeDocumentId }, {
68
- default: withCtx(({ page }) => [createElementVNode("div", {
69
- class: normalizeClass(unref(cls).e("pdf-page")),
70
- style: normalizeStyle({
71
- width: page.width + "px",
72
- height: page.height + "px"
73
- })
74
- }, [createVNode(unref(RenderLayer), {
101
+ default: withCtx(() => [createVNode(_sfc_main$1, null, {
102
+ default: withCtx(() => [createVNode(unref(ZoomGestureWrapper), {
75
103
  "document-id": activeDocumentId,
76
- "page-index": page.pageIndex
77
- }, null, 8, ["document-id", "page-index"])], 6)]),
104
+ "enable-wheel": true
105
+ }, {
106
+ default: withCtx(() => [createVNode(unref(Scroller), { "document-id": activeDocumentId }, {
107
+ default: withCtx(({ page }) => [createElementVNode("div", {
108
+ class: normalizeClass(unref(cls).e("pdf-page")),
109
+ style: normalizeStyle({
110
+ width: page.width + "px",
111
+ height: page.height + "px"
112
+ })
113
+ }, [createVNode(unref(RenderLayer), {
114
+ "document-id": activeDocumentId,
115
+ "page-index": page.pageIndex
116
+ }, null, 8, ["document-id", "page-index"])], 6)]),
117
+ _: 2
118
+ }, 1032, ["document-id"])]),
119
+ _: 2
120
+ }, 1032, ["document-id"])]),
78
121
  _: 2
79
- }, 1032, ["document-id"])]),
122
+ }, 1024)]),
80
123
  _: 2
81
124
  }, 1032, ["document-id", "class"])) : createCommentVNode("v-if", true)]),
82
125
  _: 2
@@ -1 +1 @@
1
- {"version":3,"file":"pdf-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/pdf-previewer.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('pdf')\" v-bind=\"attrs\">\n <div v-if=\"!engine || isLoading\" :class=\"cls.e('loading')\">正在加载 PDF 引擎…</div>\n <EmbedPDF v-else-if=\"pdfUrl\" :engine=\"engine\" :plugins=\"plugins\" v-slot=\"{ activeDocumentId }\">\n <DocumentContent\n v-if=\"activeDocumentId\"\n :document-id=\"activeDocumentId\"\n v-slot=\"{ isLoaded }\"\n >\n <Viewport v-if=\"isLoaded\" :document-id=\"activeDocumentId\" :class=\"cls.e('pdf-viewport')\">\n <Scroller :document-id=\"activeDocumentId\">\n <template #default=\"{ page }\">\n <div\n :class=\"cls.e('pdf-page')\"\n :style=\"{ width: page.width + 'px', height: page.height + 'px' }\"\n >\n <RenderLayer :document-id=\"activeDocumentId\" :page-index=\"page.pageIndex\" />\n </div>\n </template>\n </Scroller>\n </Viewport>\n </DocumentContent>\n </EmbedPDF>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { createPluginRegistration } from '@embedpdf/core'\nimport { EmbedPDF } from '@embedpdf/core/vue'\nimport { usePdfiumEngine } from '@embedpdf/engines/vue'\nimport {\n DocumentContent,\n DocumentManagerPluginPackage\n} from '@embedpdf/plugin-document-manager/vue'\nimport { RenderLayer, RenderPluginPackage } from '@embedpdf/plugin-render/vue'\nimport { ScrollPluginPackage, Scroller } from '@embedpdf/plugin-scroll/vue'\nimport { ViewportPluginPackage, Viewport } from '@embedpdf/plugin-viewport/vue'\nimport { bem } from '@veltra/utils'\nimport { computed, onBeforeUnmount, shallowRef, useAttrs, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\nimport { toBlobUrl } from '../helper'\n\ndefineOptions({ name: 'FileViewerPdfPreviewer', inheritAttrs: false })\n\nconst props = defineProps<{ file: FileViewerItem }>()\n\nconst emit = defineEmits<{ (e: 'error', err: unknown): void }>()\n\nconst cls = bem('file-viewer')\nconst attrs = useAttrs()\n\nconst { engine, isLoading, error } = usePdfiumEngine()\n\nconst pdfUrl = shallowRef<string>('')\nlet revoke: (() => void) | undefined\n\nfunction load() {\n revoke?.()\n const r = toBlobUrl(props.file.src, props.file.mime ?? 'application/pdf')\n pdfUrl.value = r.url\n revoke = r.revoke\n}\n\nconst plugins = computed(() => {\n if (!pdfUrl.value) return []\n return [\n createPluginRegistration(DocumentManagerPluginPackage, {\n initialDocuments: [{ url: pdfUrl.value }]\n }),\n createPluginRegistration(ViewportPluginPackage),\n createPluginRegistration(ScrollPluginPackage),\n createPluginRegistration(RenderPluginPackage)\n ]\n})\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nwatch(error, (err) => {\n if (err) emit('error', err)\n})\n\nonBeforeUnmount(() => {\n revoke?.()\n pdfUrl.value = ''\n})\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;EA6CA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAEb,MAAM,MAAM,IAAI,cAAa;EAC7B,MAAM,QAAQ,UAAS;EAEvB,MAAM,EAAE,QAAQ,WAAW,UAAU,iBAAgB;EAErD,MAAM,SAAS,WAAmB,GAAE;EACpC,IAAI;EAEJ,SAAS,OAAO;AACd,aAAS;GACT,MAAM,IAAI,UAAU,MAAM,KAAK,KAAK,MAAM,KAAK,QAAQ,kBAAiB;AACxE,UAAO,QAAQ,EAAE;AACjB,YAAS,EAAE;;EAGb,MAAM,UAAU,eAAe;AAC7B,OAAI,CAAC,OAAO,MAAO,QAAO,EAAC;AAC3B,UAAO;IACL,yBAAyB,8BAA8B,EACrD,kBAAkB,CAAC,EAAE,KAAK,OAAO,OAAO,CAAA,EACzC,CAAC;IACF,yBAAyB,sBAAsB;IAC/C,yBAAyB,oBAAoB;IAC7C,yBAAyB,oBAAmB;IAC9C;IACD;AAED,cACQ,MAAM,YACN,MAAM,EACZ,EAAE,WAAW,MAAK,CACpB;AAEA,QAAM,QAAQ,QAAQ;AACpB,OAAI,IAAK,MAAK,SAAS,IAAG;IAC3B;AAED,wBAAsB;AACpB,aAAS;AACT,UAAO,QAAQ;IAChB;;uBAxFC,mBAsBM,OAtBN,WAsBM,EAtBA,OAAO,MAAA,IAAG,CAAC,EAAC,MAAA,EAAA,EAAiB,MAAA,MAAK,CAAA,EAAA,CAAA,CAC1B,MAAA,OAAM,IAAI,MAAA,UAAS,IAAA,WAAA,EAA/B,mBAA6E,OAAA;;IAA3C,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,UAAA,CAAA;MAAa,gBAAY,EAAA,IAClD,OAAA,SAAA,WAAA,EAArB,YAmBW,MAAA,SAAA,EAAA;;IAnBmB,QAAQ,MAAA,OAAM;IAAG,SAAS,QAAA;;sBAkBpC,EAlBuD,uBAAgB,CAEjF,oBAAA,WAAA,EADR,YAiBkB,MAAA,gBAAA,EAAA;;KAff,eAAa;;uBAcH,EAbD,eAAQ,CAEF,YAAA,WAAA,EAAhB,YAWW,MAAA,SAAA,EAAA;;MAXgB,eAAa;MAAmB,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,eAAA,CAAA;;6BAU1D,CATX,YASW,MAAA,SAAA,EAAA,EATA,eAAa,kBAAgB,EAAA;OAC3B,SAAO,SAMV,EANc,WAAI,CACxB,mBAKM,OAAA;QAJH,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,WAAA,CAAA;QACZ,OAAK,eAAA;SAAA,OAAW,KAAK,QAAK;SAAA,QAAiB,KAAK,SAAM;SAAA,CAAA;WAEvD,YAA4E,MAAA,YAAA,EAAA;QAA9D,eAAa;QAAmB,cAAY,KAAK"}
1
+ {"version":3,"file":"pdf-previewer.js","names":[],"sources":["../../../../src/components/file-viewer/previewers/pdf-previewer.vue"],"sourcesContent":["<template>\n <div :class=\"cls.e('pdf')\" v-bind=\"attrs\">\n <div v-if=\"!engine || isLoading\" :class=\"cls.e('loading')\">正在加载 PDF 引擎…</div>\n <EmbedPDF v-else-if=\"pdfUrl\" :engine=\"engine\" :plugins=\"plugins\" v-slot=\"{ activeDocumentId }\">\n <PdfZoomBridge\n v-if=\"activeDocumentId\"\n :document-id=\"activeDocumentId\"\n @zoom-change=\"onZoomChange\"\n />\n <DocumentContent\n v-if=\"activeDocumentId\"\n :document-id=\"activeDocumentId\"\n v-slot=\"{ isLoaded }\"\n >\n <Viewport v-if=\"isLoaded\" :document-id=\"activeDocumentId\" :class=\"cls.e('pdf-viewport')\">\n <PdfViewportScroll>\n <ZoomGestureWrapper :document-id=\"activeDocumentId\" :enable-wheel=\"true\">\n <Scroller :document-id=\"activeDocumentId\">\n <template #default=\"{ page }\">\n <div\n :class=\"cls.e('pdf-page')\"\n :style=\"{ width: page.width + 'px', height: page.height + 'px' }\"\n >\n <RenderLayer :document-id=\"activeDocumentId\" :page-index=\"page.pageIndex\" />\n </div>\n </template>\n </Scroller>\n </ZoomGestureWrapper>\n </PdfViewportScroll>\n </Viewport>\n </DocumentContent>\n </EmbedPDF>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { createPluginRegistration } from '@embedpdf/core'\nimport { EmbedPDF } from '@embedpdf/core/vue'\nimport { usePdfiumEngine } from '@embedpdf/engines/vue'\nimport {\n DocumentContent,\n DocumentManagerPluginPackage\n} from '@embedpdf/plugin-document-manager/vue'\nimport { RenderLayer, RenderPluginPackage } from '@embedpdf/plugin-render/vue'\nimport { ScrollPluginPackage, Scroller } from '@embedpdf/plugin-scroll/vue'\nimport { ViewportPluginPackage, Viewport } from '@embedpdf/plugin-viewport/vue'\nimport {\n ZoomGestureWrapper,\n ZoomMode,\n ZoomPluginPackage,\n type ZoomScope\n} from '@embedpdf/plugin-zoom/vue'\nimport { bem } from '@veltra/utils'\nimport { computed, onBeforeUnmount, shallowRef, useAttrs, watch } from 'vue'\n\nimport type { FileViewerItem } from '../../../types/file-viewer'\nimport { toBlobUrl } from '../helper'\nimport PdfViewportScroll from './pdf-viewport-scroll.vue'\nimport PdfZoomBridge from './pdf-zoom-bridge.vue'\n\ndefineOptions({ name: 'FileViewerPdfPreviewer', inheritAttrs: false })\n\nconst props = defineProps<{ file: FileViewerItem }>()\n\nconst emit = defineEmits<{\n (e: 'error', err: unknown): void\n (e: 'zoom-change', level: number): void\n}>()\n\nconst cls = bem('file-viewer')\nconst attrs = useAttrs()\n\nconst { engine, isLoading, error } = usePdfiumEngine()\n\nconst pdfUrl = shallowRef<string>('')\nlet revoke: (() => void) | undefined\n\n/** 当前文档的 zoom API(由 PdfZoomBridge 注入) */\nlet zoomScope: ZoomScope | null = null\n\nfunction load() {\n revoke?.()\n const r = toBlobUrl(props.file.src, props.file.mime ?? 'application/pdf')\n pdfUrl.value = r.url\n revoke = r.revoke\n}\n\nconst plugins = computed(() => {\n if (!pdfUrl.value) return []\n return [\n createPluginRegistration(DocumentManagerPluginPackage, {\n initialDocuments: [{ url: pdfUrl.value }]\n }),\n createPluginRegistration(ViewportPluginPackage, { viewportGap: 0 }),\n createPluginRegistration(ScrollPluginPackage, { defaultBufferSize: 2 }),\n createPluginRegistration(RenderPluginPackage),\n createPluginRegistration(ZoomPluginPackage, {\n defaultZoomLevel: ZoomMode.FitPage,\n minZoom: 0.5,\n maxZoom: 3,\n zoomStep: 0.1\n })\n ]\n})\n\nfunction onZoomChange(payload: { level: number; scope: ZoomScope | null }) {\n zoomScope = payload.scope\n emit('zoom-change', payload.level)\n}\n\nfunction zoomIn() {\n zoomScope?.zoomIn()\n}\n\nfunction zoomOut() {\n zoomScope?.zoomOut()\n}\n\nfunction resetZoom() {\n zoomScope?.requestZoom(ZoomMode.FitPage)\n}\n\nwatch(\n () => props.file,\n () => load(),\n { immediate: true }\n)\n\nwatch(error, (err) => {\n if (err) emit('error', err)\n})\n\nonBeforeUnmount(() => {\n revoke?.()\n pdfUrl.value = ''\n zoomScope = null\n})\n\ndefineExpose({\n zoomIn,\n zoomOut,\n resetZoom\n})\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EA8DA,MAAM,QAAQ;EAEd,MAAM,OAAO;EAKb,MAAM,MAAM,IAAI,cAAa;EAC7B,MAAM,QAAQ,UAAS;EAEvB,MAAM,EAAE,QAAQ,WAAW,UAAU,iBAAgB;EAErD,MAAM,SAAS,WAAmB,GAAE;EACpC,IAAI;;EAGJ,IAAI,YAA8B;EAElC,SAAS,OAAO;AACd,aAAS;GACT,MAAM,IAAI,UAAU,MAAM,KAAK,KAAK,MAAM,KAAK,QAAQ,kBAAiB;AACxE,UAAO,QAAQ,EAAE;AACjB,YAAS,EAAE;;EAGb,MAAM,UAAU,eAAe;AAC7B,OAAI,CAAC,OAAO,MAAO,QAAO,EAAC;AAC3B,UAAO;IACL,yBAAyB,8BAA8B,EACrD,kBAAkB,CAAC,EAAE,KAAK,OAAO,OAAO,CAAA,EACzC,CAAC;IACF,yBAAyB,uBAAuB,EAAE,aAAa,GAAG,CAAC;IACnE,yBAAyB,qBAAqB,EAAE,mBAAmB,GAAG,CAAC;IACvE,yBAAyB,oBAAoB;IAC7C,yBAAyB,mBAAmB;KAC1C,kBAAkB,SAAS;KAC3B,SAAS;KACT,SAAS;KACT,UAAU;KACX,CAAA;IACH;IACD;EAED,SAAS,aAAa,SAAqD;AACzE,eAAY,QAAQ;AACpB,QAAK,eAAe,QAAQ,MAAK;;EAGnC,SAAS,SAAS;AAChB,cAAW,QAAO;;EAGpB,SAAS,UAAU;AACjB,cAAW,SAAQ;;EAGrB,SAAS,YAAY;AACnB,cAAW,YAAY,SAAS,QAAO;;AAGzC,cACQ,MAAM,YACN,MAAM,EACZ,EAAE,WAAW,MAAK,CACpB;AAEA,QAAM,QAAQ,QAAQ;AACpB,OAAI,IAAK,MAAK,SAAS,IAAG;IAC3B;AAED,wBAAsB;AACpB,aAAS;AACT,UAAO,QAAQ;AACf,eAAY;IACb;AAED,WAAa;GACX;GACA;GACA;GACD,CAAA;;uBA7IC,mBA+BM,OA/BN,WA+BM,EA/BA,OAAO,MAAA,IAAG,CAAC,EAAC,MAAA,EAAA,EAAiB,MAAA,MAAK,CAAA,EAAA,CAAA,CAC1B,MAAA,OAAM,IAAI,MAAA,UAAS,IAAA,WAAA,EAA/B,mBAA6E,OAAA;;IAA3C,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,UAAA,CAAA;MAAa,gBAAY,EAAA,IAClD,OAAA,SAAA,WAAA,EAArB,YA4BW,MAAA,SAAA,EAAA;;IA5BmB,QAAQ,MAAA,OAAM;IAAG,SAAS,QAAA;;sBAKpD,EALuE,uBAAgB,CAEjF,oBAAA,WAAA,EADR,YAIE,aAAA;;KAFC,eAAa;KACA;sEAGR,oBAAA,WAAA,EADR,YAqBkB,MAAA,gBAAA,EAAA;;KAnBf,eAAa;;uBAkBH,EAjBD,eAAQ,CAEF,YAAA,WAAA,EAAhB,YAeW,MAAA,SAAA,EAAA;;MAfgB,eAAa;MAAmB,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,eAAA,CAAA;;6BAcjD,CAbpB,YAaoB,aAAA,MAAA;8BADG,CAXrB,YAWqB,MAAA,mBAAA,EAAA;QAXA,eAAa;QAAmB,gBAAc;;+BAUtD,CATX,YASW,MAAA,SAAA,EAAA,EATA,eAAa,kBAAgB,EAAA;SAC3B,SAAO,SAMV,EANc,WAAI,CACxB,mBAKM,OAAA;UAJH,OAAK,eAAE,MAAA,IAAG,CAAC,EAAC,WAAA,CAAA;UACZ,OAAK,eAAA;WAAA,OAAW,KAAK,QAAK;WAAA,QAAiB,KAAK,SAAM;WAAA,CAAA;aAEvD,YAA4E,MAAA,YAAA,EAAA;UAA9D,eAAa;UAAmB,cAAY,KAAK"}