@spectrum-web-components/overlay 0.16.3 → 0.16.6-devmode.0

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 (96) 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 +69 -15
  10. package/src/ActiveOverlay.d.ts +2 -2
  11. package/src/ActiveOverlay.dev.js +445 -0
  12. package/src/ActiveOverlay.dev.js.map +7 -0
  13. package/src/ActiveOverlay.js +404 -423
  14. package/src/ActiveOverlay.js.map +7 -1
  15. package/src/OverlayTrigger.dev.js +293 -0
  16. package/src/OverlayTrigger.dev.js.map +7 -0
  17. package/src/OverlayTrigger.js +245 -264
  18. package/src/OverlayTrigger.js.map +7 -1
  19. package/src/VirtualTrigger.dev.js +30 -0
  20. package/src/VirtualTrigger.dev.js.map +7 -0
  21. package/src/VirtualTrigger.js +28 -38
  22. package/src/VirtualTrigger.js.map +7 -1
  23. package/src/active-overlay.css.dev.js +12 -0
  24. package/src/active-overlay.css.dev.js.map +7 -0
  25. package/src/active-overlay.css.js +3 -14
  26. package/src/active-overlay.css.js.map +7 -1
  27. package/src/index.dev.js +7 -0
  28. package/src/index.dev.js.map +7 -0
  29. package/src/index.js +7 -18
  30. package/src/index.js.map +7 -1
  31. package/src/loader.dev.js +5 -0
  32. package/src/loader.dev.js.map +7 -0
  33. package/src/loader.js +3 -14
  34. package/src/loader.js.map +7 -1
  35. package/src/overlay-events.d.ts +11 -0
  36. package/src/overlay-events.dev.js +7 -0
  37. package/src/overlay-events.dev.js.map +7 -0
  38. package/src/overlay-events.js +7 -0
  39. package/src/overlay-events.js.map +7 -0
  40. package/src/overlay-stack.d.ts +2 -0
  41. package/src/overlay-stack.dev.js +436 -0
  42. package/src/overlay-stack.dev.js.map +7 -0
  43. package/src/overlay-stack.js +374 -419
  44. package/src/overlay-stack.js.map +7 -1
  45. package/src/overlay-timer.dev.js +71 -0
  46. package/src/overlay-timer.dev.js.map +7 -0
  47. package/src/overlay-timer.js +64 -82
  48. package/src/overlay-timer.js.map +7 -1
  49. package/src/overlay-trigger.css.dev.js +6 -0
  50. package/src/overlay-trigger.css.dev.js.map +7 -0
  51. package/src/overlay-trigger.css.js +3 -14
  52. package/src/overlay-trigger.css.js.map +7 -1
  53. package/src/overlay-types.dev.js +1 -0
  54. package/src/overlay-types.dev.js.map +7 -0
  55. package/src/overlay-types.js +1 -13
  56. package/src/overlay-types.js.map +7 -1
  57. package/src/overlay-utils.dev.js +28 -0
  58. package/src/overlay-utils.dev.js.map +7 -0
  59. package/src/overlay-utils.js +22 -33
  60. package/src/overlay-utils.js.map +7 -1
  61. package/src/overlay.dev.js +85 -0
  62. package/src/overlay.dev.js.map +7 -0
  63. package/src/overlay.js +83 -119
  64. package/src/overlay.js.map +7 -1
  65. package/stories/overlay-story-components.js +188 -184
  66. package/stories/overlay-story-components.js.map +7 -1
  67. package/stories/overlay.stories.js +238 -228
  68. package/stories/overlay.stories.js.map +7 -1
  69. package/sync/overlay-trigger.dev.js +7 -0
  70. package/sync/overlay-trigger.dev.js.map +7 -0
  71. package/sync/overlay-trigger.js +5 -16
  72. package/sync/overlay-trigger.js.map +7 -1
  73. package/test/benchmark/basic-test.js +7 -18
  74. package/test/benchmark/basic-test.js.map +7 -1
  75. package/test/overlay-lifecycle.test.js +107 -115
  76. package/test/overlay-lifecycle.test.js.map +7 -1
  77. package/test/overlay-timer.test.js +110 -122
  78. package/test/overlay-timer.test.js.map +7 -1
  79. package/test/overlay-trigger-click.test.js +43 -48
  80. package/test/overlay-trigger-click.test.js.map +7 -1
  81. package/test/overlay-trigger-extended.test.js +167 -182
  82. package/test/overlay-trigger-extended.test.js.map +7 -1
  83. package/test/overlay-trigger-hover-click.test.js +59 -73
  84. package/test/overlay-trigger-hover-click.test.js.map +7 -1
  85. package/test/overlay-trigger-hover.test.js +74 -77
  86. package/test/overlay-trigger-hover.test.js.map +7 -1
  87. package/test/overlay-trigger-longpress.test.js +166 -178
  88. package/test/overlay-trigger-longpress.test.js.map +7 -1
  89. package/test/overlay-trigger-sync.test.js +400 -422
  90. package/test/overlay-trigger-sync.test.js.map +7 -1
  91. package/test/overlay-trigger.test.js +400 -422
  92. package/test/overlay-trigger.test.js.map +7 -1
  93. package/test/overlay.test-vrt.js +4 -15
  94. package/test/overlay.test-vrt.js.map +7 -1
  95. package/test/overlay.test.js +458 -479
  96. 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';
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";
16
9
  function isLeftClick(event) {
17
- return event.button === 0;
10
+ return event.button === 0;
18
11
  }
19
12
  function hasModifier(event) {
20
- return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
13
+ return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
21
14
  }
22
15
  export class OverlayStack {
23
- constructor() {
24
- 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
+ }
25
55
  this.preventMouseRootClose = false;
26
- this.root = document.body;
27
- this.handlingResize = false;
28
- this.overlayTimer = new OverlayTimer();
29
- this.canTabTrap = true;
30
- this.trappingInited = false;
31
- this._eventsAreBound = false;
32
- this._bodyMarginsApplied = false;
33
- this.forwardContextmenuEvent = async (event) => {
34
- const topOverlay = this.overlays[this.overlays.length - 1];
35
- if (!this.trappingInited ||
36
- topOverlay.interaction !== 'modal' ||
37
- event.target !== this.overlayHolder) {
38
- return;
39
- }
40
- event.stopPropagation();
41
- event.preventDefault();
42
- await this.closeTopOverlay();
43
- let target = document.elementFromPoint(event.clientX, event.clientY);
44
- while (target === null || target === void 0 ? void 0 : target.shadowRoot) {
45
- const innerTarget = target.shadowRoot.elementFromPoint(event.clientX, event.clientY);
46
- if (!innerTarget || innerTarget === target) {
47
- break;
48
- }
49
- target = innerTarget;
50
- }
51
- target === null || target === void 0 ? void 0 : target.dispatchEvent(new MouseEvent('contextmenu', event));
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,321 +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
- window.addEventListener('resize', this.handleResize);
218
+ if (details.interaction === "modal") {
219
+ this.startTabTrapping();
231
220
  }
232
- isClickOverlayActiveForTrigger(trigger) {
233
- 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 });
234
225
  }
235
- async openOverlay(details) {
236
- this.addEventListeners();
237
- if (this.findOverlayForContent(details.content)) {
238
- return false;
239
- }
240
- if (details.notImmediatelyClosable) {
241
- this._doesNotCloseOnFirstClick = true;
242
- }
243
- if (details.interaction === 'modal') {
244
- this.startTabTrapping();
245
- }
246
- const contentWithLifecycle = details.content;
247
- if (contentWithLifecycle.overlayWillOpenCallback) {
248
- const { trigger } = details;
249
- contentWithLifecycle.overlayWillOpenCallback({ trigger });
250
- }
251
- if (details.delayed) {
252
- const cancelledPromise = this.overlayTimer.openTimer(details.content);
253
- const promises = [cancelledPromise];
254
- if (details.abortPromise) {
255
- promises.push(details.abortPromise);
256
- }
257
- const cancelled = await Promise.race(promises);
258
- if (cancelled) {
259
- if (contentWithLifecycle.overlayOpenCancelledCallback) {
260
- const { trigger } = details;
261
- contentWithLifecycle.overlayOpenCancelledCallback({
262
- trigger,
263
- });
264
- }
265
- return cancelled;
266
- }
267
- }
268
- if (details.root) {
269
- this.closeOverlaysForRoot(details.root);
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
+ });
270
239
  }
271
- if (details.interaction === 'click') {
272
- this.closeAllHoverOverlays();
273
- }
274
- else if (details.interaction === 'hover' &&
275
- this.isClickOverlayActiveForTrigger(details.trigger)) {
276
- // Don't show a hover popover if the click popover is already active
277
- return true;
278
- }
279
- const activeOverlay = ActiveOverlay.create(details);
280
- if (this.overlays.length) {
281
- const topOverlay = this.overlays[this.overlays.length - 1];
282
- topOverlay.obscure(activeOverlay.interaction);
283
- }
284
- document.body.appendChild(activeOverlay);
285
- /**
286
- * The following work to make the new overlay the "top" of the stack
287
- * has to happen AFTER the current call stack completes in case there
288
- * is work there in to remove the previous "top" overlay.
289
- */
290
- return new Promise((res) => requestAnimationFrame(res)).then(async () => {
291
- this.overlays.push(activeOverlay);
292
- await activeOverlay.updateComplete;
293
- this.addOverlayEventListeners(activeOverlay);
294
- if (typeof contentWithLifecycle.open !== 'undefined') {
295
- contentWithLifecycle.open = true;
296
- }
297
- let cb = () => {
298
- return;
299
- };
300
- if (contentWithLifecycle.overlayOpenCallback) {
301
- const { trigger } = activeOverlay;
302
- const { overlayOpenCallback } = contentWithLifecycle;
303
- cb = async () => await overlayOpenCallback({ trigger });
304
- }
305
- await activeOverlay.openCallback(cb);
306
- return false;
307
- });
240
+ return cancelled;
241
+ }
308
242
  }
309
- addOverlayEventListeners(activeOverlay) {
310
- activeOverlay.addEventListener('close', (() => {
311
- this.hideAndCloseOverlay(activeOverlay, true // animated?
312
- );
313
- }));
314
- switch (activeOverlay.interaction) {
315
- case 'replace':
316
- this.addReplaceOverlayEventListeners(activeOverlay);
317
- break;
318
- case 'inline':
319
- this.addInlineOverlayEventListeners(activeOverlay);
320
- break;
321
- }
243
+ if (details.root) {
244
+ this.closeOverlaysForRoot(details.root);
322
245
  }
323
- addReplaceOverlayEventListeners(activeOverlay) {
324
- activeOverlay.addEventListener('keydown', (event) => {
325
- const { code } = event;
326
- /* c8 ignore next */
327
- if (code !== 'Tab')
328
- return;
329
- event.stopPropagation();
330
- this.closeOverlay(activeOverlay.overlayContent);
331
- activeOverlay.tabbingAway = true;
332
- activeOverlay.trigger.focus();
333
- activeOverlay.trigger.dispatchEvent(new KeyboardEvent('keydown', event));
334
- });
246
+ if (details.interaction === "click") {
247
+ this.closeAllHoverOverlays();
248
+ } else if (details.interaction === "hover" && this.isClickOverlayActiveForTrigger(details.trigger)) {
249
+ return true;
335
250
  }
336
- addInlineOverlayEventListeners(activeOverlay) {
337
- activeOverlay.trigger.addEventListener('keydown', activeOverlay.handleInlineTriggerKeydown);
338
- activeOverlay.addEventListener('keydown', (event) => {
339
- const { code, shiftKey } = event;
340
- /* c8 ignore next */
341
- if (code !== 'Tab')
342
- return;
343
- activeOverlay.tabbingAway = true;
344
- if (shiftKey) {
345
- const returnFocusElement = document.createElement('span');
346
- returnFocusElement.tabIndex = -1;
347
- if (activeOverlay.trigger.hasAttribute('slot')) {
348
- returnFocusElement.slot = activeOverlay.trigger.slot;
349
- }
350
- activeOverlay.trigger.insertAdjacentElement('afterend', returnFocusElement);
351
- returnFocusElement.focus();
352
- returnFocusElement.remove();
353
- return;
354
- }
355
- event.stopPropagation();
356
- const triggerWithLifecycle = activeOverlay.trigger;
357
- if (typeof triggerWithLifecycle.open !== 'undefined') {
358
- triggerWithLifecycle.open = false;
359
- }
360
- this.closeOverlay(activeOverlay.overlayContent);
361
- activeOverlay.trigger.focus();
362
- });
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);
363
255
  }
364
- closeOverlay(content) {
365
- this.overlayTimer.close(content);
366
- requestAnimationFrame(() => {
367
- const overlayFromContent = this.findOverlayForContent(content);
368
- const overlaysToClose = [overlayFromContent];
369
- overlaysToClose.push(...findOverlaysRootedInOverlay(overlayFromContent, this.overlays));
370
- overlaysToClose.forEach((overlay) => this.hideAndCloseOverlay(overlay));
371
- });
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;
372
287
  }
373
- closeAllHoverOverlays() {
374
- for (const overlay of this.overlays) {
375
- if (overlay.interaction === 'hover') {
376
- this.hideAndCloseOverlay(overlay, false);
377
- }
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;
378
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
+ }
379
342
  }
380
- closeOverlaysForRoot(root) {
381
- const overlaysToClose = [];
382
- for (const overlay of this.overlays) {
383
- if (overlay.root && overlay.root === root) {
384
- overlaysToClose.push(overlay);
385
- overlaysToClose.push(...findOverlaysRootedInOverlay(overlay, this.overlays));
386
- }
387
- }
388
- 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
+ }
389
351
  }
390
- async manageFocusAfterCloseWhenOverlaysRemain(returnBeforeFocus) {
391
- const topOverlay = this.overlays[this.overlays.length - 1];
392
- topOverlay.feature();
393
- // Push focus in the the next remaining overlay as needed when a `type="modal"` overlay exists.
394
- if (topOverlay.interaction === 'modal' || topOverlay.hasModalRoot) {
395
- if (returnBeforeFocus)
396
- return;
397
- await topOverlay.focus();
398
- }
399
- else {
400
- this.stopTabTrapping();
401
- }
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();
402
363
  }
403
- manageFocusAfterCloseWhenLastOverlay(overlay) {
404
- this.stopTabTrapping();
405
- const isModal = overlay.interaction === 'modal';
406
- const isReceivesFocus = overlay.receivesFocus === 'auto';
407
- const isReplace = overlay.interaction === 'replace';
408
- const isInline = overlay.interaction === 'inline';
409
- const isTabbingAwayFromInlineOrReplace = (isReplace || isInline) && !overlay.tabbingAway;
410
- overlay.tabbingAway = false;
411
- if (!isModal && !isReceivesFocus && !isTabbingAwayFromInlineOrReplace) {
412
- return;
413
- }
414
- // Manage post closure focus when needed.
415
- const overlayRoot = overlay.overlayContent.getRootNode();
416
- const overlayContentActiveElement = overlayRoot.activeElement;
417
- let triggerRoot;
418
- let triggerActiveElement;
419
- const contentContainsActiveElement = () => overlay.overlayContent.contains(overlayContentActiveElement);
420
- const triggerRootContainsActiveElement = () => {
421
- triggerRoot = overlay.trigger.getRootNode();
422
- triggerActiveElement = triggerRoot.activeElement;
423
- return triggerRoot.contains(triggerActiveElement);
424
- };
425
- const triggerHostIsActiveElement = () => triggerRoot.host && triggerRoot.host === triggerActiveElement;
426
- // Return focus to the trigger as long as the user hasn't actively focused
427
- // something outside of the current overlay interface; trigger, root, host.
428
- if (isModal ||
429
- contentContainsActiveElement() ||
430
- triggerRootContainsActiveElement() ||
431
- triggerHostIsActiveElement()) {
432
- overlay.trigger.focus();
433
- }
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;
434
375
  }
435
- async hideAndCloseOverlay(overlay, animated, returnBeforeFocus) {
436
- if (!overlay) {
437
- return;
438
- }
439
- const contentWithLifecycle = overlay.overlayContent;
440
- if (typeof contentWithLifecycle.overlayWillCloseCallback !== 'undefined') {
441
- const { trigger } = overlay;
442
- if (contentWithLifecycle.overlayWillCloseCallback({ trigger })) {
443
- return;
444
- }
445
- }
446
- await overlay.hide(animated);
447
- if (typeof contentWithLifecycle.open !== 'undefined') {
448
- contentWithLifecycle.open = false;
449
- }
450
- if (contentWithLifecycle.overlayCloseCallback) {
451
- const { trigger } = overlay;
452
- await contentWithLifecycle.overlayCloseCallback({ trigger });
453
- }
454
- if (overlay.state != 'dispose')
455
- return;
456
- const index = this.overlays.indexOf(overlay);
457
- if (index >= 0) {
458
- this.overlays.splice(index, 1);
459
- }
460
- if (this.overlays.length) {
461
- await this.manageFocusAfterCloseWhenOverlaysRemain(returnBeforeFocus);
462
- }
463
- else {
464
- this.manageFocusAfterCloseWhenLastOverlay(overlay);
465
- }
466
- overlay.remove();
467
- overlay.dispose();
468
- overlay.trigger.dispatchEvent(new CustomEvent('sp-closed', {
469
- bubbles: true,
470
- composed: true,
471
- cancelable: true,
472
- detail: {
473
- interaction: overlay.interaction,
474
- },
475
- }));
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);
476
415
  }
477
- closeTopOverlay() {
478
- return this.hideAndCloseOverlay(this.topOverlay, true);
416
+ if (this.overlays.length) {
417
+ await this.manageFocusAfterCloseWhenOverlaysRemain(returnBeforeFocus);
418
+ } else {
419
+ this.manageFocusAfterCloseWhenLastOverlay(overlay);
479
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
+ }
480
435
  }
481
- //# sourceMappingURL=overlay-stack.js.map
436
+ //# sourceMappingURL=overlay-stack.js.map