@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.
- package/active-overlay.dev.js +3 -0
- package/active-overlay.dev.js.map +7 -0
- package/active-overlay.js +3 -14
- package/active-overlay.js.map +7 -1
- package/overlay-trigger.dev.js +3 -0
- package/overlay-trigger.dev.js.map +7 -0
- package/overlay-trigger.js +3 -14
- package/overlay-trigger.js.map +7 -1
- package/package.json +69 -15
- package/src/ActiveOverlay.d.ts +2 -2
- package/src/ActiveOverlay.dev.js +445 -0
- package/src/ActiveOverlay.dev.js.map +7 -0
- package/src/ActiveOverlay.js +404 -423
- package/src/ActiveOverlay.js.map +7 -1
- package/src/OverlayTrigger.dev.js +293 -0
- package/src/OverlayTrigger.dev.js.map +7 -0
- package/src/OverlayTrigger.js +245 -264
- package/src/OverlayTrigger.js.map +7 -1
- package/src/VirtualTrigger.dev.js +30 -0
- package/src/VirtualTrigger.dev.js.map +7 -0
- package/src/VirtualTrigger.js +28 -38
- package/src/VirtualTrigger.js.map +7 -1
- package/src/active-overlay.css.dev.js +12 -0
- package/src/active-overlay.css.dev.js.map +7 -0
- package/src/active-overlay.css.js +3 -14
- package/src/active-overlay.css.js.map +7 -1
- package/src/index.dev.js +7 -0
- package/src/index.dev.js.map +7 -0
- package/src/index.js +7 -18
- package/src/index.js.map +7 -1
- package/src/loader.dev.js +5 -0
- package/src/loader.dev.js.map +7 -0
- package/src/loader.js +3 -14
- package/src/loader.js.map +7 -1
- package/src/overlay-events.d.ts +11 -0
- package/src/overlay-events.dev.js +7 -0
- package/src/overlay-events.dev.js.map +7 -0
- package/src/overlay-events.js +7 -0
- package/src/overlay-events.js.map +7 -0
- package/src/overlay-stack.d.ts +2 -0
- package/src/overlay-stack.dev.js +436 -0
- package/src/overlay-stack.dev.js.map +7 -0
- package/src/overlay-stack.js +374 -419
- package/src/overlay-stack.js.map +7 -1
- package/src/overlay-timer.dev.js +71 -0
- package/src/overlay-timer.dev.js.map +7 -0
- package/src/overlay-timer.js +64 -82
- package/src/overlay-timer.js.map +7 -1
- package/src/overlay-trigger.css.dev.js +6 -0
- package/src/overlay-trigger.css.dev.js.map +7 -0
- package/src/overlay-trigger.css.js +3 -14
- package/src/overlay-trigger.css.js.map +7 -1
- package/src/overlay-types.dev.js +1 -0
- package/src/overlay-types.dev.js.map +7 -0
- package/src/overlay-types.js +1 -13
- package/src/overlay-types.js.map +7 -1
- package/src/overlay-utils.dev.js +28 -0
- package/src/overlay-utils.dev.js.map +7 -0
- package/src/overlay-utils.js +22 -33
- package/src/overlay-utils.js.map +7 -1
- package/src/overlay.dev.js +85 -0
- package/src/overlay.dev.js.map +7 -0
- package/src/overlay.js +83 -119
- package/src/overlay.js.map +7 -1
- package/stories/overlay-story-components.js +188 -184
- package/stories/overlay-story-components.js.map +7 -1
- package/stories/overlay.stories.js +238 -228
- package/stories/overlay.stories.js.map +7 -1
- package/sync/overlay-trigger.dev.js +7 -0
- package/sync/overlay-trigger.dev.js.map +7 -0
- package/sync/overlay-trigger.js +5 -16
- package/sync/overlay-trigger.js.map +7 -1
- package/test/benchmark/basic-test.js +7 -18
- package/test/benchmark/basic-test.js.map +7 -1
- package/test/overlay-lifecycle.test.js +107 -115
- package/test/overlay-lifecycle.test.js.map +7 -1
- package/test/overlay-timer.test.js +110 -122
- package/test/overlay-timer.test.js.map +7 -1
- package/test/overlay-trigger-click.test.js +43 -48
- package/test/overlay-trigger-click.test.js.map +7 -1
- package/test/overlay-trigger-extended.test.js +167 -182
- package/test/overlay-trigger-extended.test.js.map +7 -1
- package/test/overlay-trigger-hover-click.test.js +59 -73
- package/test/overlay-trigger-hover-click.test.js.map +7 -1
- package/test/overlay-trigger-hover.test.js +74 -77
- package/test/overlay-trigger-hover.test.js.map +7 -1
- package/test/overlay-trigger-longpress.test.js +166 -178
- package/test/overlay-trigger-longpress.test.js.map +7 -1
- package/test/overlay-trigger-sync.test.js +400 -422
- package/test/overlay-trigger-sync.test.js.map +7 -1
- package/test/overlay-trigger.test.js +400 -422
- package/test/overlay-trigger.test.js.map +7 -1
- package/test/overlay.test-vrt.js +4 -15
- package/test/overlay.test-vrt.js.map +7 -1
- package/test/overlay.test.js +458 -479
- package/test/overlay.test.js.map +7 -1
package/src/overlay-stack.js
CHANGED
|
@@ -1,135 +1,114 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
10
|
+
return event.button === 0;
|
|
18
11
|
}
|
|
19
12
|
function hasModifier(event) {
|
|
20
|
-
|
|
13
|
+
return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
|
|
21
14
|
}
|
|
22
15
|
export class OverlayStack {
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
210
|
-
|
|
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
|
-
|
|
213
|
-
|
|
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
|
-
|
|
216
|
-
|
|
217
|
-
if (overlayContent === item.overlayContent) {
|
|
218
|
-
return item;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
return undefined;
|
|
215
|
+
if (details.notImmediatelyClosable) {
|
|
216
|
+
this._doesNotCloseOnFirstClick = true;
|
|
222
217
|
}
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
233
|
-
|
|
221
|
+
const contentWithLifecycle = details.content;
|
|
222
|
+
if (contentWithLifecycle.overlayWillOpenCallback) {
|
|
223
|
+
const { trigger } = details;
|
|
224
|
+
contentWithLifecycle.overlayWillOpenCallback({ trigger });
|
|
234
225
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
-
|
|
272
|
-
|
|
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
|
-
|
|
310
|
-
|
|
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
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
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
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
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
|
-
|
|
478
|
-
|
|
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
|