From a51684eb7efd786abc205950b8c629b6b2f71631 Mon Sep 17 00:00:00 2001 From: Tomi Virkki Date: Tue, 10 Sep 2024 09:03:50 +0300 Subject: [PATCH] feat: dashboard widget rowspan (#7781) --- dev/dashboard-layout.html | 2 +- dev/dashboard.html | 1 + .../src/vaadin-dashboard-layout-mixin.js | 5 +++ .../dashboard/src/vaadin-dashboard-section.js | 2 + .../dashboard/src/vaadin-dashboard-widget.js | 1 + packages/dashboard/src/vaadin-dashboard.d.ts | 5 +++ packages/dashboard/src/vaadin-dashboard.js | 1 + .../dashboard/test/dashboard-layout.test.ts | 45 +++++++++++++++++++ packages/dashboard/test/dashboard.test.ts | 18 ++++++++ packages/dashboard/test/helpers.ts | 7 +++ .../dashboard/test/typings/dashboard.types.ts | 9 +++- 11 files changed, 93 insertions(+), 3 deletions(-) diff --git a/dev/dashboard-layout.html b/dev/dashboard-layout.html index 97e34f781b..223e0e175c 100644 --- a/dev/dashboard-layout.html +++ b/dev/dashboard-layout.html @@ -59,7 +59,7 @@ - +
54 000€
diff --git a/dev/dashboard.html b/dev/dashboard.html index 7a69b285b5..10f4c8bddc 100644 --- a/dev/dashboard.html +++ b/dev/dashboard.html @@ -62,6 +62,7 @@ items: [ { title: 'Sales closed this month', + rowspan: 2, content: '54 000€', type: 'kpi', }, diff --git a/packages/dashboard/src/vaadin-dashboard-layout-mixin.js b/packages/dashboard/src/vaadin-dashboard-layout-mixin.js index bca569d49e..b3bd0e7166 100644 --- a/packages/dashboard/src/vaadin-dashboard-layout-mixin.js +++ b/packages/dashboard/src/vaadin-dashboard-layout-mixin.js @@ -72,6 +72,7 @@ export const DashboardLayoutMixin = (superClass) => } ::slotted(*) { + /* The grid-column value applied to children */ --_vaadin-dashboard-item-column: span min( var(--vaadin-dashboard-item-colspan, 1), @@ -79,6 +80,10 @@ export const DashboardLayoutMixin = (superClass) => ); grid-column: var(--_vaadin-dashboard-item-column); + + /* The grid-row value applied to children */ + --_vaadin-dashboard-item-row: span var(--vaadin-dashboard-item-rowspan, 1); + grid-row: var(--_vaadin-dashboard-item-row); } `; } diff --git a/packages/dashboard/src/vaadin-dashboard-section.js b/packages/dashboard/src/vaadin-dashboard-section.js index 597fd9bea5..ab11921faf 100644 --- a/packages/dashboard/src/vaadin-dashboard-section.js +++ b/packages/dashboard/src/vaadin-dashboard-section.js @@ -66,6 +66,8 @@ class DashboardSection extends ControllerMixin(ElementMixin(PolylitMixin(LitElem ); grid-column: var(--_vaadin-dashboard-item-column); + --_vaadin-dashboard-item-row: span var(--vaadin-dashboard-item-rowspan, 1); + grid-row: var(--_vaadin-dashboard-item-row); } header { diff --git a/packages/dashboard/src/vaadin-dashboard-widget.js b/packages/dashboard/src/vaadin-dashboard-widget.js index 8139e91b0e..8efd5dd8da 100644 --- a/packages/dashboard/src/vaadin-dashboard-widget.js +++ b/packages/dashboard/src/vaadin-dashboard-widget.js @@ -37,6 +37,7 @@ class DashboardWidget extends ControllerMixin(ElementMixin(PolylitMixin(LitEleme display: flex; flex-direction: column; grid-column: var(--_vaadin-dashboard-item-column); + grid-row: var(--_vaadin-dashboard-item-row); position: relative; } diff --git a/packages/dashboard/src/vaadin-dashboard.d.ts b/packages/dashboard/src/vaadin-dashboard.d.ts index 4d535d5652..9dac015b4b 100644 --- a/packages/dashboard/src/vaadin-dashboard.d.ts +++ b/packages/dashboard/src/vaadin-dashboard.d.ts @@ -18,6 +18,11 @@ export interface DashboardItem { * The column span of the item */ colspan?: number; + + /** + * The row span of the item + */ + rowspan?: number; } export interface DashboardSectionItem { diff --git a/packages/dashboard/src/vaadin-dashboard.js b/packages/dashboard/src/vaadin-dashboard.js index 4625651366..6ac2aff8c8 100644 --- a/packages/dashboard/src/vaadin-dashboard.js +++ b/packages/dashboard/src/vaadin-dashboard.js @@ -138,6 +138,7 @@ class Dashboard extends ControllerMixin(DashboardLayoutMixin(ElementMixin(Themab const itemDragged = this.__widgetReorderController.draggedItem === item; const style = ` ${item.colspan ? `--vaadin-dashboard-item-colspan: ${item.colspan};` : ''} + ${item.rowspan ? `--vaadin-dashboard-item-rowspan: ${item.rowspan};` : ''} ${itemDragged ? '--_vaadin-dashboard-item-placeholder-display: block;' : ''} `.trim(); diff --git a/packages/dashboard/test/dashboard-layout.test.ts b/packages/dashboard/test/dashboard-layout.test.ts index 2a918e4167..5d26f7c7f3 100644 --- a/packages/dashboard/test/dashboard-layout.test.ts +++ b/packages/dashboard/test/dashboard-layout.test.ts @@ -15,6 +15,7 @@ import { setMaximumColumnWidth, setMinimumColumnWidth, setMinimumRowHeight, + setRowspan, } from './helpers.js'; describe('dashboard layout', () => { @@ -261,6 +262,36 @@ describe('dashboard layout', () => { }); }); + describe('row span', () => { + it('should span multiple rows', async () => { + setMinimumRowHeight(dashboard, 100); + setRowspan(childElements[0], 2); + await nextFrame(); + + /* prettier-ignore */ + expectLayout(dashboard, [ + [0, 1], + [0], + ]); + }); + + it('should span multiple rows on a single column', async () => { + setMinimumRowHeight(dashboard, 100); + setRowspan(childElements[0], 2); + await nextFrame(); + + dashboard.style.width = `${columnWidth}px`; + await nextFrame(); + + /* prettier-ignore */ + expectLayout(dashboard, [ + [0], + [0], + [1], + ]); + }); + }); + describe('gap', () => { it('should have a default gap', () => { // Clear the gap used in the tests @@ -428,6 +459,20 @@ describe('dashboard layout', () => { ]); }); + it('should span multiple rows inside a section', async () => { + // Using a minimum row height here causes Firefox to crash, disabling for now + // setMinimumRowHeight(dashboard, 100); + setRowspan(childElements[2], 2); + await nextFrame(); + + /* prettier-ignore */ + expectLayout(dashboard, [ + [0, 1], + [2, 3], + [2] + ]); + }); + it('should use minimum row height for all section rows', async () => { dashboard.style.width = `${columnWidth}px`; setMinimumRowHeight(dashboard, 300); diff --git a/packages/dashboard/test/dashboard.test.ts b/packages/dashboard/test/dashboard.test.ts index 3fc85a7981..6bad6d5dc2 100644 --- a/packages/dashboard/test/dashboard.test.ts +++ b/packages/dashboard/test/dashboard.test.ts @@ -111,6 +111,24 @@ describe('dashboard', () => { }); }); + describe('row span', () => { + it('should span one row by default', () => { + dashboard.style.width = `${columnWidth}px`; + const widgets = [getElementFromCell(dashboard, 0, 0), getElementFromCell(dashboard, 1, 0)]; + expect(widgets[0]).to.not.equal(widgets[1]); + }); + + it('should span multiple rows', async () => { + dashboard.style.width = `${columnWidth}px`; + dashboard.items = [{ rowspan: 2, id: 'Item 0' }]; + await nextFrame(); + + const widget = getElementFromCell(dashboard, 0, 0); + expect(widget).to.have.property('widgetTitle', 'Item 0 title'); + expect(getElementFromCell(dashboard, 1, 0)).to.equal(widget); + }); + }); + describe('section', () => { beforeEach(async () => { dashboard.items = [ diff --git a/packages/dashboard/test/helpers.ts b/packages/dashboard/test/helpers.ts index f6728340ed..1e8b53deb0 100644 --- a/packages/dashboard/test/helpers.ts +++ b/packages/dashboard/test/helpers.ts @@ -95,6 +95,13 @@ export function setColspan(element: HTMLElement, colspan?: number): void { element.style.setProperty('--vaadin-dashboard-item-colspan', colspan !== undefined ? `${colspan}` : null); } +/** + * Sets the row span of the element + */ +export function setRowspan(element: HTMLElement, rowspan?: number): void { + element.style.setProperty('--vaadin-dashboard-item-rowspan', rowspan !== undefined ? `${rowspan}` : null); +} + /** * Sets the gap between the cells of the dashboard. */ diff --git a/packages/dashboard/test/typings/dashboard.types.ts b/packages/dashboard/test/typings/dashboard.types.ts index 6e61a5c9c7..0489bebbb5 100644 --- a/packages/dashboard/test/typings/dashboard.types.ts +++ b/packages/dashboard/test/typings/dashboard.types.ts @@ -24,6 +24,11 @@ interface TestDashboardItem extends DashboardItem { const genericDashboard = document.createElement('vaadin-dashboard'); assertType(genericDashboard); +assertType<{ colspan?: number; rowspan?: number }>(genericDashboard.items[0] as DashboardItem); +assertType<{ items: DashboardItem[]; title?: string | null }>( + genericDashboard.items[0] as DashboardSectionItem, +); + assertType(genericDashboard); assertType(genericDashboard); assertType> | null | undefined>(genericDashboard.items); @@ -34,8 +39,8 @@ assertType>(narrowedDashboard); assertType>>(narrowedDashboard.items); assertType | null | undefined>(narrowedDashboard.renderer); assertType< - | { colspan?: number; testProperty: string } - | { title?: string | null; items: Array<{ colspan?: number; testProperty: string }> } + | { colspan?: number; rowspan?: number; testProperty: string } + | { title?: string | null; items: Array<{ colspan?: number; rowspan?: number; testProperty: string }> } >(narrowedDashboard.items[0]); narrowedDashboard.addEventListener('dashboard-item-reorder-start', (event) => {