@vaadin/dialog 23.1.0-alpha1 → 23.1.0-alpha4

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/dialog",
3
- "version": "23.1.0-alpha1",
3
+ "version": "23.1.0-alpha4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -35,18 +35,18 @@
35
35
  "dependencies": {
36
36
  "@open-wc/dedupe-mixin": "^1.3.0",
37
37
  "@polymer/polymer": "^3.0.0",
38
- "@vaadin/component-base": "23.1.0-alpha1",
39
- "@vaadin/vaadin-lumo-styles": "23.1.0-alpha1",
40
- "@vaadin/vaadin-material-styles": "23.1.0-alpha1",
41
- "@vaadin/vaadin-overlay": "23.1.0-alpha1",
42
- "@vaadin/vaadin-themable-mixin": "23.1.0-alpha1"
38
+ "@vaadin/component-base": "23.1.0-alpha4",
39
+ "@vaadin/vaadin-lumo-styles": "23.1.0-alpha4",
40
+ "@vaadin/vaadin-material-styles": "23.1.0-alpha4",
41
+ "@vaadin/vaadin-overlay": "23.1.0-alpha4",
42
+ "@vaadin/vaadin-themable-mixin": "23.1.0-alpha4"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@esm-bundle/chai": "^4.3.4",
46
- "@vaadin/polymer-legacy-adapter": "23.1.0-alpha1",
46
+ "@vaadin/polymer-legacy-adapter": "23.1.0-alpha4",
47
47
  "@vaadin/testing-helpers": "^0.3.2",
48
- "@vaadin/text-area": "23.1.0-alpha1",
49
- "sinon": "^9.2.1"
48
+ "@vaadin/text-area": "23.1.0-alpha4",
49
+ "sinon": "^13.0.2"
50
50
  },
51
- "gitHead": "5d0cdee069f866037c507265fafb4d0476795333"
51
+ "gitHead": "aacdb7fe09811894751f0378ff7fb66071892c71"
52
52
  }
@@ -6,7 +6,7 @@
6
6
  import { Constructor } from '@open-wc/dedupe-mixin';
7
7
 
8
8
  export declare function DialogDraggableMixin<T extends Constructor<HTMLElement>>(
9
- base: T
9
+ base: T,
10
10
  ): T & Constructor<DialogDraggableMixinClass>;
11
11
 
12
12
  export declare class DialogDraggableMixinClass {
@@ -28,19 +28,19 @@ export const DialogDraggableMixin = (superClass) =>
28
28
  draggable: {
29
29
  type: Boolean,
30
30
  value: false,
31
- reflectToAttribute: true
31
+ reflectToAttribute: true,
32
32
  },
33
33
 
34
34
  /** @private */
35
35
  _touchDevice: {
36
36
  type: Boolean,
37
- value: isTouch
37
+ value: isTouch,
38
38
  },
39
39
 
40
40
  /* TODO: Expose as a public property (check naming) */
41
41
  __dragHandleClassName: {
42
- type: String
43
- }
42
+ type: String,
43
+ },
44
44
  };
45
45
  }
46
46
 
@@ -82,7 +82,9 @@ export const DialogDraggableMixin = (superClass) =>
82
82
  });
83
83
 
84
84
  if ((isResizerContainer && !isResizerContainerScrollbar) || isContentPart || isDraggable) {
85
- !isDraggable && e.preventDefault();
85
+ if (!isDraggable) {
86
+ e.preventDefault();
87
+ }
86
88
  this._originalBounds = this.$.overlay.getBounds();
87
89
  const event = getMouseOrFirstTouchEvent(e);
88
90
  this._originalMouseCoords = { top: event.pageY, left: event.pageX };
@@ -6,7 +6,7 @@
6
6
  import { Constructor } from '@open-wc/dedupe-mixin';
7
7
 
8
8
  export declare function DialogResizableMixin<T extends Constructor<HTMLElement>>(
9
- base: T
9
+ base: T,
10
10
  ): T & Constructor<DialogResizableMixinClass>;
11
11
 
12
12
  export declare class DialogResizableMixinClass {
@@ -24,6 +24,7 @@ registerStyles(
24
24
  .resizer-container {
25
25
  overflow: auto;
26
26
  flex-grow: 1;
27
+ border-radius: inherit; /* prevent child elements being drawn outside part=overlay */
27
28
  }
28
29
 
29
30
  [part='overlay'][style] .resizer-container {
@@ -35,6 +36,12 @@ registerStyles(
35
36
  display: none;
36
37
  }
37
38
 
39
+ :host([resizable]) [part='title'] {
40
+ cursor: move;
41
+ -webkit-user-select: none;
42
+ user-select: none;
43
+ }
44
+
38
45
  .resizer {
39
46
  position: absolute;
40
47
  height: 16px;
@@ -98,7 +105,7 @@ registerStyles(
98
105
  cursor: nwse-resize;
99
106
  }
100
107
  `,
101
- { moduleId: 'vaadin-dialog-resizable-overlay-styles' }
108
+ { moduleId: 'vaadin-dialog-resizable-overlay-styles' },
102
109
  );
103
110
 
104
111
  /**
@@ -115,8 +122,8 @@ export const DialogResizableMixin = (superClass) =>
115
122
  resizable: {
116
123
  type: Boolean,
117
124
  value: false,
118
- reflectToAttribute: true
119
- }
125
+ reflectToAttribute: true,
126
+ },
120
127
  };
121
128
  }
122
129
 
@@ -245,7 +252,7 @@ export const DialogResizableMixin = (superClass) =>
245
252
  const content = this.$.overlay.$.content;
246
253
  content.setAttribute(
247
254
  'style',
248
- 'position: absolute; top: 0; right: 0; bottom: 0; left: 0; box-sizing: content-box; height: auto;'
255
+ 'position: absolute; top: 0; right: 0; bottom: 0; left: 0; box-sizing: content-box; height: auto;',
249
256
  );
250
257
  const { width: contentWidth, height: contentHeight } = getComputedStyle(content);
251
258
  content.removeAttribute('style');
@@ -110,6 +110,7 @@ export type DialogEventMap = HTMLElementEventMap & DialogCustomEventMap;
110
110
  * `has-title` | Set when the element has a title
111
111
  * `has-header` | Set when the element has header renderer
112
112
  * `has-footer` | Set when the element has footer renderer
113
+ * `overflow` | Set to `top`, `bottom`, none or both
113
114
  *
114
115
  * Note: the `theme` attribute value set on `<vaadin-dialog>` is
115
116
  * propagated to the internal `<vaadin-dialog-overlay>` component.
@@ -207,13 +208,13 @@ declare class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixi
207
208
  addEventListener<K extends keyof DialogEventMap>(
208
209
  type: K,
209
210
  listener: (this: Dialog, ev: DialogEventMap[K]) => void,
210
- options?: boolean | AddEventListenerOptions
211
+ options?: boolean | AddEventListenerOptions,
211
212
  ): void;
212
213
 
213
214
  removeEventListener<K extends keyof DialogEventMap>(
214
215
  type: K,
215
216
  listener: (this: Dialog, ev: DialogEventMap[K]) => void,
216
- options?: boolean | EventListenerOptions
217
+ options?: boolean | EventListenerOptions,
217
218
  ): void;
218
219
  }
219
220
 
@@ -15,32 +15,41 @@ import { DialogResizableMixin } from './vaadin-dialog-resizable-mixin.js';
15
15
  registerStyles(
16
16
  'vaadin-dialog-overlay',
17
17
  css`
18
- /* prefixing with the element tag to avoid styling confirm-dialog header part */
19
- header[part='header'] {
18
+ [part='header'],
19
+ [part='header-content'],
20
+ [part='footer'] {
20
21
  display: flex;
22
+ align-items: center;
23
+ flex-wrap: wrap;
24
+ flex: none;
25
+ pointer-events: none;
26
+ z-index: 1;
27
+ }
28
+
29
+ ::slotted([slot='header-content']),
30
+ ::slotted([slot='title']),
31
+ ::slotted([slot='footer']) {
32
+ display: contents;
33
+ pointer-events: auto;
21
34
  }
22
35
 
23
36
  [part='header-content'] {
24
37
  flex: 1;
25
38
  }
26
39
 
27
- /* prefixing with the element tag to avoid styling confirm-dialog footer part */
28
- footer[part='footer'] {
29
- display: flex;
40
+ :host([has-title]) [part='header-content'],
41
+ [part='footer'] {
30
42
  justify-content: flex-end;
31
43
  }
32
44
 
33
- :host(:not([has-title]):not([has-header])) header[part='header'],
34
- :host(:not([has-title])) [part='title'] {
35
- display: none;
36
- }
37
-
38
- :host(:not([has-footer])) footer[part='footer'] {
39
- display: none;
45
+ :host(:not([has-title]):not([has-header])) [part='header'],
46
+ :host(:not([has-header])) [part='header-content'],
47
+ :host(:not([has-title])) [part='title'],
48
+ :host(:not([has-footer])) [part='footer'] {
49
+ display: none !important;
40
50
  }
41
51
 
42
52
  :host(:is([has-title], [has-header], [has-footer])) [part='content'] {
43
- min-height: 100%;
44
53
  height: auto;
45
54
  }
46
55
 
@@ -54,8 +63,6 @@ registerStyles(
54
63
  :host(:is([has-title], [has-header], [has-footer])) [part='content'] {
55
64
  flex: 1;
56
65
  overflow: auto;
57
- min-height: auto;
58
- height: 100%;
59
66
  }
60
67
  }
61
68
 
@@ -71,7 +78,7 @@ registerStyles(
71
78
  max-width: none;
72
79
  }
73
80
  `,
74
- { moduleId: 'vaadin-dialog-overlay-styles' }
81
+ { moduleId: 'vaadin-dialog-overlay-styles' },
75
82
  );
76
83
 
77
84
  let memoizedTemplate;
@@ -132,7 +139,7 @@ export class DialogOverlay extends OverlayElement {
132
139
  static get observers() {
133
140
  return [
134
141
  '_headerFooterRendererChange(headerRenderer, footerRenderer, opened)',
135
- '_headerTitleChanged(headerTitle, opened)'
142
+ '_headerTitleChanged(headerTitle, opened)',
136
143
  ];
137
144
  }
138
145
 
@@ -146,15 +153,27 @@ export class DialogOverlay extends OverlayElement {
146
153
 
147
154
  headerRenderer: Function,
148
155
 
149
- footerRenderer: Function
156
+ footerRenderer: Function,
150
157
  };
151
158
  }
152
159
 
160
+ /** @protected */
153
161
  ready() {
154
162
  super.ready();
155
163
 
156
164
  const uniqueId = (DialogOverlay._uniqueId = 1 + DialogOverlay._uniqueId || 0);
157
165
  this._titleId = `${this.constructor.is}-title-${uniqueId}`;
166
+
167
+ // Update overflow attribute on resize
168
+ this.__resizeObserver = new ResizeObserver(() => {
169
+ this.__updateOverflow();
170
+ });
171
+ this.__resizeObserver.observe(this.$.resizerContainer);
172
+
173
+ // Update overflow attribute on scroll
174
+ this.$.content.addEventListener('scroll', () => {
175
+ this.__updateOverflow();
176
+ });
158
177
  }
159
178
 
160
179
  /** @private */
@@ -196,12 +215,17 @@ export class DialogOverlay extends OverlayElement {
196
215
  const openedChanged = this._oldOpenedFooterHeader !== opened;
197
216
  this._oldOpenedFooterHeader = opened;
198
217
 
218
+ // Set attributes here to update styles before detecting content overflow
219
+ this.toggleAttribute('has-header', !!headerRenderer);
220
+ this.toggleAttribute('has-footer', !!footerRenderer);
221
+
199
222
  if (headerRendererChanged) {
200
223
  if (headerRenderer) {
201
224
  this.headerContainer = this.__initContainer(this.headerContainer, 'header-content');
202
225
  } else if (this.headerContainer) {
203
226
  this.headerContainer.remove();
204
227
  this.headerContainer = null;
228
+ this.__updateOverflow();
205
229
  }
206
230
  }
207
231
 
@@ -211,6 +235,7 @@ export class DialogOverlay extends OverlayElement {
211
235
  } else if (this.footerContainer) {
212
236
  this.footerContainer.remove();
213
237
  this.footerContainer = null;
238
+ this.__updateOverflow();
214
239
  }
215
240
  }
216
241
 
@@ -222,18 +247,16 @@ export class DialogOverlay extends OverlayElement {
222
247
  this.requestContentUpdate();
223
248
  }
224
249
  }
225
-
226
- this.toggleAttribute('has-header', !!headerRenderer);
227
- this.toggleAttribute('has-footer', !!footerRenderer);
228
250
  }
229
251
 
230
252
  /** @private */
231
253
  _headerTitleChanged(headerTitle, opened) {
254
+ this.toggleAttribute('has-title', !!headerTitle);
255
+
232
256
  if (opened && (headerTitle || this._oldHeaderTitle)) {
233
257
  this.requestContentUpdate();
234
258
  }
235
259
  this._oldHeaderTitle = headerTitle;
236
- this.toggleAttribute('has-title', !!headerTitle);
237
260
  }
238
261
 
239
262
  /** @private */
@@ -259,24 +282,33 @@ export class DialogOverlay extends OverlayElement {
259
282
  requestContentUpdate() {
260
283
  super.requestContentUpdate();
261
284
 
262
- // If a new renderer has been set, make sure to reattach the header/footer roots
263
- if (this.headerContainer && !this.headerContainer.parentElement) {
264
- this.appendChild(this.headerContainer);
265
- }
285
+ if (this.headerContainer) {
286
+ // If a new renderer has been set, make sure to reattach the container
287
+ if (!this.headerContainer.parentElement) {
288
+ this.appendChild(this.headerContainer);
289
+ }
266
290
 
267
- if (this.footerContainer && !this.footerContainer.parentElement) {
268
- this.appendChild(this.footerContainer);
291
+ if (this.headerRenderer) {
292
+ // Only call header renderer after the container has been initialized
293
+ this.headerRenderer.call(this.owner, this.headerContainer, this.owner);
294
+ }
269
295
  }
270
296
 
271
- if (this.headerRenderer) {
272
- this.headerRenderer.call(this.owner, this.headerContainer, this.owner);
273
- }
297
+ if (this.footerContainer) {
298
+ // If a new renderer has been set, make sure to reattach the container
299
+ if (!this.footerContainer.parentElement) {
300
+ this.appendChild(this.footerContainer);
301
+ }
274
302
 
275
- if (this.footerRenderer) {
276
- this.footerRenderer.call(this.owner, this.footerContainer, this.owner);
303
+ if (this.footerRenderer) {
304
+ // Only call header renderer after the container has been initialized
305
+ this.footerRenderer.call(this.owner, this.footerContainer, this.owner);
306
+ }
277
307
  }
278
308
 
279
309
  this._headerTitleRenderer();
310
+
311
+ this.__updateOverflow();
280
312
  }
281
313
 
282
314
  /**
@@ -331,6 +363,32 @@ export class DialogOverlay extends OverlayElement {
331
363
  this.$.resizerContainer.scrollTop = scrollPosition;
332
364
  });
333
365
  }
366
+
367
+ /** @private */
368
+ __updateOverflow() {
369
+ let overflow = '';
370
+
371
+ // Only set "overflow" attribute if the dialog has a header, title or footer.
372
+ // Check for state attributes as extending components might not use renderers.
373
+ if (this.hasAttribute('has-header') || this.hasAttribute('has-footer') || this.headerTitle) {
374
+ const content = this.$.content;
375
+
376
+ if (content.scrollTop > 0) {
377
+ overflow += ' top';
378
+ }
379
+
380
+ if (content.scrollTop < content.scrollHeight - content.clientHeight) {
381
+ overflow += ' bottom';
382
+ }
383
+ }
384
+
385
+ const value = overflow.trim();
386
+ if (value.length > 0 && this.getAttribute('overflow') !== value) {
387
+ this.setAttribute('overflow', value);
388
+ } else if (value.length === 0 && this.hasAttribute('overflow')) {
389
+ this.removeAttribute('overflow');
390
+ }
391
+ }
334
392
  }
335
393
 
336
394
  customElements.define(DialogOverlay.is, DialogOverlay);
@@ -386,6 +444,7 @@ customElements.define(DialogOverlay.is, DialogOverlay);
386
444
  * `has-title` | Set when the element has a title
387
445
  * `has-header` | Set when the element has header renderer
388
446
  * `has-footer` | Set when the element has footer renderer
447
+ * `overflow` | Set to `top`, `bottom`, none or both
389
448
  *
390
449
  * Note: the `theme` attribute value set on `<vaadin-dialog>` is
391
450
  * propagated to the internal `<vaadin-dialog-overlay>` component.
@@ -438,7 +497,7 @@ class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixin(Dialog
438
497
  opened: {
439
498
  type: Boolean,
440
499
  value: false,
441
- notify: true
500
+ notify: true,
442
501
  },
443
502
 
444
503
  /**
@@ -448,7 +507,7 @@ class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixin(Dialog
448
507
  */
449
508
  noCloseOnOutsideClick: {
450
509
  type: Boolean,
451
- value: false
510
+ value: false,
452
511
  },
453
512
 
454
513
  /**
@@ -458,7 +517,7 @@ class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixin(Dialog
458
517
  */
459
518
  noCloseOnEsc: {
460
519
  type: Boolean,
461
- value: false
520
+ value: false,
462
521
  },
463
522
 
464
523
  /**
@@ -468,7 +527,7 @@ class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixin(Dialog
468
527
  */
469
528
  ariaLabel: {
470
529
  type: String,
471
- value: ''
530
+ value: '',
472
531
  },
473
532
 
474
533
  /**
@@ -527,8 +586,8 @@ class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixin(Dialog
527
586
  */
528
587
  modeless: {
529
588
  type: Boolean,
530
- value: false
531
- }
589
+ value: false,
590
+ },
532
591
  };
533
592
  }
534
593
 
@@ -536,7 +595,7 @@ class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixin(Dialog
536
595
  return [
537
596
  '_openedChanged(opened)',
538
597
  '_ariaLabelChanged(ariaLabel)',
539
- '_rendererChanged(renderer, headerRenderer, footerRenderer)'
598
+ '_rendererChanged(renderer, headerRenderer, footerRenderer)',
540
599
  ];
541
600
  }
542
601
 
@@ -566,9 +625,20 @@ class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixin(Dialog
566
625
  this.$.overlay.setProperties({ owner: this, renderer, headerRenderer, footerRenderer });
567
626
  }
568
627
 
628
+ /** @protected */
629
+ connectedCallback() {
630
+ super.connectedCallback();
631
+ // Restore opened state if overlay was opened when disconnecting
632
+ if (this.__restoreOpened) {
633
+ this.opened = true;
634
+ }
635
+ }
636
+
569
637
  /** @protected */
570
638
  disconnectedCallback() {
571
639
  super.disconnectedCallback();
640
+ // Close overlay and memorize opened state
641
+ this.__restoreOpened = this.opened;
572
642
  this.opened = false;
573
643
  }
574
644
 
@@ -27,33 +27,45 @@ const dialogOverlay = css`
27
27
  padding: var(--lumo-space-l);
28
28
  }
29
29
 
30
- [part='header'] {
31
- gap: var(--lumo-space-s);
30
+ :host(:is([has-header], [has-title])) [part='header'] + [part='content'] {
31
+ padding-top: 0;
32
+ }
33
+
34
+ [part='header'],
35
+ [part='header-content'],
36
+ [part='footer'] {
37
+ gap: var(--lumo-space-xs) var(--lumo-space-s);
38
+ line-height: var(--lumo-line-height-s);
32
39
  }
33
40
 
34
- :host([has-header]) [part='header'],
35
- :host([has-title]) [part='header'] {
36
- padding: var(--lumo-space-m) var(--lumo-space-l);
37
- border-bottom: 1px solid var(--lumo-contrast-10pct);
41
+ [part='header'] {
42
+ padding: var(--lumo-space-m);
43
+ background-color: var(--lumo-base-color);
44
+ border-radius: var(--lumo-border-radius-l) var(--lumo-border-radius-l) 0 0; /* Needed for Safari */
38
45
  }
39
46
 
40
- :host([has-footer]) [part='footer'] {
47
+ [part='footer'] {
41
48
  padding: var(--lumo-space-s) var(--lumo-space-m);
42
- border-top: 1px solid var(--lumo-contrast-10pct);
49
+ background-color: var(--lumo-contrast-5pct);
50
+ border-radius: 0 0 var(--lumo-border-radius-l) var(--lumo-border-radius-l); /* Needed for Safari */
43
51
  }
44
52
 
45
- /* No padding */
46
- :host([theme~='no-padding']) [part='content'] {
47
- padding: 0;
53
+ [part='title'] {
54
+ font-size: var(--lumo-font-size-xl);
55
+ font-weight: 600;
56
+ color: var(--lumo-header-text-color);
57
+ margin-inline-start: calc(var(--lumo-space-l) - var(--lumo-space-m));
48
58
  }
49
59
 
50
- :host([theme~='no-padding'][has-header]) [part='header'],
51
- :host([theme~='no-padding'][has-title]) [part='header'] {
60
+ /* No padding */
61
+ :host([theme~='no-padding']) [part='content'] {
52
62
  padding: 0;
53
63
  }
54
64
 
55
- :host([theme~='no-padding'][has-footer]) [part='footer'] {
56
- padding: 0;
65
+ @media (min-height: 320px) {
66
+ :host([overflow~='top']) [part='header'] {
67
+ box-shadow: 0 1px 0 0 var(--lumo-contrast-10pct);
68
+ }
57
69
  }
58
70
 
59
71
  /* Animations */
@@ -16,17 +16,39 @@ const dialogOverlay = css`
16
16
  padding: 24px;
17
17
  }
18
18
 
19
- :host([has-header]) [part='header'],
20
- :host([has-title]) [part='header'] {
21
- padding: 9px 24px;
22
- font-weight: 500;
19
+ [part='header'] {
20
+ padding: 16px;
21
+ }
22
+
23
+ :host(:is([has-header], [has-title])) [part='header'] + [part='content'] {
24
+ padding-top: 0;
25
+ }
26
+
27
+ [part='header'],
28
+ [part='header-content'],
29
+ [part='footer'] {
23
30
  gap: 8px;
24
- border-bottom: 1px solid var(--material-divider-color);
31
+ line-height: 1.2;
25
32
  }
26
33
 
27
- :host([has-footer]) [part='footer'] {
34
+ [part='title'] {
35
+ font-size: var(--material-h5-font-size);
36
+ font-weight: 500;
37
+ margin-inline-start: 8px;
38
+ }
39
+
40
+ [part='footer'] {
28
41
  padding: 8px;
29
- border-top: 1px solid var(--material-divider-color);
42
+ }
43
+
44
+ @media (min-height: 320px) {
45
+ :host([overflow~='top']) [part='header'] {
46
+ box-shadow: 0 1px 0 0 var(--material-divider-color);
47
+ }
48
+
49
+ :host([overflow~='bottom']) [part='footer'] {
50
+ box-shadow: 0 -1px 0 0 var(--material-divider-color);
51
+ }
30
52
  }
31
53
 
32
54
  /* No padding */
@@ -36,5 +58,5 @@ const dialogOverlay = css`
36
58
  `;
37
59
 
38
60
  registerStyles('vaadin-dialog-overlay', [overlay, dialogOverlay], {
39
- moduleId: 'material-dialog'
61
+ moduleId: 'material-dialog',
40
62
  });