@everymatrix/general-registration 1.21.2 → 1.21.4
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/dist/cjs/checkbox-group-input_13.cjs.entry.js +36089 -20728
- package/dist/cjs/index.cjs.js +0 -16
- package/dist/collection/index.js +17 -16
- package/dist/components/active-mixin.js +97 -7
- package/dist/components/checkbox-group-input2.js +4169 -496
- package/dist/components/date-input2.js +8052 -3274
- package/dist/components/field-mixin.js +1879 -3982
- package/dist/components/index.js +0 -17
- package/dist/components/input-field-shared-styles.js +1347 -327
- package/dist/components/password-input2.js +3860 -288
- package/dist/components/vaadin-button.js +2088 -228
- package/dist/components/vaadin-combo-box.js +4117 -809
- package/dist/components/virtual-keyboard-controller.js +1056 -1816
- package/dist/esm/checkbox-group-input_13.entry.js +36089 -20728
- package/dist/esm/index.js +1 -16
- package/dist/general-registration/general-registration.esm.js +1 -1
- package/dist/general-registration/index.esm.js +0 -1
- package/dist/general-registration/p-d90b8853.entry.js +8627 -0
- package/package.json +6 -6
- package/dist/components/pattern-mixin.js +0 -85
- package/dist/general-registration/p-7cae0c34.entry.js +0 -3584
|
@@ -1,80 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { b as isIOS } from './input-field-shared-styles.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @license
|
|
6
|
-
* Copyright (c) 2017 - 2022 Vaadin Ltd.
|
|
7
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const overlay = i`
|
|
11
|
-
:host {
|
|
12
|
-
top: var(--lumo-space-m);
|
|
13
|
-
right: var(--lumo-space-m);
|
|
14
|
-
bottom: var(--lumo-space-m);
|
|
15
|
-
left: var(--lumo-space-m);
|
|
16
|
-
/* Workaround for Edge issue (only on Surface), where an overflowing vaadin-list-box inside vaadin-select-overlay makes the overlay transparent */
|
|
17
|
-
/* stylelint-disable-next-line */
|
|
18
|
-
outline: 0px solid transparent;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
[part='overlay'] {
|
|
22
|
-
background-color: var(--lumo-base-color);
|
|
23
|
-
background-image: linear-gradient(var(--lumo-tint-5pct), var(--lumo-tint-5pct));
|
|
24
|
-
border-radius: var(--lumo-border-radius-m);
|
|
25
|
-
box-shadow: 0 0 0 1px var(--lumo-shade-5pct), var(--lumo-box-shadow-m);
|
|
26
|
-
color: var(--lumo-body-text-color);
|
|
27
|
-
font-family: var(--lumo-font-family);
|
|
28
|
-
font-size: var(--lumo-font-size-m);
|
|
29
|
-
font-weight: 400;
|
|
30
|
-
line-height: var(--lumo-line-height-m);
|
|
31
|
-
letter-spacing: 0;
|
|
32
|
-
text-transform: none;
|
|
33
|
-
-webkit-text-size-adjust: 100%;
|
|
34
|
-
-webkit-font-smoothing: antialiased;
|
|
35
|
-
-moz-osx-font-smoothing: grayscale;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
[part='content'] {
|
|
39
|
-
padding: var(--lumo-space-xs);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
[part='backdrop'] {
|
|
43
|
-
background-color: var(--lumo-shade-20pct);
|
|
44
|
-
animation: 0.2s lumo-overlay-backdrop-enter both;
|
|
45
|
-
will-change: opacity;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
@keyframes lumo-overlay-backdrop-enter {
|
|
49
|
-
0% {
|
|
50
|
-
opacity: 0;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
:host([closing]) [part='backdrop'] {
|
|
55
|
-
animation: 0.2s lumo-overlay-backdrop-exit both;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
@keyframes lumo-overlay-backdrop-exit {
|
|
59
|
-
100% {
|
|
60
|
-
opacity: 0;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@keyframes lumo-overlay-dummy-animation {
|
|
65
|
-
0% {
|
|
66
|
-
opacity: 1;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
100% {
|
|
70
|
-
opacity: 1;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
`;
|
|
74
|
-
|
|
75
|
-
registerStyles('', overlay, { moduleId: 'lumo-overlay' });
|
|
76
|
-
|
|
77
|
-
registerStyles('vaadin-overlay', overlay, { moduleId: 'lumo-vaadin-overlay' });
|
|
1
|
+
import { v as getDeepActiveElement, x as getFocusableElements, b as isElementFocused, d as dedupingMixin, i } from './field-mixin.js';
|
|
78
2
|
|
|
79
3
|
/**
|
|
80
4
|
@license
|
|
@@ -150,851 +74,362 @@ function afterNextRender(context, callback, args) {
|
|
|
150
74
|
}
|
|
151
75
|
|
|
152
76
|
/**
|
|
153
|
-
@license
|
|
154
|
-
Copyright (c)
|
|
155
|
-
|
|
156
|
-
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
157
|
-
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
158
|
-
Code distributed by Google as part of the polymer project is also
|
|
159
|
-
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
160
|
-
*/
|
|
161
|
-
|
|
162
|
-
// Common implementation for mixin & behavior
|
|
163
|
-
function mutablePropertyChange(inst, property, value, old, mutableData) {
|
|
164
|
-
let isObject;
|
|
165
|
-
if (mutableData) {
|
|
166
|
-
isObject = (typeof value === 'object' && value !== null);
|
|
167
|
-
// Pull `old` for Objects from temp cache, but treat `null` as a primitive
|
|
168
|
-
if (isObject) {
|
|
169
|
-
old = inst.__dataTemp[property];
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
// Strict equality check, but return false for NaN===NaN
|
|
173
|
-
let shouldChange = (old !== value && (old === old || value === value));
|
|
174
|
-
// Objects are stored in temporary cache (cleared at end of
|
|
175
|
-
// turn), which is used for dirty-checking
|
|
176
|
-
if (isObject && shouldChange) {
|
|
177
|
-
inst.__dataTemp[property] = value;
|
|
178
|
-
}
|
|
179
|
-
return shouldChange;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Element class mixin to skip strict dirty-checking for objects and arrays
|
|
184
|
-
* (always consider them to be "dirty"), for use on elements utilizing
|
|
185
|
-
* `PropertyEffects`
|
|
186
|
-
*
|
|
187
|
-
* By default, `PropertyEffects` performs strict dirty checking on
|
|
188
|
-
* objects, which means that any deep modifications to an object or array will
|
|
189
|
-
* not be propagated unless "immutable" data patterns are used (i.e. all object
|
|
190
|
-
* references from the root to the mutation were changed).
|
|
191
|
-
*
|
|
192
|
-
* Polymer also provides a proprietary data mutation and path notification API
|
|
193
|
-
* (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient
|
|
194
|
-
* mutation and notification of deep changes in an object graph to all elements
|
|
195
|
-
* bound to the same object graph.
|
|
196
|
-
*
|
|
197
|
-
* In cases where neither immutable patterns nor the data mutation API can be
|
|
198
|
-
* used, applying this mixin will cause Polymer to skip dirty checking for
|
|
199
|
-
* objects and arrays (always consider them to be "dirty"). This allows a
|
|
200
|
-
* user to make a deep modification to a bound object graph, and then either
|
|
201
|
-
* simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`
|
|
202
|
-
* (e.g. `this.notifyPath('items')`) to update the tree. Note that all
|
|
203
|
-
* elements that wish to be updated based on deep mutations must apply this
|
|
204
|
-
* mixin or otherwise skip strict dirty checking for objects/arrays.
|
|
205
|
-
* Specifically, any elements in the binding tree between the source of a
|
|
206
|
-
* mutation and the consumption of it must apply this mixin or enable the
|
|
207
|
-
* `OptionalMutableData` mixin.
|
|
208
|
-
*
|
|
209
|
-
* In order to make the dirty check strategy configurable, see
|
|
210
|
-
* `OptionalMutableData`.
|
|
211
|
-
*
|
|
212
|
-
* Note, the performance characteristics of propagating large object graphs
|
|
213
|
-
* will be worse as opposed to using strict dirty checking with immutable
|
|
214
|
-
* patterns or Polymer's path notification API.
|
|
215
|
-
*
|
|
216
|
-
* @mixinFunction
|
|
217
|
-
* @polymer
|
|
218
|
-
* @summary Element class mixin to skip strict dirty-checking for objects
|
|
219
|
-
* and arrays
|
|
220
|
-
* @template T
|
|
221
|
-
* @param {function(new:T)} superClass Class to apply mixin to.
|
|
222
|
-
* @return {function(new:T)} superClass with mixin applied.
|
|
77
|
+
* @license
|
|
78
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
79
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
223
80
|
*/
|
|
224
|
-
const MutableData = dedupingMixin(superClass => {
|
|
225
81
|
|
|
226
|
-
|
|
227
|
-
* @polymer
|
|
228
|
-
* @mixinClass
|
|
229
|
-
* @implements {Polymer_MutableData}
|
|
230
|
-
*/
|
|
231
|
-
class MutableData extends superClass {
|
|
232
|
-
/**
|
|
233
|
-
* Overrides `PropertyEffects` to provide option for skipping
|
|
234
|
-
* strict equality checking for Objects and Arrays.
|
|
235
|
-
*
|
|
236
|
-
* This method pulls the value to dirty check against from the `__dataTemp`
|
|
237
|
-
* cache (rather than the normal `__data` cache) for Objects. Since the temp
|
|
238
|
-
* cache is cleared at the end of a turn, this implementation allows
|
|
239
|
-
* side-effects of deep object changes to be processed by re-setting the
|
|
240
|
-
* same object (using the temp cache as an in-turn backstop to prevent
|
|
241
|
-
* cycles due to 2-way notification).
|
|
242
|
-
*
|
|
243
|
-
* @param {string} property Property name
|
|
244
|
-
* @param {*} value New property value
|
|
245
|
-
* @param {*} old Previous property value
|
|
246
|
-
* @return {boolean} Whether the property should be considered a change
|
|
247
|
-
* @protected
|
|
248
|
-
*/
|
|
249
|
-
_shouldPropertyChange(property, value, old) {
|
|
250
|
-
return mutablePropertyChange(this, property, value, old, true);
|
|
251
|
-
}
|
|
82
|
+
const testUserAgent = (regexp) => regexp.test(navigator.userAgent);
|
|
252
83
|
|
|
253
|
-
|
|
84
|
+
const testPlatform = (regexp) => regexp.test(navigator.platform);
|
|
254
85
|
|
|
255
|
-
|
|
86
|
+
const testVendor = (regexp) => regexp.test(navigator.vendor);
|
|
256
87
|
|
|
257
|
-
|
|
88
|
+
testUserAgent(/Android/u);
|
|
258
89
|
|
|
259
|
-
|
|
260
|
-
* Element class mixin to add the optional ability to skip strict
|
|
261
|
-
* dirty-checking for objects and arrays (always consider them to be
|
|
262
|
-
* "dirty") by setting a `mutable-data` attribute on an element instance.
|
|
263
|
-
*
|
|
264
|
-
* By default, `PropertyEffects` performs strict dirty checking on
|
|
265
|
-
* objects, which means that any deep modifications to an object or array will
|
|
266
|
-
* not be propagated unless "immutable" data patterns are used (i.e. all object
|
|
267
|
-
* references from the root to the mutation were changed).
|
|
268
|
-
*
|
|
269
|
-
* Polymer also provides a proprietary data mutation and path notification API
|
|
270
|
-
* (e.g. `notifyPath`, `set`, and array mutation API's) that allow efficient
|
|
271
|
-
* mutation and notification of deep changes in an object graph to all elements
|
|
272
|
-
* bound to the same object graph.
|
|
273
|
-
*
|
|
274
|
-
* In cases where neither immutable patterns nor the data mutation API can be
|
|
275
|
-
* used, applying this mixin will allow Polymer to skip dirty checking for
|
|
276
|
-
* objects and arrays (always consider them to be "dirty"). This allows a
|
|
277
|
-
* user to make a deep modification to a bound object graph, and then either
|
|
278
|
-
* simply re-set the object (e.g. `this.items = this.items`) or call `notifyPath`
|
|
279
|
-
* (e.g. `this.notifyPath('items')`) to update the tree. Note that all
|
|
280
|
-
* elements that wish to be updated based on deep mutations must apply this
|
|
281
|
-
* mixin or otherwise skip strict dirty checking for objects/arrays.
|
|
282
|
-
* Specifically, any elements in the binding tree between the source of a
|
|
283
|
-
* mutation and the consumption of it must enable this mixin or apply the
|
|
284
|
-
* `MutableData` mixin.
|
|
285
|
-
*
|
|
286
|
-
* While this mixin adds the ability to forgo Object/Array dirty checking,
|
|
287
|
-
* the `mutableData` flag defaults to false and must be set on the instance.
|
|
288
|
-
*
|
|
289
|
-
* Note, the performance characteristics of propagating large object graphs
|
|
290
|
-
* will be worse by relying on `mutableData: true` as opposed to using
|
|
291
|
-
* strict dirty checking with immutable patterns or Polymer's path notification
|
|
292
|
-
* API.
|
|
293
|
-
*
|
|
294
|
-
* @mixinFunction
|
|
295
|
-
* @polymer
|
|
296
|
-
* @summary Element class mixin to optionally skip strict dirty-checking
|
|
297
|
-
* for objects and arrays
|
|
298
|
-
*/
|
|
299
|
-
const OptionalMutableData = dedupingMixin(superClass => {
|
|
90
|
+
testUserAgent(/Chrome/u) && testVendor(/Google Inc/u);
|
|
300
91
|
|
|
301
|
-
|
|
302
|
-
* @mixinClass
|
|
303
|
-
* @polymer
|
|
304
|
-
* @implements {Polymer_OptionalMutableData}
|
|
305
|
-
*/
|
|
306
|
-
class OptionalMutableData extends superClass {
|
|
92
|
+
testUserAgent(/Firefox/u);
|
|
307
93
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
return {
|
|
311
|
-
/**
|
|
312
|
-
* Instance-level flag for configuring the dirty-checking strategy
|
|
313
|
-
* for this element. When true, Objects and Arrays will skip dirty
|
|
314
|
-
* checking, otherwise strict equality checking will be used.
|
|
315
|
-
*/
|
|
316
|
-
mutableData: Boolean
|
|
317
|
-
};
|
|
318
|
-
}
|
|
94
|
+
// IPadOS 13 lies and says it's a Mac, but we can distinguish by detecting touch support.
|
|
95
|
+
const isIPad = testPlatform(/^iPad/u) || (testPlatform(/^Mac/u) && navigator.maxTouchPoints > 1);
|
|
319
96
|
|
|
320
|
-
|
|
321
|
-
* Overrides `PropertyEffects` to provide option for skipping
|
|
322
|
-
* strict equality checking for Objects and Arrays.
|
|
323
|
-
*
|
|
324
|
-
* When `this.mutableData` is true on this instance, this method
|
|
325
|
-
* pulls the value to dirty check against from the `__dataTemp` cache
|
|
326
|
-
* (rather than the normal `__data` cache) for Objects. Since the temp
|
|
327
|
-
* cache is cleared at the end of a turn, this implementation allows
|
|
328
|
-
* side-effects of deep object changes to be processed by re-setting the
|
|
329
|
-
* same object (using the temp cache as an in-turn backstop to prevent
|
|
330
|
-
* cycles due to 2-way notification).
|
|
331
|
-
*
|
|
332
|
-
* @param {string} property Property name
|
|
333
|
-
* @param {*} value New property value
|
|
334
|
-
* @param {*} old Previous property value
|
|
335
|
-
* @return {boolean} Whether the property should be considered a change
|
|
336
|
-
* @protected
|
|
337
|
-
*/
|
|
338
|
-
_shouldPropertyChange(property, value, old) {
|
|
339
|
-
return mutablePropertyChange(this, property, value, old, this.mutableData);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
97
|
+
const isIPhone = testPlatform(/^iPhone/u);
|
|
342
98
|
|
|
343
|
-
|
|
99
|
+
const isIOS = isIPhone || isIPad;
|
|
344
100
|
|
|
345
|
-
|
|
101
|
+
testUserAgent(/^((?!chrome|android).)*safari/iu);
|
|
346
102
|
|
|
347
|
-
|
|
348
|
-
|
|
103
|
+
(() => {
|
|
104
|
+
try {
|
|
105
|
+
document.createEvent('TouchEvent');
|
|
106
|
+
return true;
|
|
107
|
+
} catch (e) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
})();
|
|
349
111
|
|
|
350
112
|
/**
|
|
351
|
-
@license
|
|
352
|
-
Copyright (c) 2017
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
356
|
-
Code distributed by Google as part of the polymer project is also
|
|
357
|
-
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
358
|
-
*/
|
|
359
|
-
|
|
360
|
-
// Base class for HTMLTemplateElement extension that has property effects
|
|
361
|
-
// machinery for propagating host properties to children. This is an ES5
|
|
362
|
-
// class only because Babel (incorrectly) requires super() in the class
|
|
363
|
-
// constructor even though no `this` is used and it returns an instance.
|
|
364
|
-
let newInstance = null;
|
|
113
|
+
* @license
|
|
114
|
+
* Copyright (c) 2017 Anton Korzunov
|
|
115
|
+
* SPDX-License-Identifier: MIT
|
|
116
|
+
*/
|
|
365
117
|
|
|
366
118
|
/**
|
|
367
|
-
* @
|
|
368
|
-
*
|
|
369
|
-
*
|
|
119
|
+
* @fileoverview
|
|
120
|
+
*
|
|
121
|
+
* This module includes JS code copied from the `aria-hidden` package:
|
|
122
|
+
* https://github.com/theKashey/aria-hidden/blob/master/src/index.ts
|
|
370
123
|
*/
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
124
|
+
|
|
125
|
+
/** @type {WeakMap<Element, number>} */
|
|
126
|
+
let counterMap = new WeakMap();
|
|
127
|
+
|
|
128
|
+
/** @type {WeakMap<Element, boolean>} */
|
|
129
|
+
let uncontrolledNodes = new WeakMap();
|
|
130
|
+
|
|
131
|
+
/** @type {Record<string, WeakMap<Element, number>>} */
|
|
132
|
+
let markerMap = {};
|
|
133
|
+
|
|
134
|
+
/** @type {number} */
|
|
135
|
+
let lockCount = 0;
|
|
378
136
|
|
|
379
137
|
/**
|
|
380
|
-
* @
|
|
381
|
-
* @
|
|
382
|
-
* @extends {HTMLTemplateElementExtension}
|
|
383
|
-
* @private
|
|
138
|
+
* @param {?Node} node
|
|
139
|
+
* @return {boolean}
|
|
384
140
|
*/
|
|
385
|
-
const
|
|
141
|
+
const isElement = (node) => node && node.nodeType === Node.ELEMENT_NODE;
|
|
386
142
|
|
|
387
143
|
/**
|
|
388
|
-
* @
|
|
389
|
-
* @implements {Polymer_MutableData}
|
|
390
|
-
* @extends {DataTemplate}
|
|
391
|
-
* @private
|
|
144
|
+
* @param {...unknown} args
|
|
392
145
|
*/
|
|
393
|
-
const
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
function upgradeTemplate(template, constructor) {
|
|
397
|
-
newInstance = template;
|
|
398
|
-
Object.setPrototypeOf(template, constructor.prototype);
|
|
399
|
-
new constructor();
|
|
400
|
-
newInstance = null;
|
|
401
|
-
}
|
|
146
|
+
const logError = (...args) => {
|
|
147
|
+
console.error(`Error: ${args.join(' ')}. Skip setting aria-hidden.`);
|
|
148
|
+
};
|
|
402
149
|
|
|
403
150
|
/**
|
|
404
|
-
*
|
|
405
|
-
* @
|
|
406
|
-
* @
|
|
407
|
-
* @implements {Polymer_PropertyEffects}
|
|
408
|
-
* @private
|
|
151
|
+
* @param {HTMLElement} parent
|
|
152
|
+
* @param {Element[]} targets
|
|
153
|
+
* @return {Element[]}
|
|
409
154
|
*/
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
if (
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
n.textContent = '';
|
|
422
|
-
} else {
|
|
423
|
-
n.textContent = n.__polymerTextContent__;
|
|
424
|
-
}
|
|
425
|
-
// remove and replace slot
|
|
426
|
-
} else if (n.localName === 'slot') {
|
|
427
|
-
if (hide) {
|
|
428
|
-
n.__polymerReplaced__ = document.createComment('hidden-slot');
|
|
429
|
-
wrap(wrap(n).parentNode).replaceChild(n.__polymerReplaced__, n);
|
|
430
|
-
} else {
|
|
431
|
-
const replace = n.__polymerReplaced__;
|
|
432
|
-
if (replace) {
|
|
433
|
-
wrap(wrap(replace).parentNode).replaceChild(n, replace);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
155
|
+
const correctTargets = (parent, targets) => {
|
|
156
|
+
if (!isElement(parent)) {
|
|
157
|
+
logError(parent, 'is not a valid element');
|
|
158
|
+
return [];
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return targets
|
|
162
|
+
.map((target) => {
|
|
163
|
+
if (!isElement(target)) {
|
|
164
|
+
logError(target, 'is not a valid element');
|
|
165
|
+
return null;
|
|
436
166
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
} else {
|
|
443
|
-
n.style.display = n.__polymerDisplay__;
|
|
167
|
+
|
|
168
|
+
let node = target;
|
|
169
|
+
while (node && node !== parent) {
|
|
170
|
+
if (parent.contains(node)) {
|
|
171
|
+
return target;
|
|
444
172
|
}
|
|
173
|
+
node = node.getRootNode().host;
|
|
445
174
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
175
|
+
|
|
176
|
+
logError(target, 'is not contained inside', parent);
|
|
177
|
+
return null;
|
|
178
|
+
})
|
|
179
|
+
.filter((x) => Boolean(x));
|
|
180
|
+
};
|
|
453
181
|
|
|
454
182
|
/**
|
|
455
|
-
*
|
|
456
|
-
* @
|
|
457
|
-
* @
|
|
458
|
-
* @
|
|
183
|
+
* Marks everything except given node(or nodes) as aria-hidden
|
|
184
|
+
* @param {Element | Element[]} originalTarget - elements to keep on the page
|
|
185
|
+
* @param {HTMLElement} [parentNode] - top element, defaults to document.body
|
|
186
|
+
* @param {String} [markerName] - a special attribute to mark every node
|
|
187
|
+
* @param {String} [controlAttribute] - html Attribute to control
|
|
188
|
+
* @return {Function}
|
|
459
189
|
*/
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
this.root = this._stampTemplate(this.__dataHost);
|
|
466
|
-
// Save list of stamped children
|
|
467
|
-
let children = [];
|
|
468
|
-
/** @suppress {invalidCasts} */
|
|
469
|
-
this.children = /** @type {!NodeList} */ (children);
|
|
470
|
-
// Polymer 1.x did not use `Polymer.dom` here so not bothering.
|
|
471
|
-
for (let n = this.root.firstChild; n; n=n.nextSibling) {
|
|
472
|
-
children.push(n);
|
|
473
|
-
n.__templatizeInstance = this;
|
|
474
|
-
}
|
|
475
|
-
if (this.__templatizeOwner &&
|
|
476
|
-
this.__templatizeOwner.__hideTemplateChildren__) {
|
|
477
|
-
this._showHideChildren(true);
|
|
478
|
-
}
|
|
479
|
-
// Flush props only when props are passed if instance props exist
|
|
480
|
-
// or when there isn't instance props.
|
|
481
|
-
let options = this.__templatizeOptions;
|
|
482
|
-
if ((props && options.instanceProps) || !options.instanceProps) {
|
|
483
|
-
this._enableProperties();
|
|
484
|
-
}
|
|
190
|
+
const applyAttributeToOthers = (originalTarget, parentNode, markerName, controlAttribute) => {
|
|
191
|
+
const targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
|
|
192
|
+
|
|
193
|
+
if (!markerMap[markerName]) {
|
|
194
|
+
markerMap[markerName] = new WeakMap();
|
|
485
195
|
}
|
|
196
|
+
|
|
197
|
+
const markerCounter = markerMap[markerName];
|
|
198
|
+
|
|
199
|
+
/** @type {Element[]} */
|
|
200
|
+
const hiddenNodes = [];
|
|
201
|
+
|
|
202
|
+
/** @type {Set<Node>} */
|
|
203
|
+
const elementsToKeep = new Set();
|
|
204
|
+
|
|
205
|
+
/** @type {Set<Node>} */
|
|
206
|
+
const elementsToStop = new Set(targets);
|
|
207
|
+
|
|
486
208
|
/**
|
|
487
|
-
*
|
|
488
|
-
* sets any properties stored in `__hostProps`.
|
|
489
|
-
* @private
|
|
490
|
-
* @param {Object} props Object of property name-value pairs to set.
|
|
491
|
-
* @return {void}
|
|
209
|
+
* @param {?Node} el
|
|
492
210
|
*/
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
for (let hprop in this.__hostProps) {
|
|
497
|
-
this._setPendingProperty(hprop, this.__dataHost['_host_' + hprop]);
|
|
498
|
-
}
|
|
211
|
+
const keep = (el) => {
|
|
212
|
+
if (!el || elementsToKeep.has(el)) {
|
|
213
|
+
return;
|
|
499
214
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
215
|
+
|
|
216
|
+
elementsToKeep.add(el);
|
|
217
|
+
|
|
218
|
+
const slot = el.assignedSlot;
|
|
219
|
+
if (slot) {
|
|
220
|
+
keep(slot);
|
|
504
221
|
}
|
|
505
|
-
|
|
222
|
+
|
|
223
|
+
keep(el.parentNode || el.host);
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
targets.forEach(keep);
|
|
227
|
+
|
|
506
228
|
/**
|
|
507
|
-
*
|
|
508
|
-
* called on instances from the `options.forwardHostProp` callback
|
|
509
|
-
* to propagate changes of host properties to each instance.
|
|
510
|
-
*
|
|
511
|
-
* Note this method enqueues the change, which are flushed as a batch.
|
|
512
|
-
*
|
|
513
|
-
* @param {string} prop Property or path name
|
|
514
|
-
* @param {*} value Value of the property to forward
|
|
515
|
-
* @return {void}
|
|
229
|
+
* @param {?Node} el
|
|
516
230
|
*/
|
|
517
|
-
|
|
518
|
-
if (
|
|
519
|
-
|
|
231
|
+
const deep = (parent) => {
|
|
232
|
+
if (!parent || elementsToStop.has(parent)) {
|
|
233
|
+
return;
|
|
520
234
|
}
|
|
521
|
-
}
|
|
522
235
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
236
|
+
const root = parent.shadowRoot;
|
|
237
|
+
const children = root ? [...parent.children, ...root.children] : [...parent.children];
|
|
238
|
+
children.forEach((node) => {
|
|
239
|
+
// Skip elements that don't need to be hidden
|
|
240
|
+
if (['template', 'script', 'style'].includes(node.localName)) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (elementsToKeep.has(node)) {
|
|
245
|
+
deep(node);
|
|
246
|
+
} else {
|
|
247
|
+
const attr = node.getAttribute(controlAttribute);
|
|
248
|
+
const alreadyHidden = attr !== null && attr !== 'false';
|
|
249
|
+
const counterValue = (counterMap.get(node) || 0) + 1;
|
|
250
|
+
const markerValue = (markerCounter.get(node) || 0) + 1;
|
|
251
|
+
|
|
252
|
+
counterMap.set(node, counterValue);
|
|
253
|
+
markerCounter.set(node, markerValue);
|
|
254
|
+
hiddenNodes.push(node);
|
|
255
|
+
|
|
256
|
+
if (counterValue === 1 && alreadyHidden) {
|
|
257
|
+
uncontrolledNodes.set(node, true);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (markerValue === 1) {
|
|
261
|
+
node.setAttribute(markerName, 'true');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (!alreadyHidden) {
|
|
265
|
+
node.setAttribute(controlAttribute, 'true');
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
deep(parentNode);
|
|
272
|
+
|
|
273
|
+
elementsToKeep.clear();
|
|
274
|
+
|
|
275
|
+
lockCount += 1;
|
|
276
|
+
|
|
277
|
+
return () => {
|
|
278
|
+
hiddenNodes.forEach((node) => {
|
|
279
|
+
const counterValue = counterMap.get(node) - 1;
|
|
280
|
+
const markerValue = markerCounter.get(node) - 1;
|
|
281
|
+
|
|
282
|
+
counterMap.set(node, counterValue);
|
|
283
|
+
markerCounter.set(node, markerValue);
|
|
284
|
+
|
|
285
|
+
if (!counterValue) {
|
|
286
|
+
if (uncontrolledNodes.has(node)) {
|
|
287
|
+
uncontrolledNodes.delete(node);
|
|
288
|
+
} else {
|
|
289
|
+
node.removeAttribute(controlAttribute);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (!markerValue) {
|
|
294
|
+
node.removeAttribute(markerName);
|
|
546
295
|
}
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
lockCount -= 1;
|
|
299
|
+
|
|
300
|
+
if (!lockCount) {
|
|
301
|
+
// clear
|
|
302
|
+
counterMap = new WeakMap();
|
|
303
|
+
counterMap = new WeakMap();
|
|
304
|
+
uncontrolledNodes = new WeakMap();
|
|
305
|
+
markerMap = {};
|
|
547
306
|
}
|
|
307
|
+
};
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Marks everything except given node(or nodes) as aria-hidden
|
|
312
|
+
* @param {Element | Element[]} originalTarget - elements to keep on the page
|
|
313
|
+
* @param {HTMLElement} [parentNode] - top element, defaults to document.body
|
|
314
|
+
* @param {String} [markerName] - a special attribute to mark every node
|
|
315
|
+
* @return {Function} undo command
|
|
316
|
+
*/
|
|
317
|
+
const hideOthers = (originalTarget, parentNode = document.body, markerName = 'data-aria-hidden') => {
|
|
318
|
+
const targets = Array.from(Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
|
|
319
|
+
|
|
320
|
+
if (parentNode) {
|
|
321
|
+
// We should not hide ariaLive elements - https://github.com/theKashey/aria-hidden/issues/10
|
|
322
|
+
targets.push(...Array.from(parentNode.querySelectorAll('[aria-live]')));
|
|
548
323
|
}
|
|
324
|
+
|
|
325
|
+
return applyAttributeToOthers(targets, parentNode, markerName, 'aria-hidden');
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* @license
|
|
330
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
331
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
332
|
+
*/
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* A controller for handling modal state on the elements with `dialog` and `alertdialog` role.
|
|
336
|
+
* See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-modal
|
|
337
|
+
*
|
|
338
|
+
* Note, the actual `role` and `aria-modal` attributes are supposed to be handled by the
|
|
339
|
+
* consumer web component. This is done in to ensure the controller only does one thing.
|
|
340
|
+
*/
|
|
341
|
+
class AriaModalController {
|
|
549
342
|
/**
|
|
550
|
-
*
|
|
551
|
-
* text nodes, `textContent` is removed while "hidden" and replaced when
|
|
552
|
-
* "shown."
|
|
553
|
-
* @param {boolean} hide Set to true to hide the children;
|
|
554
|
-
* set to false to show them.
|
|
555
|
-
* @return {void}
|
|
556
|
-
* @protected
|
|
557
|
-
*/
|
|
558
|
-
_showHideChildren(hide) {
|
|
559
|
-
showHideChildren(hide, this.children);
|
|
560
|
-
}
|
|
561
|
-
/**
|
|
562
|
-
* Overrides default property-effects implementation to intercept
|
|
563
|
-
* textContent bindings while children are "hidden" and cache in
|
|
564
|
-
* private storage for later retrieval.
|
|
565
|
-
*
|
|
566
|
-
* @override
|
|
567
|
-
* @param {!Node} node The node to set a property on
|
|
568
|
-
* @param {string} prop The property to set
|
|
569
|
-
* @param {*} value The value to set
|
|
570
|
-
* @return {void}
|
|
571
|
-
* @protected
|
|
343
|
+
* @param {HTMLElement} host
|
|
572
344
|
*/
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
345
|
+
constructor(host, callback) {
|
|
346
|
+
/**
|
|
347
|
+
* The controller host element.
|
|
348
|
+
*
|
|
349
|
+
* @type {HTMLElement}
|
|
350
|
+
*/
|
|
351
|
+
this.host = host;
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* The callback used to detect which element
|
|
355
|
+
* to use as a target. Defaults to the host.
|
|
356
|
+
*
|
|
357
|
+
* @type {Function}
|
|
358
|
+
*/
|
|
359
|
+
this.callback = typeof callback === 'function' ? callback : () => host;
|
|
580
360
|
}
|
|
361
|
+
|
|
581
362
|
/**
|
|
582
|
-
*
|
|
583
|
-
*
|
|
584
|
-
* or else the host element.
|
|
363
|
+
* Make the controller host modal by hiding other elements from screen readers
|
|
364
|
+
* using `aria-hidden` attribute (can be replaced with `inert` in the future).
|
|
585
365
|
*
|
|
586
|
-
*
|
|
366
|
+
* The method name is chosen to align with the one provided by native `<dialog>`:
|
|
367
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal
|
|
587
368
|
*/
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
let options;
|
|
592
|
-
model = this;
|
|
593
|
-
do {
|
|
594
|
-
// A template instance's `__dataHost` is a <template>
|
|
595
|
-
// `model.__dataHost.__dataHost` is the template's host
|
|
596
|
-
model = model.__dataHost.__dataHost;
|
|
597
|
-
} while ((options = model.__templatizeOptions) && !options.parentModel);
|
|
598
|
-
this.__parentModel = model;
|
|
599
|
-
}
|
|
600
|
-
return model;
|
|
369
|
+
showModal() {
|
|
370
|
+
const targets = this.callback();
|
|
371
|
+
this.__showOthers = hideOthers(targets);
|
|
601
372
|
}
|
|
602
373
|
|
|
603
374
|
/**
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
* @param {Event} event Event to dispatch
|
|
608
|
-
* @return {boolean} Always true.
|
|
609
|
-
* @override
|
|
375
|
+
* Remove `aria-hidden` from other elements unless there are any other
|
|
376
|
+
* controller hosts on the page activated by using `showModal()` call.
|
|
610
377
|
*/
|
|
611
|
-
|
|
612
|
-
|
|
378
|
+
close() {
|
|
379
|
+
if (this.__showOthers) {
|
|
380
|
+
this.__showOthers();
|
|
381
|
+
this.__showOthers = null;
|
|
382
|
+
}
|
|
613
383
|
}
|
|
614
384
|
}
|
|
615
385
|
|
|
616
386
|
/**
|
|
617
|
-
* @
|
|
618
|
-
*
|
|
619
|
-
*
|
|
620
|
-
* @private
|
|
387
|
+
* @license
|
|
388
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
389
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
621
390
|
*/
|
|
622
|
-
const MutableTemplateInstanceBase = MutableData(
|
|
623
|
-
// This cast shouldn't be neccessary, but Closure doesn't understand that
|
|
624
|
-
// TemplateInstanceBase is a constructor function.
|
|
625
|
-
/** @type {function(new:TemplateInstanceBase)} */ (TemplateInstanceBase));
|
|
626
|
-
|
|
627
|
-
function findMethodHost(template) {
|
|
628
|
-
// Technically this should be the owner of the outermost template.
|
|
629
|
-
// In shadow dom, this is always getRootNode().host, but we can
|
|
630
|
-
// approximate this via cooperation with our dataHost always setting
|
|
631
|
-
// `_methodHost` as long as there were bindings (or id's) on this
|
|
632
|
-
// instance causing it to get a dataHost.
|
|
633
|
-
let templateHost = template.__dataHost;
|
|
634
|
-
return templateHost && templateHost._methodHost || templateHost;
|
|
635
|
-
}
|
|
636
391
|
|
|
637
|
-
/* eslint-disable valid-jsdoc */
|
|
638
392
|
/**
|
|
639
|
-
*
|
|
393
|
+
* A controller for saving a focused node and restoring focus to it later.
|
|
640
394
|
*/
|
|
641
|
-
|
|
395
|
+
class FocusRestorationController {
|
|
642
396
|
/**
|
|
643
|
-
*
|
|
644
|
-
*
|
|
397
|
+
* Saves the given node as a target for restoring focus to
|
|
398
|
+
* when `restoreFocus()` is called. If no node is provided,
|
|
399
|
+
* the currently focused node in the DOM is saved as a target.
|
|
400
|
+
*
|
|
401
|
+
* @param {Node | null | undefined} focusNode
|
|
645
402
|
*/
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
// Affordance for global mixins onto TemplatizeInstance
|
|
650
|
-
if (templatize.mixin) {
|
|
651
|
-
templatizerBase = templatize.mixin(templatizerBase);
|
|
403
|
+
saveFocus(focusNode) {
|
|
404
|
+
this.focusNode = focusNode || getDeepActiveElement();
|
|
652
405
|
}
|
|
653
406
|
|
|
654
407
|
/**
|
|
655
|
-
*
|
|
656
|
-
* @constructor
|
|
657
|
-
* @private
|
|
408
|
+
* Restores focus to the target node that was saved previously with `saveFocus()`.
|
|
658
409
|
*/
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
addNotifyEffects(klass, template, templateInfo, options);
|
|
664
|
-
return klass;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/**
|
|
668
|
-
* Adds propagate effects from the template to the template instance for
|
|
669
|
-
* properties that the host binds to the template using the `_host_` prefix.
|
|
670
|
-
*
|
|
671
|
-
* @suppress {missingProperties} class.prototype is not defined for some reason
|
|
672
|
-
*/
|
|
673
|
-
function addPropagateEffects(target, templateInfo, options, methodHost) {
|
|
674
|
-
let userForwardHostProp = options.forwardHostProp;
|
|
675
|
-
if (userForwardHostProp && templateInfo.hasHostProps) {
|
|
676
|
-
// Under the `removeNestedTemplates` optimization, a custom element like
|
|
677
|
-
// `dom-if` or `dom-repeat` can itself be treated as the "template"; this
|
|
678
|
-
// flag is used to switch between upgrading a `<template>` to be a property
|
|
679
|
-
// effects client vs. adding the effects directly to the custom element
|
|
680
|
-
const isTemplate = target.localName == 'template';
|
|
681
|
-
// Provide data API and property effects on memoized template class
|
|
682
|
-
let klass = templateInfo.templatizeTemplateClass;
|
|
683
|
-
if (!klass) {
|
|
684
|
-
if (isTemplate) {
|
|
685
|
-
/**
|
|
686
|
-
* @constructor
|
|
687
|
-
* @extends {DataTemplate}
|
|
688
|
-
*/
|
|
689
|
-
let templatizedBase =
|
|
690
|
-
options.mutableData ? MutableDataTemplate : DataTemplate;
|
|
691
|
-
|
|
692
|
-
// NOTE: due to https://github.com/google/closure-compiler/issues/2928,
|
|
693
|
-
// combining the next two lines into one assignment causes a spurious
|
|
694
|
-
// type error.
|
|
695
|
-
/** @private */
|
|
696
|
-
class TemplatizedTemplate extends templatizedBase {}
|
|
697
|
-
klass = templateInfo.templatizeTemplateClass = TemplatizedTemplate;
|
|
698
|
-
} else {
|
|
699
|
-
/**
|
|
700
|
-
* @constructor
|
|
701
|
-
* @extends {PolymerElement}
|
|
702
|
-
*/
|
|
703
|
-
const templatizedBase = target.constructor;
|
|
704
|
-
|
|
705
|
-
// Create a cached subclass of the base custom element class onto which
|
|
706
|
-
// to put the template-specific propagate effects
|
|
707
|
-
// NOTE: due to https://github.com/google/closure-compiler/issues/2928,
|
|
708
|
-
// combining the next two lines into one assignment causes a spurious
|
|
709
|
-
// type error.
|
|
710
|
-
/** @private */
|
|
711
|
-
class TemplatizedTemplateExtension extends templatizedBase {}
|
|
712
|
-
klass = templateInfo.templatizeTemplateClass =
|
|
713
|
-
TemplatizedTemplateExtension;
|
|
714
|
-
}
|
|
715
|
-
// Add template - >instances effects
|
|
716
|
-
// and host <- template effects
|
|
717
|
-
let hostProps = templateInfo.hostProps;
|
|
718
|
-
for (let prop in hostProps) {
|
|
719
|
-
klass.prototype._addPropertyEffect('_host_' + prop,
|
|
720
|
-
klass.prototype.PROPERTY_EFFECT_TYPES.PROPAGATE,
|
|
721
|
-
{fn: createForwardHostPropEffect(prop, userForwardHostProp)});
|
|
722
|
-
klass.prototype._createNotifyingProperty('_host_' + prop);
|
|
723
|
-
}
|
|
724
|
-
if (legacyWarnings && methodHost) {
|
|
725
|
-
warnOnUndeclaredProperties(templateInfo, options, methodHost);
|
|
726
|
-
}
|
|
410
|
+
restoreFocus() {
|
|
411
|
+
const focusNode = this.focusNode;
|
|
412
|
+
if (!focusNode) {
|
|
413
|
+
return;
|
|
727
414
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
//
|
|
732
|
-
//
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
if (isTemplate) {
|
|
736
|
-
upgradeTemplate(target, klass);
|
|
737
|
-
// Clear any pending data for performance
|
|
738
|
-
target.__dataTemp = {};
|
|
739
|
-
target.__dataPending = null;
|
|
740
|
-
target.__dataOld = null;
|
|
741
|
-
target._enableProperties();
|
|
415
|
+
|
|
416
|
+
if (getDeepActiveElement() === document.body) {
|
|
417
|
+
// In Firefox and Safari, focusing the node synchronously
|
|
418
|
+
// doesn't work as expected when the overlay is closing on outside click.
|
|
419
|
+
// These browsers force focus to move to the body element and retain it
|
|
420
|
+
// there until the next event loop iteration.
|
|
421
|
+
setTimeout(() => focusNode.focus());
|
|
742
422
|
} else {
|
|
743
|
-
|
|
744
|
-
Object.setPrototypeOf(target, klass.prototype);
|
|
745
|
-
// Check for any pre-bound instance host properties, and do the
|
|
746
|
-
// instance property delete/assign dance for those (directly into data;
|
|
747
|
-
// not need to go through accessor since they are pulled at instance time)
|
|
748
|
-
const hostProps = templateInfo.hostProps;
|
|
749
|
-
for (let prop in hostProps) {
|
|
750
|
-
prop = '_host_' + prop;
|
|
751
|
-
if (prop in target) {
|
|
752
|
-
const val = target[prop];
|
|
753
|
-
delete target[prop];
|
|
754
|
-
target.__data[prop] = val;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
423
|
+
focusNode.focus();
|
|
757
424
|
}
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
/* eslint-enable valid-jsdoc */
|
|
761
|
-
|
|
762
|
-
function createForwardHostPropEffect(hostProp, userForwardHostProp) {
|
|
763
|
-
return function forwardHostProp(template, prop, props) {
|
|
764
|
-
userForwardHostProp.call(template.__templatizeOwner,
|
|
765
|
-
prop.substring('_host_'.length), props[prop]);
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
425
|
|
|
769
|
-
|
|
770
|
-
let hostProps = templateInfo.hostProps || {};
|
|
771
|
-
for (let iprop in options.instanceProps) {
|
|
772
|
-
delete hostProps[iprop];
|
|
773
|
-
let userNotifyInstanceProp = options.notifyInstanceProp;
|
|
774
|
-
if (userNotifyInstanceProp) {
|
|
775
|
-
klass.prototype._addPropertyEffect(iprop,
|
|
776
|
-
klass.prototype.PROPERTY_EFFECT_TYPES.NOTIFY,
|
|
777
|
-
{fn: createNotifyInstancePropEffect(iprop, userNotifyInstanceProp)});
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
if (options.forwardHostProp && template.__dataHost) {
|
|
781
|
-
for (let hprop in hostProps) {
|
|
782
|
-
// As we're iterating hostProps in this function, note whether
|
|
783
|
-
// there were any, for an optimization in addPropagateEffects
|
|
784
|
-
if (!templateInfo.hasHostProps) {
|
|
785
|
-
templateInfo.hasHostProps = true;
|
|
786
|
-
}
|
|
787
|
-
klass.prototype._addPropertyEffect(hprop,
|
|
788
|
-
klass.prototype.PROPERTY_EFFECT_TYPES.NOTIFY,
|
|
789
|
-
{fn: createNotifyHostPropEffect()});
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
function createNotifyInstancePropEffect(instProp, userNotifyInstanceProp) {
|
|
795
|
-
return function notifyInstanceProp(inst, prop, props) {
|
|
796
|
-
userNotifyInstanceProp.call(inst.__templatizeOwner,
|
|
797
|
-
inst, prop, props[prop]);
|
|
798
|
-
};
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
function createNotifyHostPropEffect() {
|
|
802
|
-
return function notifyHostProp(inst, prop, props) {
|
|
803
|
-
inst.__dataHost._setPendingPropertyOrPath('_host_' + prop, props[prop], true, true);
|
|
804
|
-
};
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
/**
|
|
809
|
-
* Returns an anonymous `PropertyEffects` class bound to the
|
|
810
|
-
* `<template>` provided. Instancing the class will result in the
|
|
811
|
-
* template being stamped into a document fragment stored as the instance's
|
|
812
|
-
* `root` property, after which it can be appended to the DOM.
|
|
813
|
-
*
|
|
814
|
-
* Templates may utilize all Polymer data-binding features as well as
|
|
815
|
-
* declarative event listeners. Event listeners and inline computing
|
|
816
|
-
* functions in the template will be called on the host of the template.
|
|
817
|
-
*
|
|
818
|
-
* The constructor returned takes a single argument dictionary of initial
|
|
819
|
-
* property values to propagate into template bindings. Additionally
|
|
820
|
-
* host properties can be forwarded in, and instance properties can be
|
|
821
|
-
* notified out by providing optional callbacks in the `options` dictionary.
|
|
822
|
-
*
|
|
823
|
-
* Valid configuration in `options` are as follows:
|
|
824
|
-
*
|
|
825
|
-
* - `forwardHostProp(property, value)`: Called when a property referenced
|
|
826
|
-
* in the template changed on the template's host. As this library does
|
|
827
|
-
* not retain references to templates instanced by the user, it is the
|
|
828
|
-
* templatize owner's responsibility to forward host property changes into
|
|
829
|
-
* user-stamped instances. The `instance.forwardHostProp(property, value)`
|
|
830
|
-
* method on the generated class should be called to forward host
|
|
831
|
-
* properties into the template to prevent unnecessary property-changed
|
|
832
|
-
* notifications. Any properties referenced in the template that are not
|
|
833
|
-
* defined in `instanceProps` will be notified up to the template's host
|
|
834
|
-
* automatically.
|
|
835
|
-
* - `instanceProps`: Dictionary of property names that will be added
|
|
836
|
-
* to the instance by the templatize owner. These properties shadow any
|
|
837
|
-
* host properties, and changes within the template to these properties
|
|
838
|
-
* will result in `notifyInstanceProp` being called.
|
|
839
|
-
* - `mutableData`: When `true`, the generated class will skip strict
|
|
840
|
-
* dirty-checking for objects and arrays (always consider them to be
|
|
841
|
-
* "dirty").
|
|
842
|
-
* - `notifyInstanceProp(instance, property, value)`: Called when
|
|
843
|
-
* an instance property changes. Users may choose to call `notifyPath`
|
|
844
|
-
* on e.g. the owner to notify the change.
|
|
845
|
-
* - `parentModel`: When `true`, events handled by declarative event listeners
|
|
846
|
-
* (`on-event="handler"`) will be decorated with a `model` property pointing
|
|
847
|
-
* to the template instance that stamped it. It will also be returned
|
|
848
|
-
* from `instance.parentModel` in cases where template instance nesting
|
|
849
|
-
* causes an inner model to shadow an outer model.
|
|
850
|
-
*
|
|
851
|
-
* All callbacks are called bound to the `owner`. Any context
|
|
852
|
-
* needed for the callbacks (such as references to `instances` stamped)
|
|
853
|
-
* should be stored on the `owner` such that they can be retrieved via
|
|
854
|
-
* `this`.
|
|
855
|
-
*
|
|
856
|
-
* When `options.forwardHostProp` is declared as an option, any properties
|
|
857
|
-
* referenced in the template will be automatically forwarded from the host of
|
|
858
|
-
* the `<template>` to instances, with the exception of any properties listed in
|
|
859
|
-
* the `options.instanceProps` object. `instanceProps` are assumed to be
|
|
860
|
-
* managed by the owner of the instances, either passed into the constructor
|
|
861
|
-
* or set after the fact. Note, any properties passed into the constructor will
|
|
862
|
-
* always be set to the instance (regardless of whether they would normally
|
|
863
|
-
* be forwarded from the host).
|
|
864
|
-
*
|
|
865
|
-
* Note that `templatize()` can be run only once for a given `<template>`.
|
|
866
|
-
* Further calls will result in an error. Also, there is a special
|
|
867
|
-
* behavior if the template was duplicated through a mechanism such as
|
|
868
|
-
* `<dom-repeat>` or `<test-fixture>`. In this case, all calls to
|
|
869
|
-
* `templatize()` return the same class for all duplicates of a template.
|
|
870
|
-
* The class returned from `templatize()` is generated only once using
|
|
871
|
-
* the `options` from the first call. This means that any `options`
|
|
872
|
-
* provided to subsequent calls will be ignored. Therefore, it is very
|
|
873
|
-
* important not to close over any variables inside the callbacks. Also,
|
|
874
|
-
* arrow functions must be avoided because they bind the outer `this`.
|
|
875
|
-
* Inside the callbacks, any contextual information can be accessed
|
|
876
|
-
* through `this`, which points to the `owner`.
|
|
877
|
-
*
|
|
878
|
-
* @param {!HTMLTemplateElement} template Template to templatize
|
|
879
|
-
* @param {Polymer_PropertyEffects=} owner Owner of the template instances;
|
|
880
|
-
* any optional callbacks will be bound to this owner.
|
|
881
|
-
* @param {Object=} options Options dictionary (see summary for details)
|
|
882
|
-
* @return {function(new:TemplateInstanceBase, Object=)} Generated class bound
|
|
883
|
-
* to the template provided
|
|
884
|
-
* @suppress {invalidCasts}
|
|
885
|
-
*/
|
|
886
|
-
function templatize(template, owner, options) {
|
|
887
|
-
// Under strictTemplatePolicy, the templatized element must be owned
|
|
888
|
-
// by a (trusted) Polymer element, indicated by existence of _methodHost;
|
|
889
|
-
// e.g. for dom-if & dom-repeat in main document, _methodHost is null
|
|
890
|
-
if (strictTemplatePolicy && !findMethodHost(template)) {
|
|
891
|
-
throw new Error('strictTemplatePolicy: template owner not trusted');
|
|
892
|
-
}
|
|
893
|
-
options = /** @type {!TemplatizeOptions} */(options || {});
|
|
894
|
-
if (template.__templatizeOwner) {
|
|
895
|
-
throw new Error('A <template> can only be templatized once');
|
|
896
|
-
}
|
|
897
|
-
template.__templatizeOwner = owner;
|
|
898
|
-
const ctor = owner ? owner.constructor : TemplateInstanceBase;
|
|
899
|
-
let templateInfo = ctor._parseTemplate(template);
|
|
900
|
-
// Get memoized base class for the prototypical template, which
|
|
901
|
-
// includes property effects for binding template & forwarding
|
|
902
|
-
/**
|
|
903
|
-
* @constructor
|
|
904
|
-
* @extends {TemplateInstanceBase}
|
|
905
|
-
*/
|
|
906
|
-
let baseClass = templateInfo.templatizeInstanceClass;
|
|
907
|
-
if (!baseClass) {
|
|
908
|
-
baseClass = createTemplatizerClass(template, templateInfo, options);
|
|
909
|
-
templateInfo.templatizeInstanceClass = baseClass;
|
|
910
|
-
}
|
|
911
|
-
const methodHost = findMethodHost(template);
|
|
912
|
-
// Host property forwarding must be installed onto template instance
|
|
913
|
-
addPropagateEffects(template, templateInfo, options, methodHost);
|
|
914
|
-
// Subclass base class and add reference for this specific template
|
|
915
|
-
/** @private */
|
|
916
|
-
let klass = class TemplateInstance extends baseClass {};
|
|
917
|
-
/** @override */
|
|
918
|
-
klass.prototype._methodHost = methodHost;
|
|
919
|
-
/** @override */
|
|
920
|
-
klass.prototype.__dataHost = /** @type {!DataTemplate} */ (template);
|
|
921
|
-
/** @override */
|
|
922
|
-
klass.prototype.__templatizeOwner = /** @type {!Object} */ (owner);
|
|
923
|
-
/** @override */
|
|
924
|
-
klass.prototype.__hostProps = templateInfo.hostProps;
|
|
925
|
-
klass = /** @type {function(new:TemplateInstanceBase)} */(klass); //eslint-disable-line no-self-assign
|
|
926
|
-
return klass;
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
function warnOnUndeclaredProperties(templateInfo, options, methodHost) {
|
|
930
|
-
const declaredProps = methodHost.constructor._properties;
|
|
931
|
-
const {propertyEffects} = templateInfo;
|
|
932
|
-
const {instanceProps} = options;
|
|
933
|
-
for (let prop in propertyEffects) {
|
|
934
|
-
// Ensure properties with template effects are declared on the outermost
|
|
935
|
-
// host (`methodHost`), unless they are instance props or static functions
|
|
936
|
-
if (!declaredProps[prop] && !(instanceProps && instanceProps[prop])) {
|
|
937
|
-
const effects = propertyEffects[prop];
|
|
938
|
-
for (let i=0; i<effects.length; i++) {
|
|
939
|
-
const {part} = effects[i].info;
|
|
940
|
-
if (!(part.signature && part.signature.static)) {
|
|
941
|
-
console.warn(`Property '${prop}' used in template but not ` +
|
|
942
|
-
`declared in 'properties'; attribute will not be observed.`);
|
|
943
|
-
break;
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
}
|
|
426
|
+
this.focusNode = null;
|
|
947
427
|
}
|
|
948
428
|
}
|
|
949
429
|
|
|
950
|
-
/**
|
|
951
|
-
* Returns the template "model" associated with a given element, which
|
|
952
|
-
* serves as the binding scope for the template instance the element is
|
|
953
|
-
* contained in. A template model is an instance of
|
|
954
|
-
* `TemplateInstanceBase`, and should be used to manipulate data
|
|
955
|
-
* associated with this template instance.
|
|
956
|
-
*
|
|
957
|
-
* Example:
|
|
958
|
-
*
|
|
959
|
-
* let model = modelForElement(el);
|
|
960
|
-
* if (model.index < 10) {
|
|
961
|
-
* model.set('item.checked', true);
|
|
962
|
-
* }
|
|
963
|
-
*
|
|
964
|
-
* @param {HTMLElement} template The model will be returned for
|
|
965
|
-
* elements stamped from this template (accepts either an HTMLTemplateElement)
|
|
966
|
-
* or a `<dom-if>`/`<dom-repeat>` element when using `removeNestedTemplates`
|
|
967
|
-
* optimization.
|
|
968
|
-
* @param {Node=} node Node for which to return a template model.
|
|
969
|
-
* @return {TemplateInstanceBase} Template instance representing the
|
|
970
|
-
* binding scope for the element
|
|
971
|
-
*/
|
|
972
|
-
function modelForElement(template, node) {
|
|
973
|
-
let model;
|
|
974
|
-
while (node) {
|
|
975
|
-
// An element with a __templatizeInstance marks the top boundary
|
|
976
|
-
// of a scope; walk up until we find one, and then ensure that
|
|
977
|
-
// its __dataHost matches `this`, meaning this dom-repeat stamped it
|
|
978
|
-
if ((model = node.__dataHost ? node : node.__templatizeInstance)) {
|
|
979
|
-
// Found an element stamped by another template; keep walking up
|
|
980
|
-
// from its __dataHost
|
|
981
|
-
if (model.__dataHost != template) {
|
|
982
|
-
node = model.__dataHost;
|
|
983
|
-
} else {
|
|
984
|
-
return model;
|
|
985
|
-
}
|
|
986
|
-
} else {
|
|
987
|
-
// Still in a template scope, keep going up until
|
|
988
|
-
// a __templatizeInstance is found
|
|
989
|
-
node = wrap(node).parentNode;
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
return null;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
430
|
/**
|
|
996
431
|
* @license
|
|
997
|
-
* Copyright (c) 2021 -
|
|
432
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
998
433
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
999
434
|
*/
|
|
1000
435
|
|
|
@@ -1026,6 +461,27 @@ class FocusTrapController {
|
|
|
1026
461
|
this.__onKeyDown = this.__onKeyDown.bind(this);
|
|
1027
462
|
}
|
|
1028
463
|
|
|
464
|
+
/**
|
|
465
|
+
* An array of tab-ordered focusable elements inside the trap node.
|
|
466
|
+
*
|
|
467
|
+
* @return {HTMLElement[]}
|
|
468
|
+
* @private
|
|
469
|
+
*/
|
|
470
|
+
get __focusableElements() {
|
|
471
|
+
return getFocusableElements(this.__trapNode);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* The index of the element inside the trap node that currently has focus.
|
|
476
|
+
*
|
|
477
|
+
* @return {HTMLElement | undefined}
|
|
478
|
+
* @private
|
|
479
|
+
*/
|
|
480
|
+
get __focusedElementIndex() {
|
|
481
|
+
const focusableElements = this.__focusableElements;
|
|
482
|
+
return focusableElements.indexOf(focusableElements.filter(isElementFocused).pop());
|
|
483
|
+
}
|
|
484
|
+
|
|
1029
485
|
hostConnected() {
|
|
1030
486
|
document.addEventListener('keydown', this.__onKeyDown);
|
|
1031
487
|
}
|
|
@@ -1124,1123 +580,845 @@ class FocusTrapController {
|
|
|
1124
580
|
element.select();
|
|
1125
581
|
}
|
|
1126
582
|
}
|
|
1127
|
-
|
|
1128
|
-
/**
|
|
1129
|
-
* An array of tab-ordered focusable elements inside the trap node.
|
|
1130
|
-
*
|
|
1131
|
-
* @return {HTMLElement[]}
|
|
1132
|
-
* @private
|
|
1133
|
-
*/
|
|
1134
|
-
get __focusableElements() {
|
|
1135
|
-
return getFocusableElements(this.__trapNode);
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
/**
|
|
1139
|
-
* The index of the element inside the trap node that currently has focus.
|
|
1140
|
-
*
|
|
1141
|
-
* @return {HTMLElement | undefined}
|
|
1142
|
-
* @private
|
|
1143
|
-
*/
|
|
1144
|
-
get __focusedElementIndex() {
|
|
1145
|
-
const focusableElements = this.__focusableElements;
|
|
1146
|
-
return focusableElements.indexOf(focusableElements.filter(isElementFocused).pop());
|
|
1147
|
-
}
|
|
1148
583
|
}
|
|
1149
584
|
|
|
1150
585
|
/**
|
|
1151
586
|
* @license
|
|
1152
|
-
* Copyright (c)
|
|
587
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
1153
588
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1154
589
|
*/
|
|
1155
590
|
|
|
1156
591
|
/**
|
|
1157
|
-
*
|
|
1158
|
-
*
|
|
1159
|
-
* can be populated in two ways: imperatively by using renderer callback function and
|
|
1160
|
-
* declaratively by using Polymer's Templates.
|
|
1161
|
-
*
|
|
1162
|
-
* ### Rendering
|
|
1163
|
-
*
|
|
1164
|
-
* By default, the overlay uses the content provided by using the renderer callback function.
|
|
1165
|
-
*
|
|
1166
|
-
* The renderer function provides `root`, `owner`, `model` arguments when applicable.
|
|
1167
|
-
* Generate DOM content by using `model` object properties if needed, append it to the `root`
|
|
1168
|
-
* element and control the state of the host element by accessing `owner`. Before generating new
|
|
1169
|
-
* content, users are able to check if there is already content in `root` for reusing it.
|
|
1170
|
-
*
|
|
1171
|
-
* ```html
|
|
1172
|
-
* <vaadin-overlay id="overlay"></vaadin-overlay>
|
|
1173
|
-
* ```
|
|
1174
|
-
* ```js
|
|
1175
|
-
* const overlay = document.querySelector('#overlay');
|
|
1176
|
-
* overlay.renderer = function(root) {
|
|
1177
|
-
* root.textContent = "Overlay content";
|
|
1178
|
-
* };
|
|
1179
|
-
* ```
|
|
1180
|
-
*
|
|
1181
|
-
* Renderer is called on the opening of the overlay and each time the related model is updated.
|
|
1182
|
-
* DOM generated during the renderer call can be reused
|
|
1183
|
-
* in the next renderer call and will be provided with the `root` argument.
|
|
1184
|
-
* On first call it will be empty.
|
|
1185
|
-
*
|
|
1186
|
-
* **NOTE:** when the renderer property is defined, the `<template>` content is not used.
|
|
1187
|
-
*
|
|
1188
|
-
* ### Templating
|
|
1189
|
-
*
|
|
1190
|
-
* Alternatively, the content can be provided with Polymer Template.
|
|
1191
|
-
* Overlay finds the first child template and uses that in case renderer callback function
|
|
1192
|
-
* is not provided. You can also set a custom template using the `template` property.
|
|
1193
|
-
*
|
|
1194
|
-
* After the content from the template is stamped, the `content` property
|
|
1195
|
-
* points to the content container.
|
|
1196
|
-
*
|
|
1197
|
-
* The overlay provides `forwardHostProp` when calling
|
|
1198
|
-
* `Polymer.Templatize.templatize` for the template, so that the bindings
|
|
1199
|
-
* from the parent scope propagate to the content.
|
|
1200
|
-
*
|
|
1201
|
-
* ### Styling
|
|
1202
|
-
*
|
|
1203
|
-
* To style the overlay content, use styles in the parent scope:
|
|
1204
|
-
*
|
|
1205
|
-
* - If the overlay is used in a component, then the component styles
|
|
1206
|
-
* apply the overlay content.
|
|
1207
|
-
* - If the overlay is used in the global DOM scope, then global styles
|
|
1208
|
-
* apply to the overlay content.
|
|
1209
|
-
*
|
|
1210
|
-
* See examples for styling the overlay content in the live demos.
|
|
1211
|
-
*
|
|
1212
|
-
* The following Shadow DOM parts are available for styling the overlay component itself:
|
|
1213
|
-
*
|
|
1214
|
-
* Part name | Description
|
|
1215
|
-
* -----------|---------------------------------------------------------|
|
|
1216
|
-
* `backdrop` | Backdrop of the overlay
|
|
1217
|
-
* `overlay` | Container for position/sizing/alignment of the content
|
|
1218
|
-
* `content` | Content of the overlay
|
|
1219
|
-
*
|
|
1220
|
-
* The following state attributes are available for styling:
|
|
1221
|
-
*
|
|
1222
|
-
* Attribute | Description | Part
|
|
1223
|
-
* ---|---|---
|
|
1224
|
-
* `opening` | Applied just after the overlay is attached to the DOM. You can apply a CSS @keyframe animation for this state. | `:host`
|
|
1225
|
-
* `closing` | Applied just before the overlay is detached from the DOM. You can apply a CSS @keyframe animation for this state. | `:host`
|
|
1226
|
-
*
|
|
1227
|
-
* The following custom CSS properties are available for styling:
|
|
1228
|
-
*
|
|
1229
|
-
* Custom CSS property | Description | Default value
|
|
1230
|
-
* ---|---|---
|
|
1231
|
-
* `--vaadin-overlay-viewport-bottom` | Bottom offset of the visible viewport area | `0` or detected offset
|
|
1232
|
-
*
|
|
1233
|
-
* See [Styling Components](https://vaadin.com/docs/latest/styling/custom-theme/styling-components) documentation.
|
|
1234
|
-
*
|
|
1235
|
-
* @fires {CustomEvent} opened-changed - Fired when the `opened` property changes.
|
|
1236
|
-
* @fires {CustomEvent} vaadin-overlay-open - Fired after the overlay is opened.
|
|
1237
|
-
* @fires {CustomEvent} vaadin-overlay-close - Fired before the overlay will be closed. If canceled the closing of the overlay is canceled as well.
|
|
1238
|
-
* @fires {CustomEvent} vaadin-overlay-closing - Fired when the overlay will be closed.
|
|
1239
|
-
* @fires {CustomEvent} vaadin-overlay-outside-click - Fired before the overlay will be closed on outside click. If canceled the closing of the overlay is canceled as well.
|
|
1240
|
-
* @fires {CustomEvent} vaadin-overlay-escape-press - Fired before the overlay will be closed on ESC button press. If canceled the closing of the overlay is canceled as well.
|
|
1241
|
-
*
|
|
1242
|
-
* @extends HTMLElement
|
|
1243
|
-
* @mixes ThemableMixin
|
|
1244
|
-
* @mixes DirMixin
|
|
1245
|
-
* @mixes ControllerMixin
|
|
592
|
+
* @typedef ReactiveController
|
|
593
|
+
* @type {import('lit').ReactiveController}
|
|
1246
594
|
*/
|
|
1247
|
-
class Overlay extends ThemableMixin(DirMixin(ControllerMixin(PolymerElement))) {
|
|
1248
|
-
static get template() {
|
|
1249
|
-
return html`
|
|
1250
|
-
<style>
|
|
1251
|
-
:host {
|
|
1252
|
-
z-index: 200;
|
|
1253
|
-
position: fixed;
|
|
1254
|
-
|
|
1255
|
-
/* Despite of what the names say, <vaadin-overlay> is just a container
|
|
1256
|
-
for position/sizing/alignment. The actual overlay is the overlay part. */
|
|
1257
|
-
|
|
1258
|
-
/* Default position constraints: the entire viewport. Note: themes can
|
|
1259
|
-
override this to introduce gaps between the overlay and the viewport. */
|
|
1260
|
-
top: 0;
|
|
1261
|
-
right: 0;
|
|
1262
|
-
bottom: var(--vaadin-overlay-viewport-bottom);
|
|
1263
|
-
left: 0;
|
|
1264
|
-
|
|
1265
|
-
/* Use flexbox alignment for the overlay part. */
|
|
1266
|
-
display: flex;
|
|
1267
|
-
flex-direction: column; /* makes dropdowns sizing easier */
|
|
1268
|
-
/* Align to center by default. */
|
|
1269
|
-
align-items: center;
|
|
1270
|
-
justify-content: center;
|
|
1271
|
-
|
|
1272
|
-
/* Allow centering when max-width/max-height applies. */
|
|
1273
|
-
margin: auto;
|
|
1274
|
-
|
|
1275
|
-
/* The host is not clickable, only the overlay part is. */
|
|
1276
|
-
pointer-events: none;
|
|
1277
|
-
|
|
1278
|
-
/* Remove tap highlight on touch devices. */
|
|
1279
|
-
-webkit-tap-highlight-color: transparent;
|
|
1280
|
-
|
|
1281
|
-
/* CSS API for host */
|
|
1282
|
-
--vaadin-overlay-viewport-bottom: 0;
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
:host([hidden]),
|
|
1286
|
-
:host(:not([opened]):not([closing])) {
|
|
1287
|
-
display: none !important;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
[part='overlay'] {
|
|
1291
|
-
-webkit-overflow-scrolling: touch;
|
|
1292
|
-
overflow: auto;
|
|
1293
|
-
pointer-events: auto;
|
|
1294
595
|
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
background: rgba(0, 0, 0, 0.5);
|
|
1306
|
-
position: fixed;
|
|
1307
|
-
top: 0;
|
|
1308
|
-
left: 0;
|
|
1309
|
-
bottom: 0;
|
|
1310
|
-
right: 0;
|
|
1311
|
-
pointer-events: auto;
|
|
1312
|
-
}
|
|
1313
|
-
</style>
|
|
1314
|
-
|
|
1315
|
-
<div id="backdrop" part="backdrop" hidden$="[[!withBackdrop]]"></div>
|
|
1316
|
-
<div part="overlay" id="overlay" tabindex="0">
|
|
1317
|
-
<div part="content" id="content">
|
|
1318
|
-
<slot></slot>
|
|
1319
|
-
</div>
|
|
1320
|
-
</div>
|
|
1321
|
-
`;
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
static get is() {
|
|
1325
|
-
return 'vaadin-overlay';
|
|
596
|
+
/**
|
|
597
|
+
* A mixin for connecting controllers to the element.
|
|
598
|
+
*
|
|
599
|
+
* @polymerMixin
|
|
600
|
+
*/
|
|
601
|
+
const ControllerMixin = dedupingMixin((superClass) => {
|
|
602
|
+
// If the superclass extends from LitElement,
|
|
603
|
+
// use its own controllers implementation.
|
|
604
|
+
if (typeof superClass.prototype.addController === 'function') {
|
|
605
|
+
return superClass;
|
|
1326
606
|
}
|
|
1327
607
|
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
* When true, the overlay is visible and attached to body.
|
|
1332
|
-
*/
|
|
1333
|
-
opened: {
|
|
1334
|
-
type: Boolean,
|
|
1335
|
-
notify: true,
|
|
1336
|
-
observer: '_openedChanged',
|
|
1337
|
-
reflectToAttribute: true,
|
|
1338
|
-
},
|
|
1339
|
-
|
|
1340
|
-
/**
|
|
1341
|
-
* Owner element passed with renderer function
|
|
1342
|
-
* @type {HTMLElement}
|
|
1343
|
-
*/
|
|
1344
|
-
owner: Element,
|
|
1345
|
-
|
|
1346
|
-
/**
|
|
1347
|
-
* Custom function for rendering the content of the overlay.
|
|
1348
|
-
* Receives three arguments:
|
|
1349
|
-
*
|
|
1350
|
-
* - `root` The root container DOM element. Append your content to it.
|
|
1351
|
-
* - `owner` The host element of the renderer function.
|
|
1352
|
-
* - `model` The object with the properties related with rendering.
|
|
1353
|
-
* @type {OverlayRenderer | null | undefined}
|
|
1354
|
-
*/
|
|
1355
|
-
renderer: Function,
|
|
1356
|
-
|
|
1357
|
-
/**
|
|
1358
|
-
* The template of the overlay content.
|
|
1359
|
-
* @type {HTMLTemplateElement | null | undefined}
|
|
1360
|
-
*/
|
|
1361
|
-
template: {
|
|
1362
|
-
type: Object,
|
|
1363
|
-
notify: true,
|
|
1364
|
-
},
|
|
1365
|
-
|
|
1366
|
-
/**
|
|
1367
|
-
* References the content container after the template is stamped.
|
|
1368
|
-
* @type {!HTMLElement | undefined}
|
|
1369
|
-
*/
|
|
1370
|
-
content: {
|
|
1371
|
-
type: Object,
|
|
1372
|
-
notify: true,
|
|
1373
|
-
},
|
|
1374
|
-
|
|
1375
|
-
/**
|
|
1376
|
-
* When true the overlay has backdrop on top of content when opened.
|
|
1377
|
-
* @type {boolean}
|
|
1378
|
-
*/
|
|
1379
|
-
withBackdrop: {
|
|
1380
|
-
type: Boolean,
|
|
1381
|
-
value: false,
|
|
1382
|
-
reflectToAttribute: true,
|
|
1383
|
-
},
|
|
1384
|
-
|
|
1385
|
-
/**
|
|
1386
|
-
* Object with properties that is passed to `renderer` function
|
|
1387
|
-
*/
|
|
1388
|
-
model: Object,
|
|
1389
|
-
|
|
1390
|
-
/**
|
|
1391
|
-
* When true the overlay won't disable the main content, showing
|
|
1392
|
-
* it doesn’t change the functionality of the user interface.
|
|
1393
|
-
* @type {boolean}
|
|
1394
|
-
*/
|
|
1395
|
-
modeless: {
|
|
1396
|
-
type: Boolean,
|
|
1397
|
-
value: false,
|
|
1398
|
-
reflectToAttribute: true,
|
|
1399
|
-
observer: '_modelessChanged',
|
|
1400
|
-
},
|
|
1401
|
-
|
|
1402
|
-
/**
|
|
1403
|
-
* When set to true, the overlay is hidden. This also closes the overlay
|
|
1404
|
-
* immediately in case there is a closing animation in progress.
|
|
1405
|
-
* @type {boolean}
|
|
1406
|
-
*/
|
|
1407
|
-
hidden: {
|
|
1408
|
-
type: Boolean,
|
|
1409
|
-
reflectToAttribute: true,
|
|
1410
|
-
observer: '_hiddenChanged',
|
|
1411
|
-
},
|
|
1412
|
-
|
|
1413
|
-
/**
|
|
1414
|
-
* When true move focus to the first focusable element in the overlay,
|
|
1415
|
-
* or to the overlay if there are no focusable elements.
|
|
1416
|
-
* @type {boolean}
|
|
1417
|
-
*/
|
|
1418
|
-
focusTrap: {
|
|
1419
|
-
type: Boolean,
|
|
1420
|
-
value: false,
|
|
1421
|
-
},
|
|
1422
|
-
|
|
1423
|
-
/**
|
|
1424
|
-
* Set to true to enable restoring of focus when overlay is closed.
|
|
1425
|
-
* @type {boolean}
|
|
1426
|
-
*/
|
|
1427
|
-
restoreFocusOnClose: {
|
|
1428
|
-
type: Boolean,
|
|
1429
|
-
value: false,
|
|
1430
|
-
},
|
|
608
|
+
return class ControllerMixinClass extends superClass {
|
|
609
|
+
constructor() {
|
|
610
|
+
super();
|
|
1431
611
|
|
|
1432
612
|
/**
|
|
1433
|
-
* Set
|
|
1434
|
-
* if `restoreFocusOnClose` is set to true.
|
|
1435
|
-
* @type {HTMLElement}
|
|
613
|
+
* @type {Set<ReactiveController>}
|
|
1436
614
|
*/
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
},
|
|
1440
|
-
|
|
1441
|
-
/** @private */
|
|
1442
|
-
_mouseDownInside: {
|
|
1443
|
-
type: Boolean,
|
|
1444
|
-
},
|
|
1445
|
-
|
|
1446
|
-
/** @private */
|
|
1447
|
-
_mouseUpInside: {
|
|
1448
|
-
type: Boolean,
|
|
1449
|
-
},
|
|
1450
|
-
|
|
1451
|
-
/** @private */
|
|
1452
|
-
_instance: {
|
|
1453
|
-
type: Object,
|
|
1454
|
-
},
|
|
1455
|
-
|
|
1456
|
-
/** @private */
|
|
1457
|
-
_originalContentPart: Object,
|
|
1458
|
-
|
|
1459
|
-
/** @private */
|
|
1460
|
-
_contentNodes: Array,
|
|
1461
|
-
|
|
1462
|
-
/** @private */
|
|
1463
|
-
_oldOwner: Element,
|
|
1464
|
-
|
|
1465
|
-
/** @private */
|
|
1466
|
-
_oldModel: Object,
|
|
1467
|
-
|
|
1468
|
-
/** @private */
|
|
1469
|
-
_oldTemplate: Object,
|
|
1470
|
-
|
|
1471
|
-
/** @private */
|
|
1472
|
-
_oldRenderer: Object,
|
|
1473
|
-
|
|
1474
|
-
/** @private */
|
|
1475
|
-
_oldOpened: Boolean,
|
|
1476
|
-
};
|
|
1477
|
-
}
|
|
1478
|
-
|
|
1479
|
-
static get observers() {
|
|
1480
|
-
return ['_templateOrRendererChanged(template, renderer, owner, model, opened)'];
|
|
1481
|
-
}
|
|
615
|
+
this.__controllers = new Set();
|
|
616
|
+
}
|
|
1482
617
|
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
this._boundMouseUpListener = this._mouseUpListener.bind(this);
|
|
1487
|
-
this._boundOutsideClickListener = this._outsideClickListener.bind(this);
|
|
1488
|
-
this._boundKeydownListener = this._keydownListener.bind(this);
|
|
618
|
+
/** @protected */
|
|
619
|
+
connectedCallback() {
|
|
620
|
+
super.connectedCallback();
|
|
1489
621
|
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
622
|
+
this.__controllers.forEach((c) => {
|
|
623
|
+
if (c.hostConnected) {
|
|
624
|
+
c.hostConnected();
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
}
|
|
1493
628
|
|
|
1494
|
-
|
|
1495
|
-
|
|
629
|
+
/** @protected */
|
|
630
|
+
disconnectedCallback() {
|
|
631
|
+
super.disconnectedCallback();
|
|
1496
632
|
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
633
|
+
this.__controllers.forEach((c) => {
|
|
634
|
+
if (c.hostDisconnected) {
|
|
635
|
+
c.hostDisconnected();
|
|
636
|
+
}
|
|
637
|
+
});
|
|
1500
638
|
}
|
|
1501
639
|
|
|
1502
|
-
|
|
1503
|
-
|
|
640
|
+
/**
|
|
641
|
+
* Registers a controller to participate in the element update cycle.
|
|
642
|
+
*
|
|
643
|
+
* @param {ReactiveController} controller
|
|
644
|
+
* @protected
|
|
645
|
+
*/
|
|
646
|
+
addController(controller) {
|
|
647
|
+
this.__controllers.add(controller);
|
|
648
|
+
// Call hostConnected if a controller is added after the element is attached.
|
|
649
|
+
if (this.$ !== undefined && this.isConnected && controller.hostConnected) {
|
|
650
|
+
controller.hostConnected();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
1504
653
|
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
654
|
+
/**
|
|
655
|
+
* Removes a controller from the element.
|
|
656
|
+
*
|
|
657
|
+
* @param {ReactiveController} controller
|
|
658
|
+
* @protected
|
|
659
|
+
*/
|
|
660
|
+
removeController(controller) {
|
|
661
|
+
this.__controllers.delete(controller);
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
});
|
|
1508
665
|
|
|
1509
|
-
|
|
666
|
+
/**
|
|
667
|
+
* @license
|
|
668
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
669
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
670
|
+
*/
|
|
1510
671
|
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
672
|
+
/**
|
|
673
|
+
* @polymerMixin
|
|
674
|
+
* @mixes ControllerMixin
|
|
675
|
+
*/
|
|
676
|
+
const OverlayFocusMixin = (superClass) =>
|
|
677
|
+
class OverlayFocusMixin extends ControllerMixin(superClass) {
|
|
678
|
+
static get properties() {
|
|
679
|
+
return {
|
|
680
|
+
/**
|
|
681
|
+
* When true, opening the overlay moves focus to the first focusable child,
|
|
682
|
+
* or to the overlay part with tabindex if there are no focusable children.
|
|
683
|
+
* @attr {boolean} focus-trap
|
|
684
|
+
*/
|
|
685
|
+
focusTrap: {
|
|
686
|
+
type: Boolean,
|
|
687
|
+
value: false,
|
|
688
|
+
},
|
|
1517
689
|
|
|
1518
|
-
|
|
1519
|
-
|
|
690
|
+
/**
|
|
691
|
+
* Set to true to enable restoring of focus when overlay is closed.
|
|
692
|
+
* @attr {boolean} restore-focus-on-close
|
|
693
|
+
*/
|
|
694
|
+
restoreFocusOnClose: {
|
|
695
|
+
type: Boolean,
|
|
696
|
+
value: false,
|
|
697
|
+
},
|
|
1520
698
|
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
699
|
+
/**
|
|
700
|
+
* Set to specify the element which should be focused on overlay close,
|
|
701
|
+
* if `restoreFocusOnClose` is set to true.
|
|
702
|
+
* @type {HTMLElement}
|
|
703
|
+
*/
|
|
704
|
+
restoreFocusNode: {
|
|
705
|
+
type: HTMLElement,
|
|
706
|
+
},
|
|
707
|
+
};
|
|
1526
708
|
}
|
|
1527
709
|
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
const landscape = innerWidth > innerHeight;
|
|
1532
|
-
|
|
1533
|
-
const clientHeight = document.documentElement.clientHeight;
|
|
710
|
+
constructor() {
|
|
711
|
+
super();
|
|
1534
712
|
|
|
1535
|
-
|
|
1536
|
-
this.
|
|
1537
|
-
|
|
1538
|
-
this.style.setProperty('--vaadin-overlay-viewport-bottom', '0');
|
|
713
|
+
this.__ariaModalController = new AriaModalController(this);
|
|
714
|
+
this.__focusTrapController = new FocusTrapController(this);
|
|
715
|
+
this.__focusRestorationController = new FocusRestorationController();
|
|
1539
716
|
}
|
|
1540
|
-
}
|
|
1541
717
|
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
*/
|
|
1546
|
-
_setTemplateFromNodes(nodes) {
|
|
1547
|
-
this.template = nodes.find((node) => node.localName && node.localName === 'template') || this.template;
|
|
1548
|
-
}
|
|
718
|
+
/** @protected */
|
|
719
|
+
ready() {
|
|
720
|
+
super.ready();
|
|
1549
721
|
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
* fired before the `vaadin-overlay` will be closed. If canceled the closing of the overlay is canceled as well.
|
|
1554
|
-
*/
|
|
1555
|
-
close(sourceEvent) {
|
|
1556
|
-
const evt = new CustomEvent('vaadin-overlay-close', {
|
|
1557
|
-
bubbles: true,
|
|
1558
|
-
cancelable: true,
|
|
1559
|
-
detail: { sourceEvent },
|
|
1560
|
-
});
|
|
1561
|
-
this.dispatchEvent(evt);
|
|
1562
|
-
if (!evt.defaultPrevented) {
|
|
1563
|
-
this.opened = false;
|
|
722
|
+
this.addController(this.__ariaModalController);
|
|
723
|
+
this.addController(this.__focusTrapController);
|
|
724
|
+
this.addController(this.__focusRestorationController);
|
|
1564
725
|
}
|
|
1565
|
-
}
|
|
1566
726
|
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
727
|
+
/**
|
|
728
|
+
* Release focus and restore focus after the overlay is closed.
|
|
729
|
+
*
|
|
730
|
+
* @protected
|
|
731
|
+
*/
|
|
732
|
+
_resetFocus() {
|
|
733
|
+
if (this.focusTrap) {
|
|
734
|
+
this.__ariaModalController.close();
|
|
735
|
+
this.__focusTrapController.releaseFocus();
|
|
736
|
+
}
|
|
1570
737
|
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
window.addEventListener('resize', this._boundIosResizeListener);
|
|
738
|
+
if (this.restoreFocusOnClose && this._shouldRestoreFocus()) {
|
|
739
|
+
this.__focusRestorationController.restoreFocus();
|
|
740
|
+
}
|
|
1575
741
|
}
|
|
1576
|
-
}
|
|
1577
742
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
743
|
+
/**
|
|
744
|
+
* Save the previously focused node when the overlay starts to open.
|
|
745
|
+
*
|
|
746
|
+
* @protected
|
|
747
|
+
*/
|
|
748
|
+
_saveFocus() {
|
|
749
|
+
if (this.restoreFocusOnClose) {
|
|
750
|
+
this.__focusRestorationController.saveFocus(this.restoreFocusNode);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
1581
753
|
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
754
|
+
/**
|
|
755
|
+
* Trap focus within the overlay after opening has completed.
|
|
756
|
+
*
|
|
757
|
+
* @protected
|
|
758
|
+
*/
|
|
759
|
+
_trapFocus() {
|
|
760
|
+
if (this.focusTrap) {
|
|
761
|
+
this.__ariaModalController.showModal();
|
|
762
|
+
this.__focusTrapController.trapFocus(this.$.overlay);
|
|
763
|
+
}
|
|
1585
764
|
}
|
|
1586
|
-
}
|
|
1587
765
|
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
766
|
+
/**
|
|
767
|
+
* Returns true if focus is still inside the overlay or on the body element,
|
|
768
|
+
* otherwise false.
|
|
769
|
+
*
|
|
770
|
+
* Focus shouldn't be restored if it's been moved elsewhere by another
|
|
771
|
+
* component or as a result of a user interaction e.g. the user clicked
|
|
772
|
+
* on a button outside the overlay while the overlay was open.
|
|
773
|
+
*
|
|
774
|
+
* @protected
|
|
775
|
+
* @return {boolean}
|
|
776
|
+
*/
|
|
777
|
+
_shouldRestoreFocus() {
|
|
778
|
+
const activeElement = getDeepActiveElement();
|
|
779
|
+
return activeElement === document.body || this._deepContains(activeElement);
|
|
1597
780
|
}
|
|
1598
|
-
}
|
|
1599
781
|
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
782
|
+
/**
|
|
783
|
+
* Returns true if the overlay contains the given node,
|
|
784
|
+
* including those within shadow DOM trees.
|
|
785
|
+
*
|
|
786
|
+
* @param {Node} node
|
|
787
|
+
* @return {boolean}
|
|
788
|
+
* @protected
|
|
789
|
+
*/
|
|
790
|
+
_deepContains(node) {
|
|
791
|
+
if (this.contains(node)) {
|
|
792
|
+
return true;
|
|
793
|
+
}
|
|
794
|
+
let n = node;
|
|
795
|
+
const doc = node.ownerDocument;
|
|
796
|
+
// Walk from node to `this` or `document`
|
|
797
|
+
while (n && n !== doc && n !== this) {
|
|
798
|
+
n = n.parentNode || n.host;
|
|
799
|
+
}
|
|
800
|
+
return n === this;
|
|
801
|
+
}
|
|
802
|
+
};
|
|
1604
803
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
804
|
+
/**
|
|
805
|
+
* @license
|
|
806
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
807
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
808
|
+
*/
|
|
1609
809
|
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
810
|
+
/**
|
|
811
|
+
* Returns all attached overlays in visual stacking order.
|
|
812
|
+
* @private
|
|
813
|
+
*/
|
|
814
|
+
const getAttachedInstances = () =>
|
|
815
|
+
Array.from(document.body.children)
|
|
816
|
+
.filter((el) => el instanceof HTMLElement && el._hasOverlayStackMixin && !el.hasAttribute('closing'))
|
|
817
|
+
.sort((a, b) => a.__zIndex - b.__zIndex || 0);
|
|
1614
818
|
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
*
|
|
1623
|
-
* @private
|
|
1624
|
-
*/
|
|
1625
|
-
_outsideClickListener(event) {
|
|
1626
|
-
if (event.composedPath().includes(this.$.overlay) || this._mouseDownInside || this._mouseUpInside) {
|
|
1627
|
-
this._mouseDownInside = false;
|
|
1628
|
-
this._mouseUpInside = false;
|
|
1629
|
-
return;
|
|
1630
|
-
}
|
|
1631
|
-
if (!this._last) {
|
|
1632
|
-
return;
|
|
1633
|
-
}
|
|
819
|
+
/**
|
|
820
|
+
* Returns true if the overlay is the last one in the opened overlays stack.
|
|
821
|
+
* @param {HTMLElement} overlay
|
|
822
|
+
* @return {boolean}
|
|
823
|
+
* @protected
|
|
824
|
+
*/
|
|
825
|
+
const isLastOverlay = (overlay) => overlay === getAttachedInstances().pop();
|
|
1634
826
|
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
827
|
+
/**
|
|
828
|
+
* @polymerMixin
|
|
829
|
+
*/
|
|
830
|
+
const OverlayStackMixin = (superClass) =>
|
|
831
|
+
class OverlayStackMixin extends superClass {
|
|
832
|
+
constructor() {
|
|
833
|
+
super();
|
|
1641
834
|
|
|
1642
|
-
|
|
1643
|
-
this.close(event);
|
|
835
|
+
this._hasOverlayStackMixin = true;
|
|
1644
836
|
}
|
|
1645
|
-
}
|
|
1646
837
|
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
return;
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
// Only close modeless overlay on Esc press when it contains focus
|
|
1659
|
-
if (this.modeless && !event.composedPath().includes(this.$.overlay)) {
|
|
1660
|
-
return;
|
|
838
|
+
/**
|
|
839
|
+
* Returns true if this is the last one in the opened overlays stack.
|
|
840
|
+
*
|
|
841
|
+
* @return {boolean}
|
|
842
|
+
* @protected
|
|
843
|
+
*/
|
|
844
|
+
get _last() {
|
|
845
|
+
return isLastOverlay(this);
|
|
1661
846
|
}
|
|
1662
847
|
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
if (
|
|
1672
|
-
|
|
848
|
+
/**
|
|
849
|
+
* Brings the overlay as visually the frontmost one.
|
|
850
|
+
*/
|
|
851
|
+
bringToFront() {
|
|
852
|
+
let zIndex = '';
|
|
853
|
+
const frontmost = getAttachedInstances()
|
|
854
|
+
.filter((o) => o !== this)
|
|
855
|
+
.pop();
|
|
856
|
+
if (frontmost) {
|
|
857
|
+
const frontmostZIndex = frontmost.__zIndex;
|
|
858
|
+
zIndex = frontmostZIndex + 1;
|
|
1673
859
|
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
/** @protected */
|
|
1678
|
-
_ensureTemplatized() {
|
|
1679
|
-
this._setTemplateFromNodes(Array.from(this.children));
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
/**
|
|
1683
|
-
* @event vaadin-overlay-open
|
|
1684
|
-
* fired after the `vaadin-overlay` is opened.
|
|
1685
|
-
*
|
|
1686
|
-
* @private
|
|
1687
|
-
*/
|
|
1688
|
-
_openedChanged(opened, wasOpened) {
|
|
1689
|
-
if (!this._instance) {
|
|
1690
|
-
this._ensureTemplatized();
|
|
860
|
+
this.style.zIndex = zIndex;
|
|
861
|
+
this.__zIndex = zIndex || parseFloat(getComputedStyle(this).zIndex);
|
|
1691
862
|
}
|
|
1692
863
|
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
864
|
+
/** @protected */
|
|
865
|
+
_enterModalState() {
|
|
866
|
+
if (document.body.style.pointerEvents !== 'none') {
|
|
867
|
+
// Set body pointer-events to 'none' to disable mouse interactions with
|
|
868
|
+
// other document nodes.
|
|
869
|
+
this._previousDocumentPointerEvents = document.body.style.pointerEvents;
|
|
870
|
+
document.body.style.pointerEvents = 'none';
|
|
871
|
+
}
|
|
1697
872
|
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
873
|
+
// Disable pointer events in other attached overlays
|
|
874
|
+
getAttachedInstances().forEach((el) => {
|
|
875
|
+
if (el !== this) {
|
|
876
|
+
el.$.overlay.style.pointerEvents = 'none';
|
|
1701
877
|
}
|
|
1702
|
-
|
|
1703
|
-
const evt = new CustomEvent('vaadin-overlay-open', { bubbles: true });
|
|
1704
|
-
this.dispatchEvent(evt);
|
|
1705
878
|
});
|
|
879
|
+
}
|
|
1706
880
|
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
if (
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
if (this.focusTrap) {
|
|
1714
|
-
this.__focusTrapController.releaseFocus();
|
|
881
|
+
/** @protected */
|
|
882
|
+
_exitModalState() {
|
|
883
|
+
if (this._previousDocumentPointerEvents !== undefined) {
|
|
884
|
+
// Restore body pointer-events
|
|
885
|
+
document.body.style.pointerEvents = this._previousDocumentPointerEvents;
|
|
886
|
+
delete this._previousDocumentPointerEvents;
|
|
1715
887
|
}
|
|
1716
888
|
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
document.removeEventListener('keydown', this._boundKeydownListener);
|
|
889
|
+
// Restore pointer events in the previous overlay(s)
|
|
890
|
+
const instances = getAttachedInstances();
|
|
1720
891
|
|
|
1721
|
-
|
|
1722
|
-
|
|
892
|
+
let el;
|
|
893
|
+
// Use instances.pop() to ensure the reverse order
|
|
894
|
+
while ((el = instances.pop())) {
|
|
895
|
+
if (el === this) {
|
|
896
|
+
// Skip the current instance
|
|
897
|
+
continue;
|
|
898
|
+
}
|
|
899
|
+
el.$.overlay.style.removeProperty('pointer-events');
|
|
900
|
+
if (!el.modeless) {
|
|
901
|
+
// Stop after the last modal
|
|
902
|
+
break;
|
|
903
|
+
}
|
|
1723
904
|
}
|
|
1724
905
|
}
|
|
1725
|
-
}
|
|
906
|
+
};
|
|
1726
907
|
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
}
|
|
908
|
+
/**
|
|
909
|
+
* @license
|
|
910
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
911
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
912
|
+
*/
|
|
1733
913
|
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
914
|
+
/**
|
|
915
|
+
* @polymerMixin
|
|
916
|
+
* @mixes OverlayFocusMixin
|
|
917
|
+
* @mixes OverlayStackMixin
|
|
918
|
+
*/
|
|
919
|
+
const OverlayMixin = (superClass) =>
|
|
920
|
+
class OverlayMixin extends OverlayFocusMixin(OverlayStackMixin(superClass)) {
|
|
921
|
+
static get properties() {
|
|
922
|
+
return {
|
|
923
|
+
/**
|
|
924
|
+
* When true, the overlay is visible and attached to body.
|
|
925
|
+
*/
|
|
926
|
+
opened: {
|
|
927
|
+
type: Boolean,
|
|
928
|
+
notify: true,
|
|
929
|
+
observer: '_openedChanged',
|
|
930
|
+
reflectToAttribute: true,
|
|
931
|
+
},
|
|
1743
932
|
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
const listener = (event) => {
|
|
1752
|
-
if (event && event.target !== this) {
|
|
1753
|
-
return;
|
|
1754
|
-
}
|
|
1755
|
-
callback();
|
|
1756
|
-
this.removeEventListener('animationend', listener);
|
|
1757
|
-
delete this[handler];
|
|
1758
|
-
};
|
|
1759
|
-
this[handler] = listener;
|
|
1760
|
-
this.addEventListener('animationend', listener);
|
|
1761
|
-
}
|
|
933
|
+
/**
|
|
934
|
+
* Owner element passed with renderer function
|
|
935
|
+
* @type {HTMLElement}
|
|
936
|
+
*/
|
|
937
|
+
owner: {
|
|
938
|
+
type: Object,
|
|
939
|
+
},
|
|
1762
940
|
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
if (typeof this[handler] === 'function') {
|
|
1770
|
-
this[handler]();
|
|
1771
|
-
}
|
|
1772
|
-
}
|
|
941
|
+
/**
|
|
942
|
+
* Object with properties that is passed to `renderer` function
|
|
943
|
+
*/
|
|
944
|
+
model: {
|
|
945
|
+
type: Object,
|
|
946
|
+
},
|
|
1773
947
|
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
948
|
+
/**
|
|
949
|
+
* Custom function for rendering the content of the overlay.
|
|
950
|
+
* Receives three arguments:
|
|
951
|
+
*
|
|
952
|
+
* - `root` The root container DOM element. Append your content to it.
|
|
953
|
+
* - `owner` The host element of the renderer function.
|
|
954
|
+
* - `model` The object with the properties related with rendering.
|
|
955
|
+
* @type {OverlayRenderer | null | undefined}
|
|
956
|
+
*/
|
|
957
|
+
renderer: {
|
|
958
|
+
type: Object,
|
|
959
|
+
},
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* When true the overlay won't disable the main content, showing
|
|
963
|
+
* it doesn't change the functionality of the user interface.
|
|
964
|
+
* @type {boolean}
|
|
965
|
+
*/
|
|
966
|
+
modeless: {
|
|
967
|
+
type: Boolean,
|
|
968
|
+
value: false,
|
|
969
|
+
reflectToAttribute: true,
|
|
970
|
+
observer: '_modelessChanged',
|
|
971
|
+
},
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* When set to true, the overlay is hidden. This also closes the overlay
|
|
975
|
+
* immediately in case there is a closing animation in progress.
|
|
976
|
+
* @type {boolean}
|
|
977
|
+
*/
|
|
978
|
+
hidden: {
|
|
979
|
+
type: Boolean,
|
|
980
|
+
reflectToAttribute: true,
|
|
981
|
+
observer: '_hiddenChanged',
|
|
982
|
+
},
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* When true the overlay has backdrop on top of content when opened.
|
|
986
|
+
* @type {boolean}
|
|
987
|
+
*/
|
|
988
|
+
withBackdrop: {
|
|
989
|
+
type: Boolean,
|
|
990
|
+
value: false,
|
|
991
|
+
reflectToAttribute: true,
|
|
992
|
+
},
|
|
993
|
+
};
|
|
1782
994
|
}
|
|
1783
|
-
this.setAttribute('opening', '');
|
|
1784
995
|
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
this._finishOpening();
|
|
1788
|
-
});
|
|
1789
|
-
} else {
|
|
1790
|
-
this._finishOpening();
|
|
996
|
+
static get observers() {
|
|
997
|
+
return ['_rendererOrDataChanged(renderer, owner, model, opened)'];
|
|
1791
998
|
}
|
|
1792
|
-
}
|
|
1793
|
-
|
|
1794
|
-
/** @protected */
|
|
1795
|
-
_attachOverlay() {
|
|
1796
|
-
this._placeholder = document.createComment('vaadin-overlay-placeholder');
|
|
1797
|
-
this.parentNode.insertBefore(this._placeholder, this);
|
|
1798
|
-
document.body.appendChild(this);
|
|
1799
|
-
this.bringToFront();
|
|
1800
|
-
}
|
|
1801
999
|
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
document.addEventListener('iron-overlay-canceled', this._boundIronOverlayCanceledListener);
|
|
1805
|
-
this.removeAttribute('opening');
|
|
1806
|
-
}
|
|
1000
|
+
constructor() {
|
|
1001
|
+
super();
|
|
1807
1002
|
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
this.$.overlay.style.removeProperty('pointer-events');
|
|
1813
|
-
this.removeAttribute('closing');
|
|
1814
|
-
}
|
|
1003
|
+
this._boundMouseDownListener = this._mouseDownListener.bind(this);
|
|
1004
|
+
this._boundMouseUpListener = this._mouseUpListener.bind(this);
|
|
1005
|
+
this._boundOutsideClickListener = this._outsideClickListener.bind(this);
|
|
1006
|
+
this._boundKeydownListener = this._keydownListener.bind(this);
|
|
1815
1007
|
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
*
|
|
1820
|
-
* @protected
|
|
1821
|
-
*/
|
|
1822
|
-
_animatedClosing() {
|
|
1823
|
-
if (this.hasAttribute('opening')) {
|
|
1824
|
-
this._flushAnimation('opening');
|
|
1825
|
-
}
|
|
1826
|
-
if (this._placeholder) {
|
|
1827
|
-
this._exitModalState();
|
|
1828
|
-
|
|
1829
|
-
// Use this.restoreFocusNode if specified, otherwise fallback to the node
|
|
1830
|
-
// which was focused before opening the overlay.
|
|
1831
|
-
const restoreFocusNode = this.restoreFocusNode || this.__restoreFocusNode;
|
|
1832
|
-
|
|
1833
|
-
if (this.restoreFocusOnClose && restoreFocusNode) {
|
|
1834
|
-
// If the activeElement is `<body>` or inside the overlay,
|
|
1835
|
-
// we are allowed to restore the focus. In all the other
|
|
1836
|
-
// cases focus might have been moved elsewhere by another
|
|
1837
|
-
// component or by the user interaction (e.g. click on a
|
|
1838
|
-
// button outside the overlay).
|
|
1839
|
-
const activeElement = this._getActiveElement();
|
|
1840
|
-
|
|
1841
|
-
if (activeElement === document.body || this._deepContains(activeElement)) {
|
|
1842
|
-
// Focusing the restoreFocusNode doesn't always work synchronously on Firefox and Safari
|
|
1843
|
-
// (e.g. combo-box overlay close on outside click).
|
|
1844
|
-
setTimeout(() => restoreFocusNode.focus());
|
|
1845
|
-
}
|
|
1846
|
-
this.__restoreFocusNode = null;
|
|
1008
|
+
/* c8 ignore next 3 */
|
|
1009
|
+
if (isIOS) {
|
|
1010
|
+
this._boundIosResizeListener = () => this._detectIosNavbar();
|
|
1847
1011
|
}
|
|
1012
|
+
}
|
|
1848
1013
|
|
|
1849
|
-
|
|
1850
|
-
|
|
1014
|
+
/** @protected */
|
|
1015
|
+
ready() {
|
|
1016
|
+
super.ready();
|
|
1851
1017
|
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
}
|
|
1018
|
+
// Need to add dummy click listeners to this and the backdrop or else
|
|
1019
|
+
// the document click event listener (_outsideClickListener) may never
|
|
1020
|
+
// get invoked on iOS Safari (reproducible in <vaadin-dialog>
|
|
1021
|
+
// and <vaadin-context-menu>).
|
|
1022
|
+
this.addEventListener('click', () => {});
|
|
1023
|
+
this.$.backdrop.addEventListener('click', () => {});
|
|
1859
1024
|
}
|
|
1860
|
-
}
|
|
1861
1025
|
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
this._placeholder.parentNode.removeChild(this._placeholder);
|
|
1866
|
-
}
|
|
1026
|
+
/** @protected */
|
|
1027
|
+
connectedCallback() {
|
|
1028
|
+
super.connectedCallback();
|
|
1867
1029
|
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
.filter((el) => el instanceof Overlay && !el.hasAttribute('closing'))
|
|
1875
|
-
.sort((a, b) => a.__zIndex - b.__zIndex || 0);
|
|
1876
|
-
}
|
|
1030
|
+
/* c8 ignore next 3 */
|
|
1031
|
+
if (this._boundIosResizeListener) {
|
|
1032
|
+
this._detectIosNavbar();
|
|
1033
|
+
window.addEventListener('resize', this._boundIosResizeListener);
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1877
1036
|
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
* @protected
|
|
1882
|
-
*/
|
|
1883
|
-
get _last() {
|
|
1884
|
-
return this === Overlay.__attachedInstances.pop();
|
|
1885
|
-
}
|
|
1037
|
+
/** @protected */
|
|
1038
|
+
disconnectedCallback() {
|
|
1039
|
+
super.disconnectedCallback();
|
|
1886
1040
|
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
if (this.opened) {
|
|
1891
|
-
this._addGlobalListeners();
|
|
1892
|
-
this._enterModalState();
|
|
1041
|
+
/* c8 ignore next 3 */
|
|
1042
|
+
if (this._boundIosResizeListener) {
|
|
1043
|
+
window.removeEventListener('resize', this._boundIosResizeListener);
|
|
1893
1044
|
}
|
|
1894
|
-
} else {
|
|
1895
|
-
this._removeGlobalListeners();
|
|
1896
|
-
this._exitModalState();
|
|
1897
1045
|
}
|
|
1898
|
-
}
|
|
1899
1046
|
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1047
|
+
/**
|
|
1048
|
+
* Requests an update for the content of the overlay.
|
|
1049
|
+
* While performing the update, it invokes the renderer passed in the `renderer` property.
|
|
1050
|
+
*
|
|
1051
|
+
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
1052
|
+
*/
|
|
1053
|
+
requestContentUpdate() {
|
|
1054
|
+
if (this.renderer) {
|
|
1055
|
+
this.renderer.call(this.owner, this, this.owner, this.model);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1908
1058
|
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1059
|
+
/**
|
|
1060
|
+
* @param {Event=} sourceEvent
|
|
1061
|
+
*/
|
|
1062
|
+
close(sourceEvent) {
|
|
1063
|
+
const evt = new CustomEvent('vaadin-overlay-close', {
|
|
1064
|
+
bubbles: true,
|
|
1065
|
+
cancelable: true,
|
|
1066
|
+
detail: { sourceEvent },
|
|
1067
|
+
});
|
|
1068
|
+
this.dispatchEvent(evt);
|
|
1069
|
+
if (!evt.defaultPrevented) {
|
|
1070
|
+
this.opened = false;
|
|
1071
|
+
}
|
|
1916
1072
|
}
|
|
1917
1073
|
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1074
|
+
/** @private */
|
|
1075
|
+
_detectIosNavbar() {
|
|
1076
|
+
/* c8 ignore next 15 */
|
|
1077
|
+
if (!this.opened) {
|
|
1078
|
+
return;
|
|
1922
1079
|
}
|
|
1923
|
-
});
|
|
1924
|
-
}
|
|
1925
1080
|
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
document.removeEventListener('mousedown', this._boundMouseDownListener);
|
|
1929
|
-
document.removeEventListener('mouseup', this._boundMouseUpListener);
|
|
1930
|
-
document.documentElement.removeEventListener('click', this._boundOutsideClickListener, true);
|
|
1931
|
-
}
|
|
1081
|
+
const innerHeight = window.innerHeight;
|
|
1082
|
+
const innerWidth = window.innerWidth;
|
|
1932
1083
|
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
// Restore pointer events in the previous overlay(s)
|
|
1942
|
-
const instances = Overlay.__attachedInstances;
|
|
1943
|
-
let el;
|
|
1944
|
-
// Use instances.pop() to ensure the reverse order
|
|
1945
|
-
while ((el = instances.pop())) {
|
|
1946
|
-
if (el === this) {
|
|
1947
|
-
// Skip the current instance
|
|
1948
|
-
continue;
|
|
1949
|
-
}
|
|
1950
|
-
el.shadowRoot.querySelector('[part="overlay"]').style.removeProperty('pointer-events');
|
|
1951
|
-
if (!el.modeless) {
|
|
1952
|
-
// Stop after the last modal
|
|
1953
|
-
break;
|
|
1084
|
+
const landscape = innerWidth > innerHeight;
|
|
1085
|
+
|
|
1086
|
+
const clientHeight = document.documentElement.clientHeight;
|
|
1087
|
+
|
|
1088
|
+
if (landscape && clientHeight > innerHeight) {
|
|
1089
|
+
this.style.setProperty('--vaadin-overlay-viewport-bottom', `${clientHeight - innerHeight}px`);
|
|
1090
|
+
} else {
|
|
1091
|
+
this.style.setProperty('--vaadin-overlay-viewport-bottom', '0');
|
|
1954
1092
|
}
|
|
1955
1093
|
}
|
|
1956
|
-
}
|
|
1957
1094
|
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1095
|
+
/** @private */
|
|
1096
|
+
_addGlobalListeners() {
|
|
1097
|
+
document.addEventListener('mousedown', this._boundMouseDownListener);
|
|
1098
|
+
document.addEventListener('mouseup', this._boundMouseUpListener);
|
|
1099
|
+
// Firefox leaks click to document on contextmenu even if prevented
|
|
1100
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=990614
|
|
1101
|
+
document.documentElement.addEventListener('click', this._boundOutsideClickListener, true);
|
|
1962
1102
|
}
|
|
1963
1103
|
|
|
1964
|
-
|
|
1104
|
+
/** @private */
|
|
1105
|
+
_removeGlobalListeners() {
|
|
1106
|
+
document.removeEventListener('mousedown', this._boundMouseDownListener);
|
|
1107
|
+
document.removeEventListener('mouseup', this._boundMouseUpListener);
|
|
1108
|
+
document.documentElement.removeEventListener('click', this._boundOutsideClickListener, true);
|
|
1109
|
+
}
|
|
1965
1110
|
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1111
|
+
/** @private */
|
|
1112
|
+
_rendererOrDataChanged(renderer, owner, model, opened) {
|
|
1113
|
+
const ownerOrModelChanged = this._oldOwner !== owner || this._oldModel !== model;
|
|
1114
|
+
this._oldModel = model;
|
|
1115
|
+
this._oldOwner = owner;
|
|
1116
|
+
|
|
1117
|
+
const rendererChanged = this._oldRenderer !== renderer;
|
|
1118
|
+
this._oldRenderer = renderer;
|
|
1119
|
+
|
|
1120
|
+
const openedChanged = this._oldOpened !== opened;
|
|
1121
|
+
this._oldOpened = opened;
|
|
1122
|
+
|
|
1123
|
+
if (rendererChanged) {
|
|
1124
|
+
this.innerHTML = '';
|
|
1125
|
+
// Whenever a Lit-based renderer is used, it assigns a Lit part to the node it was rendered into.
|
|
1126
|
+
// When clearing the rendered content, this part needs to be manually disposed of.
|
|
1127
|
+
// Otherwise, using a Lit-based renderer on the same node will throw an exception or render nothing afterward.
|
|
1128
|
+
delete this._$litPart$;
|
|
1969
1129
|
}
|
|
1970
|
-
});
|
|
1971
1130
|
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
this.$.content = this._originalContentPart;
|
|
1976
|
-
this._originalContentPart = undefined;
|
|
1131
|
+
if (opened && renderer && (rendererChanged || openedChanged || ownerOrModelChanged)) {
|
|
1132
|
+
this.requestContentUpdate();
|
|
1133
|
+
}
|
|
1977
1134
|
}
|
|
1978
1135
|
|
|
1979
|
-
|
|
1136
|
+
/** @private */
|
|
1137
|
+
_modelessChanged(modeless) {
|
|
1138
|
+
if (!modeless) {
|
|
1139
|
+
if (this.opened) {
|
|
1140
|
+
this._addGlobalListeners();
|
|
1141
|
+
this._enterModalState();
|
|
1142
|
+
}
|
|
1143
|
+
} else {
|
|
1144
|
+
this._removeGlobalListeners();
|
|
1145
|
+
this._exitModalState();
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1980
1148
|
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1149
|
+
/** @private */
|
|
1150
|
+
_openedChanged(opened, wasOpened) {
|
|
1151
|
+
if (opened) {
|
|
1152
|
+
this._saveFocus();
|
|
1984
1153
|
|
|
1985
|
-
|
|
1986
|
-
* @param {!HTMLTemplateElement} template
|
|
1987
|
-
* @protected
|
|
1988
|
-
*/
|
|
1989
|
-
_stampOverlayTemplate(template) {
|
|
1990
|
-
this._removeOldContent();
|
|
1991
|
-
|
|
1992
|
-
if (!template._Templatizer) {
|
|
1993
|
-
template._Templatizer = templatize(template, this, {
|
|
1994
|
-
forwardHostProp(prop, value) {
|
|
1995
|
-
if (this._instance) {
|
|
1996
|
-
this._instance.forwardHostProp(prop, value);
|
|
1997
|
-
}
|
|
1998
|
-
},
|
|
1999
|
-
});
|
|
2000
|
-
}
|
|
1154
|
+
this._animatedOpening();
|
|
2001
1155
|
|
|
2002
|
-
|
|
2003
|
-
|
|
1156
|
+
afterNextRender(this, () => {
|
|
1157
|
+
this._trapFocus();
|
|
2004
1158
|
|
|
2005
|
-
|
|
1159
|
+
const evt = new CustomEvent('vaadin-overlay-open', { bubbles: true });
|
|
1160
|
+
this.dispatchEvent(evt);
|
|
1161
|
+
});
|
|
2006
1162
|
|
|
2007
|
-
|
|
2008
|
-
if (!this.$.content.shadowRoot) {
|
|
2009
|
-
this.$.content.attachShadow({ mode: 'open' });
|
|
2010
|
-
}
|
|
1163
|
+
document.addEventListener('keydown', this._boundKeydownListener);
|
|
2011
1164
|
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
)
|
|
1165
|
+
if (!this.modeless) {
|
|
1166
|
+
this._addGlobalListeners();
|
|
1167
|
+
}
|
|
1168
|
+
} else if (wasOpened) {
|
|
1169
|
+
this._resetFocus();
|
|
2016
1170
|
|
|
2017
|
-
|
|
2018
|
-
scopeCssText = scopeCssText.replace(/:host/g, ':host-nomatch');
|
|
1171
|
+
this._animatedClosing();
|
|
2019
1172
|
|
|
2020
|
-
|
|
2021
|
-
// Append a style to the content shadowRoot
|
|
2022
|
-
const style = document.createElement('style');
|
|
2023
|
-
style.textContent = scopeCssText;
|
|
2024
|
-
this.$.content.shadowRoot.appendChild(style);
|
|
2025
|
-
this._contentNodes.unshift(style);
|
|
2026
|
-
}
|
|
1173
|
+
document.removeEventListener('keydown', this._boundKeydownListener);
|
|
2027
1174
|
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
this.content = this;
|
|
1175
|
+
if (!this.modeless) {
|
|
1176
|
+
this._removeGlobalListeners();
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
2033
1179
|
}
|
|
2034
|
-
}
|
|
2035
1180
|
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
this.renderer = undefined;
|
|
1181
|
+
/** @private */
|
|
1182
|
+
_hiddenChanged(hidden) {
|
|
1183
|
+
if (hidden && this.hasAttribute('closing')) {
|
|
1184
|
+
this._flushAnimation('closing');
|
|
1185
|
+
}
|
|
2042
1186
|
}
|
|
2043
|
-
}
|
|
2044
1187
|
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
1188
|
+
/**
|
|
1189
|
+
* @return {boolean}
|
|
1190
|
+
* @private
|
|
1191
|
+
*/
|
|
1192
|
+
_shouldAnimate() {
|
|
1193
|
+
const style = getComputedStyle(this);
|
|
1194
|
+
const name = style.getPropertyValue('animation-name');
|
|
1195
|
+
const hidden = style.getPropertyValue('display') === 'none';
|
|
1196
|
+
return !hidden && name && name !== 'none';
|
|
2051
1197
|
}
|
|
2052
1198
|
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
this
|
|
2069
|
-
|
|
2070
|
-
// When clearing the rendered content, this part needs to be manually disposed of.
|
|
2071
|
-
// Otherwise, using a Lit-based renderer on the same node will throw an exception or render nothing afterward.
|
|
2072
|
-
delete this.content._$litPart$;
|
|
1199
|
+
/**
|
|
1200
|
+
* @param {string} type
|
|
1201
|
+
* @param {Function} callback
|
|
1202
|
+
* @private
|
|
1203
|
+
*/
|
|
1204
|
+
_enqueueAnimation(type, callback) {
|
|
1205
|
+
const handler = `__${type}Handler`;
|
|
1206
|
+
const listener = (event) => {
|
|
1207
|
+
if (event && event.target !== this) {
|
|
1208
|
+
return;
|
|
1209
|
+
}
|
|
1210
|
+
callback();
|
|
1211
|
+
this.removeEventListener('animationend', listener);
|
|
1212
|
+
delete this[handler];
|
|
1213
|
+
};
|
|
1214
|
+
this[handler] = listener;
|
|
1215
|
+
this.addEventListener('animationend', listener);
|
|
2073
1216
|
}
|
|
2074
1217
|
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
1218
|
+
/**
|
|
1219
|
+
* @param {string} type
|
|
1220
|
+
* @protected
|
|
1221
|
+
*/
|
|
1222
|
+
_flushAnimation(type) {
|
|
1223
|
+
const handler = `__${type}Handler`;
|
|
1224
|
+
if (typeof this[handler] === 'function') {
|
|
1225
|
+
this[handler]();
|
|
2080
1226
|
}
|
|
2081
1227
|
}
|
|
2082
|
-
}
|
|
2083
1228
|
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
}
|
|
2095
|
-
return active;
|
|
2096
|
-
}
|
|
1229
|
+
/** @private */
|
|
1230
|
+
_animatedOpening() {
|
|
1231
|
+
if (this.parentNode === document.body && this.hasAttribute('closing')) {
|
|
1232
|
+
this._flushAnimation('closing');
|
|
1233
|
+
}
|
|
1234
|
+
this._attachOverlay();
|
|
1235
|
+
if (!this.modeless) {
|
|
1236
|
+
this._enterModalState();
|
|
1237
|
+
}
|
|
1238
|
+
this.setAttribute('opening', '');
|
|
2097
1239
|
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
return true;
|
|
1240
|
+
if (this._shouldAnimate()) {
|
|
1241
|
+
this._enqueueAnimation('opening', () => {
|
|
1242
|
+
this._finishOpening();
|
|
1243
|
+
});
|
|
1244
|
+
} else {
|
|
1245
|
+
this._finishOpening();
|
|
1246
|
+
}
|
|
2106
1247
|
}
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
1248
|
+
|
|
1249
|
+
/** @private */
|
|
1250
|
+
_attachOverlay() {
|
|
1251
|
+
this._placeholder = document.createComment('vaadin-overlay-placeholder');
|
|
1252
|
+
this.parentNode.insertBefore(this._placeholder, this);
|
|
1253
|
+
document.body.appendChild(this);
|
|
1254
|
+
this.bringToFront();
|
|
2112
1255
|
}
|
|
2113
|
-
return n === this;
|
|
2114
|
-
}
|
|
2115
1256
|
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
let zIndex = '';
|
|
2121
|
-
const frontmost = Overlay.__attachedInstances.filter((o) => o !== this).pop();
|
|
2122
|
-
if (frontmost) {
|
|
2123
|
-
const frontmostZIndex = frontmost.__zIndex;
|
|
2124
|
-
zIndex = frontmostZIndex + 1;
|
|
2125
|
-
}
|
|
2126
|
-
this.style.zIndex = zIndex;
|
|
2127
|
-
this.__zIndex = zIndex || parseFloat(getComputedStyle(this).zIndex);
|
|
2128
|
-
}
|
|
2129
|
-
}
|
|
1257
|
+
/** @private */
|
|
1258
|
+
_finishOpening() {
|
|
1259
|
+
this.removeAttribute('opening');
|
|
1260
|
+
}
|
|
2130
1261
|
|
|
2131
|
-
|
|
1262
|
+
/** @private */
|
|
1263
|
+
_finishClosing() {
|
|
1264
|
+
this._detachOverlay();
|
|
1265
|
+
this.$.overlay.style.removeProperty('pointer-events');
|
|
1266
|
+
this.removeAttribute('closing');
|
|
1267
|
+
this.dispatchEvent(new CustomEvent('vaadin-overlay-closed'));
|
|
1268
|
+
}
|
|
2132
1269
|
|
|
2133
|
-
/**
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
1270
|
+
/** @private */
|
|
1271
|
+
_animatedClosing() {
|
|
1272
|
+
if (this.hasAttribute('opening')) {
|
|
1273
|
+
this._flushAnimation('opening');
|
|
1274
|
+
}
|
|
1275
|
+
if (this._placeholder) {
|
|
1276
|
+
this._exitModalState();
|
|
1277
|
+
this.setAttribute('closing', '');
|
|
1278
|
+
this.dispatchEvent(new CustomEvent('vaadin-overlay-closing'));
|
|
1279
|
+
|
|
1280
|
+
if (this._shouldAnimate()) {
|
|
1281
|
+
this._enqueueAnimation('closing', () => {
|
|
1282
|
+
this._finishClosing();
|
|
1283
|
+
});
|
|
1284
|
+
} else {
|
|
1285
|
+
this._finishClosing();
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
2138
1289
|
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
1290
|
+
/** @private */
|
|
1291
|
+
_detachOverlay() {
|
|
1292
|
+
this._placeholder.parentNode.insertBefore(this, this._placeholder);
|
|
1293
|
+
this._placeholder.parentNode.removeChild(this._placeholder);
|
|
1294
|
+
}
|
|
2144
1295
|
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
1296
|
+
/** @private */
|
|
1297
|
+
_mouseDownListener(event) {
|
|
1298
|
+
this._mouseDownInside = event.composedPath().indexOf(this.$.overlay) >= 0;
|
|
1299
|
+
}
|
|
2148
1300
|
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
1301
|
+
/** @private */
|
|
1302
|
+
_mouseUpListener(event) {
|
|
1303
|
+
this._mouseUpInside = event.composedPath().indexOf(this.$.overlay) >= 0;
|
|
1304
|
+
}
|
|
2152
1305
|
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
1306
|
+
/**
|
|
1307
|
+
* Whether to close the overlay on outside click or not.
|
|
1308
|
+
* Override this method to customize the closing logic.
|
|
1309
|
+
*
|
|
1310
|
+
* @param {Event} _event
|
|
1311
|
+
* @return {boolean}
|
|
1312
|
+
* @protected
|
|
1313
|
+
*/
|
|
1314
|
+
_shouldCloseOnOutsideClick(_event) {
|
|
1315
|
+
return this._last;
|
|
2157
1316
|
}
|
|
2158
|
-
}
|
|
2159
1317
|
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
1318
|
+
/**
|
|
1319
|
+
* Outside click listener used in capture phase to close the overlay before
|
|
1320
|
+
* propagating the event to the listener on the element that triggered it.
|
|
1321
|
+
* Otherwise, calling `open()` would result in closing and re-opening.
|
|
1322
|
+
*
|
|
1323
|
+
* @private
|
|
1324
|
+
*/
|
|
1325
|
+
_outsideClickListener(event) {
|
|
1326
|
+
if (event.composedPath().includes(this.$.overlay) || this._mouseDownInside || this._mouseUpInside) {
|
|
1327
|
+
this._mouseDownInside = false;
|
|
1328
|
+
this._mouseUpInside = false;
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
2163
1331
|
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
}
|
|
2168
|
-
}
|
|
2169
|
-
`;
|
|
1332
|
+
if (!this._shouldCloseOnOutsideClick(event)) {
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
2170
1335
|
|
|
2171
|
-
|
|
1336
|
+
const evt = new CustomEvent('vaadin-overlay-outside-click', {
|
|
1337
|
+
bubbles: true,
|
|
1338
|
+
cancelable: true,
|
|
1339
|
+
detail: { sourceEvent: event },
|
|
1340
|
+
});
|
|
1341
|
+
this.dispatchEvent(evt);
|
|
2172
1342
|
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
@media (max-width: 420px), (max-height: 420px) {
|
|
2177
|
-
:host {
|
|
2178
|
-
top: 0 !important;
|
|
2179
|
-
right: 0 !important;
|
|
2180
|
-
bottom: var(--vaadin-overlay-viewport-bottom, 0) !important;
|
|
2181
|
-
left: 0 !important;
|
|
2182
|
-
align-items: stretch !important;
|
|
2183
|
-
justify-content: flex-end !important;
|
|
1343
|
+
if (this.opened && !evt.defaultPrevented) {
|
|
1344
|
+
this.close(event);
|
|
1345
|
+
}
|
|
2184
1346
|
}
|
|
2185
1347
|
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
1348
|
+
/**
|
|
1349
|
+
* Listener used to close whe overlay on Escape press, if it is the last one.
|
|
1350
|
+
* @private
|
|
1351
|
+
*/
|
|
1352
|
+
_keydownListener(event) {
|
|
1353
|
+
if (!this._last) {
|
|
1354
|
+
return;
|
|
1355
|
+
}
|
|
2192
1356
|
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
box-sizing: border-box;
|
|
2198
|
-
-webkit-overflow-scrolling: touch;
|
|
2199
|
-
overflow: auto;
|
|
2200
|
-
-webkit-mask-image: linear-gradient(transparent, #000 40px, #000 calc(100% - 40px), transparent);
|
|
2201
|
-
mask-image: linear-gradient(transparent, #000 40px, #000 calc(100% - 40px), transparent);
|
|
2202
|
-
}
|
|
1357
|
+
// Only close modeless overlay on Esc press when it contains focus
|
|
1358
|
+
if (this.modeless && !event.composedPath().includes(this.$.overlay)) {
|
|
1359
|
+
return;
|
|
1360
|
+
}
|
|
2203
1361
|
|
|
2204
|
-
|
|
2205
|
-
|
|
1362
|
+
if (event.key === 'Escape') {
|
|
1363
|
+
const evt = new CustomEvent('vaadin-overlay-escape-press', {
|
|
1364
|
+
bubbles: true,
|
|
1365
|
+
cancelable: true,
|
|
1366
|
+
detail: { sourceEvent: event },
|
|
1367
|
+
});
|
|
1368
|
+
this.dispatchEvent(evt);
|
|
1369
|
+
|
|
1370
|
+
if (this.opened && !evt.defaultPrevented) {
|
|
1371
|
+
this.close(event);
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
2206
1374
|
}
|
|
1375
|
+
};
|
|
2207
1376
|
|
|
2208
|
-
|
|
1377
|
+
/**
|
|
1378
|
+
* @license
|
|
1379
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
1380
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1381
|
+
*/
|
|
2209
1382
|
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
1383
|
+
/**
|
|
1384
|
+
* Returns an array of ancestor root nodes for the given node.
|
|
1385
|
+
*
|
|
1386
|
+
* A root node is either a document node or a document fragment node (Shadow Root).
|
|
1387
|
+
* The array is collected by a bottom-up DOM traversing that starts with the given node
|
|
1388
|
+
* and involves both the light DOM and ancestor shadow DOM trees.
|
|
1389
|
+
*
|
|
1390
|
+
* @param {Node} node
|
|
1391
|
+
* @return {Node[]}
|
|
1392
|
+
*/
|
|
1393
|
+
function getAncestorRootNodes(node) {
|
|
1394
|
+
const result = [];
|
|
2213
1395
|
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
1396
|
+
while (node) {
|
|
1397
|
+
if (node.nodeType === Node.DOCUMENT_NODE) {
|
|
1398
|
+
result.push(node);
|
|
1399
|
+
break;
|
|
2217
1400
|
}
|
|
2218
1401
|
|
|
2219
|
-
|
|
2220
|
-
|
|
1402
|
+
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
1403
|
+
result.push(node);
|
|
1404
|
+
node = node.host;
|
|
1405
|
+
continue;
|
|
2221
1406
|
}
|
|
2222
|
-
}
|
|
2223
1407
|
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
1408
|
+
if (node.assignedSlot) {
|
|
1409
|
+
node = node.assignedSlot;
|
|
1410
|
+
continue;
|
|
2227
1411
|
}
|
|
2228
|
-
}
|
|
2229
1412
|
|
|
2230
|
-
|
|
2231
|
-
100% {
|
|
2232
|
-
transform: translateY(150%);
|
|
2233
|
-
}
|
|
1413
|
+
node = node.parentNode;
|
|
2234
1414
|
}
|
|
2235
|
-
`;
|
|
2236
1415
|
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
registerStyles('', menuOverlay, { moduleId: 'lumo-menu-overlay' });
|
|
1416
|
+
return result;
|
|
1417
|
+
}
|
|
2240
1418
|
|
|
2241
1419
|
/**
|
|
2242
1420
|
* @license
|
|
2243
|
-
* Copyright (c) 2017 -
|
|
1421
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
2244
1422
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
2245
1423
|
*/
|
|
2246
1424
|
|
|
@@ -2430,10 +1608,6 @@ const PositionMixin = (superClass) =>
|
|
|
2430
1608
|
}
|
|
2431
1609
|
}
|
|
2432
1610
|
|
|
2433
|
-
get __isRTL() {
|
|
2434
|
-
return this.getAttribute('dir') === 'rtl';
|
|
2435
|
-
}
|
|
2436
|
-
|
|
2437
1611
|
__positionSettingsChanged() {
|
|
2438
1612
|
this._updatePosition();
|
|
2439
1613
|
}
|
|
@@ -2457,9 +1631,9 @@ const PositionMixin = (superClass) =>
|
|
|
2457
1631
|
const shouldAlignStartVertically = this.__shouldAlignStartVertically(targetRect);
|
|
2458
1632
|
this.style.justifyContent = shouldAlignStartVertically ? 'flex-start' : 'flex-end';
|
|
2459
1633
|
|
|
2460
|
-
const
|
|
2461
|
-
const
|
|
2462
|
-
|
|
1634
|
+
const isRTL = this.__isRTL;
|
|
1635
|
+
const shouldAlignStartHorizontally = this.__shouldAlignStartHorizontally(targetRect, isRTL);
|
|
1636
|
+
const flexStart = (!isRTL && shouldAlignStartHorizontally) || (isRTL && !shouldAlignStartHorizontally);
|
|
2463
1637
|
this.style.alignItems = flexStart ? 'flex-start' : 'flex-end';
|
|
2464
1638
|
|
|
2465
1639
|
// Get the overlay rect after possible overlay alignment changes
|
|
@@ -2618,7 +1792,73 @@ const PositionMixin = (superClass) =>
|
|
|
2618
1792
|
|
|
2619
1793
|
/**
|
|
2620
1794
|
* @license
|
|
2621
|
-
* Copyright (c)
|
|
1795
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
1796
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1797
|
+
*/
|
|
1798
|
+
|
|
1799
|
+
const overlayStyles = i`
|
|
1800
|
+
:host {
|
|
1801
|
+
z-index: 200;
|
|
1802
|
+
position: fixed;
|
|
1803
|
+
|
|
1804
|
+
/* Despite of what the names say, <vaadin-overlay> is just a container
|
|
1805
|
+
for position/sizing/alignment. The actual overlay is the overlay part. */
|
|
1806
|
+
|
|
1807
|
+
/* Default position constraints: the entire viewport. Note: themes can
|
|
1808
|
+
override this to introduce gaps between the overlay and the viewport. */
|
|
1809
|
+
inset: 0;
|
|
1810
|
+
bottom: var(--vaadin-overlay-viewport-bottom);
|
|
1811
|
+
|
|
1812
|
+
/* Use flexbox alignment for the overlay part. */
|
|
1813
|
+
display: flex;
|
|
1814
|
+
flex-direction: column; /* makes dropdowns sizing easier */
|
|
1815
|
+
/* Align to center by default. */
|
|
1816
|
+
align-items: center;
|
|
1817
|
+
justify-content: center;
|
|
1818
|
+
|
|
1819
|
+
/* Allow centering when max-width/max-height applies. */
|
|
1820
|
+
margin: auto;
|
|
1821
|
+
|
|
1822
|
+
/* The host is not clickable, only the overlay part is. */
|
|
1823
|
+
pointer-events: none;
|
|
1824
|
+
|
|
1825
|
+
/* Remove tap highlight on touch devices. */
|
|
1826
|
+
-webkit-tap-highlight-color: transparent;
|
|
1827
|
+
|
|
1828
|
+
/* CSS API for host */
|
|
1829
|
+
--vaadin-overlay-viewport-bottom: 0;
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
:host([hidden]),
|
|
1833
|
+
:host(:not([opened]):not([closing])) {
|
|
1834
|
+
display: none !important;
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
[part='overlay'] {
|
|
1838
|
+
-webkit-overflow-scrolling: touch;
|
|
1839
|
+
overflow: auto;
|
|
1840
|
+
pointer-events: auto;
|
|
1841
|
+
|
|
1842
|
+
/* Prevent overflowing the host */
|
|
1843
|
+
max-width: 100%;
|
|
1844
|
+
box-sizing: border-box;
|
|
1845
|
+
|
|
1846
|
+
-webkit-tap-highlight-color: initial; /* reenable tap highlight inside */
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
[part='backdrop'] {
|
|
1850
|
+
z-index: -1;
|
|
1851
|
+
content: '';
|
|
1852
|
+
background: rgba(0, 0, 0, 0.5);
|
|
1853
|
+
position: fixed;
|
|
1854
|
+
inset: 0;
|
|
1855
|
+
pointer-events: auto;
|
|
1856
|
+
}
|
|
1857
|
+
`;
|
|
1858
|
+
|
|
1859
|
+
/**
|
|
1860
|
+
* @license
|
|
1861
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
2622
1862
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
2623
1863
|
*/
|
|
2624
1864
|
|
|
@@ -2655,4 +1895,4 @@ class VirtualKeyboardController {
|
|
|
2655
1895
|
}
|
|
2656
1896
|
}
|
|
2657
1897
|
|
|
2658
|
-
export {
|
|
1898
|
+
export { OverlayMixin as O, PositionMixin as P, VirtualKeyboardController as V, afterNextRender as a, hideOthers as h, overlayStyles as o };
|