Skip to content

Commit 73c9d6b

Browse files
authored
feat: vaadin-dashboard component (#7946)
2 parents 738ca00 + d1584a3 commit 73c9d6b

File tree

55 files changed

+7839
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+7839
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ The components below are licensed under [Vaadin Commercial License and Service T
136136
| [`<vaadin-charts>`](https://github.com/vaadin/web-components/tree/main/packages/charts) | [![npm version](https://badgen.net/npm/v/@vaadin/charts)](https://www.npmjs.com/package/@vaadin/charts) | [![npm version](https://badgen.net/npm/v/@vaadin/charts/next)](https://www.npmjs.com/package/@vaadin/charts/v/next) | [Issues](https://github.com/vaadin/web-components/labels/vaadin-charts) |
137137
| [`<vaadin-cookie-consent>`](https://github.com/vaadin/web-components/tree/main/packages/cookie-consent) | [![npm version](https://badgen.net/npm/v/@vaadin/cookie-consent)](https://www.npmjs.com/package/@vaadin/cookie-consent) | [![npm version](https://badgen.net/npm/v/@vaadin/cookie-consent/next)](https://www.npmjs.com/package/@vaadin/cookie-consent/v/next) | [Issues](https://github.com/vaadin/web-components/labels/vaadin-cookie-consent) |
138138
| [`<vaadin-crud>`](https://github.com/vaadin/web-components/tree/main/packages/crud) | [![npm version](https://badgen.net/npm/v/@vaadin/crud)](https://www.npmjs.com/package/@vaadin/crud) | [![npm version](https://badgen.net/npm/v/@vaadin/crud/next)](https://www.npmjs.com/package/@vaadin/crud/v/next) | [Issues](https://github.com/vaadin/web-components/labels/vaadin-crud) |
139+
| [`<vaadin-dashboard>`](https://github.com/vaadin/web-components/tree/main/packages/dashboard) | [![npm version](https://badgen.net/npm/v/@vaadin/dashboard)](https://www.npmjs.com/package/@vaadin/dashboard) | [![npm version](https://badgen.net/npm/v/@vaadin/dashboard/next)](https://www.npmjs.com/package/@vaadin/dashboard/v/next) | [Issues](https://github.com/vaadin/web-components/labels/vaadin-dashboard) |
139140
| [`<vaadin-grid-pro>`](https://github.com/vaadin/web-components/tree/main/packages/grid-pro) | [![npm version](https://badgen.net/npm/v/@vaadin/grid-pro)](https://www.npmjs.com/package/@vaadin/grid-pro) | [![npm version](https://badgen.net/npm/v/@vaadin/grid-pro/next)](https://www.npmjs.com/package/@vaadin/grid-pro/v/next) | [Issues](https://github.com/vaadin/web-components/labels/vaadin-grid-pro) |
140141
| [`<vaadin-map>`](https://github.com/vaadin/web-components/tree/main/packages/map) | [![npm version](https://badgen.net/npm/v/@vaadin/map)](https://www.npmjs.com/package/@vaadin/map) | [![npm version](https://badgen.net/npm/v/@vaadin/map/next)](https://www.npmjs.com/package/@vaadin/map/v/next) | [Issues](https://github.com/vaadin/web-components/labels/vaadin-map) |
141142
| [`<vaadin-rich-text-editor>`](https://github.com/vaadin/web-components/tree/main/packages/rich-text-editor) | [![npm version](https://badgen.net/npm/v/@vaadin/rich-text-editor)](https://www.npmjs.com/package/@vaadin/rich-text-editor) | [![npm version](https://badgen.net/npm/v/@vaadin/rich-text-editor/next)](https://www.npmjs.com/package/@vaadin/rich-text-editor/v/next) | [Issues](https://github.com/vaadin/web-components/labels/vaadin-rich-text-editor) |

dev/dashboard-layout.html

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Dashboard layout</title>
8+
<script type="module" src="./common.js"></script>
9+
10+
<script type="module">
11+
import '@vaadin/dashboard/vaadin-dashboard-layout.js';
12+
import '@vaadin/dashboard/vaadin-dashboard-widget.js';
13+
import '@vaadin/dashboard/vaadin-dashboard-section.js';
14+
</script>
15+
16+
<style>
17+
vaadin-dashboard-layout {
18+
--vaadin-dashboard-col-min-width: 300px;
19+
--vaadin-dashboard-col-max-width: 500px;
20+
--vaadin-dashboard-row-min-height: 300px;
21+
--vaadin-dashboard-col-max-count: 3;
22+
}
23+
24+
.kpi-number {
25+
font-size: 80px;
26+
font-weight: bold;
27+
color: #4caf50;
28+
height: 100%;
29+
display: flex;
30+
align-items: center;
31+
justify-content: center;
32+
}
33+
34+
.chart {
35+
height: 300px;
36+
background: repeating-linear-gradient(45deg, #e0e0e0, #e0e0e0 10px, #f5f5f5 10px, #f5f5f5 20px);
37+
}
38+
</style>
39+
</head>
40+
41+
<body>
42+
<vaadin-dashboard-layout>
43+
<vaadin-dashboard-widget widget-title="Total cost">
44+
<span slot="header-content">2023-2024</span>
45+
<div class="kpi-number">+203%</div>
46+
</vaadin-dashboard-widget>
47+
48+
<vaadin-dashboard-widget style="--vaadin-dashboard-item-colspan: 2" widget-title="Sales">
49+
<span slot="header-content">2023-2024</span>
50+
<div class="chart"></div>
51+
</vaadin-dashboard-widget>
52+
53+
<vaadin-dashboard-section section-title="Section">
54+
<vaadin-dashboard-widget style="--vaadin-dashboard-item-rowspan: 2" widget-title="Sales closed this month">
55+
<div class="kpi-number">54 000€</div>
56+
</vaadin-dashboard-widget>
57+
58+
<vaadin-dashboard-widget widget-title="Just some number">
59+
<span slot="header-content">2014-2024</span>
60+
<div class="kpi-number">1234</div>
61+
</vaadin-dashboard-widget>
62+
</vaadin-dashboard-section>
63+
64+
<vaadin-dashboard-widget>
65+
<h2 slot="title">Activity since 2023</h2>
66+
<div class="chart"></div>
67+
</vaadin-dashboard-widget>
68+
</vaadin-dashboard-layout>
69+
</body>
70+
</html>

dev/dashboard.html

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7+
<title>Dashboard</title>
8+
<script type="module" src="./common.js"></script>
9+
10+
<style>
11+
vaadin-dashboard {
12+
--vaadin-dashboard-col-min-width: 300px;
13+
--vaadin-dashboard-col-max-width: 500px;
14+
--vaadin-dashboard-row-min-height: 300px;
15+
--vaadin-dashboard-col-max-count: 3;
16+
}
17+
18+
.kpi-number {
19+
font-size: 80px;
20+
font-weight: bold;
21+
color: #4caf50;
22+
height: 100%;
23+
display: flex;
24+
align-items: center;
25+
justify-content: center;
26+
}
27+
28+
.chart {
29+
height: 100%;
30+
background: repeating-linear-gradient(45deg, #e0e0e0, #e0e0e0 10px, #f5f5f5 10px, #f5f5f5 20px);
31+
}
32+
</style>
33+
34+
<script type="module">
35+
import '@vaadin/dashboard';
36+
37+
const dashboard = document.querySelector('vaadin-dashboard');
38+
39+
dashboard.items = [
40+
{
41+
title: 'Total cost',
42+
content: '+203%',
43+
type: 'kpi',
44+
header: '2023-2024',
45+
},
46+
{
47+
title: 'Sales',
48+
type: 'chart',
49+
header: '2023-2024',
50+
colspan: 2,
51+
},
52+
{
53+
title: 'Section',
54+
items: [
55+
{
56+
title: 'Sales closed this month',
57+
rowspan: 2,
58+
content: '54 000€',
59+
type: 'kpi',
60+
},
61+
{
62+
title: 'Just some number',
63+
content: '1234',
64+
type: 'kpi',
65+
header: '2014-2024',
66+
},
67+
],
68+
},
69+
{
70+
title: 'Activity since 2023',
71+
type: 'chart',
72+
},
73+
];
74+
75+
dashboard.renderer = (root, _dashboard, { item }) => {
76+
if (!root.firstElementChild) {
77+
root.append(document.createElement('vaadin-dashboard-widget'));
78+
}
79+
root.firstElementChild.widgetTitle = item.title;
80+
root.firstElementChild.innerHTML = `
81+
<span slot="header-content">${item.header || ''}</span>
82+
${item.type === 'chart' ? '<div class="chart"></div>' : `<div class="kpi-number">${item.content}</div>`}
83+
`;
84+
};
85+
86+
dashboard.addEventListener('dashboard-item-moved', (e) => {
87+
console.log('dashboard-item-moved', e.detail);
88+
});
89+
90+
dashboard.addEventListener('dashboard-item-resized', (e) => {
91+
console.log('dashboard-item-resized', e.detail);
92+
});
93+
94+
dashboard.addEventListener('dashboard-item-removed', (e) => {
95+
console.log('dashboard-item-removed', e.detail);
96+
});
97+
98+
dashboard.addEventListener('dashboard-item-selected-changed', (e) => {
99+
console.log('dashboard-item-selected-changed', e.detail);
100+
});
101+
102+
dashboard.addEventListener('dashboard-item-move-mode-changed', (e) => {
103+
console.log('dashboard-item-move-mode-changed', e.detail);
104+
});
105+
106+
dashboard.addEventListener('dashboard-item-resize-mode-changed', (e) => {
107+
console.log('dashboard-item-resize-mode-changed', e.detail);
108+
});
109+
</script>
110+
</head>
111+
112+
<body>
113+
<vaadin-dashboard editable></vaadin-dashboard>
114+
</body>
115+
</html>

packages/dashboard/LICENSE

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
This program is available under Vaadin Commercial License and Service Terms.
2+
See https://vaadin.com/commercial-license-and-service-terms for the full
3+
license.

packages/dashboard/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# @vaadin/dashboard
2+
3+
A responsive, grid-based dashboard layout component
4+
5+
> ℹ️&nbsp; A commercial Vaadin [subscription](https://vaadin.com/pricing) is required to use Dashboard in your project.
6+
7+
[Documentation + Live Demo ↗](https://vaadin.com/docs/latest/components/dashboard)
8+
9+
[![npm version](https://badgen.net/npm/v/@vaadin/dashboard)](https://www.npmjs.com/package/@vaadin/dashboard)
10+
11+
## Installation
12+
13+
Install the component:
14+
15+
```sh
16+
npm i @vaadin/dashboard
17+
```
18+
19+
Once installed, import the component in your application:
20+
21+
```js
22+
import '@vaadin/dashboard';
23+
```
24+
25+
## Contributing
26+
27+
Read the [contributing guide](https://vaadin.com/docs/latest/contributing) to learn about our development process, how to propose bugfixes and improvements, and how to test your changes to Vaadin components.
28+
29+
## License
30+
31+
This program is available under Vaadin Commercial License and Service Terms. For license terms, see LICENSE.
32+
33+
Vaadin collects usage statistics at development time to improve this product.
34+
For details and to opt-out, see https://github.com/vaadin/vaadin-usage-statistics.

packages/dashboard/package.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{
2+
"name": "@vaadin/dashboard",
3+
"version": "24.6.0-alpha0",
4+
"publishConfig": {
5+
"access": "public"
6+
},
7+
"description": "vaadin-dashboard",
8+
"license": "SEE LICENSE IN LICENSE",
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/vaadin/web-components.git",
12+
"directory": "packages/dashboard"
13+
},
14+
"author": "Vaadin Ltd",
15+
"homepage": "https://vaadin.com/components",
16+
"bugs": {
17+
"url": "https://github.com/vaadin/web-components/issues"
18+
},
19+
"main": "vaadin-dashboard.js",
20+
"module": "vaadin-dashboard.js",
21+
"type": "module",
22+
"files": [
23+
"src",
24+
"theme",
25+
"vaadin-*.d.ts",
26+
"vaadin-*.js",
27+
"web-types.json",
28+
"web-types.lit.json"
29+
],
30+
"keywords": [
31+
"Vaadin",
32+
"dashboard",
33+
"responsive",
34+
"layout",
35+
"web-components",
36+
"web-component"
37+
],
38+
"dependencies": {
39+
"@open-wc/dedupe-mixin": "^1.3.0",
40+
"@vaadin/button": "24.6.0-alpha0",
41+
"@vaadin/component-base": "24.6.0-alpha0",
42+
"@vaadin/vaadin-lumo-styles": "24.6.0-alpha0",
43+
"@vaadin/vaadin-material-styles": "24.6.0-alpha0",
44+
"@vaadin/vaadin-themable-mixin": "24.6.0-alpha0",
45+
"lit": "^3.0.0"
46+
},
47+
"devDependencies": {
48+
"@vaadin/chai-plugins": "24.6.0-alpha0",
49+
"@vaadin/testing-helpers": "^1.0.0"
50+
},
51+
"cvdlName": "vaadin-dashboard",
52+
"web-types": [
53+
"web-types.json",
54+
"web-types.lit.json"
55+
]
56+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* @license
3+
* Copyright (c) 2000 - 2024 Vaadin Ltd.
4+
*
5+
* This program is available under Vaadin Commercial License and Service Terms.
6+
*
7+
*
8+
* See https://vaadin.com/commercial-license-and-service-terms for the full
9+
* license.
10+
*/
11+
import { fireMove, fireRemove, fireResize } from './vaadin-dashboard-helpers.js';
12+
13+
/**
14+
* A controller for managing widget/section keyboard interactions.
15+
*/
16+
export class KeyboardController {
17+
constructor(host) {
18+
this.host = host;
19+
20+
host.addEventListener('focusout', (e) => this.__focusout(e));
21+
host.addEventListener('focusin', (e) => this.__focusin(e));
22+
host.addEventListener('keydown', (e) => this.__keydown(e));
23+
}
24+
25+
/** @private */
26+
__focusout(e) {
27+
const focusOutElement = e.composedPath()[0];
28+
const isHostVisible = !!this.host.offsetHeight;
29+
const isFocusButtonHidden = getComputedStyle(focusOutElement).display === 'none';
30+
if (isHostVisible && isFocusButtonHidden) {
31+
this.host.__focusApply();
32+
} else {
33+
this.host.__exitMode();
34+
this.host.__focused = false;
35+
this.host.__selected = false;
36+
}
37+
}
38+
39+
/** @private */
40+
__focusin(e) {
41+
if (e.target === this.host) {
42+
this.host.__focused = true;
43+
}
44+
}
45+
46+
/** @private */
47+
__keydown(e) {
48+
if (e.metaKey || e.ctrlKey || !this.host.__selected) {
49+
return;
50+
}
51+
52+
if (e.key === 'Backspace' || e.key === 'Delete') {
53+
this.__delete(e);
54+
} else if (e.key === 'Escape') {
55+
this.__escape(e);
56+
} else if (e.shiftKey && e.key.startsWith('Arrow')) {
57+
this.__resize(e);
58+
} else if (e.key.startsWith('Arrow')) {
59+
this.__move(e);
60+
}
61+
}
62+
63+
/** @private */
64+
__delete(e) {
65+
e.preventDefault();
66+
fireRemove(this.host);
67+
}
68+
69+
/** @private */
70+
__escape(e) {
71+
e.preventDefault();
72+
if (this.host.__moveMode || this.host.__resizeMode) {
73+
this.host.__exitMode(true);
74+
} else {
75+
this.host.__selected = false;
76+
this.host.focus();
77+
}
78+
}
79+
80+
/** @private */
81+
__resize(e) {
82+
const resizeMap = {
83+
ArrowRight: [document.dir === 'rtl' ? -1 : 1, 0],
84+
ArrowLeft: [document.dir === 'rtl' ? 1 : -1, 0],
85+
ArrowDown: [0, 1],
86+
ArrowUp: [0, -1],
87+
};
88+
if (resizeMap[e.key]) {
89+
e.preventDefault();
90+
fireResize(this.host, ...resizeMap[e.key]);
91+
}
92+
}
93+
94+
/** @private */
95+
__move(e) {
96+
const moveMap = {
97+
ArrowRight: document.dir === 'rtl' ? -1 : 1,
98+
ArrowLeft: document.dir === 'rtl' ? 1 : -1,
99+
ArrowDown: 1,
100+
ArrowUp: -1,
101+
};
102+
if (moveMap[e.key]) {
103+
e.preventDefault();
104+
fireMove(this.host, moveMap[e.key]);
105+
}
106+
}
107+
}

0 commit comments

Comments
 (0)