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

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
@@ -18332,7 +18332,7 @@ const ThumbnailPanel = (props) => {
18332
18332
  };
18333
18333
  const throttleUpdateRange = throttle(() => {
18334
18334
  updateVisibleRange();
18335
- }, 200);
18335
+ }, 500);
18336
18336
  const handleClick = (index, _event) => {
18337
18337
  props.onPageClick(index);
18338
18338
  };
@@ -18449,14 +18449,10 @@ const ThumbnailPanel = (props) => {
18449
18449
  const ImagePage = (props) => {
18450
18450
  const isLoading = useSignal(true);
18451
18451
  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 });
18452
+ const elementHeight = useSignal(0);
18457
18453
  const imgStyle = useComputed(() => {
18458
18454
  let result = {};
18459
- const { width, height } = parentDimensions;
18455
+ const { width, height } = props.parentDimensions;
18460
18456
  if (isLoading.value) {
18461
18457
  result = {
18462
18458
  height: "".concat(height * props.state.value.scale, "px"),
@@ -18490,33 +18486,25 @@ const ImagePage = (props) => {
18490
18486
  console.error("图片加载失败:", error2);
18491
18487
  isLoading.value = false;
18492
18488
  };
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
- }
18489
+ const handleHeightChange = (newHeight) => {
18490
+ var _a;
18491
+ elementHeight.value = newHeight;
18492
+ (_a = props.onHeightChange) == null ? void 0 : _a.call(props, props.index, newHeight);
18503
18493
  };
18504
18494
  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);
18495
+ if (!imgRef.current) return;
18496
+ const resizeObserver = new ResizeObserver((entries) => {
18497
+ for (const entry of entries) {
18498
+ const contentRect = entry.contentRect;
18499
+ const newHeight = contentRect.height;
18500
+ handleHeightChange(newHeight);
18514
18501
  }
18515
- }
18502
+ });
18503
+ resizeObserver.observe(imgRef.current);
18516
18504
  return () => {
18517
- observer.disconnect();
18505
+ resizeObserver.disconnect();
18518
18506
  };
18519
- }, []);
18507
+ }, [props.index]);
18520
18508
  return /* @__PURE__ */ u(
18521
18509
  "div",
18522
18510
  {
@@ -18525,7 +18513,7 @@ const ImagePage = (props) => {
18525
18513
  style: imgStyle.value,
18526
18514
  "data-page-index": props.index,
18527
18515
  children: [
18528
- props.isShowImage ? /* @__PURE__ */ u(
18516
+ /* @__PURE__ */ u(
18529
18517
  "img",
18530
18518
  {
18531
18519
  className: "image-content",
@@ -18539,7 +18527,7 @@ const ImagePage = (props) => {
18539
18527
  },
18540
18528
  loading: "lazy"
18541
18529
  }
18542
- ) : /* @__PURE__ */ u(Loading, {}),
18530
+ ),
18543
18531
  isLoading.value && /* @__PURE__ */ u(Loading, {})
18544
18532
  ]
18545
18533
  }
@@ -18550,40 +18538,128 @@ const FilePreviewImageGroup = (props) => {
18550
18538
  const state = controller.state;
18551
18539
  const contentRef = A(null);
18552
18540
  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
- }
18541
+ const [parentDimensions, setParentDimensions] = d$2({
18542
+ width: 0,
18543
+ height: 0
18544
+ });
18545
+ const prevDimensions = A({ width: 0, height: 0 });
18546
+ const itemPositions = useSignal([]);
18547
+ const estimateHeight = useSignal(0);
18548
+ const phantomHeight = useSignal(0);
18549
+ const startOffset = useSignal(0);
18550
+ const visibleInfo = useSignal({
18551
+ startIndex: 0,
18552
+ // 起始索引
18553
+ count: 1,
18554
+ // 显示数量
18555
+ buffer: 1
18556
+ // 缓冲区域子项个数
18557
+ });
18558
+ const visibleData = useComputed(() => {
18559
+ const start = Math.max(0, visibleInfo.value.startIndex);
18560
+ const end = Math.min(
18561
+ state.value.items.length - 1,
18562
+ visibleInfo.value.startIndex + visibleInfo.value.count + visibleInfo.value.buffer
18563
+ );
18564
+ return state.value.items.slice(start, end + 1);
18565
+ });
18566
+ const preloadImages = () => {
18567
+ const preloadPages = state.value.items.slice(0, 2);
18568
+ preloadPages.forEach((page) => {
18569
+ if (page) {
18570
+ const img = new Image();
18571
+ img.src = "".concat(imgBasePath).concat(page.image_url);
18572
+ }
18573
+ });
18574
+ };
18575
+ const initPhantomHeight = () => {
18576
+ var _a;
18577
+ const rect = (_a = contentRef.current) == null ? void 0 : _a.getBoundingClientRect();
18578
+ if (!rect) return;
18579
+ const newHeight = Math.round(rect.height);
18580
+ estimateHeight.value = newHeight;
18581
+ phantomHeight.value = newHeight * state.value.items.length;
18582
+ };
18583
+ const initItemPositions = () => {
18584
+ itemPositions.value = state.value.items.map((_item, index) => {
18585
+ return {
18586
+ index,
18587
+ top: index * estimateHeight.value,
18588
+ bottom: (index + 1) * estimateHeight.value,
18589
+ height: estimateHeight.value
18590
+ };
18591
+ });
18592
+ };
18593
+ const updateParentStyle = () => {
18594
+ var _a;
18595
+ const rect = (_a = contentRef.current) == null ? void 0 : _a.getBoundingClientRect();
18596
+ if (!rect) return;
18597
+ const newWidth = Math.round(rect.width);
18598
+ const newHeight = Math.round(rect.height);
18599
+ if (prevDimensions.current.width !== newWidth || prevDimensions.current.height !== newHeight) {
18600
+ prevDimensions.current = { width: newWidth, height: newHeight };
18601
+ setParentDimensions({ width: newWidth, height: newHeight });
18602
+ }
18603
+ };
18604
+ const getStartIndex = (scrollTop) => {
18605
+ let start = 0;
18606
+ let end = state.value.items.length - 1;
18607
+ let tempIndex = null;
18608
+ while (start <= end) {
18609
+ const midIndex = parseInt(String((end + start) / 2));
18610
+ const midBottom = itemPositions.value[midIndex].bottom;
18611
+ if (midBottom === scrollTop) {
18612
+ tempIndex = midIndex + 1;
18613
+ return tempIndex;
18614
+ }
18615
+ if (midBottom < scrollTop) {
18616
+ start = midIndex + 1;
18617
+ } else if (midBottom > scrollTop) {
18618
+ if (tempIndex === null || tempIndex > midIndex) {
18619
+ tempIndex = midIndex;
18574
18620
  }
18621
+ end -= 1;
18575
18622
  }
18576
- return closestPage;
18577
18623
  }
18624
+ return tempIndex;
18625
+ };
18626
+ const getOffsetY = () => {
18627
+ const realStart = visibleInfo.value.startIndex;
18628
+ if (realStart) {
18629
+ return itemPositions.value[realStart].top;
18630
+ }
18631
+ return 0;
18632
+ };
18633
+ const updateVisualSize = (id, curHeight) => {
18634
+ if (curHeight === 0) return;
18635
+ const oldHeight = itemPositions.value[id].height;
18636
+ const dValue = curHeight - oldHeight;
18637
+ if (dValue) {
18638
+ itemPositions.value[id].height = curHeight;
18639
+ itemPositions.value[id].bottom = itemPositions.value[id].bottom + dValue;
18640
+ for (let index = id + 1; index < itemPositions.value.length; index++) {
18641
+ itemPositions.value[index].top = itemPositions.value[index].top + dValue;
18642
+ itemPositions.value[index].bottom = itemPositions.value[index].bottom + dValue;
18643
+ }
18644
+ }
18645
+ };
18646
+ const computeClosestPage = () => {
18647
+ if (!contentRef.current) return;
18648
+ const scrollTop = contentRef.current.scrollTop;
18649
+ const closestPage = getStartIndex(scrollTop);
18650
+ return closestPage;
18578
18651
  };
18579
18652
  const handleScroll = throttle(() => {
18580
18653
  if (contentRef.current) {
18581
18654
  const closestPage = computeClosestPage();
18582
- if (!isScrolling.value && closestPage !== state.value.currentPage) {
18655
+ if (closestPage === void 0) return;
18656
+ visibleInfo.value.startIndex = closestPage;
18657
+ startOffset.value = getOffsetY();
18658
+ if (closestPage !== state.value.currentPage) {
18583
18659
  controller.updateState({ currentPage: closestPage });
18584
18660
  }
18585
18661
  }
18586
- }, 200);
18662
+ }, 500);
18587
18663
  const handleImageResize = () => {
18588
18664
  if (contentRef.current) {
18589
18665
  setTimeout(() => {
@@ -18595,76 +18671,19 @@ const FilePreviewImageGroup = (props) => {
18595
18671
  }
18596
18672
  };
18597
18673
  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
18674
  isScrolling.value = true;
18619
- if (updateIsScrollingTimer) {
18620
- clearTimeout(updateIsScrollingTimer);
18675
+ visibleInfo.value.startIndex = pageIndex;
18676
+ startOffset.value = getOffsetY();
18677
+ if (contentRef.current) {
18678
+ contentRef.current.scrollTop = startOffset.value;
18621
18679
  }
18622
- updateIsScrollingTimer = setTimeout(() => {
18680
+ setTimeout(() => {
18623
18681
  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);
18682
+ }, 0);
18663
18683
  };
18664
18684
  const handlePageClick = (pageIndex) => {
18665
18685
  controller.updateState({ currentPage: pageIndex });
18666
- updateIsScrolling();
18667
- scrollToPageWhenStable(pageIndex);
18686
+ scrollToPage(pageIndex);
18668
18687
  };
18669
18688
  const handleInput = (e2) => {
18670
18689
  const target = e2.target;
@@ -18695,20 +18714,23 @@ const FilePreviewImageGroup = (props) => {
18695
18714
  scrollToPage(state.value.currentPage);
18696
18715
  };
18697
18716
  y$1(() => {
18698
- if (contentRef.current) {
18699
- contentRef.current.addEventListener("scroll", handleScroll);
18700
- }
18701
18717
  preloadImages();
18702
18718
  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);
18719
+ initPhantomHeight();
18720
+ initItemPositions();
18721
+ updateParentStyle();
18722
+ const observer = new ResizeObserver(() => {
18723
+ requestAnimationFrame(() => {
18724
+ updateParentStyle();
18725
+ });
18726
+ });
18727
+ if (contentRef.current) {
18728
+ if (contentRef) {
18729
+ observer.observe(contentRef.current);
18711
18730
  }
18731
+ }
18732
+ return () => {
18733
+ observer.disconnect();
18712
18734
  };
18713
18735
  }, []);
18714
18736
  return /* @__PURE__ */ u("div", { className: "file-preview-image-group", children: [
@@ -18734,33 +18756,43 @@ const FilePreviewImageGroup = (props) => {
18734
18756
  ref: contentRef,
18735
18757
  className: "image-group-main-container",
18736
18758
  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;
18759
+ if (!isScrolling.value) {
18760
+ handleScroll();
18752
18761
  }
18753
- return /* @__PURE__ */ u(
18754
- ImagePage,
18762
+ },
18763
+ children: [
18764
+ /* @__PURE__ */ u(
18765
+ "div",
18755
18766
  {
18756
- page,
18757
- index,
18758
- state,
18759
- isShowImage: true
18760
- },
18761
- page.image_url
18762
- );
18763
- })
18767
+ class: "image-group-main-phantom",
18768
+ style: { height: "".concat(phantomHeight.value, "px") }
18769
+ }
18770
+ ),
18771
+ /* @__PURE__ */ u(
18772
+ "div",
18773
+ {
18774
+ className: "image-group-item-container",
18775
+ style: {
18776
+ transform: "translate3d(0,".concat(startOffset.value, "px,0)")
18777
+ },
18778
+ children: visibleData.value && visibleData.value.length > 0 && visibleData.value.map((page) => {
18779
+ return /* @__PURE__ */ u(
18780
+ ImagePage,
18781
+ {
18782
+ page,
18783
+ index: page.index,
18784
+ state,
18785
+ parentDimensions,
18786
+ onHeightChange: (index, height) => {
18787
+ updateVisualSize(index, height);
18788
+ }
18789
+ },
18790
+ page.image_url
18791
+ );
18792
+ })
18793
+ }
18794
+ )
18795
+ ]
18764
18796
  }
18765
18797
  ),
18766
18798
  /* @__PURE__ */ u(Teleport, { to: "#custom-controls", children: /* @__PURE__ */ u("div", { className: "image-toolbar-container", children: [