Skip to content

Commit a51684e

Browse files
authored
feat: dashboard widget rowspan (#7781)
1 parent a590b1b commit a51684e

11 files changed

+93
-3
lines changed

dev/dashboard-layout.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
</vaadin-dashboard-widget>
6060

6161
<vaadin-dashboard-section section-title="Section">
62-
<vaadin-dashboard-widget widget-title="Sales closed this month">
62+
<vaadin-dashboard-widget style="--vaadin-dashboard-item-rowspan: 2" widget-title="Sales closed this month">
6363
<div class="kpi-number">54 000€</div>
6464
</vaadin-dashboard-widget>
6565

dev/dashboard.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
items: [
6363
{
6464
title: 'Sales closed this month',
65+
rowspan: 2,
6566
content: '54 000€',
6667
type: 'kpi',
6768
},

packages/dashboard/src/vaadin-dashboard-layout-mixin.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,18 @@ export const DashboardLayoutMixin = (superClass) =>
7272
}
7373
7474
::slotted(*) {
75+
/* The grid-column value applied to children */
7576
--_vaadin-dashboard-item-column: span
7677
min(
7778
var(--vaadin-dashboard-item-colspan, 1),
7879
var(--_vaadin-dashboard-effective-col-count, var(--_vaadin-dashboard-col-count))
7980
);
8081
8182
grid-column: var(--_vaadin-dashboard-item-column);
83+
84+
/* The grid-row value applied to children */
85+
--_vaadin-dashboard-item-row: span var(--vaadin-dashboard-item-rowspan, 1);
86+
grid-row: var(--_vaadin-dashboard-item-row);
8287
}
8388
`;
8489
}

packages/dashboard/src/vaadin-dashboard-section.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ class DashboardSection extends ControllerMixin(ElementMixin(PolylitMixin(LitElem
6666
);
6767
6868
grid-column: var(--_vaadin-dashboard-item-column);
69+
--_vaadin-dashboard-item-row: span var(--vaadin-dashboard-item-rowspan, 1);
70+
grid-row: var(--_vaadin-dashboard-item-row);
6971
}
7072
7173
header {

packages/dashboard/src/vaadin-dashboard-widget.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class DashboardWidget extends ControllerMixin(ElementMixin(PolylitMixin(LitEleme
3737
display: flex;
3838
flex-direction: column;
3939
grid-column: var(--_vaadin-dashboard-item-column);
40+
grid-row: var(--_vaadin-dashboard-item-row);
4041
position: relative;
4142
}
4243

packages/dashboard/src/vaadin-dashboard.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ export interface DashboardItem {
1818
* The column span of the item
1919
*/
2020
colspan?: number;
21+
22+
/**
23+
* The row span of the item
24+
*/
25+
rowspan?: number;
2126
}
2227

2328
export interface DashboardSectionItem<TItem extends DashboardItem> {

packages/dashboard/src/vaadin-dashboard.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ class Dashboard extends ControllerMixin(DashboardLayoutMixin(ElementMixin(Themab
138138
const itemDragged = this.__widgetReorderController.draggedItem === item;
139139
const style = `
140140
${item.colspan ? `--vaadin-dashboard-item-colspan: ${item.colspan};` : ''}
141+
${item.rowspan ? `--vaadin-dashboard-item-rowspan: ${item.rowspan};` : ''}
141142
${itemDragged ? '--_vaadin-dashboard-item-placeholder-display: block;' : ''}
142143
`.trim();
143144

packages/dashboard/test/dashboard-layout.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
setMaximumColumnWidth,
1616
setMinimumColumnWidth,
1717
setMinimumRowHeight,
18+
setRowspan,
1819
} from './helpers.js';
1920

2021
describe('dashboard layout', () => {
@@ -261,6 +262,36 @@ describe('dashboard layout', () => {
261262
});
262263
});
263264

265+
describe('row span', () => {
266+
it('should span multiple rows', async () => {
267+
setMinimumRowHeight(dashboard, 100);
268+
setRowspan(childElements[0], 2);
269+
await nextFrame();
270+
271+
/* prettier-ignore */
272+
expectLayout(dashboard, [
273+
[0, 1],
274+
[0],
275+
]);
276+
});
277+
278+
it('should span multiple rows on a single column', async () => {
279+
setMinimumRowHeight(dashboard, 100);
280+
setRowspan(childElements[0], 2);
281+
await nextFrame();
282+
283+
dashboard.style.width = `${columnWidth}px`;
284+
await nextFrame();
285+
286+
/* prettier-ignore */
287+
expectLayout(dashboard, [
288+
[0],
289+
[0],
290+
[1],
291+
]);
292+
});
293+
});
294+
264295
describe('gap', () => {
265296
it('should have a default gap', () => {
266297
// Clear the gap used in the tests
@@ -428,6 +459,20 @@ describe('dashboard layout', () => {
428459
]);
429460
});
430461

462+
it('should span multiple rows inside a section', async () => {
463+
// Using a minimum row height here causes Firefox to crash, disabling for now
464+
// setMinimumRowHeight(dashboard, 100);
465+
setRowspan(childElements[2], 2);
466+
await nextFrame();
467+
468+
/* prettier-ignore */
469+
expectLayout(dashboard, [
470+
[0, 1],
471+
[2, 3],
472+
[2]
473+
]);
474+
});
475+
431476
it('should use minimum row height for all section rows', async () => {
432477
dashboard.style.width = `${columnWidth}px`;
433478
setMinimumRowHeight(dashboard, 300);

packages/dashboard/test/dashboard.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,24 @@ describe('dashboard', () => {
111111
});
112112
});
113113

114+
describe('row span', () => {
115+
it('should span one row by default', () => {
116+
dashboard.style.width = `${columnWidth}px`;
117+
const widgets = [getElementFromCell(dashboard, 0, 0), getElementFromCell(dashboard, 1, 0)];
118+
expect(widgets[0]).to.not.equal(widgets[1]);
119+
});
120+
121+
it('should span multiple rows', async () => {
122+
dashboard.style.width = `${columnWidth}px`;
123+
dashboard.items = [{ rowspan: 2, id: 'Item 0' }];
124+
await nextFrame();
125+
126+
const widget = getElementFromCell(dashboard, 0, 0);
127+
expect(widget).to.have.property('widgetTitle', 'Item 0 title');
128+
expect(getElementFromCell(dashboard, 1, 0)).to.equal(widget);
129+
});
130+
});
131+
114132
describe('section', () => {
115133
beforeEach(async () => {
116134
dashboard.items = [

packages/dashboard/test/helpers.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ export function setColspan(element: HTMLElement, colspan?: number): void {
9595
element.style.setProperty('--vaadin-dashboard-item-colspan', colspan !== undefined ? `${colspan}` : null);
9696
}
9797

98+
/**
99+
* Sets the row span of the element
100+
*/
101+
export function setRowspan(element: HTMLElement, rowspan?: number): void {
102+
element.style.setProperty('--vaadin-dashboard-item-rowspan', rowspan !== undefined ? `${rowspan}` : null);
103+
}
104+
98105
/**
99106
* Sets the gap between the cells of the dashboard.
100107
*/

packages/dashboard/test/typings/dashboard.types.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ interface TestDashboardItem extends DashboardItem {
2424
const genericDashboard = document.createElement('vaadin-dashboard');
2525
assertType<Dashboard>(genericDashboard);
2626

27+
assertType<{ colspan?: number; rowspan?: number }>(genericDashboard.items[0] as DashboardItem);
28+
assertType<{ items: DashboardItem[]; title?: string | null }>(
29+
genericDashboard.items[0] as DashboardSectionItem<DashboardItem>,
30+
);
31+
2732
assertType<ElementMixinClass>(genericDashboard);
2833
assertType<DashboardLayoutMixinClass>(genericDashboard);
2934
assertType<Array<DashboardItem | DashboardSectionItem<DashboardItem>> | null | undefined>(genericDashboard.items);
@@ -34,8 +39,8 @@ assertType<Dashboard<TestDashboardItem>>(narrowedDashboard);
3439
assertType<Array<TestDashboardItem | DashboardSectionItem<TestDashboardItem>>>(narrowedDashboard.items);
3540
assertType<DashboardRenderer<TestDashboardItem> | null | undefined>(narrowedDashboard.renderer);
3641
assertType<
37-
| { colspan?: number; testProperty: string }
38-
| { title?: string | null; items: Array<{ colspan?: number; testProperty: string }> }
42+
| { colspan?: number; rowspan?: number; testProperty: string }
43+
| { title?: string | null; items: Array<{ colspan?: number; rowspan?: number; testProperty: string }> }
3944
>(narrowedDashboard.items[0]);
4045

4146
narrowedDashboard.addEventListener('dashboard-item-reorder-start', (event) => {

0 commit comments

Comments
 (0)