@vaadin/dashboard 24.6.0-beta1 → 24.7.0-alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/dashboard",
3
- "version": "24.6.0-beta1",
3
+ "version": "24.7.0-alpha1",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -37,15 +37,15 @@
37
37
  ],
38
38
  "dependencies": {
39
39
  "@open-wc/dedupe-mixin": "^1.3.0",
40
- "@vaadin/button": "24.6.0-beta1",
41
- "@vaadin/component-base": "24.6.0-beta1",
42
- "@vaadin/vaadin-lumo-styles": "24.6.0-beta1",
43
- "@vaadin/vaadin-material-styles": "24.6.0-beta1",
44
- "@vaadin/vaadin-themable-mixin": "24.6.0-beta1",
40
+ "@vaadin/button": "24.7.0-alpha1",
41
+ "@vaadin/component-base": "24.7.0-alpha1",
42
+ "@vaadin/vaadin-lumo-styles": "24.7.0-alpha1",
43
+ "@vaadin/vaadin-material-styles": "24.7.0-alpha1",
44
+ "@vaadin/vaadin-themable-mixin": "24.7.0-alpha1",
45
45
  "lit": "^3.0.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@vaadin/chai-plugins": "24.6.0-beta1",
48
+ "@vaadin/chai-plugins": "24.7.0-alpha1",
49
49
  "@vaadin/testing-helpers": "^1.0.0"
50
50
  },
51
51
  "cvdlName": "vaadin-dashboard",
@@ -53,5 +53,5 @@
53
53
  "web-types.json",
54
54
  "web-types.lit.json"
55
55
  ],
56
- "gitHead": "ab28efb0dcf2cd1ef72100e2e8f32232fa49aacc"
56
+ "gitHead": "04be941c9a7b659871c97f31b9cc3ffd7528087b"
57
57
  }
@@ -18,7 +18,6 @@ export class KeyboardController {
18
18
  this.host = host;
19
19
 
20
20
  host.addEventListener('focusout', (e) => this.__focusout(e));
21
- host.addEventListener('focusin', (e) => this.__focusin(e));
22
21
  host.addEventListener('keydown', (e) => this.__keydown(e));
23
22
  }
24
23
 
@@ -36,13 +35,6 @@ export class KeyboardController {
36
35
  }
37
36
  }
38
37
 
39
- /** @private */
40
- __focusin(e) {
41
- if (e.target === this.host) {
42
- this.host.__focused = true;
43
- }
44
- }
45
-
46
38
  /** @private */
47
39
  __keydown(e) {
48
40
  if (e.metaKey || e.ctrlKey || !this.host.__selected) {
@@ -132,8 +132,19 @@ export const DashboardItemMixin = (superClass) =>
132
132
  aria-label=${this.__i18n[i18nSelectTitleForEditingProperty]}
133
133
  aria-describedby="title"
134
134
  aria-pressed="${!!this.__selected}"
135
+ @focus="${() => {
136
+ this.__focused = true;
137
+ }}"
138
+ @blur="${() => {
139
+ this.__focused = false;
140
+ }}"
135
141
  @click="${() => {
136
- this.__selected = true;
142
+ const wasSelected = this.__selected;
143
+ this.__selected = !wasSelected;
144
+ this.__focused = wasSelected;
145
+ if (this.__selected) {
146
+ this.$['drag-handle'].focus();
147
+ }
137
148
  }}"
138
149
  ></button>
139
150
  </label>`;
@@ -24,6 +24,7 @@ export const DashboardLayoutMixin = (superClass) =>
24
24
  :host {
25
25
  display: block;
26
26
  overflow: hidden;
27
+ width: 100%;
27
28
  }
28
29
 
29
30
  :host([hidden]) {
@@ -36,12 +37,19 @@ export const DashboardLayoutMixin = (superClass) =>
36
37
 
37
38
  #grid {
38
39
  box-sizing: border-box;
39
- --_vaadin-dashboard-default-spacing: 1rem;
40
- --_vaadin-dashboard-spacing: max(
40
+
41
+ /* Padding around dashboard edges */
42
+ --_vaadin-dashboard-default-padding: 1rem;
43
+ --_vaadin-dashboard-padding: max(
41
44
  0px,
42
- var(--vaadin-dashboard-spacing, var(--_vaadin-dashboard-default-spacing))
45
+ var(--vaadin-dashboard-padding, var(--_vaadin-dashboard-default-padding))
43
46
  );
44
- padding: var(--_vaadin-dashboard-spacing);
47
+ padding: var(--_vaadin-dashboard-padding);
48
+
49
+ /* Gap between widgets */
50
+ --_vaadin-dashboard-default-gap: 1rem;
51
+ --_vaadin-dashboard-gap: max(0px, var(--vaadin-dashboard-gap, var(--_vaadin-dashboard-default-gap)));
52
+ gap: var(--_vaadin-dashboard-gap);
45
53
 
46
54
  /* Default min and max column widths */
47
55
  --_vaadin-dashboard-default-col-min-width: 25rem;
@@ -86,8 +94,6 @@ export const DashboardLayoutMixin = (superClass) =>
86
94
  );
87
95
 
88
96
  grid-auto-rows: var(--_vaadin-dashboard-row-height);
89
-
90
- gap: var(--_vaadin-dashboard-spacing);
91
97
  }
92
98
 
93
99
  ::slotted(*) {
@@ -35,7 +35,8 @@ import { DashboardLayoutMixin } from './vaadin-dashboard-layout-mixin.js';
35
35
  * `--vaadin-dashboard-col-max-width` | maximum column width of the layout
36
36
  * `--vaadin-dashboard-row-min-height` | minimum row height of the layout
37
37
  * `--vaadin-dashboard-col-max-count` | maximum column count of the layout
38
- * `--vaadin-dashboard-spacing` | spacing between child elements and space around its outer edges. Must be in length units (0 is not allowed, 0px is)
38
+ * `--vaadin-dashboard-gap` | gap between child elements. Must be in length units (0 is not allowed, 0px is)
39
+ * `--vaadin-dashboard-padding` | space around the dashboard's outer edges. Must be in length units (0 is not allowed, 0px is)
39
40
  *
40
41
  * The following state attributes are available for styling:
41
42
  *
@@ -38,7 +38,8 @@ import { DashboardLayoutMixin } from './vaadin-dashboard-layout-mixin.js';
38
38
  * `--vaadin-dashboard-col-max-width` | maximum column width of the layout
39
39
  * `--vaadin-dashboard-row-min-height` | minimum row height of the layout
40
40
  * `--vaadin-dashboard-col-max-count` | maximum column count of the layout
41
- * `--vaadin-dashboard-spacing` | spacing between child elements and space around its outer edges. Must be in length units (0 is not allowed, 0px is)
41
+ * `--vaadin-dashboard-gap` | gap between child elements. Must be in length units (0 is not allowed, 0px is)
42
+ * `--vaadin-dashboard-padding` | space around the dashboard's outer edges. Must be in length units (0 is not allowed, 0px is)
42
43
  *
43
44
  * The following state attributes are available for styling:
44
45
  *
@@ -87,7 +87,7 @@ class DashboardSection extends DashboardItemMixin(ElementMixin(ThemableMixin(Pol
87
87
  grid-template-columns: subgrid;
88
88
  --_vaadin-dashboard-section-column: 1 / calc(var(--_vaadin-dashboard-effective-col-count) + 1);
89
89
  grid-column: var(--_vaadin-dashboard-section-column) !important;
90
- gap: var(--_vaadin-dashboard-spacing, 1rem);
90
+ gap: var(--_vaadin-dashboard-gap, 1rem);
91
91
  /* Dashboard section header height */
92
92
  --_vaadin-dashboard-section-header-height: minmax(0, auto);
93
93
  grid-template-rows: var(--_vaadin-dashboard-section-header-height) repeat(
@@ -179,9 +179,11 @@ class DashboardSection extends DashboardItemMixin(ElementMixin(ThemableMixin(Pol
179
179
  /** @protected */
180
180
  render() {
181
181
  return html`
182
- ${this.__renderFocusButton('selectSection')} ${this.__renderMoveControls()}
182
+ ${this.__renderMoveControls()}
183
183
 
184
184
  <div id="focustrap">
185
+ ${this.__renderFocusButton('selectSection')}
186
+
185
187
  <header part="header">
186
188
  ${this.__renderDragHandle()}
187
189
  <h2 id="title" part="title">${this.sectionTitle}</h2>
@@ -139,11 +139,11 @@ class DashboardWidget extends DashboardItemMixin(ElementMixin(ThemableMixin(Poly
139
139
  content: '';
140
140
  z-index: 2;
141
141
  position: absolute;
142
- inset-inline-start: 0;
143
- top: 0;
142
+ top: -1px;
144
143
  width: var(--_vaadin-dashboard-widget-resizer-width, 0);
145
144
  height: var(--_vaadin-dashboard-widget-resizer-height, 0);
146
145
  background: rgba(0, 0, 0, 0.1);
146
+ border-radius: inherit;
147
147
  }
148
148
  `,
149
149
  super.styles,
@@ -209,9 +209,11 @@ class DashboardWidget extends DashboardItemMixin(ElementMixin(ThemableMixin(Poly
209
209
  /** @protected */
210
210
  render() {
211
211
  return html`
212
- ${this.__renderFocusButton('selectWidget')} ${this.__renderMoveControls()} ${this.__renderResizeControls()}
212
+ ${this.__renderMoveControls()} ${this.__renderResizeControls()}
213
213
 
214
214
  <div id="focustrap">
215
+ ${this.__renderFocusButton('selectWidget')}
216
+
215
217
  <header part="header">
216
218
  ${this.__renderDragHandle()}
217
219
  ${this.__nestedHeadingLevel
@@ -196,7 +196,8 @@ export interface DashboardI18n {
196
196
  * `--vaadin-dashboard-col-max-width` | maximum column width of the dashboard
197
197
  * `--vaadin-dashboard-row-min-height` | minimum row height of the dashboard
198
198
  * `--vaadin-dashboard-col-max-count` | maximum column count of the dashboard
199
- * `--vaadin-dashboard-spacing` | spacing between child elements and space around its outer edges. Must be in length units (0 is not allowed, 0px is)
199
+ * `--vaadin-dashboard-gap` | gap between child elements. Must be in length units (0 is not allowed, 0px is)
200
+ * `--vaadin-dashboard-padding` | space around the dashboard's outer edges. Must be in length units (0 is not allowed, 0px is)
200
201
  *
201
202
  * The following state attributes are available for styling:
202
203
  *
@@ -76,7 +76,8 @@ import { WidgetResizeController } from './widget-resize-controller.js';
76
76
  * `--vaadin-dashboard-col-max-width` | maximum column width of the dashboard
77
77
  * `--vaadin-dashboard-row-min-height` | minimum row height of the dashboard
78
78
  * `--vaadin-dashboard-col-max-count` | maximum column count of the dashboard
79
- * `--vaadin-dashboard-spacing` | spacing between child elements and space around its outer edges. Must be in length units (0 is not allowed, 0px is)
79
+ * `--vaadin-dashboard-gap` | gap between child elements. Must be in length units (0 is not allowed, 0px is)
80
+ * `--vaadin-dashboard-padding` | space around the dashboard's outer edges. Must be in length units (0 is not allowed, 0px is)
80
81
  *
81
82
  * The following state attributes are available for styling:
82
83
  *
@@ -258,7 +259,7 @@ class Dashboard extends DashboardLayoutMixin(ElementMixin(ThemableMixin(PolylitM
258
259
  let wrappers = [...hostElement.children].filter((el) => el.localName === WRAPPER_LOCAL_NAME);
259
260
  let previousWrapper = null;
260
261
 
261
- const focusedWrapper = wrappers.find((wrapper) => wrapper.querySelector('[focused]'));
262
+ const focusedWrapper = wrappers.find((wrapper) => wrapper.querySelector(':focus'));
262
263
  const focusedWrapperWillBeRemoved = focusedWrapper && !this.__isActiveWrapper(focusedWrapper);
263
264
  const wrapperClosestToRemovedFocused =
264
265
  focusedWrapperWillBeRemoved && this.__getClosestActiveWrapper(focusedWrapper);
@@ -271,7 +272,7 @@ class Dashboard extends DashboardLayoutMixin(ElementMixin(ThemableMixin(PolylitM
271
272
  // Update the wrapper style
272
273
  this.__updateWrapper(wrapper, item);
273
274
 
274
- if (!wrapper.contains(document.activeElement)) {
275
+ if (wrapper !== focusedWrapper) {
275
276
  if (previousWrapper) {
276
277
  // Append the wrapper after the previous one if it's not already there
277
278
  if (wrapper.previousElementSibling !== previousWrapper) {
@@ -319,7 +320,7 @@ class Dashboard extends DashboardLayoutMixin(ElementMixin(ThemableMixin(PolylitM
319
320
  this.__focusWrapperContent(wrapperClosestToRemovedFocused || this.querySelector(WRAPPER_LOCAL_NAME));
320
321
  }
321
322
 
322
- const focusedItem = this.querySelector('[focused]');
323
+ const focusedItem = this.querySelector(':focus');
323
324
  if (focusedItem && this.__outsideViewport(focusedItem)) {
324
325
  // If the focused wrapper is not in the viewport, scroll it into view
325
326
  focusedItem.scrollIntoView();
@@ -89,10 +89,10 @@ export class WidgetResizeController {
89
89
 
90
90
  const currentElementHeight = itemWrapper.firstElementChild.offsetHeight;
91
91
  const rowMinHeight = Math.min(...gridStyle.gridTemplateRows.split(' ').map((height) => parseFloat(height)));
92
- if (this.__resizeHeight > currentElementHeight + gapSize + rowMinHeight / 2) {
92
+ if (e.detail.ddy > 0 && this.__resizeHeight > currentElementHeight + gapSize + rowMinHeight / 2) {
93
93
  // Resized vertically above the half of the next row, increase rowspan
94
94
  this.__updateResizedItem(0, 1);
95
- } else if (this.__resizeHeight < currentElementHeight - rowMinHeight / 2) {
95
+ } else if (e.detail.ddy < 0 && this.__resizeHeight < currentElementHeight - rowMinHeight / 2) {
96
96
  // Resized vertically below the half of the current row, decrease rowspan
97
97
  this.__updateResizedItem(0, -1);
98
98
  }
@@ -2,7 +2,8 @@ import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themab
2
2
 
3
3
  export const dashboardLayoutStyles = css`
4
4
  #grid {
5
- --_vaadin-dashboard-default-spacing: var(--lumo-space-l);
5
+ --_vaadin-dashboard-default-gap: var(--lumo-space-m);
6
+ --_vaadin-dashboard-default-padding: var(--lumo-space-m);
6
7
  }
7
8
  `;
8
9
 
@@ -7,14 +7,78 @@ import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themab
7
7
  import { dashboardWidgetAndSection } from './vaadin-dashboard-widget-styles.js';
8
8
 
9
9
  const section = css`
10
+ /* stylelint-disable rule-empty-line-before */
11
+
10
12
  :host {
11
- --_focus-ring-spacing-max-offset: calc(var(--_vaadin-dashboard-spacing) / 2);
13
+ --_section-outline-offset: calc(min(var(--_vaadin-dashboard-gap), var(--_vaadin-dashboard-padding)) / 3);
14
+ --_focus-ring-offset: calc((var(--_section-outline-offset) - var(--_focus-ring-width)));
15
+ border-radius: var(--lumo-border-radius-l);
16
+ }
17
+
18
+ header {
19
+ margin-bottom: calc(-1 * var(--_section-outline-offset));
20
+ line-height: var(--lumo-line-height-s);
21
+ padding-inline: var(--lumo-space-s);
22
+ min-height: var(--lumo-size-l);
23
+ }
24
+
25
+ [part='title'] {
26
+ font-size: var(--lumo-font-size-xl);
27
+ font-weight: 600;
28
+ }
29
+
30
+ /* Section states */
31
+
32
+ :host([editable]) {
33
+ outline: 1px solid var(--lumo-contrast-10pct);
34
+ outline-offset: calc(var(--_section-outline-offset) - 1px);
35
+ background: var(--lumo-contrast-5pct);
36
+ box-shadow: 0 0 0 var(--_section-outline-offset) var(--lumo-contrast-5pct);
37
+ }
38
+ :host([editable]) header {
39
+ padding-inline: var(--lumo-space-xs);
40
+ }
41
+
42
+ :host([focused])::after {
43
+ content: '';
44
+ display: block;
45
+ position: absolute;
46
+ inset: 0;
47
+ border-radius: var(--lumo-border-radius-l);
48
+ z-index: 9;
49
+ outline: var(--_focus-ring-width) solid var(--_focus-ring-color);
50
+ outline-offset: var(--_focus-ring-offset);
51
+ }
52
+
53
+ :host([selected]) {
54
+ background: var(--lumo-primary-color-10pct);
55
+ box-shadow: 0 0 0 var(--_section-outline-offset) var(--lumo-primary-color-10pct);
56
+ }
57
+ :host([selected]:not([focused])) {
58
+ outline-color: var(--lumo-primary-color-50pct);
12
59
  }
13
60
 
14
61
  :host([move-mode]) ::slotted(*) {
15
62
  --_vaadin-dashboard-widget-opacity: 0.3;
16
63
  --_vaadin-dashboard-widget-filter: blur(10px);
17
64
  }
65
+
66
+ :host([dragging]) {
67
+ background: var(--vaadin-dashboard-drop-target-background-color);
68
+ outline: var(--vaadin-dashboard-drop-target-border);
69
+ box-shadow: 0 0 0 var(--_section-outline-offset) var(--vaadin-dashboard-drop-target-background-color);
70
+ }
71
+
72
+ /* Accessible move mode controls */
73
+
74
+ [part~='move-backward-button'] {
75
+ inset-inline-start: calc(-1 * var(--_section-outline-offset));
76
+ }
77
+
78
+ [part~='move-forward-button'] {
79
+ inset-inline-end: calc(-1 * var(--_section-outline-offset));
80
+ transform: translateY(-50%);
81
+ }
18
82
  `;
19
83
 
20
84
  registerStyles('vaadin-dashboard-section', [dashboardWidgetAndSection, section], {
@@ -4,123 +4,115 @@ import '@vaadin/vaadin-lumo-styles/spacing.js';
4
4
  import '@vaadin/vaadin-lumo-styles/style.js';
5
5
  import '@vaadin/vaadin-lumo-styles/typography.js';
6
6
  import '@vaadin/vaadin-lumo-styles/font-icons.js';
7
+ import { addGlobalThemeStyles } from '@vaadin/vaadin-themable-mixin/register-styles';
7
8
  import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
8
9
 
10
+ /* Global styles */
11
+ const dashboardWidgetProps = css`
12
+ html {
13
+ --vaadin-dashboard-widget-background: var(--lumo-base-color);
14
+ --vaadin-dashboard-widget-border-radius: var(--lumo-border-radius-l);
15
+ --vaadin-dashboard-widget-border-width: 1px;
16
+ --vaadin-dashboard-widget-border-color: var(--lumo-contrast-20pct);
17
+ --vaadin-dashboard-widget-shadow: 0 0 0 0 transparent;
18
+ --vaadin-dashboard-widget-editable-shadow: var(--lumo-box-shadow-s);
19
+ --vaadin-dashboard-widget-selected-shadow: 0 2px 4px -1px var(--lumo-primary-color-10pct),
20
+ 0 3px 12px -1px var(--lumo-primary-color-50pct);
21
+ --vaadin-dashboard-drop-target-background-color: var(--lumo-primary-color-10pct);
22
+ --vaadin-dashboard-drop-target-border: 1px dashed var(--lumo-primary-color-50pct);
23
+ }
24
+ `;
25
+ addGlobalThemeStyles('dashboard-widget-props', dashboardWidgetProps);
26
+
27
+ /* Styles shared between widgets and sections */
9
28
  const dashboardWidgetAndSection = css`
29
+ /* stylelint-disable rule-empty-line-before */
30
+ /* stylelint-disable length-zero-no-unit */
31
+
10
32
  :host {
11
- border-radius: var(--lumo-border-radius-l);
12
33
  color: var(--lumo-body-text-color);
13
34
  font-family: var(--lumo-font-family);
14
35
  font-size: var(--lumo-font-size-m);
15
36
  line-height: var(--lumo-line-height-m);
16
37
  --_focus-ring-color: var(--vaadin-focus-ring-color, var(--lumo-primary-color-50pct));
17
38
  --_focus-ring-width: var(--vaadin-focus-ring-width, 2px);
18
- /* default max value for the focus ring spacing offset. calc doesn't support unitless 0. */
19
- /* stylelint-disable length-zero-no-unit */
20
- --_focus-ring-spacing-max-offset: 0px;
21
- /* Calculates the offset by which the focus ring should be shifted inwards based on a custom --vaadin-dashboard-spacing value.
22
- Effectively keeps the focus ring visible if --vaadin-dashboard-spacing is set to 0px */
23
- --_focus-ring-spacing-offset: min(
24
- max(calc(var(--_focus-ring-width) * -1), var(--_vaadin-dashboard-spacing) - var(--_focus-ring-width)),
25
- var(--_focus-ring-spacing-max-offset, 0px)
26
- );
27
- outline: none;
28
- }
29
-
30
- :host::before {
31
- content: '';
32
- display: block;
33
- position: absolute;
34
- inset: 0;
35
- border-radius: var(--lumo-border-radius-l);
36
- pointer-events: none;
37
- margin: calc(var(--_focus-ring-spacing-offset) * -1);
39
+ --_icon-color: var(--lumo-contrast-60pct);
40
+ opacity: var(--_vaadin-dashboard-widget-opacity);
41
+ filter: var(--_vaadin-dashboard-widget-filter);
38
42
  }
39
43
 
40
- :host([focused])::before {
41
- outline: var(--_focus-ring-width) solid var(--_focus-ring-color);
44
+ :host([selected]) {
45
+ opacity: 1;
46
+ z-index: 1;
42
47
  }
43
48
 
44
- :host([selected])::before {
45
- box-shadow:
46
- 0 2px 4px -1px var(--lumo-primary-color-10pct),
47
- 0 3px 12px -1px var(--lumo-primary-color-50pct);
49
+ :host([focused]) {
50
+ z-index: 1;
51
+ }
52
+
53
+ header {
54
+ display: flex;
55
+ align-items: center;
56
+ box-sizing: border-box;
57
+ justify-content: space-between;
58
+ gap: var(--lumo-space-xs);
59
+ }
60
+
61
+ [part='title'] {
62
+ flex: 1;
63
+ color: var(--lumo-header-text-color);
64
+ margin: 0;
65
+ white-space: nowrap;
66
+ text-overflow: ellipsis;
67
+ overflow: hidden;
48
68
  }
49
69
 
50
- /* Buttons styling */
51
70
  vaadin-dashboard-button {
52
71
  font-family: 'lumo-icons';
53
- font-size: var(--lumo-icon-size-s);
72
+ font-size: var(--lumo-icon-size-m);
73
+ margin: 0;
54
74
  }
55
75
 
56
- .icon::before {
76
+ vaadin-dashboard-button .icon::before {
57
77
  display: block;
58
78
  content: var(--icon);
59
79
  }
60
80
 
61
- :host(:not([selected])) *:not(.mode-controls) vaadin-dashboard-button,
62
- :host([move-mode]) *:not(.mode-controls) vaadin-dashboard-button,
63
- :host([resize-mode]) *:not(.mode-controls) vaadin-dashboard-button {
64
- color: var(--lumo-disabled-text-color);
81
+ /* Common styles for non-mode edit buttons */
82
+ [part='move-button'],
83
+ [part='resize-button'],
84
+ [part='remove-button'] {
85
+ color: var(--_icon-color);
86
+ padding-inline: 0;
65
87
  }
66
-
67
- /* Header styling */
68
- header {
69
- display: flex;
70
- align-items: center;
71
- padding: var(--lumo-space-s) var(--lumo-space-m);
72
- gap: var(--lumo-space-s);
73
- min-height: var(--lumo-size-m);
74
- justify-content: space-between;
88
+ :where([part='move-button'], [part='resize-button'], [part='remove-button']):hover {
89
+ --_icon-color: var(--lumo-primary-text-color);
75
90
  }
76
-
77
- :host([editable]) header {
78
- padding-inline: var(--lumo-space-s);
91
+ :host([selected]) {
92
+ --_icon-color: var(--lumo-primary-text-color);
93
+ }
94
+ :host(:is([move-mode], [resize-mode])) {
95
+ --_icon-color: var(--lumo-disabled-text-color);
79
96
  }
80
97
 
81
- /* Drag handle styling */
98
+ /* Drag handle */
82
99
  [part~='move-button'] {
83
100
  cursor: move;
84
101
  --icon: var(--lumo-icons-drag-handle);
85
102
  }
86
103
 
87
- /* Remove button styling */
104
+ /* Remove button */
88
105
  [part~='remove-button'] {
89
106
  cursor: pointer;
90
107
  --icon: var(--lumo-icons-cross);
91
108
  }
92
109
 
93
- /* Title styling */
94
- h2,
95
- h3 {
96
- flex: 1;
97
- font-size: var(--lumo-font-size-m);
98
- font-weight: 500;
99
- color: var(--lumo-header-text-color);
100
- margin: 0;
101
- }
102
-
103
- /* Content styling */
104
- [part~='content'] {
105
- min-height: var(--lumo-size-m);
106
- padding: var(--lumo-space-s);
107
- }
108
-
109
- /* Mode controls styling */
110
+ /* Mode controls */
110
111
  .mode-controls vaadin-dashboard-button[focused] {
111
112
  z-index: 3;
112
113
  }
113
114
 
114
- /* Move mode styling */
115
-
116
- [part~='move-backward-button'] {
117
- inset-inline-start: calc(0px - var(--_focus-ring-spacing-offset));
118
- }
119
-
120
- [part~='move-forward-button'] {
121
- inset-inline-end: calc(0px - var(--_focus-ring-spacing-offset));
122
- transform: translateY(-50%);
123
- }
115
+ /* Move mode */
124
116
 
125
117
  :host(:not([dir='rtl'])) [part~='move-backward-button'],
126
118
  :host([dir='rtl']) [part~='move-forward-button'] {
@@ -142,38 +134,78 @@ const dashboardWidgetAndSection = css`
142
134
  }
143
135
  `;
144
136
 
137
+ /* Widget styles */
145
138
  const dashboardWidget = css`
146
139
  :host {
147
- opacity: var(--_vaadin-dashboard-widget-opacity);
148
- filter: var(--_vaadin-dashboard-widget-filter);
149
- background-color: var(--lumo-base-color);
140
+ background: var(--vaadin-dashboard-widget-background);
141
+ border-radius: var(--vaadin-dashboard-widget-border-radius);
142
+ --_border-shadow: 0 0 0 var(--vaadin-dashboard-widget-border-width) var(--vaadin-dashboard-widget-border-color);
143
+ --_shadow: var(--vaadin-dashboard-widget-shadow);
144
+ box-shadow: var(--_shadow), var(--_border-shadow);
150
145
  }
151
146
 
152
- :host(:not([selected])) {
153
- box-shadow: var(--lumo-box-shadow-s);
147
+ /* Widget states */
148
+
149
+ :host([editable]) {
150
+ --_shadow: var(--vaadin-dashboard-widget-editable-shadow);
151
+ }
152
+
153
+ :host([focused]) {
154
+ --_border-shadow: inset 0 0 0 var(--_focus-ring-width) var(--_focus-ring-color);
154
155
  }
155
156
 
156
157
  :host([selected]) {
157
- opacity: 1;
158
+ --_shadow: var(--vaadin-dashboard-widget-selected-shadow);
159
+ background: var(--lumo-primary-color-10pct);
158
160
  }
159
161
 
160
- :host([resize-mode]) [part~='content'] ::slotted(*),
161
- :host([move-mode]) [part~='content'] ::slotted(*) {
162
- opacity: 0.3;
163
- filter: blur(10px);
162
+ :host([dragging]) {
163
+ box-shadow: none;
164
+ background: var(--vaadin-dashboard-drop-target-background-color);
165
+ border: var(--vaadin-dashboard-drop-target-border);
166
+ }
167
+
168
+ :host([resizing])::after {
169
+ background: var(--vaadin-dashboard-drop-target-background-color);
170
+ border: var(--vaadin-dashboard-drop-target-border);
164
171
  }
165
172
 
166
- /* Header styling */
173
+ /* Widget parts */
174
+
167
175
  header {
176
+ min-height: var(--lumo-size-l);
177
+ padding: 0 var(--lumo-space-m);
168
178
  border-bottom: 1px solid var(--lumo-contrast-10pct);
169
179
  }
170
180
 
171
- /* Resize handle styling */
181
+ :host([editable]) header {
182
+ padding-inline: var(--lumo-space-xs);
183
+ }
184
+
185
+ [part='title'] {
186
+ font-size: var(--lumo-font-size-l);
187
+ font-weight: 600;
188
+ }
189
+
190
+ #content {
191
+ min-height: var(--lumo-size-m);
192
+ padding: var(--lumo-space-s);
193
+ }
194
+
195
+ :host([resize-mode]) #content,
196
+ :host([move-mode]) #content {
197
+ opacity: 0.75;
198
+ filter: blur(10px);
199
+ }
200
+
201
+ /* Resize handle */
202
+
172
203
  [part~='resize-button'] {
204
+ --_resize-button-offset: min(var(--_vaadin-dashboard-gap), var(--_vaadin-dashboard-padding), var(--lumo-space-xs));
173
205
  position: absolute;
174
- bottom: var(--lumo-space-s);
175
- inset-inline-end: var(--lumo-space-s);
176
- cursor: se-resize;
206
+ bottom: calc(-1 * var(--_resize-button-offset));
207
+ inset-inline-end: calc(-1 * var(--_resize-button-offset));
208
+ cursor: nwse-resize;
177
209
  --icon: var(--lumo-icons-resize-handle);
178
210
  }
179
211
 
@@ -185,7 +217,8 @@ const dashboardWidget = css`
185
217
  transform: scaleX(-1);
186
218
  }
187
219
 
188
- /* Resize mode styling */
220
+ /* Accessible resize mode controls */
221
+
189
222
  [part~='resize-apply-button'] {
190
223
  --icon: var(--lumo-icons-checkmark);
191
224
  font-size: var(--lumo-icon-size-m);
@@ -198,10 +231,19 @@ const dashboardWidget = css`
198
231
  min-width: var(--lumo-size-s);
199
232
  }
200
233
 
234
+ [part~='resize-shrink-width-button'] + [part~='resize-grow-width-button'] {
235
+ margin-left: 1px;
236
+ }
237
+
201
238
  [part~='resize-grow-height-button'],
202
239
  [part~='resize-shrink-height-button'] {
203
240
  height: var(--lumo-size-s);
204
- margin: 0;
241
+ padding-right: 0;
242
+ padding-left: 0;
243
+ }
244
+
245
+ [part~='resize-shrink-height-button'] + [part~='resize-grow-height-button'] {
246
+ margin-top: 1px;
205
247
  }
206
248
 
207
249
  :host(:not([dir='rtl'])) [part~='resize-grow-width-button'],
@@ -246,6 +288,26 @@ const dashboardWidget = css`
246
288
  border-top-left-radius: 0;
247
289
  border-top-right-radius: 0;
248
290
  }
291
+
292
+ /* Windows High Contrast Mode */
293
+ @media (forced-colors: active) {
294
+ :host {
295
+ border: 1px solid;
296
+ }
297
+ :host([focused]) {
298
+ outline: 2px solid;
299
+ outline-offset: 1px;
300
+ }
301
+ :host([selected]) {
302
+ outline-width: 1px;
303
+ outline-offset: 0px;
304
+ outline-color: Highlight;
305
+ }
306
+ :host([selected][focused]) {
307
+ outline-width: 3px;
308
+ outline-offset: 0px;
309
+ }
310
+ }
249
311
  `;
250
312
 
251
313
  registerStyles('vaadin-dashboard-widget', [dashboardWidget, dashboardWidgetAndSection], {
package/web-types.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/dashboard",
4
- "version": "24.6.0-beta1",
4
+ "version": "24.7.0-alpha1",
5
5
  "description-markup": "markdown",
6
6
  "contributions": {
7
7
  "html": {
8
8
  "elements": [
9
9
  {
10
10
  "name": "vaadin-dashboard-layout",
11
- "description": "A responsive, grid-based dashboard layout component\n\n```html\n<vaadin-dashboard-layout>\n <vaadin-dashboard-widget widget-title=\"Widget 1\"></vaadin-dashboard-widget>\n <vaadin-dashboard-widget widget-title=\"Widget 2\"></vaadin-dashboard-widget>\n <vaadin-dashboard-section section-title=\"Section\">\n <vaadin-dashboard-widget widget-title=\"Widget in Section\"></vaadin-dashboard-widget>\n </vaadin-dashboard-section>\n</vaadin-dashboard-layout>\n```\n\n### Styling\n\nThe following custom properties are available:\n\nCustom Property | Description\n------------------------------------|-------------\n`--vaadin-dashboard-col-min-width` | minimum column width of the layout\n`--vaadin-dashboard-col-max-width` | maximum column width of the layout\n`--vaadin-dashboard-row-min-height` | minimum row height of the layout\n`--vaadin-dashboard-col-max-count` | maximum column count of the layout\n`--vaadin-dashboard-spacing` | spacing between child elements and space around its outer edges. Must be in length units (0 is not allowed, 0px is)\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------|-------------\n`dense-layout` | Set when the dashboard is in dense mode.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
11
+ "description": "A responsive, grid-based dashboard layout component\n\n```html\n<vaadin-dashboard-layout>\n <vaadin-dashboard-widget widget-title=\"Widget 1\"></vaadin-dashboard-widget>\n <vaadin-dashboard-widget widget-title=\"Widget 2\"></vaadin-dashboard-widget>\n <vaadin-dashboard-section section-title=\"Section\">\n <vaadin-dashboard-widget widget-title=\"Widget in Section\"></vaadin-dashboard-widget>\n </vaadin-dashboard-section>\n</vaadin-dashboard-layout>\n```\n\n### Styling\n\nThe following custom properties are available:\n\nCustom Property | Description\n------------------------------------|-------------\n`--vaadin-dashboard-col-min-width` | minimum column width of the layout\n`--vaadin-dashboard-col-max-width` | maximum column width of the layout\n`--vaadin-dashboard-row-min-height` | minimum row height of the layout\n`--vaadin-dashboard-col-max-count` | maximum column count of the layout\n`--vaadin-dashboard-gap` | gap between child elements. Must be in length units (0 is not allowed, 0px is)\n`--vaadin-dashboard-padding` | space around the dashboard's outer edges. Must be in length units (0 is not allowed, 0px is)\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------|-------------\n`dense-layout` | Set when the dashboard is in dense mode.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
12
12
  "attributes": [
13
13
  {
14
14
  "name": "dense-layout",
@@ -136,7 +136,7 @@
136
136
  },
137
137
  {
138
138
  "name": "vaadin-dashboard",
139
- "description": "A responsive, grid-based dashboard layout component\n\n### Quick Start\n\nAssign an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-beta1/#/elements/vaadin-dashboard#property-items) property.\nSet a renderer function to the [`renderer`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-beta1/#/elements/vaadin-dashboard#property-renderer) property.\n\nThe widgets and the sections will be generated and configured based on the renderer and the items provided.\n\n```html\n<vaadin-dashboard></vaadin-dashboard>\n```\n```js\nconst dashboard = document.querySelector('vaadin-dashboard');\n\ndashboard.items = [\n { title: 'Widget 1 title', content: 'Text 1', rowspan: 2 },\n { title: 'Widget 2 title', content: 'Text 2', colspan: 2 },\n {\n title: 'Section title',\n items: [{ title: 'Widget in section title', content: 'Text 3' }]\n },\n // ... more items\n];\n\ndashboard.renderer = (root, _dashboard, { item }) => {\n const widget = root.firstElementChild || document.createElement('vaadin-dashboard-widget');\n if (!root.contains(widget)) {\n root.appendChild(widget);\n }\n widget.widgetTitle = item.title;\n widget.textContent = item.content;\n};\n```\n\n### Styling\n\nThe following custom properties are available:\n\nCustom Property | Description\n------------------------------------|-------------\n`--vaadin-dashboard-col-min-width` | minimum column width of the dashboard\n`--vaadin-dashboard-col-max-width` | maximum column width of the dashboard\n`--vaadin-dashboard-row-min-height` | minimum row height of the dashboard\n`--vaadin-dashboard-col-max-count` | maximum column count of the dashboard\n`--vaadin-dashboard-spacing` | spacing between child elements and space around its outer edges. Must be in length units (0 is not allowed, 0px is)\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------|-------------\n`editable` | Set when the dashboard is editable.\n`dense-layout` | Set when the dashboard is in dense mode.\n`item-selected`| Set when an item is selected.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
139
+ "description": "A responsive, grid-based dashboard layout component\n\n### Quick Start\n\nAssign an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.7.0-alpha1/#/elements/vaadin-dashboard#property-items) property.\nSet a renderer function to the [`renderer`](https://cdn.vaadin.com/vaadin-web-components/24.7.0-alpha1/#/elements/vaadin-dashboard#property-renderer) property.\n\nThe widgets and the sections will be generated and configured based on the renderer and the items provided.\n\n```html\n<vaadin-dashboard></vaadin-dashboard>\n```\n```js\nconst dashboard = document.querySelector('vaadin-dashboard');\n\ndashboard.items = [\n { title: 'Widget 1 title', content: 'Text 1', rowspan: 2 },\n { title: 'Widget 2 title', content: 'Text 2', colspan: 2 },\n {\n title: 'Section title',\n items: [{ title: 'Widget in section title', content: 'Text 3' }]\n },\n // ... more items\n];\n\ndashboard.renderer = (root, _dashboard, { item }) => {\n const widget = root.firstElementChild || document.createElement('vaadin-dashboard-widget');\n if (!root.contains(widget)) {\n root.appendChild(widget);\n }\n widget.widgetTitle = item.title;\n widget.textContent = item.content;\n};\n```\n\n### Styling\n\nThe following custom properties are available:\n\nCustom Property | Description\n------------------------------------|-------------\n`--vaadin-dashboard-col-min-width` | minimum column width of the dashboard\n`--vaadin-dashboard-col-max-width` | maximum column width of the dashboard\n`--vaadin-dashboard-row-min-height` | minimum row height of the dashboard\n`--vaadin-dashboard-col-max-count` | maximum column count of the dashboard\n`--vaadin-dashboard-gap` | gap between child elements. Must be in length units (0 is not allowed, 0px is)\n`--vaadin-dashboard-padding` | space around the dashboard's outer edges. Must be in length units (0 is not allowed, 0px is)\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------|-------------\n`editable` | Set when the dashboard is editable.\n`dense-layout` | Set when the dashboard is in dense mode.\n`item-selected`| Set when an item is selected.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
140
140
  "attributes": [
141
141
  {
142
142
  "name": "dense-layout",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/web-types",
3
3
  "name": "@vaadin/dashboard",
4
- "version": "24.6.0-beta1",
4
+ "version": "24.7.0-alpha1",
5
5
  "description-markup": "markdown",
6
6
  "framework": "lit",
7
7
  "framework-config": {
@@ -16,7 +16,7 @@
16
16
  "elements": [
17
17
  {
18
18
  "name": "vaadin-dashboard-layout",
19
- "description": "A responsive, grid-based dashboard layout component\n\n```html\n<vaadin-dashboard-layout>\n <vaadin-dashboard-widget widget-title=\"Widget 1\"></vaadin-dashboard-widget>\n <vaadin-dashboard-widget widget-title=\"Widget 2\"></vaadin-dashboard-widget>\n <vaadin-dashboard-section section-title=\"Section\">\n <vaadin-dashboard-widget widget-title=\"Widget in Section\"></vaadin-dashboard-widget>\n </vaadin-dashboard-section>\n</vaadin-dashboard-layout>\n```\n\n### Styling\n\nThe following custom properties are available:\n\nCustom Property | Description\n------------------------------------|-------------\n`--vaadin-dashboard-col-min-width` | minimum column width of the layout\n`--vaadin-dashboard-col-max-width` | maximum column width of the layout\n`--vaadin-dashboard-row-min-height` | minimum row height of the layout\n`--vaadin-dashboard-col-max-count` | maximum column count of the layout\n`--vaadin-dashboard-spacing` | spacing between child elements and space around its outer edges. Must be in length units (0 is not allowed, 0px is)\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------|-------------\n`dense-layout` | Set when the dashboard is in dense mode.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
19
+ "description": "A responsive, grid-based dashboard layout component\n\n```html\n<vaadin-dashboard-layout>\n <vaadin-dashboard-widget widget-title=\"Widget 1\"></vaadin-dashboard-widget>\n <vaadin-dashboard-widget widget-title=\"Widget 2\"></vaadin-dashboard-widget>\n <vaadin-dashboard-section section-title=\"Section\">\n <vaadin-dashboard-widget widget-title=\"Widget in Section\"></vaadin-dashboard-widget>\n </vaadin-dashboard-section>\n</vaadin-dashboard-layout>\n```\n\n### Styling\n\nThe following custom properties are available:\n\nCustom Property | Description\n------------------------------------|-------------\n`--vaadin-dashboard-col-min-width` | minimum column width of the layout\n`--vaadin-dashboard-col-max-width` | maximum column width of the layout\n`--vaadin-dashboard-row-min-height` | minimum row height of the layout\n`--vaadin-dashboard-col-max-count` | maximum column count of the layout\n`--vaadin-dashboard-gap` | gap between child elements. Must be in length units (0 is not allowed, 0px is)\n`--vaadin-dashboard-padding` | space around the dashboard's outer edges. Must be in length units (0 is not allowed, 0px is)\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------|-------------\n`dense-layout` | Set when the dashboard is in dense mode.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
20
20
  "extension": true,
21
21
  "attributes": [
22
22
  {
@@ -58,7 +58,7 @@
58
58
  },
59
59
  {
60
60
  "name": "vaadin-dashboard",
61
- "description": "A responsive, grid-based dashboard layout component\n\n### Quick Start\n\nAssign an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-beta1/#/elements/vaadin-dashboard#property-items) property.\nSet a renderer function to the [`renderer`](https://cdn.vaadin.com/vaadin-web-components/24.6.0-beta1/#/elements/vaadin-dashboard#property-renderer) property.\n\nThe widgets and the sections will be generated and configured based on the renderer and the items provided.\n\n```html\n<vaadin-dashboard></vaadin-dashboard>\n```\n```js\nconst dashboard = document.querySelector('vaadin-dashboard');\n\ndashboard.items = [\n { title: 'Widget 1 title', content: 'Text 1', rowspan: 2 },\n { title: 'Widget 2 title', content: 'Text 2', colspan: 2 },\n {\n title: 'Section title',\n items: [{ title: 'Widget in section title', content: 'Text 3' }]\n },\n // ... more items\n];\n\ndashboard.renderer = (root, _dashboard, { item }) => {\n const widget = root.firstElementChild || document.createElement('vaadin-dashboard-widget');\n if (!root.contains(widget)) {\n root.appendChild(widget);\n }\n widget.widgetTitle = item.title;\n widget.textContent = item.content;\n};\n```\n\n### Styling\n\nThe following custom properties are available:\n\nCustom Property | Description\n------------------------------------|-------------\n`--vaadin-dashboard-col-min-width` | minimum column width of the dashboard\n`--vaadin-dashboard-col-max-width` | maximum column width of the dashboard\n`--vaadin-dashboard-row-min-height` | minimum row height of the dashboard\n`--vaadin-dashboard-col-max-count` | maximum column count of the dashboard\n`--vaadin-dashboard-spacing` | spacing between child elements and space around its outer edges. Must be in length units (0 is not allowed, 0px is)\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------|-------------\n`editable` | Set when the dashboard is editable.\n`dense-layout` | Set when the dashboard is in dense mode.\n`item-selected`| Set when an item is selected.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
61
+ "description": "A responsive, grid-based dashboard layout component\n\n### Quick Start\n\nAssign an array to the [`items`](https://cdn.vaadin.com/vaadin-web-components/24.7.0-alpha1/#/elements/vaadin-dashboard#property-items) property.\nSet a renderer function to the [`renderer`](https://cdn.vaadin.com/vaadin-web-components/24.7.0-alpha1/#/elements/vaadin-dashboard#property-renderer) property.\n\nThe widgets and the sections will be generated and configured based on the renderer and the items provided.\n\n```html\n<vaadin-dashboard></vaadin-dashboard>\n```\n```js\nconst dashboard = document.querySelector('vaadin-dashboard');\n\ndashboard.items = [\n { title: 'Widget 1 title', content: 'Text 1', rowspan: 2 },\n { title: 'Widget 2 title', content: 'Text 2', colspan: 2 },\n {\n title: 'Section title',\n items: [{ title: 'Widget in section title', content: 'Text 3' }]\n },\n // ... more items\n];\n\ndashboard.renderer = (root, _dashboard, { item }) => {\n const widget = root.firstElementChild || document.createElement('vaadin-dashboard-widget');\n if (!root.contains(widget)) {\n root.appendChild(widget);\n }\n widget.widgetTitle = item.title;\n widget.textContent = item.content;\n};\n```\n\n### Styling\n\nThe following custom properties are available:\n\nCustom Property | Description\n------------------------------------|-------------\n`--vaadin-dashboard-col-min-width` | minimum column width of the dashboard\n`--vaadin-dashboard-col-max-width` | maximum column width of the dashboard\n`--vaadin-dashboard-row-min-height` | minimum row height of the dashboard\n`--vaadin-dashboard-col-max-count` | maximum column count of the dashboard\n`--vaadin-dashboard-gap` | gap between child elements. Must be in length units (0 is not allowed, 0px is)\n`--vaadin-dashboard-padding` | space around the dashboard's outer edges. Must be in length units (0 is not allowed, 0px is)\n\nThe following state attributes are available for styling:\n\nAttribute | Description\n---------------|-------------\n`editable` | Set when the dashboard is editable.\n`dense-layout` | Set when the dashboard is in dense mode.\n`item-selected`| Set when an item is selected.\n\nSee [Styling Components](https://vaadin.com/docs/latest/styling/styling-components) documentation.",
62
62
  "extension": true,
63
63
  "attributes": [
64
64
  {