@ui5/webcomponents-base 0.0.0-6ef02a35f → 0.0.0-701b14e36

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 (159) hide show
  1. package/.eslintignore +3 -2
  2. package/CHANGELOG.md +199 -0
  3. package/README.md +26 -2
  4. package/bundle.esm.js +6 -2
  5. package/dist/Boot.js +34 -18
  6. package/dist/CSP.js +59 -0
  7. package/dist/CustomElementsRegistry.js +60 -4
  8. package/dist/CustomElementsScope.js +20 -98
  9. package/dist/CustomElementsScopeUtils.js +108 -0
  10. package/dist/Device.js +20 -1
  11. package/dist/EventProvider.js +19 -25
  12. package/dist/FeaturesRegistry.js +4 -1
  13. package/dist/FontFace.js +7 -95
  14. package/dist/InitialConfiguration.js +11 -7
  15. package/dist/Keys.js +56 -0
  16. package/dist/ManagedStyles.js +83 -0
  17. package/dist/Render.js +3 -1
  18. package/dist/Runtimes.js +107 -0
  19. package/dist/StaticAreaItem.js +15 -10
  20. package/dist/SystemCSSVars.js +4 -25
  21. package/dist/UI5Element.js +59 -60
  22. package/dist/UI5ElementMetadata.js +18 -2
  23. package/dist/asset-registries/Icons.js +22 -8
  24. package/dist/asset-registries/Illustrations.js +10 -3
  25. package/dist/asset-registries/LocaleData.js +17 -3
  26. package/dist/asset-registries/Themes.js +6 -2
  27. package/dist/assets-meta/IconCollectionsAlias.js +18 -0
  28. package/dist/config/Icons.js +52 -0
  29. package/dist/config/Theme.js +25 -0
  30. package/dist/css/BusyIndicator.css +76 -0
  31. package/dist/css/FontFace.css +75 -0
  32. package/dist/css/OverrideFontFace.css +32 -0
  33. package/dist/css/SystemCSSVars.css +17 -0
  34. package/dist/delegate/ItemNavigation.js +66 -0
  35. package/dist/features/F6Navigation.js +106 -0
  36. package/dist/features/OpenUI5Enablement.js +119 -0
  37. package/dist/generated/AssetParameters.js +1 -1
  38. package/dist/generated/VersionInfo.js +10 -0
  39. package/dist/generated/css/BusyIndicator.css.js +5 -0
  40. package/dist/generated/css/FontFace.css.js +5 -0
  41. package/dist/generated/css/OverrideFontFace.css.js +5 -0
  42. package/dist/generated/css/SystemCSSVars.css.js +5 -0
  43. package/dist/i18nBundle.js +33 -2
  44. package/dist/renderer/LitRenderer.js +33 -12
  45. package/dist/renderer/directives/style-map.js +72 -0
  46. package/dist/renderer/executeTemplate.js +19 -2
  47. package/dist/resources/bundle.esm.js +15 -9
  48. package/dist/resources/bundle.esm.js.map +1 -1
  49. package/dist/sap/base/Log.js +2 -10
  50. package/dist/sap/base/assert.js +1 -5
  51. package/dist/sap/base/security/encodeCSS.js +14 -0
  52. package/dist/sap/base/security/encodeXML.js +23 -0
  53. package/dist/sap/base/strings/toHex.js +8 -0
  54. package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +1 -1
  55. package/dist/test-resources/elements/WithStaticArea.js +2 -1
  56. package/dist/test-resources/pages/AllTestElements.html +3 -0
  57. package/dist/test-resources/pages/i18n.html +1 -3
  58. package/dist/test-resources/specs/ConfigurationChange.spec.js +9 -9
  59. package/dist/test-resources/specs/ConfigurationScript.spec.js +24 -24
  60. package/dist/test-resources/specs/ConfigurationURL.spec.js +33 -33
  61. package/dist/test-resources/specs/CustomTheme.spec.js +7 -7
  62. package/dist/test-resources/specs/EventProvider.spec.js +63 -0
  63. package/dist/test-resources/specs/StaticArea.spec.js +55 -13
  64. package/dist/test-resources/specs/Theming.spec.js +22 -11
  65. package/dist/test-resources/specs/UI5ElementInvalidation.js +29 -29
  66. package/dist/test-resources/specs/UI5ElementLifecycle.js +11 -11
  67. package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +11 -11
  68. package/dist/test-resources/specs/UI5ElementMetadataExt.js +8 -8
  69. package/dist/test-resources/specs/UI5ElementPropertyValidation.js +6 -6
  70. package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +36 -36
  71. package/dist/test-resources/specs/UI5ElementShadowDOM.js +9 -9
  72. package/dist/test-resources/specs/UI5ElementSlots.js +9 -9
  73. package/dist/theming/CustomStyle.js +23 -3
  74. package/dist/theming/applyTheme.js +11 -10
  75. package/dist/theming/getEffectiveLinksHrefs.js +27 -0
  76. package/dist/theming/getEffectiveStyle.js +9 -0
  77. package/dist/theming/getStylesString.js +4 -2
  78. package/dist/theming/getThemeDesignerTheme.js +25 -5
  79. package/dist/theming/preloadLinks.js +23 -0
  80. package/dist/types/DataType.js +12 -0
  81. package/dist/types/Float.js +4 -0
  82. package/dist/types/Integer.js +4 -0
  83. package/dist/updateShadowRoot.js +8 -4
  84. package/dist/util/FocusableElements.js +8 -6
  85. package/dist/util/InvisibleMessage.js +11 -9
  86. package/dist/util/TabbableElements.js +4 -0
  87. package/dist/util/createLinkInHead.js +19 -0
  88. package/dist/util/escapeRegex.js +10 -0
  89. package/dist/util/generateHighlightedMarkup.js +42 -0
  90. package/dist/util/getNormalizedTarget.js +16 -0
  91. package/dist/util/isNodeHidden.js +1 -1
  92. package/lib/generate-asset-parameters/index.js +8 -5
  93. package/lib/generate-styles/index.js +26 -0
  94. package/lib/generate-version-info/index.js +32 -0
  95. package/package-scripts.js +12 -16
  96. package/package.json +10 -12
  97. package/src/Boot.js +34 -18
  98. package/src/CSP.js +59 -0
  99. package/src/CustomElementsRegistry.js +60 -4
  100. package/src/CustomElementsScope.js +20 -98
  101. package/src/CustomElementsScopeUtils.js +108 -0
  102. package/src/Device.js +20 -1
  103. package/src/EventProvider.js +19 -25
  104. package/src/FeaturesRegistry.js +4 -1
  105. package/src/FontFace.js +7 -95
  106. package/src/InitialConfiguration.js +11 -7
  107. package/src/Keys.js +56 -0
  108. package/src/ManagedStyles.js +83 -0
  109. package/src/Render.js +3 -1
  110. package/src/Runtimes.js +107 -0
  111. package/src/StaticAreaItem.js +15 -10
  112. package/src/SystemCSSVars.js +4 -25
  113. package/src/UI5Element.js +59 -60
  114. package/src/UI5ElementMetadata.js +18 -2
  115. package/src/asset-registries/Icons.js +22 -8
  116. package/src/asset-registries/Illustrations.js +10 -3
  117. package/src/asset-registries/LocaleData.js +17 -3
  118. package/src/asset-registries/Themes.js +6 -2
  119. package/src/assets-meta/IconCollectionsAlias.js +18 -0
  120. package/src/config/Icons.js +52 -0
  121. package/src/config/Theme.js +25 -0
  122. package/src/css/BusyIndicator.css +76 -0
  123. package/src/css/FontFace.css +75 -0
  124. package/src/css/OverrideFontFace.css +32 -0
  125. package/src/css/SystemCSSVars.css +17 -0
  126. package/src/delegate/ItemNavigation.js +66 -0
  127. package/src/features/F6Navigation.js +106 -0
  128. package/src/features/OpenUI5Enablement.js +119 -0
  129. package/src/i18nBundle.js +33 -2
  130. package/src/renderer/LitRenderer.js +33 -12
  131. package/src/renderer/directives/style-map.js +72 -0
  132. package/src/renderer/executeTemplate.js +19 -2
  133. package/src/theming/CustomStyle.js +23 -3
  134. package/src/theming/applyTheme.js +11 -10
  135. package/src/theming/getEffectiveLinksHrefs.js +27 -0
  136. package/src/theming/getEffectiveStyle.js +9 -0
  137. package/src/theming/getStylesString.js +4 -2
  138. package/src/theming/getThemeDesignerTheme.js +25 -5
  139. package/src/theming/preloadLinks.js +23 -0
  140. package/src/types/DataType.js +12 -0
  141. package/src/types/Float.js +4 -0
  142. package/src/types/Integer.js +4 -0
  143. package/src/updateShadowRoot.js +8 -4
  144. package/src/util/FocusableElements.js +8 -6
  145. package/src/util/InvisibleMessage.js +11 -9
  146. package/src/util/TabbableElements.js +4 -0
  147. package/src/util/createLinkInHead.js +19 -0
  148. package/src/util/escapeRegex.js +10 -0
  149. package/src/util/generateHighlightedMarkup.js +42 -0
  150. package/src/util/getNormalizedTarget.js +16 -0
  151. package/src/util/isNodeHidden.js +1 -1
  152. package/used-modules.txt +4 -1
  153. package/dist/config/AssetsPath.js +0 -17
  154. package/dist/theming/createThemePropertiesStyleTag.js +0 -20
  155. package/dist/util/encodeCSS.js +0 -24
  156. package/hash.txt +0 -1
  157. package/src/config/AssetsPath.js +0 -17
  158. package/src/theming/createThemePropertiesStyleTag.js +0 -20
  159. package/src/util/encodeCSS.js +0 -24
@@ -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
+ };
@@ -2,7 +2,8 @@ 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 "./CustomElementsScope.js";
5
+ import { getEffectiveScopingSuffixForTag } from "./CustomElementsScopeUtils.js";
6
+ import getEffectiveDir from "./locale/getEffectiveDir.js";
6
7
 
7
8
  /**
8
9
  *
@@ -24,6 +25,9 @@ class StaticAreaItem extends HTMLElement {
24
25
  setOwnerElement(ownerElement) {
25
26
  this.ownerElement = ownerElement;
26
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
+ }
27
31
  }
28
32
 
29
33
  /**
@@ -33,6 +37,7 @@ class StaticAreaItem extends HTMLElement {
33
37
  update() {
34
38
  if (this._rendered) {
35
39
  this._updateContentDensity();
40
+ this._updateDirection();
36
41
  updateShadowRoot(this.ownerElement, true);
37
42
  }
38
43
  }
@@ -51,6 +56,15 @@ class StaticAreaItem extends HTMLElement {
51
56
  }
52
57
  }
53
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
+
54
68
  /**
55
69
  * @protected
56
70
  * Returns reference to the DOM element where the current fragment is added.
@@ -65,15 +79,6 @@ class StaticAreaItem extends HTMLElement {
65
79
  return this.shadowRoot;
66
80
  }
67
81
 
68
- /**
69
- * @protected
70
- * @param refName
71
- * @returns {Element}
72
- */
73
- getStableDomRef(refName) {
74
- return this.shadowRoot.querySelector(`[data-ui5-stable=${refName}]`);
75
- }
76
-
77
82
  static getTag() {
78
83
  const pureTag = "ui5-static-area-item";
79
84
  const suffix = getEffectiveScopingSuffixForTag(pureTag);
@@ -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;
@@ -10,15 +10,15 @@ import { registerTag, isTagRegistered, recordTagRegistrationFailure } from "./Cu
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
19
  import getClassCopy from "./util/getClassCopy.js";
20
20
  import { markAsRtlAware } from "./locale/RTLAwareRegistry.js";
21
- import isLegacyBrowser from "./isLegacyBrowser.js";
21
+ import preloadLinks from "./theming/preloadLinks.js";
22
22
 
23
23
  let autoId = 0;
24
24
 
@@ -43,9 +43,11 @@ function _invalidate(changeInfo) {
43
43
 
44
44
  this._changedState.push(changeInfo);
45
45
  renderDeferred(this);
46
- this._eventProvider.fireEvent("change", { ...changeInfo, target: this });
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,8 +103,10 @@ 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
- const needsShadowDOM = this.constructor._needsShadowDOM();
106
110
  const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
107
111
 
108
112
  this._inDOM = true;
@@ -113,10 +117,6 @@ class UI5Element extends HTMLElement {
113
117
  await this._processChildren();
114
118
  }
115
119
 
116
- if (needsShadowDOM && !this.shadowRoot) { // Workaround for Firefox74 bug
117
- await Promise.resolve();
118
- }
119
-
120
120
  if (!this._inDOM) { // Component removed from DOM while _processChildren was running
121
121
  return;
122
122
  }
@@ -134,7 +134,6 @@ class UI5Element extends HTMLElement {
134
134
  * @private
135
135
  */
136
136
  disconnectedCallback() {
137
- const needsShadowDOM = this.constructor._needsShadowDOM();
138
137
  const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
139
138
 
140
139
  this._inDOM = false;
@@ -143,13 +142,11 @@ class UI5Element extends HTMLElement {
143
142
  this._stopObservingDOMChildren();
144
143
  }
145
144
 
146
- if (needsShadowDOM) {
147
- if (this._fullyConnected) {
148
- if (typeof this.onExitDOM === "function") {
149
- this.onExitDOM();
150
- }
151
- this._fullyConnected = false;
145
+ if (this._fullyConnected) {
146
+ if (typeof this.onExitDOM === "function") {
147
+ this.onExitDOM();
152
148
  }
149
+ this._fullyConnected = false;
153
150
  }
154
151
 
155
152
  if (this.staticAreaItem && this.staticAreaItem.parentElement) {
@@ -259,7 +256,8 @@ class UI5Element extends HTMLElement {
259
256
 
260
257
  // Listen for any invalidation on the child if invalidateOnChildChange is true or an object (ignore when false or not set)
261
258
  if (child.isUI5Element && slotData.invalidateOnChildChange) {
262
- child._attachChange(this._getChildChangeListener(slotName));
259
+ const method = (child.attachInvalidate || child._attachChange).bind(child);
260
+ method(this._getChildChangeListener(slotName));
263
261
  }
264
262
 
265
263
  // Listen for the slotchange event if the child is a slot itself
@@ -319,7 +317,8 @@ class UI5Element extends HTMLElement {
319
317
 
320
318
  children.forEach(child => {
321
319
  if (child && child.isUI5Element) {
322
- child._detachChange(this._getChildChangeListener(slotName));
320
+ const method = (child.detachInvalidate || child._detachChange).bind(child);
321
+ method(this._getChildChangeListener(slotName));
323
322
  }
324
323
 
325
324
  if (isSlot(child)) {
@@ -334,20 +333,20 @@ class UI5Element extends HTMLElement {
334
333
  * Attach a callback that will be executed whenever the component is invalidated
335
334
  *
336
335
  * @param callback
337
- * @protected
336
+ * @public
338
337
  */
339
- _attachChange(callback) {
340
- this._eventProvider.attachEvent("change", callback);
338
+ attachInvalidate(callback) {
339
+ this._eventProvider.attachEvent("invalidate", callback);
341
340
  }
342
341
 
343
342
  /**
344
343
  * Detach the callback that is executed whenever the component is invalidated
345
344
  *
346
345
  * @param callback
347
- * @protected
346
+ * @public
348
347
  */
349
- _detachChange(callback) {
350
- this._eventProvider.detachEvent("change", callback);
348
+ detachInvalidate(callback) {
349
+ this._eventProvider.detachEvent("invalidate", callback);
351
350
  }
352
351
 
353
352
  /**
@@ -384,12 +383,8 @@ class UI5Element extends HTMLElement {
384
383
  const propertyTypeClass = properties[nameInCamelCase].type;
385
384
  if (propertyTypeClass === Boolean) {
386
385
  newValue = newValue !== null;
387
- }
388
- if (propertyTypeClass === Integer) {
389
- newValue = parseInt(newValue);
390
- }
391
- if (propertyTypeClass === Float) {
392
- newValue = parseFloat(newValue);
386
+ } else if (isDescendantOf(propertyTypeClass, DataType)) {
387
+ newValue = propertyTypeClass.attributeToProperty(newValue);
393
388
  }
394
389
  this[nameInCamelCase] = newValue;
395
390
  }
@@ -402,22 +397,24 @@ class UI5Element extends HTMLElement {
402
397
  if (!this.constructor.getMetadata().hasAttribute(name)) {
403
398
  return;
404
399
  }
405
-
406
- if (typeof newValue === "object") {
407
- return;
408
- }
409
-
400
+ const properties = this.constructor.getMetadata().getProperties();
401
+ const propertyTypeClass = properties[name].type;
410
402
  const attrName = camelToKebabCase(name);
411
403
  const attrValue = this.getAttribute(attrName);
412
- if (typeof newValue === "boolean") {
404
+
405
+ if (propertyTypeClass === Boolean) {
413
406
  if (newValue === true && attrValue === null) {
414
407
  this.setAttribute(attrName, "");
415
408
  } else if (newValue === false && attrValue !== null) {
416
409
  this.removeAttribute(attrName);
417
410
  }
418
- } else if (attrValue !== newValue) {
419
- this.setAttribute(attrName, newValue);
420
- }
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
421
418
  }
422
419
 
423
420
  /**
@@ -617,25 +614,27 @@ class UI5Element extends HTMLElement {
617
614
 
618
615
  /**
619
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
620
618
  * Use this method instead of "this.shadowRoot" to read the Shadow DOM, if ever necessary
619
+ *
621
620
  * @public
622
621
  */
623
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
+
624
628
  if (!this.shadowRoot || this.shadowRoot.children.length === 0) {
625
629
  return;
626
630
  }
627
631
 
628
- this._assertShadowRootStructure();
629
-
630
- return this.shadowRoot.children.length === 1
631
- ? this.shadowRoot.children[0] : this.shadowRoot.children[1];
632
- }
633
-
634
- _assertShadowRootStructure() {
635
- const expectedChildrenCount = document.adoptedStyleSheets || isLegacyBrowser() ? 1 : 2;
636
- if (this.shadowRoot.children.length !== expectedChildrenCount) {
632
+ const children = [...this.shadowRoot.children].filter(child => !["link", "style"].includes(child.localName));
633
+ if (children.length !== 1) {
637
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
638
635
  }
636
+
637
+ return children[0];
639
638
  }
640
639
 
641
640
  /**
@@ -661,17 +660,6 @@ class UI5Element extends HTMLElement {
661
660
  return this.getFocusDomRef();
662
661
  }
663
662
 
664
- /**
665
- * 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
666
- * @public
667
- * @method
668
- * @param {String} refName Defines the name of the stable DOM ref
669
- */
670
- getStableDomRef(refName) {
671
- const staticAreaResult = this.staticAreaItem && this.staticAreaItem.getStableDomRef(refName);
672
- return staticAreaResult || this.getDomRef().querySelector(`[data-ui5-stable=${refName}]`);
673
- }
674
-
675
663
  /**
676
664
  * Set the focus to the element, returned by "getFocusDomRef()" (marked by "data-sap-focus-ref")
677
665
  * @public
@@ -861,6 +849,8 @@ class UI5Element extends HTMLElement {
861
849
  const oldState = this._state[prop];
862
850
  if (propData.multiple && propData.compareValues) {
863
851
  isDifferent = !arraysAreEqual(oldState, value);
852
+ } else if (isDescendantOf(propData.type, DataType)) {
853
+ isDifferent = !propData.type.valuesAreEqual(oldState, value);
864
854
  } else {
865
855
  isDifferent = oldState !== value;
866
856
  }
@@ -908,7 +898,15 @@ class UI5Element extends HTMLElement {
908
898
  * @protected
909
899
  */
910
900
  static get metadata() {
911
- 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;
912
910
  }
913
911
 
914
912
  /**
@@ -996,6 +994,7 @@ class UI5Element extends HTMLElement {
996
994
  this._generateAccessors();
997
995
  registerTag(tag);
998
996
  window.customElements.define(tag, this);
997
+ preloadLinks(this);
999
998
 
1000
999
  if (altTag && !customElements.get(altTag)) {
1001
1000
  registerTag(altTag);
@@ -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
@@ -1,11 +1,12 @@
1
1
  import getSharedResource from "../getSharedResource.js";
2
+ import IconCollectionsAlias from "../assets-meta/IconCollectionsAlias.js";
3
+ import { getEffectiveDefaultIconCollection } from "../config/Icons.js";
2
4
 
3
5
  const loaders = new Map();
4
6
  const registry = getSharedResource("SVGIcons.registry", new Map());
5
7
  const iconCollectionPromises = getSharedResource("SVGIcons.promises", new Map());
6
8
 
7
9
  const ICON_NOT_FOUND = "ICON_NOT_FOUND";
8
- const DEFAULT_COLLECTION = "SAP-icons";
9
10
 
10
11
  /**
11
12
  * @deprecated
@@ -47,7 +48,7 @@ const _fillRegistry = bundleData => {
47
48
  // set
48
49
  const registerIcon = (name, { pathData, ltr, accData, collection, packageName } = {}) => { // eslint-disable-line
49
50
  if (!collection) {
50
- collection = DEFAULT_COLLECTION;
51
+ collection = getEffectiveDefaultIconCollection();
51
52
  }
52
53
 
53
54
  const key = `${collection}/${name}`;
@@ -67,12 +68,16 @@ const _parseName = name => {
67
68
 
68
69
  let collection;
69
70
  [name, collection] = name.split("/").reverse();
70
- collection = collection || DEFAULT_COLLECTION;
71
- // hardcoded alias in case icon explorer is used, resolve `SAP-icons-TNT` to `tnt`
72
- // aliases can be made a feature in the future if more collections need it or more aliases are needed.
73
- if (collection === "SAP-icons-TNT") {
74
- collection = "tnt";
75
- }
71
+ collection = collection || getEffectiveDefaultIconCollection();
72
+
73
+ // Normalize collection name.
74
+ // - resolve `SAP-icons-TNT` to `tnt`.
75
+ // - resolve `BusinessSuiteInAppSymbols` to `business-suite`.
76
+ // - resolve `horizon` to `SAP-icons-v5`,
77
+ // Note: aliases can be made as a feature, if more collections need it or more aliases are needed.
78
+ collection = _normalizeCollection(collection);
79
+ name = name.replace("icon-", "");
80
+
76
81
  const registryKey = `${collection}/${name}`;
77
82
  return { name, collection, registryKey };
78
83
  };
@@ -108,9 +113,18 @@ const _getRegisteredNames = async () => {
108
113
  // fetch one icon of each collection to trigger the bundle load
109
114
  await getIconData("edit");
110
115
  await getIconData("tnt/arrow");
116
+ await getIconData("business-suite/3d");
111
117
  return Array.from(registry.keys());
112
118
  };
113
119
 
120
+ const _normalizeCollection = collectionName => {
121
+ if (IconCollectionsAlias[collectionName]) {
122
+ return IconCollectionsAlias[collectionName];
123
+ }
124
+
125
+ return collectionName;
126
+ };
127
+
114
128
  export {
115
129
  registerIconBundle,
116
130
  registerIconLoader,
@@ -3,8 +3,8 @@ import getSharedResource from "../getSharedResource.js";
3
3
  const registry = getSharedResource("SVGIllustration.registry", new Map());
4
4
  const ILLUSTRATION_NOT_FOUND = "ILLUSTRATION_NOT_FOUND";
5
5
 
6
- const registerIllustration = (name, { dialogSvg, sceneSvg, spotSvg, title, subtitle } = {}) => { // eslint-disable-line
7
- registry.set(name, {
6
+ const registerIllustration = (name, { dialogSvg, sceneSvg, spotSvg, set, title, subtitle } = {}) => { // eslint-disable-line
7
+ registry.set(`${set}/${name}`, {
8
8
  dialogSvg,
9
9
  sceneSvg,
10
10
  spotSvg,
@@ -14,7 +14,14 @@ const registerIllustration = (name, { dialogSvg, sceneSvg, spotSvg, title, subti
14
14
  };
15
15
 
16
16
  const getIllustrationDataSync = nameProp => {
17
- return registry.get(nameProp) || ILLUSTRATION_NOT_FOUND;
17
+ let set = "fiori";
18
+
19
+ if (nameProp.startsWith("Tnt")) {
20
+ set = "tnt";
21
+ nameProp = nameProp.replace(/^Tnt/, "");
22
+ }
23
+
24
+ return registry.get(`${set}/${nameProp}`) || ILLUSTRATION_NOT_FOUND;
18
25
  };
19
26
 
20
27
  export {
@@ -13,14 +13,22 @@ 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
 
18
+ const DEV_MODE = false;
19
+
19
20
  const _showAssetsWarningOnce = localeId => {
20
- if (!warningShown) {
21
+ if (warningShown) {
22
+ return;
23
+ }
24
+
25
+ if (!DEV_MODE) {
21
26
  console.warn(`[LocaleData] Supported locale "${localeId}" not configured, import the "Assets.js" module from the webcomponents package you are using.`); /* eslint-disable-line */
22
- warningShown = true;
27
+ } else {
28
+ console.warn(`[LocaleData] Note: in dev mode, CLDR assets might be disabled for performance reasons. Try running "ENABLE_CLDR=1 yarn start" to test CLDR assets.`); /* eslint-disable-line */
23
29
  }
30
+
31
+ warningShown = true;
24
32
  };
25
33
 
26
34
  const calcLocale = (language, region, script) => {
@@ -39,6 +47,12 @@ const calcLocale = (language, region, script) => {
39
47
  }
40
48
  }
41
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
+
42
56
  // try language + region
43
57
  let localeId = `${language}_${region}`;
44
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 themeStyles.get(`${packageName}_${DEFAULT_THEME}`);
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,18 @@
1
+ /**
2
+ * Supported icon collection names and aliases.
3
+ *
4
+ * Users might specify a collection, using both the key and the value in the following key-value pairs,
5
+ * e.g the following pairs are completely exchangeable:
6
+ * "SAP-icons-TNT/actor" and "tnt/actor", "BusinessSuiteInAppSymbols/3d" and "business-suite/3d",
7
+ * "SAP-icons-v5/accept" and "horizon/accept".
8
+ *
9
+ * Note: technically, in the code we maintain the collections under the "value" name - "tnt", "business-suite",
10
+ * SAP-icons-v5" and "SAP-icons"(which does not have an alias).
11
+ */
12
+ const IconCollectionsAlias = {
13
+ "SAP-icons-TNT": "tnt",
14
+ "BusinessSuiteInAppSymbols": "business-suite",
15
+ "horizon": "SAP-icons-v5",
16
+ };
17
+
18
+ export default IconCollectionsAlias;