@everymatrix/general-input 1.28.7 → 1.28.8
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_10.cjs.entry.js +12517 -13047
- package/dist/components/active-mixin.js +6 -6
- package/dist/components/checkbox-group-input2.js +307 -260
- package/dist/components/date-input2.js +2206 -3449
- package/dist/components/field-mixin.js +2512 -2226
- package/dist/components/input-field-shared-styles.js +211 -308
- package/dist/components/password-input2.js +72 -119
- package/dist/components/pattern-mixin.js +85 -0
- package/dist/components/vaadin-button.js +73 -102
- package/dist/components/vaadin-combo-box.js +808 -991
- package/dist/components/virtual-keyboard-controller.js +1768 -1111
- package/dist/esm/checkbox-group-input_10.entry.js +12517 -13047
- package/dist/general-input/general-input.esm.js +1 -1
- package/dist/general-input/p-6958a2a8.entry.js +3581 -0
- package/package.json +1 -1
- package/dist/general-input/p-765941e7.entry.js +0 -3646
- /package/dist/types/Users/{adrian.pripon/Documents/Work → sebastian.strulea/Documents/work}/widgets-stencil/packages/general-input/.stencil/packages/general-input/stencil.config.d.ts +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { i, r as registerStyles,
|
|
1
|
+
import { i, r as registerStyles, d as dedupingMixin, B as PropertyEffects, G as strictTemplatePolicy, w as wrap, H as legacyWarnings, J as getFocusableElements, b as isElementFocused, T as ThemableMixin, A as DirMixin, C as ControllerMixin, P as PolymerElement, h as html, m as FlattenedNodesObserver, M as getAncestorRootNodes } from './field-mixin.js';
|
|
2
2
|
import { b as isIOS } from './input-field-shared-styles.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @license
|
|
6
|
-
* Copyright (c) 2017 -
|
|
6
|
+
* Copyright (c) 2017 - 2022 Vaadin Ltd.
|
|
7
7
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
8
8
|
*/
|
|
9
9
|
|
|
@@ -74,113 +74,7 @@ const overlay = i`
|
|
|
74
74
|
|
|
75
75
|
registerStyles('', overlay, { moduleId: 'lumo-overlay' });
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
* @license
|
|
79
|
-
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
80
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
81
|
-
*/
|
|
82
|
-
|
|
83
|
-
const menuOverlayCore = i`
|
|
84
|
-
:host([opening]),
|
|
85
|
-
:host([closing]) {
|
|
86
|
-
animation: 0.14s lumo-overlay-dummy-animation;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
[part='overlay'] {
|
|
90
|
-
will-change: opacity, transform;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
:host([opening]) [part='overlay'] {
|
|
94
|
-
animation: 0.1s lumo-menu-overlay-enter ease-out both;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
@keyframes lumo-menu-overlay-enter {
|
|
98
|
-
0% {
|
|
99
|
-
opacity: 0;
|
|
100
|
-
transform: translateY(-4px);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
:host([closing]) [part='overlay'] {
|
|
105
|
-
animation: 0.1s lumo-menu-overlay-exit both;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
@keyframes lumo-menu-overlay-exit {
|
|
109
|
-
100% {
|
|
110
|
-
opacity: 0;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
`;
|
|
114
|
-
|
|
115
|
-
registerStyles('', menuOverlayCore, { moduleId: 'lumo-menu-overlay-core' });
|
|
116
|
-
|
|
117
|
-
const menuOverlayExt = i`
|
|
118
|
-
/* Small viewport (bottom sheet) styles */
|
|
119
|
-
/* Use direct media queries instead of the state attributes ([phone] and [fullscreen]) provided by the elements */
|
|
120
|
-
@media (max-width: 420px), (max-height: 420px) {
|
|
121
|
-
:host {
|
|
122
|
-
top: 0 !important;
|
|
123
|
-
right: 0 !important;
|
|
124
|
-
bottom: var(--vaadin-overlay-viewport-bottom, 0) !important;
|
|
125
|
-
left: 0 !important;
|
|
126
|
-
align-items: stretch !important;
|
|
127
|
-
justify-content: flex-end !important;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
[part='overlay'] {
|
|
131
|
-
max-height: 50vh;
|
|
132
|
-
width: 100vw;
|
|
133
|
-
border-radius: 0;
|
|
134
|
-
box-shadow: var(--lumo-box-shadow-xl);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/* The content part scrolls instead of the overlay part, because of the gradient fade-out */
|
|
138
|
-
[part='content'] {
|
|
139
|
-
padding: 30px var(--lumo-space-m);
|
|
140
|
-
max-height: inherit;
|
|
141
|
-
box-sizing: border-box;
|
|
142
|
-
-webkit-overflow-scrolling: touch;
|
|
143
|
-
overflow: auto;
|
|
144
|
-
-webkit-mask-image: linear-gradient(transparent, #000 40px, #000 calc(100% - 40px), transparent);
|
|
145
|
-
mask-image: linear-gradient(transparent, #000 40px, #000 calc(100% - 40px), transparent);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
[part='backdrop'] {
|
|
149
|
-
display: block;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/* Animations */
|
|
153
|
-
|
|
154
|
-
:host([opening]) [part='overlay'] {
|
|
155
|
-
animation: 0.2s lumo-mobile-menu-overlay-enter cubic-bezier(0.215, 0.61, 0.355, 1) both;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
:host([closing]),
|
|
159
|
-
:host([closing]) [part='backdrop'] {
|
|
160
|
-
animation-delay: 0.14s;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
:host([closing]) [part='overlay'] {
|
|
164
|
-
animation: 0.14s 0.14s lumo-mobile-menu-overlay-exit cubic-bezier(0.55, 0.055, 0.675, 0.19) both;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
@keyframes lumo-mobile-menu-overlay-enter {
|
|
169
|
-
0% {
|
|
170
|
-
transform: translateY(150%);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
@keyframes lumo-mobile-menu-overlay-exit {
|
|
175
|
-
100% {
|
|
176
|
-
transform: translateY(150%);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
`;
|
|
180
|
-
|
|
181
|
-
const menuOverlay = [overlay, menuOverlayCore, menuOverlayExt];
|
|
182
|
-
|
|
183
|
-
registerStyles('', menuOverlay, { moduleId: 'lumo-menu-overlay' });
|
|
77
|
+
registerStyles('vaadin-overlay', overlay, { moduleId: 'lumo-vaadin-overlay' });
|
|
184
78
|
|
|
185
79
|
/**
|
|
186
80
|
@license
|
|
@@ -256,326 +150,851 @@ function afterNextRender(context, callback, args) {
|
|
|
256
150
|
}
|
|
257
151
|
|
|
258
152
|
/**
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
* This module includes JS code copied from the `aria-hidden` package:
|
|
268
|
-
* https://github.com/theKashey/aria-hidden/blob/master/src/index.ts
|
|
269
|
-
*/
|
|
270
|
-
|
|
271
|
-
/** @type {WeakMap<Element, number>} */
|
|
272
|
-
let counterMap = new WeakMap();
|
|
273
|
-
|
|
274
|
-
/** @type {WeakMap<Element, boolean>} */
|
|
275
|
-
let uncontrolledNodes = new WeakMap();
|
|
276
|
-
|
|
277
|
-
/** @type {Record<string, WeakMap<Element, number>>} */
|
|
278
|
-
let markerMap = {};
|
|
153
|
+
@license
|
|
154
|
+
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
155
|
+
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
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
|
+
*/
|
|
279
161
|
|
|
280
|
-
|
|
281
|
-
|
|
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
|
+
}
|
|
282
181
|
|
|
283
182
|
/**
|
|
284
|
-
*
|
|
285
|
-
*
|
|
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.
|
|
286
223
|
*/
|
|
287
|
-
const
|
|
224
|
+
const MutableData = dedupingMixin(superClass => {
|
|
288
225
|
|
|
289
|
-
/**
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
+
}
|
|
295
252
|
|
|
296
|
-
/**
|
|
297
|
-
* @param {HTMLElement} parent
|
|
298
|
-
* @param {Element[]} targets
|
|
299
|
-
* @return {Element[]}
|
|
300
|
-
*/
|
|
301
|
-
const correctTargets = (parent, targets) => {
|
|
302
|
-
if (!isElement(parent)) {
|
|
303
|
-
logError(parent, 'is not a valid element');
|
|
304
|
-
return [];
|
|
305
253
|
}
|
|
306
254
|
|
|
307
|
-
return
|
|
308
|
-
.map((target) => {
|
|
309
|
-
if (!isElement(target)) {
|
|
310
|
-
logError(target, 'is not a valid element');
|
|
311
|
-
return null;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
let node = target;
|
|
315
|
-
while (node && node !== parent) {
|
|
316
|
-
if (parent.contains(node)) {
|
|
317
|
-
return target;
|
|
318
|
-
}
|
|
319
|
-
node = node.getRootNode().host;
|
|
320
|
-
}
|
|
255
|
+
return MutableData;
|
|
321
256
|
|
|
322
|
-
|
|
323
|
-
return null;
|
|
324
|
-
})
|
|
325
|
-
.filter((x) => Boolean(x));
|
|
326
|
-
};
|
|
257
|
+
});
|
|
327
258
|
|
|
328
259
|
/**
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
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
|
|
335
298
|
*/
|
|
336
|
-
const
|
|
337
|
-
const targets = correctTargets(parentNode, Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
|
|
338
|
-
|
|
339
|
-
if (!markerMap[markerName]) {
|
|
340
|
-
markerMap[markerName] = new WeakMap();
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const markerCounter = markerMap[markerName];
|
|
344
|
-
|
|
345
|
-
/** @type {Element[]} */
|
|
346
|
-
const hiddenNodes = [];
|
|
347
|
-
|
|
348
|
-
/** @type {Set<Node>} */
|
|
349
|
-
const elementsToKeep = new Set();
|
|
350
|
-
|
|
351
|
-
/** @type {Set<Node>} */
|
|
352
|
-
const elementsToStop = new Set(targets);
|
|
299
|
+
const OptionalMutableData = dedupingMixin(superClass => {
|
|
353
300
|
|
|
354
301
|
/**
|
|
355
|
-
* @
|
|
302
|
+
* @mixinClass
|
|
303
|
+
* @polymer
|
|
304
|
+
* @implements {Polymer_OptionalMutableData}
|
|
356
305
|
*/
|
|
357
|
-
|
|
358
|
-
if (!el || elementsToKeep.has(el)) {
|
|
359
|
-
return;
|
|
360
|
-
}
|
|
306
|
+
class OptionalMutableData extends superClass {
|
|
361
307
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
308
|
+
/** @nocollapse */
|
|
309
|
+
static get properties() {
|
|
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
|
+
};
|
|
367
318
|
}
|
|
368
319
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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);
|
|
380
340
|
}
|
|
341
|
+
}
|
|
381
342
|
|
|
382
|
-
|
|
383
|
-
const children = root ? [...parent.children, ...root.children] : [...parent.children];
|
|
384
|
-
children.forEach((node) => {
|
|
385
|
-
// Skip elements that don't need to be hidden
|
|
386
|
-
if (['template', 'script', 'style'].includes(node.localName)) {
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (elementsToKeep.has(node)) {
|
|
391
|
-
deep(node);
|
|
392
|
-
} else {
|
|
393
|
-
const attr = node.getAttribute(controlAttribute);
|
|
394
|
-
const alreadyHidden = attr !== null && attr !== 'false';
|
|
395
|
-
const counterValue = (counterMap.get(node) || 0) + 1;
|
|
396
|
-
const markerValue = (markerCounter.get(node) || 0) + 1;
|
|
397
|
-
|
|
398
|
-
counterMap.set(node, counterValue);
|
|
399
|
-
markerCounter.set(node, markerValue);
|
|
400
|
-
hiddenNodes.push(node);
|
|
401
|
-
|
|
402
|
-
if (counterValue === 1 && alreadyHidden) {
|
|
403
|
-
uncontrolledNodes.set(node, true);
|
|
404
|
-
}
|
|
343
|
+
return OptionalMutableData;
|
|
405
344
|
|
|
406
|
-
|
|
407
|
-
node.setAttribute(markerName, 'true');
|
|
408
|
-
}
|
|
345
|
+
});
|
|
409
346
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
});
|
|
415
|
-
};
|
|
347
|
+
// Export for use by legacy behavior
|
|
348
|
+
MutableData._mutablePropertyChange = mutablePropertyChange;
|
|
416
349
|
|
|
417
|
-
|
|
350
|
+
/**
|
|
351
|
+
@license
|
|
352
|
+
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
353
|
+
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
354
|
+
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
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
|
+
*/
|
|
418
359
|
|
|
419
|
-
|
|
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;
|
|
420
365
|
|
|
421
|
-
|
|
366
|
+
/**
|
|
367
|
+
* @constructor
|
|
368
|
+
* @extends {HTMLTemplateElement}
|
|
369
|
+
* @private
|
|
370
|
+
*/
|
|
371
|
+
function HTMLTemplateElementExtension() { return newInstance; }
|
|
372
|
+
HTMLTemplateElementExtension.prototype = Object.create(HTMLTemplateElement.prototype, {
|
|
373
|
+
constructor: {
|
|
374
|
+
value: HTMLTemplateElementExtension,
|
|
375
|
+
writable: true
|
|
376
|
+
}
|
|
377
|
+
});
|
|
422
378
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
379
|
+
/**
|
|
380
|
+
* @constructor
|
|
381
|
+
* @implements {Polymer_PropertyEffects}
|
|
382
|
+
* @extends {HTMLTemplateElementExtension}
|
|
383
|
+
* @private
|
|
384
|
+
*/
|
|
385
|
+
const DataTemplate = PropertyEffects(HTMLTemplateElementExtension);
|
|
427
386
|
|
|
428
|
-
|
|
429
|
-
|
|
387
|
+
/**
|
|
388
|
+
* @constructor
|
|
389
|
+
* @implements {Polymer_MutableData}
|
|
390
|
+
* @extends {DataTemplate}
|
|
391
|
+
* @private
|
|
392
|
+
*/
|
|
393
|
+
const MutableDataTemplate = MutableData(DataTemplate);
|
|
394
|
+
|
|
395
|
+
// Applies a DataTemplate subclass to a <template> instance
|
|
396
|
+
function upgradeTemplate(template, constructor) {
|
|
397
|
+
newInstance = template;
|
|
398
|
+
Object.setPrototypeOf(template, constructor.prototype);
|
|
399
|
+
new constructor();
|
|
400
|
+
newInstance = null;
|
|
401
|
+
}
|
|
430
402
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
403
|
+
/**
|
|
404
|
+
* Base class for TemplateInstance.
|
|
405
|
+
* @constructor
|
|
406
|
+
* @extends {HTMLElement}
|
|
407
|
+
* @implements {Polymer_PropertyEffects}
|
|
408
|
+
* @private
|
|
409
|
+
*/
|
|
410
|
+
const templateInstanceBase = PropertyEffects(class {});
|
|
411
|
+
|
|
412
|
+
function showHideChildren(hide, children) {
|
|
413
|
+
for (let i=0; i<children.length; i++) {
|
|
414
|
+
let n = children[i];
|
|
415
|
+
// Ignore non-changes
|
|
416
|
+
if (Boolean(hide) != Boolean(n.__hideTemplateChildren__)) {
|
|
417
|
+
// clear and restore text
|
|
418
|
+
if (n.nodeType === Node.TEXT_NODE) {
|
|
419
|
+
if (hide) {
|
|
420
|
+
n.__polymerTextContent__ = n.textContent;
|
|
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);
|
|
434
430
|
} else {
|
|
435
|
-
|
|
431
|
+
const replace = n.__polymerReplaced__;
|
|
432
|
+
if (replace) {
|
|
433
|
+
wrap(wrap(replace).parentNode).replaceChild(n, replace);
|
|
434
|
+
}
|
|
436
435
|
}
|
|
437
436
|
}
|
|
438
|
-
|
|
439
|
-
if (
|
|
440
|
-
|
|
437
|
+
// hide and show nodes
|
|
438
|
+
else if (n.style) {
|
|
439
|
+
if (hide) {
|
|
440
|
+
n.__polymerDisplay__ = n.style.display;
|
|
441
|
+
n.style.display = 'none';
|
|
442
|
+
} else {
|
|
443
|
+
n.style.display = n.__polymerDisplay__;
|
|
444
|
+
}
|
|
441
445
|
}
|
|
442
|
-
});
|
|
443
|
-
|
|
444
|
-
lockCount -= 1;
|
|
445
|
-
|
|
446
|
-
if (!lockCount) {
|
|
447
|
-
// clear
|
|
448
|
-
counterMap = new WeakMap();
|
|
449
|
-
counterMap = new WeakMap();
|
|
450
|
-
uncontrolledNodes = new WeakMap();
|
|
451
|
-
markerMap = {};
|
|
452
446
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
* Marks everything except given node(or nodes) as aria-hidden
|
|
458
|
-
* @param {Element | Element[]} originalTarget - elements to keep on the page
|
|
459
|
-
* @param {HTMLElement} [parentNode] - top element, defaults to document.body
|
|
460
|
-
* @param {String} [markerName] - a special attribute to mark every node
|
|
461
|
-
* @return {Function} undo command
|
|
462
|
-
*/
|
|
463
|
-
const hideOthers = (originalTarget, parentNode = document.body, markerName = 'data-aria-hidden') => {
|
|
464
|
-
const targets = Array.from(Array.isArray(originalTarget) ? originalTarget : [originalTarget]);
|
|
465
|
-
|
|
466
|
-
if (parentNode) {
|
|
467
|
-
// We should not hide ariaLive elements - https://github.com/theKashey/aria-hidden/issues/10
|
|
468
|
-
targets.push(...Array.from(parentNode.querySelectorAll('[aria-live]')));
|
|
447
|
+
n.__hideTemplateChildren__ = hide;
|
|
448
|
+
if (n._showHideChildren) {
|
|
449
|
+
n._showHideChildren(hide);
|
|
450
|
+
}
|
|
469
451
|
}
|
|
470
|
-
|
|
471
|
-
return applyAttributeToOthers(targets, parentNode, markerName, 'aria-hidden');
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
/**
|
|
475
|
-
* @license
|
|
476
|
-
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
477
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
478
|
-
*/
|
|
452
|
+
}
|
|
479
453
|
|
|
480
454
|
/**
|
|
481
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
*
|
|
485
|
-
* consumer web component. This is done in to ensure the controller only does one thing.
|
|
455
|
+
* @polymer
|
|
456
|
+
* @customElement
|
|
457
|
+
* @appliesMixin PropertyEffects
|
|
458
|
+
* @unrestricted
|
|
486
459
|
*/
|
|
487
|
-
class
|
|
460
|
+
class TemplateInstanceBase extends templateInstanceBase {
|
|
461
|
+
constructor(props) {
|
|
462
|
+
super();
|
|
463
|
+
this._configureProperties(props);
|
|
464
|
+
/** @type {!StampedTemplate} */
|
|
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
|
+
}
|
|
485
|
+
}
|
|
488
486
|
/**
|
|
489
|
-
*
|
|
487
|
+
* Configure the given `props` by calling `_setPendingProperty`. Also
|
|
488
|
+
* sets any properties stored in `__hostProps`.
|
|
489
|
+
* @private
|
|
490
|
+
* @param {Object} props Object of property name-value pairs to set.
|
|
491
|
+
* @return {void}
|
|
490
492
|
*/
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
* @type {Function}
|
|
504
|
-
*/
|
|
505
|
-
this.callback = typeof callback === 'function' ? callback : () => host;
|
|
493
|
+
_configureProperties(props) {
|
|
494
|
+
let options = this.__templatizeOptions;
|
|
495
|
+
if (options.forwardHostProp) {
|
|
496
|
+
for (let hprop in this.__hostProps) {
|
|
497
|
+
this._setPendingProperty(hprop, this.__dataHost['_host_' + hprop]);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
// Any instance props passed in the constructor will overwrite host props;
|
|
501
|
+
// normally this would be a user error but we don't specifically filter them
|
|
502
|
+
for (let iprop in props) {
|
|
503
|
+
this._setPendingProperty(iprop, props[iprop]);
|
|
504
|
+
}
|
|
506
505
|
}
|
|
507
|
-
|
|
508
506
|
/**
|
|
509
|
-
*
|
|
510
|
-
*
|
|
507
|
+
* Forwards a host property to this instance. This method should be
|
|
508
|
+
* called on instances from the `options.forwardHostProp` callback
|
|
509
|
+
* to propagate changes of host properties to each instance.
|
|
511
510
|
*
|
|
512
|
-
*
|
|
513
|
-
*
|
|
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}
|
|
514
516
|
*/
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
517
|
+
forwardHostProp(prop, value) {
|
|
518
|
+
if (this._setPendingPropertyOrPath(prop, value, false, true)) {
|
|
519
|
+
this.__dataHost._enqueueClient(this);
|
|
520
|
+
}
|
|
518
521
|
}
|
|
519
522
|
|
|
520
523
|
/**
|
|
521
|
-
*
|
|
522
|
-
*
|
|
524
|
+
* Override point for adding custom or simulated event handling.
|
|
525
|
+
*
|
|
526
|
+
* @override
|
|
527
|
+
* @param {!Node} node Node to add event listener to
|
|
528
|
+
* @param {string} eventName Name of event
|
|
529
|
+
* @param {function(!Event):void} handler Listener function to add
|
|
530
|
+
* @return {void}
|
|
531
|
+
*/
|
|
532
|
+
_addEventListenerToNode(node, eventName, handler) {
|
|
533
|
+
if (this._methodHost && this.__templatizeOptions.parentModel) {
|
|
534
|
+
// If this instance should be considered a parent model, decorate
|
|
535
|
+
// events this template instance as `model`
|
|
536
|
+
this._methodHost._addEventListenerToNode(node, eventName, (e) => {
|
|
537
|
+
e.model = this;
|
|
538
|
+
handler(e);
|
|
539
|
+
});
|
|
540
|
+
} else {
|
|
541
|
+
// Otherwise delegate to the template's host (which could be)
|
|
542
|
+
// another template instance
|
|
543
|
+
let templateHost = this.__dataHost.__dataHost;
|
|
544
|
+
if (templateHost) {
|
|
545
|
+
templateHost._addEventListenerToNode(node, eventName, handler);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Shows or hides the template instance top level child elements. For
|
|
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
|
|
523
572
|
*/
|
|
524
|
-
|
|
525
|
-
if (
|
|
526
|
-
|
|
527
|
-
|
|
573
|
+
_setUnmanagedPropertyToNode(node, prop, value) {
|
|
574
|
+
if (node.__hideTemplateChildren__ &&
|
|
575
|
+
node.nodeType == Node.TEXT_NODE && prop == 'textContent') {
|
|
576
|
+
node.__polymerTextContent__ = value;
|
|
577
|
+
} else {
|
|
578
|
+
super._setUnmanagedPropertyToNode(node, prop, value);
|
|
528
579
|
}
|
|
529
580
|
}
|
|
581
|
+
/**
|
|
582
|
+
* Find the parent model of this template instance. The parent model
|
|
583
|
+
* is either another templatize instance that had option `parentModel: true`,
|
|
584
|
+
* or else the host element.
|
|
585
|
+
*
|
|
586
|
+
* @return {!Polymer_PropertyEffects} The parent model of this instance
|
|
587
|
+
*/
|
|
588
|
+
get parentModel() {
|
|
589
|
+
let model = this.__parentModel;
|
|
590
|
+
if (!model) {
|
|
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;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Stub of HTMLElement's `dispatchEvent`, so that effects that may
|
|
605
|
+
* dispatch events safely no-op.
|
|
606
|
+
*
|
|
607
|
+
* @param {Event} event Event to dispatch
|
|
608
|
+
* @return {boolean} Always true.
|
|
609
|
+
* @override
|
|
610
|
+
*/
|
|
611
|
+
dispatchEvent(event) { // eslint-disable-line no-unused-vars
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
530
614
|
}
|
|
531
615
|
|
|
532
616
|
/**
|
|
533
|
-
* @
|
|
534
|
-
*
|
|
535
|
-
*
|
|
617
|
+
* @constructor
|
|
618
|
+
* @extends {TemplateInstanceBase}
|
|
619
|
+
* @implements {Polymer_MutableData}
|
|
620
|
+
* @private
|
|
536
621
|
*/
|
|
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
|
+
}
|
|
537
636
|
|
|
637
|
+
/* eslint-disable valid-jsdoc */
|
|
538
638
|
/**
|
|
539
|
-
*
|
|
639
|
+
* @suppress {missingProperties} class.prototype is not defined for some reason
|
|
540
640
|
*/
|
|
541
|
-
|
|
641
|
+
function createTemplatizerClass(template, templateInfo, options) {
|
|
542
642
|
/**
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
* the currently focused node in the DOM is saved as a target.
|
|
546
|
-
*
|
|
547
|
-
* @param {Node | null | undefined} focusNode
|
|
643
|
+
* @constructor
|
|
644
|
+
* @extends {TemplateInstanceBase}
|
|
548
645
|
*/
|
|
549
|
-
|
|
550
|
-
|
|
646
|
+
let templatizerBase = options.mutableData ?
|
|
647
|
+
MutableTemplateInstanceBase : TemplateInstanceBase;
|
|
648
|
+
|
|
649
|
+
// Affordance for global mixins onto TemplatizeInstance
|
|
650
|
+
if (templatize.mixin) {
|
|
651
|
+
templatizerBase = templatize.mixin(templatizerBase);
|
|
551
652
|
}
|
|
552
653
|
|
|
553
654
|
/**
|
|
554
|
-
*
|
|
655
|
+
* Anonymous class created by the templatize
|
|
656
|
+
* @constructor
|
|
657
|
+
* @private
|
|
555
658
|
*/
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
659
|
+
let klass = class extends templatizerBase { };
|
|
660
|
+
/** @override */
|
|
661
|
+
klass.prototype.__templatizeOptions = options;
|
|
662
|
+
klass.prototype._bindTemplate(template);
|
|
663
|
+
addNotifyEffects(klass, template, templateInfo, options);
|
|
664
|
+
return klass;
|
|
665
|
+
}
|
|
561
666
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
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
|
+
}
|
|
727
|
+
}
|
|
728
|
+
// Mix any pre-bound data into __data; no need to flush this to
|
|
729
|
+
// instances since they pull from the template at instance-time
|
|
730
|
+
if (target.__dataProto) {
|
|
731
|
+
// Note, generally `__dataProto` could be chained, but it's guaranteed
|
|
732
|
+
// to not be since this is a vanilla template we just added effects to
|
|
733
|
+
Object.assign(target.__data, target.__dataProto);
|
|
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();
|
|
568
742
|
} else {
|
|
569
|
-
|
|
743
|
+
// Swizzle the cached subclass prototype onto the custom element
|
|
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
|
+
}
|
|
757
|
+
}
|
|
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
|
+
|
|
769
|
+
function addNotifyEffects(klass, template, templateInfo, options) {
|
|
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
|
+
}
|
|
570
946
|
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
571
949
|
|
|
572
|
-
|
|
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
|
+
}
|
|
573
991
|
}
|
|
992
|
+
return null;
|
|
574
993
|
}
|
|
575
994
|
|
|
576
995
|
/**
|
|
577
996
|
* @license
|
|
578
|
-
* Copyright (c) 2021 -
|
|
997
|
+
* Copyright (c) 2021 - 2022 Vaadin Ltd.
|
|
579
998
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
580
999
|
*/
|
|
581
1000
|
|
|
@@ -607,27 +1026,6 @@ class FocusTrapController {
|
|
|
607
1026
|
this.__onKeyDown = this.__onKeyDown.bind(this);
|
|
608
1027
|
}
|
|
609
1028
|
|
|
610
|
-
/**
|
|
611
|
-
* An array of tab-ordered focusable elements inside the trap node.
|
|
612
|
-
*
|
|
613
|
-
* @return {HTMLElement[]}
|
|
614
|
-
* @private
|
|
615
|
-
*/
|
|
616
|
-
get __focusableElements() {
|
|
617
|
-
return getFocusableElements(this.__trapNode);
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
* The index of the element inside the trap node that currently has focus.
|
|
622
|
-
*
|
|
623
|
-
* @return {HTMLElement | undefined}
|
|
624
|
-
* @private
|
|
625
|
-
*/
|
|
626
|
-
get __focusedElementIndex() {
|
|
627
|
-
const focusableElements = this.__focusableElements;
|
|
628
|
-
return focusableElements.indexOf(focusableElements.filter(isElementFocused).pop());
|
|
629
|
-
}
|
|
630
|
-
|
|
631
1029
|
hostConnected() {
|
|
632
1030
|
document.addEventListener('keydown', this.__onKeyDown);
|
|
633
1031
|
}
|
|
@@ -726,722 +1124,1123 @@ class FocusTrapController {
|
|
|
726
1124
|
element.select();
|
|
727
1125
|
}
|
|
728
1126
|
}
|
|
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
|
+
}
|
|
729
1148
|
}
|
|
730
1149
|
|
|
731
1150
|
/**
|
|
732
1151
|
* @license
|
|
733
|
-
* Copyright (c) 2017 -
|
|
1152
|
+
* Copyright (c) 2017 - 2022 Vaadin Ltd.
|
|
734
1153
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
735
1154
|
*/
|
|
736
1155
|
|
|
737
1156
|
/**
|
|
738
|
-
*
|
|
1157
|
+
*
|
|
1158
|
+
* `<vaadin-overlay>` is a Web Component for creating overlays. The content of the overlay
|
|
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
|
|
739
1245
|
* @mixes ControllerMixin
|
|
740
1246
|
*/
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
type: Boolean,
|
|
752
|
-
value: false,
|
|
753
|
-
},
|
|
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. */
|
|
754
1257
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
value: false,
|
|
762
|
-
},
|
|
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;
|
|
763
1264
|
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
type: HTMLElement,
|
|
771
|
-
},
|
|
772
|
-
};
|
|
773
|
-
}
|
|
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;
|
|
774
1271
|
|
|
775
|
-
|
|
776
|
-
|
|
1272
|
+
/* Allow centering when max-width/max-height applies. */
|
|
1273
|
+
margin: auto;
|
|
777
1274
|
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
this.__focusRestorationController = new FocusRestorationController();
|
|
781
|
-
}
|
|
1275
|
+
/* The host is not clickable, only the overlay part is. */
|
|
1276
|
+
pointer-events: none;
|
|
782
1277
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
super.ready();
|
|
1278
|
+
/* Remove tap highlight on touch devices. */
|
|
1279
|
+
-webkit-tap-highlight-color: transparent;
|
|
786
1280
|
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
}
|
|
1281
|
+
/* CSS API for host */
|
|
1282
|
+
--vaadin-overlay-viewport-bottom: 0;
|
|
1283
|
+
}
|
|
791
1284
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
*/
|
|
797
|
-
_resetFocus() {
|
|
798
|
-
if (this.focusTrap) {
|
|
799
|
-
this.__ariaModalController.close();
|
|
800
|
-
this.__focusTrapController.releaseFocus();
|
|
801
|
-
}
|
|
1285
|
+
:host([hidden]),
|
|
1286
|
+
:host(:not([opened]):not([closing])) {
|
|
1287
|
+
display: none !important;
|
|
1288
|
+
}
|
|
802
1289
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1290
|
+
[part='overlay'] {
|
|
1291
|
+
-webkit-overflow-scrolling: touch;
|
|
1292
|
+
overflow: auto;
|
|
1293
|
+
pointer-events: auto;
|
|
807
1294
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
* @protected
|
|
812
|
-
*/
|
|
813
|
-
_saveFocus() {
|
|
814
|
-
if (this.restoreFocusOnClose) {
|
|
815
|
-
this.__focusRestorationController.saveFocus(this.restoreFocusNode);
|
|
816
|
-
}
|
|
817
|
-
}
|
|
1295
|
+
/* Prevent overflowing the host in MSIE 11 */
|
|
1296
|
+
max-width: 100%;
|
|
1297
|
+
box-sizing: border-box;
|
|
818
1298
|
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
*
|
|
822
|
-
* @protected
|
|
823
|
-
*/
|
|
824
|
-
_trapFocus() {
|
|
825
|
-
if (this.focusTrap) {
|
|
826
|
-
this.__ariaModalController.showModal();
|
|
827
|
-
this.__focusTrapController.trapFocus(this.$.overlay);
|
|
828
|
-
}
|
|
829
|
-
}
|
|
1299
|
+
-webkit-tap-highlight-color: initial; /* reenable tap highlight inside */
|
|
1300
|
+
}
|
|
830
1301
|
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
1302
|
+
[part='backdrop'] {
|
|
1303
|
+
z-index: -1;
|
|
1304
|
+
content: '';
|
|
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
|
+
}
|
|
846
1323
|
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
*
|
|
851
|
-
* @param {Node} node
|
|
852
|
-
* @return {boolean}
|
|
853
|
-
* @protected
|
|
854
|
-
*/
|
|
855
|
-
_deepContains(node) {
|
|
856
|
-
if (this.contains(node)) {
|
|
857
|
-
return true;
|
|
858
|
-
}
|
|
859
|
-
let n = node;
|
|
860
|
-
const doc = node.ownerDocument;
|
|
861
|
-
// Walk from node to `this` or `document`
|
|
862
|
-
while (n && n !== doc && n !== this) {
|
|
863
|
-
n = n.parentNode || n.host;
|
|
864
|
-
}
|
|
865
|
-
return n === this;
|
|
866
|
-
}
|
|
867
|
-
};
|
|
1324
|
+
static get is() {
|
|
1325
|
+
return 'vaadin-overlay';
|
|
1326
|
+
}
|
|
868
1327
|
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
1328
|
+
static get properties() {
|
|
1329
|
+
return {
|
|
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
|
+
},
|
|
1431
|
+
|
|
1432
|
+
/**
|
|
1433
|
+
* Set to specify the element which should be focused on overlay close,
|
|
1434
|
+
* if `restoreFocusOnClose` is set to true.
|
|
1435
|
+
* @type {HTMLElement}
|
|
1436
|
+
*/
|
|
1437
|
+
restoreFocusNode: {
|
|
1438
|
+
type: HTMLElement,
|
|
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
|
+
}
|
|
874
1478
|
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
*/
|
|
879
|
-
const getAttachedInstances = () =>
|
|
880
|
-
Array.from(document.body.children)
|
|
881
|
-
.filter((el) => el instanceof HTMLElement && el._hasOverlayStackMixin && !el.hasAttribute('closing'))
|
|
882
|
-
.sort((a, b) => a.__zIndex - b.__zIndex || 0);
|
|
1479
|
+
static get observers() {
|
|
1480
|
+
return ['_templateOrRendererChanged(template, renderer, owner, model, opened)'];
|
|
1481
|
+
}
|
|
883
1482
|
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
const isLastOverlay = (overlay) => overlay === getAttachedInstances().pop();
|
|
1483
|
+
constructor() {
|
|
1484
|
+
super();
|
|
1485
|
+
this._boundMouseDownListener = this._mouseDownListener.bind(this);
|
|
1486
|
+
this._boundMouseUpListener = this._mouseUpListener.bind(this);
|
|
1487
|
+
this._boundOutsideClickListener = this._outsideClickListener.bind(this);
|
|
1488
|
+
this._boundKeydownListener = this._keydownListener.bind(this);
|
|
891
1489
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
const OverlayStackMixin = (superClass) =>
|
|
896
|
-
class OverlayStackMixin extends superClass {
|
|
897
|
-
constructor() {
|
|
898
|
-
super();
|
|
1490
|
+
this._observer = new FlattenedNodesObserver(this, (info) => {
|
|
1491
|
+
this._setTemplateFromNodes(info.addedNodes);
|
|
1492
|
+
});
|
|
899
1493
|
|
|
900
|
-
|
|
901
|
-
|
|
1494
|
+
// Listener for preventing closing of the paper-dialog and all components extending `iron-overlay-behavior`.
|
|
1495
|
+
this._boundIronOverlayCanceledListener = this._ironOverlayCanceled.bind(this);
|
|
902
1496
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
* @return {boolean}
|
|
907
|
-
* @protected
|
|
908
|
-
*/
|
|
909
|
-
get _last() {
|
|
910
|
-
return isLastOverlay(this);
|
|
1497
|
+
/* c8 ignore next 3 */
|
|
1498
|
+
if (isIOS) {
|
|
1499
|
+
this._boundIosResizeListener = () => this._detectIosNavbar();
|
|
911
1500
|
}
|
|
912
1501
|
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1502
|
+
this.__focusTrapController = new FocusTrapController(this);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
/** @protected */
|
|
1506
|
+
ready() {
|
|
1507
|
+
super.ready();
|
|
1508
|
+
|
|
1509
|
+
this._observer.flush();
|
|
1510
|
+
|
|
1511
|
+
// Need to add dummy click listeners to this and the backdrop or else
|
|
1512
|
+
// the document click event listener (_outsideClickListener) may never
|
|
1513
|
+
// get invoked on iOS Safari (reproducible in <vaadin-dialog>
|
|
1514
|
+
// and <vaadin-context-menu>).
|
|
1515
|
+
this.addEventListener('click', () => {});
|
|
1516
|
+
this.$.backdrop.addEventListener('click', () => {});
|
|
1517
|
+
|
|
1518
|
+
this.addController(this.__focusTrapController);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
/** @private */
|
|
1522
|
+
_detectIosNavbar() {
|
|
1523
|
+
/* c8 ignore next 15 */
|
|
1524
|
+
if (!this.opened) {
|
|
1525
|
+
return;
|
|
927
1526
|
}
|
|
928
1527
|
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
if (document.body.style.pointerEvents !== 'none') {
|
|
932
|
-
// Set body pointer-events to 'none' to disable mouse interactions with
|
|
933
|
-
// other document nodes.
|
|
934
|
-
this._previousDocumentPointerEvents = document.body.style.pointerEvents;
|
|
935
|
-
document.body.style.pointerEvents = 'none';
|
|
936
|
-
}
|
|
1528
|
+
const innerHeight = window.innerHeight;
|
|
1529
|
+
const innerWidth = window.innerWidth;
|
|
937
1530
|
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
});
|
|
1531
|
+
const landscape = innerWidth > innerHeight;
|
|
1532
|
+
|
|
1533
|
+
const clientHeight = document.documentElement.clientHeight;
|
|
1534
|
+
|
|
1535
|
+
if (landscape && clientHeight > innerHeight) {
|
|
1536
|
+
this.style.setProperty('--vaadin-overlay-viewport-bottom', `${clientHeight - innerHeight}px`);
|
|
1537
|
+
} else {
|
|
1538
|
+
this.style.setProperty('--vaadin-overlay-viewport-bottom', '0');
|
|
944
1539
|
}
|
|
1540
|
+
}
|
|
945
1541
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
1542
|
+
/**
|
|
1543
|
+
* @param {!Array<!Element>} nodes
|
|
1544
|
+
* @protected
|
|
1545
|
+
*/
|
|
1546
|
+
_setTemplateFromNodes(nodes) {
|
|
1547
|
+
this.template = nodes.find((node) => node.localName && node.localName === 'template') || this.template;
|
|
1548
|
+
}
|
|
953
1549
|
|
|
954
|
-
|
|
955
|
-
|
|
1550
|
+
/**
|
|
1551
|
+
* @param {Event=} sourceEvent
|
|
1552
|
+
* @event vaadin-overlay-close
|
|
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;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
956
1566
|
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
if (!el.modeless) {
|
|
966
|
-
// Stop after the last modal
|
|
967
|
-
break;
|
|
968
|
-
}
|
|
969
|
-
}
|
|
1567
|
+
/** @protected */
|
|
1568
|
+
connectedCallback() {
|
|
1569
|
+
super.connectedCallback();
|
|
1570
|
+
|
|
1571
|
+
/* c8 ignore next 3 */
|
|
1572
|
+
if (this._boundIosResizeListener) {
|
|
1573
|
+
this._detectIosNavbar();
|
|
1574
|
+
window.addEventListener('resize', this._boundIosResizeListener);
|
|
970
1575
|
}
|
|
971
|
-
}
|
|
1576
|
+
}
|
|
972
1577
|
|
|
973
|
-
/**
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
977
|
-
*/
|
|
1578
|
+
/** @protected */
|
|
1579
|
+
disconnectedCallback() {
|
|
1580
|
+
super.disconnectedCallback();
|
|
978
1581
|
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
const OverlayMixin = (superClass) =>
|
|
985
|
-
class OverlayMixin extends OverlayFocusMixin(OverlayStackMixin(superClass)) {
|
|
986
|
-
static get properties() {
|
|
987
|
-
return {
|
|
988
|
-
/**
|
|
989
|
-
* When true, the overlay is visible and attached to body.
|
|
990
|
-
*/
|
|
991
|
-
opened: {
|
|
992
|
-
type: Boolean,
|
|
993
|
-
notify: true,
|
|
994
|
-
observer: '_openedChanged',
|
|
995
|
-
reflectToAttribute: true,
|
|
996
|
-
},
|
|
1582
|
+
/* c8 ignore next 3 */
|
|
1583
|
+
if (this._boundIosResizeListener) {
|
|
1584
|
+
window.removeEventListener('resize', this._boundIosResizeListener);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
997
1587
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1588
|
+
/**
|
|
1589
|
+
* Requests an update for the content of the overlay.
|
|
1590
|
+
* While performing the update, it invokes the renderer passed in the `renderer` property.
|
|
1591
|
+
*
|
|
1592
|
+
* It is not guaranteed that the update happens immediately (synchronously) after it is requested.
|
|
1593
|
+
*/
|
|
1594
|
+
requestContentUpdate() {
|
|
1595
|
+
if (this.renderer) {
|
|
1596
|
+
this.renderer.call(this.owner, this.content, this.owner, this.model);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1005
1599
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
type: Object,
|
|
1011
|
-
},
|
|
1600
|
+
/** @private */
|
|
1601
|
+
_ironOverlayCanceled(event) {
|
|
1602
|
+
event.preventDefault();
|
|
1603
|
+
}
|
|
1012
1604
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
* - `root` The root container DOM element. Append your content to it.
|
|
1018
|
-
* - `owner` The host element of the renderer function.
|
|
1019
|
-
* - `model` The object with the properties related with rendering.
|
|
1020
|
-
* @type {OverlayRenderer | null | undefined}
|
|
1021
|
-
*/
|
|
1022
|
-
renderer: {
|
|
1023
|
-
type: Object,
|
|
1024
|
-
},
|
|
1605
|
+
/** @private */
|
|
1606
|
+
_mouseDownListener(event) {
|
|
1607
|
+
this._mouseDownInside = event.composedPath().indexOf(this.$.overlay) >= 0;
|
|
1608
|
+
}
|
|
1025
1609
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
*/
|
|
1031
|
-
modeless: {
|
|
1032
|
-
type: Boolean,
|
|
1033
|
-
value: false,
|
|
1034
|
-
reflectToAttribute: true,
|
|
1035
|
-
observer: '_modelessChanged',
|
|
1036
|
-
},
|
|
1610
|
+
/** @private */
|
|
1611
|
+
_mouseUpListener(event) {
|
|
1612
|
+
this._mouseUpInside = event.composedPath().indexOf(this.$.overlay) >= 0;
|
|
1613
|
+
}
|
|
1037
1614
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1615
|
+
/**
|
|
1616
|
+
* We need to listen on 'click' / 'tap' event and capture it and close the overlay before
|
|
1617
|
+
* propagating the event to the listener in the button. Otherwise, if the clicked button would call
|
|
1618
|
+
* open(), this would happen: https://www.youtube.com/watch?v=Z86V_ICUCD4
|
|
1619
|
+
*
|
|
1620
|
+
* @event vaadin-overlay-outside-click
|
|
1621
|
+
* fired before the `vaadin-overlay` will be closed on outside click. If canceled the closing of the overlay is canceled as well.
|
|
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
|
+
}
|
|
1048
1634
|
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
};
|
|
1635
|
+
const evt = new CustomEvent('vaadin-overlay-outside-click', {
|
|
1636
|
+
bubbles: true,
|
|
1637
|
+
cancelable: true,
|
|
1638
|
+
detail: { sourceEvent: event },
|
|
1639
|
+
});
|
|
1640
|
+
this.dispatchEvent(evt);
|
|
1641
|
+
|
|
1642
|
+
if (this.opened && !evt.defaultPrevented) {
|
|
1643
|
+
this.close(event);
|
|
1059
1644
|
}
|
|
1645
|
+
}
|
|
1060
1646
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1647
|
+
/**
|
|
1648
|
+
* @event vaadin-overlay-escape-press
|
|
1649
|
+
* fired before the `vaadin-overlay` will be closed on ESC button press. If canceled the closing of the overlay is canceled as well.
|
|
1650
|
+
*
|
|
1651
|
+
* @private
|
|
1652
|
+
*/
|
|
1653
|
+
_keydownListener(event) {
|
|
1654
|
+
if (!this._last) {
|
|
1655
|
+
return;
|
|
1063
1656
|
}
|
|
1064
1657
|
|
|
1065
|
-
|
|
1066
|
-
|
|
1658
|
+
// Only close modeless overlay on Esc press when it contains focus
|
|
1659
|
+
if (this.modeless && !event.composedPath().includes(this.$.overlay)) {
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1067
1662
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1663
|
+
if (event.key === 'Escape') {
|
|
1664
|
+
const evt = new CustomEvent('vaadin-overlay-escape-press', {
|
|
1665
|
+
bubbles: true,
|
|
1666
|
+
cancelable: true,
|
|
1667
|
+
detail: { sourceEvent: event },
|
|
1668
|
+
});
|
|
1669
|
+
this.dispatchEvent(evt);
|
|
1072
1670
|
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
this._boundIosResizeListener = () => this._detectIosNavbar();
|
|
1671
|
+
if (this.opened && !evt.defaultPrevented) {
|
|
1672
|
+
this.close(event);
|
|
1076
1673
|
}
|
|
1077
1674
|
}
|
|
1675
|
+
}
|
|
1078
1676
|
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1677
|
+
/** @protected */
|
|
1678
|
+
_ensureTemplatized() {
|
|
1679
|
+
this._setTemplateFromNodes(Array.from(this.children));
|
|
1680
|
+
}
|
|
1082
1681
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
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();
|
|
1089
1691
|
}
|
|
1090
1692
|
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1693
|
+
if (opened) {
|
|
1694
|
+
// Store focused node.
|
|
1695
|
+
this.__restoreFocusNode = this._getActiveElement();
|
|
1696
|
+
this._animatedOpening();
|
|
1094
1697
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1698
|
+
afterNextRender(this, () => {
|
|
1699
|
+
if (this.focusTrap) {
|
|
1700
|
+
this.__focusTrapController.trapFocus(this.$.overlay);
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
const evt = new CustomEvent('vaadin-overlay-open', { bubbles: true });
|
|
1704
|
+
this.dispatchEvent(evt);
|
|
1705
|
+
});
|
|
1706
|
+
|
|
1707
|
+
document.addEventListener('keydown', this._boundKeydownListener);
|
|
1708
|
+
|
|
1709
|
+
if (!this.modeless) {
|
|
1710
|
+
this._addGlobalListeners();
|
|
1711
|
+
}
|
|
1712
|
+
} else if (wasOpened) {
|
|
1713
|
+
if (this.focusTrap) {
|
|
1714
|
+
this.__focusTrapController.releaseFocus();
|
|
1099
1715
|
}
|
|
1100
|
-
}
|
|
1101
1716
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1717
|
+
this._animatedClosing();
|
|
1718
|
+
|
|
1719
|
+
document.removeEventListener('keydown', this._boundKeydownListener);
|
|
1105
1720
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
window.removeEventListener('resize', this._boundIosResizeListener);
|
|
1721
|
+
if (!this.modeless) {
|
|
1722
|
+
this._removeGlobalListeners();
|
|
1109
1723
|
}
|
|
1110
1724
|
}
|
|
1725
|
+
}
|
|
1111
1726
|
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1727
|
+
/** @private */
|
|
1728
|
+
_hiddenChanged(hidden) {
|
|
1729
|
+
if (hidden && this.hasAttribute('closing')) {
|
|
1730
|
+
this._flushAnimation('closing');
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1734
|
+
/**
|
|
1735
|
+
* @return {boolean}
|
|
1736
|
+
* @protected
|
|
1737
|
+
*/
|
|
1738
|
+
_shouldAnimate() {
|
|
1739
|
+
const name = getComputedStyle(this).getPropertyValue('animation-name');
|
|
1740
|
+
const hidden = getComputedStyle(this).getPropertyValue('display') === 'none';
|
|
1741
|
+
return !hidden && name && name !== 'none';
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
/**
|
|
1745
|
+
* @param {string} type
|
|
1746
|
+
* @param {Function} callback
|
|
1747
|
+
* @protected
|
|
1748
|
+
*/
|
|
1749
|
+
_enqueueAnimation(type, callback) {
|
|
1750
|
+
const handler = `__${type}Handler`;
|
|
1751
|
+
const listener = (event) => {
|
|
1752
|
+
if (event && event.target !== this) {
|
|
1753
|
+
return;
|
|
1121
1754
|
}
|
|
1755
|
+
callback();
|
|
1756
|
+
this.removeEventListener('animationend', listener);
|
|
1757
|
+
delete this[handler];
|
|
1758
|
+
};
|
|
1759
|
+
this[handler] = listener;
|
|
1760
|
+
this.addEventListener('animationend', listener);
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
/**
|
|
1764
|
+
* @param {string} type
|
|
1765
|
+
* @protected
|
|
1766
|
+
*/
|
|
1767
|
+
_flushAnimation(type) {
|
|
1768
|
+
const handler = `__${type}Handler`;
|
|
1769
|
+
if (typeof this[handler] === 'function') {
|
|
1770
|
+
this[handler]();
|
|
1122
1771
|
}
|
|
1772
|
+
}
|
|
1123
1773
|
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1774
|
+
/** @protected */
|
|
1775
|
+
_animatedOpening() {
|
|
1776
|
+
if (this.parentNode === document.body && this.hasAttribute('closing')) {
|
|
1777
|
+
this._flushAnimation('closing');
|
|
1778
|
+
}
|
|
1779
|
+
this._attachOverlay();
|
|
1780
|
+
if (!this.modeless) {
|
|
1781
|
+
this._enterModalState();
|
|
1782
|
+
}
|
|
1783
|
+
this.setAttribute('opening', '');
|
|
1784
|
+
|
|
1785
|
+
if (this._shouldAnimate()) {
|
|
1786
|
+
this._enqueueAnimation('opening', () => {
|
|
1787
|
+
this._finishOpening();
|
|
1132
1788
|
});
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
this.opened = false;
|
|
1136
|
-
}
|
|
1789
|
+
} else {
|
|
1790
|
+
this._finishOpening();
|
|
1137
1791
|
}
|
|
1792
|
+
}
|
|
1138
1793
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
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
|
+
|
|
1802
|
+
/** @protected */
|
|
1803
|
+
_finishOpening() {
|
|
1804
|
+
document.addEventListener('iron-overlay-canceled', this._boundIronOverlayCanceledListener);
|
|
1805
|
+
this.removeAttribute('opening');
|
|
1806
|
+
}
|
|
1145
1807
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1808
|
+
/** @protected */
|
|
1809
|
+
_finishClosing() {
|
|
1810
|
+
document.removeEventListener('iron-overlay-canceled', this._boundIronOverlayCanceledListener);
|
|
1811
|
+
this._detachOverlay();
|
|
1812
|
+
this.$.overlay.style.removeProperty('pointer-events');
|
|
1813
|
+
this.removeAttribute('closing');
|
|
1814
|
+
}
|
|
1148
1815
|
|
|
1149
|
-
|
|
1816
|
+
/**
|
|
1817
|
+
* @event vaadin-overlay-closing
|
|
1818
|
+
* Fired when the overlay will be closed.
|
|
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;
|
|
1847
|
+
}
|
|
1150
1848
|
|
|
1151
|
-
|
|
1849
|
+
this.setAttribute('closing', '');
|
|
1850
|
+
this.dispatchEvent(new CustomEvent('vaadin-overlay-closing'));
|
|
1152
1851
|
|
|
1153
|
-
if (
|
|
1154
|
-
this.
|
|
1852
|
+
if (this._shouldAnimate()) {
|
|
1853
|
+
this._enqueueAnimation('closing', () => {
|
|
1854
|
+
this._finishClosing();
|
|
1855
|
+
});
|
|
1155
1856
|
} else {
|
|
1156
|
-
this.
|
|
1857
|
+
this._finishClosing();
|
|
1157
1858
|
}
|
|
1158
1859
|
}
|
|
1860
|
+
}
|
|
1159
1861
|
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1862
|
+
/** @protected */
|
|
1863
|
+
_detachOverlay() {
|
|
1864
|
+
this._placeholder.parentNode.insertBefore(this, this._placeholder);
|
|
1865
|
+
this._placeholder.parentNode.removeChild(this._placeholder);
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1868
|
+
/**
|
|
1869
|
+
* Returns all attached overlays in visual stacking order.
|
|
1870
|
+
* @private
|
|
1871
|
+
*/
|
|
1872
|
+
static get __attachedInstances() {
|
|
1873
|
+
return Array.from(document.body.children)
|
|
1874
|
+
.filter((el) => el instanceof Overlay && !el.hasAttribute('closing'))
|
|
1875
|
+
.sort((a, b) => a.__zIndex - b.__zIndex || 0);
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
/**
|
|
1879
|
+
* Returns true if this is the last one in the opened overlays stack
|
|
1880
|
+
* @return {boolean}
|
|
1881
|
+
* @protected
|
|
1882
|
+
*/
|
|
1883
|
+
get _last() {
|
|
1884
|
+
return this === Overlay.__attachedInstances.pop();
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1887
|
+
/** @private */
|
|
1888
|
+
_modelessChanged(modeless) {
|
|
1889
|
+
if (!modeless) {
|
|
1890
|
+
if (this.opened) {
|
|
1891
|
+
this._addGlobalListeners();
|
|
1892
|
+
this._enterModalState();
|
|
1893
|
+
}
|
|
1894
|
+
} else {
|
|
1895
|
+
this._removeGlobalListeners();
|
|
1896
|
+
this._exitModalState();
|
|
1167
1897
|
}
|
|
1898
|
+
}
|
|
1168
1899
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1900
|
+
/** @protected */
|
|
1901
|
+
_addGlobalListeners() {
|
|
1902
|
+
document.addEventListener('mousedown', this._boundMouseDownListener);
|
|
1903
|
+
document.addEventListener('mouseup', this._boundMouseUpListener);
|
|
1904
|
+
// Firefox leaks click to document on contextmenu even if prevented
|
|
1905
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=990614
|
|
1906
|
+
document.documentElement.addEventListener('click', this._boundOutsideClickListener, true);
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
/** @protected */
|
|
1910
|
+
_enterModalState() {
|
|
1911
|
+
if (document.body.style.pointerEvents !== 'none') {
|
|
1912
|
+
// Set body pointer-events to 'none' to disable mouse interactions with
|
|
1913
|
+
// other document nodes.
|
|
1914
|
+
this._previousDocumentPointerEvents = document.body.style.pointerEvents;
|
|
1915
|
+
document.body.style.pointerEvents = 'none';
|
|
1174
1916
|
}
|
|
1175
1917
|
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
this._oldOwner = owner;
|
|
1181
|
-
|
|
1182
|
-
const rendererChanged = this._oldRenderer !== renderer;
|
|
1183
|
-
this._oldRenderer = renderer;
|
|
1184
|
-
|
|
1185
|
-
const openedChanged = this._oldOpened !== opened;
|
|
1186
|
-
this._oldOpened = opened;
|
|
1187
|
-
|
|
1188
|
-
if (rendererChanged) {
|
|
1189
|
-
this.innerHTML = '';
|
|
1190
|
-
// Whenever a Lit-based renderer is used, it assigns a Lit part to the node it was rendered into.
|
|
1191
|
-
// When clearing the rendered content, this part needs to be manually disposed of.
|
|
1192
|
-
// Otherwise, using a Lit-based renderer on the same node will throw an exception or render nothing afterward.
|
|
1193
|
-
delete this._$litPart$;
|
|
1918
|
+
// Disable pointer events in other attached overlays
|
|
1919
|
+
Overlay.__attachedInstances.forEach((el) => {
|
|
1920
|
+
if (el !== this) {
|
|
1921
|
+
el.shadowRoot.querySelector('[part="overlay"]').style.pointerEvents = 'none';
|
|
1194
1922
|
}
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1195
1925
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1926
|
+
/** @protected */
|
|
1927
|
+
_removeGlobalListeners() {
|
|
1928
|
+
document.removeEventListener('mousedown', this._boundMouseDownListener);
|
|
1929
|
+
document.removeEventListener('mouseup', this._boundMouseUpListener);
|
|
1930
|
+
document.documentElement.removeEventListener('click', this._boundOutsideClickListener, true);
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/** @protected */
|
|
1934
|
+
_exitModalState() {
|
|
1935
|
+
if (this._previousDocumentPointerEvents !== undefined) {
|
|
1936
|
+
// Restore body pointer-events
|
|
1937
|
+
document.body.style.pointerEvents = this._previousDocumentPointerEvents;
|
|
1938
|
+
delete this._previousDocumentPointerEvents;
|
|
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;
|
|
1198
1954
|
}
|
|
1199
1955
|
}
|
|
1956
|
+
}
|
|
1200
1957
|
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1958
|
+
/** @protected */
|
|
1959
|
+
_removeOldContent() {
|
|
1960
|
+
if (!this.content || !this._contentNodes) {
|
|
1961
|
+
return;
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
this._observer.disconnect();
|
|
1965
|
+
|
|
1966
|
+
this._contentNodes.forEach((node) => {
|
|
1967
|
+
if (node.parentNode === this.content) {
|
|
1968
|
+
this.content.removeChild(node);
|
|
1211
1969
|
}
|
|
1970
|
+
});
|
|
1971
|
+
|
|
1972
|
+
if (this._originalContentPart) {
|
|
1973
|
+
// Restore the original <div part="content">
|
|
1974
|
+
this.$.content.parentNode.replaceChild(this._originalContentPart, this.$.content);
|
|
1975
|
+
this.$.content = this._originalContentPart;
|
|
1976
|
+
this._originalContentPart = undefined;
|
|
1212
1977
|
}
|
|
1213
1978
|
|
|
1214
|
-
|
|
1215
|
-
_openedChanged(opened, wasOpened) {
|
|
1216
|
-
if (opened) {
|
|
1217
|
-
this._saveFocus();
|
|
1979
|
+
this._observer.connect();
|
|
1218
1980
|
|
|
1219
|
-
|
|
1981
|
+
this._contentNodes = undefined;
|
|
1982
|
+
this.content = undefined;
|
|
1983
|
+
}
|
|
1220
1984
|
|
|
1221
|
-
|
|
1222
|
-
|
|
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
|
+
}
|
|
2001
|
+
|
|
2002
|
+
this._instance = new template._Templatizer({});
|
|
2003
|
+
this._contentNodes = Array.from(this._instance.root.childNodes);
|
|
2004
|
+
|
|
2005
|
+
const templateRoot = template._templateRoot || (template._templateRoot = template.getRootNode());
|
|
2006
|
+
|
|
2007
|
+
if (templateRoot !== document) {
|
|
2008
|
+
if (!this.$.content.shadowRoot) {
|
|
2009
|
+
this.$.content.attachShadow({ mode: 'open' });
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
let scopeCssText = Array.from(templateRoot.querySelectorAll('style')).reduce(
|
|
2013
|
+
(result, style) => result + style.textContent,
|
|
2014
|
+
'',
|
|
2015
|
+
);
|
|
2016
|
+
|
|
2017
|
+
// The overlay root’s :host styles should not apply inside the overlay
|
|
2018
|
+
scopeCssText = scopeCssText.replace(/:host/g, ':host-nomatch');
|
|
2019
|
+
|
|
2020
|
+
if (scopeCssText) {
|
|
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
|
+
}
|
|
2027
|
+
|
|
2028
|
+
this.$.content.shadowRoot.appendChild(this._instance.root);
|
|
2029
|
+
this.content = this.$.content.shadowRoot;
|
|
2030
|
+
} else {
|
|
2031
|
+
this.appendChild(this._instance.root);
|
|
2032
|
+
this.content = this;
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
/** @private */
|
|
2037
|
+
_removeNewRendererOrTemplate(template, oldTemplate, renderer, oldRenderer) {
|
|
2038
|
+
if (template !== oldTemplate) {
|
|
2039
|
+
this.template = undefined;
|
|
2040
|
+
} else if (renderer !== oldRenderer) {
|
|
2041
|
+
this.renderer = undefined;
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
1223
2044
|
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
2045
|
+
/** @private */
|
|
2046
|
+
// eslint-disable-next-line max-params
|
|
2047
|
+
_templateOrRendererChanged(template, renderer, owner, model, opened) {
|
|
2048
|
+
if (template && renderer) {
|
|
2049
|
+
this._removeNewRendererOrTemplate(template, this._oldTemplate, renderer, this._oldRenderer);
|
|
2050
|
+
throw new Error('You should only use either a renderer or a template for overlay content');
|
|
2051
|
+
}
|
|
1227
2052
|
|
|
1228
|
-
|
|
2053
|
+
const ownerOrModelChanged = this._oldOwner !== owner || this._oldModel !== model;
|
|
2054
|
+
this._oldModel = model;
|
|
2055
|
+
this._oldOwner = owner;
|
|
1229
2056
|
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
}
|
|
1233
|
-
} else if (wasOpened) {
|
|
1234
|
-
this._resetFocus();
|
|
2057
|
+
const templateChanged = this._oldTemplate !== template;
|
|
2058
|
+
this._oldTemplate = template;
|
|
1235
2059
|
|
|
1236
|
-
|
|
2060
|
+
const rendererChanged = this._oldRenderer !== renderer;
|
|
2061
|
+
this._oldRenderer = renderer;
|
|
1237
2062
|
|
|
1238
|
-
|
|
2063
|
+
const openedChanged = this._oldOpened !== opened;
|
|
2064
|
+
this._oldOpened = opened;
|
|
1239
2065
|
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
2066
|
+
if (rendererChanged) {
|
|
2067
|
+
this.content = this;
|
|
2068
|
+
this.content.innerHTML = '';
|
|
2069
|
+
// Whenever a Lit-based renderer is used, it assigns a Lit part to the node it was rendered into.
|
|
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$;
|
|
1244
2073
|
}
|
|
1245
2074
|
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
2075
|
+
if (template && templateChanged) {
|
|
2076
|
+
this._stampOverlayTemplate(template);
|
|
2077
|
+
} else if (renderer && (rendererChanged || openedChanged || ownerOrModelChanged)) {
|
|
2078
|
+
if (opened) {
|
|
2079
|
+
this.requestContentUpdate();
|
|
1250
2080
|
}
|
|
1251
2081
|
}
|
|
2082
|
+
}
|
|
1252
2083
|
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
2084
|
+
/**
|
|
2085
|
+
* @return {!Element}
|
|
2086
|
+
* @protected
|
|
2087
|
+
*/
|
|
2088
|
+
_getActiveElement() {
|
|
2089
|
+
// Document.activeElement can be null
|
|
2090
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
|
|
2091
|
+
let active = document.activeElement || document.body;
|
|
2092
|
+
while (active.shadowRoot && active.shadowRoot.activeElement) {
|
|
2093
|
+
active = active.shadowRoot.activeElement;
|
|
2094
|
+
}
|
|
2095
|
+
return active;
|
|
2096
|
+
}
|
|
1263
2097
|
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
if (event && event.target !== this) {
|
|
1273
|
-
return;
|
|
1274
|
-
}
|
|
1275
|
-
callback();
|
|
1276
|
-
this.removeEventListener('animationend', listener);
|
|
1277
|
-
delete this[handler];
|
|
1278
|
-
};
|
|
1279
|
-
this[handler] = listener;
|
|
1280
|
-
this.addEventListener('animationend', listener);
|
|
2098
|
+
/**
|
|
2099
|
+
* @param {!Node} node
|
|
2100
|
+
* @return {boolean}
|
|
2101
|
+
* @protected
|
|
2102
|
+
*/
|
|
2103
|
+
_deepContains(node) {
|
|
2104
|
+
if (this.contains(node)) {
|
|
2105
|
+
return true;
|
|
1281
2106
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
_flushAnimation(type) {
|
|
1288
|
-
const handler = `__${type}Handler`;
|
|
1289
|
-
if (typeof this[handler] === 'function') {
|
|
1290
|
-
this[handler]();
|
|
1291
|
-
}
|
|
2107
|
+
let n = node;
|
|
2108
|
+
const doc = node.ownerDocument;
|
|
2109
|
+
// Walk from node to `this` or `document`
|
|
2110
|
+
while (n && n !== doc && n !== this) {
|
|
2111
|
+
n = n.parentNode || n.host;
|
|
1292
2112
|
}
|
|
2113
|
+
return n === this;
|
|
2114
|
+
}
|
|
1293
2115
|
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
2116
|
+
/**
|
|
2117
|
+
* Brings the overlay as visually the frontmost one
|
|
2118
|
+
*/
|
|
2119
|
+
bringToFront() {
|
|
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
|
+
}
|
|
1304
2130
|
|
|
1305
|
-
|
|
1306
|
-
this._enqueueAnimation('opening', () => {
|
|
1307
|
-
this._finishOpening();
|
|
1308
|
-
});
|
|
1309
|
-
} else {
|
|
1310
|
-
this._finishOpening();
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
2131
|
+
customElements.define(Overlay.is, Overlay);
|
|
1313
2132
|
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
this.bringToFront();
|
|
1320
|
-
}
|
|
2133
|
+
/**
|
|
2134
|
+
* @license
|
|
2135
|
+
* Copyright (c) 2017 - 2022 Vaadin Ltd.
|
|
2136
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
2137
|
+
*/
|
|
1321
2138
|
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
2139
|
+
const menuOverlayCore = i`
|
|
2140
|
+
:host([opening]),
|
|
2141
|
+
:host([closing]) {
|
|
2142
|
+
animation: 0.14s lumo-overlay-dummy-animation;
|
|
2143
|
+
}
|
|
1326
2144
|
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
2145
|
+
[part='overlay'] {
|
|
2146
|
+
will-change: opacity, transform;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
:host([opening]) [part='overlay'] {
|
|
2150
|
+
animation: 0.1s lumo-menu-overlay-enter ease-out both;
|
|
2151
|
+
}
|
|
2152
|
+
|
|
2153
|
+
@keyframes lumo-menu-overlay-enter {
|
|
2154
|
+
0% {
|
|
2155
|
+
opacity: 0;
|
|
2156
|
+
transform: translateY(-4px);
|
|
1333
2157
|
}
|
|
2158
|
+
}
|
|
1334
2159
|
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
this.setAttribute('closing', '');
|
|
1343
|
-
this.dispatchEvent(new CustomEvent('vaadin-overlay-closing'));
|
|
1344
|
-
|
|
1345
|
-
if (this._shouldAnimate()) {
|
|
1346
|
-
this._enqueueAnimation('closing', () => {
|
|
1347
|
-
this._finishClosing();
|
|
1348
|
-
});
|
|
1349
|
-
} else {
|
|
1350
|
-
this._finishClosing();
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
2160
|
+
:host([closing]) [part='overlay'] {
|
|
2161
|
+
animation: 0.1s lumo-menu-overlay-exit both;
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
@keyframes lumo-menu-overlay-exit {
|
|
2165
|
+
100% {
|
|
2166
|
+
opacity: 0;
|
|
1353
2167
|
}
|
|
2168
|
+
}
|
|
2169
|
+
`;
|
|
1354
2170
|
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
2171
|
+
registerStyles('', menuOverlayCore, { moduleId: 'lumo-menu-overlay-core' });
|
|
2172
|
+
|
|
2173
|
+
const menuOverlayExt = i`
|
|
2174
|
+
/* Small viewport (bottom sheet) styles */
|
|
2175
|
+
/* Use direct media queries instead of the state attributes ([phone] and [fullscreen]) provided by the elements */
|
|
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;
|
|
1359
2184
|
}
|
|
1360
2185
|
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
2186
|
+
[part='overlay'] {
|
|
2187
|
+
max-height: 50vh;
|
|
2188
|
+
width: 100vw;
|
|
2189
|
+
border-radius: 0;
|
|
2190
|
+
box-shadow: var(--lumo-box-shadow-xl);
|
|
1364
2191
|
}
|
|
1365
2192
|
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
2193
|
+
/* The content part scrolls instead of the overlay part, because of the gradient fade-out */
|
|
2194
|
+
[part='content'] {
|
|
2195
|
+
padding: 30px var(--lumo-space-m);
|
|
2196
|
+
max-height: inherit;
|
|
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);
|
|
1369
2202
|
}
|
|
1370
2203
|
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
* Override this method to customize the closing logic.
|
|
1374
|
-
*
|
|
1375
|
-
* @param {Event} _event
|
|
1376
|
-
* @return {boolean}
|
|
1377
|
-
* @protected
|
|
1378
|
-
*/
|
|
1379
|
-
_shouldCloseOnOutsideClick(_event) {
|
|
1380
|
-
return this._last;
|
|
2204
|
+
[part='backdrop'] {
|
|
2205
|
+
display: block;
|
|
1381
2206
|
}
|
|
1382
2207
|
|
|
1383
|
-
|
|
1384
|
-
* Outside click listener used in capture phase to close the overlay before
|
|
1385
|
-
* propagating the event to the listener on the element that triggered it.
|
|
1386
|
-
* Otherwise, calling `open()` would result in closing and re-opening.
|
|
1387
|
-
*
|
|
1388
|
-
* @private
|
|
1389
|
-
*/
|
|
1390
|
-
_outsideClickListener(event) {
|
|
1391
|
-
if (event.composedPath().includes(this.$.overlay) || this._mouseDownInside || this._mouseUpInside) {
|
|
1392
|
-
this._mouseDownInside = false;
|
|
1393
|
-
this._mouseUpInside = false;
|
|
1394
|
-
return;
|
|
1395
|
-
}
|
|
2208
|
+
/* Animations */
|
|
1396
2209
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
2210
|
+
:host([opening]) [part='overlay'] {
|
|
2211
|
+
animation: 0.2s lumo-mobile-menu-overlay-enter cubic-bezier(0.215, 0.61, 0.355, 1) both;
|
|
2212
|
+
}
|
|
1400
2213
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
});
|
|
1406
|
-
this.dispatchEvent(evt);
|
|
2214
|
+
:host([closing]),
|
|
2215
|
+
:host([closing]) [part='backdrop'] {
|
|
2216
|
+
animation-delay: 0.14s;
|
|
2217
|
+
}
|
|
1407
2218
|
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
}
|
|
2219
|
+
:host([closing]) [part='overlay'] {
|
|
2220
|
+
animation: 0.14s 0.14s lumo-mobile-menu-overlay-exit cubic-bezier(0.55, 0.055, 0.675, 0.19) both;
|
|
1411
2221
|
}
|
|
2222
|
+
}
|
|
1412
2223
|
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
if (!this._last) {
|
|
1419
|
-
return;
|
|
1420
|
-
}
|
|
2224
|
+
@keyframes lumo-mobile-menu-overlay-enter {
|
|
2225
|
+
0% {
|
|
2226
|
+
transform: translateY(150%);
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
1421
2229
|
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
2230
|
+
@keyframes lumo-mobile-menu-overlay-exit {
|
|
2231
|
+
100% {
|
|
2232
|
+
transform: translateY(150%);
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
`;
|
|
1426
2236
|
|
|
1427
|
-
|
|
1428
|
-
const evt = new CustomEvent('vaadin-overlay-escape-press', {
|
|
1429
|
-
bubbles: true,
|
|
1430
|
-
cancelable: true,
|
|
1431
|
-
detail: { sourceEvent: event },
|
|
1432
|
-
});
|
|
1433
|
-
this.dispatchEvent(evt);
|
|
2237
|
+
const menuOverlay = [overlay, menuOverlayCore, menuOverlayExt];
|
|
1434
2238
|
|
|
1435
|
-
|
|
1436
|
-
this.close(event);
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
};
|
|
2239
|
+
registerStyles('', menuOverlay, { moduleId: 'lumo-menu-overlay' });
|
|
1441
2240
|
|
|
1442
2241
|
/**
|
|
1443
2242
|
* @license
|
|
1444
|
-
* Copyright (c) 2017 -
|
|
2243
|
+
* Copyright (c) 2017 - 2022 Vaadin Ltd.
|
|
1445
2244
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1446
2245
|
*/
|
|
1447
2246
|
|
|
@@ -1631,6 +2430,10 @@ const PositionMixin = (superClass) =>
|
|
|
1631
2430
|
}
|
|
1632
2431
|
}
|
|
1633
2432
|
|
|
2433
|
+
get __isRTL() {
|
|
2434
|
+
return this.getAttribute('dir') === 'rtl';
|
|
2435
|
+
}
|
|
2436
|
+
|
|
1634
2437
|
__positionSettingsChanged() {
|
|
1635
2438
|
this._updatePosition();
|
|
1636
2439
|
}
|
|
@@ -1654,9 +2457,9 @@ const PositionMixin = (superClass) =>
|
|
|
1654
2457
|
const shouldAlignStartVertically = this.__shouldAlignStartVertically(targetRect);
|
|
1655
2458
|
this.style.justifyContent = shouldAlignStartVertically ? 'flex-start' : 'flex-end';
|
|
1656
2459
|
|
|
1657
|
-
const
|
|
1658
|
-
const
|
|
1659
|
-
|
|
2460
|
+
const shouldAlignStartHorizontally = this.__shouldAlignStartHorizontally(targetRect, this.__isRTL);
|
|
2461
|
+
const flexStart =
|
|
2462
|
+
(!this.__isRTL && shouldAlignStartHorizontally) || (this.__isRTL && !shouldAlignStartHorizontally);
|
|
1660
2463
|
this.style.alignItems = flexStart ? 'flex-start' : 'flex-end';
|
|
1661
2464
|
|
|
1662
2465
|
// Get the overlay rect after possible overlay alignment changes
|
|
@@ -1815,153 +2618,7 @@ const PositionMixin = (superClass) =>
|
|
|
1815
2618
|
|
|
1816
2619
|
/**
|
|
1817
2620
|
* @license
|
|
1818
|
-
* Copyright (c)
|
|
1819
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1820
|
-
*/
|
|
1821
|
-
|
|
1822
|
-
const overlayStyles = i`
|
|
1823
|
-
:host {
|
|
1824
|
-
z-index: 200;
|
|
1825
|
-
position: fixed;
|
|
1826
|
-
|
|
1827
|
-
/* Despite of what the names say, <vaadin-overlay> is just a container
|
|
1828
|
-
for position/sizing/alignment. The actual overlay is the overlay part. */
|
|
1829
|
-
|
|
1830
|
-
/* Default position constraints: the entire viewport. Note: themes can
|
|
1831
|
-
override this to introduce gaps between the overlay and the viewport. */
|
|
1832
|
-
inset: 0;
|
|
1833
|
-
bottom: var(--vaadin-overlay-viewport-bottom);
|
|
1834
|
-
|
|
1835
|
-
/* Use flexbox alignment for the overlay part. */
|
|
1836
|
-
display: flex;
|
|
1837
|
-
flex-direction: column; /* makes dropdowns sizing easier */
|
|
1838
|
-
/* Align to center by default. */
|
|
1839
|
-
align-items: center;
|
|
1840
|
-
justify-content: center;
|
|
1841
|
-
|
|
1842
|
-
/* Allow centering when max-width/max-height applies. */
|
|
1843
|
-
margin: auto;
|
|
1844
|
-
|
|
1845
|
-
/* The host is not clickable, only the overlay part is. */
|
|
1846
|
-
pointer-events: none;
|
|
1847
|
-
|
|
1848
|
-
/* Remove tap highlight on touch devices. */
|
|
1849
|
-
-webkit-tap-highlight-color: transparent;
|
|
1850
|
-
|
|
1851
|
-
/* CSS API for host */
|
|
1852
|
-
--vaadin-overlay-viewport-bottom: 0;
|
|
1853
|
-
}
|
|
1854
|
-
|
|
1855
|
-
:host([hidden]),
|
|
1856
|
-
:host(:not([opened]):not([closing])) {
|
|
1857
|
-
display: none !important;
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
|
-
[part='overlay'] {
|
|
1861
|
-
-webkit-overflow-scrolling: touch;
|
|
1862
|
-
overflow: auto;
|
|
1863
|
-
pointer-events: auto;
|
|
1864
|
-
|
|
1865
|
-
/* Prevent overflowing the host */
|
|
1866
|
-
max-width: 100%;
|
|
1867
|
-
box-sizing: border-box;
|
|
1868
|
-
|
|
1869
|
-
-webkit-tap-highlight-color: initial; /* reenable tap highlight inside */
|
|
1870
|
-
}
|
|
1871
|
-
|
|
1872
|
-
[part='backdrop'] {
|
|
1873
|
-
z-index: -1;
|
|
1874
|
-
content: '';
|
|
1875
|
-
background: rgba(0, 0, 0, 0.5);
|
|
1876
|
-
position: fixed;
|
|
1877
|
-
inset: 0;
|
|
1878
|
-
pointer-events: auto;
|
|
1879
|
-
}
|
|
1880
|
-
`;
|
|
1881
|
-
|
|
1882
|
-
/**
|
|
1883
|
-
* @license
|
|
1884
|
-
* Copyright (c) 2023 Vaadin Ltd.
|
|
1885
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1886
|
-
*/
|
|
1887
|
-
|
|
1888
|
-
/**
|
|
1889
|
-
* A mixin that forwards CSS class names to the internal overlay element
|
|
1890
|
-
* by setting the `overlayClass` property or `overlay-class` attribute.
|
|
1891
|
-
*
|
|
1892
|
-
* @polymerMixin
|
|
1893
|
-
*/
|
|
1894
|
-
const OverlayClassMixin = (superclass) =>
|
|
1895
|
-
class OverlayClassMixinClass extends superclass {
|
|
1896
|
-
static get properties() {
|
|
1897
|
-
return {
|
|
1898
|
-
/**
|
|
1899
|
-
* A space-delimited list of CSS class names to set on the overlay element.
|
|
1900
|
-
* This property does not affect other CSS class names set manually via JS.
|
|
1901
|
-
*
|
|
1902
|
-
* Note, if the CSS class name was set with this property, clearing it will
|
|
1903
|
-
* remove it from the overlay, even if the same class name was also added
|
|
1904
|
-
* manually, e.g. by using `classList.add()` in the `renderer` function.
|
|
1905
|
-
*
|
|
1906
|
-
* @attr {string} overlay-class
|
|
1907
|
-
*/
|
|
1908
|
-
overlayClass: {
|
|
1909
|
-
type: String,
|
|
1910
|
-
},
|
|
1911
|
-
|
|
1912
|
-
/**
|
|
1913
|
-
* An overlay element on which CSS class names are set.
|
|
1914
|
-
*
|
|
1915
|
-
* @protected
|
|
1916
|
-
*/
|
|
1917
|
-
_overlayElement: {
|
|
1918
|
-
type: Object,
|
|
1919
|
-
},
|
|
1920
|
-
};
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
|
-
static get observers() {
|
|
1924
|
-
return ['__updateOverlayClassNames(overlayClass, _overlayElement)'];
|
|
1925
|
-
}
|
|
1926
|
-
|
|
1927
|
-
/** @private */
|
|
1928
|
-
__updateOverlayClassNames(overlayClass, overlayElement) {
|
|
1929
|
-
if (!overlayElement) {
|
|
1930
|
-
return;
|
|
1931
|
-
}
|
|
1932
|
-
|
|
1933
|
-
// Overlay is set but overlayClass is not set
|
|
1934
|
-
if (overlayClass === undefined) {
|
|
1935
|
-
return;
|
|
1936
|
-
}
|
|
1937
|
-
|
|
1938
|
-
const { classList } = overlayElement;
|
|
1939
|
-
|
|
1940
|
-
if (!this.__initialClasses) {
|
|
1941
|
-
this.__initialClasses = new Set(classList);
|
|
1942
|
-
}
|
|
1943
|
-
|
|
1944
|
-
if (Array.isArray(this.__previousClasses)) {
|
|
1945
|
-
// Remove old classes that no longer apply
|
|
1946
|
-
const classesToRemove = this.__previousClasses.filter((name) => !this.__initialClasses.has(name));
|
|
1947
|
-
if (classesToRemove.length > 0) {
|
|
1948
|
-
classList.remove(...classesToRemove);
|
|
1949
|
-
}
|
|
1950
|
-
}
|
|
1951
|
-
|
|
1952
|
-
// Add new classes based on the overlayClass
|
|
1953
|
-
const classesToAdd = typeof overlayClass === 'string' ? overlayClass.split(' ') : [];
|
|
1954
|
-
if (classesToAdd.length > 0) {
|
|
1955
|
-
classList.add(...classesToAdd);
|
|
1956
|
-
}
|
|
1957
|
-
|
|
1958
|
-
this.__previousClasses = classesToAdd;
|
|
1959
|
-
}
|
|
1960
|
-
};
|
|
1961
|
-
|
|
1962
|
-
/**
|
|
1963
|
-
* @license
|
|
1964
|
-
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
2621
|
+
* Copyright (c) 2021 - 2022 Vaadin Ltd.
|
|
1965
2622
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
1966
2623
|
*/
|
|
1967
2624
|
|
|
@@ -1998,4 +2655,4 @@ class VirtualKeyboardController {
|
|
|
1998
2655
|
}
|
|
1999
2656
|
}
|
|
2000
2657
|
|
|
2001
|
-
export {
|
|
2658
|
+
export { Overlay as O, PositionMixin as P, VirtualKeyboardController as V, OptionalMutableData as a, modelForElement as b, afterNextRender as c, menuOverlayCore as d, menuOverlay as m, overlay as o, templatize as t };
|