@ui5/webcomponents-base 0.0.0-b4cbc43ba → 0.0.0-b93c2a321

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 (212) hide show
  1. package/.eslintignore +3 -0
  2. package/CHANGELOG.md +214 -0
  3. package/README.md +26 -2
  4. package/bundle.esm.js +10 -7
  5. package/dist/AssetRegistry.js +8 -9
  6. package/dist/Boot.js +17 -6
  7. package/dist/CSP.js +59 -0
  8. package/dist/CustomElementsRegistry.js +60 -4
  9. package/dist/CustomElementsScope.js +20 -98
  10. package/dist/CustomElementsScopeUtils.js +108 -0
  11. package/dist/DOMObserver.js +6 -2
  12. package/dist/Device.js +69 -776
  13. package/dist/EventProvider.js +19 -25
  14. package/dist/FeaturesRegistry.js +4 -1
  15. package/dist/FontFace.js +7 -95
  16. package/dist/InitialConfiguration.js +37 -21
  17. package/dist/Keys.js +74 -0
  18. package/dist/ManagedStyles.js +83 -0
  19. package/dist/MediaRange.js +109 -0
  20. package/dist/{util/parseProperties.js → PropertiesFileFormat.js} +6 -0
  21. package/dist/Render.js +3 -2
  22. package/dist/Runtimes.js +107 -0
  23. package/dist/StaticArea.js +3 -0
  24. package/dist/StaticAreaItem.js +31 -10
  25. package/dist/SystemCSSVars.js +4 -25
  26. package/dist/UI5Element.js +66 -65
  27. package/dist/UI5ElementMetadata.js +18 -2
  28. package/dist/asset-registries/Icons.js +117 -14
  29. package/dist/asset-registries/Illustrations.js +30 -0
  30. package/dist/asset-registries/LocaleData.js +97 -68
  31. package/dist/asset-registries/Themes.js +23 -33
  32. package/dist/asset-registries/i18n.js +61 -50
  33. package/dist/assets-meta/IconCollectionsAlias.js +18 -0
  34. package/dist/config/Icons.js +52 -0
  35. package/dist/config/Language.js +15 -15
  36. package/dist/config/Theme.js +25 -0
  37. package/dist/css/BusyIndicator.css +76 -0
  38. package/dist/css/FontFace.css +75 -0
  39. package/dist/css/OverrideFontFace.css +32 -0
  40. package/dist/css/SystemCSSVars.css +17 -0
  41. package/dist/delegate/ItemNavigation.js +163 -105
  42. package/dist/delegate/ScrollEnablement.js +25 -19
  43. package/dist/features/F6Navigation.js +108 -0
  44. package/dist/features/OpenUI5Enablement.js +119 -0
  45. package/dist/features/OpenUI5Support.js +41 -6
  46. package/dist/generated/AssetParameters.js +1 -1
  47. package/dist/generated/VersionInfo.js +10 -0
  48. package/dist/generated/css/BusyIndicator.css.js +5 -0
  49. package/dist/generated/css/FontFace.css.js +5 -0
  50. package/dist/generated/css/OverrideFontFace.css.js +5 -0
  51. package/dist/generated/css/SystemCSSVars.css.js +5 -0
  52. package/dist/i18nBundle.js +38 -4
  53. package/dist/renderer/LitRenderer.js +39 -18
  54. package/dist/renderer/directives/style-map.js +72 -0
  55. package/dist/renderer/executeTemplate.js +19 -2
  56. package/dist/resources/bundle.esm.js +15 -104
  57. package/dist/resources/bundle.esm.js.map +1 -1
  58. package/dist/sap/base/Log.js +241 -0
  59. package/dist/sap/base/assert.js +8 -0
  60. package/dist/sap/base/security/URLListValidator.js +148 -0
  61. package/dist/sap/base/security/encodeCSS.js +14 -0
  62. package/dist/sap/base/security/encodeXML.js +23 -0
  63. package/dist/sap/base/security/sanitizeHTML.js +16 -0
  64. package/dist/sap/base/strings/toHex.js +8 -0
  65. package/dist/sap/base/util/now.js +7 -0
  66. package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +3585 -0
  67. package/dist/test-resources/assets/Themes.js +8 -8
  68. package/dist/test-resources/elements/WithStaticArea.js +2 -1
  69. package/dist/test-resources/pages/AllTestElements.html +3 -0
  70. package/dist/test-resources/pages/i18n.html +2 -9
  71. package/dist/test-resources/specs/ConfigurationChange.spec.js +10 -8
  72. package/dist/test-resources/specs/ConfigurationScript.spec.js +25 -23
  73. package/dist/test-resources/specs/ConfigurationURL.spec.js +65 -17
  74. package/dist/test-resources/specs/CustomTheme.spec.js +9 -7
  75. package/dist/test-resources/specs/EventProvider.spec.js +63 -0
  76. package/dist/test-resources/specs/StaticArea.spec.js +56 -12
  77. package/dist/test-resources/specs/Theming.spec.js +12 -10
  78. package/dist/test-resources/specs/UI5ElementInvalidation.js +30 -28
  79. package/dist/test-resources/specs/UI5ElementLifecycle.js +12 -10
  80. package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +12 -10
  81. package/dist/test-resources/specs/UI5ElementMetadataExt.js +9 -7
  82. package/dist/test-resources/specs/UI5ElementPropertyValidation.js +7 -5
  83. package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +37 -35
  84. package/dist/test-resources/specs/UI5ElementShadowDOM.js +10 -8
  85. package/dist/test-resources/specs/UI5ElementSlots.js +10 -8
  86. package/dist/theming/CustomStyle.js +23 -3
  87. package/dist/theming/applyTheme.js +11 -10
  88. package/dist/theming/getEffectiveLinksHrefs.js +27 -0
  89. package/dist/theming/getEffectiveStyle.js +9 -0
  90. package/dist/theming/getStylesString.js +4 -2
  91. package/dist/theming/getThemeDesignerTheme.js +25 -5
  92. package/dist/theming/preloadLinks.js +23 -0
  93. package/dist/types/CSSColor.js +9 -0
  94. package/dist/types/DataType.js +12 -0
  95. package/dist/types/Float.js +4 -0
  96. package/dist/types/Integer.js +4 -0
  97. package/dist/types/InvisibleMessageMode.js +30 -0
  98. package/dist/updateShadowRoot.js +8 -4
  99. package/dist/util/AriaLabelHelper.js +4 -4
  100. package/dist/util/ColorConversion.js +370 -0
  101. package/dist/util/FocusableElements.js +13 -7
  102. package/dist/util/HTMLSanitizer.js +7 -0
  103. package/dist/util/InvisibleMessage.js +60 -0
  104. package/dist/util/PopupUtils.js +93 -0
  105. package/dist/util/TabbableElements.js +5 -1
  106. package/dist/util/clamp.js +12 -0
  107. package/dist/util/createLinkInHead.js +19 -0
  108. package/dist/util/escapeRegex.js +10 -0
  109. package/dist/util/generateHighlightedMarkup.js +42 -0
  110. package/dist/util/getClassCopy.js +10 -0
  111. package/dist/util/getNormalizedTarget.js +16 -0
  112. package/dist/util/isElementInView.js +15 -0
  113. package/dist/util/isNodeHidden.js +1 -1
  114. package/dist/util/isNodeTabbable.js +4 -4
  115. package/hash.txt +1 -0
  116. package/index.js +1 -1
  117. package/lib/generate-asset-parameters/index.js +0 -1
  118. package/lib/generate-styles/index.js +18 -0
  119. package/lib/generate-version-info/index.js +27 -0
  120. package/package-scripts.js +31 -15
  121. package/package.json +19 -10
  122. package/src/AssetRegistry.js +8 -9
  123. package/src/Boot.js +17 -6
  124. package/src/CSP.js +59 -0
  125. package/src/CustomElementsRegistry.js +60 -4
  126. package/src/CustomElementsScope.js +20 -98
  127. package/src/CustomElementsScopeUtils.js +108 -0
  128. package/src/DOMObserver.js +6 -2
  129. package/src/Device.js +69 -776
  130. package/src/EventProvider.js +19 -25
  131. package/src/FeaturesRegistry.js +4 -1
  132. package/src/FontFace.js +7 -95
  133. package/src/InitialConfiguration.js +37 -21
  134. package/src/Keys.js +74 -0
  135. package/src/ManagedStyles.js +83 -0
  136. package/src/MediaRange.js +109 -0
  137. package/src/{util/parseProperties.js → PropertiesFileFormat.js} +6 -0
  138. package/src/Render.js +3 -2
  139. package/src/Runtimes.js +107 -0
  140. package/src/StaticArea.js +3 -0
  141. package/src/StaticAreaItem.js +31 -10
  142. package/src/SystemCSSVars.js +4 -25
  143. package/src/UI5Element.js +66 -65
  144. package/src/UI5ElementMetadata.js +18 -2
  145. package/src/asset-registries/Icons.js +117 -14
  146. package/src/asset-registries/Illustrations.js +30 -0
  147. package/src/asset-registries/LocaleData.js +97 -68
  148. package/src/asset-registries/Themes.js +23 -33
  149. package/src/asset-registries/i18n.js +61 -50
  150. package/src/assets-meta/IconCollectionsAlias.js +18 -0
  151. package/src/config/Icons.js +52 -0
  152. package/src/config/Language.js +15 -15
  153. package/src/config/Theme.js +25 -0
  154. package/src/css/BusyIndicator.css +76 -0
  155. package/src/css/FontFace.css +75 -0
  156. package/src/css/OverrideFontFace.css +32 -0
  157. package/src/css/SystemCSSVars.css +17 -0
  158. package/src/delegate/ItemNavigation.js +163 -105
  159. package/src/delegate/ScrollEnablement.js +25 -19
  160. package/src/features/F6Navigation.js +108 -0
  161. package/src/features/OpenUI5Enablement.js +119 -0
  162. package/src/features/OpenUI5Support.js +41 -6
  163. package/src/i18nBundle.js +38 -4
  164. package/src/renderer/LitRenderer.js +39 -18
  165. package/src/renderer/directives/style-map.js +72 -0
  166. package/src/renderer/executeTemplate.js +19 -2
  167. package/src/theming/CustomStyle.js +23 -3
  168. package/src/theming/applyTheme.js +11 -10
  169. package/src/theming/getEffectiveLinksHrefs.js +27 -0
  170. package/src/theming/getEffectiveStyle.js +9 -0
  171. package/src/theming/getStylesString.js +4 -2
  172. package/src/theming/getThemeDesignerTheme.js +25 -5
  173. package/src/theming/preloadLinks.js +23 -0
  174. package/src/types/CSSColor.js +9 -0
  175. package/src/types/DataType.js +12 -0
  176. package/src/types/Float.js +4 -0
  177. package/src/types/Integer.js +4 -0
  178. package/src/types/InvisibleMessageMode.js +30 -0
  179. package/src/updateShadowRoot.js +8 -4
  180. package/src/util/AriaLabelHelper.js +4 -4
  181. package/src/util/ColorConversion.js +370 -0
  182. package/src/util/FocusableElements.js +13 -7
  183. package/src/util/HTMLSanitizer.js +7 -0
  184. package/src/util/InvisibleMessage.js +60 -0
  185. package/src/util/PopupUtils.js +93 -0
  186. package/src/util/TabbableElements.js +5 -1
  187. package/src/util/clamp.js +12 -0
  188. package/src/util/createLinkInHead.js +19 -0
  189. package/src/util/escapeRegex.js +10 -0
  190. package/src/util/generateHighlightedMarkup.js +42 -0
  191. package/src/util/getClassCopy.js +10 -0
  192. package/src/util/getNormalizedTarget.js +16 -0
  193. package/src/util/isElementInView.js +15 -0
  194. package/src/util/isNodeHidden.js +1 -1
  195. package/src/util/isNodeTabbable.js +4 -4
  196. package/used-modules.txt +10 -0
  197. package/dist/SVGIconRegistry.js +0 -73
  198. package/dist/config/AssetsPath.js +0 -17
  199. package/dist/features/PropertiesFormatSupport.js +0 -8
  200. package/dist/renderer/ifDefined.js +0 -21
  201. package/dist/renderer/scopeHTML.js +0 -32
  202. package/dist/theming/createThemePropertiesStyleTag.js +0 -20
  203. package/dist/util/EffectiveAssetPath.js +0 -27
  204. package/dist/util/encodeCSS.js +0 -24
  205. package/src/SVGIconRegistry.js +0 -73
  206. package/src/config/AssetsPath.js +0 -17
  207. package/src/features/PropertiesFormatSupport.js +0 -8
  208. package/src/renderer/ifDefined.js +0 -21
  209. package/src/renderer/scopeHTML.js +0 -32
  210. package/src/theming/createThemePropertiesStyleTag.js +0 -20
  211. package/src/util/EffectiveAssetPath.js +0 -27
  212. package/src/util/encodeCSS.js +0 -24
@@ -15,6 +15,12 @@ const mEscapes = {
15
15
  "\\t": "\t",
16
16
  };
17
17
 
18
+ /**
19
+ * Parses a .properties format
20
+ * @param {string} sText the contents a of a .properties file
21
+ * @returns a object with key/value pairs parsed from the .properties file format
22
+ * @public
23
+ */
18
24
  const parseProperties = sText => {
19
25
  const properties = {},
20
26
  aLines = sText.split(rLines);
package/dist/Render.js CHANGED
@@ -15,7 +15,6 @@ let mutationObserverTimer;
15
15
 
16
16
  let queuePromise;
17
17
 
18
-
19
18
  /**
20
19
  * Schedules a render task (if not already scheduled) to render the component
21
20
  *
@@ -136,6 +135,7 @@ const _resolveTaskPromise = () => {
136
135
  * reRenderAllUI5Elements({tag: "ui5-button"}) -> re-renders only instances of ui5-button
137
136
  * reRenderAllUI5Elements({rtlAware: true}) -> re-renders only rtlAware components
138
137
  * reRenderAllUI5Elements({languageAware: true}) -> re-renders only languageAware components
138
+ * reRenderAllUI5Elements({themeAware: true}) -> re-renders only themeAware components
139
139
  * reRenderAllUI5Elements({rtlAware: true, languageAware: true}) -> re-renders components that are rtlAware or languageAware
140
140
  * etc...
141
141
  *
@@ -148,7 +148,8 @@ const reRenderAllUI5Elements = async filters => {
148
148
  const tag = element.constructor.getMetadata().getTag();
149
149
  const rtlAware = isRtlAware(element.constructor);
150
150
  const languageAware = element.constructor.getMetadata().isLanguageAware();
151
- if (!filters || (filters.tag === tag) || (filters.rtlAware && rtlAware) || (filters.languageAware && languageAware)) {
151
+ const themeAware = element.constructor.getMetadata().isThemeAware();
152
+ if (!filters || (filters.tag === tag) || (filters.rtlAware && rtlAware) || (filters.languageAware && languageAware) || (filters.themeAware && themeAware)) {
152
153
  renderDeferred(element);
153
154
  }
154
155
  });
@@ -0,0 +1,107 @@
1
+ import VersionInfo from "./generated/VersionInfo.js";
2
+ import getSharedResource from "./getSharedResource.js";
3
+
4
+ let currentRuntimeIndex;
5
+ let currentRuntimeAlias = "";
6
+
7
+ const compareCache = new Map();
8
+
9
+ /**
10
+ * Central registry where all runtimes register themselves by pushing an object.
11
+ * The index in the registry servers as an ID for the runtime.
12
+ * @type {*}
13
+ */
14
+ const Runtimes = getSharedResource("Runtimes", []);
15
+
16
+ /**
17
+ * Registers the current runtime in the shared runtimes resource registry
18
+ */
19
+ const registerCurrentRuntime = () => {
20
+ if (currentRuntimeIndex === undefined) {
21
+ currentRuntimeIndex = Runtimes.length;
22
+ Runtimes.push({
23
+ ...VersionInfo,
24
+ alias: currentRuntimeAlias,
25
+ description: `Runtime ${currentRuntimeIndex} - ver ${VersionInfo.version}${currentRuntimeAlias ? ` (${currentRuntimeAlias})` : ""}`,
26
+ });
27
+ }
28
+ };
29
+
30
+ /**
31
+ * Returns the index of the current runtime's object in the shared runtimes resource registry
32
+ * @returns {*}
33
+ */
34
+ const getCurrentRuntimeIndex = () => {
35
+ return currentRuntimeIndex;
36
+ };
37
+
38
+ /**
39
+ * Compares two runtimes and returns 1 if the first is of a bigger version, -1 if the second is of a bigger version, and 0 if equal
40
+ * @param index1 The index of the first runtime to compare
41
+ * @param index2 The index of the second runtime to compare
42
+ * @returns {number}
43
+ */
44
+ const compareRuntimes = (index1, index2) => {
45
+ const cacheIndex = `${index1},${index2}`;
46
+ if (compareCache.has(cacheIndex)) {
47
+ return compareCache.get(cacheIndex);
48
+ }
49
+
50
+ const runtime1 = Runtimes[index1];
51
+ const runtime2 = Runtimes[index2];
52
+
53
+ if (!runtime1 || !runtime2) {
54
+ throw new Error("Invalid runtime index supplied");
55
+ }
56
+
57
+ // If any of the two is a next version, bigger buildTime wins
58
+ if (runtime1.isNext || runtime2.isNext) {
59
+ return runtime1.buildTime - runtime2.buildTime;
60
+ }
61
+
62
+ // If major versions differ, bigger one wins
63
+ const majorDiff = runtime1.major - runtime2.major;
64
+ if (majorDiff) {
65
+ return majorDiff;
66
+ }
67
+
68
+ // If minor versions differ, bigger one wins
69
+ const minorDiff = runtime1.minor - runtime2.minor;
70
+ if (minorDiff) {
71
+ return minorDiff;
72
+ }
73
+
74
+ // If patch versions differ, bigger one wins
75
+ const patchDiff = runtime1.patch - runtime2.patch;
76
+ if (patchDiff) {
77
+ return patchDiff;
78
+ }
79
+
80
+ // Bigger suffix wins, f.e. rc10 > rc9
81
+ // Important: suffix is alphanumeric, must use natural compare
82
+ const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: "base" });
83
+ const result = collator.compare(runtime1.suffix, runtime2.suffix);
84
+
85
+ compareCache.set(cacheIndex, result);
86
+ return result;
87
+ };
88
+
89
+ /**
90
+ * Set an alias for the the current app/library/microfrontend which will appear in debug messages and console warnings
91
+ * @param alias
92
+ */
93
+ const setRuntimeAlias = alias => {
94
+ currentRuntimeAlias = alias;
95
+ };
96
+
97
+ const getAllRuntimes = () => {
98
+ return Runtimes;
99
+ };
100
+
101
+ export {
102
+ getCurrentRuntimeIndex,
103
+ registerCurrentRuntime,
104
+ compareRuntimes,
105
+ setRuntimeAlias,
106
+ getAllRuntimes,
107
+ };
@@ -0,0 +1,3 @@
1
+ if (!customElements.get("ui5-static-area")) {
2
+ customElements.define("ui5-static-area", class extends HTMLElement {});
3
+ }
@@ -1,6 +1,9 @@
1
+ import "./StaticArea.js";
1
2
  import updateShadowRoot from "./updateShadowRoot.js";
2
3
  import { renderFinished } from "./Render.js";
3
4
  import getEffectiveContentDensity from "./util/getEffectiveContentDensity.js";
5
+ import { getEffectiveScopingSuffixForTag } from "./CustomElementsScopeUtils.js";
6
+ import getEffectiveDir from "./locale/getEffectiveDir.js";
4
7
 
5
8
  /**
6
9
  *
@@ -22,6 +25,9 @@ class StaticAreaItem extends HTMLElement {
22
25
  setOwnerElement(ownerElement) {
23
26
  this.ownerElement = ownerElement;
24
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
+ }
25
31
  }
26
32
 
27
33
  /**
@@ -31,6 +37,7 @@ class StaticAreaItem extends HTMLElement {
31
37
  update() {
32
38
  if (this._rendered) {
33
39
  this._updateContentDensity();
40
+ this._updateDirection();
34
41
  updateShadowRoot(this.ownerElement, true);
35
42
  }
36
43
  }
@@ -49,6 +56,15 @@ class StaticAreaItem extends HTMLElement {
49
56
  }
50
57
  }
51
58
 
59
+ _updateDirection() {
60
+ const dir = getEffectiveDir(this.ownerElement);
61
+ if (dir) {
62
+ this.setAttribute("dir", dir);
63
+ } else {
64
+ this.removeAttribute("dir");
65
+ }
66
+ }
67
+
52
68
  /**
53
69
  * @protected
54
70
  * Returns reference to the DOM element where the current fragment is added.
@@ -63,18 +79,23 @@ class StaticAreaItem extends HTMLElement {
63
79
  return this.shadowRoot;
64
80
  }
65
81
 
66
- /**
67
- * @protected
68
- * @param refName
69
- * @returns {Element}
70
- */
71
- getStableDomRef(refName) {
72
- return this.shadowRoot.querySelector(`[data-ui5-stable=${refName}]`);
82
+ static getTag() {
83
+ const pureTag = "ui5-static-area-item";
84
+ const suffix = getEffectiveScopingSuffixForTag(pureTag);
85
+ if (!suffix) {
86
+ return pureTag;
87
+ }
88
+
89
+ return `${pureTag}-${suffix}`;
73
90
  }
74
- }
75
91
 
76
- if (!customElements.get("ui5-static-area-item")) {
77
- customElements.define("ui5-static-area-item", StaticAreaItem);
92
+ static createInstance() {
93
+ if (!customElements.get(StaticAreaItem.getTag())) {
94
+ customElements.define(StaticAreaItem.getTag(), StaticAreaItem);
95
+ }
96
+
97
+ return document.createElement(this.getTag());
98
+ }
78
99
  }
79
100
 
80
101
  export default StaticAreaItem;
@@ -1,31 +1,10 @@
1
- import createStyleInHead from "./util/createStyleInHead.js";
2
-
3
- const systemCSSVars = `
4
- :root {
5
- --_ui5_content_density:cozy;
6
- }
7
-
8
- [data-ui5-compact-size],
9
- .ui5-content-density-compact,
10
- .sapUiSizeCompact {
11
- --_ui5_content_density:compact;
12
- }
13
-
14
- [dir="rtl"] {
15
- --_ui5_dir:rtl;
16
- }
17
-
18
- [dir="ltr"] {
19
- --_ui5_dir:ltr;
20
- }
21
- `;
1
+ import { hasStyle, createStyle } from "./ManagedStyles.js";
2
+ import systemCSSVars from "./generated/css/SystemCSSVars.css.js";
22
3
 
23
4
  const insertSystemCSSVars = () => {
24
- if (document.querySelector(`head>style[data-ui5-system-css-vars]`)) {
25
- return;
5
+ if (!hasStyle("data-ui5-system-css-vars")) {
6
+ createStyle(systemCSSVars, "data-ui5-system-css-vars");
26
7
  }
27
-
28
- createStyleInHead(systemCSSVars, { "data-ui5-system-css-vars": "" });
29
8
  };
30
9
 
31
10
  export default insertSystemCSSVars;
@@ -3,21 +3,22 @@ import { boot } from "./Boot.js";
3
3
  import UI5ElementMetadata from "./UI5ElementMetadata.js";
4
4
  import EventProvider from "./EventProvider.js";
5
5
  import getSingletonElementInstance from "./util/getSingletonElementInstance.js";
6
- import "./StaticAreaItem.js";
6
+ import StaticAreaItem from "./StaticAreaItem.js";
7
7
  import updateShadowRoot from "./updateShadowRoot.js";
8
8
  import { renderDeferred, renderImmediately, cancelRender } from "./Render.js";
9
9
  import { registerTag, isTagRegistered, recordTagRegistrationFailure } from "./CustomElementsRegistry.js";
10
10
  import { observeDOMNode, unobserveDOMNode } from "./DOMObserver.js";
11
11
  import { skipOriginalEvent } from "./config/NoConflict.js";
12
12
  import getEffectiveDir from "./locale/getEffectiveDir.js";
13
- import Integer from "./types/Integer.js";
14
- import Float from "./types/Float.js";
13
+ import DataType from "./types/DataType.js";
15
14
  import { kebabToCamelCase, camelToKebabCase } from "./util/StringHelper.js";
16
15
  import isValidPropertyName from "./util/isValidPropertyName.js";
16
+ import isDescendantOf from "./util/isDescendantOf.js";
17
17
  import { isSlot, getSlotName, getSlottedElementsList } from "./util/SlotsHelper.js";
18
18
  import arraysAreEqual from "./util/arraysAreEqual.js";
19
+ import getClassCopy from "./util/getClassCopy.js";
19
20
  import { markAsRtlAware } from "./locale/RTLAwareRegistry.js";
20
- import isLegacyBrowser from "./isLegacyBrowser.js";
21
+ import preloadLinks from "./theming/preloadLinks.js";
21
22
 
22
23
  let autoId = 0;
23
24
 
@@ -42,9 +43,11 @@ function _invalidate(changeInfo) {
42
43
 
43
44
  this._changedState.push(changeInfo);
44
45
  renderDeferred(this);
45
- this._eventProvider.fireEvent("change", { ...changeInfo, target: this });
46
+ this._eventProvider.fireEvent("invalidate", { ...changeInfo, target: this });
46
47
  }
47
48
 
49
+ let metadata = {};
50
+
48
51
  /**
49
52
  * Base class for all UI5 Web Components
50
53
  *
@@ -100,8 +103,10 @@ class UI5Element extends HTMLElement {
100
103
  */
101
104
  async connectedCallback() {
102
105
  this.setAttribute(this.constructor.getMetadata().getPureTag(), "");
106
+ if (this.constructor.getMetadata().supportsF6FastNavigation()) {
107
+ this.setAttribute("data-sap-ui-fastnavgroup", "true");
108
+ }
103
109
 
104
- const needsShadowDOM = this.constructor._needsShadowDOM();
105
110
  const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
106
111
 
107
112
  this._inDOM = true;
@@ -112,10 +117,6 @@ class UI5Element extends HTMLElement {
112
117
  await this._processChildren();
113
118
  }
114
119
 
115
- if (needsShadowDOM && !this.shadowRoot) { // Workaround for Firefox74 bug
116
- await Promise.resolve();
117
- }
118
-
119
120
  if (!this._inDOM) { // Component removed from DOM while _processChildren was running
120
121
  return;
121
122
  }
@@ -133,7 +134,6 @@ class UI5Element extends HTMLElement {
133
134
  * @private
134
135
  */
135
136
  disconnectedCallback() {
136
- const needsShadowDOM = this.constructor._needsShadowDOM();
137
137
  const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
138
138
 
139
139
  this._inDOM = false;
@@ -142,13 +142,11 @@ class UI5Element extends HTMLElement {
142
142
  this._stopObservingDOMChildren();
143
143
  }
144
144
 
145
- if (needsShadowDOM) {
146
- if (this._fullyConnected) {
147
- if (typeof this.onExitDOM === "function") {
148
- this.onExitDOM();
149
- }
150
- this._fullyConnected = false;
145
+ if (this._fullyConnected) {
146
+ if (typeof this.onExitDOM === "function") {
147
+ this.onExitDOM();
151
148
  }
149
+ this._fullyConnected = false;
152
150
  }
153
151
 
154
152
  if (this.staticAreaItem && this.staticAreaItem.parentElement) {
@@ -258,7 +256,8 @@ class UI5Element extends HTMLElement {
258
256
 
259
257
  // Listen for any invalidation on the child if invalidateOnChildChange is true or an object (ignore when false or not set)
260
258
  if (child.isUI5Element && slotData.invalidateOnChildChange) {
261
- child._attachChange(this._getChildChangeListener(slotName));
259
+ const method = (child.attachInvalidate || child._attachChange).bind(child);
260
+ method(this._getChildChangeListener(slotName));
262
261
  }
263
262
 
264
263
  // Listen for the slotchange event if the child is a slot itself
@@ -318,7 +317,8 @@ class UI5Element extends HTMLElement {
318
317
 
319
318
  children.forEach(child => {
320
319
  if (child && child.isUI5Element) {
321
- child._detachChange(this._getChildChangeListener(slotName));
320
+ const method = (child.detachInvalidate || child._detachChange).bind(child);
321
+ method(this._getChildChangeListener(slotName));
322
322
  }
323
323
 
324
324
  if (isSlot(child)) {
@@ -333,20 +333,20 @@ class UI5Element extends HTMLElement {
333
333
  * Attach a callback that will be executed whenever the component is invalidated
334
334
  *
335
335
  * @param callback
336
- * @protected
336
+ * @public
337
337
  */
338
- _attachChange(callback) {
339
- this._eventProvider.attachEvent("change", callback);
338
+ attachInvalidate(callback) {
339
+ this._eventProvider.attachEvent("invalidate", callback);
340
340
  }
341
341
 
342
342
  /**
343
343
  * Detach the callback that is executed whenever the component is invalidated
344
344
  *
345
345
  * @param callback
346
- * @protected
346
+ * @public
347
347
  */
348
- _detachChange(callback) {
349
- this._eventProvider.detachEvent("change", callback);
348
+ detachInvalidate(callback) {
349
+ this._eventProvider.detachEvent("invalidate", callback);
350
350
  }
351
351
 
352
352
  /**
@@ -383,12 +383,8 @@ class UI5Element extends HTMLElement {
383
383
  const propertyTypeClass = properties[nameInCamelCase].type;
384
384
  if (propertyTypeClass === Boolean) {
385
385
  newValue = newValue !== null;
386
- }
387
- if (propertyTypeClass === Integer) {
388
- newValue = parseInt(newValue);
389
- }
390
- if (propertyTypeClass === Float) {
391
- newValue = parseFloat(newValue);
386
+ } else if (isDescendantOf(propertyTypeClass, DataType)) {
387
+ newValue = propertyTypeClass.attributeToProperty(newValue);
392
388
  }
393
389
  this[nameInCamelCase] = newValue;
394
390
  }
@@ -401,22 +397,24 @@ class UI5Element extends HTMLElement {
401
397
  if (!this.constructor.getMetadata().hasAttribute(name)) {
402
398
  return;
403
399
  }
404
-
405
- if (typeof newValue === "object") {
406
- return;
407
- }
408
-
400
+ const properties = this.constructor.getMetadata().getProperties();
401
+ const propertyTypeClass = properties[name].type;
409
402
  const attrName = camelToKebabCase(name);
410
403
  const attrValue = this.getAttribute(attrName);
411
- if (typeof newValue === "boolean") {
404
+
405
+ if (propertyTypeClass === Boolean) {
412
406
  if (newValue === true && attrValue === null) {
413
407
  this.setAttribute(attrName, "");
414
408
  } else if (newValue === false && attrValue !== null) {
415
409
  this.removeAttribute(attrName);
416
410
  }
417
- } else if (attrValue !== newValue) {
418
- this.setAttribute(attrName, newValue);
419
- }
411
+ } else if (isDescendantOf(propertyTypeClass, DataType)) {
412
+ this.setAttribute(attrName, propertyTypeClass.propertyToAttribute(newValue));
413
+ } else if (typeof newValue !== "object") {
414
+ if (attrValue !== newValue) {
415
+ this.setAttribute(attrName, newValue);
416
+ }
417
+ } // else { return; } // old object handling
420
418
  }
421
419
 
422
420
  /**
@@ -442,7 +440,7 @@ class UI5Element extends HTMLElement {
442
440
  * @private
443
441
  */
444
442
  _initializeState() {
445
- this._state = Object.assign({}, this.constructor.getMetadata().getInitialState());
443
+ this._state = { ...this.constructor.getMetadata().getInitialState() };
446
444
  }
447
445
 
448
446
  /**
@@ -616,25 +614,27 @@ class UI5Element extends HTMLElement {
616
614
 
617
615
  /**
618
616
  * Returns the DOM Element inside the Shadow Root that corresponds to the opening tag in the UI5 Web Component's template
617
+ * *Note:* For logical (abstract) elements (items, options, etc...), returns the part of the parent's DOM that represents this option
619
618
  * Use this method instead of "this.shadowRoot" to read the Shadow DOM, if ever necessary
619
+ *
620
620
  * @public
621
621
  */
622
622
  getDomRef() {
623
+ // If a component set _getRealDomRef to its children, use the return value of this function
624
+ if (typeof this._getRealDomRef === "function") {
625
+ return this._getRealDomRef();
626
+ }
627
+
623
628
  if (!this.shadowRoot || this.shadowRoot.children.length === 0) {
624
629
  return;
625
630
  }
626
631
 
627
- this._assertShadowRootStructure();
628
-
629
- return this.shadowRoot.children.length === 1
630
- ? this.shadowRoot.children[0] : this.shadowRoot.children[1];
631
- }
632
-
633
- _assertShadowRootStructure() {
634
- const expectedChildrenCount = document.adoptedStyleSheets || isLegacyBrowser() ? 1 : 2;
635
- if (this.shadowRoot.children.length !== expectedChildrenCount) {
632
+ const children = [...this.shadowRoot.children].filter(child => !["link", "style"].includes(child.localName));
633
+ if (children.length !== 1) {
636
634
  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
637
635
  }
636
+
637
+ return children[0];
638
638
  }
639
639
 
640
640
  /**
@@ -660,17 +660,6 @@ class UI5Element extends HTMLElement {
660
660
  return this.getFocusDomRef();
661
661
  }
662
662
 
663
- /**
664
- * Use this method in order to get a reference to an element in the shadow root of the web component or the static area item of the component
665
- * @public
666
- * @method
667
- * @param {String} refName Defines the name of the stable DOM ref
668
- */
669
- getStableDomRef(refName) {
670
- const staticAreaResult = this.staticAreaItem && this.staticAreaItem.getStableDomRef(refName);
671
- return staticAreaResult || this.getDomRef().querySelector(`[data-ui5-stable=${refName}]`);
672
- }
673
-
674
663
  /**
675
664
  * Set the focus to the element, returned by "getFocusDomRef()" (marked by "data-sap-focus-ref")
676
665
  * @public
@@ -795,7 +784,7 @@ class UI5Element extends HTMLElement {
795
784
  }
796
785
 
797
786
  if (!this.staticAreaItem) {
798
- this.staticAreaItem = document.createElement("ui5-static-area-item");
787
+ this.staticAreaItem = StaticAreaItem.createInstance();
799
788
  this.staticAreaItem.setOwnerElement(this);
800
789
  }
801
790
  if (!this.staticAreaItem.parentElement) {
@@ -860,6 +849,8 @@ class UI5Element extends HTMLElement {
860
849
  const oldState = this._state[prop];
861
850
  if (propData.multiple && propData.compareValues) {
862
851
  isDifferent = !arraysAreEqual(oldState, value);
852
+ } else if (isDescendantOf(propData.type, DataType)) {
853
+ isDifferent = !propData.type.valuesAreEqual(oldState, value);
863
854
  } else {
864
855
  isDifferent = oldState !== value;
865
856
  }
@@ -907,7 +898,15 @@ class UI5Element extends HTMLElement {
907
898
  * @protected
908
899
  */
909
900
  static get metadata() {
910
- 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;
911
910
  }
912
911
 
913
912
  /**
@@ -995,11 +994,13 @@ class UI5Element extends HTMLElement {
995
994
  this._generateAccessors();
996
995
  registerTag(tag);
997
996
  window.customElements.define(tag, this);
997
+ preloadLinks(this);
998
998
 
999
999
  if (altTag && !customElements.get(altTag)) {
1000
- class oldClassName extends this {}
1001
1000
  registerTag(altTag);
1002
- window.customElements.define(altTag, oldClassName);
1001
+ window.customElements.define(altTag, getClassCopy(this, () => {
1002
+ console.log(`The ${altTag} tag is deprecated and will be removed in the next release, please use ${tag} instead.`); // eslint-disable-line
1003
+ }));
1003
1004
  }
1004
1005
  }
1005
1006
  return this;
@@ -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 "./CustomElementsScope.js";
5
+ import { getEffectiveScopingSuffixForTag } from "./CustomElementsScopeUtils.js";
6
6
 
7
7
  /**
8
8
  *
@@ -126,7 +126,7 @@ class UI5ElementMetadata {
126
126
  */
127
127
  hasAttribute(propName) {
128
128
  const propData = this.getProperties()[propName];
129
- return propData.type !== Object && !propData.noAttribute;
129
+ return propData.type !== Object && !propData.noAttribute && !propData.multiple;
130
130
  }
131
131
 
132
132
  /**
@@ -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
@@ -212,6 +220,14 @@ class UI5ElementMetadata {
212
220
  return !!this.metadata.languageAware;
213
221
  }
214
222
 
223
+ /**
224
+ * Determines whether this UI5 Element has any theme dependant carachteristics.
225
+ * @returns {boolean}
226
+ */
227
+ isThemeAware() {
228
+ return !!this.metadata.themeAware;
229
+ }
230
+
215
231
  /**
216
232
  * Matches a changed entity (property/slot) with the given name against the "invalidateOnChildChange" configuration
217
233
  * and determines whether this should cause and invalidation