diff --git a/dev/dashboard.html b/dev/dashboard.html
index 10f4c8bddc..81f1c6cae7 100644
--- a/dev/dashboard.html
+++ b/dev/dashboard.html
@@ -102,6 +102,20 @@
console.log('dashboard-item-reorder-end');
console.log('items after reorder', e.target.items);
});
+
+ dashboard.addEventListener('dashboard-item-resize-start', (e) => {
+ console.log('dashboard-item-resize-start');
+ });
+
+ dashboard.addEventListener('dashboard-item-drag-resize', (e) => {
+ console.log('dashboard-item-drag-resize', e.detail);
+ // e.preventDefault();
+ });
+
+ dashboard.addEventListener('dashboard-item-resize-end', (e) => {
+ console.log('dashboard-item-resize-end');
+ console.log('item after resize', e.detail);
+ });
diff --git a/packages/dashboard/src/vaadin-dashboard.d.ts b/packages/dashboard/src/vaadin-dashboard.d.ts
index 9dac015b4b..5b5feb2c49 100644
--- a/packages/dashboard/src/vaadin-dashboard.d.ts
+++ b/packages/dashboard/src/vaadin-dashboard.d.ts
@@ -65,12 +65,41 @@ export type DashboardItemDragReorderEvent = CustomE
targetIndex: number;
}>;
+/**
+ * Fired when item resizing starts
+ */
+export type DashboardItemResizeStartEvent = CustomEvent<{
+ item: TItem;
+}>;
+
+/**
+ * Fired when item resizing ends
+ */
+export type DashboardItemResizeEndEvent = CustomEvent<{
+ item: TItem;
+}>;
+
+/**
+ * Fired when an item will be resized by dragging
+ */
+export type DashboardItemDragResizeEvent = CustomEvent<{
+ item: TItem;
+ colspan: number;
+ rowspan: number;
+}>;
+
export interface DashboardCustomEventMap {
'dashboard-item-reorder-start': DashboardItemReorderStartEvent;
'dashboard-item-reorder-end': DashboardItemReorderEndEvent;
'dashboard-item-drag-reorder': DashboardItemDragReorderEvent;
+
+ 'dashboard-item-resize-start': DashboardItemResizeStartEvent;
+
+ 'dashboard-item-resize-end': DashboardItemResizeEndEvent;
+
+ 'dashboard-item-drag-resize': DashboardItemDragResizeEvent;
}
export type DashboardEventMap = DashboardCustomEventMap & HTMLElementEventMap;
diff --git a/packages/dashboard/src/vaadin-dashboard.js b/packages/dashboard/src/vaadin-dashboard.js
index e065a64738..ea88afe402 100644
--- a/packages/dashboard/src/vaadin-dashboard.js
+++ b/packages/dashboard/src/vaadin-dashboard.js
@@ -27,6 +27,9 @@ import { WidgetResizeController } from './widget-resize-controller.js';
* @fires {CustomEvent} dashboard-item-drag-reorder - Fired when an items will be reordered by dragging
* @fires {CustomEvent} dashboard-item-reorder-start - Fired when item reordering starts
* @fires {CustomEvent} dashboard-item-reorder-end - Fired when item reordering ends
+ * @fires {CustomEvent} dashboard-item-drag-resize - Fired when an item will be resized by dragging
+ * @fires {CustomEvent} dashboard-item-resize-start - Fired when item resizing starts
+ * @fires {CustomEvent} dashboard-item-resize-end - Fired when item resizing ends
*
* @customElement
* @extends HTMLElement
@@ -106,6 +109,12 @@ class Dashboard extends ControllerMixin(DashboardLayoutMixin(ElementMixin(Themab
this.__widgetResizeController = new WidgetResizeController(this);
}
+ /** @protected */
+ disconnectedCallback() {
+ super.disconnectedCallback();
+ this.__widgetResizeController.cleanup();
+ }
+
/** @protected */
ready() {
super.ready();
@@ -189,6 +198,24 @@ class Dashboard extends ControllerMixin(DashboardLayoutMixin(ElementMixin(Themab
*
* @event dashboard-item-drag-reorder
*/
+
+ /**
+ * Fired when item resizing starts
+ *
+ * @event dashboard-item-resize-start
+ */
+
+ /**
+ * Fired when item resizing ends
+ *
+ * @event dashboard-item-resize-end
+ */
+
+ /**
+ * Fired when an item will be resized by dragging
+ *
+ * @event dashboard-item-drag-resize
+ */
}
defineCustomElement(Dashboard);
diff --git a/packages/dashboard/src/widget-resize-controller.js b/packages/dashboard/src/widget-resize-controller.js
index 6734ad4828..dadec05b5d 100644
--- a/packages/dashboard/src/widget-resize-controller.js
+++ b/packages/dashboard/src/widget-resize-controller.js
@@ -110,7 +110,7 @@ export class WidgetResizeController extends EventTarget {
this.host.$.grid.toggleAttribute('resizing', false);
this.__resizedElementRemoveObserver.disconnect();
- document.removeEventListener('touchmove', this.__touchMoveCancelListener);
+ this.cleanup();
this.host.dispatchEvent(new CustomEvent('dashboard-item-resize-end'));
}
@@ -126,14 +126,25 @@ export class WidgetResizeController extends EventTarget {
}
/** @private */
- __updateResizedItem(colspan, rowspan) {
- if (this.resizedItem.colspan !== colspan || this.resizedItem.rowspan !== rowspan) {
- this.resizedItem.colspan = colspan;
- this.resizedItem.rowspan = rowspan;
- this.host.dispatchEvent(new CustomEvent('dashboard-item-resize', { detail: { item: this.resizedItem } }));
- this.host.items = [...this.host.items];
- requestAnimationFrame(() => this.__updateWidgetStyles());
+ __updateResizedItem(colspan = 1, rowspan = 1) {
+ if (this.resizedItem.colspan === colspan && this.resizedItem.rowspan === rowspan) {
+ return;
+ }
+
+ const resizeEvent = new CustomEvent('dashboard-item-drag-resize', {
+ detail: { item: this.resizedItem, colspan, rowspan },
+ cancelable: true,
+ });
+
+ // Dispatch the resize event and resize items if the event is not canceled
+ if (!this.host.dispatchEvent(resizeEvent)) {
+ return;
}
+
+ this.resizedItem.colspan = colspan;
+ this.resizedItem.rowspan = rowspan;
+ this.host.items = [...this.host.items];
+ requestAnimationFrame(() => this.__updateWidgetStyles());
}
/** @private */
@@ -150,4 +161,8 @@ export class WidgetResizeController extends EventTarget {
this.host.appendChild(this.__resizedElement);
}
}
+
+ cleanup() {
+ document.removeEventListener('touchmove', this.__touchMoveCancelListener);
+ }
}
diff --git a/packages/dashboard/test/dashboard-widget-resizing.test.ts b/packages/dashboard/test/dashboard-widget-resizing.test.ts
index a8d7cee3f0..a5e79f8bee 100644
--- a/packages/dashboard/test/dashboard-widget-resizing.test.ts
+++ b/packages/dashboard/test/dashboard-widget-resizing.test.ts
@@ -1,5 +1,6 @@
import { expect } from '@vaadin/chai-plugins';
import { fixtureSync, nextFrame } from '@vaadin/testing-helpers';
+import sinon from 'sinon';
import '../vaadin-dashboard.js';
import type { Dashboard, DashboardItem } from '../vaadin-dashboard.js';
import {
@@ -228,6 +229,75 @@ describe('dashboard - widget resizing', () => {
]);
});
+ it('should dispatch an item resize start event', async () => {
+ const resizeStartSpy = sinon.spy();
+ dashboard.addEventListener('dashboard-item-resize-start', resizeStartSpy);
+ fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
+ await nextFrame();
+
+ expect(resizeStartSpy).to.have.been.calledOnce;
+ });
+
+ it('should dispatch an item drag resize event', async () => {
+ const resizeSpy = sinon.spy();
+ dashboard.addEventListener('dashboard-item-drag-resize', resizeSpy);
+ dashboard.addEventListener('dashboard-item-drag-resize', (e) => e.preventDefault());
+ fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
+ await nextFrame();
+ fireResizeOver(getElementFromCell(dashboard, 0, 1)!, 'end');
+ await nextFrame();
+
+ expect(resizeSpy).to.have.been.calledOnce;
+ expect(resizeSpy.getCall(0).args[0].detail).to.deep.equal({
+ item: { id: 0 },
+ colspan: 2,
+ rowspan: 1,
+ });
+ });
+
+ it('should not resize if the drag resize event is cancelled', async () => {
+ dashboard.addEventListener('dashboard-item-drag-resize', (e) => e.preventDefault());
+ fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
+ await nextFrame();
+ fireResizeOver(getElementFromCell(dashboard, 0, 1)!, 'end');
+ await nextFrame();
+ // prettier-ignore
+ expectLayout(dashboard, [
+ [0, 1],
+ ]);
+ });
+
+ it('should dispatch an item resize end event', async () => {
+ const resizeEndSpy = sinon.spy();
+ dashboard.addEventListener('dashboard-item-resize-end', resizeEndSpy);
+ fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
+ await nextFrame();
+ fireResizeEnd(dashboard);
+ await nextFrame();
+
+ expect(resizeEndSpy).to.have.been.calledOnce;
+ });
+
+ it('should cancel touchmove events while resizing', async () => {
+ fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
+ await nextFrame();
+ const touchmove = new TouchEvent('touchmove', { cancelable: true, bubbles: true });
+ document.dispatchEvent(touchmove);
+
+ expect(touchmove.defaultPrevented).to.be.true;
+ });
+
+ it('should not cancel touchmove events after resizing has finished', async () => {
+ fireResizeStart(getElementFromCell(dashboard, 0, 0)!);
+ await nextFrame();
+ fireResizeEnd(dashboard);
+
+ const touchmove = new TouchEvent('touchmove', { cancelable: true, bubbles: true });
+ document.dispatchEvent(touchmove);
+
+ expect(touchmove.defaultPrevented).to.be.false;
+ });
+
// Make sure the original resized element is restored in the host.
// Otherwise, "track" event would stop working.
describe('ensure track event', () => {
diff --git a/packages/dashboard/test/typings/dashboard.types.ts b/packages/dashboard/test/typings/dashboard.types.ts
index 0489bebbb5..c16507f5c8 100644
--- a/packages/dashboard/test/typings/dashboard.types.ts
+++ b/packages/dashboard/test/typings/dashboard.types.ts
@@ -5,8 +5,11 @@ import type {
Dashboard,
DashboardItem,
DashboardItemDragReorderEvent,
+ DashboardItemDragResizeEvent,
DashboardItemReorderEndEvent,
DashboardItemReorderStartEvent,
+ DashboardItemResizeEndEvent,
+ DashboardItemResizeStartEvent,
DashboardRenderer,
DashboardSectionItem,
} from '../../vaadin-dashboard.js';
@@ -57,6 +60,22 @@ narrowedDashboard.addEventListener('dashboard-item-drag-reorder', (event) => {
assertType(event.detail.targetIndex);
});
+narrowedDashboard.addEventListener('dashboard-item-resize-start', (event) => {
+ assertType>(event);
+});
+
+narrowedDashboard.addEventListener('dashboard-item-resize-end', (event) => {
+ assertType>(event);
+ assertType(event.detail.item);
+});
+
+narrowedDashboard.addEventListener('dashboard-item-drag-resize', (event) => {
+ assertType>(event);
+ assertType(event.detail.item);
+ assertType(event.detail.colspan);
+ assertType(event.detail.rowspan);
+});
+
/* DashboardLayout */
const layout = document.createElement('vaadin-dashboard-layout');
assertType(layout);