Skip to content

Commit df36b64

Browse files
committed
feat(framework): Maintain a common z-index for all UI5 Web Components instances and OpenUI5 (#2980)
1 parent 9c156aa commit df36b64

File tree

8 files changed

+149
-84
lines changed

8 files changed

+149
-84
lines changed

packages/base/src/features/OpenUI5Support.js

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,41 @@
11
import { registerFeature } from "../FeaturesRegistry.js";
22
import { setTheme } from "../config/Theme.js";
3+
import { getCurrentZIndex } from "../util/PopupUtils.js";
34

4-
const sap = window.sap;
5-
const core = sap && sap.ui && typeof sap.ui.getCore === "function" && sap.ui.getCore();
5+
const getCore = () => {
6+
const sap = window.sap;
7+
const core = sap && sap.ui && typeof sap.ui.getCore === "function" && sap.ui.getCore();
8+
return core;
9+
};
610

711
const isLoaded = () => {
8-
return !!core;
12+
return !!getCore();
913
};
1014

1115
const init = () => {
16+
const core = getCore();
1217
if (!core) {
1318
return Promise.resolve();
1419
}
1520

1621
return new Promise(resolve => {
1722
core.attachInit(() => {
18-
sap.ui.require(["sap/ui/core/LocaleData"], resolve);
23+
window.sap.ui.require(["sap/ui/core/LocaleData", "sap/ui/core/Popup"], (LocaleData, Popup) => {
24+
Popup.setInitialZIndex(getCurrentZIndex());
25+
resolve();
26+
});
1927
});
2028
});
2129
};
2230

2331
const getConfigurationSettingsObject = () => {
32+
const core = getCore();
2433
if (!core) {
2534
return;
2635
}
2736

2837
const config = core.getConfiguration();
29-
const LocaleData = sap.ui.require("sap/ui/core/LocaleData");
38+
const LocaleData = window.sap.ui.require("sap/ui/core/LocaleData");
3039

3140
return {
3241
animationMode: config.getAnimationMode(),
@@ -41,23 +50,26 @@ const getConfigurationSettingsObject = () => {
4150
};
4251

4352
const getLocaleDataObject = () => {
53+
const core = getCore();
4454
if (!core) {
4555
return;
4656
}
4757

4858
const config = core.getConfiguration();
49-
const LocaleData = sap.ui.require("sap/ui/core/LocaleData");
59+
const LocaleData = window.sap.ui.require("sap/ui/core/LocaleData");
5060
return LocaleData.getInstance(config.getLocale())._get();
5161
};
5262

5363
const listenForThemeChange = () => {
64+
const core = getCore();
5465
const config = core.getConfiguration();
5566
core.attachThemeChanged(async () => {
5667
await setTheme(config.getTheme());
5768
});
5869
};
5970

6071
const attachListeners = () => {
72+
const core = getCore();
6173
if (!core) {
6274
return;
6375
}
@@ -66,6 +78,7 @@ const attachListeners = () => {
6678
};
6779

6880
const cssVariablesLoaded = () => {
81+
const core = getCore();
6982
if (!core) {
7083
return;
7184
}
@@ -78,13 +91,35 @@ const cssVariablesLoaded = () => {
7891
return !!link.href.match(/\/css(-|_)variables\.css/);
7992
};
8093

94+
const getNextZIndex = () => {
95+
const core = getCore();
96+
if (!core) {
97+
return;
98+
}
99+
100+
const Popup = window.sap.ui.require("sap/ui/core/Popup");
101+
return Popup.getNextZIndex();
102+
};
103+
104+
const setInitialZIndex = () => {
105+
const core = getCore();
106+
if (!core) {
107+
return;
108+
}
109+
110+
const Popup = window.sap.ui.require("sap/ui/core/Popup");
111+
Popup.setInitialZIndex(getCurrentZIndex());
112+
};
113+
81114
const OpenUI5Support = {
82115
isLoaded,
83116
init,
84117
getConfigurationSettingsObject,
85118
getLocaleDataObject,
86119
attachListeners,
87120
cssVariablesLoaded,
121+
getNextZIndex,
122+
setInitialZIndex,
88123
};
89124

90125
registerFeature("OpenUI5Support", OpenUI5Support);
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import getSharedResource from "../getSharedResource.js";
2+
import { getFeature } from "../FeaturesRegistry.js";
3+
import getActiveElement from "./getActiveElement.js";
4+
5+
const PopupUtilsData = getSharedResource("PopupUtilsData", {});
6+
PopupUtilsData.currentZIndex = PopupUtilsData.currentZIndex || 100;
7+
8+
const getFocusedElement = () => {
9+
const element = getActiveElement();
10+
return (element && typeof element.focus === "function") ? element : null;
11+
};
12+
13+
const isFocusedElementWithinNode = node => {
14+
const fe = getFocusedElement();
15+
16+
if (fe) {
17+
return isNodeContainedWithin(node, fe);
18+
}
19+
20+
return false;
21+
};
22+
23+
const isNodeContainedWithin = (parent, child) => {
24+
let currentNode = parent;
25+
26+
if (currentNode.shadowRoot) {
27+
currentNode = Array.from(currentNode.shadowRoot.children).find(n => n.localName !== "style");
28+
}
29+
30+
if (currentNode === child) {
31+
return true;
32+
}
33+
34+
const childNodes = currentNode.localName === "slot" ? currentNode.assignedNodes() : currentNode.children;
35+
36+
if (childNodes) {
37+
return Array.from(childNodes).some(n => isNodeContainedWithin(n, child));
38+
}
39+
};
40+
41+
const isPointInRect = (x, y, rect) => {
42+
return x >= rect.left && x <= rect.right
43+
&& y >= rect.top && y <= rect.bottom;
44+
};
45+
46+
const isClickInRect = (event, rect) => {
47+
let x;
48+
let y;
49+
50+
if (event.touches) {
51+
const touch = event.touches[0];
52+
x = touch.clientX;
53+
y = touch.clientY;
54+
} else {
55+
x = event.clientX;
56+
y = event.clientY;
57+
}
58+
59+
return isPointInRect(x, y, rect);
60+
};
61+
62+
const getClosedPopupParent = el => {
63+
const parent = el.parentElement || (el.getRootNode && el.getRootNode().host);
64+
65+
if (parent && ((parent.openBy && parent.isUI5Element) || (parent.open && parent.isUI5Element) || parent === document.documentElement)) {
66+
return parent;
67+
}
68+
69+
return getClosedPopupParent(parent);
70+
};
71+
72+
73+
const getNextZIndex = () => {
74+
const OpenUI5Support = getFeature("OpenUI5Support");
75+
if (OpenUI5Support && OpenUI5Support.isLoaded()) { // use OpenUI5 for getting z-index values, if loaded
76+
return OpenUI5Support.getNextZIndex();
77+
}
78+
79+
PopupUtilsData.currentZIndex += 2;
80+
return PopupUtilsData.currentZIndex;
81+
};
82+
83+
const getCurrentZIndex = () => {
84+
return PopupUtilsData.currentZIndex;
85+
};
86+
87+
export {
88+
getFocusedElement,
89+
isClickInRect,
90+
getClosedPopupParent,
91+
getNextZIndex,
92+
getCurrentZIndex,
93+
isFocusedElementWithinNode,
94+
};

packages/main/src/Popover.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import Integer from "@ui5/webcomponents-base/dist/types/Integer.js";
22
import ResizeHandler from "@ui5/webcomponents-base/dist/delegate/ResizeHandler.js";
3+
import { getClosedPopupParent } from "@ui5/webcomponents-base/dist/util/PopupUtils.js";
34
import Popup from "./Popup.js";
45
import PopoverPlacementType from "./types/PopoverPlacementType.js";
56
import PopoverVerticalAlign from "./types/PopoverVerticalAlign.js";
67
import PopoverHorizontalAlign from "./types/PopoverHorizontalAlign.js";
78
import { addOpenedPopover, removeOpenedPopover } from "./popup-utils/PopoverRegistry.js";
8-
import { getClosedPopupParent } from "./popup-utils/PopupUtils.js";
99

1010
// Template
1111
import PopoverTemplate from "./generated/templates/PopoverTemplate.lit.js";

packages/main/src/Popup.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
55
import { getFirstFocusableElement, getLastFocusableElement } from "@ui5/webcomponents-base/dist/util/FocusableElements.js";
66
import createStyleInHead from "@ui5/webcomponents-base/dist/util/createStyleInHead.js";
77
import { isTabPrevious } from "@ui5/webcomponents-base/dist/Keys.js";
8+
import { getNextZIndex, getFocusedElement, isFocusedElementWithinNode } from "@ui5/webcomponents-base/dist/util/PopupUtils.js";
89
import PopupTemplate from "./generated/templates/PopupTemplate.lit.js";
910
import PopupBlockLayer from "./generated/templates/PopupBlockLayerTemplate.lit.js";
10-
import { getNextZIndex, getFocusedElement, isFocusedElementWithinNode } from "./popup-utils/PopupUtils.js";
1111
import { addOpenedPopup, removeOpenedPopup } from "./popup-utils/OpenedPopupsRegistry.js";
1212

1313
// Styles

packages/main/src/ResponsivePopover.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { isPhone } from "@ui5/webcomponents-base/dist/Device.js";
2-
import { getNextZIndex } from "./popup-utils/PopupUtils.js";
2+
import { getNextZIndex } from "@ui5/webcomponents-base/dist/util/PopupUtils.js";
33
import ResponsivePopoverTemplate from "./generated/templates/ResponsivePopoverTemplate.lit.js";
44
import Popover from "./Popover.js";
55
import Dialog from "./Dialog.js";

packages/main/src/Toast.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import Integer from "@ui5/webcomponents-base/dist/types/Integer.js";
22
import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js";
33
import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js";
4+
import { getNextZIndex } from "@ui5/webcomponents-base/dist/util/PopupUtils.js";
45
import ToastPlacement from "./types/ToastPlacement.js";
5-
import { getNextZIndex } from "./popup-utils/PopupUtils.js";
66

77
// Template
88
import ToastTemplate from "./generated/templates/ToastTemplate.lit.js";

packages/main/src/popup-utils/PopoverRegistry.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isClickInRect } from "./PopupUtils.js";
1+
import { isClickInRect } from "@ui5/webcomponents-base/dist/util/PopupUtils.js";
22
import { getOpenedPopups, addOpenedPopup, removeOpenedPopup } from "./OpenedPopupsRegistry.js";
33

44

Lines changed: 9 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,17 @@
1-
import getActiveElement from "@ui5/webcomponents-base/dist/util/getActiveElement.js";
2-
3-
let currentZIndex = 100;
4-
5-
const getFocusedElement = () => {
6-
const element = getActiveElement();
7-
return (element && typeof element.focus === "function") ? element : null;
8-
};
9-
10-
const isFocusedElementWithinNode = node => {
11-
const fe = getFocusedElement();
12-
13-
if (fe) {
14-
return isNodeContainedWithin(node, fe);
15-
}
16-
17-
return false;
18-
};
19-
20-
const isNodeContainedWithin = (parent, child) => {
21-
let currentNode = parent;
22-
23-
if (currentNode.shadowRoot) {
24-
currentNode = Array.from(currentNode.shadowRoot.children).find(n => n.localName !== "style");
25-
}
26-
27-
if (currentNode === child) {
28-
return true;
29-
}
30-
31-
const childNodes = currentNode.localName === "slot" ? currentNode.assignedNodes() : currentNode.children;
32-
33-
if (childNodes) {
34-
return Array.from(childNodes).some(n => isNodeContainedWithin(n, child));
35-
}
36-
};
37-
38-
const isPointInRect = (x, y, rect) => {
39-
return x >= rect.left && x <= rect.right
40-
&& y >= rect.top && y <= rect.bottom;
41-
};
42-
43-
const isClickInRect = (event, rect) => {
44-
let x;
45-
let y;
46-
47-
if (event.touches) {
48-
const touch = event.touches[0];
49-
x = touch.clientX;
50-
y = touch.clientY;
51-
} else {
52-
x = event.clientX;
53-
y = event.clientY;
54-
}
55-
56-
return isPointInRect(x, y, rect);
57-
};
58-
59-
const getClosedPopupParent = el => {
60-
const parent = el.parentElement || (el.getRootNode && el.getRootNode().host);
61-
62-
if (parent && ((parent.openBy && parent.isUI5Element) || (parent.open && parent.isUI5Element) || parent === document.documentElement)) {
63-
return parent;
64-
}
65-
66-
return getClosedPopupParent(parent);
67-
};
68-
69-
70-
const getNextZIndex = () => {
71-
currentZIndex += 2;
72-
return currentZIndex;
73-
};
1+
import {
2+
getFocusedElement,
3+
isClickInRect,
4+
getClosedPopupParent,
5+
getNextZIndex,
6+
getCurrentZIndex,
7+
isFocusedElementWithinNode,
8+
} from "@ui5/webcomponents-base/dist/util/PopupUtils.js";
749

7510
export {
7611
getFocusedElement,
7712
isClickInRect,
7813
getClosedPopupParent,
7914
getNextZIndex,
15+
getCurrentZIndex,
8016
isFocusedElementWithinNode,
8117
};

0 commit comments

Comments
 (0)