Skip to content

Commit

Permalink
fix: support resizing widgets in rtl (#7803)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomivirkki authored Sep 16, 2024
1 parent af5c2b1 commit fd1db23
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 71 deletions.
6 changes: 5 additions & 1 deletion packages/dashboard/src/vaadin-dashboard-widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class DashboardWidget extends ControllerMixin(ElementMixin(PolylitMixin(LitEleme
display: var(--_vaadin-dashboard-widget-actions-display, none);
position: absolute;
bottom: 0;
right: 0;
inset-inline-end: 0;
font-size: 30px;
cursor: grab;
line-height: 1;
Expand All @@ -64,6 +64,10 @@ class DashboardWidget extends ControllerMixin(ElementMixin(PolylitMixin(LitEleme
content: '\\2921';
}
:host([dir='rtl']) #resize-handle::before {
content: '\\2922';
}
:host::after {
content: '';
z-index: 2;
Expand Down
2 changes: 1 addition & 1 deletion packages/dashboard/src/widget-resize-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export class WidgetResizeController extends EventTarget {
return;
}

this.__resizeWidth = this.__resizeStartWidth + e.detail.dx;
this.__resizeWidth = this.__resizeStartWidth + (document.dir === 'rtl' ? -e.detail.dx : e.detail.dx);
this.__resizeHeight = this.__resizeStartHeight + e.detail.dy;
this.__updateWidgetStyles();

Expand Down
135 changes: 69 additions & 66 deletions packages/dashboard/test/dashboard-widget-resizing.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import '../vaadin-dashboard.js';
import { isSafari } from '@vaadin/component-base/src/browser-utils.js';
import type { Dashboard, DashboardItem } from '../vaadin-dashboard.js';
import {
describeBidirectional,
expectLayout,
fireResizeEnd,
fireResizeOver,
Expand Down Expand Up @@ -51,89 +52,91 @@ describe('dashboard - widget resizing', () => {
});

describe('mouse drag', () => {
it('should resize a widget while dragging (start -> end)', async () => {
// Start dragging the first widget resize handle
fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
await nextFrame();
describeBidirectional('horizontal', () => {
it('should resize a widget while dragging (start -> end)', async () => {
// Start dragging the first widget resize handle
fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
await nextFrame();

// Drag over the end edge of the second one
fireResizeOver(getElementFromCell(dashboard, 0, 1)!, 'end');
await nextFrame();
// Drag over the end edge of the second one
fireResizeOver(getElementFromCell(dashboard, 0, 1)!, 'end');
await nextFrame();

fireResizeEnd(dashboard);
await nextFrame();
fireResizeEnd(dashboard);
await nextFrame();

// Expect the widgets to be reordered
// prettier-ignore
expectLayout(dashboard, [
[0, 0],
[1],
]);
});
// Expect the widgets to be reordered
// prettier-ignore
expectLayout(dashboard, [
[0, 0],
[1],
]);
});

it('should not resize if dragged barely over another widget (start -> end)', async () => {
fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
await nextFrame();
it('should not resize if dragged barely over another widget (start -> end)', async () => {
fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
await nextFrame();

fireResizeOver(getElementFromCell(dashboard, 0, 1)!, 'start');
await nextFrame();
fireResizeOver(getElementFromCell(dashboard, 0, 1)!, 'start');
await nextFrame();

fireResizeEnd(dashboard);
await nextFrame();
fireResizeEnd(dashboard);
await nextFrame();

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

it('should resize a widget while dragging (end -> start)', async () => {
dashboard.items = [{ id: 0, colspan: 2 }, { id: 1 }];
await nextFrame();
// prettier-ignore
expectLayout(dashboard, [
[0, 0],
[1],
]);
it('should resize a widget while dragging (end -> start)', async () => {
dashboard.items = [{ id: 0, colspan: 2 }, { id: 1 }];
await nextFrame();
// prettier-ignore
expectLayout(dashboard, [
[0, 0],
[1],
]);

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

fireResizeOver(getElementFromCell(dashboard, 0, 0)!, 'start');
await nextFrame();
fireResizeOver(getElementFromCell(dashboard, 0, 0)!, 'start');
await nextFrame();

fireResizeEnd(dashboard);
await nextFrame();
fireResizeEnd(dashboard);
await nextFrame();

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

it('should not resize if dragged barely over another widget (end -> start)', async () => {
dashboard.items = [{ id: 0, colspan: 2 }, { id: 1 }];
await nextFrame();
// prettier-ignore
expectLayout(dashboard, [
[0, 0],
[1],
]);
it('should not resize if dragged barely over another widget (end -> start)', async () => {
dashboard.items = [{ id: 0, colspan: 2 }, { id: 1 }];
await nextFrame();
// prettier-ignore
expectLayout(dashboard, [
[0, 0],
[1],
]);

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

fireResizeOver(getElementFromCell(dashboard, 0, 0)!, 'end');
await nextFrame();
fireResizeOver(getElementFromCell(dashboard, 0, 0)!, 'end');
await nextFrame();

fireResizeEnd(dashboard);
await nextFrame();
fireResizeEnd(dashboard);
await nextFrame();

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

it('should resize a widget while dragging (top -> bottom)', async () => {
Expand Down
23 changes: 20 additions & 3 deletions packages/dashboard/test/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ function _getRowHeights(dashboard: Element): number[] {
}

function _getElementFromCell(dashboard: HTMLElement, rowIndex: number, columnIndex: number, rowHeights: number[]) {
const { top, left } = dashboard.getBoundingClientRect();
const { top, left, right } = dashboard.getBoundingClientRect();
const columnWidths = getColumnWidths(dashboard);
const x = left + columnWidths.slice(0, columnIndex).reduce((sum, width) => sum + width, 0);
const columnOffset = columnWidths.slice(0, columnIndex).reduce((sum, width) => sum + width, 0);
const rtl = document.dir === 'rtl';
const x = rtl ? right - columnOffset : left + columnOffset;
const y = top + rowHeights.slice(0, rowIndex).reduce((sum, height) => sum + height, 0);

return document
.elementsFromPoint(x + columnWidths[columnIndex] / 2, y + rowHeights[rowIndex] - 1)
.elementsFromPoint(x + (columnWidths[columnIndex] / 2) * (rtl ? -1 : 1), y + rowHeights[rowIndex] - 1)
.reverse()
.find(
(element) =>
Expand Down Expand Up @@ -279,3 +281,18 @@ export function fireResizeEnd(dragOverTarget: Element): void {
export function getRemoveButton(section: DashboardWidget | DashboardSection): HTMLElement {
return section.shadowRoot!.querySelector('#remove-button') as HTMLElement;
}

export function describeBidirectional(name: string, tests: () => void): void {
describe(name, tests);
describe(`${name} (RTL)`, () => {
before(() => {
document.dir = 'rtl';
});

after(() => {
document.dir = 'ltr'; // Reset to default after tests
});

tests();
});
}

0 comments on commit fd1db23

Please sign in to comment.