@everymatrix/general-input 1.44.0 → 1.45.2

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.
Files changed (139) hide show
  1. package/dist/cjs/app-globals-3a1e7e63.js +5 -0
  2. package/dist/cjs/checkbox-group-input_10.cjs.entry.js +3873 -1756
  3. package/dist/cjs/general-input.cjs.entry.js +65 -63
  4. package/dist/cjs/general-input.cjs.js +17 -11
  5. package/dist/cjs/index-8cb018cb.js +1316 -0
  6. package/dist/cjs/index.cjs.js +13 -13
  7. package/dist/cjs/loader.cjs.js +7 -13
  8. package/dist/cjs/locale.utils-76c75c40.js +147 -0
  9. package/dist/cjs/toggle-checkbox-input.cjs.entry.js +77 -78
  10. package/dist/collection/collection-manifest.json +14 -14
  11. package/dist/collection/components/checkbox-group-input/checkbox-group-input.js +368 -353
  12. package/dist/collection/components/checkbox-input/checkbox-input.js +325 -315
  13. package/dist/collection/components/date-input/date-input.css +2 -2
  14. package/dist/collection/components/date-input/date-input.js +397 -376
  15. package/dist/collection/components/email-input/email-input.css +7 -11
  16. package/dist/collection/components/email-input/email-input.js +404 -385
  17. package/dist/collection/components/general-input/general-input.js +373 -368
  18. package/dist/collection/components/general-input/index.js +1 -0
  19. package/dist/collection/components/number-input/number-input.js +370 -352
  20. package/dist/collection/components/password-input/password-input.css +2 -4
  21. package/dist/collection/components/password-input/password-input.js +513 -540
  22. package/dist/collection/components/radio-input/radio-input.js +301 -286
  23. package/dist/collection/components/select-input/select-input.css +8 -9
  24. package/dist/collection/components/select-input/select-input.js +427 -414
  25. package/dist/collection/components/tel-input/tel-input.css +1 -1
  26. package/dist/collection/components/tel-input/tel-input.js +440 -422
  27. package/dist/collection/components/text-input/text-input.css +0 -1
  28. package/dist/collection/components/text-input/text-input.js +444 -429
  29. package/dist/collection/components/toggle-checkbox-input/toggle-checkbox-input.js +327 -340
  30. package/dist/collection/index.js +13 -13
  31. package/dist/collection/utils/locale.utils.js +133 -133
  32. package/dist/collection/utils/utils.js +3 -3
  33. package/dist/esm/app-globals-0f993ce5.js +3 -0
  34. package/dist/esm/checkbox-group-input_10.entry.js +3873 -1756
  35. package/dist/esm/general-input.entry.js +65 -63
  36. package/dist/esm/general-input.js +14 -11
  37. package/dist/esm/index-514fda47.js +1287 -0
  38. package/dist/esm/index.js +13 -13
  39. package/dist/esm/loader.js +7 -13
  40. package/dist/esm/locale.utils-ca41bf95.js +144 -0
  41. package/dist/esm/toggle-checkbox-input.entry.js +77 -78
  42. package/dist/general-input/general-input.esm.js +1 -1
  43. package/dist/general-input/p-03e81c11.js +2 -0
  44. package/dist/general-input/p-aec71434.js +1 -0
  45. package/dist/general-input/p-e1255160.js +1 -0
  46. package/dist/general-input/p-eb454344.entry.js +1 -0
  47. package/dist/general-input/p-ecdc294b.entry.js +5430 -0
  48. package/dist/general-input/p-f92ab852.entry.js +1 -0
  49. package/dist/stencil.config.dev.js +17 -0
  50. package/dist/stencil.config.js +14 -19
  51. package/dist/types/Users/adrian.pripon/Documents/Work/widgets-monorepo/packages/stencil/general-input/.stencil/packages/stencil/general-input/stencil.config.d.ts +2 -0
  52. package/dist/types/Users/adrian.pripon/Documents/Work/widgets-monorepo/packages/stencil/general-input/.stencil/packages/stencil/general-input/stencil.config.dev.d.ts +2 -0
  53. package/dist/types/components/checkbox-group-input/checkbox-group-input.d.ts +68 -68
  54. package/dist/types/components/checkbox-input/checkbox-input.d.ts +61 -62
  55. package/dist/types/components/date-input/date-input.d.ts +78 -78
  56. package/dist/types/components/email-input/email-input.d.ts +77 -77
  57. package/dist/types/components/general-input/general-input.d.ts +72 -72
  58. package/dist/types/components/general-input/index.d.ts +1 -0
  59. package/dist/types/components/number-input/number-input.d.ts +71 -71
  60. package/dist/types/components/password-input/password-input.d.ts +87 -92
  61. package/dist/types/components/radio-input/radio-input.d.ts +55 -55
  62. package/dist/types/components/select-input/select-input.d.ts +79 -79
  63. package/dist/types/components/tel-input/tel-input.d.ts +85 -85
  64. package/dist/types/components/text-input/text-input.d.ts +81 -81
  65. package/dist/types/components/toggle-checkbox-input/toggle-checkbox-input.d.ts +63 -68
  66. package/dist/types/components.d.ts +201 -39
  67. package/dist/types/stencil-public-runtime.d.ts +142 -33
  68. package/dist/types/utils/locale.utils.d.ts +8 -8
  69. package/dist/types/utils/types.d.ts +54 -54
  70. package/loader/cdn.js +1 -3
  71. package/loader/index.cjs.js +1 -3
  72. package/loader/index.d.ts +13 -1
  73. package/loader/index.es2017.js +1 -3
  74. package/loader/index.js +1 -3
  75. package/loader/package.json +1 -0
  76. package/package.json +8 -1
  77. package/dist/cjs/index-132a0774.js +0 -1327
  78. package/dist/cjs/locale.utils-2fa6f747.js +0 -147
  79. package/dist/components/active-mixin.js +0 -975
  80. package/dist/components/checkbox-group-input.d.ts +0 -11
  81. package/dist/components/checkbox-group-input.js +0 -6
  82. package/dist/components/checkbox-group-input2.js +0 -1078
  83. package/dist/components/checkbox-input.d.ts +0 -11
  84. package/dist/components/checkbox-input.js +0 -6
  85. package/dist/components/checkbox-input2.js +0 -132
  86. package/dist/components/date-input.d.ts +0 -11
  87. package/dist/components/date-input.js +0 -6
  88. package/dist/components/date-input2.js +0 -11556
  89. package/dist/components/email-input.d.ts +0 -11
  90. package/dist/components/email-input.js +0 -6
  91. package/dist/components/email-input2.js +0 -171
  92. package/dist/components/field-mixin.js +0 -12426
  93. package/dist/components/general-input.d.ts +0 -11
  94. package/dist/components/general-input.js +0 -6
  95. package/dist/components/general-input2.js +0 -350
  96. package/dist/components/index.d.ts +0 -26
  97. package/dist/components/index.js +0 -18
  98. package/dist/components/input-field-shared-styles.js +0 -1211
  99. package/dist/components/number-input.d.ts +0 -11
  100. package/dist/components/number-input.js +0 -6
  101. package/dist/components/number-input2.js +0 -158
  102. package/dist/components/password-input.d.ts +0 -11
  103. package/dist/components/password-input.js +0 -6
  104. package/dist/components/password-input2.js +0 -1059
  105. package/dist/components/radio-input.d.ts +0 -11
  106. package/dist/components/radio-input.js +0 -6
  107. package/dist/components/radio-input2.js +0 -114
  108. package/dist/components/select-input.d.ts +0 -11
  109. package/dist/components/select-input.js +0 -6
  110. package/dist/components/select-input2.js +0 -183
  111. package/dist/components/tel-input.d.ts +0 -11
  112. package/dist/components/tel-input.js +0 -6
  113. package/dist/components/tel-input2.js +0 -197
  114. package/dist/components/text-input.d.ts +0 -11
  115. package/dist/components/text-input.js +0 -6
  116. package/dist/components/text-input2.js +0 -199
  117. package/dist/components/toggle-checkbox-input.d.ts +0 -11
  118. package/dist/components/toggle-checkbox-input.js +0 -6
  119. package/dist/components/tooltipIcon.js +0 -146
  120. package/dist/components/vaadin-button.js +0 -490
  121. package/dist/components/vaadin-combo-box.js +0 -4512
  122. package/dist/components/virtual-keyboard-controller.js +0 -2001
  123. package/dist/esm/index-db76d5b5.js +0 -1299
  124. package/dist/esm/locale.utils-30fb5289.js +0 -144
  125. package/dist/esm/polyfills/core-js.js +0 -11
  126. package/dist/esm/polyfills/css-shim.js +0 -1
  127. package/dist/esm/polyfills/dom.js +0 -79
  128. package/dist/esm/polyfills/es5-html-element.js +0 -1
  129. package/dist/esm/polyfills/index.js +0 -34
  130. package/dist/esm/polyfills/system.js +0 -6
  131. package/dist/general-input/p-04d4b145.js +0 -1
  132. package/dist/general-input/p-a8221ce9.entry.js +0 -1
  133. package/dist/general-input/p-b408093e.js +0 -1
  134. package/dist/general-input/p-b64caafa.entry.js +0 -3646
  135. package/dist/general-input/p-c85c0e4d.entry.js +0 -1
  136. package/dist/types/Users/adrian.pripon/Documents/Work/widgets-stencil/packages/general-input/.stencil/packages/general-input/stencil.config.d.ts +0 -2
  137. /package/dist/cjs/{tooltipIcon-092a795f.js → tooltipIcon-7e9ee226.js} +0 -0
  138. /package/dist/esm/{tooltipIcon-99c1c7b7.js → tooltipIcon-0a5a06a2.js} +0 -0
  139. /package/dist/general-input/{p-f4f4ccda.js → p-2dccd0bf.js} +0 -0
@@ -1,2001 +0,0 @@
1
- import { i, r as registerStyles, J as getDeepActiveElement, M as getFocusableElements, N as isElementFocused, H as ControllerMixin, O as getAncestorRootNodes } from './field-mixin.js';
2
- import { b as isIOS } from './input-field-shared-styles.js';
3
-
4
- /**
5
- * @license
6
- * Copyright (c) 2017 - 2023 Vaadin Ltd.
7
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
8
- */
9
-
10
- const overlay = i`
11
- :host {
12
- top: var(--lumo-space-m);
13
- right: var(--lumo-space-m);
14
- bottom: var(--lumo-space-m);
15
- left: var(--lumo-space-m);
16
- /* Workaround for Edge issue (only on Surface), where an overflowing vaadin-list-box inside vaadin-select-overlay makes the overlay transparent */
17
- /* stylelint-disable-next-line */
18
- outline: 0px solid transparent;
19
- }
20
-
21
- [part='overlay'] {
22
- background-color: var(--lumo-base-color);
23
- background-image: linear-gradient(var(--lumo-tint-5pct), var(--lumo-tint-5pct));
24
- border-radius: var(--lumo-border-radius-m);
25
- box-shadow: 0 0 0 1px var(--lumo-shade-5pct), var(--lumo-box-shadow-m);
26
- color: var(--lumo-body-text-color);
27
- font-family: var(--lumo-font-family);
28
- font-size: var(--lumo-font-size-m);
29
- font-weight: 400;
30
- line-height: var(--lumo-line-height-m);
31
- letter-spacing: 0;
32
- text-transform: none;
33
- -webkit-text-size-adjust: 100%;
34
- -webkit-font-smoothing: antialiased;
35
- -moz-osx-font-smoothing: grayscale;
36
- }
37
-
38
- [part='content'] {
39
- padding: var(--lumo-space-xs);
40
- }
41
-
42
- [part='backdrop'] {
43
- background-color: var(--lumo-shade-20pct);
44
- animation: 0.2s lumo-overlay-backdrop-enter both;
45
- will-change: opacity;
46
- }
47
-
48
- @keyframes lumo-overlay-backdrop-enter {
49
- 0% {
50
- opacity: 0;
51
- }
52
- }
53
-
54
- :host([closing]) [part='backdrop'] {
55
- animation: 0.2s lumo-overlay-backdrop-exit both;
56
- }
57
-
58
- @keyframes lumo-overlay-backdrop-exit {
59
- 100% {
60
- opacity: 0;
61
- }
62
- }
63
-
64
- @keyframes lumo-overlay-dummy-animation {
65
- 0% {
66
- opacity: 1;
67
- }
68
-
69
- 100% {
70
- opacity: 1;
71
- }
72
- }
73
- `;
74
-
75
- registerStyles('', overlay, { moduleId: 'lumo-overlay' });
76
-
77
- /**
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' });
184
-
185
- /**
186
- @license
187
- Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
188
- This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
189
- The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
190
- The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
191
- Code distributed by Google as part of the polymer project is also
192
- subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
193
- */
194
-
195
- let scheduled = false;
196
- let beforeRenderQueue = [];
197
- let afterRenderQueue = [];
198
-
199
- function schedule() {
200
- scheduled = true;
201
- // before next render
202
- requestAnimationFrame(function() {
203
- scheduled = false;
204
- flushQueue(beforeRenderQueue);
205
- // after the render
206
- setTimeout(function() {
207
- runQueue(afterRenderQueue);
208
- });
209
- });
210
- }
211
-
212
- function flushQueue(queue) {
213
- while (queue.length) {
214
- callMethod(queue.shift());
215
- }
216
- }
217
-
218
- function runQueue(queue) {
219
- for (let i=0, l=queue.length; i < l; i++) {
220
- callMethod(queue.shift());
221
- }
222
- }
223
-
224
- function callMethod(info) {
225
- const context = info[0];
226
- const callback = info[1];
227
- const args = info[2];
228
- try {
229
- callback.apply(context, args);
230
- } catch(e) {
231
- setTimeout(() => {
232
- throw e;
233
- });
234
- }
235
- }
236
-
237
- /**
238
- * Enqueues a callback which will be run after the next render, equivalent
239
- * to one task (`setTimeout`) after the next `requestAnimationFrame`.
240
- *
241
- * This method is useful for tuning the first-render performance of an
242
- * element or application by deferring non-critical work until after the
243
- * first paint. Typical non-render-critical work may include adding UI
244
- * event listeners and aria attributes.
245
- *
246
- * @param {*} context Context object the callback function will be bound to
247
- * @param {function(...*):void} callback Callback function
248
- * @param {!Array=} args An array of arguments to call the callback function with
249
- * @return {void}
250
- */
251
- function afterNextRender(context, callback, args) {
252
- if (!scheduled) {
253
- schedule();
254
- }
255
- afterRenderQueue.push([context, callback, args]);
256
- }
257
-
258
- /**
259
- * @license
260
- * Copyright (c) 2017 Anton Korzunov
261
- * SPDX-License-Identifier: MIT
262
- */
263
-
264
- /**
265
- * @fileoverview
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 = {};
279
-
280
- /** @type {number} */
281
- let lockCount = 0;
282
-
283
- /**
284
- * @param {?Node} node
285
- * @return {boolean}
286
- */
287
- const isElement = (node) => node && node.nodeType === Node.ELEMENT_NODE;
288
-
289
- /**
290
- * @param {...unknown} args
291
- */
292
- const logError = (...args) => {
293
- console.error(`Error: ${args.join(' ')}. Skip setting aria-hidden.`);
294
- };
295
-
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
- }
306
-
307
- return targets
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
- }
321
-
322
- logError(target, 'is not contained inside', parent);
323
- return null;
324
- })
325
- .filter((x) => Boolean(x));
326
- };
327
-
328
- /**
329
- * Marks everything except given node(or nodes) as aria-hidden
330
- * @param {Element | Element[]} originalTarget - elements to keep on the page
331
- * @param {HTMLElement} [parentNode] - top element, defaults to document.body
332
- * @param {String} [markerName] - a special attribute to mark every node
333
- * @param {String} [controlAttribute] - html Attribute to control
334
- * @return {Function}
335
- */
336
- const applyAttributeToOthers = (originalTarget, parentNode, markerName, controlAttribute) => {
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);
353
-
354
- /**
355
- * @param {?Node} el
356
- */
357
- const keep = (el) => {
358
- if (!el || elementsToKeep.has(el)) {
359
- return;
360
- }
361
-
362
- elementsToKeep.add(el);
363
-
364
- const slot = el.assignedSlot;
365
- if (slot) {
366
- keep(slot);
367
- }
368
-
369
- keep(el.parentNode || el.host);
370
- };
371
-
372
- targets.forEach(keep);
373
-
374
- /**
375
- * @param {?Node} el
376
- */
377
- const deep = (parent) => {
378
- if (!parent || elementsToStop.has(parent)) {
379
- return;
380
- }
381
-
382
- const root = parent.shadowRoot;
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
- }
405
-
406
- if (markerValue === 1) {
407
- node.setAttribute(markerName, 'true');
408
- }
409
-
410
- if (!alreadyHidden) {
411
- node.setAttribute(controlAttribute, 'true');
412
- }
413
- }
414
- });
415
- };
416
-
417
- deep(parentNode);
418
-
419
- elementsToKeep.clear();
420
-
421
- lockCount += 1;
422
-
423
- return () => {
424
- hiddenNodes.forEach((node) => {
425
- const counterValue = counterMap.get(node) - 1;
426
- const markerValue = markerCounter.get(node) - 1;
427
-
428
- counterMap.set(node, counterValue);
429
- markerCounter.set(node, markerValue);
430
-
431
- if (!counterValue) {
432
- if (uncontrolledNodes.has(node)) {
433
- uncontrolledNodes.delete(node);
434
- } else {
435
- node.removeAttribute(controlAttribute);
436
- }
437
- }
438
-
439
- if (!markerValue) {
440
- node.removeAttribute(markerName);
441
- }
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
- }
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]')));
469
- }
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
- */
479
-
480
- /**
481
- * A controller for handling modal state on the elements with `dialog` and `alertdialog` role.
482
- * See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-modal
483
- *
484
- * Note, the actual `role` and `aria-modal` attributes are supposed to be handled by the
485
- * consumer web component. This is done in to ensure the controller only does one thing.
486
- */
487
- class AriaModalController {
488
- /**
489
- * @param {HTMLElement} host
490
- */
491
- constructor(host, callback) {
492
- /**
493
- * The controller host element.
494
- *
495
- * @type {HTMLElement}
496
- */
497
- this.host = host;
498
-
499
- /**
500
- * The callback used to detect which element
501
- * to use as a target. Defaults to the host.
502
- *
503
- * @type {Function}
504
- */
505
- this.callback = typeof callback === 'function' ? callback : () => host;
506
- }
507
-
508
- /**
509
- * Make the controller host modal by hiding other elements from screen readers
510
- * using `aria-hidden` attribute (can be replaced with `inert` in the future).
511
- *
512
- * The method name is chosen to align with the one provided by native `<dialog>`:
513
- * https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal
514
- */
515
- showModal() {
516
- const targets = this.callback();
517
- this.__showOthers = hideOthers(targets);
518
- }
519
-
520
- /**
521
- * Remove `aria-hidden` from other elements unless there are any other
522
- * controller hosts on the page activated by using `showModal()` call.
523
- */
524
- close() {
525
- if (this.__showOthers) {
526
- this.__showOthers();
527
- this.__showOthers = null;
528
- }
529
- }
530
- }
531
-
532
- /**
533
- * @license
534
- * Copyright (c) 2021 - 2023 Vaadin Ltd.
535
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
536
- */
537
-
538
- /**
539
- * A controller for saving a focused node and restoring focus to it later.
540
- */
541
- class FocusRestorationController {
542
- /**
543
- * Saves the given node as a target for restoring focus to
544
- * when `restoreFocus()` is called. If no node is provided,
545
- * the currently focused node in the DOM is saved as a target.
546
- *
547
- * @param {Node | null | undefined} focusNode
548
- */
549
- saveFocus(focusNode) {
550
- this.focusNode = focusNode || getDeepActiveElement();
551
- }
552
-
553
- /**
554
- * Restores focus to the target node that was saved previously with `saveFocus()`.
555
- */
556
- restoreFocus() {
557
- const focusNode = this.focusNode;
558
- if (!focusNode) {
559
- return;
560
- }
561
-
562
- if (getDeepActiveElement() === document.body) {
563
- // In Firefox and Safari, focusing the node synchronously
564
- // doesn't work as expected when the overlay is closing on outside click.
565
- // These browsers force focus to move to the body element and retain it
566
- // there until the next event loop iteration.
567
- setTimeout(() => focusNode.focus());
568
- } else {
569
- focusNode.focus();
570
- }
571
-
572
- this.focusNode = null;
573
- }
574
- }
575
-
576
- /**
577
- * @license
578
- * Copyright (c) 2021 - 2023 Vaadin Ltd.
579
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
580
- */
581
-
582
- const instances = [];
583
-
584
- /**
585
- * A controller for trapping focus within a DOM node.
586
- */
587
- class FocusTrapController {
588
- /**
589
- * @param {HTMLElement} host
590
- */
591
- constructor(host) {
592
- /**
593
- * The controller host element.
594
- *
595
- * @type {HTMLElement}
596
- */
597
- this.host = host;
598
-
599
- /**
600
- * A node for trapping focus in.
601
- *
602
- * @type {HTMLElement | null}
603
- * @private
604
- */
605
- this.__trapNode = null;
606
-
607
- this.__onKeyDown = this.__onKeyDown.bind(this);
608
- }
609
-
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
- hostConnected() {
632
- document.addEventListener('keydown', this.__onKeyDown);
633
- }
634
-
635
- hostDisconnected() {
636
- document.removeEventListener('keydown', this.__onKeyDown);
637
- }
638
-
639
- /**
640
- * Activates a focus trap for a DOM node that will prevent focus from escaping the node.
641
- * The trap can be deactivated with the `.releaseFocus()` method.
642
- *
643
- * If focus is initially outside the trap, the method will move focus inside,
644
- * on the first focusable element of the trap in the tab order.
645
- * The first focusable element can be the trap node itself if it is focusable
646
- * and comes first in the tab order.
647
- *
648
- * If there are no focusable elements, the method will throw an exception
649
- * and the trap will not be set.
650
- *
651
- * @param {HTMLElement} trapNode
652
- */
653
- trapFocus(trapNode) {
654
- this.__trapNode = trapNode;
655
-
656
- if (this.__focusableElements.length === 0) {
657
- this.__trapNode = null;
658
- throw new Error('The trap node should have at least one focusable descendant or be focusable itself.');
659
- }
660
-
661
- instances.push(this);
662
-
663
- if (this.__focusedElementIndex === -1) {
664
- this.__focusableElements[0].focus();
665
- }
666
- }
667
-
668
- /**
669
- * Deactivates the focus trap set with the `.trapFocus()` method
670
- * so that it becomes possible to tab outside the trap node.
671
- */
672
- releaseFocus() {
673
- this.__trapNode = null;
674
-
675
- instances.pop();
676
- }
677
-
678
- /**
679
- * A `keydown` event handler that manages tabbing navigation when the trap is enabled.
680
- *
681
- * - Moves focus to the next focusable element of the trap on `Tab` press.
682
- * When no next element to focus, the method moves focus to the first focusable element.
683
- * - Moves focus to the prev focusable element of the trap on `Shift+Tab` press.
684
- * When no prev element to focus, the method moves focus to the last focusable element.
685
- *
686
- * @param {KeyboardEvent} event
687
- * @private
688
- */
689
- __onKeyDown(event) {
690
- if (!this.__trapNode) {
691
- return;
692
- }
693
-
694
- // Only handle events for the last instance
695
- if (this !== Array.from(instances).pop()) {
696
- return;
697
- }
698
-
699
- if (event.key === 'Tab') {
700
- event.preventDefault();
701
-
702
- const backward = event.shiftKey;
703
- this.__focusNextElement(backward);
704
- }
705
- }
706
-
707
- /**
708
- * - Moves focus to the next focusable element if `backward === false`.
709
- * When no next element to focus, the method moves focus to the first focusable element.
710
- * - Moves focus to the prev focusable element if `backward === true`.
711
- * When no prev element to focus the method moves focus to the last focusable element.
712
- *
713
- * If no focusable elements, the method returns immediately.
714
- *
715
- * @param {boolean} backward
716
- * @private
717
- */
718
- __focusNextElement(backward = false) {
719
- const focusableElements = this.__focusableElements;
720
- const step = backward ? -1 : 1;
721
- const currentIndex = this.__focusedElementIndex;
722
- const nextIndex = (focusableElements.length + currentIndex + step) % focusableElements.length;
723
- const element = focusableElements[nextIndex];
724
- element.focus();
725
- if (element.localName === 'input') {
726
- element.select();
727
- }
728
- }
729
- }
730
-
731
- /**
732
- * @license
733
- * Copyright (c) 2017 - 2023 Vaadin Ltd.
734
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
735
- */
736
-
737
- /**
738
- * @polymerMixin
739
- * @mixes ControllerMixin
740
- */
741
- const OverlayFocusMixin = (superClass) =>
742
- class OverlayFocusMixin extends ControllerMixin(superClass) {
743
- static get properties() {
744
- return {
745
- /**
746
- * When true, opening the overlay moves focus to the first focusable child,
747
- * or to the overlay part with tabindex if there are no focusable children.
748
- * @attr {boolean} focus-trap
749
- */
750
- focusTrap: {
751
- type: Boolean,
752
- value: false,
753
- },
754
-
755
- /**
756
- * Set to true to enable restoring of focus when overlay is closed.
757
- * @attr {boolean} restore-focus-on-close
758
- */
759
- restoreFocusOnClose: {
760
- type: Boolean,
761
- value: false,
762
- },
763
-
764
- /**
765
- * Set to specify the element which should be focused on overlay close,
766
- * if `restoreFocusOnClose` is set to true.
767
- * @type {HTMLElement}
768
- */
769
- restoreFocusNode: {
770
- type: HTMLElement,
771
- },
772
- };
773
- }
774
-
775
- constructor() {
776
- super();
777
-
778
- this.__ariaModalController = new AriaModalController(this);
779
- this.__focusTrapController = new FocusTrapController(this);
780
- this.__focusRestorationController = new FocusRestorationController();
781
- }
782
-
783
- /** @protected */
784
- ready() {
785
- super.ready();
786
-
787
- this.addController(this.__ariaModalController);
788
- this.addController(this.__focusTrapController);
789
- this.addController(this.__focusRestorationController);
790
- }
791
-
792
- /**
793
- * Release focus and restore focus after the overlay is closed.
794
- *
795
- * @protected
796
- */
797
- _resetFocus() {
798
- if (this.focusTrap) {
799
- this.__ariaModalController.close();
800
- this.__focusTrapController.releaseFocus();
801
- }
802
-
803
- if (this.restoreFocusOnClose && this._shouldRestoreFocus()) {
804
- this.__focusRestorationController.restoreFocus();
805
- }
806
- }
807
-
808
- /**
809
- * Save the previously focused node when the overlay starts to open.
810
- *
811
- * @protected
812
- */
813
- _saveFocus() {
814
- if (this.restoreFocusOnClose) {
815
- this.__focusRestorationController.saveFocus(this.restoreFocusNode);
816
- }
817
- }
818
-
819
- /**
820
- * Trap focus within the overlay after opening has completed.
821
- *
822
- * @protected
823
- */
824
- _trapFocus() {
825
- if (this.focusTrap) {
826
- this.__ariaModalController.showModal();
827
- this.__focusTrapController.trapFocus(this.$.overlay);
828
- }
829
- }
830
-
831
- /**
832
- * Returns true if focus is still inside the overlay or on the body element,
833
- * otherwise false.
834
- *
835
- * Focus shouldn't be restored if it's been moved elsewhere by another
836
- * component or as a result of a user interaction e.g. the user clicked
837
- * on a button outside the overlay while the overlay was open.
838
- *
839
- * @protected
840
- * @return {boolean}
841
- */
842
- _shouldRestoreFocus() {
843
- const activeElement = getDeepActiveElement();
844
- return activeElement === document.body || this._deepContains(activeElement);
845
- }
846
-
847
- /**
848
- * Returns true if the overlay contains the given node,
849
- * including those within shadow DOM trees.
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
- };
868
-
869
- /**
870
- * @license
871
- * Copyright (c) 2017 - 2023 Vaadin Ltd.
872
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
873
- */
874
-
875
- /**
876
- * Returns all attached overlays in visual stacking order.
877
- * @private
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);
883
-
884
- /**
885
- * Returns true if the overlay is the last one in the opened overlays stack.
886
- * @param {HTMLElement} overlay
887
- * @return {boolean}
888
- * @protected
889
- */
890
- const isLastOverlay = (overlay) => overlay === getAttachedInstances().pop();
891
-
892
- /**
893
- * @polymerMixin
894
- */
895
- const OverlayStackMixin = (superClass) =>
896
- class OverlayStackMixin extends superClass {
897
- constructor() {
898
- super();
899
-
900
- this._hasOverlayStackMixin = true;
901
- }
902
-
903
- /**
904
- * Returns true if this is the last one in the opened overlays stack.
905
- *
906
- * @return {boolean}
907
- * @protected
908
- */
909
- get _last() {
910
- return isLastOverlay(this);
911
- }
912
-
913
- /**
914
- * Brings the overlay as visually the frontmost one.
915
- */
916
- bringToFront() {
917
- let zIndex = '';
918
- const frontmost = getAttachedInstances()
919
- .filter((o) => o !== this)
920
- .pop();
921
- if (frontmost) {
922
- const frontmostZIndex = frontmost.__zIndex;
923
- zIndex = frontmostZIndex + 1;
924
- }
925
- this.style.zIndex = zIndex;
926
- this.__zIndex = zIndex || parseFloat(getComputedStyle(this).zIndex);
927
- }
928
-
929
- /** @protected */
930
- _enterModalState() {
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
- }
937
-
938
- // Disable pointer events in other attached overlays
939
- getAttachedInstances().forEach((el) => {
940
- if (el !== this) {
941
- el.$.overlay.style.pointerEvents = 'none';
942
- }
943
- });
944
- }
945
-
946
- /** @protected */
947
- _exitModalState() {
948
- if (this._previousDocumentPointerEvents !== undefined) {
949
- // Restore body pointer-events
950
- document.body.style.pointerEvents = this._previousDocumentPointerEvents;
951
- delete this._previousDocumentPointerEvents;
952
- }
953
-
954
- // Restore pointer events in the previous overlay(s)
955
- const instances = getAttachedInstances();
956
-
957
- let el;
958
- // Use instances.pop() to ensure the reverse order
959
- while ((el = instances.pop())) {
960
- if (el === this) {
961
- // Skip the current instance
962
- continue;
963
- }
964
- el.$.overlay.style.removeProperty('pointer-events');
965
- if (!el.modeless) {
966
- // Stop after the last modal
967
- break;
968
- }
969
- }
970
- }
971
- };
972
-
973
- /**
974
- * @license
975
- * Copyright (c) 2017 - 2023 Vaadin Ltd.
976
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
977
- */
978
-
979
- /**
980
- * @polymerMixin
981
- * @mixes OverlayFocusMixin
982
- * @mixes OverlayStackMixin
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
- },
997
-
998
- /**
999
- * Owner element passed with renderer function
1000
- * @type {HTMLElement}
1001
- */
1002
- owner: {
1003
- type: Object,
1004
- },
1005
-
1006
- /**
1007
- * Object with properties that is passed to `renderer` function
1008
- */
1009
- model: {
1010
- type: Object,
1011
- },
1012
-
1013
- /**
1014
- * Custom function for rendering the content of the overlay.
1015
- * Receives three arguments:
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
- },
1025
-
1026
- /**
1027
- * When true the overlay won't disable the main content, showing
1028
- * it doesn't change the functionality of the user interface.
1029
- * @type {boolean}
1030
- */
1031
- modeless: {
1032
- type: Boolean,
1033
- value: false,
1034
- reflectToAttribute: true,
1035
- observer: '_modelessChanged',
1036
- },
1037
-
1038
- /**
1039
- * When set to true, the overlay is hidden. This also closes the overlay
1040
- * immediately in case there is a closing animation in progress.
1041
- * @type {boolean}
1042
- */
1043
- hidden: {
1044
- type: Boolean,
1045
- reflectToAttribute: true,
1046
- observer: '_hiddenChanged',
1047
- },
1048
-
1049
- /**
1050
- * When true the overlay has backdrop on top of content when opened.
1051
- * @type {boolean}
1052
- */
1053
- withBackdrop: {
1054
- type: Boolean,
1055
- value: false,
1056
- reflectToAttribute: true,
1057
- },
1058
- };
1059
- }
1060
-
1061
- static get observers() {
1062
- return ['_rendererOrDataChanged(renderer, owner, model, opened)'];
1063
- }
1064
-
1065
- constructor() {
1066
- super();
1067
-
1068
- this._boundMouseDownListener = this._mouseDownListener.bind(this);
1069
- this._boundMouseUpListener = this._mouseUpListener.bind(this);
1070
- this._boundOutsideClickListener = this._outsideClickListener.bind(this);
1071
- this._boundKeydownListener = this._keydownListener.bind(this);
1072
-
1073
- /* c8 ignore next 3 */
1074
- if (isIOS) {
1075
- this._boundIosResizeListener = () => this._detectIosNavbar();
1076
- }
1077
- }
1078
-
1079
- /** @protected */
1080
- ready() {
1081
- super.ready();
1082
-
1083
- // Need to add dummy click listeners to this and the backdrop or else
1084
- // the document click event listener (_outsideClickListener) may never
1085
- // get invoked on iOS Safari (reproducible in <vaadin-dialog>
1086
- // and <vaadin-context-menu>).
1087
- this.addEventListener('click', () => {});
1088
- this.$.backdrop.addEventListener('click', () => {});
1089
- }
1090
-
1091
- /** @protected */
1092
- connectedCallback() {
1093
- super.connectedCallback();
1094
-
1095
- /* c8 ignore next 3 */
1096
- if (this._boundIosResizeListener) {
1097
- this._detectIosNavbar();
1098
- window.addEventListener('resize', this._boundIosResizeListener);
1099
- }
1100
- }
1101
-
1102
- /** @protected */
1103
- disconnectedCallback() {
1104
- super.disconnectedCallback();
1105
-
1106
- /* c8 ignore next 3 */
1107
- if (this._boundIosResizeListener) {
1108
- window.removeEventListener('resize', this._boundIosResizeListener);
1109
- }
1110
- }
1111
-
1112
- /**
1113
- * Requests an update for the content of the overlay.
1114
- * While performing the update, it invokes the renderer passed in the `renderer` property.
1115
- *
1116
- * It is not guaranteed that the update happens immediately (synchronously) after it is requested.
1117
- */
1118
- requestContentUpdate() {
1119
- if (this.renderer) {
1120
- this.renderer.call(this.owner, this, this.owner, this.model);
1121
- }
1122
- }
1123
-
1124
- /**
1125
- * @param {Event=} sourceEvent
1126
- */
1127
- close(sourceEvent) {
1128
- const evt = new CustomEvent('vaadin-overlay-close', {
1129
- bubbles: true,
1130
- cancelable: true,
1131
- detail: { sourceEvent },
1132
- });
1133
- this.dispatchEvent(evt);
1134
- if (!evt.defaultPrevented) {
1135
- this.opened = false;
1136
- }
1137
- }
1138
-
1139
- /** @private */
1140
- _detectIosNavbar() {
1141
- /* c8 ignore next 15 */
1142
- if (!this.opened) {
1143
- return;
1144
- }
1145
-
1146
- const innerHeight = window.innerHeight;
1147
- const innerWidth = window.innerWidth;
1148
-
1149
- const landscape = innerWidth > innerHeight;
1150
-
1151
- const clientHeight = document.documentElement.clientHeight;
1152
-
1153
- if (landscape && clientHeight > innerHeight) {
1154
- this.style.setProperty('--vaadin-overlay-viewport-bottom', `${clientHeight - innerHeight}px`);
1155
- } else {
1156
- this.style.setProperty('--vaadin-overlay-viewport-bottom', '0');
1157
- }
1158
- }
1159
-
1160
- /** @private */
1161
- _addGlobalListeners() {
1162
- document.addEventListener('mousedown', this._boundMouseDownListener);
1163
- document.addEventListener('mouseup', this._boundMouseUpListener);
1164
- // Firefox leaks click to document on contextmenu even if prevented
1165
- // https://bugzilla.mozilla.org/show_bug.cgi?id=990614
1166
- document.documentElement.addEventListener('click', this._boundOutsideClickListener, true);
1167
- }
1168
-
1169
- /** @private */
1170
- _removeGlobalListeners() {
1171
- document.removeEventListener('mousedown', this._boundMouseDownListener);
1172
- document.removeEventListener('mouseup', this._boundMouseUpListener);
1173
- document.documentElement.removeEventListener('click', this._boundOutsideClickListener, true);
1174
- }
1175
-
1176
- /** @private */
1177
- _rendererOrDataChanged(renderer, owner, model, opened) {
1178
- const ownerOrModelChanged = this._oldOwner !== owner || this._oldModel !== model;
1179
- this._oldModel = model;
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$;
1194
- }
1195
-
1196
- if (opened && renderer && (rendererChanged || openedChanged || ownerOrModelChanged)) {
1197
- this.requestContentUpdate();
1198
- }
1199
- }
1200
-
1201
- /** @private */
1202
- _modelessChanged(modeless) {
1203
- if (!modeless) {
1204
- if (this.opened) {
1205
- this._addGlobalListeners();
1206
- this._enterModalState();
1207
- }
1208
- } else {
1209
- this._removeGlobalListeners();
1210
- this._exitModalState();
1211
- }
1212
- }
1213
-
1214
- /** @private */
1215
- _openedChanged(opened, wasOpened) {
1216
- if (opened) {
1217
- this._saveFocus();
1218
-
1219
- this._animatedOpening();
1220
-
1221
- afterNextRender(this, () => {
1222
- this._trapFocus();
1223
-
1224
- const evt = new CustomEvent('vaadin-overlay-open', { bubbles: true });
1225
- this.dispatchEvent(evt);
1226
- });
1227
-
1228
- document.addEventListener('keydown', this._boundKeydownListener);
1229
-
1230
- if (!this.modeless) {
1231
- this._addGlobalListeners();
1232
- }
1233
- } else if (wasOpened) {
1234
- this._resetFocus();
1235
-
1236
- this._animatedClosing();
1237
-
1238
- document.removeEventListener('keydown', this._boundKeydownListener);
1239
-
1240
- if (!this.modeless) {
1241
- this._removeGlobalListeners();
1242
- }
1243
- }
1244
- }
1245
-
1246
- /** @private */
1247
- _hiddenChanged(hidden) {
1248
- if (hidden && this.hasAttribute('closing')) {
1249
- this._flushAnimation('closing');
1250
- }
1251
- }
1252
-
1253
- /**
1254
- * @return {boolean}
1255
- * @private
1256
- */
1257
- _shouldAnimate() {
1258
- const style = getComputedStyle(this);
1259
- const name = style.getPropertyValue('animation-name');
1260
- const hidden = style.getPropertyValue('display') === 'none';
1261
- return !hidden && name && name !== 'none';
1262
- }
1263
-
1264
- /**
1265
- * @param {string} type
1266
- * @param {Function} callback
1267
- * @private
1268
- */
1269
- _enqueueAnimation(type, callback) {
1270
- const handler = `__${type}Handler`;
1271
- const listener = (event) => {
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);
1281
- }
1282
-
1283
- /**
1284
- * @param {string} type
1285
- * @protected
1286
- */
1287
- _flushAnimation(type) {
1288
- const handler = `__${type}Handler`;
1289
- if (typeof this[handler] === 'function') {
1290
- this[handler]();
1291
- }
1292
- }
1293
-
1294
- /** @private */
1295
- _animatedOpening() {
1296
- if (this.parentNode === document.body && this.hasAttribute('closing')) {
1297
- this._flushAnimation('closing');
1298
- }
1299
- this._attachOverlay();
1300
- if (!this.modeless) {
1301
- this._enterModalState();
1302
- }
1303
- this.setAttribute('opening', '');
1304
-
1305
- if (this._shouldAnimate()) {
1306
- this._enqueueAnimation('opening', () => {
1307
- this._finishOpening();
1308
- });
1309
- } else {
1310
- this._finishOpening();
1311
- }
1312
- }
1313
-
1314
- /** @private */
1315
- _attachOverlay() {
1316
- this._placeholder = document.createComment('vaadin-overlay-placeholder');
1317
- this.parentNode.insertBefore(this._placeholder, this);
1318
- document.body.appendChild(this);
1319
- this.bringToFront();
1320
- }
1321
-
1322
- /** @private */
1323
- _finishOpening() {
1324
- this.removeAttribute('opening');
1325
- }
1326
-
1327
- /** @private */
1328
- _finishClosing() {
1329
- this._detachOverlay();
1330
- this.$.overlay.style.removeProperty('pointer-events');
1331
- this.removeAttribute('closing');
1332
- this.dispatchEvent(new CustomEvent('vaadin-overlay-closed'));
1333
- }
1334
-
1335
- /** @private */
1336
- _animatedClosing() {
1337
- if (this.hasAttribute('opening')) {
1338
- this._flushAnimation('opening');
1339
- }
1340
- if (this._placeholder) {
1341
- this._exitModalState();
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
- }
1353
- }
1354
-
1355
- /** @private */
1356
- _detachOverlay() {
1357
- this._placeholder.parentNode.insertBefore(this, this._placeholder);
1358
- this._placeholder.parentNode.removeChild(this._placeholder);
1359
- }
1360
-
1361
- /** @private */
1362
- _mouseDownListener(event) {
1363
- this._mouseDownInside = event.composedPath().indexOf(this.$.overlay) >= 0;
1364
- }
1365
-
1366
- /** @private */
1367
- _mouseUpListener(event) {
1368
- this._mouseUpInside = event.composedPath().indexOf(this.$.overlay) >= 0;
1369
- }
1370
-
1371
- /**
1372
- * Whether to close the overlay on outside click or not.
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;
1381
- }
1382
-
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
- }
1396
-
1397
- if (!this._shouldCloseOnOutsideClick(event)) {
1398
- return;
1399
- }
1400
-
1401
- const evt = new CustomEvent('vaadin-overlay-outside-click', {
1402
- bubbles: true,
1403
- cancelable: true,
1404
- detail: { sourceEvent: event },
1405
- });
1406
- this.dispatchEvent(evt);
1407
-
1408
- if (this.opened && !evt.defaultPrevented) {
1409
- this.close(event);
1410
- }
1411
- }
1412
-
1413
- /**
1414
- * Listener used to close whe overlay on Escape press, if it is the last one.
1415
- * @private
1416
- */
1417
- _keydownListener(event) {
1418
- if (!this._last) {
1419
- return;
1420
- }
1421
-
1422
- // Only close modeless overlay on Esc press when it contains focus
1423
- if (this.modeless && !event.composedPath().includes(this.$.overlay)) {
1424
- return;
1425
- }
1426
-
1427
- if (event.key === 'Escape') {
1428
- const evt = new CustomEvent('vaadin-overlay-escape-press', {
1429
- bubbles: true,
1430
- cancelable: true,
1431
- detail: { sourceEvent: event },
1432
- });
1433
- this.dispatchEvent(evt);
1434
-
1435
- if (this.opened && !evt.defaultPrevented) {
1436
- this.close(event);
1437
- }
1438
- }
1439
- }
1440
- };
1441
-
1442
- /**
1443
- * @license
1444
- * Copyright (c) 2017 - 2023 Vaadin Ltd.
1445
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
1446
- */
1447
-
1448
- const PROP_NAMES_VERTICAL = {
1449
- start: 'top',
1450
- end: 'bottom',
1451
- };
1452
-
1453
- const PROP_NAMES_HORIZONTAL = {
1454
- start: 'left',
1455
- end: 'right',
1456
- };
1457
-
1458
- const targetResizeObserver = new ResizeObserver((entries) => {
1459
- setTimeout(() => {
1460
- entries.forEach((entry) => {
1461
- if (entry.target.__overlay) {
1462
- entry.target.__overlay._updatePosition();
1463
- }
1464
- });
1465
- });
1466
- });
1467
-
1468
- /**
1469
- * @polymerMixin
1470
- */
1471
- const PositionMixin = (superClass) =>
1472
- class PositionMixin extends superClass {
1473
- static get properties() {
1474
- return {
1475
- /**
1476
- * The element next to which this overlay should be aligned.
1477
- * The position of the overlay relative to the positionTarget can be adjusted
1478
- * with properties `horizontalAlign`, `verticalAlign`, `noHorizontalOverlap`
1479
- * and `noVerticalOverlap`.
1480
- */
1481
- positionTarget: {
1482
- type: Object,
1483
- value: null,
1484
- },
1485
-
1486
- /**
1487
- * When `positionTarget` is set, this property defines whether to align the overlay's
1488
- * left or right side to the target element by default.
1489
- * Possible values are `start` and `end`.
1490
- * RTL is taken into account when interpreting the value.
1491
- * The overlay is automatically flipped to the opposite side when it doesn't fit into
1492
- * the default side defined by this property.
1493
- *
1494
- * @attr {start|end} horizontal-align
1495
- */
1496
- horizontalAlign: {
1497
- type: String,
1498
- value: 'start',
1499
- },
1500
-
1501
- /**
1502
- * When `positionTarget` is set, this property defines whether to align the overlay's
1503
- * top or bottom side to the target element by default.
1504
- * Possible values are `top` and `bottom`.
1505
- * The overlay is automatically flipped to the opposite side when it doesn't fit into
1506
- * the default side defined by this property.
1507
- *
1508
- * @attr {top|bottom} vertical-align
1509
- */
1510
- verticalAlign: {
1511
- type: String,
1512
- value: 'top',
1513
- },
1514
-
1515
- /**
1516
- * When `positionTarget` is set, this property defines whether the overlay should overlap
1517
- * the target element in the x-axis, or be positioned right next to it.
1518
- *
1519
- * @attr {boolean} no-horizontal-overlap
1520
- */
1521
- noHorizontalOverlap: {
1522
- type: Boolean,
1523
- value: false,
1524
- },
1525
-
1526
- /**
1527
- * When `positionTarget` is set, this property defines whether the overlay should overlap
1528
- * the target element in the y-axis, or be positioned right above/below it.
1529
- *
1530
- * @attr {boolean} no-vertical-overlap
1531
- */
1532
- noVerticalOverlap: {
1533
- type: Boolean,
1534
- value: false,
1535
- },
1536
-
1537
- /**
1538
- * If the overlay content has no intrinsic height, this property can be used to set
1539
- * the minimum vertical space (in pixels) required by the overlay. Setting a value to
1540
- * the property effectively disables the content measurement in favor of using this
1541
- * fixed value for determining the open direction.
1542
- *
1543
- * @attr {number} required-vertical-space
1544
- */
1545
- requiredVerticalSpace: {
1546
- type: Number,
1547
- value: 0,
1548
- },
1549
- };
1550
- }
1551
-
1552
- static get observers() {
1553
- return [
1554
- '__positionSettingsChanged(horizontalAlign, verticalAlign, noHorizontalOverlap, noVerticalOverlap, requiredVerticalSpace)',
1555
- '__overlayOpenedChanged(opened, positionTarget)',
1556
- ];
1557
- }
1558
-
1559
- constructor() {
1560
- super();
1561
-
1562
- this.__onScroll = this.__onScroll.bind(this);
1563
- this._updatePosition = this._updatePosition.bind(this);
1564
- }
1565
-
1566
- /** @protected */
1567
- connectedCallback() {
1568
- super.connectedCallback();
1569
-
1570
- if (this.opened) {
1571
- this.__addUpdatePositionEventListeners();
1572
- }
1573
- }
1574
-
1575
- /** @protected */
1576
- disconnectedCallback() {
1577
- super.disconnectedCallback();
1578
- this.__removeUpdatePositionEventListeners();
1579
- }
1580
-
1581
- /** @private */
1582
- __addUpdatePositionEventListeners() {
1583
- window.addEventListener('resize', this._updatePosition);
1584
-
1585
- this.__positionTargetAncestorRootNodes = getAncestorRootNodes(this.positionTarget);
1586
- this.__positionTargetAncestorRootNodes.forEach((node) => {
1587
- node.addEventListener('scroll', this.__onScroll, true);
1588
- });
1589
- }
1590
-
1591
- /** @private */
1592
- __removeUpdatePositionEventListeners() {
1593
- window.removeEventListener('resize', this._updatePosition);
1594
-
1595
- if (this.__positionTargetAncestorRootNodes) {
1596
- this.__positionTargetAncestorRootNodes.forEach((node) => {
1597
- node.removeEventListener('scroll', this.__onScroll, true);
1598
- });
1599
- this.__positionTargetAncestorRootNodes = null;
1600
- }
1601
- }
1602
-
1603
- /** @private */
1604
- __overlayOpenedChanged(opened, positionTarget) {
1605
- this.__removeUpdatePositionEventListeners();
1606
-
1607
- if (positionTarget) {
1608
- positionTarget.__overlay = null;
1609
- targetResizeObserver.unobserve(positionTarget);
1610
-
1611
- if (opened) {
1612
- this.__addUpdatePositionEventListeners();
1613
- positionTarget.__overlay = this;
1614
- targetResizeObserver.observe(positionTarget);
1615
- }
1616
- }
1617
-
1618
- if (opened) {
1619
- const computedStyle = getComputedStyle(this);
1620
- if (!this.__margins) {
1621
- this.__margins = {};
1622
- ['top', 'bottom', 'left', 'right'].forEach((propName) => {
1623
- this.__margins[propName] = parseInt(computedStyle[propName], 10);
1624
- });
1625
- }
1626
- this.setAttribute('dir', computedStyle.direction);
1627
-
1628
- this._updatePosition();
1629
- // Schedule another position update (to cover virtual keyboard opening for example)
1630
- requestAnimationFrame(() => this._updatePosition());
1631
- }
1632
- }
1633
-
1634
- __positionSettingsChanged() {
1635
- this._updatePosition();
1636
- }
1637
-
1638
- /** @private */
1639
- __onScroll(e) {
1640
- // If the scroll event occurred inside the overlay, ignore it.
1641
- if (!this.contains(e.target)) {
1642
- this._updatePosition();
1643
- }
1644
- }
1645
-
1646
- _updatePosition() {
1647
- if (!this.positionTarget || !this.opened) {
1648
- return;
1649
- }
1650
-
1651
- const targetRect = this.positionTarget.getBoundingClientRect();
1652
-
1653
- // Detect the desired alignment and update the layout accordingly
1654
- const shouldAlignStartVertically = this.__shouldAlignStartVertically(targetRect);
1655
- this.style.justifyContent = shouldAlignStartVertically ? 'flex-start' : 'flex-end';
1656
-
1657
- const isRTL = this.__isRTL;
1658
- const shouldAlignStartHorizontally = this.__shouldAlignStartHorizontally(targetRect, isRTL);
1659
- const flexStart = (!isRTL && shouldAlignStartHorizontally) || (isRTL && !shouldAlignStartHorizontally);
1660
- this.style.alignItems = flexStart ? 'flex-start' : 'flex-end';
1661
-
1662
- // Get the overlay rect after possible overlay alignment changes
1663
- const overlayRect = this.getBoundingClientRect();
1664
-
1665
- // Obtain vertical positioning properties
1666
- const verticalProps = this.__calculatePositionInOneDimension(
1667
- targetRect,
1668
- overlayRect,
1669
- this.noVerticalOverlap,
1670
- PROP_NAMES_VERTICAL,
1671
- this,
1672
- shouldAlignStartVertically,
1673
- );
1674
-
1675
- // Obtain horizontal positioning properties
1676
- const horizontalProps = this.__calculatePositionInOneDimension(
1677
- targetRect,
1678
- overlayRect,
1679
- this.noHorizontalOverlap,
1680
- PROP_NAMES_HORIZONTAL,
1681
- this,
1682
- shouldAlignStartHorizontally,
1683
- );
1684
-
1685
- // Apply the positioning properties to the overlay
1686
- Object.assign(this.style, verticalProps, horizontalProps);
1687
-
1688
- this.toggleAttribute('bottom-aligned', !shouldAlignStartVertically);
1689
- this.toggleAttribute('top-aligned', shouldAlignStartVertically);
1690
-
1691
- this.toggleAttribute('end-aligned', !flexStart);
1692
- this.toggleAttribute('start-aligned', flexStart);
1693
- }
1694
-
1695
- __shouldAlignStartHorizontally(targetRect, rtl) {
1696
- // Using previous size to fix a case where window resize may cause the overlay to be squeezed
1697
- // smaller than its current space before the fit-calculations.
1698
- const contentWidth = Math.max(this.__oldContentWidth || 0, this.$.overlay.offsetWidth);
1699
- this.__oldContentWidth = this.$.overlay.offsetWidth;
1700
-
1701
- const viewportWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
1702
- const defaultAlignLeft = (!rtl && this.horizontalAlign === 'start') || (rtl && this.horizontalAlign === 'end');
1703
-
1704
- return this.__shouldAlignStart(
1705
- targetRect,
1706
- contentWidth,
1707
- viewportWidth,
1708
- this.__margins,
1709
- defaultAlignLeft,
1710
- this.noHorizontalOverlap,
1711
- PROP_NAMES_HORIZONTAL,
1712
- );
1713
- }
1714
-
1715
- __shouldAlignStartVertically(targetRect) {
1716
- // Using previous size to fix a case where window resize may cause the overlay to be squeezed
1717
- // smaller than its current space before the fit-calculations.
1718
- const contentHeight =
1719
- this.requiredVerticalSpace || Math.max(this.__oldContentHeight || 0, this.$.overlay.offsetHeight);
1720
- this.__oldContentHeight = this.$.overlay.offsetHeight;
1721
-
1722
- const viewportHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
1723
- const defaultAlignTop = this.verticalAlign === 'top';
1724
-
1725
- return this.__shouldAlignStart(
1726
- targetRect,
1727
- contentHeight,
1728
- viewportHeight,
1729
- this.__margins,
1730
- defaultAlignTop,
1731
- this.noVerticalOverlap,
1732
- PROP_NAMES_VERTICAL,
1733
- );
1734
- }
1735
-
1736
- // eslint-disable-next-line max-params
1737
- __shouldAlignStart(targetRect, contentSize, viewportSize, margins, defaultAlignStart, noOverlap, propNames) {
1738
- const spaceForStartAlignment =
1739
- viewportSize - targetRect[noOverlap ? propNames.end : propNames.start] - margins[propNames.end];
1740
- const spaceForEndAlignment = targetRect[noOverlap ? propNames.start : propNames.end] - margins[propNames.start];
1741
-
1742
- const spaceForDefaultAlignment = defaultAlignStart ? spaceForStartAlignment : spaceForEndAlignment;
1743
- const spaceForOtherAlignment = defaultAlignStart ? spaceForEndAlignment : spaceForStartAlignment;
1744
-
1745
- const shouldGoToDefaultSide =
1746
- spaceForDefaultAlignment > spaceForOtherAlignment || spaceForDefaultAlignment > contentSize;
1747
-
1748
- return defaultAlignStart === shouldGoToDefaultSide;
1749
- }
1750
-
1751
- /**
1752
- * Returns an adjusted value after resizing the browser window,
1753
- * to avoid wrong calculations when e.g. previously set `bottom`
1754
- * CSS property value is larger than the updated viewport height.
1755
- * See https://github.com/vaadin/web-components/issues/4604
1756
- */
1757
- __adjustBottomProperty(cssPropNameToSet, propNames, currentValue) {
1758
- let adjustedProp;
1759
-
1760
- if (cssPropNameToSet === propNames.end) {
1761
- // Adjust horizontally
1762
- if (propNames.end === PROP_NAMES_VERTICAL.end) {
1763
- const viewportHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
1764
-
1765
- if (currentValue > viewportHeight && this.__oldViewportHeight) {
1766
- const heightDiff = this.__oldViewportHeight - viewportHeight;
1767
- adjustedProp = currentValue - heightDiff;
1768
- }
1769
-
1770
- this.__oldViewportHeight = viewportHeight;
1771
- }
1772
-
1773
- // Adjust vertically
1774
- if (propNames.end === PROP_NAMES_HORIZONTAL.end) {
1775
- const viewportWidth = Math.min(window.innerWidth, document.documentElement.clientWidth);
1776
-
1777
- if (currentValue > viewportWidth && this.__oldViewportWidth) {
1778
- const widthDiff = this.__oldViewportWidth - viewportWidth;
1779
- adjustedProp = currentValue - widthDiff;
1780
- }
1781
-
1782
- this.__oldViewportWidth = viewportWidth;
1783
- }
1784
- }
1785
-
1786
- return adjustedProp;
1787
- }
1788
-
1789
- /**
1790
- * Returns an object with CSS position properties to set,
1791
- * e.g. { top: "100px" }
1792
- */
1793
- // eslint-disable-next-line max-params
1794
- __calculatePositionInOneDimension(targetRect, overlayRect, noOverlap, propNames, overlay, shouldAlignStart) {
1795
- const cssPropNameToSet = shouldAlignStart ? propNames.start : propNames.end;
1796
- const cssPropNameToClear = shouldAlignStart ? propNames.end : propNames.start;
1797
-
1798
- const currentValue = parseFloat(overlay.style[cssPropNameToSet] || getComputedStyle(overlay)[cssPropNameToSet]);
1799
- const adjustedValue = this.__adjustBottomProperty(cssPropNameToSet, propNames, currentValue);
1800
-
1801
- const diff =
1802
- overlayRect[shouldAlignStart ? propNames.start : propNames.end] -
1803
- targetRect[noOverlap === shouldAlignStart ? propNames.end : propNames.start];
1804
-
1805
- const valueToSet = adjustedValue
1806
- ? `${adjustedValue}px`
1807
- : `${currentValue + diff * (shouldAlignStart ? -1 : 1)}px`;
1808
-
1809
- return {
1810
- [cssPropNameToSet]: valueToSet,
1811
- [cssPropNameToClear]: '',
1812
- };
1813
- }
1814
- };
1815
-
1816
- /**
1817
- * @license
1818
- * Copyright (c) 2017 - 2023 Vaadin Ltd.
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.
1965
- * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
1966
- */
1967
-
1968
- /**
1969
- * A controller which prevents the virtual keyboard from showing up on mobile devices
1970
- * when the field's overlay is closed.
1971
- */
1972
- class VirtualKeyboardController {
1973
- /**
1974
- * @param {{ inputElement?: HTMLElement; opened: boolean } & HTMLElement} host
1975
- */
1976
- constructor(host) {
1977
- this.host = host;
1978
-
1979
- host.addEventListener('opened-changed', () => {
1980
- if (!host.opened) {
1981
- // Prevent opening the virtual keyboard when the input gets re-focused on dropdown close
1982
- this.__setVirtualKeyboardEnabled(false);
1983
- }
1984
- });
1985
-
1986
- // Re-enable virtual keyboard on blur, so it gets opened when the field is focused again
1987
- host.addEventListener('blur', () => this.__setVirtualKeyboardEnabled(true));
1988
-
1989
- // Re-enable the virtual keyboard whenever the field is touched
1990
- host.addEventListener('touchstart', () => this.__setVirtualKeyboardEnabled(true));
1991
- }
1992
-
1993
- /** @private */
1994
- __setVirtualKeyboardEnabled(value) {
1995
- if (this.host.inputElement) {
1996
- this.host.inputElement.inputMode = value ? '' : 'none';
1997
- }
1998
- }
1999
- }
2000
-
2001
- export { OverlayMixin as O, PositionMixin as P, VirtualKeyboardController as V, afterNextRender as a, OverlayClassMixin as b, overlay as c, menuOverlayCore as d, hideOthers as h, menuOverlay as m, overlayStyles as o };