@ui5/webcomponents-base 0.0.0-4180fe799 → 0.0.0-453158269
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/.eslintignore +1 -1
- package/CHANGELOG.md +211 -0
- package/dist/Boot.js +34 -18
- package/dist/CustomElementsRegistry.js +60 -4
- package/dist/CustomElementsScope.js +20 -98
- package/dist/CustomElementsScopeUtils.js +108 -0
- package/dist/Device.js +15 -1
- package/dist/FeaturesRegistry.js +4 -1
- package/dist/Keys.js +47 -0
- package/dist/Runtimes.js +107 -0
- package/dist/StaticAreaItem.js +4 -1
- package/dist/UI5Element.js +18 -3
- package/dist/UI5ElementMetadata.js +9 -1
- package/dist/asset-registries/Icons.js +3 -7
- package/dist/asset-registries/LocaleData.js +6 -1
- package/dist/asset-registries/Themes.js +6 -2
- package/dist/config/Icons.js +52 -0
- package/dist/config/Theme.js +11 -0
- package/dist/css/BusyIndicator.css +80 -0
- package/dist/css/FontFace.css +38 -8
- package/dist/features/F6Navigation.js +106 -0
- package/dist/features/OpenUI5Enablement.js +119 -0
- package/dist/generated/AssetParameters.js +1 -1
- package/dist/generated/VersionInfo.js +10 -0
- package/dist/generated/css/BusyIndicator.css.js +5 -0
- package/dist/generated/css/FontFace.css.js +1 -1
- package/dist/renderer/LitRenderer.js +29 -11
- package/dist/renderer/executeTemplate.js +19 -2
- package/dist/resources/bundle.esm.js +8 -13
- package/dist/resources/bundle.esm.js.map +1 -1
- package/dist/sap/base/security/encodeCSS.js +14 -0
- package/dist/sap/base/security/encodeXML.js +23 -0
- package/dist/sap/base/strings/toHex.js +8 -0
- package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +1 -1
- package/dist/test-resources/specs/Theming.spec.js +11 -0
- package/dist/theming/CustomStyle.js +23 -3
- package/dist/theming/applyTheme.js +8 -4
- package/dist/theming/getEffectiveLinksHrefs.js +7 -0
- package/dist/theming/getEffectiveStyle.js +9 -0
- package/dist/theming/getThemeDesignerTheme.js +24 -5
- package/dist/updateShadowRoot.js +1 -1
- package/dist/util/FocusableElements.js +8 -6
- package/dist/util/InvisibleMessage.js +11 -9
- package/dist/util/TabbableElements.js +4 -0
- package/dist/util/escapeRegex.js +10 -0
- package/dist/util/generateHighlightedMarkup.js +42 -0
- package/dist/util/getNormalizedTarget.js +16 -0
- package/dist/util/isNodeHidden.js +1 -1
- package/hash.txt +1 -1
- package/lib/generate-asset-parameters/index.js +8 -4
- package/lib/generate-styles/index.js +17 -9
- package/lib/generate-version-info/index.js +32 -0
- package/package-scripts.js +5 -12
- package/package.json +6 -6
- package/src/Boot.js +34 -18
- package/src/CustomElementsRegistry.js +60 -4
- package/src/CustomElementsScope.js +20 -98
- package/src/CustomElementsScopeUtils.js +108 -0
- package/src/Device.js +15 -1
- package/src/FeaturesRegistry.js +4 -1
- package/src/Keys.js +47 -0
- package/src/Runtimes.js +107 -0
- package/src/StaticAreaItem.js +4 -1
- package/src/UI5Element.js +18 -3
- package/src/UI5ElementMetadata.js +9 -1
- package/src/asset-registries/Icons.js +3 -7
- package/src/asset-registries/LocaleData.js +6 -1
- package/src/asset-registries/Themes.js +6 -2
- package/src/config/Icons.js +52 -0
- package/src/config/Theme.js +11 -0
- package/src/css/BusyIndicator.css +80 -0
- package/src/css/FontFace.css +38 -8
- package/src/features/F6Navigation.js +106 -0
- package/src/features/OpenUI5Enablement.js +119 -0
- package/src/renderer/LitRenderer.js +29 -11
- package/src/renderer/executeTemplate.js +19 -2
- package/src/theming/CustomStyle.js +23 -3
- package/src/theming/applyTheme.js +8 -4
- package/src/theming/getEffectiveLinksHrefs.js +7 -0
- package/src/theming/getEffectiveStyle.js +9 -0
- package/src/theming/getThemeDesignerTheme.js +24 -5
- package/src/updateShadowRoot.js +1 -1
- package/src/util/FocusableElements.js +8 -6
- package/src/util/InvisibleMessage.js +11 -9
- package/src/util/TabbableElements.js +4 -0
- package/src/util/escapeRegex.js +10 -0
- package/src/util/generateHighlightedMarkup.js +42 -0
- package/src/util/getNormalizedTarget.js +16 -0
- package/src/util/isNodeHidden.js +1 -1
- package/used-modules.txt +4 -1
- package/dist/util/encodeCSS.js +0 -24
- package/src/util/encodeCSS.js +0 -24
package/src/StaticAreaItem.js
CHANGED
|
@@ -2,7 +2,7 @@ import "./StaticArea.js";
|
|
|
2
2
|
import updateShadowRoot from "./updateShadowRoot.js";
|
|
3
3
|
import { renderFinished } from "./Render.js";
|
|
4
4
|
import getEffectiveContentDensity from "./util/getEffectiveContentDensity.js";
|
|
5
|
-
import { getEffectiveScopingSuffixForTag } from "./
|
|
5
|
+
import { getEffectiveScopingSuffixForTag } from "./CustomElementsScopeUtils.js";
|
|
6
6
|
import getEffectiveDir from "./locale/getEffectiveDir.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -25,6 +25,9 @@ class StaticAreaItem extends HTMLElement {
|
|
|
25
25
|
setOwnerElement(ownerElement) {
|
|
26
26
|
this.ownerElement = ownerElement;
|
|
27
27
|
this.classList.add(this.ownerElement._id); // used for getting the popover in the tests
|
|
28
|
+
if (this.ownerElement.hasAttribute("data-ui5-static-stable")) {
|
|
29
|
+
this.setAttribute("data-ui5-stable", this.ownerElement.getAttribute("data-ui5-static-stable")); // stable selector
|
|
30
|
+
}
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
/**
|
package/src/UI5Element.js
CHANGED
|
@@ -46,6 +46,8 @@ function _invalidate(changeInfo) {
|
|
|
46
46
|
this._eventProvider.fireEvent("invalidate", { ...changeInfo, target: this });
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
let metadata = {};
|
|
50
|
+
|
|
49
51
|
/**
|
|
50
52
|
* Base class for all UI5 Web Components
|
|
51
53
|
*
|
|
@@ -101,6 +103,9 @@ class UI5Element extends HTMLElement {
|
|
|
101
103
|
*/
|
|
102
104
|
async connectedCallback() {
|
|
103
105
|
this.setAttribute(this.constructor.getMetadata().getPureTag(), "");
|
|
106
|
+
if (this.constructor.getMetadata().supportsF6FastNavigation()) {
|
|
107
|
+
this.setAttribute("data-sap-ui-fastnavgroup", "true");
|
|
108
|
+
}
|
|
104
109
|
|
|
105
110
|
const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
|
|
106
111
|
|
|
@@ -251,7 +256,8 @@ class UI5Element extends HTMLElement {
|
|
|
251
256
|
|
|
252
257
|
// Listen for any invalidation on the child if invalidateOnChildChange is true or an object (ignore when false or not set)
|
|
253
258
|
if (child.isUI5Element && slotData.invalidateOnChildChange) {
|
|
254
|
-
child.attachInvalidate
|
|
259
|
+
const method = (child.attachInvalidate || child._attachChange).bind(child);
|
|
260
|
+
method(this._getChildChangeListener(slotName));
|
|
255
261
|
}
|
|
256
262
|
|
|
257
263
|
// Listen for the slotchange event if the child is a slot itself
|
|
@@ -311,7 +317,8 @@ class UI5Element extends HTMLElement {
|
|
|
311
317
|
|
|
312
318
|
children.forEach(child => {
|
|
313
319
|
if (child && child.isUI5Element) {
|
|
314
|
-
child.detachInvalidate
|
|
320
|
+
const method = (child.detachInvalidate || child._detachChange).bind(child);
|
|
321
|
+
method(this._getChildChangeListener(slotName));
|
|
315
322
|
}
|
|
316
323
|
|
|
317
324
|
if (isSlot(child)) {
|
|
@@ -891,7 +898,15 @@ class UI5Element extends HTMLElement {
|
|
|
891
898
|
* @protected
|
|
892
899
|
*/
|
|
893
900
|
static get metadata() {
|
|
894
|
-
return
|
|
901
|
+
return metadata;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Sets a new metadata object for this UI5 Web Component Class
|
|
906
|
+
* @protected
|
|
907
|
+
*/
|
|
908
|
+
static set metadata(newMetadata) {
|
|
909
|
+
metadata = newMetadata;
|
|
895
910
|
}
|
|
896
911
|
|
|
897
912
|
/**
|
|
@@ -2,7 +2,7 @@ import DataType from "./types/DataType.js";
|
|
|
2
2
|
import isDescendantOf from "./util/isDescendantOf.js";
|
|
3
3
|
import { camelToKebabCase } from "./util/StringHelper.js";
|
|
4
4
|
import { getSlottedElements } from "./util/SlotsHelper.js";
|
|
5
|
-
import { getEffectiveScopingSuffixForTag } from "./
|
|
5
|
+
import { getEffectiveScopingSuffixForTag } from "./CustomElementsScopeUtils.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
*
|
|
@@ -188,6 +188,14 @@ class UI5ElementMetadata {
|
|
|
188
188
|
return !!this.metadata.managedSlots;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Determines whether this control supports F6 fast navigation
|
|
193
|
+
* @public
|
|
194
|
+
*/
|
|
195
|
+
supportsF6FastNavigation() {
|
|
196
|
+
return !!this.metadata.fastNavigation;
|
|
197
|
+
}
|
|
198
|
+
|
|
191
199
|
/**
|
|
192
200
|
* Returns an object with key-value pairs of properties and their metadata definitions
|
|
193
201
|
* @public
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import getSharedResource from "../getSharedResource.js";
|
|
2
2
|
import IconCollectionsAlias from "../assets-meta/IconCollectionsAlias.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getEffectiveDefaultIconCollection } from "../config/Icons.js";
|
|
4
4
|
|
|
5
5
|
const loaders = new Map();
|
|
6
6
|
const registry = getSharedResource("SVGIcons.registry", new Map());
|
|
@@ -48,7 +48,7 @@ const _fillRegistry = bundleData => {
|
|
|
48
48
|
// set
|
|
49
49
|
const registerIcon = (name, { pathData, ltr, accData, collection, packageName } = {}) => { // eslint-disable-line
|
|
50
50
|
if (!collection) {
|
|
51
|
-
collection =
|
|
51
|
+
collection = getEffectiveDefaultIconCollection();
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
const key = `${collection}/${name}`;
|
|
@@ -68,7 +68,7 @@ const _parseName = name => {
|
|
|
68
68
|
|
|
69
69
|
let collection;
|
|
70
70
|
[name, collection] = name.split("/").reverse();
|
|
71
|
-
collection = collection ||
|
|
71
|
+
collection = collection || getEffectiveDefaultIconCollection();
|
|
72
72
|
|
|
73
73
|
// Normalize collection name.
|
|
74
74
|
// - resolve `SAP-icons-TNT` to `tnt`.
|
|
@@ -117,10 +117,6 @@ const _getRegisteredNames = async () => {
|
|
|
117
117
|
return Array.from(registry.keys());
|
|
118
118
|
};
|
|
119
119
|
|
|
120
|
-
const _getDefaultCollection = () => {
|
|
121
|
-
return isTheme("sap_horizon") ? "SAP-icons-v5" : "SAP-icons";
|
|
122
|
-
};
|
|
123
|
-
|
|
124
120
|
const _normalizeCollection = collectionName => {
|
|
125
121
|
if (IconCollectionsAlias[collectionName]) {
|
|
126
122
|
return IconCollectionsAlias[collectionName];
|
|
@@ -13,7 +13,6 @@ const M_ISO639_OLD_TO_NEW = {
|
|
|
13
13
|
"iw": "he",
|
|
14
14
|
"ji": "yi",
|
|
15
15
|
"in": "id",
|
|
16
|
-
"sh": "sr",
|
|
17
16
|
};
|
|
18
17
|
|
|
19
18
|
const DEV_MODE = false;
|
|
@@ -48,6 +47,12 @@ const calcLocale = (language, region, script) => {
|
|
|
48
47
|
}
|
|
49
48
|
}
|
|
50
49
|
|
|
50
|
+
// Special case 3: for Serbian, there are cyrillic and latin scripts, "sh" and "sr-latn" map to "latin", "sr" maps to cyrillic.
|
|
51
|
+
if (language === "sh" || (language === "sr" && script === "Latn")) {
|
|
52
|
+
language = "sr";
|
|
53
|
+
region = "Latn";
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
// try language + region
|
|
52
57
|
let localeId = `${language}_${region}`;
|
|
53
58
|
if (SUPPORTED_LOCALES.includes(localeId)) {
|
|
@@ -38,10 +38,14 @@ const getThemeProperties = async (packageName, themeName) => {
|
|
|
38
38
|
|
|
39
39
|
if (!registeredThemes.has(themeName)) {
|
|
40
40
|
const regThemesStr = [...registeredThemes.values()].join(", ");
|
|
41
|
-
console.warn(`You have requested a non-registered theme - falling back to ${DEFAULT_THEME}. Registered themes are: ${regThemesStr}`); /* eslint-disable-line */
|
|
42
|
-
return
|
|
41
|
+
console.warn(`You have requested a non-registered theme ${themeName} - falling back to ${DEFAULT_THEME}. Registered themes are: ${regThemesStr}`); /* eslint-disable-line */
|
|
42
|
+
return _getThemeProperties(packageName, DEFAULT_THEME);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
return _getThemeProperties(packageName, themeName);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const _getThemeProperties = async (packageName, themeName) => {
|
|
45
49
|
const loader = loaders.get(`${packageName}/${themeName}`);
|
|
46
50
|
if (!loader) {
|
|
47
51
|
// no themes for package
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getTheme, isThemeFamily } from "./Theme.js";
|
|
2
|
+
|
|
3
|
+
const IconCollectionConfiguration = new Map();
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sets the default icon collection (v4 or v5) per theme,
|
|
7
|
+
* which will be applied in case icon collection is not specified.
|
|
8
|
+
*
|
|
9
|
+
* Note: by default SAP-icons-v5 is used in SAP Horizon and SAP-icons-v4 for all the rest.
|
|
10
|
+
* @param {String} theme
|
|
11
|
+
* @param {String} collectionName
|
|
12
|
+
*/
|
|
13
|
+
const setDefaultIconCollection = (theme, collectionName) => {
|
|
14
|
+
if (collectionName === "horizon") {
|
|
15
|
+
collectionName = "SAP-icons-v5";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
IconCollectionConfiguration.set(theme, collectionName);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns the default icon collection (v4 or v5) for given theme,
|
|
23
|
+
* that is configured.
|
|
24
|
+
*
|
|
25
|
+
* @param {String} theme
|
|
26
|
+
* @returns {String}
|
|
27
|
+
*/
|
|
28
|
+
const getDefaultIconCollection = theme => {
|
|
29
|
+
return IconCollectionConfiguration.get(theme);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns the effective icon collection that will be applied for icon web components
|
|
34
|
+
* whenever namespace is not specified.
|
|
35
|
+
* @returns {String}
|
|
36
|
+
*/
|
|
37
|
+
const getEffectiveDefaultIconCollection = () => {
|
|
38
|
+
const currentTheme = getTheme();
|
|
39
|
+
const currentThemeConfiguration = IconCollectionConfiguration.get(currentTheme);
|
|
40
|
+
|
|
41
|
+
if (currentThemeConfiguration) {
|
|
42
|
+
return currentThemeConfiguration;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return isThemeFamily("sap_horizon") ? "SAP-icons-v5" : "SAP-icons";
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
setDefaultIconCollection,
|
|
50
|
+
getDefaultIconCollection,
|
|
51
|
+
getEffectiveDefaultIconCollection,
|
|
52
|
+
};
|
package/src/config/Theme.js
CHANGED
|
@@ -35,8 +35,19 @@ const isTheme = _theme => {
|
|
|
35
35
|
return currentTheme === _theme || currentTheme === `${_theme}_exp`;
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Returns if the current theme is part of given theme family
|
|
40
|
+
* @private
|
|
41
|
+
* @param {String} the theme family
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
const isThemeFamily = _theme => {
|
|
45
|
+
return getTheme().startsWith(_theme);
|
|
46
|
+
};
|
|
47
|
+
|
|
38
48
|
export {
|
|
39
49
|
getTheme,
|
|
40
50
|
setTheme,
|
|
41
51
|
isTheme,
|
|
52
|
+
isThemeFamily,
|
|
42
53
|
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
.busy-indicator-wrapper {
|
|
2
|
+
position: relative;
|
|
3
|
+
height: 100%;
|
|
4
|
+
width: 100%;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.busy-indicator-overlay {
|
|
8
|
+
display: var(--ui5_web_components_busy_indicator_display);
|
|
9
|
+
position: absolute;
|
|
10
|
+
inset: 0;
|
|
11
|
+
background: var(--ui5_web_components_busy_indicator_background-color);
|
|
12
|
+
z-index: 99;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.busy-indicator-busy-area {
|
|
16
|
+
display: var(--ui5_web_components_busy_indicator_display);
|
|
17
|
+
position: absolute;
|
|
18
|
+
z-index: 99;
|
|
19
|
+
inset: 0;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
align-items: center;
|
|
22
|
+
background-color: inherit;
|
|
23
|
+
flex-direction: column;
|
|
24
|
+
color: var(--_ui5_busy_indicator_color);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
:host([__is-busy]) .busy-indicator-wrapper > :not(.busy-indicator-busy-area):not(.busy-indicator-overlay):not([busy-indicator-before-span]) {
|
|
28
|
+
--ui5_web_components_busy_indicator_display: none;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.busy-indicator-busy-area:focus {
|
|
32
|
+
outline: var(--_ui5_busy_indicator_focus_outline);
|
|
33
|
+
outline-offset: -.125rem;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.busy-indicator-circle {
|
|
37
|
+
width: 1rem;
|
|
38
|
+
height: 1rem;
|
|
39
|
+
display: inline-block;
|
|
40
|
+
background-color: currentColor;
|
|
41
|
+
border-radius: 50%;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.circle-animation-0 {
|
|
45
|
+
animation: grow 1.6s infinite cubic-bezier(0.32, 0.06, 0.85, 1.11);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.circle-animation-1 {
|
|
49
|
+
animation: grow 1.6s infinite cubic-bezier(0.32, 0.06, 0.85, 1.11);
|
|
50
|
+
animation-delay: 200ms;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.circle-animation-2 {
|
|
54
|
+
animation: grow 1.6s infinite cubic-bezier(0.32, 0.06, 0.85, 1.11);
|
|
55
|
+
animation-delay: 400ms;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.sapUiLocalBusy {
|
|
59
|
+
--ui5_web_components_busy_indicator_display: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.busy-indicator-wrapper [ui5-busy-indicator] {
|
|
63
|
+
display: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@keyframes grow {
|
|
67
|
+
0%, 50%, 100% {
|
|
68
|
+
-webkit-transform: scale(0.5);
|
|
69
|
+
-moz-transform: scale(0.5);
|
|
70
|
+
-ms-transform: scale(0.5);
|
|
71
|
+
transform: scale(0.5);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
25% {
|
|
75
|
+
-webkit-transform: scale(1);
|
|
76
|
+
-moz-transform: scale(1);
|
|
77
|
+
-ms-transform: scale(1);
|
|
78
|
+
transform: scale(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/css/FontFace.css
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
font-style: normal;
|
|
4
4
|
font-weight: 400;
|
|
5
5
|
src: local("72"),
|
|
6
|
-
url(https://ui5.sap.com/
|
|
7
|
-
url(https://ui5.sap.com/
|
|
6
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular.woff2?ui5-webcomponents) format("woff2"),
|
|
7
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular.woff?ui5-webcomponents) format("woff");
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
@font-face {
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
font-style: normal;
|
|
13
13
|
font-weight: 400;
|
|
14
14
|
src: local('72-full'),
|
|
15
|
-
url(https://ui5.sap.com/
|
|
16
|
-
url(https://ui5.sap.com/
|
|
15
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular-full.woff2?ui5-webcomponents) format("woff2"),
|
|
16
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular-full.woff?ui5-webcomponents) format("woff");
|
|
17
17
|
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
font-style: normal;
|
|
23
23
|
font-weight: 700;
|
|
24
24
|
src: local('72-Bold'),
|
|
25
|
-
url(https://ui5.sap.com/
|
|
26
|
-
url(https://ui5.sap.com/
|
|
25
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold.woff2?ui5-webcomponents) format("woff2"),
|
|
26
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold.woff?ui5-webcomponents) format("woff");
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
@font-face {
|
|
@@ -31,8 +31,38 @@
|
|
|
31
31
|
font-style: normal;
|
|
32
32
|
font-weight: 700;
|
|
33
33
|
src: local('72-Bold-full'),
|
|
34
|
-
url(https://ui5.sap.com/
|
|
35
|
-
url(https://ui5.sap.com/
|
|
34
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold-full.woff2?ui5-webcomponents) format("woff2"),
|
|
35
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold-full.woff?ui5-webcomponents) format("woff");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@font-face {
|
|
39
|
+
font-family: '72-Bold';
|
|
40
|
+
font-style: normal;
|
|
41
|
+
src: local('72-Bold'),
|
|
42
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold.woff2?ui5-webcomponents) format("woff2"),
|
|
43
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold.woff?ui5-webcomponents) format("woff");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@font-face {
|
|
47
|
+
font-family: '72-Boldfull';
|
|
48
|
+
font-style: normal;
|
|
49
|
+
src: url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold-full.woff2?ui5-webcomponents) format("woff2"),
|
|
50
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold-full.woff?ui5-webcomponents) format("woff");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@font-face {
|
|
54
|
+
font-family: '72-Light';
|
|
55
|
+
font-style: normal;
|
|
56
|
+
src: local('72-Light'),
|
|
57
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Light.woff2?ui5-webcomponents) format("woff2"),
|
|
58
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Light.woff?ui5-webcomponents) format("woff");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@font-face {
|
|
62
|
+
font-family: '72-Lightfull';
|
|
63
|
+
font-style: normal;
|
|
64
|
+
src: url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Light-full.woff2?ui5-webcomponents) format("woff2"),
|
|
65
|
+
url(https://ui5.sap.com/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Light-full.woff?ui5-webcomponents) format("woff");
|
|
36
66
|
}
|
|
37
67
|
|
|
38
68
|
@font-face {
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { registerFeature } from "../FeaturesRegistry.js";
|
|
2
|
+
import { isF6Next, isF6Previous } from "../Keys.js";
|
|
3
|
+
import { getFirstFocusableElement } from "../util/FocusableElements.js";
|
|
4
|
+
|
|
5
|
+
class F6Navigation {
|
|
6
|
+
init() {
|
|
7
|
+
this.keydownHandler = this._keydownHandler.bind(this);
|
|
8
|
+
this.attachEventListeners();
|
|
9
|
+
this.selectedGroup = null;
|
|
10
|
+
this.groups = [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
attachEventListeners() {
|
|
14
|
+
document.addEventListener("keydown", this.keydownHandler);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async _keydownHandler(event) {
|
|
18
|
+
if (isF6Next(event)) {
|
|
19
|
+
this.updateGroups();
|
|
20
|
+
if (this.groups.length < 1) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const nextIndex = this.groups.indexOf(this.selectedGroup);
|
|
25
|
+
let nextElement = null;
|
|
26
|
+
|
|
27
|
+
if (nextIndex > -1) {
|
|
28
|
+
if (nextIndex + 1 >= this.groups.length) {
|
|
29
|
+
nextElement = this.groups[0];
|
|
30
|
+
} else {
|
|
31
|
+
nextElement = this.groups[nextIndex + 1];
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
nextElement = this.groups[0];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const elementToFocus = await getFirstFocusableElement(nextElement.isUI5Element ? nextElement.getDomRef() : nextElement, true);
|
|
38
|
+
elementToFocus.focus();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (isF6Previous(event)) {
|
|
42
|
+
this.updateGroups();
|
|
43
|
+
if (this.groups.length < 1) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const nextIndex = this.groups.indexOf(this.selectedGroup);
|
|
48
|
+
let nextElement = null;
|
|
49
|
+
|
|
50
|
+
if (nextIndex > -1) {
|
|
51
|
+
if (nextIndex - 1 < 0) {
|
|
52
|
+
nextElement = this.groups[this.groups.length - 1];
|
|
53
|
+
} else {
|
|
54
|
+
// Handle the situation where the first focusable element of two neighbor groups is the same
|
|
55
|
+
// For example:
|
|
56
|
+
// <ui5-flexible-column-layout>
|
|
57
|
+
// <ui5-list>
|
|
58
|
+
// <ui5-li>List Item</ui5-li>
|
|
59
|
+
// </ui5-list>
|
|
60
|
+
// </ui5-flexible-column-layout>
|
|
61
|
+
// Here for both FCL & List the firstFoccusableElement is the same (the ui5-li)
|
|
62
|
+
|
|
63
|
+
const firstFocusable = await getFirstFocusableElement(this.groups[nextIndex - 1], true);
|
|
64
|
+
const shouldSkipParent = firstFocusable === await getFirstFocusableElement(this.groups[nextIndex], true);
|
|
65
|
+
|
|
66
|
+
nextElement = this.groups[shouldSkipParent ? nextIndex - 2 : nextIndex - 1];
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
nextElement = this.groups[this.groups.length - 1];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const elementToFocus = await getFirstFocusableElement(nextElement.isUI5Element ? nextElement.getDomRef() : nextElement, true);
|
|
73
|
+
elementToFocus.focus();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
removeEventListeners() {
|
|
78
|
+
document.removeEventListener("keydown", this.keydownHandler);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
updateGroups() {
|
|
82
|
+
this.setSelectedGroup(document.activeElement);
|
|
83
|
+
this.setGroups();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
setGroups() {
|
|
87
|
+
this.groups = Array.from(document.querySelectorAll("[data-sap-ui-fastnavgroup='true']")).filter(group => group.clientWidth && window.getComputedStyle(group).visibility !== "hidden");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
setSelectedGroup(element) {
|
|
91
|
+
while (element && element.getAttribute("data-sap-ui-fastnavgroup") !== "true" && element !== document.querySelector("html")) {
|
|
92
|
+
element = element.parentElement ? element.parentNode : element.parentNode.host;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
this.selectedGroup = element;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
destroy() {
|
|
99
|
+
this.removeEventListeners();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const F6HelperInstance = new F6Navigation();
|
|
104
|
+
registerFeature("F6Navigation", F6HelperInstance);
|
|
105
|
+
|
|
106
|
+
export default F6Navigation;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { registerFeature } from "../FeaturesRegistry.js";
|
|
2
|
+
import BusyIndicatorStyles from "../generated/css/BusyIndicator.css.js";
|
|
3
|
+
import merge from "../thirdparty/merge.js";
|
|
4
|
+
import {
|
|
5
|
+
isTabPrevious,
|
|
6
|
+
} from "../Keys.js";
|
|
7
|
+
|
|
8
|
+
const busyIndicatorMetadata = {
|
|
9
|
+
properties: {
|
|
10
|
+
__isBusy: {
|
|
11
|
+
type: Boolean,
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const getBusyIndicatorStyles = () => {
|
|
17
|
+
return BusyIndicatorStyles;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const wrapTemplateResultInBusyMarkup = (html, host, templateResult) => {
|
|
21
|
+
if (host.isOpenUI5Component && host.__isBusy) {
|
|
22
|
+
templateResult = html`
|
|
23
|
+
<div class="busy-indicator-wrapper">
|
|
24
|
+
<span tabindex="0" busy-indicator-before-span @focusin=${host.__suppressFocusIn}></span>
|
|
25
|
+
${templateResult}
|
|
26
|
+
<div class="busy-indicator-overlay"></div>
|
|
27
|
+
<div busy-indicator
|
|
28
|
+
class="busy-indicator-busy-area"
|
|
29
|
+
tabindex="0"
|
|
30
|
+
role="progressbar"
|
|
31
|
+
@keydown=${host.__suppressFocusBack}
|
|
32
|
+
aria-valuemin="0"
|
|
33
|
+
aria-valuemax="100"
|
|
34
|
+
aria-valuetext="Busy">
|
|
35
|
+
<div>
|
|
36
|
+
<div class="busy-indicator-circle circle-animation-0"></div>
|
|
37
|
+
<div class="busy-indicator-circle circle-animation-1"></div>
|
|
38
|
+
<div class="busy-indicator-circle circle-animation-2"></div>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</div>`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return templateResult;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const enrichBusyIndicatorMetadata = UI5Element => {
|
|
48
|
+
UI5Element.metadata = merge(UI5Element.metadata, busyIndicatorMetadata);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const enrichBusyIndicatorMethods = UI5ElementPrototype => {
|
|
52
|
+
Object.defineProperties(UI5ElementPrototype, {
|
|
53
|
+
"__redirectFocus": { value: true, writable: true },
|
|
54
|
+
"__suppressFocusBack": {
|
|
55
|
+
get() {
|
|
56
|
+
const that = this;
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
handleEvent: e => {
|
|
60
|
+
if (isTabPrevious(e)) {
|
|
61
|
+
const beforeElem = that.shadowRoot.querySelector("[busy-indicator-before-span]");
|
|
62
|
+
that.__redirectFocus = false;
|
|
63
|
+
beforeElem.focus();
|
|
64
|
+
that.__redirectFocus = true;
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
capture: true,
|
|
68
|
+
passive: false,
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
"isOpenUI5Component": { get: () => { return true; } },
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
UI5ElementPrototype.__suppressFocusIn = function handleFocusIn() {
|
|
76
|
+
const busyIndicator = this.shadowRoot.querySelector("[busy-indicator]");
|
|
77
|
+
if (busyIndicator && this.__redirectFocus) {
|
|
78
|
+
busyIndicator.focus();
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
UI5ElementPrototype.getDomRef = function getDomRef() {
|
|
83
|
+
// If a component set _getRealDomRef to its children, use the return value of this function
|
|
84
|
+
if (typeof this._getRealDomRef === "function") {
|
|
85
|
+
return this._getRealDomRef();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!this.shadowRoot || this.shadowRoot.children.length === 0) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const children = [...this.shadowRoot.children].filter(child => !["link", "style"].includes(child.localName));
|
|
93
|
+
|
|
94
|
+
if (children.length !== 1) {
|
|
95
|
+
console.warn(`The shadow DOM for ${this.constructor.getMetadata().getTag()} does not have a top level element, the getDomRef() method might not work as expected`); // eslint-disable-line
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (this.__isBusy) {
|
|
99
|
+
return children[0].querySelector(".busy-indicator-wrapper > :not([busy-indicator-before-span]):not(.busy-indicator-overlay):not(.busy-indicator-busy-area)");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return children[0];
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const enrichBusyIndicatorSettings = UI5Element => {
|
|
107
|
+
enrichBusyIndicatorMetadata(UI5Element);
|
|
108
|
+
enrichBusyIndicatorMethods(UI5Element.prototype);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const OpenUI5Enablement = {
|
|
112
|
+
enrichBusyIndicatorSettings,
|
|
113
|
+
wrapTemplateResultInBusyMarkup,
|
|
114
|
+
getBusyIndicatorStyles,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export default OpenUI5Enablement;
|
|
118
|
+
|
|
119
|
+
registerFeature("OpenUI5Enablement", OpenUI5Enablement);
|
|
@@ -1,28 +1,46 @@
|
|
|
1
|
-
import { render } from "lit-html";
|
|
2
1
|
import {
|
|
2
|
+
render,
|
|
3
3
|
html,
|
|
4
4
|
svg,
|
|
5
|
-
|
|
6
|
-
} from "
|
|
5
|
+
} from "lit-html";
|
|
6
|
+
import { getFeature } from "../FeaturesRegistry.js";
|
|
7
|
+
|
|
8
|
+
const effectiveHtml = (...args) => {
|
|
9
|
+
const LitStatic = getFeature("LitStatic");
|
|
10
|
+
const fn = LitStatic ? LitStatic.html : html;
|
|
11
|
+
return fn(...args);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const effectiveSvg = (...args) => {
|
|
15
|
+
const LitStatic = getFeature("LitStatic");
|
|
16
|
+
const fn = LitStatic ? LitStatic.svg : svg;
|
|
17
|
+
return fn(...args);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const litRender = (templateResult, domNode, styleStrOrHrefsArr, forStaticArea, { host } = {}) => {
|
|
21
|
+
const OpenUI5Enablement = getFeature("OpenUI5Enablement");
|
|
22
|
+
if (OpenUI5Enablement && !forStaticArea) {
|
|
23
|
+
templateResult = OpenUI5Enablement.wrapTemplateResultInBusyMarkup(effectiveHtml, host, templateResult);
|
|
24
|
+
}
|
|
7
25
|
|
|
8
|
-
const litRender = (templateResult, domNode, styleStrOrHrefsArr, { host } = {}) => {
|
|
9
26
|
if (typeof styleStrOrHrefsArr === "string") {
|
|
10
|
-
templateResult =
|
|
27
|
+
templateResult = effectiveHtml`<style>${styleStrOrHrefsArr}</style>${templateResult}`;
|
|
11
28
|
} else if (Array.isArray(styleStrOrHrefsArr) && styleStrOrHrefsArr.length) {
|
|
12
|
-
templateResult =
|
|
29
|
+
templateResult = effectiveHtml`${styleStrOrHrefsArr.map(href => effectiveHtml`<link type="text/css" rel="stylesheet" href="${href}">`)}${templateResult}`;
|
|
13
30
|
}
|
|
14
31
|
render(templateResult, domNode, { host });
|
|
15
32
|
};
|
|
16
33
|
|
|
17
34
|
const scopeTag = (tag, tags, suffix) => {
|
|
18
|
-
const
|
|
19
|
-
|
|
35
|
+
const LitStatic = getFeature("LitStatic");
|
|
36
|
+
if (LitStatic) {
|
|
37
|
+
return LitStatic.unsafeStatic((tags || []).includes(tag) ? `${tag}-${suffix}` : tag);
|
|
38
|
+
}
|
|
20
39
|
};
|
|
21
40
|
|
|
22
41
|
export {
|
|
23
|
-
html,
|
|
24
|
-
svg,
|
|
25
|
-
unsafeStatic,
|
|
42
|
+
effectiveHtml as html,
|
|
43
|
+
effectiveSvg as svg,
|
|
26
44
|
};
|
|
27
45
|
export { scopeTag };
|
|
28
46
|
export { repeat } from "lit-html/directives/repeat.js";
|