@vaadin/dialog 24.2.0-alpha4 → 24.2.0-dev.385a0a5b2

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": "24.2.0-alpha4",
3
+ "version": "24.2.0-dev.385a0a5b2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -23,6 +23,10 @@
23
23
  "lit.d.ts",
24
24
  "lit.js",
25
25
  "src",
26
+ "!src/vaadin-lit-dialog-overlay.d.ts",
27
+ "!src/vaadin-lit-dialog-overlay.js",
28
+ "!src/vaadin-lit-dialog.d.ts",
29
+ "!src/vaadin-lit-dialog.js",
26
30
  "theme",
27
31
  "vaadin-*.d.ts",
28
32
  "vaadin-*.js",
@@ -39,18 +43,18 @@
39
43
  "dependencies": {
40
44
  "@open-wc/dedupe-mixin": "^1.3.0",
41
45
  "@polymer/polymer": "^3.0.0",
42
- "@vaadin/component-base": "24.2.0-alpha4",
43
- "@vaadin/lit-renderer": "24.2.0-alpha4",
44
- "@vaadin/overlay": "24.2.0-alpha4",
45
- "@vaadin/vaadin-lumo-styles": "24.2.0-alpha4",
46
- "@vaadin/vaadin-material-styles": "24.2.0-alpha4",
47
- "@vaadin/vaadin-themable-mixin": "24.2.0-alpha4"
46
+ "@vaadin/component-base": "24.2.0-dev.385a0a5b2",
47
+ "@vaadin/lit-renderer": "24.2.0-dev.385a0a5b2",
48
+ "@vaadin/overlay": "24.2.0-dev.385a0a5b2",
49
+ "@vaadin/vaadin-lumo-styles": "24.2.0-dev.385a0a5b2",
50
+ "@vaadin/vaadin-material-styles": "24.2.0-dev.385a0a5b2",
51
+ "@vaadin/vaadin-themable-mixin": "24.2.0-dev.385a0a5b2"
48
52
  },
49
53
  "devDependencies": {
50
54
  "@esm-bundle/chai": "^4.3.4",
51
- "@vaadin/a11y-base": "24.2.0-alpha4",
52
- "@vaadin/testing-helpers": "^0.4.2",
53
- "@vaadin/text-area": "24.2.0-alpha4",
55
+ "@vaadin/a11y-base": "24.2.0-dev.385a0a5b2",
56
+ "@vaadin/testing-helpers": "^0.4.3",
57
+ "@vaadin/text-area": "24.2.0-dev.385a0a5b2",
54
58
  "lit": "^2.0.0",
55
59
  "sinon": "^13.0.2"
56
60
  },
@@ -58,5 +62,5 @@
58
62
  "web-types.json",
59
63
  "web-types.lit.json"
60
64
  ],
61
- "gitHead": "aaf7c5ebfea62628210eead4229be1718ac6b129"
65
+ "gitHead": "9d84e4049890430a33e91ff64a6e751a1ba9b9d9"
62
66
  }
@@ -4,12 +4,12 @@
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
6
  /* eslint-disable max-classes-per-file */
7
- import type { TemplateResult } from 'lit';
8
7
  import type { DirectiveResult } from 'lit/directive.js';
8
+ import type { LitRendererResult } from '@vaadin/lit-renderer';
9
9
  import { LitRendererDirective } from '@vaadin/lit-renderer';
10
10
  import type { Dialog } from '../vaadin-dialog.js';
11
11
 
12
- export type DialogLitRenderer = (dialog: Dialog) => TemplateResult;
12
+ export type DialogLitRenderer = (dialog: Dialog) => LitRendererResult;
13
13
 
14
14
  declare abstract class AbstractDialogRendererDirective extends LitRendererDirective<Dialog, DialogLitRenderer> {
15
15
  /**
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+
8
+ export declare function DialogBaseMixin<T extends Constructor<HTMLElement>>(
9
+ base: T,
10
+ ): Constructor<DialogBaseMixinClass> & T;
11
+
12
+ export declare class DialogBaseMixinClass {
13
+ /**
14
+ * True if the overlay is currently displayed.
15
+ */
16
+ opened: boolean;
17
+
18
+ /**
19
+ * Set to true to disable closing dialog on outside click
20
+ * @attr {boolean} no-close-on-outside-click
21
+ */
22
+ noCloseOnOutsideClick: boolean;
23
+
24
+ /**
25
+ * Set to true to disable closing dialog on Escape press
26
+ * @attr {boolean} no-close-on-esc
27
+ */
28
+ noCloseOnEsc: boolean;
29
+
30
+ /**
31
+ * Set to true to remove backdrop and allow click events on background elements.
32
+ */
33
+ modeless: boolean;
34
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+
7
+ /**
8
+ * @polymerMixin
9
+ */
10
+ export const DialogBaseMixin = (superClass) =>
11
+ class DialogBaseMixin extends superClass {
12
+ static get properties() {
13
+ return {
14
+ /**
15
+ * True if the overlay is currently displayed.
16
+ * @type {boolean}
17
+ */
18
+ opened: {
19
+ type: Boolean,
20
+ value: false,
21
+ notify: true,
22
+ },
23
+
24
+ /**
25
+ * Set to true to disable closing dialog on outside click
26
+ * @attr {boolean} no-close-on-outside-click
27
+ * @type {boolean}
28
+ */
29
+ noCloseOnOutsideClick: {
30
+ type: Boolean,
31
+ value: false,
32
+ },
33
+
34
+ /**
35
+ * Set to true to disable closing dialog on Escape press
36
+ * @attr {boolean} no-close-on-esc
37
+ * @type {boolean}
38
+ */
39
+ noCloseOnEsc: {
40
+ type: Boolean,
41
+ value: false,
42
+ },
43
+
44
+ /**
45
+ * Set to true to remove backdrop and allow click events on background elements.
46
+ * @type {boolean}
47
+ */
48
+ modeless: {
49
+ type: Boolean,
50
+ value: false,
51
+ },
52
+ };
53
+ }
54
+
55
+ /** @protected */
56
+ ready() {
57
+ super.ready();
58
+
59
+ const overlay = this.$.overlay;
60
+
61
+ overlay.addEventListener('vaadin-overlay-outside-click', this._handleOutsideClick.bind(this));
62
+ overlay.addEventListener('vaadin-overlay-escape-press', this._handleEscPress.bind(this));
63
+
64
+ this._overlayElement = overlay;
65
+ }
66
+
67
+ /** @protected */
68
+ connectedCallback() {
69
+ super.connectedCallback();
70
+ // Restore opened state if overlay was opened when disconnecting
71
+ if (this.__restoreOpened) {
72
+ this.opened = true;
73
+ }
74
+ }
75
+
76
+ /** @protected */
77
+ disconnectedCallback() {
78
+ super.disconnectedCallback();
79
+ // Automatically close the overlay when dialog is removed from DOM
80
+ // Using a timeout to avoid toggling opened state, and dispatching change
81
+ // events, when just moving the dialog in the DOM
82
+ setTimeout(() => {
83
+ if (!this.isConnected) {
84
+ this.__restoreOpened = this.opened;
85
+ this.opened = false;
86
+ }
87
+ });
88
+ }
89
+
90
+ /** @protected */
91
+ _onOverlayOpened(e) {
92
+ if (e.detail.value === false) {
93
+ this.opened = false;
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Close the dialog if `noCloseOnOutsideClick` isn't set to true
99
+ * @private
100
+ */
101
+ _handleOutsideClick(e) {
102
+ if (this.noCloseOnOutsideClick) {
103
+ e.preventDefault();
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Close the dialog if `noCloseOnEsc` isn't set to true
109
+ * @private
110
+ */
111
+ _handleEscPress(e) {
112
+ if (this.noCloseOnEsc) {
113
+ e.preventDefault();
114
+ }
115
+ }
116
+
117
+ /** @private */
118
+ _bringOverlayToFront() {
119
+ if (this.modeless) {
120
+ this._overlayElement.bringToFront();
121
+ }
122
+ }
123
+ };
@@ -45,13 +45,16 @@ export const DialogDraggableMixin = (superClass) =>
45
45
  }
46
46
 
47
47
  /** @protected */
48
- ready() {
48
+ async ready() {
49
49
  super.ready();
50
50
  this._originalBounds = {};
51
51
  this._originalMouseCoords = {};
52
52
  this._startDrag = this._startDrag.bind(this);
53
53
  this._drag = this._drag.bind(this);
54
54
  this._stopDrag = this._stopDrag.bind(this);
55
+
56
+ // Wait for overlay render
57
+ await new Promise(requestAnimationFrame);
55
58
  this.$.overlay.$.overlay.addEventListener('mousedown', this._startDrag);
56
59
  this.$.overlay.$.overlay.addEventListener('touchstart', this._startDrag);
57
60
  }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import type { Constructor } from '@open-wc/dedupe-mixin';
7
+ import type { OverlayMixinClass } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
8
+ import type { DialogRenderer } from './vaadin-dialog.js';
9
+
10
+ export type DialogOverlayBounds = {
11
+ top: number;
12
+ left: number;
13
+ width: number;
14
+ height: number;
15
+ };
16
+
17
+ export type DialogOverlayBoundsParam =
18
+ | DialogOverlayBounds
19
+ | {
20
+ top?: number | string;
21
+ left?: number | string;
22
+ width?: number | string;
23
+ height?: number | string;
24
+ };
25
+
26
+ export declare function DialogOverlayMixin<T extends Constructor<HTMLElement>>(
27
+ base: T,
28
+ ): Constructor<DialogOverlayMixinClass> & Constructor<OverlayMixinClass> & T;
29
+
30
+ export declare class DialogOverlayMixinClass {
31
+ /**
32
+ * String used for rendering a dialog title.
33
+ * @attr {string} header-title
34
+ */
35
+ headerTitle: string;
36
+
37
+ /**
38
+ * Custom function for rendering the dialog header.
39
+ */
40
+ headerRenderer: DialogRenderer | null | undefined;
41
+
42
+ /**
43
+ * Custom function for rendering the dialog footer.
44
+ */
45
+ footerRenderer: DialogRenderer | null | undefined;
46
+
47
+ /**
48
+ * Retrieves the coordinates of the overlay.
49
+ */
50
+ getBounds(): DialogOverlayBounds;
51
+
52
+ /**
53
+ * Updates the coordinates of the overlay.
54
+ */
55
+ setBounds(bounds: DialogOverlayBoundsParam): void;
56
+ }
@@ -0,0 +1,257 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2017 - 2023 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { OverlayMixin } from '@vaadin/overlay/src/vaadin-overlay-mixin.js';
7
+
8
+ /**
9
+ * @polymerMixin
10
+ * @mixes OverlayMixin
11
+ */
12
+ export const DialogOverlayMixin = (superClass) =>
13
+ class DialogOverlayMixin extends OverlayMixin(superClass) {
14
+ static get properties() {
15
+ return {
16
+ /**
17
+ * String used for rendering a dialog title.
18
+ */
19
+ headerTitle: {
20
+ type: String,
21
+ },
22
+
23
+ /**
24
+ * Custom function for rendering the dialog header.
25
+ */
26
+ headerRenderer: {
27
+ type: Object,
28
+ },
29
+
30
+ /**
31
+ * Custom function for rendering the dialog footer.
32
+ */
33
+ footerRenderer: {
34
+ type: Object,
35
+ },
36
+ };
37
+ }
38
+
39
+ static get observers() {
40
+ return [
41
+ '_headerFooterRendererChange(headerRenderer, footerRenderer, opened)',
42
+ '_headerTitleChanged(headerTitle, opened)',
43
+ ];
44
+ }
45
+
46
+ /** @protected */
47
+ ready() {
48
+ super.ready();
49
+
50
+ // Update overflow attribute on resize
51
+ this.__resizeObserver = new ResizeObserver(() => {
52
+ this.__updateOverflow();
53
+ });
54
+ this.__resizeObserver.observe(this.$.resizerContainer);
55
+
56
+ // Update overflow attribute on scroll
57
+ this.$.content.addEventListener('scroll', () => {
58
+ this.__updateOverflow();
59
+ });
60
+ }
61
+
62
+ /** @private */
63
+ __createContainer(slot) {
64
+ const container = document.createElement('div');
65
+ container.setAttribute('slot', slot);
66
+ return container;
67
+ }
68
+
69
+ /** @private */
70
+ __clearContainer(container) {
71
+ container.innerHTML = '';
72
+ // Whenever a Lit-based renderer is used, it assigns a Lit part to the node it was rendered into.
73
+ // When clearing the rendered content, this part needs to be manually disposed of.
74
+ // Otherwise, using a Lit-based renderer on the same node will throw an exception or render nothing afterward.
75
+ delete container._$litPart$;
76
+ }
77
+
78
+ /** @private */
79
+ __initContainer(container, slot) {
80
+ if (container) {
81
+ // Reset existing container in case if a new renderer is set.
82
+ this.__clearContainer(container);
83
+ } else {
84
+ // Create the container, but wait to append it until requestContentUpdate is called.
85
+ container = this.__createContainer(slot);
86
+ }
87
+ return container;
88
+ }
89
+
90
+ /** @private */
91
+ _headerFooterRendererChange(headerRenderer, footerRenderer, opened) {
92
+ const headerRendererChanged = this.__oldHeaderRenderer !== headerRenderer;
93
+ this.__oldHeaderRenderer = headerRenderer;
94
+
95
+ const footerRendererChanged = this.__oldFooterRenderer !== footerRenderer;
96
+ this.__oldFooterRenderer = footerRenderer;
97
+
98
+ const openedChanged = this._oldOpenedFooterHeader !== opened;
99
+ this._oldOpenedFooterHeader = opened;
100
+
101
+ // Set attributes here to update styles before detecting content overflow
102
+ this.toggleAttribute('has-header', !!headerRenderer);
103
+ this.toggleAttribute('has-footer', !!footerRenderer);
104
+
105
+ if (headerRendererChanged) {
106
+ if (headerRenderer) {
107
+ this.headerContainer = this.__initContainer(this.headerContainer, 'header-content');
108
+ } else if (this.headerContainer) {
109
+ this.headerContainer.remove();
110
+ this.headerContainer = null;
111
+ this.__updateOverflow();
112
+ }
113
+ }
114
+
115
+ if (footerRendererChanged) {
116
+ if (footerRenderer) {
117
+ this.footerContainer = this.__initContainer(this.footerContainer, 'footer');
118
+ } else if (this.footerContainer) {
119
+ this.footerContainer.remove();
120
+ this.footerContainer = null;
121
+ this.__updateOverflow();
122
+ }
123
+ }
124
+
125
+ if (
126
+ (headerRenderer && (headerRendererChanged || openedChanged)) ||
127
+ (footerRenderer && (footerRendererChanged || openedChanged))
128
+ ) {
129
+ if (opened) {
130
+ this.requestContentUpdate();
131
+ }
132
+ }
133
+ }
134
+
135
+ /** @private */
136
+ _headerTitleChanged(headerTitle, opened) {
137
+ this.toggleAttribute('has-title', !!headerTitle);
138
+
139
+ if (opened && (headerTitle || this._oldHeaderTitle)) {
140
+ this.requestContentUpdate();
141
+ }
142
+ this._oldHeaderTitle = headerTitle;
143
+ }
144
+
145
+ /** @private */
146
+ _headerTitleRenderer() {
147
+ if (this.headerTitle) {
148
+ if (!this.headerTitleElement) {
149
+ this.headerTitleElement = document.createElement('h2');
150
+ this.headerTitleElement.setAttribute('slot', 'title');
151
+ this.headerTitleElement.classList.add('draggable');
152
+ }
153
+ this.appendChild(this.headerTitleElement);
154
+ this.headerTitleElement.textContent = this.headerTitle;
155
+ } else if (this.headerTitleElement) {
156
+ this.headerTitleElement.remove();
157
+ this.headerTitleElement = null;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * @override
163
+ */
164
+ requestContentUpdate() {
165
+ super.requestContentUpdate();
166
+
167
+ if (this.headerContainer) {
168
+ // If a new renderer has been set, make sure to reattach the container
169
+ if (!this.headerContainer.parentElement) {
170
+ this.appendChild(this.headerContainer);
171
+ }
172
+
173
+ if (this.headerRenderer) {
174
+ // Only call header renderer after the container has been initialized
175
+ this.headerRenderer.call(this.owner, this.headerContainer, this.owner);
176
+ }
177
+ }
178
+
179
+ if (this.footerContainer) {
180
+ // If a new renderer has been set, make sure to reattach the container
181
+ if (!this.footerContainer.parentElement) {
182
+ this.appendChild(this.footerContainer);
183
+ }
184
+
185
+ if (this.footerRenderer) {
186
+ // Only call header renderer after the container has been initialized
187
+ this.footerRenderer.call(this.owner, this.footerContainer, this.owner);
188
+ }
189
+ }
190
+
191
+ this._headerTitleRenderer();
192
+
193
+ this.__updateOverflow();
194
+ }
195
+
196
+ /**
197
+ * Updates the coordinates of the overlay.
198
+ * @param {!DialogOverlayBoundsParam} bounds
199
+ */
200
+ setBounds(bounds) {
201
+ const overlay = this.$.overlay;
202
+ const parsedBounds = { ...bounds };
203
+
204
+ if (overlay.style.position !== 'absolute') {
205
+ overlay.style.position = 'absolute';
206
+ this.setAttribute('has-bounds-set', '');
207
+ }
208
+
209
+ Object.keys(parsedBounds).forEach((arg) => {
210
+ if (typeof parsedBounds[arg] === 'number') {
211
+ parsedBounds[arg] = `${parsedBounds[arg]}px`;
212
+ }
213
+ });
214
+
215
+ Object.assign(overlay.style, parsedBounds);
216
+ }
217
+
218
+ /**
219
+ * Retrieves the coordinates of the overlay.
220
+ * @return {!DialogOverlayBounds}
221
+ */
222
+ getBounds() {
223
+ const overlayBounds = this.$.overlay.getBoundingClientRect();
224
+ const containerBounds = this.getBoundingClientRect();
225
+ const top = overlayBounds.top - containerBounds.top;
226
+ const left = overlayBounds.left - containerBounds.left;
227
+ const width = overlayBounds.width;
228
+ const height = overlayBounds.height;
229
+ return { top, left, width, height };
230
+ }
231
+
232
+ /** @private */
233
+ __updateOverflow() {
234
+ let overflow = '';
235
+
236
+ // Only set "overflow" attribute if the dialog has a header, title or footer.
237
+ // Check for state attributes as extending components might not use renderers.
238
+ if (this.hasAttribute('has-header') || this.hasAttribute('has-footer') || this.headerTitle) {
239
+ const content = this.$.content;
240
+
241
+ if (content.scrollTop > 0) {
242
+ overflow += ' top';
243
+ }
244
+
245
+ if (content.scrollTop < content.scrollHeight - content.clientHeight) {
246
+ overflow += ' bottom';
247
+ }
248
+ }
249
+
250
+ const value = overflow.trim();
251
+ if (value.length > 0 && this.getAttribute('overflow') !== value) {
252
+ this.setAttribute('overflow', value);
253
+ } else if (value.length === 0 && this.hasAttribute('overflow')) {
254
+ this.removeAttribute('overflow');
255
+ }
256
+ }
257
+ };
@@ -3,38 +3,16 @@
3
3
  * Copyright (c) 2017 - 2023 Vaadin Ltd.
4
4
  * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
5
  */
6
- import { Overlay } from '@vaadin/overlay/src/vaadin-overlay.js';
6
+ import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
7
+ import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
8
+ import { DialogOverlayMixin } from './vaadin-dialog-overlay-mixin.js';
7
9
 
8
- export type DialogOverlayBounds = {
9
- top: number;
10
- left: number;
11
- width: number;
12
- height: number;
13
- };
14
-
15
- export type DialogOverlayBoundsParam =
16
- | DialogOverlayBounds
17
- | {
18
- top?: number | string;
19
- left?: number | string;
20
- width?: number | string;
21
- height?: number | string;
22
- };
10
+ export { DialogOverlayBounds, DialogOverlayBoundsParam } from './vaadin-dialog-overlay-mixin.js';
23
11
 
24
12
  /**
25
13
  * An element used internally by `<vaadin-dialog>`. Not intended to be used separately.
26
14
  */
27
- export class DialogOverlay extends Overlay {
28
- /**
29
- * Retrieves the coordinates of the overlay.
30
- */
31
- getBounds(): DialogOverlayBounds;
32
-
33
- /**
34
- * Updates the coordinates of the overlay.
35
- */
36
- setBounds(bounds: DialogOverlayBoundsParam): void;
37
- }
15
+ export class DialogOverlay extends DialogOverlayMixin(DirMixin(ThemableMixin(HTMLElement))) {}
38
16
 
39
17
  declare global {
40
18
  interface HTMLElementTagNameMap {