@spectrum-web-components/overlay 0.16.4 → 0.16.6-devmode.7

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 (93) hide show
  1. package/active-overlay.dev.js +3 -0
  2. package/active-overlay.dev.js.map +7 -0
  3. package/active-overlay.js +3 -14
  4. package/active-overlay.js.map +7 -1
  5. package/overlay-trigger.dev.js +3 -0
  6. package/overlay-trigger.dev.js.map +7 -0
  7. package/overlay-trigger.js +3 -14
  8. package/overlay-trigger.js.map +7 -1
  9. package/package.json +68 -14
  10. package/src/ActiveOverlay.dev.js +445 -0
  11. package/src/ActiveOverlay.dev.js.map +7 -0
  12. package/src/ActiveOverlay.js +404 -424
  13. package/src/ActiveOverlay.js.map +7 -1
  14. package/src/OverlayTrigger.dev.js +293 -0
  15. package/src/OverlayTrigger.dev.js.map +7 -0
  16. package/src/OverlayTrigger.js +245 -264
  17. package/src/OverlayTrigger.js.map +7 -1
  18. package/src/VirtualTrigger.dev.js +30 -0
  19. package/src/VirtualTrigger.dev.js.map +7 -0
  20. package/src/VirtualTrigger.js +28 -38
  21. package/src/VirtualTrigger.js.map +7 -1
  22. package/src/active-overlay.css.dev.js +12 -0
  23. package/src/active-overlay.css.dev.js.map +7 -0
  24. package/src/active-overlay.css.js +3 -14
  25. package/src/active-overlay.css.js.map +7 -1
  26. package/src/index.dev.js +7 -0
  27. package/src/index.dev.js.map +7 -0
  28. package/src/index.js +7 -18
  29. package/src/index.js.map +7 -1
  30. package/src/loader.dev.js +5 -0
  31. package/src/loader.dev.js.map +7 -0
  32. package/src/loader.js +3 -14
  33. package/src/loader.js.map +7 -1
  34. package/src/overlay-events.dev.js +7 -0
  35. package/src/overlay-events.dev.js.map +7 -0
  36. package/src/overlay-events.js +5 -16
  37. package/src/overlay-events.js.map +7 -1
  38. package/src/overlay-stack.dev.js +436 -0
  39. package/src/overlay-stack.dev.js.map +7 -0
  40. package/src/overlay-stack.js +374 -420
  41. package/src/overlay-stack.js.map +7 -1
  42. package/src/overlay-timer.dev.js +71 -0
  43. package/src/overlay-timer.dev.js.map +7 -0
  44. package/src/overlay-timer.js +64 -82
  45. package/src/overlay-timer.js.map +7 -1
  46. package/src/overlay-trigger.css.dev.js +6 -0
  47. package/src/overlay-trigger.css.dev.js.map +7 -0
  48. package/src/overlay-trigger.css.js +3 -14
  49. package/src/overlay-trigger.css.js.map +7 -1
  50. package/src/overlay-types.dev.js +1 -0
  51. package/src/overlay-types.dev.js.map +7 -0
  52. package/src/overlay-types.js +1 -13
  53. package/src/overlay-types.js.map +7 -1
  54. package/src/overlay-utils.dev.js +28 -0
  55. package/src/overlay-utils.dev.js.map +7 -0
  56. package/src/overlay-utils.js +22 -33
  57. package/src/overlay-utils.js.map +7 -1
  58. package/src/overlay.dev.js +85 -0
  59. package/src/overlay.dev.js.map +7 -0
  60. package/src/overlay.js +83 -119
  61. package/src/overlay.js.map +7 -1
  62. package/stories/overlay-story-components.js +188 -184
  63. package/stories/overlay-story-components.js.map +7 -1
  64. package/stories/overlay.stories.js +238 -228
  65. package/stories/overlay.stories.js.map +7 -1
  66. package/sync/overlay-trigger.dev.js +7 -0
  67. package/sync/overlay-trigger.dev.js.map +7 -0
  68. package/sync/overlay-trigger.js +5 -16
  69. package/sync/overlay-trigger.js.map +7 -1
  70. package/test/benchmark/basic-test.js +7 -18
  71. package/test/benchmark/basic-test.js.map +7 -1
  72. package/test/overlay-lifecycle.test.js +107 -115
  73. package/test/overlay-lifecycle.test.js.map +7 -1
  74. package/test/overlay-timer.test.js +110 -122
  75. package/test/overlay-timer.test.js.map +7 -1
  76. package/test/overlay-trigger-click.test.js +43 -48
  77. package/test/overlay-trigger-click.test.js.map +7 -1
  78. package/test/overlay-trigger-extended.test.js +167 -182
  79. package/test/overlay-trigger-extended.test.js.map +7 -1
  80. package/test/overlay-trigger-hover-click.test.js +59 -73
  81. package/test/overlay-trigger-hover-click.test.js.map +7 -1
  82. package/test/overlay-trigger-hover.test.js +74 -77
  83. package/test/overlay-trigger-hover.test.js.map +7 -1
  84. package/test/overlay-trigger-longpress.test.js +166 -178
  85. package/test/overlay-trigger-longpress.test.js.map +7 -1
  86. package/test/overlay-trigger-sync.test.js +400 -422
  87. package/test/overlay-trigger-sync.test.js.map +7 -1
  88. package/test/overlay-trigger.test.js +400 -422
  89. package/test/overlay-trigger.test.js.map +7 -1
  90. package/test/overlay.test-vrt.js +4 -15
  91. package/test/overlay.test-vrt.js.map +7 -1
  92. package/test/overlay.test.js +458 -479
  93. package/test/overlay.test.js.map +7 -1
@@ -1,135 +1,114 @@
1
- /*
2
- Copyright 2020 Adobe. All rights reserved.
3
- This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
- you may not use this file except in compliance with the License. You may obtain a copy
5
- of the License at http://www.apache.org/licenses/LICENSE-2.0
6
-
7
- Unless required by applicable law or agreed to in writing, software distributed under
8
- the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
- OF ANY KIND, either express or implied. See the License for the specific language
10
- governing permissions and limitations under the License.
11
- */
12
- import { ActiveOverlay } from './ActiveOverlay.js';
13
- import { OverlayTimer } from './overlay-timer.js';
14
- import '../active-overlay.js';
15
- import { findOverlaysRootedInOverlay, parentOverlayOf, } from './overlay-utils.js';
16
- import { getDeepElementFromPoint } from '@spectrum-web-components/shared/src/get-deep-element-from-point.js';
1
+ import { ActiveOverlay } from "./ActiveOverlay.js";
2
+ import { OverlayTimer } from "./overlay-timer.js";
3
+ import "../active-overlay.js";
4
+ import {
5
+ findOverlaysRootedInOverlay,
6
+ parentOverlayOf
7
+ } from "./overlay-utils.js";
8
+ import { getDeepElementFromPoint } from "@spectrum-web-components/shared/src/get-deep-element-from-point.js";
17
9
  function isLeftClick(event) {
18
- return event.button === 0;
10
+ return event.button === 0;
19
11
  }
20
12
  function hasModifier(event) {
21
- return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
13
+ return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
22
14
  }
23
15
  export class OverlayStack {
24
- constructor() {
25
- this.overlays = [];
16
+ constructor() {
17
+ this.overlays = [];
18
+ this.preventMouseRootClose = false;
19
+ this.root = document.body;
20
+ this.handlingResize = false;
21
+ this.overlayTimer = new OverlayTimer();
22
+ this.canTabTrap = true;
23
+ this.trappingInited = false;
24
+ this._eventsAreBound = false;
25
+ this._bodyMarginsApplied = false;
26
+ this.forwardContextmenuEvent = async (event) => {
27
+ var _a;
28
+ const topOverlay = this.overlays[this.overlays.length - 1];
29
+ if (!this.trappingInited || topOverlay.interaction !== "modal" || event.target !== this.overlayHolder) {
30
+ return;
31
+ }
32
+ event.stopPropagation();
33
+ event.preventDefault();
34
+ await this.closeTopOverlay();
35
+ (_a = getDeepElementFromPoint(event.clientX, event.clientY)) == null ? void 0 : _a.dispatchEvent(new MouseEvent("contextmenu", event));
36
+ };
37
+ this.handleOverlayClose = (event) => {
38
+ const { root } = event;
39
+ if (!root)
40
+ return;
41
+ this.closeOverlaysForRoot(root);
42
+ };
43
+ this.handleMouseCapture = (event) => {
44
+ const topOverlay = this.topOverlay;
45
+ if (!event.target || !topOverlay || !topOverlay.overlayContent || hasModifier(event) || !isLeftClick(event)) {
46
+ this.preventMouseRootClose = true;
47
+ return;
48
+ }
49
+ if (event.target instanceof Node) {
50
+ const path = event.composedPath();
51
+ if (path.indexOf(topOverlay.overlayContent) >= 0) {
52
+ this.preventMouseRootClose = true;
53
+ return;
54
+ }
26
55
  this.preventMouseRootClose = false;
27
- this.root = document.body;
28
- this.handlingResize = false;
29
- this.overlayTimer = new OverlayTimer();
30
- this.canTabTrap = true;
31
- this.trappingInited = false;
32
- this._eventsAreBound = false;
33
- this._bodyMarginsApplied = false;
34
- this.forwardContextmenuEvent = async (event) => {
35
- var _a;
36
- const topOverlay = this.overlays[this.overlays.length - 1];
37
- if (!this.trappingInited ||
38
- topOverlay.interaction !== 'modal' ||
39
- event.target !== this.overlayHolder) {
40
- return;
41
- }
42
- event.stopPropagation();
43
- event.preventDefault();
44
- await this.closeTopOverlay();
45
- (_a = getDeepElementFromPoint(event.clientX, event.clientY)) === null || _a === void 0 ? void 0 : _a.dispatchEvent(new MouseEvent('contextmenu', event));
46
- };
47
- this.handleOverlayClose = (event) => {
48
- const { root } = event;
49
- if (!root)
50
- return;
51
- this.closeOverlaysForRoot(root);
52
- };
53
- this.handleMouseCapture = (event) => {
54
- const topOverlay = this.topOverlay;
55
- if (!event.target ||
56
- !topOverlay ||
57
- !topOverlay.overlayContent ||
58
- hasModifier(event) ||
59
- !isLeftClick(event)) {
60
- this.preventMouseRootClose = true;
61
- return;
62
- }
63
- if (event.target instanceof Node) {
64
- const path = event.composedPath();
65
- if (path.indexOf(topOverlay.overlayContent) >= 0) {
66
- this.preventMouseRootClose = true;
67
- return;
68
- }
69
- this.preventMouseRootClose = false;
70
- }
71
- };
72
- /**
73
- * A "longpress" occurs before the "click" that creates it has occured.
74
- * In that way the first click will still be part of the "longpress" and
75
- * not part of closing the overlay.
76
- */
56
+ }
57
+ };
58
+ this._doesNotCloseOnFirstClick = false;
59
+ this.handleMouse = (event) => {
60
+ var _a;
61
+ if (this._doesNotCloseOnFirstClick) {
77
62
  this._doesNotCloseOnFirstClick = false;
78
- this.handleMouse = (event) => {
79
- var _a;
80
- if (this._doesNotCloseOnFirstClick) {
81
- this._doesNotCloseOnFirstClick = false;
82
- return;
83
- }
84
- if (this.preventMouseRootClose || event.defaultPrevented) {
85
- return;
86
- }
87
- this.closeTopOverlay();
88
- const overlaysToClose = [];
89
- let root = (_a = this.topOverlay) === null || _a === void 0 ? void 0 : _a.root;
90
- let overlay = parentOverlayOf(root);
91
- while (root && overlay) {
92
- overlaysToClose.push(overlay);
93
- overlay = parentOverlayOf(root);
94
- root = overlay === null || overlay === void 0 ? void 0 : overlay.root;
95
- }
96
- if (overlay) {
97
- overlaysToClose.push(overlay);
98
- }
99
- overlaysToClose.forEach((overlay) => this.hideAndCloseOverlay(overlay));
100
- };
101
- this.handleKeyUp = (event) => {
102
- if (event.code === 'Escape') {
103
- this.closeTopOverlay();
104
- }
105
- };
106
- this.handleResize = () => {
107
- if (this.handlingResize)
108
- return;
109
- this.handlingResize = true;
110
- requestAnimationFrame(async () => {
111
- const promises = this.overlays.map((overlay) => overlay.updateOverlayPosition());
112
- await Promise.all(promises);
113
- this.handlingResize = false;
114
- });
115
- };
63
+ return;
64
+ }
65
+ if (this.preventMouseRootClose || event.defaultPrevented) {
66
+ return;
67
+ }
68
+ this.closeTopOverlay();
69
+ const overlaysToClose = [];
70
+ let root = (_a = this.topOverlay) == null ? void 0 : _a.root;
71
+ let overlay = parentOverlayOf(root);
72
+ while (root && overlay) {
73
+ overlaysToClose.push(overlay);
74
+ overlay = parentOverlayOf(root);
75
+ root = overlay == null ? void 0 : overlay.root;
76
+ }
77
+ if (overlay) {
78
+ overlaysToClose.push(overlay);
79
+ }
80
+ overlaysToClose.forEach((overlay2) => this.hideAndCloseOverlay(overlay2));
81
+ };
82
+ this.handleKeyUp = (event) => {
83
+ if (event.code === "Escape") {
84
+ this.closeTopOverlay();
85
+ }
86
+ };
87
+ this.handleResize = () => {
88
+ if (this.handlingResize)
89
+ return;
90
+ this.handlingResize = true;
91
+ requestAnimationFrame(async () => {
92
+ const promises = this.overlays.map((overlay) => overlay.updateOverlayPosition());
93
+ await Promise.all(promises);
94
+ this.handlingResize = false;
95
+ });
96
+ };
97
+ }
98
+ initTabTrapping() {
99
+ if (this.trappingInited)
100
+ return;
101
+ this.trappingInited = true;
102
+ if (this.document.body.shadowRoot) {
103
+ this.canTabTrap = false;
104
+ return;
116
105
  }
117
- initTabTrapping() {
118
- if (this.trappingInited)
119
- return;
120
- this.trappingInited = true;
121
- /* c8 ignore next 4 */
122
- if (this.document.body.shadowRoot) {
123
- this.canTabTrap = false;
124
- return;
125
- }
126
- this.document.body.attachShadow({ mode: 'open' });
127
- /* c8 ignore next 3 */
128
- if (!this.document.body.shadowRoot) {
129
- return;
130
- }
131
- const root = this.document.body.shadowRoot;
132
- root.innerHTML = `
106
+ this.document.body.attachShadow({ mode: "open" });
107
+ if (!this.document.body.shadowRoot) {
108
+ return;
109
+ }
110
+ const root = this.document.body.shadowRoot;
111
+ root.innerHTML = `
133
112
  <style>
134
113
  :host {
135
114
  position: relative;
@@ -161,322 +140,297 @@ export class OverlayStack {
161
140
  <div id="actual"><slot></slot></div>
162
141
  <div id="holder"><slot name="open"></slot></div>
163
142
  `;
164
- this.tabTrapper = root.querySelector('#actual');
165
- this.overlayHolder = root.querySelector('#holder');
166
- this.tabTrapper.attachShadow({ mode: 'open' });
167
- if (this.tabTrapper.shadowRoot) {
168
- this.tabTrapper.shadowRoot.innerHTML = '<slot></slot>';
169
- }
170
- this.overlayHolder.addEventListener('contextmenu', this.forwardContextmenuEvent, true);
171
- requestAnimationFrame(() => {
172
- this.applyBodyMargins();
173
- const observer = new ResizeObserver(() => {
174
- this.applyBodyMargins();
175
- });
176
- observer.observe(document.body);
177
- });
143
+ this.tabTrapper = root.querySelector("#actual");
144
+ this.overlayHolder = root.querySelector("#holder");
145
+ this.tabTrapper.attachShadow({ mode: "open" });
146
+ if (this.tabTrapper.shadowRoot) {
147
+ this.tabTrapper.shadowRoot.innerHTML = "<slot></slot>";
178
148
  }
179
- applyBodyMargins() {
180
- const { marginLeft, marginRight, marginTop, marginBottom } = getComputedStyle(document.body);
181
- const allZero = parseFloat(marginLeft) === 0 &&
182
- parseFloat(marginRight) === 0 &&
183
- parseFloat(marginTop) === 0 &&
184
- parseFloat(marginBottom) === 0;
185
- if (allZero && !this._bodyMarginsApplied) {
186
- return;
187
- }
188
- this.tabTrapper.style.setProperty('--swc-body-margins-inline', `calc(${marginLeft} + ${marginRight})`);
189
- this.tabTrapper.style.setProperty('--swc-body-margins-block', `calc(${marginTop} + ${marginBottom})`);
190
- this._bodyMarginsApplied = !allZero;
149
+ this.overlayHolder.addEventListener("contextmenu", this.forwardContextmenuEvent, true);
150
+ requestAnimationFrame(() => {
151
+ this.applyBodyMargins();
152
+ const observer = new ResizeObserver(() => {
153
+ this.applyBodyMargins();
154
+ });
155
+ observer.observe(document.body);
156
+ });
157
+ }
158
+ applyBodyMargins() {
159
+ const { marginLeft, marginRight, marginTop, marginBottom } = getComputedStyle(document.body);
160
+ const allZero = parseFloat(marginLeft) === 0 && parseFloat(marginRight) === 0 && parseFloat(marginTop) === 0 && parseFloat(marginBottom) === 0;
161
+ if (allZero && !this._bodyMarginsApplied) {
162
+ return;
191
163
  }
192
- startTabTrapping() {
193
- this.initTabTrapping();
194
- /* c8 ignore next 3 */
195
- if (!this.canTabTrap) {
196
- return;
197
- }
198
- this.tabTrapper.tabIndex = -1;
199
- this.tabTrapper.setAttribute('aria-hidden', 'true');
164
+ this.tabTrapper.style.setProperty("--swc-body-margins-inline", `calc(${marginLeft} + ${marginRight})`);
165
+ this.tabTrapper.style.setProperty("--swc-body-margins-block", `calc(${marginTop} + ${marginBottom})`);
166
+ this._bodyMarginsApplied = !allZero;
167
+ }
168
+ startTabTrapping() {
169
+ this.initTabTrapping();
170
+ if (!this.canTabTrap) {
171
+ return;
200
172
  }
201
- stopTabTrapping() {
202
- /* c8 ignore next 3 */
203
- if (!this.canTabTrap || !this.trappingInited) {
204
- return;
205
- }
206
- this.tabTrapper.removeAttribute('tabindex');
207
- this.tabTrapper.removeAttribute('aria-hidden');
173
+ this.tabTrapper.tabIndex = -1;
174
+ this.tabTrapper.setAttribute("aria-hidden", "true");
175
+ }
176
+ stopTabTrapping() {
177
+ if (!this.canTabTrap || !this.trappingInited) {
178
+ return;
208
179
  }
209
- get document() {
210
- return this.root.ownerDocument /* c8 ignore next */ || document;
180
+ this.tabTrapper.removeAttribute("tabindex");
181
+ this.tabTrapper.removeAttribute("aria-hidden");
182
+ }
183
+ get document() {
184
+ return this.root.ownerDocument || document;
185
+ }
186
+ get topOverlay() {
187
+ return this.overlays.slice(-1)[0];
188
+ }
189
+ findOverlayForContent(overlayContent) {
190
+ for (const item of this.overlays) {
191
+ if (overlayContent === item.overlayContent) {
192
+ return item;
193
+ }
211
194
  }
212
- get topOverlay() {
213
- return this.overlays.slice(-1)[0];
195
+ return void 0;
196
+ }
197
+ addEventListeners() {
198
+ if (this._eventsAreBound)
199
+ return;
200
+ this._eventsAreBound = true;
201
+ this.document.addEventListener("click", this.handleMouseCapture, true);
202
+ this.document.addEventListener("click", this.handleMouse);
203
+ this.document.addEventListener("keyup", this.handleKeyUp);
204
+ this.document.addEventListener("sp-overlay-close", this.handleOverlayClose);
205
+ window.addEventListener("resize", this.handleResize);
206
+ }
207
+ isClickOverlayActiveForTrigger(trigger) {
208
+ return this.overlays.some((item) => trigger === item.trigger && item.interaction === "click");
209
+ }
210
+ async openOverlay(details) {
211
+ this.addEventListeners();
212
+ if (this.findOverlayForContent(details.content)) {
213
+ return false;
214
214
  }
215
- findOverlayForContent(overlayContent) {
216
- for (const item of this.overlays) {
217
- if (overlayContent === item.overlayContent) {
218
- return item;
219
- }
220
- }
221
- return undefined;
215
+ if (details.notImmediatelyClosable) {
216
+ this._doesNotCloseOnFirstClick = true;
222
217
  }
223
- addEventListeners() {
224
- if (this._eventsAreBound)
225
- return;
226
- this._eventsAreBound = true;
227
- this.document.addEventListener('click', this.handleMouseCapture, true);
228
- this.document.addEventListener('click', this.handleMouse);
229
- this.document.addEventListener('keyup', this.handleKeyUp);
230
- this.document.addEventListener('sp-overlay-close', this.handleOverlayClose);
231
- window.addEventListener('resize', this.handleResize);
218
+ if (details.interaction === "modal") {
219
+ this.startTabTrapping();
232
220
  }
233
- isClickOverlayActiveForTrigger(trigger) {
234
- return this.overlays.some((item) => trigger === item.trigger && item.interaction === 'click');
221
+ const contentWithLifecycle = details.content;
222
+ if (contentWithLifecycle.overlayWillOpenCallback) {
223
+ const { trigger } = details;
224
+ contentWithLifecycle.overlayWillOpenCallback({ trigger });
235
225
  }
236
- async openOverlay(details) {
237
- this.addEventListeners();
238
- if (this.findOverlayForContent(details.content)) {
239
- return false;
240
- }
241
- if (details.notImmediatelyClosable) {
242
- this._doesNotCloseOnFirstClick = true;
243
- }
244
- if (details.interaction === 'modal') {
245
- this.startTabTrapping();
246
- }
247
- const contentWithLifecycle = details.content;
248
- if (contentWithLifecycle.overlayWillOpenCallback) {
249
- const { trigger } = details;
250
- contentWithLifecycle.overlayWillOpenCallback({ trigger });
251
- }
252
- if (details.delayed) {
253
- const cancelledPromise = this.overlayTimer.openTimer(details.content);
254
- const promises = [cancelledPromise];
255
- if (details.abortPromise) {
256
- promises.push(details.abortPromise);
257
- }
258
- const cancelled = await Promise.race(promises);
259
- if (cancelled) {
260
- if (contentWithLifecycle.overlayOpenCancelledCallback) {
261
- const { trigger } = details;
262
- contentWithLifecycle.overlayOpenCancelledCallback({
263
- trigger,
264
- });
265
- }
266
- return cancelled;
267
- }
268
- }
269
- if (details.root) {
270
- this.closeOverlaysForRoot(details.root);
271
- }
272
- if (details.interaction === 'click') {
273
- this.closeAllHoverOverlays();
226
+ if (details.delayed) {
227
+ const cancelledPromise = this.overlayTimer.openTimer(details.content);
228
+ const promises = [cancelledPromise];
229
+ if (details.abortPromise) {
230
+ promises.push(details.abortPromise);
231
+ }
232
+ const cancelled = await Promise.race(promises);
233
+ if (cancelled) {
234
+ if (contentWithLifecycle.overlayOpenCancelledCallback) {
235
+ const { trigger } = details;
236
+ contentWithLifecycle.overlayOpenCancelledCallback({
237
+ trigger
238
+ });
274
239
  }
275
- else if (details.interaction === 'hover' &&
276
- this.isClickOverlayActiveForTrigger(details.trigger)) {
277
- // Don't show a hover popover if the click popover is already active
278
- return true;
279
- }
280
- const activeOverlay = ActiveOverlay.create(details);
281
- if (this.overlays.length) {
282
- const topOverlay = this.overlays[this.overlays.length - 1];
283
- topOverlay.obscure(activeOverlay.interaction);
284
- }
285
- document.body.appendChild(activeOverlay);
286
- /**
287
- * The following work to make the new overlay the "top" of the stack
288
- * has to happen AFTER the current call stack completes in case there
289
- * is work there in to remove the previous "top" overlay.
290
- */
291
- return new Promise((res) => requestAnimationFrame(res)).then(async () => {
292
- this.overlays.push(activeOverlay);
293
- await activeOverlay.updateComplete;
294
- this.addOverlayEventListeners(activeOverlay);
295
- if (typeof contentWithLifecycle.open !== 'undefined') {
296
- contentWithLifecycle.open = true;
297
- }
298
- let cb = () => {
299
- return;
300
- };
301
- if (contentWithLifecycle.overlayOpenCallback) {
302
- const { trigger } = activeOverlay;
303
- const { overlayOpenCallback } = contentWithLifecycle;
304
- cb = async () => await overlayOpenCallback({ trigger });
305
- }
306
- await activeOverlay.openCallback(cb);
307
- return false;
308
- });
240
+ return cancelled;
241
+ }
309
242
  }
310
- addOverlayEventListeners(activeOverlay) {
311
- activeOverlay.addEventListener('close', (() => {
312
- this.hideAndCloseOverlay(activeOverlay, true // animated?
313
- );
314
- }));
315
- switch (activeOverlay.interaction) {
316
- case 'replace':
317
- this.addReplaceOverlayEventListeners(activeOverlay);
318
- break;
319
- case 'inline':
320
- this.addInlineOverlayEventListeners(activeOverlay);
321
- break;
322
- }
243
+ if (details.root) {
244
+ this.closeOverlaysForRoot(details.root);
323
245
  }
324
- addReplaceOverlayEventListeners(activeOverlay) {
325
- activeOverlay.addEventListener('keydown', (event) => {
326
- const { code } = event;
327
- /* c8 ignore next */
328
- if (code !== 'Tab')
329
- return;
330
- event.stopPropagation();
331
- this.closeOverlay(activeOverlay.overlayContent);
332
- activeOverlay.tabbingAway = true;
333
- activeOverlay.trigger.focus();
334
- activeOverlay.trigger.dispatchEvent(new KeyboardEvent('keydown', event));
335
- });
246
+ if (details.interaction === "click") {
247
+ this.closeAllHoverOverlays();
248
+ } else if (details.interaction === "hover" && this.isClickOverlayActiveForTrigger(details.trigger)) {
249
+ return true;
336
250
  }
337
- addInlineOverlayEventListeners(activeOverlay) {
338
- activeOverlay.trigger.addEventListener('keydown', activeOverlay.handleInlineTriggerKeydown);
339
- activeOverlay.addEventListener('keydown', (event) => {
340
- const { code, shiftKey } = event;
341
- /* c8 ignore next */
342
- if (code !== 'Tab')
343
- return;
344
- activeOverlay.tabbingAway = true;
345
- if (shiftKey) {
346
- const returnFocusElement = document.createElement('span');
347
- returnFocusElement.tabIndex = -1;
348
- if (activeOverlay.trigger.hasAttribute('slot')) {
349
- returnFocusElement.slot = activeOverlay.trigger.slot;
350
- }
351
- activeOverlay.trigger.insertAdjacentElement('afterend', returnFocusElement);
352
- returnFocusElement.focus();
353
- returnFocusElement.remove();
354
- return;
355
- }
356
- event.stopPropagation();
357
- const triggerWithLifecycle = activeOverlay.trigger;
358
- if (typeof triggerWithLifecycle.open !== 'undefined') {
359
- triggerWithLifecycle.open = false;
360
- }
361
- this.closeOverlay(activeOverlay.overlayContent);
362
- activeOverlay.trigger.focus();
363
- });
251
+ const activeOverlay = ActiveOverlay.create(details);
252
+ if (this.overlays.length) {
253
+ const topOverlay = this.overlays[this.overlays.length - 1];
254
+ topOverlay.obscure(activeOverlay.interaction);
364
255
  }
365
- closeOverlay(content) {
366
- this.overlayTimer.close(content);
367
- requestAnimationFrame(() => {
368
- const overlayFromContent = this.findOverlayForContent(content);
369
- const overlaysToClose = [overlayFromContent];
370
- overlaysToClose.push(...findOverlaysRootedInOverlay(overlayFromContent, this.overlays));
371
- overlaysToClose.forEach((overlay) => this.hideAndCloseOverlay(overlay));
372
- });
256
+ document.body.appendChild(activeOverlay);
257
+ return new Promise((res) => requestAnimationFrame(res)).then(async () => {
258
+ this.overlays.push(activeOverlay);
259
+ await activeOverlay.updateComplete;
260
+ this.addOverlayEventListeners(activeOverlay);
261
+ if (typeof contentWithLifecycle.open !== "undefined") {
262
+ contentWithLifecycle.open = true;
263
+ }
264
+ let cb = () => {
265
+ return;
266
+ };
267
+ if (contentWithLifecycle.overlayOpenCallback) {
268
+ const { trigger } = activeOverlay;
269
+ const { overlayOpenCallback } = contentWithLifecycle;
270
+ cb = async () => await overlayOpenCallback({ trigger });
271
+ }
272
+ await activeOverlay.openCallback(cb);
273
+ return false;
274
+ });
275
+ }
276
+ addOverlayEventListeners(activeOverlay) {
277
+ activeOverlay.addEventListener("close", () => {
278
+ this.hideAndCloseOverlay(activeOverlay, true);
279
+ });
280
+ switch (activeOverlay.interaction) {
281
+ case "replace":
282
+ this.addReplaceOverlayEventListeners(activeOverlay);
283
+ break;
284
+ case "inline":
285
+ this.addInlineOverlayEventListeners(activeOverlay);
286
+ break;
373
287
  }
374
- closeAllHoverOverlays() {
375
- for (const overlay of this.overlays) {
376
- if (overlay.interaction === 'hover') {
377
- this.hideAndCloseOverlay(overlay, false);
378
- }
288
+ }
289
+ addReplaceOverlayEventListeners(activeOverlay) {
290
+ activeOverlay.addEventListener("keydown", (event) => {
291
+ const { code } = event;
292
+ if (code !== "Tab")
293
+ return;
294
+ event.stopPropagation();
295
+ this.closeOverlay(activeOverlay.overlayContent);
296
+ activeOverlay.tabbingAway = true;
297
+ activeOverlay.trigger.focus();
298
+ activeOverlay.trigger.dispatchEvent(new KeyboardEvent("keydown", event));
299
+ });
300
+ }
301
+ addInlineOverlayEventListeners(activeOverlay) {
302
+ activeOverlay.trigger.addEventListener("keydown", activeOverlay.handleInlineTriggerKeydown);
303
+ activeOverlay.addEventListener("keydown", (event) => {
304
+ const { code, shiftKey } = event;
305
+ if (code !== "Tab")
306
+ return;
307
+ activeOverlay.tabbingAway = true;
308
+ if (shiftKey) {
309
+ const returnFocusElement = document.createElement("span");
310
+ returnFocusElement.tabIndex = -1;
311
+ if (activeOverlay.trigger.hasAttribute("slot")) {
312
+ returnFocusElement.slot = activeOverlay.trigger.slot;
379
313
  }
314
+ activeOverlay.trigger.insertAdjacentElement("afterend", returnFocusElement);
315
+ returnFocusElement.focus();
316
+ returnFocusElement.remove();
317
+ return;
318
+ }
319
+ event.stopPropagation();
320
+ const triggerWithLifecycle = activeOverlay.trigger;
321
+ if (typeof triggerWithLifecycle.open !== "undefined") {
322
+ triggerWithLifecycle.open = false;
323
+ }
324
+ this.closeOverlay(activeOverlay.overlayContent);
325
+ activeOverlay.trigger.focus();
326
+ });
327
+ }
328
+ closeOverlay(content) {
329
+ this.overlayTimer.close(content);
330
+ requestAnimationFrame(() => {
331
+ const overlayFromContent = this.findOverlayForContent(content);
332
+ const overlaysToClose = [overlayFromContent];
333
+ overlaysToClose.push(...findOverlaysRootedInOverlay(overlayFromContent, this.overlays));
334
+ overlaysToClose.forEach((overlay) => this.hideAndCloseOverlay(overlay));
335
+ });
336
+ }
337
+ closeAllHoverOverlays() {
338
+ for (const overlay of this.overlays) {
339
+ if (overlay.interaction === "hover") {
340
+ this.hideAndCloseOverlay(overlay, false);
341
+ }
380
342
  }
381
- closeOverlaysForRoot(root) {
382
- const overlaysToClose = [];
383
- for (const overlay of this.overlays) {
384
- if (overlay.root && overlay.root === root) {
385
- overlaysToClose.push(overlay);
386
- overlaysToClose.push(...findOverlaysRootedInOverlay(overlay, this.overlays));
387
- }
388
- }
389
- overlaysToClose.forEach((overlay) => this.hideAndCloseOverlay(overlay, true, true));
343
+ }
344
+ closeOverlaysForRoot(root) {
345
+ const overlaysToClose = [];
346
+ for (const overlay of this.overlays) {
347
+ if (overlay.root && overlay.root === root) {
348
+ overlaysToClose.push(overlay);
349
+ overlaysToClose.push(...findOverlaysRootedInOverlay(overlay, this.overlays));
350
+ }
390
351
  }
391
- async manageFocusAfterCloseWhenOverlaysRemain(returnBeforeFocus) {
392
- const topOverlay = this.overlays[this.overlays.length - 1];
393
- topOverlay.feature();
394
- // Push focus in the the next remaining overlay as needed when a `type="modal"` overlay exists.
395
- if (topOverlay.interaction === 'modal' || topOverlay.hasModalRoot) {
396
- if (returnBeforeFocus)
397
- return;
398
- await topOverlay.focus();
399
- }
400
- else {
401
- this.stopTabTrapping();
402
- }
352
+ overlaysToClose.forEach((overlay) => this.hideAndCloseOverlay(overlay, true, true));
353
+ }
354
+ async manageFocusAfterCloseWhenOverlaysRemain(returnBeforeFocus) {
355
+ const topOverlay = this.overlays[this.overlays.length - 1];
356
+ topOverlay.feature();
357
+ if (topOverlay.interaction === "modal" || topOverlay.hasModalRoot) {
358
+ if (returnBeforeFocus)
359
+ return;
360
+ await topOverlay.focus();
361
+ } else {
362
+ this.stopTabTrapping();
403
363
  }
404
- manageFocusAfterCloseWhenLastOverlay(overlay) {
405
- this.stopTabTrapping();
406
- const isModal = overlay.interaction === 'modal';
407
- const isReceivesFocus = overlay.receivesFocus === 'auto';
408
- const isReplace = overlay.interaction === 'replace';
409
- const isInline = overlay.interaction === 'inline';
410
- const isTabbingAwayFromInlineOrReplace = (isReplace || isInline) && !overlay.tabbingAway;
411
- overlay.tabbingAway = false;
412
- if (!isModal && !isReceivesFocus && !isTabbingAwayFromInlineOrReplace) {
413
- return;
414
- }
415
- // Manage post closure focus when needed.
416
- const overlayRoot = overlay.overlayContent.getRootNode();
417
- const overlayContentActiveElement = overlayRoot.activeElement;
418
- let triggerRoot;
419
- let triggerActiveElement;
420
- const contentContainsActiveElement = () => overlay.overlayContent.contains(overlayContentActiveElement);
421
- const triggerRootContainsActiveElement = () => {
422
- triggerRoot = overlay.trigger.getRootNode();
423
- triggerActiveElement = triggerRoot.activeElement;
424
- return triggerRoot.contains(triggerActiveElement);
425
- };
426
- const triggerHostIsActiveElement = () => triggerRoot.host && triggerRoot.host === triggerActiveElement;
427
- // Return focus to the trigger as long as the user hasn't actively focused
428
- // something outside of the current overlay interface; trigger, root, host.
429
- if (isModal ||
430
- contentContainsActiveElement() ||
431
- triggerRootContainsActiveElement() ||
432
- triggerHostIsActiveElement()) {
433
- overlay.trigger.focus();
434
- }
364
+ }
365
+ manageFocusAfterCloseWhenLastOverlay(overlay) {
366
+ this.stopTabTrapping();
367
+ const isModal = overlay.interaction === "modal";
368
+ const isReceivesFocus = overlay.receivesFocus === "auto";
369
+ const isReplace = overlay.interaction === "replace";
370
+ const isInline = overlay.interaction === "inline";
371
+ const isTabbingAwayFromInlineOrReplace = (isReplace || isInline) && !overlay.tabbingAway;
372
+ overlay.tabbingAway = false;
373
+ if (!isModal && !isReceivesFocus && !isTabbingAwayFromInlineOrReplace) {
374
+ return;
435
375
  }
436
- async hideAndCloseOverlay(overlay, animated, returnBeforeFocus) {
437
- if (!overlay) {
438
- return;
439
- }
440
- const contentWithLifecycle = overlay.overlayContent;
441
- if (typeof contentWithLifecycle.overlayWillCloseCallback !== 'undefined') {
442
- const { trigger } = overlay;
443
- if (contentWithLifecycle.overlayWillCloseCallback({ trigger })) {
444
- return;
445
- }
446
- }
447
- await overlay.hide(animated);
448
- if (typeof contentWithLifecycle.open !== 'undefined') {
449
- contentWithLifecycle.open = false;
450
- }
451
- if (contentWithLifecycle.overlayCloseCallback) {
452
- const { trigger } = overlay;
453
- await contentWithLifecycle.overlayCloseCallback({ trigger });
454
- }
455
- if (overlay.state != 'dispose')
456
- return;
457
- const index = this.overlays.indexOf(overlay);
458
- if (index >= 0) {
459
- this.overlays.splice(index, 1);
460
- }
461
- if (this.overlays.length) {
462
- await this.manageFocusAfterCloseWhenOverlaysRemain(returnBeforeFocus);
463
- }
464
- else {
465
- this.manageFocusAfterCloseWhenLastOverlay(overlay);
466
- }
467
- overlay.remove();
468
- overlay.dispose();
469
- overlay.trigger.dispatchEvent(new CustomEvent('sp-closed', {
470
- bubbles: true,
471
- composed: true,
472
- cancelable: true,
473
- detail: {
474
- interaction: overlay.interaction,
475
- },
476
- }));
376
+ const overlayRoot = overlay.overlayContent.getRootNode();
377
+ const overlayContentActiveElement = overlayRoot.activeElement;
378
+ let triggerRoot;
379
+ let triggerActiveElement;
380
+ const contentContainsActiveElement = () => overlay.overlayContent.contains(overlayContentActiveElement);
381
+ const triggerRootContainsActiveElement = () => {
382
+ triggerRoot = overlay.trigger.getRootNode();
383
+ triggerActiveElement = triggerRoot.activeElement;
384
+ return triggerRoot.contains(triggerActiveElement);
385
+ };
386
+ const triggerHostIsActiveElement = () => triggerRoot.host && triggerRoot.host === triggerActiveElement;
387
+ if (isModal || contentContainsActiveElement() || triggerRootContainsActiveElement() || triggerHostIsActiveElement()) {
388
+ overlay.trigger.focus();
389
+ }
390
+ }
391
+ async hideAndCloseOverlay(overlay, animated, returnBeforeFocus) {
392
+ if (!overlay) {
393
+ return;
394
+ }
395
+ const contentWithLifecycle = overlay.overlayContent;
396
+ if (typeof contentWithLifecycle.overlayWillCloseCallback !== "undefined") {
397
+ const { trigger } = overlay;
398
+ if (contentWithLifecycle.overlayWillCloseCallback({ trigger })) {
399
+ return;
400
+ }
401
+ }
402
+ await overlay.hide(animated);
403
+ if (typeof contentWithLifecycle.open !== "undefined") {
404
+ contentWithLifecycle.open = false;
405
+ }
406
+ if (contentWithLifecycle.overlayCloseCallback) {
407
+ const { trigger } = overlay;
408
+ await contentWithLifecycle.overlayCloseCallback({ trigger });
409
+ }
410
+ if (overlay.state != "dispose")
411
+ return;
412
+ const index = this.overlays.indexOf(overlay);
413
+ if (index >= 0) {
414
+ this.overlays.splice(index, 1);
477
415
  }
478
- closeTopOverlay() {
479
- return this.hideAndCloseOverlay(this.topOverlay, true);
416
+ if (this.overlays.length) {
417
+ await this.manageFocusAfterCloseWhenOverlaysRemain(returnBeforeFocus);
418
+ } else {
419
+ this.manageFocusAfterCloseWhenLastOverlay(overlay);
480
420
  }
421
+ overlay.remove();
422
+ overlay.dispose();
423
+ overlay.trigger.dispatchEvent(new CustomEvent("sp-closed", {
424
+ bubbles: true,
425
+ composed: true,
426
+ cancelable: true,
427
+ detail: {
428
+ interaction: overlay.interaction
429
+ }
430
+ }));
431
+ }
432
+ closeTopOverlay() {
433
+ return this.hideAndCloseOverlay(this.topOverlay, true);
434
+ }
481
435
  }
482
- //# sourceMappingURL=overlay-stack.js.map
436
+ //# sourceMappingURL=overlay-stack.js.map