@vaadin/dialog 22.0.0-alpha10

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.
@@ -0,0 +1,351 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) 2021 Vaadin Ltd.
4
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
5
+ */
6
+ import { PolymerElement, html } from '@polymer/polymer/polymer-element.js';
7
+ import { IronResizableBehavior } from '@polymer/iron-resizable-behavior/iron-resizable-behavior.js';
8
+ import { mixinBehaviors } from '@polymer/polymer/lib/legacy/class.js';
9
+ import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
10
+ import { processTemplates } from '@vaadin/component-base/src/templates.js';
11
+ import { OverlayElement } from '@vaadin/vaadin-overlay/src/vaadin-overlay.js';
12
+ import { ThemePropertyMixin } from '@vaadin/vaadin-themable-mixin/vaadin-theme-property-mixin.js';
13
+ import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
14
+ import { DialogDraggableMixin } from './vaadin-dialog-draggable-mixin.js';
15
+ import { DialogResizableMixin } from './vaadin-dialog-resizable-mixin.js';
16
+
17
+ registerStyles(
18
+ 'vaadin-dialog-overlay',
19
+ css`
20
+ /*
21
+ NOTE(platosha): Make some min-width to prevent collapsing of the content
22
+ taking the parent width, e. g., <vaadin-grid> and such.
23
+ */
24
+ [part='content'] {
25
+ min-width: 12em; /* matches the default <vaadin-text-field> width */
26
+ }
27
+
28
+ :host([has-bounds-set]) [part='overlay'] {
29
+ max-width: none;
30
+ }
31
+ `,
32
+ { moduleId: 'vaadin-dialog-overlay-styles' }
33
+ );
34
+
35
+ let memoizedTemplate;
36
+
37
+ /**
38
+ * An element used internally by `<vaadin-dialog>`. Not intended to be used separately.
39
+ *
40
+ * @extends OverlayElement
41
+ * @private
42
+ */
43
+ class DialogOverlay extends mixinBehaviors(IronResizableBehavior, OverlayElement) {
44
+ static get is() {
45
+ return 'vaadin-dialog-overlay';
46
+ }
47
+
48
+ static get template() {
49
+ if (!memoizedTemplate) {
50
+ memoizedTemplate = super.template.cloneNode(true);
51
+ const contentPart = memoizedTemplate.content.querySelector('[part="content"]');
52
+ const overlayPart = memoizedTemplate.content.querySelector('[part="overlay"]');
53
+ const resizerContainer = document.createElement('div');
54
+ resizerContainer.id = 'resizerContainer';
55
+ resizerContainer.classList.add('resizer-container');
56
+ resizerContainer.appendChild(contentPart);
57
+ overlayPart.appendChild(resizerContainer);
58
+ }
59
+ return memoizedTemplate;
60
+ }
61
+
62
+ static get properties() {
63
+ return {
64
+ modeless: Boolean,
65
+
66
+ withBackdrop: Boolean
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Updates the coordinates of the overlay.
72
+ * @param {!DialogOverlayBoundsParam} bounds
73
+ */
74
+ setBounds(bounds) {
75
+ const overlay = this.$.overlay;
76
+ const parsedBounds = Object.assign({}, bounds);
77
+
78
+ if (overlay.style.position !== 'absolute') {
79
+ overlay.style.position = 'absolute';
80
+ this.setAttribute('has-bounds-set', '');
81
+ this.__forceSafariReflow();
82
+ }
83
+
84
+ for (const arg in parsedBounds) {
85
+ if (typeof parsedBounds[arg] === 'number') {
86
+ parsedBounds[arg] = `${parsedBounds[arg]}px`;
87
+ }
88
+ }
89
+
90
+ Object.assign(overlay.style, parsedBounds);
91
+ }
92
+
93
+ /**
94
+ * Retrieves the coordinates of the overlay.
95
+ * @return {!DialogOverlayBounds}
96
+ */
97
+ getBounds() {
98
+ const overlayBounds = this.$.overlay.getBoundingClientRect();
99
+ const containerBounds = this.getBoundingClientRect();
100
+ const top = overlayBounds.top - containerBounds.top;
101
+ const left = overlayBounds.left - containerBounds.left;
102
+ const width = overlayBounds.width;
103
+ const height = overlayBounds.height;
104
+ return { top, left, width, height };
105
+ }
106
+
107
+ /**
108
+ * Safari 13 renders overflowing elements incorrectly.
109
+ * This forces it to recalculate height.
110
+ * @private
111
+ */
112
+ __forceSafariReflow() {
113
+ const scrollPosition = this.$.resizerContainer.scrollTop;
114
+ const overlay = this.$.overlay;
115
+ overlay.style.display = 'block';
116
+
117
+ requestAnimationFrame(() => {
118
+ overlay.style.display = '';
119
+ this.$.resizerContainer.scrollTop = scrollPosition;
120
+ });
121
+ }
122
+ }
123
+
124
+ customElements.define(DialogOverlay.is, DialogOverlay);
125
+
126
+ /**
127
+ * `<vaadin-dialog>` is a Web Component for creating customized modal dialogs.
128
+ *
129
+ * ### Rendering
130
+ *
131
+ * The content of the dialog can be populated by using the renderer callback function.
132
+ *
133
+ * The renderer function provides `root`, `dialog` arguments.
134
+ * Generate DOM content, append it to the `root` element and control the state
135
+ * of the host element by accessing `dialog`. Before generating new content,
136
+ * users are able to check if there is already content in `root` for reusing it.
137
+ *
138
+ * ```html
139
+ * <vaadin-dialog id="dialog"></vaadin-dialog>
140
+ * ```
141
+ * ```js
142
+ * const dialog = document.querySelector('#dialog');
143
+ * dialog.renderer = function(root, dialog) {
144
+ * root.textContent = "Sample dialog";
145
+ * };
146
+ * ```
147
+ *
148
+ * Renderer is called on the opening of the dialog.
149
+ * DOM generated during the renderer call can be reused
150
+ * in the next renderer call and will be provided with the `root` argument.
151
+ * On first call it will be empty.
152
+ *
153
+ * ### Styling
154
+ *
155
+ * `<vaadin-dialog>` uses `<vaadin-dialog-overlay>` internal
156
+ * themable component as the actual visible dialog overlay.
157
+ *
158
+ * See [`<vaadin-overlay>`](#/elements/vaadin-overlay) documentation.
159
+ * for `<vaadin-dialog-overlay>` parts.
160
+ *
161
+ * Note: the `theme` attribute value set on `<vaadin-dialog>` is
162
+ * propagated to the internal `<vaadin-dialog-overlay>` component.
163
+ *
164
+ * See [Styling Components](https://vaadin.com/docs/latest/ds/customization/styling-components) documentation.
165
+ *
166
+ * @fires {CustomEvent} resize - Fired when the dialog resize is finished.
167
+ * @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
168
+ *
169
+ * @extends HTMLElement
170
+ * @mixes ThemePropertyMixin
171
+ * @mixes ElementMixin
172
+ * @mixes DialogDraggableMixin
173
+ * @mixes DialogResizableMixin
174
+ */
175
+ class Dialog extends ThemePropertyMixin(ElementMixin(DialogDraggableMixin(DialogResizableMixin(PolymerElement)))) {
176
+ static get template() {
177
+ return html`
178
+ <style>
179
+ :host {
180
+ display: none;
181
+ }
182
+ </style>
183
+
184
+ <vaadin-dialog-overlay
185
+ id="overlay"
186
+ on-opened-changed="_onOverlayOpened"
187
+ on-mousedown="_bringOverlayToFront"
188
+ on-touchstart="_bringOverlayToFront"
189
+ theme$="[[theme]]"
190
+ modeless="[[modeless]]"
191
+ with-backdrop="[[!modeless]]"
192
+ resizable$="[[resizable]]"
193
+ focus-trap
194
+ ></vaadin-dialog-overlay>
195
+ `;
196
+ }
197
+
198
+ static get is() {
199
+ return 'vaadin-dialog';
200
+ }
201
+
202
+ static get properties() {
203
+ return {
204
+ /**
205
+ * True if the overlay is currently displayed.
206
+ * @type {boolean}
207
+ */
208
+ opened: {
209
+ type: Boolean,
210
+ value: false,
211
+ notify: true
212
+ },
213
+
214
+ /**
215
+ * Set to true to disable closing dialog on outside click
216
+ * @attr {boolean} no-close-on-outside-click
217
+ * @type {boolean}
218
+ */
219
+ noCloseOnOutsideClick: {
220
+ type: Boolean,
221
+ value: false
222
+ },
223
+
224
+ /**
225
+ * Set to true to disable closing dialog on Escape press
226
+ * @attr {boolean} no-close-on-esc
227
+ * @type {boolean}
228
+ */
229
+ noCloseOnEsc: {
230
+ type: Boolean,
231
+ value: false
232
+ },
233
+
234
+ /**
235
+ * Set the `aria-label` attribute for assistive technologies like
236
+ * screen readers. An empty string value for this property (the
237
+ * default) means that the `aria-label` attribute is not present.
238
+ */
239
+ ariaLabel: {
240
+ type: String,
241
+ value: ''
242
+ },
243
+
244
+ /**
245
+ * Custom function for rendering the content of the dialog.
246
+ * Receives two arguments:
247
+ *
248
+ * - `root` The root container DOM element. Append your content to it.
249
+ * - `dialog` The reference to the `<vaadin-dialog>` element.
250
+ * @type {DialogRenderer | undefined}
251
+ */
252
+ renderer: Function,
253
+
254
+ /**
255
+ * Set to true to remove backdrop and allow click events on background elements.
256
+ * @type {boolean}
257
+ */
258
+ modeless: {
259
+ type: Boolean,
260
+ value: false
261
+ }
262
+ };
263
+ }
264
+
265
+ static get observers() {
266
+ return ['_openedChanged(opened)', '_ariaLabelChanged(ariaLabel)', '_rendererChanged(renderer)'];
267
+ }
268
+
269
+ /** @protected */
270
+ ready() {
271
+ super.ready();
272
+ this.$.overlay.setAttribute('role', 'dialog');
273
+ this.$.overlay.addEventListener('vaadin-overlay-outside-click', this._handleOutsideClick.bind(this));
274
+ this.$.overlay.addEventListener('vaadin-overlay-escape-press', this._handleEscPress.bind(this));
275
+
276
+ processTemplates(this);
277
+ }
278
+
279
+ /**
280
+ * Requests an update for the content of the dialog.
281
+ * While performing the update, it invokes the renderer passed in the `renderer` property.
282
+ *
283
+ * It is not guaranteed that the update happens immediately (synchronously) after it is requested.
284
+ */
285
+ requestContentUpdate() {
286
+ this.$.overlay.requestContentUpdate();
287
+ }
288
+
289
+ /** @private */
290
+ _rendererChanged(renderer) {
291
+ this.$.overlay.setProperties({ owner: this, renderer });
292
+ }
293
+
294
+ /** @protected */
295
+ disconnectedCallback() {
296
+ super.disconnectedCallback();
297
+ this.opened = false;
298
+ }
299
+
300
+ /** @private */
301
+ _openedChanged(opened) {
302
+ this.$.overlay.opened = opened;
303
+ }
304
+
305
+ /** @private */
306
+ _ariaLabelChanged(ariaLabel) {
307
+ if (ariaLabel) {
308
+ this.$.overlay.setAttribute('aria-label', ariaLabel);
309
+ } else {
310
+ this.$.overlay.removeAttribute('aria-label');
311
+ }
312
+ }
313
+
314
+ /** @private */
315
+ _onOverlayOpened(e) {
316
+ if (e.detail.value === false) {
317
+ this.opened = false;
318
+ }
319
+ }
320
+
321
+ /**
322
+ * Close the dialog if `noCloseOnOutsideClick` isn't set to true
323
+ * @private
324
+ */
325
+ _handleOutsideClick(e) {
326
+ if (this.noCloseOnOutsideClick) {
327
+ e.preventDefault();
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Close the dialog if `noCloseOnEsc` isn't set to true
333
+ * @private
334
+ */
335
+ _handleEscPress(e) {
336
+ if (this.noCloseOnEsc) {
337
+ e.preventDefault();
338
+ }
339
+ }
340
+
341
+ /** @private */
342
+ _bringOverlayToFront() {
343
+ if (this.modeless) {
344
+ this.$.overlay.bringToFront();
345
+ }
346
+ }
347
+ }
348
+
349
+ customElements.define(Dialog.is, Dialog);
350
+
351
+ export { Dialog };
@@ -0,0 +1,69 @@
1
+ import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
2
+ import '@vaadin/vaadin-lumo-styles/spacing.js';
3
+ import { overlay } from '@vaadin/vaadin-lumo-styles/mixins/overlay.js';
4
+
5
+ const dialogOverlay = css`
6
+ /* Optical centering */
7
+ :host::before,
8
+ :host::after {
9
+ content: '';
10
+ flex-basis: 0;
11
+ flex-grow: 1;
12
+ }
13
+
14
+ :host::after {
15
+ flex-grow: 1.1;
16
+ }
17
+
18
+ [part='overlay'] {
19
+ border-radius: var(--lumo-border-radius-l);
20
+ box-shadow: 0 0 0 1px var(--lumo-shade-5pct), var(--lumo-box-shadow-xl);
21
+ background-image: none;
22
+ outline: none;
23
+ -webkit-tap-highlight-color: transparent;
24
+ }
25
+
26
+ [part='content'] {
27
+ padding: var(--lumo-space-l);
28
+ }
29
+
30
+ /* No padding */
31
+ :host([theme~='no-padding']) [part='content'] {
32
+ padding: 0;
33
+ }
34
+
35
+ /* Animations */
36
+
37
+ :host([opening]),
38
+ :host([closing]) {
39
+ animation: 0.25s lumo-overlay-dummy-animation;
40
+ }
41
+
42
+ :host([opening]) [part='overlay'] {
43
+ animation: 0.12s 0.05s vaadin-dialog-enter cubic-bezier(0.215, 0.61, 0.355, 1) both;
44
+ }
45
+
46
+ @keyframes vaadin-dialog-enter {
47
+ 0% {
48
+ opacity: 0;
49
+ transform: scale(0.95);
50
+ }
51
+ }
52
+
53
+ :host([closing]) [part='overlay'] {
54
+ animation: 0.1s 0.03s vaadin-dialog-exit cubic-bezier(0.55, 0.055, 0.675, 0.19) both;
55
+ }
56
+
57
+ :host([closing]) [part='backdrop'] {
58
+ animation-delay: 0.05s;
59
+ }
60
+
61
+ @keyframes vaadin-dialog-exit {
62
+ 100% {
63
+ opacity: 0;
64
+ transform: scale(1.02);
65
+ }
66
+ }
67
+ `;
68
+
69
+ registerStyles('vaadin-dialog-overlay', [overlay, dialogOverlay], { moduleId: 'lumo-dialog' });
@@ -0,0 +1,2 @@
1
+ import './vaadin-dialog-styles.js';
2
+ import '../../src/vaadin-dialog.js';
@@ -0,0 +1,26 @@
1
+ import { registerStyles, css } from '@vaadin/vaadin-themable-mixin/register-styles.js';
2
+ import { overlay } from '@vaadin/vaadin-material-styles/mixins/overlay.js';
3
+ import '@vaadin/vaadin-material-styles/shadow.js';
4
+
5
+ const dialogOverlay = css`
6
+ [part='overlay'] {
7
+ box-shadow: var(--material-shadow-elevation-24dp);
8
+ outline: none;
9
+ max-width: 560px;
10
+ min-width: 280px;
11
+ -webkit-tap-highlight-color: transparent;
12
+ }
13
+
14
+ [part='content'] {
15
+ padding: 24px;
16
+ }
17
+
18
+ /* No padding */
19
+ :host([theme~='no-padding']) [part='content'] {
20
+ padding: 0;
21
+ }
22
+ `;
23
+
24
+ registerStyles('vaadin-dialog-overlay', [overlay, dialogOverlay], {
25
+ moduleId: 'material-dialog'
26
+ });
@@ -0,0 +1,2 @@
1
+ import './vaadin-dialog-styles.js';
2
+ import '../../src/vaadin-dialog.js';
@@ -0,0 +1 @@
1
+ export * from './src/vaadin-dialog.js';
@@ -0,0 +1,2 @@
1
+ import './theme/lumo/vaadin-dialog.js';
2
+ export * from './src/vaadin-dialog.js';