Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions packages/common/src/core/__tests__/slickGrid.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5110,6 +5110,7 @@ describe('SlickGrid core file', () => {
resizeHandleElm.dispatchEvent(cMouseDownEvent);
container.dispatchEvent(cMouseDownEvent);
document.body.dispatchEvent(bodyMouseMoveEvent);
expect((grid as any)._columnResizeAutoScrollTimer).toBeUndefined();
document.body.dispatchEvent(bodyMouseUpEvent);

expect(scrollToXSpy).not.toHaveBeenCalledWith(400);
Expand Down Expand Up @@ -5186,15 +5187,12 @@ describe('SlickGrid core file', () => {
container.dispatchEvent(cMouseDownEvent);
document.body.dispatchEvent(bodyMouseMoveEvent);

const dragCallCountAfterMove = onColumnsDragSpy.mock.calls.length;

// The minimal auto-scroll logic triggers the callback every 30ms (RESIZE_AUTOSCROLL_MIN_INTERVAL_MS),
// so after 90ms, we expect 4 calls (initial + 3 intervals)
// Resize and reorder auto-scroll share the same 30ms interval.
vi.advanceTimersByTime(90);
expect(onColumnsDragSpy.mock.calls.length).toBe(4);

vi.advanceTimersByTime(40);
expect(onColumnsDragSpy.mock.calls.length).toBeGreaterThan(dragCallCountAfterMove);
expect(onColumnsDragSpy.mock.calls.length).toBe(5);

document.body.dispatchEvent(bodyMouseUpEvent);
});
Expand Down Expand Up @@ -5294,7 +5292,7 @@ describe('SlickGrid core file', () => {
document.body.dispatchEvent(upEvt);
});

it('should trigger accelerated auto-scroll when resizing column inside grid (non-browser-edge)', () => {
it('should clamp resizing to the viewport edge before auto-scroll continues at the shared rate', () => {
grid = new SlickGrid<any, Column>(container, data, columns, {
...defaultOptions,
forceFitColumns: false,
Expand All @@ -5309,26 +5307,27 @@ describe('SlickGrid core file', () => {
Object.defineProperty(viewportX, 'scrollLeft', { configurable: true, writable: true, value: 0 });

const columnElms = container.querySelectorAll('.slick-header-column');
const lastColumnElm = columnElms[3];
const resizeHandleElm = lastColumnElm.querySelector('.slick-resizable-handle') as HTMLDivElement;
const resizeHandleElm = columnElms[0].querySelector('.slick-resizable-handle') as HTMLDivElement;

const cMouseDownEvent = new CustomEvent('mousedown');
const bodyMouseMoveEvent = new CustomEvent('mousemove');
Object.defineProperty(bodyMouseMoveEvent, 'target', { writable: true, value: resizeHandleElm });
Object.defineProperty(cMouseDownEvent, 'pageX', { writable: true, value: 80 });
Object.defineProperty(cMouseDownEvent, 'pageY', { writable: true, value: 12 });
Object.defineProperty(bodyMouseMoveEvent, 'pageX', { writable: true, value: 140 });
Object.defineProperty(bodyMouseMoveEvent, 'pageX', { writable: true, value: 1000 });
Object.defineProperty(bodyMouseMoveEvent, 'pageY', { writable: true, value: 13 });
// Simulate pointer inside grid, not at browser edge
Object.defineProperty(bodyMouseMoveEvent, 'clientX', { writable: true, value: 400 });

resizeHandleElm.dispatchEvent(cMouseDownEvent);
container.dispatchEvent(cMouseDownEvent);
document.body.dispatchEvent(bodyMouseMoveEvent);

// Advance timers to trigger the accelerated auto-scroll branch
vi.advanceTimersByTime(200);
expect(onColumnsDragSpy).toHaveBeenCalled();
expect(columns[1].width).toBe(720);
expect(onColumnsDragSpy).toHaveBeenCalledTimes(1);

vi.advanceTimersByTime(30);
expect(columns[1].width).toBe(730);
expect(onColumnsDragSpy).toHaveBeenCalledTimes(2);
document.body.dispatchEvent(new CustomEvent('mouseup'));
});

Expand Down
46 changes: 19 additions & 27 deletions packages/common/src/core/slickGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,8 @@ import { applyHtmlToElement, runOptionalHtmlSanitizer } from './utils.js';
// body scroll range (header width is the header/body scroll-sync floor) and column
// drag-reorder has room past the last column
const HEADER_WIDTH_SLACK = 1000;
const RESIZE_AUTOSCROLL_MIN_INTERVAL_MS = 30;
const RESIZE_AUTOSCROLL_MAX_INTERVAL_MS = 600;
const RESIZE_AUTOSCROLL_ACCELERATE_INTERVAL = 5;
const COLUMN_AUTOSCROLL_DISTANCE_PX = 10;
const COLUMN_AUTOSCROLL_INTERVAL_MS = 30;
const RESIZE_AUTOSCROLL_BROWSER_EDGE_PX = 1;
const RESIZE_AUTOSCROLL_BROWSER_EDGE_LEFT_DELAY_MS = 300;
const RESIZE_AUTOSCROLL_BROWSER_EDGE_RIGHT_DELAY_MS = 1200;
Expand Down Expand Up @@ -2180,7 +2179,10 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
stopAutoScroll();
columnScrollDirection = direction;
if (direction) {
columnScrollTimer = setInterval(() => (this._viewportScrollContainerX.scrollLeft += direction * 10), 30);
columnScrollTimer = setInterval(
() => (this._viewportScrollContainerX.scrollLeft += direction * COLUMN_AUTOSCROLL_DISTANCE_PX),
COLUMN_AUTOSCROLL_INTERVAL_MS
);
}
}
}
Expand Down Expand Up @@ -2304,44 +2306,33 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
if (this._columnResizeAutoScrollTimer) {
return;
}
let elapsed = 0;
this._columnResizeAutoScrollTimer = setInterval(() => {
const isBrowserEdge = Math.abs(autoScrollOffsetX) === 1;
const viewportOffset = getOffset(this._viewportScrollContainerX);
const moveDistance = isBrowserEdge ? 4 * autoScrollOffsetX : (this.getAbsoluteColumnMinWidth() / 2) * Math.sign(autoScrollOffsetX);
/* v8 ignore next 5 */
if (!isBrowserEdge) {
const delay = RESIZE_AUTOSCROLL_MAX_INTERVAL_MS - Math.abs(autoScrollOffsetX) * RESIZE_AUTOSCROLL_ACCELERATE_INTERVAL;
elapsed += RESIZE_AUTOSCROLL_MIN_INTERVAL_MS;
if (elapsed < delay) {
return;
}
elapsed = 0;
}
/* v8 ignore next */
const targetPageX =
autoScrollOffsetX > 0
? viewportOffset.left + this._viewportScrollContainerX.clientWidth + moveDistance
: viewportOffset.left - moveDistance;
? viewportOffset.left + this._viewportScrollContainerX.clientWidth + COLUMN_AUTOSCROLL_DISTANCE_PX
: viewportOffset.left - COLUMN_AUTOSCROLL_DISTANCE_PX;
resizeCallback(targetPageX + resizeAutoScrollDeltaX);
}, RESIZE_AUTOSCROLL_MIN_INTERVAL_MS);
}, COLUMN_AUTOSCROLL_INTERVAL_MS);
};

const updateColumnResizeAutoScroll = (
clientX: number | undefined,
targetPageX: number,
resizeCallback: (targetPageX: number) => void
) => {
): number => {
// TODO: there is a known bug with auto-scroll in RTL,
// so disable it until someone can contribute a fix
if (this._options.rtl) {
if (this._options.rtl || !this._options.autoScrollOnColumnResize) {
stopColumnResizeAutoScroll();
return;
return targetPageX;
}

autoScrollClientX = isDefinedNumber(clientX) ? clientX : autoScrollClientX;
const left = getOffset(this._viewportScrollContainerX).left;
const right = left + this._viewportScrollContainerX.clientWidth;
const viewportWidth = this._viewportScrollContainerX.clientWidth;
const right = left + viewportWidth;
const browserW = window.innerWidth || document.documentElement.clientWidth || 0;
if (targetPageX <= left) {
autoScrollOffsetX = targetPageX - left;
Expand All @@ -2359,9 +2350,10 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
}
if (autoScrollOffsetX) {
scheduleColumnResizeAutoScroll(resizeCallback);
} else {
stopColumnResizeAutoScroll();
return autoScrollOffsetX > 0 && viewportWidth ? Math.min(right, targetPageX) : targetPageX;
}
stopColumnResizeAutoScroll();
return targetPageX;
};

for (let i = 0; i < children.length; i++) {
Expand Down Expand Up @@ -2671,9 +2663,9 @@ export class SlickGrid<TData = any, C extends Column<TData> = Column<TData>, O e
},
onResize: (e, resizeElms) => {
const targetEvent = (e as TouchEvent).touches ? (e as TouchEvent).changedTouches[0] : e;
const targetPageX = (targetEvent as MouseEvent).pageX;
let targetPageX = (targetEvent as MouseEvent).pageX;
if (!(this.hasFrozenColumns() && i <= this._options.frozenColumn!)) {
updateColumnResizeAutoScroll((targetEvent as MouseEvent).clientX, targetPageX, (resizePageX) =>
targetPageX = updateColumnResizeAutoScroll((targetEvent as MouseEvent).clientX, targetPageX, (resizePageX) =>
applyColumnResize(resizePageX, resizeElms)
);
}
Expand Down
Loading