@ibiz-template-plugin/ibiz-file-previewer 0.0.13 → 0.0.15

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.es.js CHANGED
@@ -18284,18 +18284,6 @@ const FilePreviewText = (props) => {
18284
18284
  }
18285
18285
  ) });
18286
18286
  };
18287
- const FilePreviewUnkown = (props) => {
18288
- const c2 = props.controller;
18289
- const fileType = c2.filePreviewShell.getState().fileType;
18290
- y$1(() => {
18291
- props.onInitialization();
18292
- }, []);
18293
- return /* @__PURE__ */ u("div", { className: "file-preview-unkown ".concat(c2.state.value.theme), children: /* @__PURE__ */ u("div", { children: [
18294
- "暂未支持",
18295
- fileType,
18296
- "类型预览"
18297
- ] }) });
18298
- };
18299
18287
  const Loading = ({ size = 24 }) => {
18300
18288
  return /* @__PURE__ */ u("div", { className: "loading-mask", children: /* @__PURE__ */ u("div", { className: "loading-spinner", children: /* @__PURE__ */ u(LoaddingSvg, { size }) }) });
18301
18289
  };
@@ -18332,7 +18320,7 @@ const ThumbnailPanel = (props) => {
18332
18320
  };
18333
18321
  const throttleUpdateRange = throttle(() => {
18334
18322
  updateVisibleRange();
18335
- }, 200);
18323
+ }, 500);
18336
18324
  const handleClick = (index, _event) => {
18337
18325
  props.onPageClick(index);
18338
18326
  };
@@ -18449,14 +18437,10 @@ const ThumbnailPanel = (props) => {
18449
18437
  const ImagePage = (props) => {
18450
18438
  const isLoading = useSignal(true);
18451
18439
  const imgRef = A(null);
18452
- const [parentDimensions, setParentDimensions] = d$2({
18453
- width: 0,
18454
- height: 0
18455
- });
18456
- const prevDimensions = A({ width: 0, height: 0 });
18440
+ const elementHeight = useSignal(0);
18457
18441
  const imgStyle = useComputed(() => {
18458
18442
  let result = {};
18459
- const { width, height } = parentDimensions;
18443
+ const { width, height } = props.parentDimensions;
18460
18444
  if (isLoading.value) {
18461
18445
  result = {
18462
18446
  height: "".concat(height * props.state.value.scale, "px"),
@@ -18490,33 +18474,25 @@ const ImagePage = (props) => {
18490
18474
  console.error("图片加载失败:", error2);
18491
18475
  isLoading.value = false;
18492
18476
  };
18493
- const updateParentStyle = () => {
18494
- var _a, _b;
18495
- const rect = (_b = (_a = imgRef.current) == null ? void 0 : _a.parentElement) == null ? void 0 : _b.getBoundingClientRect();
18496
- if (!rect) return;
18497
- const newWidth = Math.round(rect.width);
18498
- const newHeight = Math.round(rect.height);
18499
- if (prevDimensions.current.width !== newWidth || prevDimensions.current.height !== newHeight) {
18500
- prevDimensions.current = { width: newWidth, height: newHeight };
18501
- setParentDimensions({ width: newWidth, height: newHeight });
18502
- }
18477
+ const handleHeightChange = (newHeight) => {
18478
+ var _a;
18479
+ elementHeight.value = newHeight;
18480
+ (_a = props.onHeightChange) == null ? void 0 : _a.call(props, props.index, newHeight);
18503
18481
  };
18504
18482
  y$1(() => {
18505
- updateParentStyle();
18506
- const observer = new ResizeObserver(() => {
18507
- requestAnimationFrame(() => {
18508
- updateParentStyle();
18509
- });
18510
- });
18511
- if (imgRef.current) {
18512
- if (imgRef.current.parentElement) {
18513
- observer.observe(imgRef.current.parentElement);
18483
+ if (!imgRef.current) return;
18484
+ const resizeObserver = new ResizeObserver((entries) => {
18485
+ for (const entry of entries) {
18486
+ const contentRect = entry.contentRect;
18487
+ const newHeight = contentRect.height;
18488
+ handleHeightChange(newHeight);
18514
18489
  }
18515
- }
18490
+ });
18491
+ resizeObserver.observe(imgRef.current);
18516
18492
  return () => {
18517
- observer.disconnect();
18493
+ resizeObserver.disconnect();
18518
18494
  };
18519
- }, []);
18495
+ }, [props.index]);
18520
18496
  return /* @__PURE__ */ u(
18521
18497
  "div",
18522
18498
  {
@@ -18525,7 +18501,7 @@ const ImagePage = (props) => {
18525
18501
  style: imgStyle.value,
18526
18502
  "data-page-index": props.index,
18527
18503
  children: [
18528
- props.isShowImage ? /* @__PURE__ */ u(
18504
+ /* @__PURE__ */ u(
18529
18505
  "img",
18530
18506
  {
18531
18507
  className: "image-content",
@@ -18539,7 +18515,7 @@ const ImagePage = (props) => {
18539
18515
  },
18540
18516
  loading: "lazy"
18541
18517
  }
18542
- ) : /* @__PURE__ */ u(Loading, {}),
18518
+ ),
18543
18519
  isLoading.value && /* @__PURE__ */ u(Loading, {})
18544
18520
  ]
18545
18521
  }
@@ -18550,40 +18526,128 @@ const FilePreviewImageGroup = (props) => {
18550
18526
  const state = controller.state;
18551
18527
  const contentRef = A(null);
18552
18528
  const isScrolling = useSignal(false);
18553
- const computeClosestPage = () => {
18554
- if (contentRef.current) {
18555
- const containerRect = contentRef.current.getBoundingClientRect();
18556
- let closestPage = state.value.currentPage;
18557
- let minDistance = Infinity;
18558
- const checkRangeStart = Math.max(0, closestPage - 200);
18559
- const checkRangeEnd = Math.min(
18560
- state.value.items.length - 1,
18561
- closestPage + 200
18562
- );
18563
- for (let index = checkRangeStart; index <= checkRangeEnd; index++) {
18564
- const pageElement = contentRef.current.querySelector(
18565
- '[data-page-index="'.concat(index, '"]')
18566
- );
18567
- if (pageElement) {
18568
- const rect = pageElement.getBoundingClientRect();
18569
- const distance = Math.abs(rect.top - containerRect.top);
18570
- if (distance < minDistance) {
18571
- minDistance = distance;
18572
- closestPage = index;
18573
- }
18529
+ const [parentDimensions, setParentDimensions] = d$2({
18530
+ width: 0,
18531
+ height: 0
18532
+ });
18533
+ const prevDimensions = A({ width: 0, height: 0 });
18534
+ const itemPositions = useSignal([]);
18535
+ const estimateHeight = useSignal(0);
18536
+ const phantomHeight = useSignal(0);
18537
+ const startOffset = useSignal(0);
18538
+ const visibleInfo = useSignal({
18539
+ startIndex: 0,
18540
+ // 起始索引
18541
+ count: 1,
18542
+ // 显示数量
18543
+ buffer: 1
18544
+ // 缓冲区域子项个数
18545
+ });
18546
+ const visibleData = useComputed(() => {
18547
+ const start = Math.max(0, visibleInfo.value.startIndex);
18548
+ const end = Math.min(
18549
+ state.value.items.length - 1,
18550
+ visibleInfo.value.startIndex + visibleInfo.value.count + visibleInfo.value.buffer
18551
+ );
18552
+ return state.value.items.slice(start, end + 1);
18553
+ });
18554
+ const preloadImages = () => {
18555
+ const preloadPages = state.value.items.slice(0, 2);
18556
+ preloadPages.forEach((page) => {
18557
+ if (page) {
18558
+ const img = new Image();
18559
+ img.src = "".concat(imgBasePath).concat(page.image_url);
18560
+ }
18561
+ });
18562
+ };
18563
+ const initPhantomHeight = () => {
18564
+ var _a;
18565
+ const rect = (_a = contentRef.current) == null ? void 0 : _a.getBoundingClientRect();
18566
+ if (!rect) return;
18567
+ const newHeight = Math.round(rect.height);
18568
+ estimateHeight.value = newHeight;
18569
+ phantomHeight.value = newHeight * state.value.items.length;
18570
+ };
18571
+ const initItemPositions = () => {
18572
+ itemPositions.value = state.value.items.map((_item, index) => {
18573
+ return {
18574
+ index,
18575
+ top: index * estimateHeight.value,
18576
+ bottom: (index + 1) * estimateHeight.value,
18577
+ height: estimateHeight.value
18578
+ };
18579
+ });
18580
+ };
18581
+ const updateParentStyle = () => {
18582
+ var _a;
18583
+ const rect = (_a = contentRef.current) == null ? void 0 : _a.getBoundingClientRect();
18584
+ if (!rect) return;
18585
+ const newWidth = Math.round(rect.width);
18586
+ const newHeight = Math.round(rect.height);
18587
+ if (prevDimensions.current.width !== newWidth || prevDimensions.current.height !== newHeight) {
18588
+ prevDimensions.current = { width: newWidth, height: newHeight };
18589
+ setParentDimensions({ width: newWidth, height: newHeight });
18590
+ }
18591
+ };
18592
+ const getStartIndex = (scrollTop) => {
18593
+ let start = 0;
18594
+ let end = state.value.items.length - 1;
18595
+ let tempIndex = null;
18596
+ while (start <= end) {
18597
+ const midIndex = parseInt(String((end + start) / 2));
18598
+ const midBottom = itemPositions.value[midIndex].bottom;
18599
+ if (midBottom === scrollTop) {
18600
+ tempIndex = midIndex + 1;
18601
+ return tempIndex;
18602
+ }
18603
+ if (midBottom < scrollTop) {
18604
+ start = midIndex + 1;
18605
+ } else if (midBottom > scrollTop) {
18606
+ if (tempIndex === null || tempIndex > midIndex) {
18607
+ tempIndex = midIndex;
18574
18608
  }
18609
+ end -= 1;
18575
18610
  }
18576
- return closestPage;
18577
18611
  }
18612
+ return tempIndex;
18613
+ };
18614
+ const getOffsetY = () => {
18615
+ const realStart = visibleInfo.value.startIndex;
18616
+ if (realStart) {
18617
+ return itemPositions.value[realStart].top;
18618
+ }
18619
+ return 0;
18620
+ };
18621
+ const updateVisualSize = (id, curHeight) => {
18622
+ if (curHeight === 0) return;
18623
+ const oldHeight = itemPositions.value[id].height;
18624
+ const dValue = curHeight - oldHeight;
18625
+ if (dValue) {
18626
+ itemPositions.value[id].height = curHeight;
18627
+ itemPositions.value[id].bottom = itemPositions.value[id].bottom + dValue;
18628
+ for (let index = id + 1; index < itemPositions.value.length; index++) {
18629
+ itemPositions.value[index].top = itemPositions.value[index].top + dValue;
18630
+ itemPositions.value[index].bottom = itemPositions.value[index].bottom + dValue;
18631
+ }
18632
+ }
18633
+ };
18634
+ const computeClosestPage = () => {
18635
+ if (!contentRef.current) return;
18636
+ const scrollTop = contentRef.current.scrollTop;
18637
+ const closestPage = getStartIndex(scrollTop);
18638
+ return closestPage;
18578
18639
  };
18579
18640
  const handleScroll = throttle(() => {
18580
18641
  if (contentRef.current) {
18581
18642
  const closestPage = computeClosestPage();
18582
- if (!isScrolling.value && closestPage !== state.value.currentPage) {
18643
+ if (closestPage === void 0) return;
18644
+ visibleInfo.value.startIndex = closestPage;
18645
+ startOffset.value = getOffsetY();
18646
+ if (closestPage !== state.value.currentPage) {
18583
18647
  controller.updateState({ currentPage: closestPage });
18584
18648
  }
18585
18649
  }
18586
- }, 200);
18650
+ }, 500);
18587
18651
  const handleImageResize = () => {
18588
18652
  if (contentRef.current) {
18589
18653
  setTimeout(() => {
@@ -18595,76 +18659,19 @@ const FilePreviewImageGroup = (props) => {
18595
18659
  }
18596
18660
  };
18597
18661
  const scrollToPage = (pageIndex) => {
18598
- if (contentRef.current) {
18599
- const pageElement = contentRef.current.querySelector(
18600
- '[data-page-index="'.concat(pageIndex, '"]')
18601
- );
18602
- if (pageElement) {
18603
- pageElement.scrollIntoView({ behavior: "smooth", block: "start" });
18604
- }
18605
- }
18606
- };
18607
- const preloadImages = () => {
18608
- const preloadPages = state.value.items.slice(0, 2);
18609
- preloadPages.forEach((page) => {
18610
- if (page) {
18611
- const img = new Image();
18612
- img.src = "".concat(imgBasePath).concat(page.image_url);
18613
- }
18614
- });
18615
- };
18616
- let updateIsScrollingTimer;
18617
- const updateIsScrolling = () => {
18618
18662
  isScrolling.value = true;
18619
- if (updateIsScrollingTimer) {
18620
- clearTimeout(updateIsScrollingTimer);
18663
+ visibleInfo.value.startIndex = pageIndex;
18664
+ startOffset.value = getOffsetY();
18665
+ if (contentRef.current) {
18666
+ contentRef.current.scrollTop = startOffset.value;
18621
18667
  }
18622
- updateIsScrollingTimer = setTimeout(() => {
18668
+ setTimeout(() => {
18623
18669
  isScrolling.value = false;
18624
- }, 1e3);
18625
- };
18626
- const MAX_ATTEMPTS = 30;
18627
- const STABLE_THRESHOLD = 2;
18628
- let requestAnimationFrameId;
18629
- const scrollToPageWhenStable = (pageIndex) => {
18630
- let lastTop = null;
18631
- let stableCount = 0;
18632
- let attempt = 0;
18633
- const tryScroll = () => {
18634
- const container = contentRef.current;
18635
- if (!container) return;
18636
- const pageElement = container.querySelector(
18637
- '[data-page-index="'.concat(pageIndex, '"]')
18638
- );
18639
- if (!pageElement) return;
18640
- const rect = pageElement.getBoundingClientRect();
18641
- if (rect.height > 0) {
18642
- if (lastTop !== null && Math.abs(rect.top - lastTop) < 1) {
18643
- stableCount++;
18644
- } else {
18645
- stableCount = 0;
18646
- }
18647
- lastTop = rect.top;
18648
- if (stableCount >= STABLE_THRESHOLD) {
18649
- scrollToPage(pageIndex);
18650
- updateIsScrolling();
18651
- return;
18652
- }
18653
- }
18654
- attempt++;
18655
- if (attempt < MAX_ATTEMPTS) {
18656
- requestAnimationFrameId = requestAnimationFrame(tryScroll);
18657
- } else {
18658
- scrollToPage(pageIndex);
18659
- updateIsScrolling();
18660
- }
18661
- };
18662
- requestAnimationFrameId = requestAnimationFrame(tryScroll);
18670
+ }, 0);
18663
18671
  };
18664
18672
  const handlePageClick = (pageIndex) => {
18665
18673
  controller.updateState({ currentPage: pageIndex });
18666
- updateIsScrolling();
18667
- scrollToPageWhenStable(pageIndex);
18674
+ scrollToPage(pageIndex);
18668
18675
  };
18669
18676
  const handleInput = (e2) => {
18670
18677
  const target = e2.target;
@@ -18695,20 +18702,23 @@ const FilePreviewImageGroup = (props) => {
18695
18702
  scrollToPage(state.value.currentPage);
18696
18703
  };
18697
18704
  y$1(() => {
18698
- if (contentRef.current) {
18699
- contentRef.current.addEventListener("scroll", handleScroll);
18700
- }
18701
18705
  preloadImages();
18702
18706
  props.onInitialization();
18703
- return () => {
18704
- var _a;
18705
- (_a = contentRef.current) == null ? void 0 : _a.removeEventListener("scroll", handleScroll);
18706
- if (updateIsScrollingTimer) {
18707
- clearTimeout(updateIsScrollingTimer);
18708
- }
18709
- if (requestAnimationFrameId) {
18710
- cancelAnimationFrame(requestAnimationFrameId);
18707
+ initPhantomHeight();
18708
+ initItemPositions();
18709
+ updateParentStyle();
18710
+ const observer = new ResizeObserver(() => {
18711
+ requestAnimationFrame(() => {
18712
+ updateParentStyle();
18713
+ });
18714
+ });
18715
+ if (contentRef.current) {
18716
+ if (contentRef) {
18717
+ observer.observe(contentRef.current);
18711
18718
  }
18719
+ }
18720
+ return () => {
18721
+ observer.disconnect();
18712
18722
  };
18713
18723
  }, []);
18714
18724
  return /* @__PURE__ */ u("div", { className: "file-preview-image-group", children: [
@@ -18734,33 +18744,43 @@ const FilePreviewImageGroup = (props) => {
18734
18744
  ref: contentRef,
18735
18745
  className: "image-group-main-container",
18736
18746
  onScroll: () => {
18737
- handleScroll();
18738
- },
18739
- children: state.value.items && state.value.items.length > 0 && state.value.items.map((page, index) => {
18740
- const bufferRange = 3;
18741
- const startRange = Math.max(
18742
- 0,
18743
- state.value.currentPage - bufferRange
18744
- );
18745
- const endRange = Math.min(
18746
- state.value.items.length - 1,
18747
- state.value.currentPage + bufferRange
18748
- );
18749
- const shouldRender = index >= startRange && index <= endRange;
18750
- if (!shouldRender) {
18751
- return null;
18747
+ if (!isScrolling.value) {
18748
+ handleScroll();
18752
18749
  }
18753
- return /* @__PURE__ */ u(
18754
- ImagePage,
18750
+ },
18751
+ children: [
18752
+ /* @__PURE__ */ u(
18753
+ "div",
18755
18754
  {
18756
- page,
18757
- index,
18758
- state,
18759
- isShowImage: true
18760
- },
18761
- page.image_url
18762
- );
18763
- })
18755
+ class: "image-group-main-phantom",
18756
+ style: { height: "".concat(phantomHeight.value, "px") }
18757
+ }
18758
+ ),
18759
+ /* @__PURE__ */ u(
18760
+ "div",
18761
+ {
18762
+ className: "image-group-item-container",
18763
+ style: {
18764
+ transform: "translate3d(0,".concat(startOffset.value, "px,0)")
18765
+ },
18766
+ children: visibleData.value && visibleData.value.length > 0 && visibleData.value.map((page) => {
18767
+ return /* @__PURE__ */ u(
18768
+ ImagePage,
18769
+ {
18770
+ page,
18771
+ index: page.index,
18772
+ state,
18773
+ parentDimensions,
18774
+ onHeightChange: (index, height) => {
18775
+ updateVisualSize(index, height);
18776
+ }
18777
+ },
18778
+ page.image_url
18779
+ );
18780
+ })
18781
+ }
18782
+ )
18783
+ ]
18764
18784
  }
18765
18785
  ),
18766
18786
  /* @__PURE__ */ u(Teleport, { to: "#custom-controls", children: /* @__PURE__ */ u("div", { className: "image-toolbar-container", children: [
@@ -18999,7 +19019,7 @@ const FilePreviewShell = (props) => {
18999
19019
  ] })
19000
19020
  ] }),
19001
19021
  showDownloadMenu.value && /* @__PURE__ */ u("div", { className: "download-options", children: [
19002
- /* @__PURE__ */ u(
19022
+ state.value.fileContent === "" && /* @__PURE__ */ u(
19003
19023
  "button",
19004
19024
  {
19005
19025
  className: "download-option",
@@ -19009,7 +19029,7 @@ const FilePreviewShell = (props) => {
19009
19029
  children: "下载原文件"
19010
19030
  }
19011
19031
  ),
19012
- state.value.engineType !== EngineType.PDF && state.value.engineType !== EngineType.UNKNOWN && /* @__PURE__ */ u(
19032
+ state.value.engineType !== EngineType.PDF && /* @__PURE__ */ u(
19013
19033
  "button",
19014
19034
  {
19015
19035
  className: "download-option",
@@ -19991,8 +20011,11 @@ class FilePreviewTextController extends FilePreviewItemController {
19991
20011
  */
19992
20012
  async getContent() {
19993
20013
  const options = this.filePreviewShell.getOptions();
19994
- const { fileId, fileType, fileCat } = this.filePreviewShell.getState();
20014
+ const { fileId, fileType, fileCat, fileContent } = this.filePreviewShell.getState();
19995
20015
  try {
20016
+ if (fileContent) {
20017
+ return fileContent;
20018
+ }
19996
20019
  const content = await options.getContent(fileId, fileType, fileCat);
19997
20020
  return content || "";
19998
20021
  } catch (error2) {
@@ -20096,9 +20119,14 @@ class FilePreviewItemDispatcher {
20096
20119
  );
20097
20120
  this.registerItem(
20098
20121
  EngineType.UNKNOWN,
20099
- FilePreviewUnkown,
20122
+ // 未识别类型统一识别为md格式
20123
+ // FilePreviewUnkown as PreviewItemComponent,
20124
+ // (filePreviewShell: IFilePreviewShellController) => {
20125
+ // return new FilePreviewItemController(filePreviewShell);
20126
+ // },
20127
+ FilePreviewMD,
20100
20128
  (filePreviewShell) => {
20101
- return new FilePreviewItemController(filePreviewShell);
20129
+ return new FilePreviewMDController(filePreviewShell);
20102
20130
  }
20103
20131
  );
20104
20132
  }
@@ -20141,6 +20169,7 @@ class FilePreviewShellController {
20141
20169
  fileName: "",
20142
20170
  fileId: "",
20143
20171
  fileCat: "",
20172
+ fileContent: "",
20144
20173
  theme: "dark",
20145
20174
  isLoading: false,
20146
20175
  isCreated: false,
@@ -20169,7 +20198,11 @@ class FilePreviewShellController {
20169
20198
  let fileId = "";
20170
20199
  let fileName = "";
20171
20200
  let fileCat = "";
20172
- if (data.url) {
20201
+ let fileContent = "";
20202
+ if (data.content) {
20203
+ fileName = data.name || "";
20204
+ fileContent = data.content;
20205
+ } else if (data.url) {
20173
20206
  const result = await this.options.upLoadFileToOss(data.url);
20174
20207
  if (result) {
20175
20208
  const { id, name, cat } = result;
@@ -20183,7 +20216,7 @@ class FilePreviewShellController {
20183
20216
  if (data.id) fileId = data.id;
20184
20217
  }
20185
20218
  const fileType = fileNameToFileType(fileName);
20186
- this.updateState({ fileId, fileName, fileCat, fileType });
20219
+ this.updateState({ fileId, fileName, fileCat, fileType, fileContent });
20187
20220
  await this.parseEngineType();
20188
20221
  }
20189
20222
  /**
@@ -20283,8 +20316,15 @@ class FilePreviewShellController {
20283
20316
  async copyTextContent(_event) {
20284
20317
  if (!this.options.getContent) return;
20285
20318
  await navigator.clipboard.writeText("");
20286
- const { fileId, fileType, fileCat } = this.state.value;
20287
- const content = await this.options.getContent(fileId, fileType, fileCat);
20319
+ const { fileId, fileType, fileCat, fileContent } = this.state.value;
20320
+ let content = fileContent;
20321
+ if (content === "") {
20322
+ content = await this.options.getContent(
20323
+ fileId,
20324
+ fileType,
20325
+ fileCat
20326
+ );
20327
+ }
20288
20328
  if (content) {
20289
20329
  await navigator.clipboard.writeText(content);
20290
20330
  }