@pdanpdan/virtual-scroll 0.10.1 → 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.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +553 -522
- package/dist/index.mjs.map +1 -1
- package/dist/virtual-scroll.css +1 -1
- package/package.json +1 -1
- package/src/components/VirtualScroll.vue +1 -1
- package/src/composables/useVirtualScroll.ts +60 -16
- package/src/composables/useVirtualScrollSizes.ts +1 -1
- package/src/extensions/sticky.ts +1 -1
package/dist/virtual-scroll.css
CHANGED
|
@@ -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-
|
|
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
|
@@ -1100,7 +1100,7 @@ const internalItemRole = computed(() => {
|
|
|
1100
1100
|
}
|
|
1101
1101
|
return 'listitem';
|
|
1102
1102
|
});
|
|
1103
|
-
const itemRole = computed(() => props.itemRole
|
|
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,16 +417,19 @@ export function useVirtualScroll<T = unknown>(
|
|
|
417
417
|
const scrollBehavior = isCorrection ? 'auto' : (behavior || 'smooth');
|
|
418
418
|
|
|
419
419
|
if (!dryRun) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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);
|
|
430
433
|
}
|
|
431
434
|
}
|
|
432
435
|
|
|
@@ -438,7 +441,7 @@ export function useVirtualScroll<T = unknown>(
|
|
|
438
441
|
scrollOptions.top = Math.max(0, finalY);
|
|
439
442
|
}
|
|
440
443
|
|
|
441
|
-
if (!
|
|
444
|
+
if (!dryRun) {
|
|
442
445
|
scrollTo(container, scrollOptions);
|
|
443
446
|
}
|
|
444
447
|
|
|
@@ -466,6 +469,11 @@ export function useVirtualScroll<T = unknown>(
|
|
|
466
469
|
programmaticScrollTimer = undefined;
|
|
467
470
|
checkPendingScroll();
|
|
468
471
|
}, 1000);
|
|
472
|
+
} else {
|
|
473
|
+
programmaticScrollTimer = setTimeout(() => {
|
|
474
|
+
isProgrammaticScroll.value = false;
|
|
475
|
+
programmaticScrollTimer = undefined;
|
|
476
|
+
}, 150);
|
|
469
477
|
}
|
|
470
478
|
pendingScroll.value = null;
|
|
471
479
|
|
|
@@ -620,7 +628,7 @@ export function useVirtualScroll<T = unknown>(
|
|
|
620
628
|
treeUpdateFlag.value;
|
|
621
629
|
const { start, end } = range.value;
|
|
622
630
|
const items: RenderedItem<T>[] = [];
|
|
623
|
-
const stickyIndices =
|
|
631
|
+
const stickyIndices = (props.value.stickyIndices || []).toSorted((a, b) => a - b);
|
|
624
632
|
const stickySet = new Set(stickyIndices);
|
|
625
633
|
const sortedIndices: number[] = [];
|
|
626
634
|
if (isHydrated.value || !props.value.ssrRange) {
|
|
@@ -830,11 +838,47 @@ export function useVirtualScroll<T = unknown>(
|
|
|
830
838
|
const scrollValueY = actualScrollY;
|
|
831
839
|
const currentRelX = displayToVirtual(scrollValueX, 0, scaleX.value);
|
|
832
840
|
const currentRelY = displayToVirtual(scrollValueY, 0, scaleY.value);
|
|
833
|
-
const { targetX, targetY } = calculateScrollTarget({
|
|
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
|
+
});
|
|
834
878
|
const toleranceX = 2 * scaleX.value;
|
|
835
879
|
const toleranceY = 2 * scaleY.value;
|
|
836
|
-
const reachedX = (colIndex === null || colIndex === undefined) || Math.abs(currentRelX - targetX) < toleranceX;
|
|
837
|
-
const reachedY = (rowIndex === null || rowIndex === undefined) || Math.abs(currentRelY - targetY) < toleranceY;
|
|
880
|
+
const reachedX = (colIndex === null || colIndex === undefined) || (viewportWidth.value > 0 && Math.abs(currentRelX - targetX) < toleranceX);
|
|
881
|
+
const reachedY = (rowIndex === null || rowIndex === undefined) || (viewportHeight.value > 0 && Math.abs(currentRelY - targetY) < toleranceY);
|
|
838
882
|
if (reachedX && reachedY) {
|
|
839
883
|
const isMeasuredX = colIndex == null || colIndex === undefined || measuredColumns.value[ colIndex ] === 1;
|
|
840
884
|
const isMeasuredY = rowIndex == null || rowIndex === undefined || measuredItemsY.value[ rowIndex ] === 1;
|
|
@@ -848,7 +892,7 @@ export function useVirtualScroll<T = unknown>(
|
|
|
848
892
|
}
|
|
849
893
|
}
|
|
850
894
|
|
|
851
|
-
watch([ treeUpdateFlag, viewportWidth, viewportHeight ], checkPendingScroll);
|
|
895
|
+
watch([ treeUpdateFlag, viewportWidth, viewportHeight, isHydrating ], checkPendingScroll);
|
|
852
896
|
watch(isScrolling, (scrolling) => {
|
|
853
897
|
if (!scrolling) {
|
|
854
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 =
|
|
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);
|
package/src/extensions/sticky.ts
CHANGED
|
@@ -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(() =>
|
|
14
|
+
computed(() => (ctx.props.value.stickyIndices || []).toSorted((a, b) => a - b));
|
|
15
15
|
|
|
16
16
|
return {
|
|
17
17
|
name: 'sticky',
|