2 files changed
+58
-11
No files matched your search
@@ -1,6 +1,6 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { effectScope, nextTick, ref } from "vue";
|
||||
import { effectScope, nextTick, ref, watch } from "vue";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { dataGridColumnOffsets, dataGridHorizontalColumnWindow, useDataGridColumnLayout, useDataGridColumnLayoutState, type ColumnHeaderReferenceDragController } from "@/composables/useDataGridColumnLayout";
|
||||
import { columnHeaderDragAutoScrollDelta, columnHeaderDropTargetIndex } from "@/lib/dataGrid/dataGridColumnHeaderInteraction";
|
||||
@@ -40,6 +40,45 @@ describe("useDataGridColumnLayout", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps rendered columns stable while scrolling inside the same buffered window", async () => {
|
||||
const scrollLeft = ref(100);
|
||||
const columnNames = ref(Array.from({ length: 40 }, (_, index) => `column_${index}`));
|
||||
const visibleColumnIndexes = ref(columnNames.value.map((_, index) => index));
|
||||
const renderedColumnWidths = ref(columnNames.value.map(() => 100));
|
||||
const scope = effectScope();
|
||||
const layout = scope.run(() =>
|
||||
useDataGridColumnLayout({
|
||||
columnNames,
|
||||
visibleColumnIndexes,
|
||||
renderedColumnWidths,
|
||||
scrollLeft,
|
||||
viewportWidth: ref(500),
|
||||
rowNumberWidth: ref(40),
|
||||
}),
|
||||
)!;
|
||||
|
||||
const firstWindow = layout.horizontalColumnWindow.value;
|
||||
const firstColumns = layout.renderedGridColumns.value;
|
||||
const renderedColumnUpdates = vi.fn();
|
||||
const stopWatching = watch(layout.renderedGridColumns, renderedColumnUpdates, { flush: "sync" });
|
||||
|
||||
for (let position = 101; position <= 140; position += 1) scrollLeft.value = position;
|
||||
await nextTick();
|
||||
|
||||
expect(layout.horizontalColumnWindow.value).toBe(firstWindow);
|
||||
expect(layout.renderedGridColumns.value).toBe(firstColumns);
|
||||
expect(renderedColumnUpdates).not.toHaveBeenCalled();
|
||||
|
||||
scrollLeft.value = 1_500;
|
||||
await nextTick();
|
||||
|
||||
expect(layout.horizontalColumnWindow.value).not.toBe(firstWindow);
|
||||
expect(layout.renderedGridColumns.value).not.toBe(firstColumns);
|
||||
expect(renderedColumnUpdates).toHaveBeenCalledTimes(1);
|
||||
stopWatching();
|
||||
scope.stop();
|
||||
});
|
||||
|
||||
it("accelerates column drag scrolling toward the viewport edges", () => {
|
||||
expect(columnHeaderDragAutoScrollDelta({ clientX: 100, viewportLeft: 0, viewportRight: 400 })).toBe(0);
|
||||
expect(columnHeaderDragAutoScrollDelta({ clientX: 32, viewportLeft: 0, viewportRight: 400 })).toBeLessThan(0);
|
||||
|
||||
@@ -99,6 +99,11 @@ export function dataGridHorizontalColumnWindow(options: { widths: readonly numbe
|
||||
return { start, end, beforeWidth: offsets[start] ?? 0, afterWidth: Math.max(0, columnsWidth - visibleWidth) };
|
||||
}
|
||||
|
||||
export function stableDataGridHorizontalColumnWindow(previous: DataGridHorizontalColumnWindow | undefined, next: DataGridHorizontalColumnWindow): DataGridHorizontalColumnWindow {
|
||||
if (previous && previous.start === next.start && previous.end === next.end && previous.beforeWidth === next.beforeWidth && previous.afterWidth === next.afterWidth) return previous;
|
||||
return next;
|
||||
}
|
||||
|
||||
export function useDataGridColumnLayoutState(options: {
|
||||
columns: MaybeRefOrGetter<readonly string[]>;
|
||||
sourceColumns?: MaybeRefOrGetter<readonly (string | undefined)[] | undefined>;
|
||||
@@ -503,16 +508,19 @@ export function useDataGridColumnLayout(options: {
|
||||
}) {
|
||||
const renderedColumnOffsets = computed(() => dataGridColumnOffsets(toValue(options.renderedColumnWidths)));
|
||||
const frozenColumnCount = computed(() => toValue(options.frozenColumnCount ?? 0));
|
||||
const horizontalColumnWindow = computed(() =>
|
||||
dataGridHorizontalColumnWindow({
|
||||
widths: toValue(options.renderedColumnWidths),
|
||||
offsets: renderedColumnOffsets.value,
|
||||
columnCount: toValue(options.visibleColumnIndexes).length,
|
||||
scrollLeft: toValue(options.scrollLeft),
|
||||
viewportWidth: toValue(options.viewportWidth),
|
||||
rowNumberWidth: toValue(options.rowNumberWidth),
|
||||
bufferPx: options.bufferPx ?? 900,
|
||||
}),
|
||||
const horizontalColumnWindow = computed<DataGridHorizontalColumnWindow>((previous) =>
|
||||
stableDataGridHorizontalColumnWindow(
|
||||
previous,
|
||||
dataGridHorizontalColumnWindow({
|
||||
widths: toValue(options.renderedColumnWidths),
|
||||
offsets: renderedColumnOffsets.value,
|
||||
columnCount: toValue(options.visibleColumnIndexes).length,
|
||||
scrollLeft: toValue(options.scrollLeft),
|
||||
viewportWidth: toValue(options.viewportWidth),
|
||||
rowNumberWidth: toValue(options.rowNumberWidth),
|
||||
bufferPx: options.bufferPx ?? 900,
|
||||
}),
|
||||
),
|
||||
);
|
||||
const renderedGridColumns = computed<RenderedDataGridColumn[]>(() => {
|
||||
const columnNames = toValue(options.columnNames);
|
||||
|
||||
Reference in new issue
Block a user