@ui5/webcomponents-base 0.0.0-0fcda382e → 0.0.0-11d529e8a

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 (298) hide show
  1. package/.eslintignore +2 -0
  2. package/CHANGELOG.md +137 -0
  3. package/README.md +26 -1
  4. package/bundle.esm.js +17 -7
  5. package/dist/AssetRegistry.js +8 -6
  6. package/dist/Boot.js +43 -0
  7. package/dist/CustomElementsRegistry.js +24 -8
  8. package/dist/CustomElementsScope.js +108 -0
  9. package/dist/DOMObserver.js +65 -0
  10. package/dist/Device.js +58 -779
  11. package/dist/EventProvider.js +38 -26
  12. package/dist/FontFace.js +52 -7
  13. package/dist/InitialConfiguration.js +32 -8
  14. package/dist/Keys.js +89 -2
  15. package/dist/MediaRange.js +109 -0
  16. package/dist/PropertiesFileFormat.js +95 -0
  17. package/dist/Render.js +173 -0
  18. package/dist/RenderQueue.js +41 -17
  19. package/dist/RenderScheduler.js +24 -126
  20. package/dist/StaticArea.js +1 -39
  21. package/dist/StaticAreaItem.js +64 -62
  22. package/dist/SystemCSSVars.js +31 -0
  23. package/dist/Theming.js +2 -1
  24. package/dist/UI5Element.js +427 -299
  25. package/dist/UI5ElementMetadata.js +157 -19
  26. package/dist/asset-registries/Icons.js +118 -14
  27. package/dist/asset-registries/Illustrations.js +30 -0
  28. package/dist/asset-registries/LocaleData.js +90 -65
  29. package/dist/asset-registries/Themes.js +23 -32
  30. package/dist/asset-registries/i18n.js +72 -30
  31. package/dist/config/AnimationMode.js +11 -1
  32. package/dist/config/Language.js +58 -2
  33. package/dist/delegate/ItemNavigation.js +244 -171
  34. package/dist/delegate/ResizeHandler.js +78 -38
  35. package/dist/delegate/ScrollEnablement.js +49 -20
  36. package/dist/features/OpenUI5Support.js +42 -7
  37. package/dist/generated/AssetParameters.js +1 -1
  38. package/dist/getSharedResource.js +30 -0
  39. package/dist/i18nBundle.js +27 -4
  40. package/dist/isLegacyBrowser.js +3 -0
  41. package/dist/locale/RTLAwareRegistry.js +14 -0
  42. package/dist/locale/applyDirection.js +17 -0
  43. package/dist/locale/directionChange.js +32 -0
  44. package/dist/locale/getEffectiveDir.js +28 -0
  45. package/dist/locale/getLocale.js +12 -2
  46. package/dist/locale/languageChange.js +22 -0
  47. package/dist/renderer/LitRenderer.js +21 -4
  48. package/dist/renderer/executeTemplate.js +17 -0
  49. package/dist/resources/bundle.esm.js +17 -109
  50. package/dist/resources/bundle.esm.js.map +1 -1
  51. package/dist/sap/base/Log.js +241 -0
  52. package/dist/sap/base/assert.js +8 -0
  53. package/dist/sap/base/security/URLListValidator.js +148 -0
  54. package/dist/sap/base/security/sanitizeHTML.js +16 -0
  55. package/dist/sap/base/util/now.js +7 -0
  56. package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +3585 -0
  57. package/dist/test-resources/assets/Themes.js +10 -6
  58. package/dist/test-resources/elements/Parent.js +6 -2
  59. package/dist/test-resources/elements/WithStaticArea.js +2 -1
  60. package/dist/test-resources/pages/AllTestElements.html +3 -3
  61. package/dist/test-resources/pages/Configuration.html +0 -2
  62. package/dist/test-resources/pages/ConfigurationScript.html +1 -3
  63. package/dist/test-resources/pages/assets/messagebundle_de.properties +1 -0
  64. package/dist/test-resources/pages/assets/messagebundle_en.properties +1 -0
  65. package/dist/test-resources/pages/assets/messagebundle_es.properties +1 -0
  66. package/dist/test-resources/pages/assets/messagebundle_fr.properties +1 -0
  67. package/dist/test-resources/pages/i18n.html +35 -0
  68. package/dist/test-resources/specs/ConfigurationChange.spec.js +11 -9
  69. package/dist/test-resources/specs/ConfigurationScript.spec.js +25 -23
  70. package/dist/test-resources/specs/ConfigurationURL.spec.js +65 -17
  71. package/dist/test-resources/specs/CustomTheme.spec.js +7 -5
  72. package/dist/test-resources/specs/EventProvider.spec.js +63 -0
  73. package/dist/test-resources/specs/StaticArea.spec.js +56 -12
  74. package/dist/test-resources/specs/Theming.spec.js +9 -7
  75. package/dist/test-resources/specs/UI5ElementInvalidation.js +54 -70
  76. package/dist/test-resources/specs/UI5ElementLifecycle.js +19 -14
  77. package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +25 -51
  78. package/dist/test-resources/specs/UI5ElementMetadataExt.js +9 -7
  79. package/dist/test-resources/specs/UI5ElementPropertyValidation.js +7 -5
  80. package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +37 -35
  81. package/dist/test-resources/specs/UI5ElementShadowDOM.js +10 -8
  82. package/dist/test-resources/specs/UI5ElementSlots.js +10 -8
  83. package/dist/theming/CustomStyle.js +28 -7
  84. package/dist/theming/ThemeLoaded.js +22 -0
  85. package/dist/theming/applyTheme.js +2 -5
  86. package/dist/theming/getConstructableStyle.js +15 -10
  87. package/dist/theming/getEffectiveStyle.js +23 -8
  88. package/dist/theming/getStylesString.js +13 -0
  89. package/dist/types/CSSColor.js +9 -0
  90. package/dist/types/CalendarType.js +1 -1
  91. package/dist/types/DataType.js +13 -1
  92. package/dist/types/Float.js +14 -0
  93. package/dist/types/Integer.js +4 -0
  94. package/dist/types/InvisibleMessageMode.js +30 -0
  95. package/dist/types/ItemNavigationBehavior.js +2 -7
  96. package/dist/types/NavigationMode.js +1 -0
  97. package/dist/types/PopupState.js +1 -1
  98. package/dist/types/ValueState.js +1 -1
  99. package/dist/updateShadowRoot.js +26 -0
  100. package/dist/util/AriaLabelHelper.js +41 -0
  101. package/dist/util/Caret.js +45 -0
  102. package/dist/util/ColorConversion.js +370 -0
  103. package/dist/util/FocusableElements.js +25 -8
  104. package/dist/util/HTMLSanitizer.js +7 -0
  105. package/dist/util/InvisibleMessage.js +58 -0
  106. package/dist/util/PopupUtils.js +93 -0
  107. package/dist/util/SlotsHelper.js +43 -0
  108. package/dist/util/TabbableElements.js +1 -1
  109. package/dist/util/arraysAreEqual.js +15 -0
  110. package/dist/util/clamp.js +12 -0
  111. package/dist/util/debounce.js +17 -0
  112. package/dist/util/encodeCSS.js +24 -0
  113. package/dist/util/getActiveElement.js +11 -0
  114. package/dist/util/getClassCopy.js +10 -0
  115. package/dist/util/getEffectiveContentDensity.js +5 -0
  116. package/dist/util/getSingletonElementInstance.js +13 -0
  117. package/dist/util/isElementInView.js +15 -0
  118. package/dist/util/isNodeHidden.js +1 -5
  119. package/dist/util/isNodeTabbable.js +4 -4
  120. package/dist/util/isValidPropertyName.js +9 -3
  121. package/dist/util/setToArray.js +10 -0
  122. package/hash.txt +1 -0
  123. package/index.js +1 -1
  124. package/package-scripts.js +33 -18
  125. package/package.json +20 -11
  126. package/src/AssetRegistry.js +8 -6
  127. package/src/Boot.js +43 -0
  128. package/src/CustomElementsRegistry.js +24 -8
  129. package/src/CustomElementsScope.js +108 -0
  130. package/src/DOMObserver.js +65 -0
  131. package/src/Device.js +58 -779
  132. package/src/EventProvider.js +38 -26
  133. package/src/FontFace.js +52 -7
  134. package/src/InitialConfiguration.js +32 -8
  135. package/src/Keys.js +89 -2
  136. package/src/MediaRange.js +109 -0
  137. package/src/PropertiesFileFormat.js +95 -0
  138. package/src/Render.js +173 -0
  139. package/src/RenderQueue.js +41 -17
  140. package/src/RenderScheduler.js +24 -126
  141. package/src/StaticArea.js +1 -39
  142. package/src/StaticAreaItem.js +64 -62
  143. package/src/SystemCSSVars.js +31 -0
  144. package/src/Theming.js +2 -1
  145. package/src/UI5Element.js +427 -299
  146. package/src/UI5ElementMetadata.js +157 -19
  147. package/src/asset-registries/Icons.js +118 -14
  148. package/src/asset-registries/Illustrations.js +30 -0
  149. package/src/asset-registries/LocaleData.js +90 -65
  150. package/src/asset-registries/Themes.js +23 -32
  151. package/src/asset-registries/i18n.js +72 -30
  152. package/src/config/AnimationMode.js +11 -1
  153. package/src/config/Language.js +58 -2
  154. package/src/delegate/ItemNavigation.js +244 -171
  155. package/src/delegate/ResizeHandler.js +78 -38
  156. package/src/delegate/ScrollEnablement.js +49 -20
  157. package/src/features/OpenUI5Support.js +42 -7
  158. package/src/getSharedResource.js +30 -0
  159. package/src/i18nBundle.js +27 -4
  160. package/src/isLegacyBrowser.js +3 -0
  161. package/src/locale/RTLAwareRegistry.js +14 -0
  162. package/src/locale/applyDirection.js +17 -0
  163. package/src/locale/directionChange.js +32 -0
  164. package/src/locale/getEffectiveDir.js +28 -0
  165. package/src/locale/getLocale.js +12 -2
  166. package/src/locale/languageChange.js +22 -0
  167. package/src/renderer/LitRenderer.js +21 -4
  168. package/src/renderer/executeTemplate.js +17 -0
  169. package/src/theming/CustomStyle.js +28 -7
  170. package/src/theming/ThemeLoaded.js +22 -0
  171. package/src/theming/applyTheme.js +2 -5
  172. package/src/theming/getConstructableStyle.js +15 -10
  173. package/src/theming/getEffectiveStyle.js +23 -8
  174. package/src/theming/getStylesString.js +13 -0
  175. package/src/types/CSSColor.js +9 -0
  176. package/src/types/CalendarType.js +1 -1
  177. package/src/types/DataType.js +13 -1
  178. package/src/types/Float.js +14 -0
  179. package/src/types/Integer.js +4 -0
  180. package/src/types/InvisibleMessageMode.js +30 -0
  181. package/src/types/ItemNavigationBehavior.js +2 -7
  182. package/src/types/NavigationMode.js +1 -0
  183. package/src/types/PopupState.js +1 -1
  184. package/src/types/ValueState.js +1 -1
  185. package/src/updateShadowRoot.js +26 -0
  186. package/src/util/AriaLabelHelper.js +41 -0
  187. package/src/util/Caret.js +45 -0
  188. package/src/util/ColorConversion.js +370 -0
  189. package/src/util/FocusableElements.js +25 -8
  190. package/src/util/HTMLSanitizer.js +7 -0
  191. package/src/util/InvisibleMessage.js +58 -0
  192. package/src/util/PopupUtils.js +93 -0
  193. package/src/util/SlotsHelper.js +43 -0
  194. package/src/util/TabbableElements.js +1 -1
  195. package/src/util/arraysAreEqual.js +15 -0
  196. package/src/util/clamp.js +12 -0
  197. package/src/util/debounce.js +17 -0
  198. package/src/util/encodeCSS.js +24 -0
  199. package/src/util/getActiveElement.js +11 -0
  200. package/src/util/getClassCopy.js +10 -0
  201. package/src/util/getEffectiveContentDensity.js +5 -0
  202. package/src/util/getSingletonElementInstance.js +13 -0
  203. package/src/util/isElementInView.js +15 -0
  204. package/src/util/isNodeHidden.js +1 -5
  205. package/src/util/isNodeTabbable.js +4 -4
  206. package/src/util/isValidPropertyName.js +9 -3
  207. package/src/util/setToArray.js +10 -0
  208. package/used-modules.txt +7 -0
  209. package/bundle.es5.js +0 -28
  210. package/dist/SVGIconRegistry.js +0 -60
  211. package/dist/boot.js +0 -32
  212. package/dist/compatibility/DOMObserver.js +0 -62
  213. package/dist/compatibility/patchNodeValue.js +0 -24
  214. package/dist/compatibility/whenPolyfillLoaded.js +0 -26
  215. package/dist/delegate/CustomResize.js +0 -78
  216. package/dist/delegate/NativeResize.js +0 -44
  217. package/dist/features/browsersupport/Edge.js +0 -6
  218. package/dist/features/browsersupport/IE11.js +0 -41
  219. package/dist/features/browsersupport/IE11WithWebComponentsPolyfill.js +0 -5
  220. package/dist/renderer/ifDefined.js +0 -21
  221. package/dist/resources/bundle.es5.js +0 -212
  222. package/dist/resources/bundle.es5.js.map +0 -1
  223. package/dist/theming/CSSVarsPonyfill.js +0 -24
  224. package/dist/theming/adaptCSSForIE.js +0 -90
  225. package/dist/theming/createComponentStyleTag.js +0 -49
  226. package/dist/thirdparty/Array.from.js +0 -16
  227. package/dist/thirdparty/Array.prototype.fill.js +0 -44
  228. package/dist/thirdparty/Array.prototype.find.js +0 -46
  229. package/dist/thirdparty/Array.prototype.includes.js +0 -51
  230. package/dist/thirdparty/Element.prototype.closest.js +0 -11
  231. package/dist/thirdparty/Element.prototype.matches.js +0 -6
  232. package/dist/thirdparty/Map.prototype.keys.js +0 -9
  233. package/dist/thirdparty/Number.isInteger.js +0 -5
  234. package/dist/thirdparty/Number.isNaN.js +0 -1
  235. package/dist/thirdparty/Number.parseInt.js +0 -1
  236. package/dist/thirdparty/Object.assign.js +0 -31
  237. package/dist/thirdparty/Object.entries.js +0 -11
  238. package/dist/thirdparty/Symbol.js +0 -2
  239. package/dist/thirdparty/WeakSet.js +0 -27
  240. package/dist/thirdparty/es6-string-methods.js +0 -182
  241. package/dist/thirdparty/events-polyfills.js +0 -89
  242. package/dist/thirdparty/fetch.js +0 -1
  243. package/dist/thirdparty/template.js +0 -600
  244. package/dist/thirdparty/webcomponents-sd-ce-pf.js +0 -318
  245. package/dist/webcomponentsjs/LICENSE.md +0 -19
  246. package/dist/webcomponentsjs/README.md +0 -229
  247. package/dist/webcomponentsjs/bundles/webcomponents-ce.js +0 -63
  248. package/dist/webcomponentsjs/bundles/webcomponents-ce.js.map +0 -1
  249. package/dist/webcomponentsjs/bundles/webcomponents-sd-ce-pf.js +0 -297
  250. package/dist/webcomponentsjs/bundles/webcomponents-sd-ce-pf.js.map +0 -1
  251. package/dist/webcomponentsjs/bundles/webcomponents-sd-ce.js +0 -208
  252. package/dist/webcomponentsjs/bundles/webcomponents-sd-ce.js.map +0 -1
  253. package/dist/webcomponentsjs/bundles/webcomponents-sd.js +0 -166
  254. package/dist/webcomponentsjs/bundles/webcomponents-sd.js.map +0 -1
  255. package/dist/webcomponentsjs/custom-elements-es5-adapter.js +0 -15
  256. package/dist/webcomponentsjs/package.json +0 -46
  257. package/dist/webcomponentsjs/src/entrypoints/custom-elements-es5-adapter-index.js +0 -16
  258. package/dist/webcomponentsjs/src/entrypoints/webcomponents-bundle-index.js +0 -53
  259. package/dist/webcomponentsjs/src/entrypoints/webcomponents-ce-index.js +0 -17
  260. package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-ce-index.js +0 -19
  261. package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-ce-pf-index.js +0 -28
  262. package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-index.js +0 -18
  263. package/dist/webcomponentsjs/webcomponents-bundle.js +0 -298
  264. package/dist/webcomponentsjs/webcomponents-bundle.js.map +0 -1
  265. package/dist/webcomponentsjs/webcomponents-loader.js +0 -185
  266. package/src/SVGIconRegistry.js +0 -60
  267. package/src/boot.js +0 -32
  268. package/src/compatibility/DOMObserver.js +0 -62
  269. package/src/compatibility/patchNodeValue.js +0 -24
  270. package/src/compatibility/whenPolyfillLoaded.js +0 -26
  271. package/src/delegate/CustomResize.js +0 -78
  272. package/src/delegate/NativeResize.js +0 -44
  273. package/src/features/browsersupport/Edge.js +0 -6
  274. package/src/features/browsersupport/IE11.js +0 -41
  275. package/src/features/browsersupport/IE11WithWebComponentsPolyfill.js +0 -5
  276. package/src/renderer/ifDefined.js +0 -21
  277. package/src/theming/CSSVarsPonyfill.js +0 -24
  278. package/src/theming/adaptCSSForIE.js +0 -90
  279. package/src/theming/createComponentStyleTag.js +0 -49
  280. package/src/thirdparty/Array.from.js +0 -16
  281. package/src/thirdparty/Array.prototype.fill.js +0 -44
  282. package/src/thirdparty/Array.prototype.find.js +0 -46
  283. package/src/thirdparty/Array.prototype.includes.js +0 -51
  284. package/src/thirdparty/Element.prototype.closest.js +0 -11
  285. package/src/thirdparty/Element.prototype.matches.js +0 -6
  286. package/src/thirdparty/Map.prototype.keys.js +0 -9
  287. package/src/thirdparty/Number.isInteger.js +0 -5
  288. package/src/thirdparty/Number.isNaN.js +0 -1
  289. package/src/thirdparty/Number.parseInt.js +0 -1
  290. package/src/thirdparty/Object.assign.js +0 -31
  291. package/src/thirdparty/Object.entries.js +0 -11
  292. package/src/thirdparty/Symbol.js +0 -2
  293. package/src/thirdparty/WeakSet.js +0 -27
  294. package/src/thirdparty/es6-string-methods.js +0 -182
  295. package/src/thirdparty/events-polyfills.js +0 -89
  296. package/src/thirdparty/fetch.js +0 -1
  297. package/src/thirdparty/template.js +0 -600
  298. package/src/thirdparty/webcomponents-sd-ce-pf.js +0 -318
@@ -1,6 +1,8 @@
1
1
  import DataType from "./types/DataType.js";
2
2
  import isDescendantOf from "./util/isDescendantOf.js";
3
3
  import { camelToKebabCase } from "./util/StringHelper.js";
4
+ import { getSlottedElements } from "./util/SlotsHelper.js";
5
+ import { getEffectiveScopingSuffixForTag } from "./CustomElementsScope.js";
4
6
 
5
7
  /**
6
8
  *
@@ -12,6 +14,50 @@ class UI5ElementMetadata {
12
14
  this.metadata = metadata;
13
15
  }
14
16
 
17
+ getInitialState() {
18
+ if (Object.prototype.hasOwnProperty.call(this, "_initialState")) {
19
+ return this._initialState;
20
+ }
21
+
22
+ const initialState = {};
23
+ const slotsAreManaged = this.slotsAreManaged();
24
+
25
+ // Initialize properties
26
+ const props = this.getProperties();
27
+ for (const propName in props) { // eslint-disable-line
28
+ const propType = props[propName].type;
29
+ const propDefaultValue = props[propName].defaultValue;
30
+
31
+ if (propType === Boolean) {
32
+ initialState[propName] = false;
33
+
34
+ if (propDefaultValue !== undefined) {
35
+ console.warn("The 'defaultValue' metadata key is ignored for all booleans properties, they would be initialized with 'false' by default"); // eslint-disable-line
36
+ }
37
+ } else if (props[propName].multiple) {
38
+ initialState[propName] = [];
39
+ } else if (propType === Object) {
40
+ initialState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : {};
41
+ } else if (propType === String) {
42
+ initialState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : "";
43
+ } else {
44
+ initialState[propName] = propDefaultValue;
45
+ }
46
+ }
47
+
48
+ // Initialize slots
49
+ if (slotsAreManaged) {
50
+ const slots = this.getSlots();
51
+ for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line
52
+ const propertyName = slotData.propertyName || slotName;
53
+ initialState[propertyName] = [];
54
+ }
55
+ }
56
+
57
+ this._initialState = initialState;
58
+ return initialState;
59
+ }
60
+
15
61
  /**
16
62
  * Only intended for use by UI5Element.js
17
63
  * @protected
@@ -32,12 +78,44 @@ class UI5ElementMetadata {
32
78
  return validateSingleSlot(value, slotData);
33
79
  }
34
80
 
81
+ /**
82
+ * Returns the tag of the UI5 Element without the scope
83
+ * @public
84
+ */
85
+ getPureTag() {
86
+ return this.metadata.tag;
87
+ }
88
+
35
89
  /**
36
90
  * Returns the tag of the UI5 Element
37
91
  * @public
38
92
  */
39
93
  getTag() {
40
- return this.metadata.tag;
94
+ const pureTag = this.metadata.tag;
95
+ const suffix = getEffectiveScopingSuffixForTag(pureTag);
96
+ if (!suffix) {
97
+ return pureTag;
98
+ }
99
+
100
+ return `${pureTag}-${suffix}`;
101
+ }
102
+
103
+ /**
104
+ * Used to get the tag we need to register for backwards compatibility
105
+ * @public
106
+ */
107
+ getAltTag() {
108
+ const pureAltTag = this.metadata.altTag;
109
+ if (!pureAltTag) {
110
+ return;
111
+ }
112
+
113
+ const suffix = getEffectiveScopingSuffixForTag(pureAltTag);
114
+ if (!suffix) {
115
+ return pureAltTag;
116
+ }
117
+
118
+ return `${pureAltTag}-${suffix}`;
41
119
  }
42
120
 
43
121
  /**
@@ -48,7 +126,7 @@ class UI5ElementMetadata {
48
126
  */
49
127
  hasAttribute(propName) {
50
128
  const propData = this.getProperties()[propName];
51
- return propData.type !== Object && !propData.noAttribute;
129
+ return propData.type !== Object && !propData.noAttribute && !propData.multiple;
52
130
  }
53
131
 
54
132
  /**
@@ -125,6 +203,82 @@ class UI5ElementMetadata {
125
203
  getEvents() {
126
204
  return this.metadata.events || {};
127
205
  }
206
+
207
+ /**
208
+ * Determines whether this UI5 Element has any translatable texts (needs to be invalidated upon language change)
209
+ * @returns {boolean}
210
+ */
211
+ isLanguageAware() {
212
+ return !!this.metadata.languageAware;
213
+ }
214
+
215
+ /**
216
+ * Matches a changed entity (property/slot) with the given name against the "invalidateOnChildChange" configuration
217
+ * and determines whether this should cause and invalidation
218
+ *
219
+ * @param slotName the name of the slot in which a child was changed
220
+ * @param type the type of change in the child: "property" or "slot"
221
+ * @param name the name of the property/slot that changed
222
+ * @returns {boolean}
223
+ */
224
+ shouldInvalidateOnChildChange(slotName, type, name) {
225
+ const config = this.getSlots()[slotName].invalidateOnChildChange;
226
+
227
+ // invalidateOnChildChange was not set in the slot metadata - by default child changes do not affect the component
228
+ if (config === undefined) {
229
+ return false;
230
+ }
231
+
232
+ // The simple format was used: invalidateOnChildChange: true/false;
233
+ if (typeof config === "boolean") {
234
+ return config;
235
+ }
236
+
237
+ // The complex format was used: invalidateOnChildChange: { properties, slots }
238
+ if (typeof config === "object") {
239
+ // A property was changed
240
+ if (type === "property") {
241
+ // The config object does not have a properties field
242
+ if (config.properties === undefined) {
243
+ return false;
244
+ }
245
+
246
+ // The config object has the short format: properties: true/false
247
+ if (typeof config.properties === "boolean") {
248
+ return config.properties;
249
+ }
250
+
251
+ // The config object has the complex format: properties: [...]
252
+ if (Array.isArray(config.properties)) {
253
+ return config.properties.includes(name);
254
+ }
255
+
256
+ throw new Error("Wrong format for invalidateOnChildChange.properties: boolean or array is expected");
257
+ }
258
+
259
+ // A slot was changed
260
+ if (type === "slot") {
261
+ // The config object does not have a slots field
262
+ if (config.slots === undefined) {
263
+ return false;
264
+ }
265
+
266
+ // The config object has the short format: slots: true/false
267
+ if (typeof config.slots === "boolean") {
268
+ return config.slots;
269
+ }
270
+
271
+ // The config object has the complex format: slots: [...]
272
+ if (Array.isArray(config.slots)) {
273
+ return config.slots.includes(name);
274
+ }
275
+
276
+ throw new Error("Wrong format for invalidateOnChildChange.slots: boolean or array is expected");
277
+ }
278
+ }
279
+
280
+ throw new Error("Wrong format for invalidateOnChildChange: boolean or object is expected");
281
+ }
128
282
  }
129
283
 
130
284
  const validateSingleProperty = (value, propData) => {
@@ -145,23 +299,7 @@ const validateSingleProperty = (value, propData) => {
145
299
  };
146
300
 
147
301
  const validateSingleSlot = (value, slotData) => {
148
- if (value === null) {
149
- return value;
150
- }
151
-
152
- const getSlottedNodes = el => {
153
- const isTag = el instanceof HTMLElement;
154
- const isSlot = isTag && el.localName === "slot";
155
-
156
- if (isSlot) {
157
- return el.assignedNodes({ flatten: true }).filter(item => item instanceof HTMLElement);
158
- }
159
-
160
- return [el];
161
- };
162
-
163
- const slottedNodes = getSlottedNodes(value);
164
- slottedNodes.forEach(el => {
302
+ value && getSlottedElements(value).forEach(el => {
165
303
  if (!(el instanceof slotData.type)) {
166
304
  throw new Error(`${el} is not of type ${slotData.type}`);
167
305
  }
@@ -1,24 +1,128 @@
1
- import { registerIcon, registerCollectionPromise } from "../SVGIconRegistry.js";
2
- import { fetchJsonOnce } from "../util/FetchHelper.js";
1
+ import getSharedResource from "../getSharedResource.js";
3
2
 
3
+ const loaders = new Map();
4
+ const registry = getSharedResource("SVGIcons.registry", new Map());
5
+ const iconCollectionPromises = getSharedResource("SVGIcons.promises", new Map());
6
+
7
+ const ICON_NOT_FOUND = "ICON_NOT_FOUND";
8
+ const DEFAULT_COLLECTION = "SAP-icons";
9
+
10
+ /**
11
+ * @deprecated
12
+ */
4
13
  const registerIconBundle = async (collectionName, bundleData) => {
5
- let resolveFn;
6
- const collectionFetched = new Promise(resolve => {
7
- resolveFn = resolve;
8
- });
9
- registerCollectionPromise(collectionName, collectionFetched);
14
+ throw new Error("This method has been removed. Use `registerIconLoader` instead.");
15
+ };
10
16
 
11
- if (typeof bundleData !== "object") { // not inlined from build -> fetch it
12
- bundleData = await fetchJsonOnce(bundleData);
17
+ const registerIconLoader = async (collectionName, loader) => {
18
+ loaders.set(collectionName, loader);
19
+ };
20
+
21
+ const _loadIconCollectionOnce = async collectionName => {
22
+ if (!iconCollectionPromises.has(collectionName)) {
23
+ if (!loaders.has(collectionName)) {
24
+ throw new Error(`No loader registered for the ${collectionName} icons collection. Probably you forgot to import the "AllIcons.js" module for the respective package.`);
25
+ }
26
+ const loadIcons = loaders.get(collectionName);
27
+ iconCollectionPromises.set(collectionName, loadIcons(collectionName));
13
28
  }
14
- fillRegistry(bundleData);
15
- resolveFn();
29
+
30
+ return iconCollectionPromises.get(collectionName);
16
31
  };
17
32
 
18
- const fillRegistry = bundleData => {
33
+ const _fillRegistry = bundleData => {
19
34
  Object.keys(bundleData.data).forEach(iconName => {
20
- registerIcon(iconName, { pathData: bundleData.data[iconName], accData: bundleData.accData[iconName], collection: bundleData.collection });
35
+ const iconData = bundleData.data[iconName];
36
+
37
+ registerIcon(iconName, {
38
+ pathData: iconData.path,
39
+ ltr: iconData.ltr,
40
+ accData: iconData.acc,
41
+ collection: bundleData.collection,
42
+ packageName: bundleData.packageName,
43
+ });
21
44
  });
22
45
  };
23
46
 
24
- export { registerIconBundle }; // eslint-disable-line
47
+ // set
48
+ const registerIcon = (name, { pathData, ltr, accData, collection, packageName } = {}) => { // eslint-disable-line
49
+ if (!collection) {
50
+ collection = DEFAULT_COLLECTION;
51
+ }
52
+
53
+ const key = `${collection}/${name}`;
54
+ registry.set(key, {
55
+ pathData,
56
+ ltr,
57
+ accData,
58
+ packageName,
59
+ });
60
+ };
61
+
62
+ const _parseName = name => {
63
+ // silently support ui5-compatible URIs
64
+ if (name.startsWith("sap-icon://")) {
65
+ name = name.replace("sap-icon://", "");
66
+ }
67
+
68
+ let collection;
69
+ [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
+ }
76
+ // hardcoded alias in case icon explorer is used, resolve `BusinessSuiteInAppSymbols` to `business-suite`
77
+ // aliases can be made a feature in the future if more collections need it or more aliases are needed.
78
+ if (collection === "BusinessSuiteInAppSymbols") {
79
+ collection = "business-suite";
80
+ name = name.replace("icon-", "");
81
+ }
82
+ const registryKey = `${collection}/${name}`;
83
+ return { name, collection, registryKey };
84
+ };
85
+
86
+ const getIconDataSync = nameProp => {
87
+ const { registryKey } = _parseName(nameProp);
88
+ return registry.get(registryKey);
89
+ };
90
+
91
+ const getIconData = async nameProp => {
92
+ const { collection, registryKey } = _parseName(nameProp);
93
+
94
+ let iconData = ICON_NOT_FOUND;
95
+ try {
96
+ iconData = await _loadIconCollectionOnce(collection);
97
+ } catch (e) {
98
+ console.error(e.message); /* eslint-disable-line */
99
+ }
100
+
101
+ if (iconData === ICON_NOT_FOUND) {
102
+ return iconData;
103
+ }
104
+
105
+ if (!registry.has(registryKey)) {
106
+ // not filled by another await. many getters will await on the same loader, but fill only once
107
+ _fillRegistry(iconData);
108
+ }
109
+ return registry.get(registryKey);
110
+ };
111
+
112
+ // test page usage only
113
+ const _getRegisteredNames = async () => {
114
+ // fetch one icon of each collection to trigger the bundle load
115
+ await getIconData("edit");
116
+ await getIconData("tnt/arrow");
117
+ await getIconData("business-suite/3d");
118
+ return Array.from(registry.keys());
119
+ };
120
+
121
+ export {
122
+ registerIconBundle,
123
+ registerIconLoader,
124
+ getIconData,
125
+ getIconDataSync,
126
+ registerIcon,
127
+ _getRegisteredNames,
128
+ };
@@ -0,0 +1,30 @@
1
+ import getSharedResource from "../getSharedResource.js";
2
+
3
+ const registry = getSharedResource("SVGIllustration.registry", new Map());
4
+ const ILLUSTRATION_NOT_FOUND = "ILLUSTRATION_NOT_FOUND";
5
+
6
+ const registerIllustration = (name, { dialogSvg, sceneSvg, spotSvg, set, title, subtitle } = {}) => { // eslint-disable-line
7
+ registry.set(`${set}/${name}`, {
8
+ dialogSvg,
9
+ sceneSvg,
10
+ spotSvg,
11
+ title,
12
+ subtitle,
13
+ });
14
+ };
15
+
16
+ const getIllustrationDataSync = nameProp => {
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;
25
+ };
26
+
27
+ export {
28
+ getIllustrationDataSync,
29
+ registerIllustration,
30
+ };
@@ -1,14 +1,13 @@
1
- import { fetchJsonOnce } from "../util/FetchHelper.js";
2
- import { getFeature } from "../FeaturesRegistry.js";
1
+ import { attachLanguageChange } from "../locale/languageChange.js";
2
+ import getLocale from "../locale/getLocale.js";
3
3
  import { DEFAULT_LOCALE, SUPPORTED_LOCALES } from "../generated/AssetParameters.js";
4
+ import { getFeature } from "../FeaturesRegistry.js";
4
5
 
5
- const resources = new Map();
6
- const cldrData = {};
7
- const cldrUrls = {};
8
-
9
- // externally configurable mapping function for resolving (localeId -> URL)
10
- // default implementation - ui5 CDN
11
- let cldrMappingFn = locale => `https://ui5.sap.com/1.60.2/resources/sap/ui/core/cldr/${locale}.json`;
6
+ const localeDataMap = new Map();
7
+ const loaders = new Map();
8
+ const cldrPromises = new Map();
9
+ const reportedErrors = new Set();
10
+ let warningShown = false;
12
11
 
13
12
  const M_ISO639_OLD_TO_NEW = {
14
13
  "iw": "he",
@@ -17,6 +16,13 @@ const M_ISO639_OLD_TO_NEW = {
17
16
  "sh": "sr",
18
17
  };
19
18
 
19
+ const _showAssetsWarningOnce = localeId => {
20
+ if (!warningShown) {
21
+ 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;
23
+ }
24
+ };
25
+
20
26
  const calcLocale = (language, region, script) => {
21
27
  // normalize language and handle special cases
22
28
  language = (language && M_ISO639_OLD_TO_NEW[language]) || language;
@@ -35,91 +41,110 @@ const calcLocale = (language, region, script) => {
35
41
 
36
42
  // try language + region
37
43
  let localeId = `${language}_${region}`;
38
- if (!SUPPORTED_LOCALES.includes(localeId)) {
39
- // fallback to language only
40
- localeId = language;
44
+ if (SUPPORTED_LOCALES.includes(localeId)) {
45
+ if (loaders.has(localeId)) {
46
+ // supported and has loader
47
+ return localeId;
48
+ }
49
+
50
+ // supported, no loader - fallback to default and warn
51
+ _showAssetsWarningOnce(localeId);
52
+ return DEFAULT_LOCALE;
41
53
  }
42
- if (!SUPPORTED_LOCALES.includes(localeId)) {
43
- // fallback to english
44
- localeId = DEFAULT_LOCALE;
54
+
55
+ // not supported, try language only
56
+ localeId = language;
57
+ if (SUPPORTED_LOCALES.includes(localeId)) {
58
+ if (loaders.has(localeId)) {
59
+ // supported and has loader
60
+ return localeId;
61
+ }
62
+
63
+ // supported, no loader - fallback to default and warn
64
+ _showAssetsWarningOnce(localeId);
65
+ return DEFAULT_LOCALE;
45
66
  }
46
67
 
47
- return localeId;
68
+ // not supported - fallback to default locale
69
+ return DEFAULT_LOCALE;
48
70
  };
49
71
 
72
+ // internal set data
73
+ const setLocaleData = (localeId, content) => {
74
+ localeDataMap.set(localeId, content);
75
+ };
50
76
 
51
- const resolveMissingMappings = () => {
52
- if (!cldrMappingFn) {
53
- return;
77
+ // external getSync
78
+ const getLocaleData = localeId => {
79
+ // if there is no loader, the default fallback was fetched and a warning was given - use default locale instead
80
+ if (!loaders.has(localeId)) {
81
+ localeId = DEFAULT_LOCALE;
54
82
  }
55
83
 
56
- const missingLocales = SUPPORTED_LOCALES.filter(locale => !cldrData[locale] && !cldrUrls[locale]);
57
- missingLocales.forEach(locale => {
58
- cldrUrls[locale] = cldrMappingFn(locale);
59
- });
60
- };
84
+ const content = localeDataMap.get(localeId);
85
+ if (!content) {
86
+ throw new Error(`CLDR data for locale ${localeId} is not loaded!`);
87
+ }
61
88
 
62
- const registerModuleContent = (moduleName, content) => {
63
- resources.set(moduleName, content);
89
+ return content;
64
90
  };
65
91
 
66
- const getModuleContent = moduleName => {
67
- const moduleContent = resources.get(moduleName);
68
- if (moduleContent) {
69
- return moduleContent;
70
- }
92
+ // load bundle over the network once
93
+ const _loadCldrOnce = localeId => {
94
+ const loadCldr = loaders.get(localeId);
71
95
 
72
- const missingModule = moduleName.match(/sap\/ui\/core\/cldr\/(\w+)\.json/);
73
- if (missingModule) {
74
- throw new Error(`CLDR data for locale ${missingModule[1]} is not loaded!`);
96
+ if (!cldrPromises.get(localeId)) {
97
+ cldrPromises.set(localeId, loadCldr(localeId));
75
98
  }
76
99
 
77
- throw new Error(`Unknown module ${moduleName}`);
100
+ return cldrPromises.get(localeId);
78
101
  };
79
102
 
103
+ // external getAsync
80
104
  const fetchCldr = async (language, region, script) => {
81
- resolveMissingMappings();
82
105
  const localeId = calcLocale(language, region, script);
83
106
 
84
- let cldrObj = cldrData[localeId];
85
- const url = cldrUrls[localeId];
86
-
107
+ // reuse OpenUI5 CLDR if present
87
108
  const OpenUI5Support = getFeature("OpenUI5Support");
88
- if (!cldrObj && OpenUI5Support) {
89
- cldrObj = OpenUI5Support.getLocaleDataObject();
109
+ if (OpenUI5Support) {
110
+ const cldrContent = OpenUI5Support.getLocaleDataObject();
111
+ if (cldrContent) {
112
+ // only if openui5 actually returned valid content
113
+ setLocaleData(localeId, cldrContent);
114
+ return;
115
+ }
90
116
  }
91
117
 
92
- if (cldrObj) {
93
- // inlined from build or fetched independently
94
- registerModuleContent(`sap/ui/core/cldr/${localeId}.json`, cldrObj);
95
- } else if (url) {
96
- // fetch it
97
- const cldrContent = await fetchJsonOnce(url);
98
- registerModuleContent(`sap/ui/core/cldr/${localeId}.json`, cldrContent);
118
+ // fetch it
119
+ try {
120
+ const cldrContent = await _loadCldrOnce(localeId);
121
+ setLocaleData(localeId, cldrContent);
122
+ } catch (e) {
123
+ if (!reportedErrors.has(e.message)) {
124
+ reportedErrors.add(e.message);
125
+ console.error(e.message); /* eslint-disable-line */
126
+ }
99
127
  }
100
128
  };
101
129
 
102
- const registerCldr = (locale, url) => {
103
- cldrUrls[locale] = url;
104
- };
105
-
106
- const setCldrData = (locale, data) => {
107
- cldrData[locale] = data;
130
+ const registerLocaleDataLoader = (localeId, loader) => {
131
+ loaders.set(localeId, loader);
108
132
  };
109
133
 
110
- const getCldrData = locale => {
111
- return cldrData[locale];
112
- };
134
+ // register default loader for "en" from ui5 CDN (dev workflow without assets)
135
+ registerLocaleDataLoader("en", async runtimeLocaleId => {
136
+ return (await fetch(`https://ui5.sap.com/1.60.2/resources/sap/ui/core/cldr/en.json`)).json();
137
+ });
113
138
 
114
- const _registerMappingFunction = mappingFn => {
115
- cldrMappingFn = mappingFn;
116
- };
139
+ // When the language changes dynamically (the user calls setLanguage),
140
+ // re-fetch the required CDRD data.
141
+ attachLanguageChange(() => {
142
+ const locale = getLocale();
143
+ return fetchCldr(locale.getLanguage(), locale.getRegion(), locale.getScript());
144
+ });
117
145
 
118
146
  export {
147
+ registerLocaleDataLoader,
119
148
  fetchCldr,
120
- registerCldr,
121
- setCldrData,
122
- getCldrData,
123
- getModuleContent,
124
- _registerMappingFunction,
149
+ getLocaleData,
125
150
  };
@@ -1,9 +1,7 @@
1
- import { fetchJsonOnce, fetchTextOnce } from "../util/FetchHelper.js";
2
1
  import { DEFAULT_THEME } from "../generated/AssetParameters.js";
3
- import getFileExtension from "../util/getFileExtension.js";
4
2
 
5
- const themeURLs = new Map();
6
3
  const themeStyles = new Map();
4
+ const loaders = new Map();
7
5
  const registeredPackages = new Set();
8
6
  const registeredThemes = new Set();
9
7
 
@@ -15,29 +13,19 @@ const registeredThemes = new Set();
15
13
  * Example usage:
16
14
  * 1) Pass the CSS Vars as a string directly.
17
15
  * registerThemeProperties("my-package", "my_theme", ":root{--var1: red;}");
18
- * 2) Pass the CSS Vars as an object directly
19
- * registerThemeProperties("my-package", "my_theme", {"_": ":root{--var1: red;}"});
20
- * 3) Pass a URL to a CSS file, containing the CSS Vars. Will be fetched on demand, not upon registration.
21
- * registerThemeProperties("my-package", "my_theme", "http://url/to/my/theme.css");
22
- * 4) Pass a URL to a JSON file, containing the CSS Vars in its "_" property. Will be fetched on demand, not upon registration.
23
- * registerThemeProperties("my-package", "my_theme", "http://url/to/my/theme.json");
24
16
  *
25
17
  * @public
26
18
  * @param packageName - the NPM package for which CSS Vars are registered
27
19
  * @param themeName - the theme which the CSS Vars implement
28
- * @param style - can be one of four options: a string, an object with a "_" property, URL to a CSS file, or URL to a JSON file with a "_" property
20
+ * @param style - the style content directly
21
+ * @deprecated
29
22
  */
30
- const registerThemeProperties = (packageName, themeName, style) => {
31
- if (style._) {
32
- // JSON object like ({"_": ":root"})
33
- themeStyles.set(`${packageName}_${themeName}`, style._);
34
- } else if (style.includes(":root") || style === "") {
35
- // pure string, including empty string
36
- themeStyles.set(`${packageName}_${themeName}`, style);
37
- } else {
38
- // url for fetching
39
- themeURLs.set(`${packageName}_${themeName}`, style);
40
- }
23
+ const registerThemeProperties = (_packageName, _themeName, _style) => {
24
+ throw new Error("`registerThemeProperties` has been depracated. Use `registerThemePropertiesLoader` instead.");
25
+ };
26
+
27
+ const registerThemePropertiesLoader = (packageName, themeName, loader) => {
28
+ loaders.set(`${packageName}/${themeName}`, loader);
41
29
  registeredPackages.add(packageName);
42
30
  registeredThemes.add(themeName);
43
31
  };
@@ -54,23 +42,25 @@ const getThemeProperties = async (packageName, themeName) => {
54
42
  return themeStyles.get(`${packageName}_${DEFAULT_THEME}`);
55
43
  }
56
44
 
57
- const data = await fetchThemeProperties(packageName, themeName);
45
+ const loader = loaders.get(`${packageName}/${themeName}`);
46
+ if (!loader) {
47
+ // no themes for package
48
+ console.error(`Theme [${themeName}] not registered for package [${packageName}]`); /* eslint-disable-line */
49
+ return;
50
+ }
51
+ let data;
52
+ try {
53
+ data = await loader(themeName);
54
+ } catch (e) {
55
+ console.error(packageName, e.message); /* eslint-disable-line */
56
+ return;
57
+ }
58
58
  const themeProps = data._ || data;
59
59
 
60
60
  themeStyles.set(`${packageName}_${themeName}`, themeProps);
61
61
  return themeProps;
62
62
  };
63
63
 
64
- const fetchThemeProperties = async (packageName, themeName) => {
65
- const url = themeURLs.get(`${packageName}_${themeName}`);
66
-
67
- if (!url) {
68
- throw new Error(`You have to import the ${packageName}/dist/Assets.js module to switch to additional themes`);
69
- }
70
-
71
- return getFileExtension(url) === ".css" ? fetchTextOnce(url) : fetchJsonOnce(url);
72
- };
73
-
74
64
  const getRegisteredPackages = () => {
75
65
  return registeredPackages;
76
66
  };
@@ -80,6 +70,7 @@ const isThemeRegistered = theme => {
80
70
  };
81
71
 
82
72
  export {
73
+ registerThemePropertiesLoader,
83
74
  registerThemeProperties,
84
75
  getThemeProperties,
85
76
  getRegisteredPackages,