Skip to content

Commit

Permalink
fix: resize only on direction of drag move (#8222)
Browse files Browse the repository at this point in the history
* fix: resize only on direction of drag move

* test: skip test for safari
  • Loading branch information
ugur-vaadin authored Nov 26, 2024
1 parent 748501e commit f83bfc2
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 5 deletions.
4 changes: 2 additions & 2 deletions packages/dashboard/src/widget-resize-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,10 @@ export class WidgetResizeController {

const currentElementHeight = itemWrapper.firstElementChild.offsetHeight;
const rowMinHeight = Math.min(...gridStyle.gridTemplateRows.split(' ').map((height) => parseFloat(height)));
if (this.__resizeHeight > currentElementHeight + gapSize + rowMinHeight / 2) {
if (e.detail.ddy > 0 && this.__resizeHeight > currentElementHeight + gapSize + rowMinHeight / 2) {
// Resized vertically above the half of the next row, increase rowspan
this.__updateResizedItem(0, 1);
} else if (this.__resizeHeight < currentElementHeight - rowMinHeight / 2) {
} else if (e.detail.ddy < 0 && this.__resizeHeight < currentElementHeight - rowMinHeight / 2) {
// Resized vertically below the half of the current row, decrease rowspan
this.__updateResizedItem(0, -1);
}
Expand Down
123 changes: 121 additions & 2 deletions packages/dashboard/test/dashboard-widget-resizing.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect } from '@vaadin/chai-plugins';
import { fixtureSync, nextFrame } from '@vaadin/testing-helpers';
import { fire, fixtureSync, nextFrame } from '@vaadin/testing-helpers';
import sinon from 'sinon';
import '../vaadin-dashboard.js';
import { isSafari } from '@vaadin/component-base/src/browser-utils.js';
Expand All @@ -11,6 +11,8 @@ import {
fireResizeOver,
fireResizeStart,
getElementFromCell,
getEventCoordinates,
getResizeHandle,
onceResized,
setMaximumColumnWidth,
setMinimumColumnWidth,
Expand Down Expand Up @@ -201,10 +203,34 @@ describe('dashboard - widget resizing', () => {
[0, 2],
]);

const resizeHandle = getResizeHandle(getElementFromCell(dashboard, 1, 0)!);
const { x: initialX, y: initialY } = getEventCoordinates(resizeHandle, 'bottom');

fireResizeStart(getElementFromCell(dashboard, 1, 0)!);
await nextFrame();

fireResizeOver(getElementFromCell(dashboard, 0, 0)!, 'top');
const targetElement = getElementFromCell(dashboard, 0, 0)!;
fireResizeOver(targetElement, 'top');
await nextFrame();

const { x: targetX, y: targetY } = getEventCoordinates(targetElement, 'top');
const event = new MouseEvent('mousemove', {
bubbles: true,
composed: true,
clientX: targetX,
clientY: targetY,
buttons: 1,
});
targetElement.dispatchEvent(event);
fire(resizeHandle, 'track', {
state: 'track',
x: targetX,
y: targetY - 1,
dx: targetX - initialX,
dy: targetY - initialY - 1,
ddx: 0,
ddy: -1,
});
await nextFrame();

fireResizeEnd(dashboard);
Expand Down Expand Up @@ -323,6 +349,99 @@ describe('dashboard - widget resizing', () => {
]);
});

(isSafari ? it.skip : it)('should resize only when dragged in the same direction (top -> bottom)', async () => {
setMinimumRowHeight(dashboard, 50);
dashboard.items = [{ id: 0, rowspan: 2 }, { id: 1 }, { id: 2 }];
await nextFrame();

// prettier-ignore
expectLayout(dashboard, [
[0, 1],
[0, 2],
]);

const widget = getElementFromCell(dashboard, 0, 1)!;
const initialHeight = widget.offsetHeight;
fireResizeStart(widget);
await nextFrame();

const targetElement = getElementFromCell(dashboard, 1, 1)!;
const { x, y } = getEventCoordinates(targetElement, 'top');
const minSizeIncreaseDelta = initialHeight / 2 + 1;
const minSizeIncreaseY = y + minSizeIncreaseDelta;
const event = new MouseEvent('mousemove', {
bubbles: true,
composed: true,
clientX: x,
clientY: minSizeIncreaseY,
buttons: 1,
});
targetElement.dispatchEvent(event);
await nextFrame();

let previousHeight = initialHeight;
const resizeHandle = getResizeHandle(widget);
for (let i = 1; i < 5; i++) {
fire(resizeHandle, 'track', {
state: 'track',
x,
y: minSizeIncreaseY + i,
dx: 0,
dy: minSizeIncreaseDelta + i,
ddx: 0,
ddy: 1,
});
await nextFrame();
const newHeight = getElementFromCell(dashboard, 0, 1)!.offsetHeight;
expect(newHeight >= previousHeight).to.be.true;
previousHeight = newHeight;
}
});

it('should resize only when dragged in the same direction (bottom -> top)', async () => {
setMinimumRowHeight(dashboard, 50);
dashboard.items = [{ id: 0, rowspan: 2 }, { id: 1 }, { id: 2, rowspan: 3 }];
await nextFrame();

const widget = getElementFromCell(dashboard, 2, 1)!;
const initialHeight = widget.offsetHeight;
fireResizeStart(widget);
await nextFrame();

const targetElement = getElementFromCell(dashboard, 1, 1)!;
const { x, y } = getEventCoordinates(targetElement, 'top');
const minSizeDecreaseDelta = initialHeight / 3 + 1;
const minSizeDecreaseY = y - minSizeDecreaseDelta;
const event = new MouseEvent('mousemove', {
bubbles: true,
composed: true,
clientX: x,
clientY: minSizeDecreaseY,
buttons: 1,
});
targetElement.dispatchEvent(event);
await nextFrame();

let previousHeight = initialHeight;
const resizeHandle = getResizeHandle(widget);

for (let i = 1; i < 5; i++) {
fire(resizeHandle, 'track', {
state: 'track',
x,
y: minSizeDecreaseY - i,
dx: 0,
dy: minSizeDecreaseDelta - i,
ddx: 0,
ddy: -1,
});
await nextFrame();
const newHeight = getElementFromCell(dashboard, 1, 1)!.offsetHeight;
expect(newHeight <= previousHeight).to.be.true;
previousHeight = newHeight;
}
});

it('should dispatch an item resized event', async () => {
const resizeEndSpy = sinon.spy();
dashboard.addEventListener('dashboard-item-resized', resizeEndSpy);
Expand Down
5 changes: 4 additions & 1 deletion packages/dashboard/test/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,10 @@ export function createDragEvent(type: string, { x, y }: { x: number; y: number }
return event;
}

function getEventCoordinates(relativeElement: Element, location: 'top' | 'bottom' | 'start' | 'end') {
export function getEventCoordinates(
relativeElement: Element,
location: 'top' | 'bottom' | 'start' | 'end',
): { x: number; y: number } {
const { top, bottom, left, right } = relativeElement.getBoundingClientRect();
const y = location === 'top' ? top : bottom;
const dir = document.dir;
Expand Down

0 comments on commit f83bfc2

Please sign in to comment.