@pdanpdan/virtual-scroll 0.10.2 → 0.10.3

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.
@@ -1,2 +1,2 @@
1
- @layer components{.virtual-scrollbar-track{--vsi-scrollbar-bg:var(--vs-scrollbar-bg,light-dark(#e6e6e6e6,#1e1e1ee6));--vsi-scrollbar-thumb-bg:var(--vs-scrollbar-thumb-bg,light-dark(#0000004d,#ffffff4d));--vsi-scrollbar-thumb-hover-bg:var(--vs-scrollbar-thumb-hover-bg,light-dark(#0009,#fff9));--vsi-scrollbar-radius:var(--vs-scrollbar-radius,4px);--vsi-scrollbar-size:var(--vs-scrollbar-size,8px);contain:layout;background-color:var(--vsi-scrollbar-bg);border-radius:var(--vsi-scrollbar-radius);z-index:30;-webkit-user-select:none;user-select:none;pointer-events:auto;transition:opacity .2s;position:absolute}.virtual-scrollbar-track.virtual-scrollbar-track--vertical{inline-size:var(--vsi-scrollbar-size);inset-block-start:2px;inset-inline-end:2px}.virtual-scrollbar-track.virtual-scrollbar-track--horizontal{block-size:var(--vsi-scrollbar-size);inset-block-end:2px;inset-inline-start:2px}.virtual-scrollbar-thumb{background-color:var(--vsi-scrollbar-thumb-bg);border-radius:var(--vsi-scrollbar-radius);touch-action:none;pointer-events:auto;cursor:pointer;position:absolute}.virtual-scrollbar-thumb:hover,.virtual-scrollbar-thumb:active,.virtual-scrollbar-thumb.virtual-scrollbar-thumb--active{background-color:var(--vsi-scrollbar-thumb-hover-bg)}.virtual-scrollbar-thumb.virtual-scrollbar-thumb--vertical{inline-size:100%}.virtual-scrollbar-thumb.virtual-scrollbar-thumb--horizontal{block-size:100%}.virtual-scroll-container[data-v-a75851a5]{outline-offset:1px;block-size:100%;inline-size:100%;position:relative}.virtual-scroll-container[data-v-a75851a5]:not(.virtual-scroll--window){overscroll-behavior:contain;overflow:auto}.virtual-scroll-container.virtual-scroll--table[data-v-a75851a5]{display:block}.virtual-scroll-container.virtual-scroll--hide-scrollbar[data-v-a75851a5]{scrollbar-width:none;-ms-overflow-style:none}.virtual-scroll-container.virtual-scroll--hide-scrollbar[data-v-a75851a5]::-webkit-scrollbar{display:none}.virtual-scroll-container.virtual-scroll--horizontal[data-v-a75851a5],.virtual-scroll-container.virtual-scroll--both[data-v-a75851a5]{white-space:nowrap}.virtual-scroll-scrollbar-container[data-v-a75851a5]{z-index:30;pointer-events:none;block-size:0;inline-size:100%;position:sticky;inset-block-start:0;inset-inline-start:0;overflow:visible}.virtual-scroll-scrollbar-viewport[data-v-a75851a5]{pointer-events:none;position:absolute;inset-block-start:0;inset-inline-start:0}.virtual-scroll-wrapper[data-v-a75851a5]{contain:layout;position:relative}:where(.virtual-scroll--hydrated>.virtual-scroll-wrapper>.virtual-scroll-item[data-v-a75851a5]){position:absolute;inset-block-start:0;inset-inline-start:0}.virtual-scroll-item[data-v-a75851a5]{box-sizing:border-box;will-change:transform;display:grid}.virtual-scroll-item[data-v-a75851a5]:where(.virtual-scroll--debug){background-color:#ff00000d;outline:1px dashed #ff000080}.virtual-scroll-item[data-v-a75851a5]:where(.virtual-scroll--debug):where(:hover){z-index:100;background-color:#ff00001a}.virtual-scroll-debug-info[data-v-a75851a5]{color:#fff;pointer-events:none;z-index:100;background:#000000b3;border-radius:4px;padding:2px 4px;font-family:monospace;font-size:10px;position:absolute;inset-block-start:2px;inset-inline-end:2px}.virtual-scroll-spacer[data-v-a75851a5]{pointer-events:none}.virtual-scroll-header[data-v-a75851a5],.virtual-scroll-footer[data-v-a75851a5]{z-index:20;position:relative}.virtual-scroll--sticky[data-v-a75851a5]{position:sticky}.virtual-scroll--sticky[data-v-a75851a5]:where(.virtual-scroll-header){box-sizing:border-box;min-inline-size:100%;inset-block-start:0;inset-inline-start:0}.virtual-scroll--sticky[data-v-a75851a5]:where(.virtual-scroll-footer){box-sizing:border-box;min-inline-size:100%;inset-block-end:0;inset-inline-start:0}.virtual-scroll--sticky[data-v-a75851a5]:where(.virtual-scroll-item){z-index:10}:is(tbody.virtual-scroll-wrapper[data-v-a75851a5],thead.virtual-scroll-header[data-v-a75851a5],tfoot.virtual-scroll-footer[data-v-a75851a5]),:is(tbody.virtual-scroll-wrapper[data-v-a75851a5],thead.virtual-scroll-header[data-v-a75851a5],tfoot.virtual-scroll-footer[data-v-a75851a5])>tr{min-inline-size:100%;display:inline-flex}:is(tbody.virtual-scroll-wrapper[data-v-a75851a5],thead.virtual-scroll-header[data-v-a75851a5],tfoot.virtual-scroll-footer[data-v-a75851a5])>tr>:is(td,th){align-items:center;display:inline-block}}
1
+ @layer components{.virtual-scrollbar-track{--vsi-scrollbar-bg:var(--vs-scrollbar-bg,light-dark(#e6e6e6e6,#1e1e1ee6));--vsi-scrollbar-thumb-bg:var(--vs-scrollbar-thumb-bg,light-dark(#0000004d,#ffffff4d));--vsi-scrollbar-thumb-hover-bg:var(--vs-scrollbar-thumb-hover-bg,light-dark(#0009,#fff9));--vsi-scrollbar-radius:var(--vs-scrollbar-radius,4px);--vsi-scrollbar-size:var(--vs-scrollbar-size,8px);contain:layout;background-color:var(--vsi-scrollbar-bg);border-radius:var(--vsi-scrollbar-radius);z-index:30;-webkit-user-select:none;user-select:none;pointer-events:auto;transition:opacity .2s;position:absolute}.virtual-scrollbar-track.virtual-scrollbar-track--vertical{inline-size:var(--vsi-scrollbar-size);inset-block-start:2px;inset-inline-end:2px}.virtual-scrollbar-track.virtual-scrollbar-track--horizontal{block-size:var(--vsi-scrollbar-size);inset-block-end:2px;inset-inline-start:2px}.virtual-scrollbar-thumb{background-color:var(--vsi-scrollbar-thumb-bg);border-radius:var(--vsi-scrollbar-radius);touch-action:none;pointer-events:auto;cursor:pointer;position:absolute}.virtual-scrollbar-thumb:hover,.virtual-scrollbar-thumb:active,.virtual-scrollbar-thumb.virtual-scrollbar-thumb--active{background-color:var(--vsi-scrollbar-thumb-hover-bg)}.virtual-scrollbar-thumb.virtual-scrollbar-thumb--vertical{inline-size:100%}.virtual-scrollbar-thumb.virtual-scrollbar-thumb--horizontal{block-size:100%}.virtual-scroll-container[data-v-200891f5]{outline-offset:1px;block-size:100%;inline-size:100%;position:relative}.virtual-scroll-container[data-v-200891f5]:not(.virtual-scroll--window){overscroll-behavior:contain;overflow:auto}.virtual-scroll-container.virtual-scroll--table[data-v-200891f5]{display:block}.virtual-scroll-container.virtual-scroll--hide-scrollbar[data-v-200891f5]{scrollbar-width:none;-ms-overflow-style:none}.virtual-scroll-container.virtual-scroll--hide-scrollbar[data-v-200891f5]::-webkit-scrollbar{display:none}.virtual-scroll-container.virtual-scroll--horizontal[data-v-200891f5],.virtual-scroll-container.virtual-scroll--both[data-v-200891f5]{white-space:nowrap}.virtual-scroll-scrollbar-container[data-v-200891f5]{z-index:30;pointer-events:none;block-size:0;inline-size:100%;position:sticky;inset-block-start:0;inset-inline-start:0;overflow:visible}.virtual-scroll-scrollbar-viewport[data-v-200891f5]{pointer-events:none;position:absolute;inset-block-start:0;inset-inline-start:0}.virtual-scroll-wrapper[data-v-200891f5]{contain:layout;position:relative}:where(.virtual-scroll--hydrated>.virtual-scroll-wrapper>.virtual-scroll-item[data-v-200891f5]){position:absolute;inset-block-start:0;inset-inline-start:0}.virtual-scroll-item[data-v-200891f5]{box-sizing:border-box;will-change:transform;display:grid}.virtual-scroll-item[data-v-200891f5]:where(.virtual-scroll--debug){background-color:#ff00000d;outline:1px dashed #ff000080}.virtual-scroll-item[data-v-200891f5]:where(.virtual-scroll--debug):where(:hover){z-index:100;background-color:#ff00001a}.virtual-scroll-debug-info[data-v-200891f5]{color:#fff;pointer-events:none;z-index:100;background:#000000b3;border-radius:4px;padding:2px 4px;font-family:monospace;font-size:10px;position:absolute;inset-block-start:2px;inset-inline-end:2px}.virtual-scroll-spacer[data-v-200891f5]{pointer-events:none}.virtual-scroll-header[data-v-200891f5],.virtual-scroll-footer[data-v-200891f5]{z-index:20;position:relative}.virtual-scroll--sticky[data-v-200891f5]{position:sticky}.virtual-scroll--sticky[data-v-200891f5]:where(.virtual-scroll-header){box-sizing:border-box;min-inline-size:100%;inset-block-start:0;inset-inline-start:0}.virtual-scroll--sticky[data-v-200891f5]:where(.virtual-scroll-footer){box-sizing:border-box;min-inline-size:100%;inset-block-end:0;inset-inline-start:0}.virtual-scroll--sticky[data-v-200891f5]:where(.virtual-scroll-item){z-index:10}:is(tbody.virtual-scroll-wrapper[data-v-200891f5],thead.virtual-scroll-header[data-v-200891f5],tfoot.virtual-scroll-footer[data-v-200891f5]),:is(tbody.virtual-scroll-wrapper[data-v-200891f5],thead.virtual-scroll-header[data-v-200891f5],tfoot.virtual-scroll-footer[data-v-200891f5])>tr{min-inline-size:100%;display:inline-flex}:is(tbody.virtual-scroll-wrapper[data-v-200891f5],thead.virtual-scroll-header[data-v-200891f5],tfoot.virtual-scroll-footer[data-v-200891f5])>tr>:is(td,th){align-items:center;display:inline-block}}
2
2
  /*$vite$:1*/
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pdanpdan/virtual-scroll",
3
3
  "type": "module",
4
- "version": "0.10.2",
4
+ "version": "0.10.3",
5
5
  "description": "A high-performance virtual scroll component for Vue 3",
6
6
  "author": "",
7
7
  "license": "MIT",
@@ -1100,7 +1100,7 @@ const internalItemRole = computed(() => {
1100
1100
  }
1101
1101
  return 'listitem';
1102
1102
  });
1103
- const itemRole = computed(() => props.itemRole != null ? props.itemRole : internalItemRole.value);
1103
+ const itemRole = computed(() => props.itemRole ?? internalItemRole.value);
1104
1104
  const cellRole = computed(() => {
1105
1105
  if (props.role === 'grid' || (!props.role && props.direction === 'both')) {
1106
1106
  return 'gridcell';
@@ -417,21 +417,19 @@ export function useVirtualScroll<T = unknown>(
417
417
  const scrollBehavior = isCorrection ? 'auto' : (behavior || 'smooth');
418
418
 
419
419
  if (!dryRun) {
420
- if (scrollBehavior === 'smooth' || !isCorrection) {
421
- isProgrammaticScroll.value = true;
422
- clearTimeout(programmaticScrollTimer);
423
- if (scrollBehavior === 'smooth') {
424
- programmaticScrollTimer = setTimeout(() => {
425
- isProgrammaticScroll.value = false;
426
- programmaticScrollTimer = undefined;
427
- checkPendingScroll();
428
- }, 1000);
429
- } else {
430
- programmaticScrollTimer = setTimeout(() => {
431
- isProgrammaticScroll.value = false;
432
- programmaticScrollTimer = undefined;
433
- }, 150);
434
- }
420
+ isProgrammaticScroll.value = true;
421
+ clearTimeout(programmaticScrollTimer);
422
+ if (scrollBehavior === 'smooth') {
423
+ programmaticScrollTimer = setTimeout(() => {
424
+ isProgrammaticScroll.value = false;
425
+ programmaticScrollTimer = undefined;
426
+ checkPendingScroll();
427
+ }, 1000);
428
+ } else {
429
+ programmaticScrollTimer = setTimeout(() => {
430
+ isProgrammaticScroll.value = false;
431
+ programmaticScrollTimer = undefined;
432
+ }, 150);
435
433
  }
436
434
  }
437
435
 
@@ -443,7 +441,7 @@ export function useVirtualScroll<T = unknown>(
443
441
  scrollOptions.top = Math.max(0, finalY);
444
442
  }
445
443
 
446
- if (!isCorrection && !dryRun) {
444
+ if (!dryRun) {
447
445
  scrollTo(container, scrollOptions);
448
446
  }
449
447
 
@@ -630,7 +628,7 @@ export function useVirtualScroll<T = unknown>(
630
628
  treeUpdateFlag.value;
631
629
  const { start, end } = range.value;
632
630
  const items: RenderedItem<T>[] = [];
633
- const stickyIndices = [ ...(props.value.stickyIndices || []) ].sort((a, b) => a - b);
631
+ const stickyIndices = (props.value.stickyIndices || []).toSorted((a, b) => a - b);
634
632
  const stickySet = new Set(stickyIndices);
635
633
  const sortedIndices: number[] = [];
636
634
  if (isHydrated.value || !props.value.ssrRange) {
@@ -840,7 +838,43 @@ export function useVirtualScroll<T = unknown>(
840
838
  const scrollValueY = actualScrollY;
841
839
  const currentRelX = displayToVirtual(scrollValueX, 0, scaleX.value);
842
840
  const currentRelY = displayToVirtual(scrollValueY, 0, scaleY.value);
843
- const { targetX, targetY } = calculateScrollTarget({ rowIndex, colIndex, options, direction: direction.value, viewportWidth: viewportWidth.value, viewportHeight: viewportHeight.value, totalWidth: virtualWidth.value, totalHeight: virtualHeight.value, gap: props.value.gap || 0, columnGap: props.value.columnGap || 0, fixedSize: fixedItemSize.value, fixedWidth: fixedColumnWidth.value, relativeScrollX: currentRelX, relativeScrollY: currentRelY, getItemSizeY: (idx) => itemSizesY.get(idx), getItemSizeX: (idx) => itemSizesX.get(idx), getItemQueryY: (idx) => itemSizesY.query(idx), getItemQueryX: (idx) => itemSizesX.query(idx), getColumnSize: (idx) => columnSizes.get(idx), getColumnQuery: (idx) => columnSizes.query(idx), scaleX: scaleX.value, scaleY: scaleY.value, hostOffsetX: componentOffset.x, hostOffsetY: componentOffset.y, stickyIndices: (props.value.stickyIndices || []), stickyStartX: stickyStartX.value, stickyStartY: stickyStartY.value, stickyEndX: stickyEndX.value, stickyEndY: stickyEndY.value, flowPaddingStartX: flowStartX.value, flowPaddingStartY: flowStartY.value, paddingStartX: paddingStartX.value, paddingStartY: paddingStartY.value, paddingEndX: paddingEndX.value, paddingEndY: paddingEndY.value });
841
+ const { targetX, targetY } = calculateScrollTarget({
842
+ rowIndex,
843
+ colIndex,
844
+ options,
845
+ direction: direction.value,
846
+ viewportWidth: viewportWidth.value,
847
+ viewportHeight: viewportHeight.value,
848
+ totalWidth: totalWidth.value,
849
+ totalHeight: totalHeight.value,
850
+ gap: props.value.gap || 0,
851
+ columnGap: props.value.columnGap || 0,
852
+ fixedSize: fixedItemSize.value,
853
+ fixedWidth: fixedColumnWidth.value,
854
+ relativeScrollX: currentRelX,
855
+ relativeScrollY: currentRelY,
856
+ getItemSizeY: (idx) => itemSizesY.get(idx),
857
+ getItemSizeX: (idx) => itemSizesX.get(idx),
858
+ getItemQueryY: (idx) => itemSizesY.query(idx),
859
+ getItemQueryX: (idx) => itemSizesX.query(idx),
860
+ getColumnSize: (idx) => columnSizes.get(idx),
861
+ getColumnQuery: (idx) => columnSizes.query(idx),
862
+ scaleX: scaleX.value,
863
+ scaleY: scaleY.value,
864
+ hostOffsetX: componentOffset.x,
865
+ hostOffsetY: componentOffset.y,
866
+ stickyIndices: props.value.stickyIndices || [],
867
+ stickyStartX: stickyStartX.value,
868
+ stickyStartY: stickyStartY.value,
869
+ stickyEndX: stickyEndX.value,
870
+ stickyEndY: stickyEndY.value,
871
+ flowPaddingStartX: flowStartX.value,
872
+ flowPaddingStartY: flowStartY.value,
873
+ paddingStartX: paddingStartX.value,
874
+ paddingStartY: paddingStartY.value,
875
+ paddingEndX: paddingEndX.value,
876
+ paddingEndY: paddingEndY.value,
877
+ });
844
878
  const toleranceX = 2 * scaleX.value;
845
879
  const toleranceY = 2 * scaleY.value;
846
880
  const reachedX = (colIndex === null || colIndex === undefined) || (viewportWidth.value > 0 && Math.abs(currentRelX - targetX) < toleranceX);
@@ -858,7 +892,7 @@ export function useVirtualScroll<T = unknown>(
858
892
  }
859
893
  }
860
894
 
861
- watch([ treeUpdateFlag, viewportWidth, viewportHeight ], checkPendingScroll);
895
+ watch([ treeUpdateFlag, viewportWidth, viewportHeight, isHydrating ], checkPendingScroll);
862
896
  watch(isScrolling, (scrolling) => {
863
897
  if (!scrolling) {
864
898
  checkPendingScroll();
@@ -388,7 +388,7 @@ export function useVirtualScrollSizes<T>(
388
388
  tryUpdateColumn(Number.parseInt(colIndexAttr, 10), inlineSize);
389
389
  } else {
390
390
  // If the element is a row, try to find cells with data-col-index
391
- const cells = Array.from(element.querySelectorAll('[data-col-index]')) as HTMLElement[];
391
+ const cells = [ ...element.querySelectorAll('[data-col-index]') ] as HTMLElement[];
392
392
 
393
393
  for (const child of cells) {
394
394
  const colIndex = Number.parseInt(child.dataset.colIndex!, 10);
@@ -11,7 +11,7 @@ import { findPrevStickyIndex } from '../utils/virtual-scroll-logic';
11
11
  */
12
12
  export function useStickyExtension<T = unknown>(): VirtualScrollExtension<T> {
13
13
  const sortedStickyIndices = (ctx: ExtensionContext<T>) =>
14
- computed(() => [ ...(ctx.props.value.stickyIndices || []) ].sort((a, b) => a - b));
14
+ computed(() => (ctx.props.value.stickyIndices || []).toSorted((a, b) => a - b));
15
15
 
16
16
  return {
17
17
  name: 'sticky',