@ui5/webcomponents-base 0.0.0-323968e1b → 0.0.0-4180fe799

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 (449) hide show
  1. package/.eslintignore +4 -0
  2. package/CHANGELOG.md +196 -0
  3. package/README.md +26 -2
  4. package/bundle.esm.js +18 -12
  5. package/dist/AssetRegistry.js +8 -6
  6. package/dist/Boot.js +43 -0
  7. package/dist/CSP.js +59 -0
  8. package/dist/CustomElementsRegistry.js +39 -0
  9. package/dist/CustomElementsScope.js +108 -0
  10. package/dist/DOMObserver.js +65 -0
  11. package/dist/Device.js +62 -778
  12. package/dist/EventProvider.js +38 -26
  13. package/dist/FontFace.js +20 -56
  14. package/dist/InitialConfiguration.js +64 -17
  15. package/dist/Keys.js +248 -0
  16. package/dist/ManagedStyles.js +83 -0
  17. package/dist/MediaRange.js +109 -0
  18. package/dist/PropertiesFileFormat.js +95 -0
  19. package/dist/Render.js +175 -0
  20. package/dist/RenderQueue.js +41 -17
  21. package/dist/RenderScheduler.js +24 -145
  22. package/dist/StaticArea.js +1 -39
  23. package/dist/StaticAreaItem.js +65 -40
  24. package/dist/SystemCSSVars.js +10 -0
  25. package/dist/Theming.js +3 -44
  26. package/dist/UI5Element.js +483 -307
  27. package/dist/UI5ElementMetadata.js +190 -19
  28. package/dist/asset-registries/Icons.js +129 -14
  29. package/dist/asset-registries/Illustrations.js +30 -0
  30. package/dist/asset-registries/LocaleData.js +108 -50
  31. package/dist/asset-registries/Themes.js +35 -32
  32. package/dist/asset-registries/i18n.js +80 -34
  33. package/dist/assets-meta/IconCollectionsAlias.js +18 -0
  34. package/dist/config/AnimationMode.js +16 -2
  35. package/dist/config/CalendarType.js +7 -7
  36. package/dist/config/FormatSettings.js +5 -1
  37. package/dist/config/Language.js +62 -3
  38. package/dist/config/NoConflict.js +10 -3
  39. package/dist/config/Theme.js +21 -3
  40. package/dist/css/FontFace.css +45 -0
  41. package/dist/css/OverrideFontFace.css +32 -0
  42. package/dist/css/SystemCSSVars.css +17 -0
  43. package/dist/delegate/ItemNavigation.js +245 -172
  44. package/dist/delegate/ResizeHandler.js +78 -38
  45. package/dist/delegate/ScrollEnablement.js +122 -14
  46. package/dist/features/OpenUI5Support.js +125 -0
  47. package/dist/generated/AssetParameters.js +13 -0
  48. package/dist/generated/css/FontFace.css.js +5 -0
  49. package/dist/generated/css/OverrideFontFace.css.js +5 -0
  50. package/dist/generated/css/SystemCSSVars.css.js +5 -0
  51. package/dist/getSharedResource.js +30 -0
  52. package/dist/i18nBundle.js +62 -11
  53. package/dist/isLegacyBrowser.js +3 -0
  54. package/dist/{Locale.js → locale/Locale.js} +0 -10
  55. package/dist/locale/RTLAwareRegistry.js +14 -0
  56. package/dist/locale/applyDirection.js +17 -0
  57. package/dist/locale/directionChange.js +32 -0
  58. package/dist/locale/getEffectiveDir.js +28 -0
  59. package/dist/locale/getLocale.js +41 -0
  60. package/dist/locale/languageChange.js +22 -0
  61. package/dist/locale/nextFallbackLocale.js +28 -0
  62. package/{src/util → dist/locale}/normalizeLocale.js +8 -31
  63. package/dist/renderer/LitRenderer.js +26 -7
  64. package/dist/renderer/directives/style-map.js +72 -0
  65. package/dist/renderer/executeTemplate.js +17 -0
  66. package/dist/resources/bundle.esm.js +20 -106
  67. package/dist/resources/bundle.esm.js.map +1 -1
  68. package/dist/sap/base/Log.js +241 -0
  69. package/dist/sap/base/assert.js +8 -0
  70. package/dist/sap/base/security/URLListValidator.js +148 -0
  71. package/dist/sap/base/security/sanitizeHTML.js +16 -0
  72. package/dist/sap/base/util/now.js +7 -0
  73. package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +3585 -0
  74. package/dist/test-resources/assets/Themes.js +11 -5
  75. package/dist/test-resources/elements/Generic.js +1 -0
  76. package/dist/test-resources/elements/Parent.js +7 -2
  77. package/dist/test-resources/elements/WithStaticArea.js +77 -0
  78. package/dist/test-resources/pages/AllTestElements.html +5 -5
  79. package/dist/test-resources/pages/Configuration.html +0 -2
  80. package/dist/test-resources/pages/ConfigurationScript.html +1 -3
  81. package/dist/test-resources/pages/assets/messagebundle_de.properties +1 -0
  82. package/dist/test-resources/pages/assets/messagebundle_en.properties +1 -0
  83. package/dist/test-resources/pages/assets/messagebundle_es.properties +1 -0
  84. package/dist/test-resources/pages/assets/messagebundle_fr.properties +1 -0
  85. package/dist/test-resources/pages/i18n.html +33 -0
  86. package/dist/test-resources/specs/ConfigurationChange.spec.js +11 -9
  87. package/dist/test-resources/specs/ConfigurationScript.spec.js +25 -23
  88. package/dist/test-resources/specs/ConfigurationURL.spec.js +65 -17
  89. package/dist/test-resources/specs/CustomTheme.spec.js +9 -7
  90. package/dist/test-resources/specs/EventProvider.spec.js +63 -0
  91. package/dist/test-resources/specs/StaticArea.spec.js +78 -0
  92. package/dist/test-resources/specs/Theming.spec.js +12 -10
  93. package/dist/test-resources/specs/UI5ElementInvalidation.js +54 -70
  94. package/dist/test-resources/specs/UI5ElementLifecycle.js +19 -14
  95. package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +25 -51
  96. package/dist/test-resources/specs/UI5ElementMetadataExt.js +9 -7
  97. package/dist/test-resources/specs/UI5ElementPropertyValidation.js +7 -5
  98. package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +37 -35
  99. package/dist/test-resources/specs/UI5ElementShadowDOM.js +10 -8
  100. package/dist/test-resources/specs/UI5ElementSlots.js +10 -8
  101. package/dist/theming/CustomStyle.js +28 -7
  102. package/dist/theming/ThemeLoaded.js +22 -0
  103. package/dist/theming/applyTheme.js +75 -0
  104. package/dist/theming/getConstructableStyle.js +30 -0
  105. package/dist/theming/getEffectiveLinksHrefs.js +20 -0
  106. package/dist/theming/getEffectiveStyle.js +30 -0
  107. package/dist/theming/getStylesString.js +15 -0
  108. package/dist/theming/getThemeDesignerTheme.js +68 -0
  109. package/dist/theming/preloadLinks.js +23 -0
  110. package/dist/thirdparty/_merge.js +32 -0
  111. package/dist/thirdparty/isPlainObject.js +18 -0
  112. package/dist/thirdparty/merge.js +10 -0
  113. package/dist/types/CSSColor.js +9 -0
  114. package/{src/dates → dist/types}/CalendarType.js +2 -2
  115. package/dist/types/DataType.js +13 -1
  116. package/dist/types/Float.js +14 -0
  117. package/dist/types/Integer.js +4 -0
  118. package/dist/types/InvisibleMessageMode.js +30 -0
  119. package/dist/types/ItemNavigationBehavior.js +2 -7
  120. package/dist/types/NavigationMode.js +1 -0
  121. package/dist/types/PopupState.js +1 -1
  122. package/dist/types/ValueState.js +2 -1
  123. package/dist/updateShadowRoot.js +30 -0
  124. package/dist/util/AriaLabelHelper.js +41 -0
  125. package/dist/util/Caret.js +45 -0
  126. package/dist/util/ColorConversion.js +370 -0
  127. package/dist/util/FocusableElements.js +25 -8
  128. package/dist/util/HTMLSanitizer.js +7 -0
  129. package/dist/util/InvisibleMessage.js +58 -0
  130. package/dist/util/PopupUtils.js +93 -0
  131. package/dist/util/SlotsHelper.js +43 -0
  132. package/dist/util/StringHelper.js +17 -2
  133. package/dist/util/TabbableElements.js +5 -2
  134. package/dist/util/arraysAreEqual.js +15 -0
  135. package/dist/util/clamp.js +12 -0
  136. package/dist/util/createLinkInHead.js +19 -0
  137. package/dist/util/debounce.js +17 -0
  138. package/dist/util/detectNavigatorLanguage.js +3 -1
  139. package/dist/util/encodeCSS.js +24 -0
  140. package/dist/util/findNodeOwner.js +35 -0
  141. package/dist/util/getActiveElement.js +11 -0
  142. package/dist/util/getClassCopy.js +10 -0
  143. package/dist/util/getEffectiveContentDensity.js +5 -0
  144. package/dist/util/getFileExtension.js +21 -0
  145. package/dist/util/getSingletonElementInstance.js +13 -0
  146. package/dist/util/isElementInView.js +15 -0
  147. package/dist/util/isNodeHidden.js +1 -5
  148. package/dist/util/isNodeTabbable.js +4 -4
  149. package/dist/util/isValidPropertyName.js +11 -2
  150. package/dist/util/setToArray.js +10 -0
  151. package/hash.txt +1 -0
  152. package/index.js +1 -1
  153. package/lib/generate-asset-parameters/index.js +21 -0
  154. package/lib/generate-styles/index.js +18 -0
  155. package/package-scripts.js +41 -18
  156. package/package.json +19 -14
  157. package/src/AssetRegistry.js +8 -6
  158. package/src/Boot.js +43 -0
  159. package/src/CSP.js +59 -0
  160. package/src/CustomElementsRegistry.js +39 -0
  161. package/src/CustomElementsScope.js +108 -0
  162. package/src/DOMObserver.js +65 -0
  163. package/src/Device.js +62 -778
  164. package/src/EventProvider.js +38 -26
  165. package/src/FontFace.js +20 -56
  166. package/src/InitialConfiguration.js +64 -17
  167. package/src/Keys.js +248 -0
  168. package/src/ManagedStyles.js +83 -0
  169. package/src/MediaRange.js +109 -0
  170. package/src/PropertiesFileFormat.js +95 -0
  171. package/src/Render.js +175 -0
  172. package/src/RenderQueue.js +41 -17
  173. package/src/RenderScheduler.js +24 -145
  174. package/src/StaticArea.js +1 -39
  175. package/src/StaticAreaItem.js +65 -40
  176. package/src/SystemCSSVars.js +10 -0
  177. package/src/Theming.js +3 -44
  178. package/src/UI5Element.js +483 -307
  179. package/src/UI5ElementMetadata.js +190 -19
  180. package/src/asset-registries/Icons.js +129 -14
  181. package/src/asset-registries/Illustrations.js +30 -0
  182. package/src/asset-registries/LocaleData.js +108 -50
  183. package/src/asset-registries/Themes.js +35 -32
  184. package/src/asset-registries/i18n.js +80 -34
  185. package/src/assets-meta/IconCollectionsAlias.js +18 -0
  186. package/src/config/AnimationMode.js +16 -2
  187. package/src/config/CalendarType.js +7 -7
  188. package/src/config/FormatSettings.js +5 -1
  189. package/src/config/Language.js +62 -3
  190. package/src/config/NoConflict.js +10 -3
  191. package/src/config/Theme.js +21 -3
  192. package/src/css/FontFace.css +45 -0
  193. package/src/css/OverrideFontFace.css +32 -0
  194. package/src/css/SystemCSSVars.css +17 -0
  195. package/src/delegate/ItemNavigation.js +245 -172
  196. package/src/delegate/ResizeHandler.js +78 -38
  197. package/src/delegate/ScrollEnablement.js +122 -14
  198. package/src/features/OpenUI5Support.js +125 -0
  199. package/src/getSharedResource.js +30 -0
  200. package/src/i18nBundle.js +62 -11
  201. package/src/isLegacyBrowser.js +3 -0
  202. package/src/{Locale.js → locale/Locale.js} +0 -10
  203. package/src/locale/RTLAwareRegistry.js +14 -0
  204. package/src/locale/applyDirection.js +17 -0
  205. package/src/locale/directionChange.js +32 -0
  206. package/src/locale/getEffectiveDir.js +28 -0
  207. package/src/locale/getLocale.js +41 -0
  208. package/src/locale/languageChange.js +22 -0
  209. package/src/locale/nextFallbackLocale.js +28 -0
  210. package/{dist/util → src/locale}/normalizeLocale.js +8 -31
  211. package/src/renderer/LitRenderer.js +26 -7
  212. package/src/renderer/directives/style-map.js +72 -0
  213. package/src/renderer/executeTemplate.js +17 -0
  214. package/src/theming/CustomStyle.js +28 -7
  215. package/src/theming/ThemeLoaded.js +22 -0
  216. package/src/theming/applyTheme.js +75 -0
  217. package/src/theming/getConstructableStyle.js +30 -0
  218. package/src/theming/getEffectiveLinksHrefs.js +20 -0
  219. package/src/theming/getEffectiveStyle.js +30 -0
  220. package/src/theming/getStylesString.js +15 -0
  221. package/src/theming/getThemeDesignerTheme.js +68 -0
  222. package/src/theming/preloadLinks.js +23 -0
  223. package/src/thirdparty/_merge.js +32 -0
  224. package/src/thirdparty/isPlainObject.js +18 -0
  225. package/src/thirdparty/merge.js +10 -0
  226. package/src/types/CSSColor.js +9 -0
  227. package/{dist/dates → src/types}/CalendarType.js +2 -2
  228. package/src/types/DataType.js +13 -1
  229. package/src/types/Float.js +14 -0
  230. package/src/types/Integer.js +4 -0
  231. package/src/types/InvisibleMessageMode.js +30 -0
  232. package/src/types/ItemNavigationBehavior.js +2 -7
  233. package/src/types/NavigationMode.js +1 -0
  234. package/src/types/PopupState.js +1 -1
  235. package/src/types/ValueState.js +2 -1
  236. package/src/updateShadowRoot.js +30 -0
  237. package/src/util/AriaLabelHelper.js +41 -0
  238. package/src/util/Caret.js +45 -0
  239. package/src/util/ColorConversion.js +370 -0
  240. package/src/util/FocusableElements.js +25 -8
  241. package/src/util/HTMLSanitizer.js +7 -0
  242. package/src/util/InvisibleMessage.js +58 -0
  243. package/src/util/PopupUtils.js +93 -0
  244. package/src/util/SlotsHelper.js +43 -0
  245. package/src/util/StringHelper.js +17 -2
  246. package/src/util/TabbableElements.js +5 -2
  247. package/src/util/arraysAreEqual.js +15 -0
  248. package/src/util/clamp.js +12 -0
  249. package/src/util/createLinkInHead.js +19 -0
  250. package/src/util/debounce.js +17 -0
  251. package/src/util/detectNavigatorLanguage.js +3 -1
  252. package/src/util/encodeCSS.js +24 -0
  253. package/src/util/findNodeOwner.js +35 -0
  254. package/src/util/getActiveElement.js +11 -0
  255. package/src/util/getClassCopy.js +10 -0
  256. package/src/util/getEffectiveContentDensity.js +5 -0
  257. package/src/util/getFileExtension.js +21 -0
  258. package/src/util/getSingletonElementInstance.js +13 -0
  259. package/src/util/isElementInView.js +15 -0
  260. package/src/util/isNodeHidden.js +1 -5
  261. package/src/util/isNodeTabbable.js +4 -4
  262. package/src/util/isValidPropertyName.js +11 -2
  263. package/src/util/setToArray.js +10 -0
  264. package/used-modules.txt +7 -0
  265. package/bundle.es5.js +0 -28
  266. package/dist/Assets.js +0 -2
  267. package/dist/CSS.js +0 -48
  268. package/dist/FormatSettings.js +0 -31
  269. package/dist/LocaleProvider.js +0 -34
  270. package/dist/ResourceLoaderOverrides.js +0 -38
  271. package/dist/SVGIconRegistry.js +0 -54
  272. package/dist/boot.js +0 -25
  273. package/dist/compatibility/DOMObserver.js +0 -62
  274. package/dist/compatibility/patchNodeValue.js +0 -24
  275. package/dist/compatibility/whenPolyfillLoaded.js +0 -26
  276. package/dist/dates/CalendarDate.js +0 -203
  277. package/dist/dates/CalendarUtils.js +0 -99
  278. package/dist/delegate/CustomResize.js +0 -78
  279. package/dist/delegate/NativeResize.js +0 -44
  280. package/dist/events/PseudoEvents.js +0 -58
  281. package/dist/features/browsersupport/Edge.js +0 -6
  282. package/dist/features/browsersupport/IE11.js +0 -41
  283. package/dist/features/calendar/Buddhist.js +0 -1
  284. package/dist/features/calendar/Islamic.js +0 -1
  285. package/dist/features/calendar/Japanese.js +0 -1
  286. package/dist/features/calendar/Persian.js +0 -1
  287. package/dist/generated/assets/cldr/sap/ui/core/cldr/ar.json +0 -5598
  288. package/dist/generated/assets/cldr/sap/ui/core/cldr/ar_EG.json +0 -5598
  289. package/dist/generated/assets/cldr/sap/ui/core/cldr/ar_SA.json +0 -5598
  290. package/dist/generated/assets/cldr/sap/ui/core/cldr/bg.json +0 -4789
  291. package/dist/generated/assets/cldr/sap/ui/core/cldr/ca.json +0 -4801
  292. package/dist/generated/assets/cldr/sap/ui/core/cldr/cs.json +0 -5245
  293. package/dist/generated/assets/cldr/sap/ui/core/cldr/da.json +0 -4696
  294. package/dist/generated/assets/cldr/sap/ui/core/cldr/de.json +0 -4797
  295. package/dist/generated/assets/cldr/sap/ui/core/cldr/de_AT.json +0 -4798
  296. package/dist/generated/assets/cldr/sap/ui/core/cldr/de_CH.json +0 -4796
  297. package/dist/generated/assets/cldr/sap/ui/core/cldr/el.json +0 -4694
  298. package/dist/generated/assets/cldr/sap/ui/core/cldr/el_CY.json +0 -4694
  299. package/dist/generated/assets/cldr/sap/ui/core/cldr/en.json +0 -4777
  300. package/dist/generated/assets/cldr/sap/ui/core/cldr/en_AU.json +0 -4769
  301. package/dist/generated/assets/cldr/sap/ui/core/cldr/en_GB.json +0 -4778
  302. package/dist/generated/assets/cldr/sap/ui/core/cldr/en_HK.json +0 -4784
  303. package/dist/generated/assets/cldr/sap/ui/core/cldr/en_IE.json +0 -4778
  304. package/dist/generated/assets/cldr/sap/ui/core/cldr/en_IN.json +0 -4779
  305. package/dist/generated/assets/cldr/sap/ui/core/cldr/en_NZ.json +0 -4778
  306. package/dist/generated/assets/cldr/sap/ui/core/cldr/en_PG.json +0 -4779
  307. package/dist/generated/assets/cldr/sap/ui/core/cldr/en_SG.json +0 -4780
  308. package/dist/generated/assets/cldr/sap/ui/core/cldr/en_ZA.json +0 -4779
  309. package/dist/generated/assets/cldr/sap/ui/core/cldr/es.json +0 -4719
  310. package/dist/generated/assets/cldr/sap/ui/core/cldr/es_AR.json +0 -4721
  311. package/dist/generated/assets/cldr/sap/ui/core/cldr/es_BO.json +0 -4720
  312. package/dist/generated/assets/cldr/sap/ui/core/cldr/es_CL.json +0 -4721
  313. package/dist/generated/assets/cldr/sap/ui/core/cldr/es_CO.json +0 -4721
  314. package/dist/generated/assets/cldr/sap/ui/core/cldr/es_MX.json +0 -4722
  315. package/dist/generated/assets/cldr/sap/ui/core/cldr/es_PE.json +0 -4720
  316. package/dist/generated/assets/cldr/sap/ui/core/cldr/es_UY.json +0 -4722
  317. package/dist/generated/assets/cldr/sap/ui/core/cldr/es_VE.json +0 -4721
  318. package/dist/generated/assets/cldr/sap/ui/core/cldr/et.json +0 -4776
  319. package/dist/generated/assets/cldr/sap/ui/core/cldr/fa.json +0 -4704
  320. package/dist/generated/assets/cldr/sap/ui/core/cldr/fi.json +0 -4816
  321. package/dist/generated/assets/cldr/sap/ui/core/cldr/fr.json +0 -4788
  322. package/dist/generated/assets/cldr/sap/ui/core/cldr/fr_BE.json +0 -4788
  323. package/dist/generated/assets/cldr/sap/ui/core/cldr/fr_CA.json +0 -4782
  324. package/dist/generated/assets/cldr/sap/ui/core/cldr/fr_CH.json +0 -4806
  325. package/dist/generated/assets/cldr/sap/ui/core/cldr/fr_LU.json +0 -4788
  326. package/dist/generated/assets/cldr/sap/ui/core/cldr/he.json +0 -5133
  327. package/dist/generated/assets/cldr/sap/ui/core/cldr/hi.json +0 -4680
  328. package/dist/generated/assets/cldr/sap/ui/core/cldr/hr.json +0 -4910
  329. package/dist/generated/assets/cldr/sap/ui/core/cldr/hu.json +0 -4664
  330. package/dist/generated/assets/cldr/sap/ui/core/cldr/id.json +0 -4500
  331. package/dist/generated/assets/cldr/sap/ui/core/cldr/it.json +0 -4757
  332. package/dist/generated/assets/cldr/sap/ui/core/cldr/it_CH.json +0 -4757
  333. package/dist/generated/assets/cldr/sap/ui/core/cldr/ja.json +0 -4599
  334. package/dist/generated/assets/cldr/sap/ui/core/cldr/kk.json +0 -4537
  335. package/dist/generated/assets/cldr/sap/ui/core/cldr/ko.json +0 -4574
  336. package/dist/generated/assets/cldr/sap/ui/core/cldr/lt.json +0 -5234
  337. package/dist/generated/assets/cldr/sap/ui/core/cldr/lv.json +0 -4902
  338. package/dist/generated/assets/cldr/sap/ui/core/cldr/ms.json +0 -4352
  339. package/dist/generated/assets/cldr/sap/ui/core/cldr/nb.json +0 -4784
  340. package/dist/generated/assets/cldr/sap/ui/core/cldr/nl.json +0 -4790
  341. package/dist/generated/assets/cldr/sap/ui/core/cldr/nl_BE.json +0 -4790
  342. package/dist/generated/assets/cldr/sap/ui/core/cldr/pl.json +0 -5223
  343. package/dist/generated/assets/cldr/sap/ui/core/cldr/pt.json +0 -4703
  344. package/dist/generated/assets/cldr/sap/ui/core/cldr/pt_PT.json +0 -4753
  345. package/dist/generated/assets/cldr/sap/ui/core/cldr/ro.json +0 -4881
  346. package/dist/generated/assets/cldr/sap/ui/core/cldr/ru.json +0 -5157
  347. package/dist/generated/assets/cldr/sap/ui/core/cldr/ru_UA.json +0 -5157
  348. package/dist/generated/assets/cldr/sap/ui/core/cldr/sk.json +0 -5125
  349. package/dist/generated/assets/cldr/sap/ui/core/cldr/sl.json +0 -5105
  350. package/dist/generated/assets/cldr/sap/ui/core/cldr/sr.json +0 -4908
  351. package/dist/generated/assets/cldr/sap/ui/core/cldr/sv.json +0 -4818
  352. package/dist/generated/assets/cldr/sap/ui/core/cldr/th.json +0 -4633
  353. package/dist/generated/assets/cldr/sap/ui/core/cldr/tr.json +0 -4791
  354. package/dist/generated/assets/cldr/sap/ui/core/cldr/uk.json +0 -5126
  355. package/dist/generated/assets/cldr/sap/ui/core/cldr/vi.json +0 -4510
  356. package/dist/generated/assets/cldr/sap/ui/core/cldr/zh_CN.json +0 -4469
  357. package/dist/generated/assets/cldr/sap/ui/core/cldr/zh_HK.json +0 -4479
  358. package/dist/generated/assets/cldr/sap/ui/core/cldr/zh_SG.json +0 -4479
  359. package/dist/generated/assets/cldr/sap/ui/core/cldr/zh_TW.json +0 -4565
  360. package/dist/json-imports/LocaleData.js +0 -171
  361. package/dist/renderer/ifDefined.js +0 -21
  362. package/dist/resources/bundle.es5.js +0 -212
  363. package/dist/resources/bundle.es5.js.map +0 -1
  364. package/dist/shims/Core-shim.js +0 -52
  365. package/dist/shims/jquery-shim.js +0 -89
  366. package/dist/theming/StyleInjection.js +0 -67
  367. package/dist/thirdparty/Array.from.js +0 -16
  368. package/dist/thirdparty/Array.prototype.fill.js +0 -44
  369. package/dist/thirdparty/Array.prototype.find.js +0 -46
  370. package/dist/thirdparty/Array.prototype.includes.js +0 -51
  371. package/dist/thirdparty/Element.prototype.closest.js +0 -11
  372. package/dist/thirdparty/Element.prototype.matches.js +0 -6
  373. package/dist/thirdparty/Map.prototype.keys.js +0 -9
  374. package/dist/thirdparty/Number.isInteger.js +0 -5
  375. package/dist/thirdparty/Number.isNaN.js +0 -1
  376. package/dist/thirdparty/Number.parseInt.js +0 -1
  377. package/dist/thirdparty/Object.assign.js +0 -31
  378. package/dist/thirdparty/Object.entries.js +0 -11
  379. package/dist/thirdparty/Symbol.js +0 -2
  380. package/dist/thirdparty/WeakSet.js +0 -27
  381. package/dist/thirdparty/events-polyfills.js +0 -89
  382. package/dist/thirdparty/fetch.js +0 -1
  383. package/dist/thirdparty/template.js +0 -600
  384. package/dist/util/CSSTransformUtils.js +0 -90
  385. package/dist/webcomponentsjs/LICENSE.md +0 -19
  386. package/dist/webcomponentsjs/README.md +0 -229
  387. package/dist/webcomponentsjs/bundles/webcomponents-ce.js +0 -63
  388. package/dist/webcomponentsjs/bundles/webcomponents-ce.js.map +0 -1
  389. package/dist/webcomponentsjs/bundles/webcomponents-sd-ce-pf.js +0 -297
  390. package/dist/webcomponentsjs/bundles/webcomponents-sd-ce-pf.js.map +0 -1
  391. package/dist/webcomponentsjs/bundles/webcomponents-sd-ce.js +0 -208
  392. package/dist/webcomponentsjs/bundles/webcomponents-sd-ce.js.map +0 -1
  393. package/dist/webcomponentsjs/bundles/webcomponents-sd.js +0 -166
  394. package/dist/webcomponentsjs/bundles/webcomponents-sd.js.map +0 -1
  395. package/dist/webcomponentsjs/custom-elements-es5-adapter.js +0 -15
  396. package/dist/webcomponentsjs/package.json +0 -46
  397. package/dist/webcomponentsjs/src/entrypoints/custom-elements-es5-adapter-index.js +0 -16
  398. package/dist/webcomponentsjs/src/entrypoints/webcomponents-bundle-index.js +0 -53
  399. package/dist/webcomponentsjs/src/entrypoints/webcomponents-ce-index.js +0 -17
  400. package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-ce-index.js +0 -19
  401. package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-ce-pf-index.js +0 -28
  402. package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-index.js +0 -18
  403. package/dist/webcomponentsjs/webcomponents-bundle.js +0 -298
  404. package/dist/webcomponentsjs/webcomponents-bundle.js.map +0 -1
  405. package/dist/webcomponentsjs/webcomponents-loader.js +0 -185
  406. package/src/Assets.js +0 -2
  407. package/src/CSS.js +0 -48
  408. package/src/FormatSettings.js +0 -31
  409. package/src/LocaleProvider.js +0 -34
  410. package/src/ResourceLoaderOverrides.js +0 -38
  411. package/src/SVGIconRegistry.js +0 -54
  412. package/src/boot.js +0 -25
  413. package/src/compatibility/DOMObserver.js +0 -62
  414. package/src/compatibility/patchNodeValue.js +0 -24
  415. package/src/compatibility/whenPolyfillLoaded.js +0 -26
  416. package/src/dates/CalendarDate.js +0 -203
  417. package/src/dates/CalendarUtils.js +0 -99
  418. package/src/delegate/CustomResize.js +0 -78
  419. package/src/delegate/NativeResize.js +0 -44
  420. package/src/events/PseudoEvents.js +0 -58
  421. package/src/features/browsersupport/Edge.js +0 -6
  422. package/src/features/browsersupport/IE11.js +0 -41
  423. package/src/features/calendar/Buddhist.js +0 -1
  424. package/src/features/calendar/Islamic.js +0 -1
  425. package/src/features/calendar/Japanese.js +0 -1
  426. package/src/features/calendar/Persian.js +0 -1
  427. package/src/json-imports/LocaleData.js +0 -171
  428. package/src/renderer/ifDefined.js +0 -21
  429. package/src/shims/Core-shim.js +0 -52
  430. package/src/shims/jquery-shim.js +0 -89
  431. package/src/theming/StyleInjection.js +0 -67
  432. package/src/thirdparty/Array.from.js +0 -16
  433. package/src/thirdparty/Array.prototype.fill.js +0 -44
  434. package/src/thirdparty/Array.prototype.find.js +0 -46
  435. package/src/thirdparty/Array.prototype.includes.js +0 -51
  436. package/src/thirdparty/Element.prototype.closest.js +0 -11
  437. package/src/thirdparty/Element.prototype.matches.js +0 -6
  438. package/src/thirdparty/Map.prototype.keys.js +0 -9
  439. package/src/thirdparty/Number.isInteger.js +0 -5
  440. package/src/thirdparty/Number.isNaN.js +0 -1
  441. package/src/thirdparty/Number.parseInt.js +0 -1
  442. package/src/thirdparty/Object.assign.js +0 -31
  443. package/src/thirdparty/Object.entries.js +0 -11
  444. package/src/thirdparty/Symbol.js +0 -2
  445. package/src/thirdparty/WeakSet.js +0 -27
  446. package/src/thirdparty/events-polyfills.js +0 -89
  447. package/src/thirdparty/fetch.js +0 -1
  448. package/src/thirdparty/template.js +0 -600
  449. package/src/util/CSSTransformUtils.js +0 -90
@@ -1,26 +1,50 @@
1
- import merge from "@ui5/webcomponents-utils/dist/sap/base/util/merge.js";
2
- import boot from "./boot.js";
3
- import { skipOriginalEvent } from "./config/NoConflict.js";
4
- import DOMObserver from "./compatibility/DOMObserver.js";
1
+ import merge from "./thirdparty/merge.js";
2
+ import { boot } from "./Boot.js";
5
3
  import UI5ElementMetadata from "./UI5ElementMetadata.js";
4
+ import EventProvider from "./EventProvider.js";
5
+ import getSingletonElementInstance from "./util/getSingletonElementInstance.js";
6
6
  import StaticAreaItem from "./StaticAreaItem.js";
7
- import Integer from "./types/Integer.js";
8
- import RenderScheduler from "./RenderScheduler.js";
9
- import { getConstructableStyle, createHeadStyle } from "./CSS.js";
10
- import { getEffectiveStyle } from "./Theming.js";
7
+ import updateShadowRoot from "./updateShadowRoot.js";
8
+ import { renderDeferred, renderImmediately, cancelRender } from "./Render.js";
9
+ import { registerTag, isTagRegistered, recordTagRegistrationFailure } from "./CustomElementsRegistry.js";
10
+ import { observeDOMNode, unobserveDOMNode } from "./DOMObserver.js";
11
+ import { skipOriginalEvent } from "./config/NoConflict.js";
12
+ import getEffectiveDir from "./locale/getEffectiveDir.js";
13
+ import DataType from "./types/DataType.js";
11
14
  import { kebabToCamelCase, camelToKebabCase } from "./util/StringHelper.js";
12
15
  import isValidPropertyName from "./util/isValidPropertyName.js";
16
+ import isDescendantOf from "./util/isDescendantOf.js";
17
+ import { isSlot, getSlotName, getSlottedElementsList } from "./util/SlotsHelper.js";
18
+ import arraysAreEqual from "./util/arraysAreEqual.js";
19
+ import getClassCopy from "./util/getClassCopy.js";
20
+ import { markAsRtlAware } from "./locale/RTLAwareRegistry.js";
21
+ import preloadLinks from "./theming/preloadLinks.js";
13
22
 
14
- const metadata = {
15
- events: {
16
- _propertyChange: {},
17
- },
18
- };
19
-
20
- const DefinitionsSet = new Set();
21
- const IDMap = new Map();
23
+ let autoId = 0;
22
24
 
23
25
  const elementTimeouts = new Map();
26
+ const uniqueDependenciesCache = new Map();
27
+
28
+ /**
29
+ * Triggers re-rendering of a UI5Element instance due to state change.
30
+ *
31
+ * @param changeInfo An object with information about the change that caused invalidation.
32
+ * @private
33
+ */
34
+ function _invalidate(changeInfo) {
35
+ // Invalidation should be suppressed: 1) before the component is rendered for the first time 2) and during the execution of onBeforeRendering
36
+ // This is necessary not only as an optimization, but also to avoid infinite loops on invalidation between children and parents (when invalidateOnChildChange is used)
37
+ if (this._suppressInvalidation) {
38
+ return;
39
+ }
40
+
41
+ // Call the onInvalidation hook
42
+ this.onInvalidation(changeInfo);
43
+
44
+ this._changedState.push(changeInfo);
45
+ renderDeferred(this);
46
+ this._eventProvider.fireEvent("invalidate", { ...changeInfo, target: this });
47
+ }
24
48
 
25
49
  /**
26
50
  * Base class for all UI5 Web Components
@@ -35,51 +59,40 @@ const elementTimeouts = new Map();
35
59
  class UI5Element extends HTMLElement {
36
60
  constructor() {
37
61
  super();
38
- this._generateId();
39
- this._initializeState();
40
- this._upgradeAllProperties();
41
- this._initializeContainers();
42
62
 
63
+ this._changedState = []; // Filled on each invalidation, cleared on re-render (used for debugging)
64
+ this._suppressInvalidation = true; // A flag telling whether all invalidations should be ignored. Initialized with "true" because a UI5Element can not be invalidated until it is rendered for the first time
65
+ this._inDOM = false; // A flag telling whether the UI5Element is currently in the DOM tree of the document or not
66
+ this._fullyConnected = false; // A flag telling whether the UI5Element's onEnterDOM hook was called (since it's possible to have the element removed from DOM before that)
67
+ this._childChangeListeners = new Map(); // used to store lazy listeners per slot for the child change event of every child inside that slot
68
+ this._slotChangeListeners = new Map(); // used to store lazy listeners per slot for the slotchange event of all slot children inside that slot
69
+ this._eventProvider = new EventProvider(); // used by parent components for listening to changes to child components
43
70
  let deferredResolve;
44
71
  this._domRefReadyPromise = new Promise(resolve => {
45
72
  deferredResolve = resolve;
46
73
  });
47
74
  this._domRefReadyPromise._deferredResolve = deferredResolve;
48
75
 
49
- this._monitoredChildProps = new Map();
50
- }
76
+ this._initializeState();
77
+ this._upgradeAllProperties();
51
78
 
52
- /**
53
- * @private
54
- */
55
- _generateId() {
56
- this._id = this.constructor._nextID();
79
+ if (this.constructor._needsShadowDOM()) {
80
+ this.attachShadow({ mode: "open" });
81
+ }
57
82
  }
58
83
 
59
84
  /**
60
- * @private
85
+ * Returns a unique ID for this UI5 Element
86
+ *
87
+ * @deprecated - This property is not guaranteed in future releases
88
+ * @protected
61
89
  */
62
- _initializeContainers() {
63
- // Init Shadow Root
64
- if (this.constructor._needsShadowDOM()) {
65
- this.attachShadow({ mode: "open" });
66
-
67
- // IE11, Edge
68
- if (window.ShadyDOM) {
69
- createHeadStyle(this.constructor);
70
- }
71
-
72
- // Chrome
73
- if (document.adoptedStyleSheets) {
74
- const style = getConstructableStyle(this.constructor);
75
- this.shadowRoot.adoptedStyleSheets = [style];
76
- }
90
+ get _id() {
91
+ if (!this.__id) {
92
+ this.__id = `ui5wc_${++autoId}`;
77
93
  }
78
94
 
79
- // Init StaticAreaItem only if needed
80
- if (this.constructor._needsStaticArea()) {
81
- this.staticAreaItem = new StaticAreaItem(this);
82
- }
95
+ return this.__id;
83
96
  }
84
97
 
85
98
  /**
@@ -87,22 +100,27 @@ class UI5Element extends HTMLElement {
87
100
  * @private
88
101
  */
89
102
  async connectedCallback() {
90
- // Render the Shadow DOM
91
- if (this.constructor._needsShadowDOM()) {
103
+ this.setAttribute(this.constructor.getMetadata().getPureTag(), "");
104
+
105
+ const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
106
+
107
+ this._inDOM = true;
108
+
109
+ if (slotsAreManaged) {
92
110
  // always register the observer before yielding control to the main thread (await)
93
111
  this._startObservingDOMChildren();
94
-
95
112
  await this._processChildren();
96
- await RenderScheduler.renderImmediately(this);
97
- this._domRefReadyPromise._deferredResolve();
98
- if (typeof this.onEnterDOM === "function") {
99
- this.onEnterDOM();
100
- }
101
113
  }
102
114
 
103
- // Render Fragment if neccessary
104
- if (this.constructor._needsStaticArea()) {
105
- this.staticAreaItem._updateFragment(this);
115
+ if (!this._inDOM) { // Component removed from DOM while _processChildren was running
116
+ return;
117
+ }
118
+
119
+ renderImmediately(this);
120
+ this._domRefReadyPromise._deferredResolve();
121
+ this._fullyConnected = true;
122
+ if (typeof this.onEnterDOM === "function") {
123
+ this.onEnterDOM();
106
124
  }
107
125
  }
108
126
 
@@ -111,16 +129,26 @@ class UI5Element extends HTMLElement {
111
129
  * @private
112
130
  */
113
131
  disconnectedCallback() {
114
- if (this.constructor._needsShadowDOM()) {
132
+ const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
133
+
134
+ this._inDOM = false;
135
+
136
+ if (slotsAreManaged) {
115
137
  this._stopObservingDOMChildren();
138
+ }
139
+
140
+ if (this._fullyConnected) {
116
141
  if (typeof this.onExitDOM === "function") {
117
142
  this.onExitDOM();
118
143
  }
144
+ this._fullyConnected = false;
119
145
  }
120
146
 
121
- if (this.constructor._needsStaticArea()) {
122
- this.staticAreaItem._removeFragmentFromStaticArea();
147
+ if (this.staticAreaItem && this.staticAreaItem.parentElement) {
148
+ this.staticAreaItem.parentElement.removeChild(this.staticAreaItem);
123
149
  }
150
+
151
+ cancelRender(this);
124
152
  }
125
153
 
126
154
  /**
@@ -131,19 +159,21 @@ class UI5Element extends HTMLElement {
131
159
  if (!shouldObserveChildren) {
132
160
  return;
133
161
  }
162
+
163
+ const canSlotText = this.constructor.getMetadata().canSlotText();
134
164
  const mutationObserverOptions = {
135
165
  childList: true,
136
- subtree: true,
137
- characterData: true,
166
+ subtree: canSlotText,
167
+ characterData: canSlotText,
138
168
  };
139
- DOMObserver.observeDOMNode(this, this._processChildren.bind(this), mutationObserverOptions);
169
+ observeDOMNode(this, this._processChildren.bind(this), mutationObserverOptions);
140
170
  }
141
171
 
142
172
  /**
143
173
  * @private
144
174
  */
145
175
  _stopObservingDOMChildren() {
146
- DOMObserver.unobserveDOMNode(this);
176
+ unobserveDOMNode(this);
147
177
  }
148
178
 
149
179
  /**
@@ -162,12 +192,18 @@ class UI5Element extends HTMLElement {
162
192
  */
163
193
  async _updateSlots() {
164
194
  const slotsMap = this.constructor.getMetadata().getSlots();
165
- const canSlotText = slotsMap.default && slotsMap.default.type === Node;
195
+ const canSlotText = this.constructor.getMetadata().canSlotText();
166
196
  const domChildren = Array.from(canSlotText ? this.childNodes : this.children);
167
197
 
168
- // Init the _state object based on the supported slots
198
+ const slotsCachedContentMap = new Map(); // Store here the content of each slot before the mutation occurred
199
+ const propertyNameToSlotMap = new Map(); // Used for reverse lookup to determine to which slot the property name corresponds
200
+
201
+ // Init the _state object based on the supported slots and store the previous values
169
202
  for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line
170
- this._clearSlot(slotName);
203
+ const propertyName = slotData.propertyName || slotName;
204
+ propertyNameToSlotMap.set(propertyName, slotName);
205
+ slotsCachedContentMap.set(propertyName, [...this._state[propertyName]]);
206
+ this._clearSlot(slotName, slotData);
171
207
  }
172
208
 
173
209
  const autoIncrementMap = new Map();
@@ -175,7 +211,7 @@ class UI5Element extends HTMLElement {
175
211
 
176
212
  const allChildrenUpgraded = domChildren.map(async (child, idx) => {
177
213
  // Determine the type of the child (mainly by the slot attribute)
178
- const slotName = this.constructor._getSlotName(child);
214
+ const slotName = getSlotName(child);
179
215
  const slotData = slotsMap[slotName];
180
216
 
181
217
  // Check if the slotName is supported
@@ -187,9 +223,9 @@ class UI5Element extends HTMLElement {
187
223
 
188
224
  // For children that need individual slots, calculate them
189
225
  if (slotData.individualSlots) {
190
- const nextId = (autoIncrementMap.get(slotName) || 0) + 1;
191
- autoIncrementMap.set(slotName, nextId);
192
- child._individualSlot = `${slotName}-${nextId}`;
226
+ const nextIndex = (autoIncrementMap.get(slotName) || 0) + 1;
227
+ autoIncrementMap.set(slotName, nextIndex);
228
+ child._individualSlot = `${slotName}-${nextIndex}`;
193
229
  }
194
230
 
195
231
  // Await for not-yet-defined custom elements
@@ -213,8 +249,14 @@ class UI5Element extends HTMLElement {
213
249
 
214
250
  child = this.constructor.getMetadata().constructor.validateSlotValue(child, slotData);
215
251
 
216
- if (child.isUI5Element) {
217
- this._attachChildPropertyUpdated(child, slotData);
252
+ // Listen for any invalidation on the child if invalidateOnChildChange is true or an object (ignore when false or not set)
253
+ if (child.isUI5Element && slotData.invalidateOnChildChange) {
254
+ child.attachInvalidate(this._getChildChangeListener(slotName));
255
+ }
256
+
257
+ // Listen for the slotchange event if the child is a slot itself
258
+ if (isSlot(child)) {
259
+ this._attachSlotChange(child, slotName);
218
260
  }
219
261
 
220
262
  const propertyName = slotData.propertyName || slotName;
@@ -230,33 +272,96 @@ class UI5Element extends HTMLElement {
230
272
 
231
273
  // Distribute the child in the _state object, keeping the Light DOM order,
232
274
  // not the order elements are defined.
233
- slottedChildrenMap.forEach((children, slot) => {
234
- this._state[slot] = children.sort((a, b) => a.idx - b.idx).map(_ => _.child);
275
+ slottedChildrenMap.forEach((children, propertyName) => {
276
+ this._state[propertyName] = children.sort((a, b) => a.idx - b.idx).map(_ => _.child);
235
277
  });
236
- this._invalidate();
278
+
279
+ // Compare the content of each slot with the cached values and invalidate for the ones that changed
280
+ let invalidated = false;
281
+ for (const [slotName, slotData] of Object.entries(slotsMap)) { // eslint-disable-line
282
+ const propertyName = slotData.propertyName || slotName;
283
+ if (!arraysAreEqual(slotsCachedContentMap.get(propertyName), this._state[propertyName])) {
284
+ _invalidate.call(this, {
285
+ type: "slot",
286
+ name: propertyNameToSlotMap.get(propertyName),
287
+ reason: "children",
288
+ });
289
+ invalidated = true;
290
+ }
291
+ }
292
+
293
+ // If none of the slots had an invalidation due to changes to immediate children,
294
+ // the change is considered to be text content of the default slot
295
+ if (!invalidated) {
296
+ _invalidate.call(this, {
297
+ type: "slot",
298
+ name: "default",
299
+ reason: "textcontent",
300
+ });
301
+ }
237
302
  }
238
303
 
239
304
  /**
240
305
  * Removes all children from the slot and detaches listeners, if any
241
306
  * @private
242
307
  */
243
- _clearSlot(slotName) {
244
- const slotData = this.constructor.getMetadata().getSlots()[slotName];
308
+ _clearSlot(slotName, slotData) {
245
309
  const propertyName = slotData.propertyName || slotName;
246
-
247
- let children = this._state[propertyName];
248
- if (!Array.isArray(children)) {
249
- children = [children];
250
- }
310
+ const children = this._state[propertyName];
251
311
 
252
312
  children.forEach(child => {
253
313
  if (child && child.isUI5Element) {
254
- this._detachChildPropertyUpdated(child);
314
+ child.detachInvalidate(this._getChildChangeListener(slotName));
315
+ }
316
+
317
+ if (isSlot(child)) {
318
+ this._detachSlotChange(child, slotName);
255
319
  }
256
320
  });
257
321
 
258
322
  this._state[propertyName] = [];
259
- this._invalidate(propertyName, []);
323
+ }
324
+
325
+ /**
326
+ * Attach a callback that will be executed whenever the component is invalidated
327
+ *
328
+ * @param callback
329
+ * @public
330
+ */
331
+ attachInvalidate(callback) {
332
+ this._eventProvider.attachEvent("invalidate", callback);
333
+ }
334
+
335
+ /**
336
+ * Detach the callback that is executed whenever the component is invalidated
337
+ *
338
+ * @param callback
339
+ * @public
340
+ */
341
+ detachInvalidate(callback) {
342
+ this._eventProvider.detachEvent("invalidate", callback);
343
+ }
344
+
345
+ /**
346
+ * Callback that is executed whenever a monitored child changes its state
347
+ *
348
+ * @param slotName the slot in which a child was invalidated
349
+ * @param childChangeInfo the changeInfo object for the child in the given slot
350
+ * @private
351
+ */
352
+ _onChildChange(slotName, childChangeInfo) {
353
+ if (!this.constructor.getMetadata().shouldInvalidateOnChildChange(slotName, childChangeInfo.type, childChangeInfo.name)) {
354
+ return;
355
+ }
356
+
357
+ // The component should be invalidated as this type of change on the child is listened for
358
+ // However, no matter what changed on the child (property/slot), the invalidation is registered as "type=slot" for the component itself
359
+ _invalidate.call(this, {
360
+ type: "slot",
361
+ name: slotName,
362
+ reason: "childchange",
363
+ child: childChangeInfo.target,
364
+ });
260
365
  }
261
366
 
262
367
  /**
@@ -271,9 +376,8 @@ class UI5Element extends HTMLElement {
271
376
  const propertyTypeClass = properties[nameInCamelCase].type;
272
377
  if (propertyTypeClass === Boolean) {
273
378
  newValue = newValue !== null;
274
- }
275
- if (propertyTypeClass === Integer) {
276
- newValue = parseInt(newValue);
379
+ } else if (isDescendantOf(propertyTypeClass, DataType)) {
380
+ newValue = propertyTypeClass.attributeToProperty(newValue);
277
381
  }
278
382
  this[nameInCamelCase] = newValue;
279
383
  }
@@ -286,22 +390,24 @@ class UI5Element extends HTMLElement {
286
390
  if (!this.constructor.getMetadata().hasAttribute(name)) {
287
391
  return;
288
392
  }
289
-
290
- if (typeof newValue === "object") {
291
- return;
292
- }
293
-
393
+ const properties = this.constructor.getMetadata().getProperties();
394
+ const propertyTypeClass = properties[name].type;
294
395
  const attrName = camelToKebabCase(name);
295
396
  const attrValue = this.getAttribute(attrName);
296
- if (typeof newValue === "boolean") {
397
+
398
+ if (propertyTypeClass === Boolean) {
297
399
  if (newValue === true && attrValue === null) {
298
400
  this.setAttribute(attrName, "");
299
401
  } else if (newValue === false && attrValue !== null) {
300
402
  this.removeAttribute(attrName);
301
403
  }
302
- } else if (attrValue !== newValue) {
303
- this.setAttribute(attrName, newValue);
304
- }
404
+ } else if (isDescendantOf(propertyTypeClass, DataType)) {
405
+ this.setAttribute(attrName, propertyTypeClass.propertyToAttribute(newValue));
406
+ } else if (typeof newValue !== "object") {
407
+ if (attrValue !== newValue) {
408
+ this.setAttribute(attrName, newValue);
409
+ }
410
+ } // else { return; } // old object handling
305
411
  }
306
412
 
307
413
  /**
@@ -327,107 +433,101 @@ class UI5Element extends HTMLElement {
327
433
  * @private
328
434
  */
329
435
  _initializeState() {
330
- const defaultState = this.constructor._getDefaultState();
331
- this._state = Object.assign({}, defaultState);
436
+ this._state = { ...this.constructor.getMetadata().getInitialState() };
332
437
  }
333
438
 
334
439
  /**
440
+ * Returns a singleton event listener for the "change" event of a child in a given slot
441
+ *
442
+ * @param slotName the name of the slot, where the child is
443
+ * @returns {any}
335
444
  * @private
336
445
  */
337
- _attachChildPropertyUpdated(child, propData) {
338
- const listenFor = propData.listenFor,
339
- childMetadata = child.constructor.getMetadata(),
340
- slotName = this.constructor._getSlotName(child), // all slotted children have the same configuration
341
- childProperties = childMetadata.getProperties();
342
-
343
- let observedProps = [],
344
- notObservedProps = [];
345
-
346
- if (!listenFor) {
347
- return;
348
- }
349
-
350
- if (Array.isArray(listenFor)) {
351
- observedProps = listenFor;
352
- } else {
353
- observedProps = Array.isArray(listenFor.props) ? listenFor.props : Object.keys(childProperties);
354
- notObservedProps = Array.isArray(listenFor.exclude) ? listenFor.exclude : [];
446
+ _getChildChangeListener(slotName) {
447
+ if (!this._childChangeListeners.has(slotName)) {
448
+ this._childChangeListeners.set(slotName, this._onChildChange.bind(this, slotName));
355
449
  }
356
-
357
- if (!this._monitoredChildProps.has(slotName)) {
358
- this._monitoredChildProps.set(slotName, { observedProps, notObservedProps });
359
- }
360
-
361
- child.addEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate);
450
+ return this._childChangeListeners.get(slotName);
362
451
  }
363
452
 
364
453
  /**
454
+ * Returns a singleton slotchange event listener that invalidates the component due to changes in the given slot
455
+ *
456
+ * @param slotName the name of the slot, where the slot element (whose slotchange event we're listening to) is
457
+ * @returns {any}
365
458
  * @private
366
459
  */
367
- _detachChildPropertyUpdated(child) {
368
- child.removeEventListener("_propertyChange", this._invalidateParentOnPropertyUpdate);
460
+ _getSlotChangeListener(slotName) {
461
+ if (!this._slotChangeListeners.has(slotName)) {
462
+ this._slotChangeListeners.set(slotName, this._onSlotChange.bind(this, slotName));
463
+ }
464
+ return this._slotChangeListeners.get(slotName);
369
465
  }
370
466
 
371
467
  /**
372
468
  * @private
373
469
  */
374
- _propertyChange(name, value) {
375
- this._updateAttribute(name, value);
376
-
377
- const customEvent = new CustomEvent("_propertyChange", {
378
- detail: { name, newValue: value },
379
- composed: false,
380
- bubbles: true,
381
- });
382
-
383
- this.dispatchEvent(customEvent);
470
+ _attachSlotChange(child, slotName) {
471
+ child.addEventListener("slotchange", this._getSlotChangeListener(slotName));
384
472
  }
385
473
 
386
474
  /**
387
475
  * @private
388
476
  */
389
- _invalidateParentOnPropertyUpdate(prop) {
390
- // The web component to be invalidated
391
- const parentNode = this.parentNode;
392
- if (!parentNode) {
393
- return;
394
- }
395
-
396
- const slotName = parentNode.constructor._getSlotName(this);
397
- const propsMetadata = parentNode._monitoredChildProps.get(slotName);
398
-
399
- if (!propsMetadata) {
400
- return;
401
- }
402
- const { observedProps, notObservedProps } = propsMetadata;
403
-
404
- if (observedProps.includes(prop.detail.name) && !notObservedProps.includes(prop.detail.name)) {
405
- parentNode._invalidate("_parent_", this);
406
- }
477
+ _detachSlotChange(child, slotName) {
478
+ child.removeEventListener("slotchange", this._getSlotChangeListener(slotName));
407
479
  }
408
480
 
409
481
  /**
410
- * Asynchronously re-renders an already rendered web component
482
+ * Whenever a slot element is slotted inside a UI5 Web Component, its slotchange event invalidates the component
483
+ *
484
+ * @param slotName the name of the slot, where the slot element (whose slotchange event we're listening to) is
411
485
  * @private
412
486
  */
413
- _invalidate() {
414
- if (this._invalidated) {
415
- // console.log("already invalidated", this, ...arguments);
416
- return;
417
- }
418
-
419
- if (this.getDomRef() && !this._suppressInvalidation) {
420
- this._invalidated = true;
421
- // console.log("INVAL", this, ...arguments);
422
- RenderScheduler.renderDeferred(this);
423
- }
487
+ _onSlotChange(slotName) {
488
+ _invalidate.call(this, {
489
+ type: "slot",
490
+ name: slotName,
491
+ reason: "slotchange",
492
+ });
424
493
  }
425
494
 
426
495
  /**
427
- * Do not call this method directly, only intended to be called by RenderScheduler.js
496
+ * A callback that is executed each time an already rendered component is invalidated (scheduled for re-rendering)
497
+ *
498
+ * @param changeInfo An object with information about the change that caused invalidation.
499
+ * The object can have the following properties:
500
+ * - type: (property|slot) tells what caused the invalidation
501
+ * 1) property: a property value was changed either directly or as a result of changing the corresponding attribute
502
+ * 2) slot: a slotted node(nodes) changed in one of several ways (see "reason")
503
+ *
504
+ * - name: the name of the property or slot that caused the invalidation
505
+ *
506
+ * - reason: (children|textcontent|childchange|slotchange) relevant only for type="slot" only and tells exactly what changed in the slot
507
+ * 1) children: immediate children (HTML elements or text nodes) were added, removed or reordered in the slot
508
+ * 2) textcontent: text nodes in the slot changed value (or nested text nodes were added or changed value). Can only trigger for slots of "type: Node"
509
+ * 3) slotchange: a slot element, slotted inside that slot had its "slotchange" event listener called. This practically means that transitively slotted children changed.
510
+ * Can only trigger if the child of a slot is a slot element itself.
511
+ * 4) childchange: indicates that a UI5Element child in that slot was invalidated and in turn invalidated the component.
512
+ * Can only trigger for slots with "invalidateOnChildChange" metadata descriptor
513
+ *
514
+ * - newValue: the new value of the property (for type="property" only)
515
+ *
516
+ * - oldValue: the old value of the property (for type="property" only)
517
+ *
518
+ * - child the child that was changed (for type="slot" and reason="childchange" only)
519
+ *
520
+ * @public
521
+ */
522
+ onInvalidation(changeInfo) {}
523
+
524
+ /**
525
+ * Do not call this method directly, only intended to be called by js
428
526
  * @protected
429
527
  */
430
528
  _render() {
529
+ const hasIndividualSlots = this.constructor.getMetadata().hasIndividualSlots();
530
+
431
531
  // suppress invalidation to prevent state changes scheduling another rendering
432
532
  this._suppressInvalidation = true;
433
533
 
@@ -441,19 +541,43 @@ class UI5Element extends HTMLElement {
441
541
  }
442
542
 
443
543
  // resume normal invalidation handling
444
- delete this._suppressInvalidation;
544
+ this._suppressInvalidation = false;
445
545
 
446
546
  // Update the shadow root with the render result
447
- // console.log(this.getDomRef() ? "RE-RENDER" : "FIRST RENDER", this);
448
- delete this._invalidated;
449
- this._updateShadowRoot();
547
+ /*
548
+ if (this._changedState.length) {
549
+ let element = this.localName;
550
+ if (this.id) {
551
+ element = `${element}#${this.id}`;
552
+ }
553
+ console.log("Re-rendering:", element, this._changedState.map(x => { // eslint-disable-line
554
+ let res = `${x.type}`;
555
+ if (x.reason) {
556
+ res = `${res}(${x.reason})`;
557
+ }
558
+ res = `${res}: ${x.name}`;
559
+ if (x.type === "property") {
560
+ res = `${res} ${x.oldValue} => ${x.newValue}`;
561
+ }
562
+
563
+ return res;
564
+ }));
565
+ }
566
+ */
567
+ this._changedState = [];
450
568
 
451
- if (this.constructor._needsStaticArea()) {
452
- this.staticAreaItem._updateFragment(this);
569
+ // Update shadow root and static area item
570
+ if (this.constructor._needsShadowDOM()) {
571
+ updateShadowRoot(this);
572
+ }
573
+ if (this.staticAreaItem) {
574
+ this.staticAreaItem.update();
453
575
  }
454
576
 
455
577
  // Safari requires that children get the slot attribute only after the slot tags have been rendered in the shadow DOM
456
- this._assignIndividualSlotsToChildren();
578
+ if (hasIndividualSlots) {
579
+ this._assignIndividualSlotsToChildren();
580
+ }
457
581
 
458
582
  // Call the onAfterRendering hook
459
583
  if (typeof this.onAfterRendering === "function") {
@@ -461,19 +585,6 @@ class UI5Element extends HTMLElement {
461
585
  }
462
586
  }
463
587
 
464
- /**
465
- * @private
466
- */
467
- _updateShadowRoot() {
468
- let styleToPrepend;
469
- const renderResult = this.constructor.template(this);
470
-
471
- if (!document.adoptedStyleSheets && !window.ShadyDOM) {
472
- styleToPrepend = getEffectiveStyle(this.constructor);
473
- }
474
- this.constructor.render(renderResult, this.shadowRoot, styleToPrepend, { eventContext: this });
475
- }
476
-
477
588
  /**
478
589
  * @private
479
590
  */
@@ -496,16 +607,27 @@ class UI5Element extends HTMLElement {
496
607
 
497
608
  /**
498
609
  * Returns the DOM Element inside the Shadow Root that corresponds to the opening tag in the UI5 Web Component's template
610
+ * *Note:* For logical (abstract) elements (items, options, etc...), returns the part of the parent's DOM that represents this option
499
611
  * Use this method instead of "this.shadowRoot" to read the Shadow DOM, if ever necessary
612
+ *
500
613
  * @public
501
614
  */
502
615
  getDomRef() {
616
+ // If a component set _getRealDomRef to its children, use the return value of this function
617
+ if (typeof this._getRealDomRef === "function") {
618
+ return this._getRealDomRef();
619
+ }
620
+
503
621
  if (!this.shadowRoot || this.shadowRoot.children.length === 0) {
504
622
  return;
505
623
  }
506
624
 
507
- return this.shadowRoot.children.length === 1
508
- ? this.shadowRoot.children[0] : this.shadowRoot.children[1];
625
+ const children = [...this.shadowRoot.children].filter(child => !["link", "style"].includes(child.localName));
626
+ if (children.length !== 1) {
627
+ 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
628
+ }
629
+
630
+ return children[0];
509
631
  }
510
632
 
511
633
  /**
@@ -521,6 +643,16 @@ class UI5Element extends HTMLElement {
521
643
  }
522
644
  }
523
645
 
646
+ /**
647
+ * Waits for dom ref and then returns the DOM Element marked with "data-sap-focus-ref" inside the template.
648
+ * This is the element that will receive the focus by default.
649
+ * @public
650
+ */
651
+ async getFocusDomRefAsync() {
652
+ await this._waitForDomRef();
653
+ return this.getFocusDomRef();
654
+ }
655
+
524
656
  /**
525
657
  * Set the focus to the element, returned by "getFocusDomRef()" (marked by "data-sap-focus-ref")
526
658
  * @public
@@ -541,37 +673,47 @@ class UI5Element extends HTMLElement {
541
673
  * @param name - name of the event
542
674
  * @param data - additional data for the event
543
675
  * @param cancelable - true, if the user can call preventDefault on the event object
676
+ * @param bubbles - true, if the event bubbles
544
677
  * @returns {boolean} false, if the event was cancelled (preventDefault called), true otherwise
545
678
  */
546
- fireEvent(name, data, cancelable) {
547
- let compatEventResult = true; // Initialized to true, because if the event is not fired at all, it should be considered "not-prevented"
679
+ fireEvent(name, data, cancelable = false, bubbles = true) {
680
+ const eventResult = this._fireEvent(name, data, cancelable, bubbles);
681
+ const camelCaseEventName = kebabToCamelCase(name);
682
+
683
+ if (camelCaseEventName !== name) {
684
+ return eventResult && this._fireEvent(camelCaseEventName, data, cancelable);
685
+ }
548
686
 
687
+ return eventResult;
688
+ }
689
+
690
+ _fireEvent(name, data, cancelable = false, bubbles = true) {
549
691
  const noConflictEvent = new CustomEvent(`ui5-${name}`, {
550
692
  detail: data,
551
693
  composed: false,
552
- bubbles: true,
694
+ bubbles,
553
695
  cancelable,
554
696
  });
555
697
 
556
- // This will be false if the compat event is prevented
557
- compatEventResult = this.dispatchEvent(noConflictEvent);
698
+ // This will be false if the no-conflict event is prevented
699
+ const noConflictEventResult = this.dispatchEvent(noConflictEvent);
558
700
 
559
701
  if (skipOriginalEvent(name)) {
560
- return compatEventResult;
702
+ return noConflictEventResult;
561
703
  }
562
704
 
563
- const customEvent = new CustomEvent(name, {
705
+ const normalEvent = new CustomEvent(name, {
564
706
  detail: data,
565
707
  composed: false,
566
- bubbles: true,
708
+ bubbles,
567
709
  cancelable,
568
710
  });
569
711
 
570
712
  // This will be false if the normal event is prevented
571
- const normalEventResult = this.dispatchEvent(customEvent);
713
+ const normalEventResult = this.dispatchEvent(normalEvent);
572
714
 
573
715
  // Return false if any of the two events was prevented (its result was false).
574
- return normalEventResult && compatEventResult;
716
+ return normalEventResult && noConflictEventResult;
575
717
  }
576
718
 
577
719
  /**
@@ -580,14 +722,19 @@ class UI5Element extends HTMLElement {
580
722
  * @public
581
723
  */
582
724
  getSlottedNodes(slotName) {
583
- const reducer = (acc, curr) => {
584
- if (curr.localName !== "slot") {
585
- return acc.concat([curr]);
586
- }
587
- return acc.concat(curr.assignedNodes({ flatten: true }).filter(item => item instanceof HTMLElement));
588
- };
725
+ return getSlottedElementsList(this[slotName]);
726
+ }
589
727
 
590
- return this[slotName].reduce(reducer, []);
728
+ /**
729
+ * Determines whether the component should be rendered in RTL mode or not.
730
+ * Returns: "rtl", "ltr" or undefined
731
+ *
732
+ * @public
733
+ * @returns {String|undefined}
734
+ */
735
+ get effectiveDir() {
736
+ markAsRtlAware(this.constructor); // if a UI5 Element calls this method, it's considered to be rtl-aware
737
+ return getEffectiveDir(this);
591
738
  }
592
739
 
593
740
  /**
@@ -607,39 +754,6 @@ class UI5Element extends HTMLElement {
607
754
  return this.getMetadata().getAttributesList();
608
755
  }
609
756
 
610
- /**
611
- * Used to generate the next auto-increment id for the current class
612
- * @returns {string}
613
- * @private
614
- */
615
- static _nextID() {
616
- const className = kebabToCamelCase(this.getMetadata().getTag());
617
- const lastNumber = IDMap.get(className);
618
- const nextNumber = lastNumber !== undefined ? lastNumber + 1 : 1;
619
- IDMap.set(className, nextNumber);
620
- return `__${className}${nextNumber}`;
621
- }
622
-
623
- /**
624
- * @private
625
- */
626
- static _getSlotName(child) {
627
- // Text nodes can only go to the default slot
628
- if (!(child instanceof HTMLElement)) {
629
- return "default";
630
- }
631
-
632
- // Discover the slot based on the real slot name (f.e. footer => footer, or content-32 => content)
633
- const slot = child.getAttribute("slot");
634
- if (slot) {
635
- const match = slot.match(/^(.+?)-\d+$/);
636
- return match ? match[1] : slot;
637
- }
638
-
639
- // Use default slot as a fallback
640
- return "default";
641
- }
642
-
643
757
  /**
644
758
  * @private
645
759
  */
@@ -651,59 +765,26 @@ class UI5Element extends HTMLElement {
651
765
  * @private
652
766
  */
653
767
  static _needsStaticArea() {
654
- return typeof this.staticAreaTemplate === "function";
768
+ return !!this.staticAreaTemplate;
655
769
  }
656
770
 
657
771
  /**
658
772
  * @public
659
773
  */
660
774
  getStaticAreaItemDomRef() {
661
- return this.staticAreaItem.getDomRef();
662
- }
663
-
664
- /**
665
- * @private
666
- */
667
- static _getDefaultState() {
668
- if (this._defaultState) {
669
- return this._defaultState;
775
+ if (!this.constructor._needsStaticArea()) {
776
+ throw new Error("This component does not use the static area");
670
777
  }
671
778
 
672
- const MetadataClass = this.getMetadata();
673
- const defaultState = {};
674
-
675
- // Initialize properties
676
- const props = MetadataClass.getProperties();
677
- for (const propName in props) { // eslint-disable-line
678
- const propType = props[propName].type;
679
- const propDefaultValue = props[propName].defaultValue;
680
-
681
- if (propType === Boolean) {
682
- defaultState[propName] = false;
683
-
684
- if (propDefaultValue !== undefined) {
685
- console.warn("The 'defaultValue' metadata key is ignored for all booleans properties, they would be initialized with 'false' by default"); // eslint-disable-line
686
- }
687
- } else if (props[propName].multiple) {
688
- defaultState[propName] = [];
689
- } else if (propType === Object) {
690
- defaultState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : {};
691
- } else if (propType === String) {
692
- defaultState[propName] = "defaultValue" in props[propName] ? props[propName].defaultValue : "";
693
- } else {
694
- defaultState[propName] = propDefaultValue;
695
- }
779
+ if (!this.staticAreaItem) {
780
+ this.staticAreaItem = StaticAreaItem.createInstance();
781
+ this.staticAreaItem.setOwnerElement(this);
696
782
  }
697
-
698
- // Initialize slots
699
- const slots = MetadataClass.getSlots();
700
- for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line
701
- const propertyName = slotData.propertyName || slotName;
702
- defaultState[propertyName] = [];
783
+ if (!this.staticAreaItem.parentElement) {
784
+ getSingletonElementInstance("ui5-static-area").appendChild(this.staticAreaItem);
703
785
  }
704
786
 
705
- this._defaultState = defaultState;
706
- return defaultState;
787
+ return this.staticAreaItem.getDomRef();
707
788
  }
708
789
 
709
790
  /**
@@ -711,18 +792,31 @@ class UI5Element extends HTMLElement {
711
792
  */
712
793
  static _generateAccessors() {
713
794
  const proto = this.prototype;
795
+ const slotsAreManaged = this.getMetadata().slotsAreManaged();
714
796
 
715
797
  // Properties
716
798
  const properties = this.getMetadata().getProperties();
717
799
  for (const [prop, propData] of Object.entries(properties)) { // eslint-disable-line
718
800
  if (!isValidPropertyName(prop)) {
719
- throw new Error(`"${prop}" is not a valid property name. Use a name that does not collide with DOM APIs`);
801
+ console.warn(`"${prop}" is not a valid property name. Use a name that does not collide with DOM APIs`); /* eslint-disable-line */
720
802
  }
721
803
 
722
- if (propData.type === "boolean" && propData.defaultValue) {
804
+ if (propData.type === Boolean && propData.defaultValue) {
723
805
  throw new Error(`Cannot set a default value for property "${prop}". All booleans are false by default.`);
724
806
  }
725
807
 
808
+ if (propData.type === Array) {
809
+ throw new Error(`Wrong type for property "${prop}". Properties cannot be of type Array - use "multiple: true" and set "type" to the single value type, such as "String", "Object", etc...`);
810
+ }
811
+
812
+ if (propData.type === Object && propData.defaultValue) {
813
+ throw new Error(`Cannot set a default value for property "${prop}". All properties of type "Object" are empty objects by default.`);
814
+ }
815
+
816
+ if (propData.multiple && propData.defaultValue) {
817
+ throw new Error(`Cannot set a default value for property "${prop}". All multiple properties are empty arrays by default.`);
818
+ }
819
+
726
820
  Object.defineProperty(proto, prop, {
727
821
  get() {
728
822
  if (this._state[prop] !== undefined) {
@@ -742,38 +836,53 @@ class UI5Element extends HTMLElement {
742
836
  }
743
837
  },
744
838
  set(value) {
839
+ let isDifferent;
745
840
  value = this.constructor.getMetadata().constructor.validatePropertyValue(value, propData);
746
841
 
747
842
  const oldState = this._state[prop];
843
+ if (propData.multiple && propData.compareValues) {
844
+ isDifferent = !arraysAreEqual(oldState, value);
845
+ } else if (isDescendantOf(propData.type, DataType)) {
846
+ isDifferent = !propData.type.valuesAreEqual(oldState, value);
847
+ } else {
848
+ isDifferent = oldState !== value;
849
+ }
748
850
 
749
- if (oldState !== value) {
851
+ if (isDifferent) {
750
852
  this._state[prop] = value;
751
- this._invalidate(prop, value);
752
- this._propertyChange(prop, value);
853
+ _invalidate.call(this, {
854
+ type: "property",
855
+ name: prop,
856
+ newValue: value,
857
+ oldValue: oldState,
858
+ });
859
+ this._updateAttribute(prop, value);
753
860
  }
754
861
  },
755
862
  });
756
863
  }
757
864
 
758
865
  // Slots
759
- const slots = this.getMetadata().getSlots();
760
- for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line
761
- if (!isValidPropertyName(slotName)) {
762
- throw new Error(`"${slotName}" is not a valid property name. Use a name that does not collide with DOM APIs`);
763
- }
866
+ if (slotsAreManaged) {
867
+ const slots = this.getMetadata().getSlots();
868
+ for (const [slotName, slotData] of Object.entries(slots)) { // eslint-disable-line
869
+ if (!isValidPropertyName(slotName)) {
870
+ console.warn(`"${slotName}" is not a valid property name. Use a name that does not collide with DOM APIs`); /* eslint-disable-line */
871
+ }
764
872
 
765
- const propertyName = slotData.propertyName || slotName;
766
- Object.defineProperty(proto, propertyName, {
767
- get() {
768
- if (this._state[propertyName] !== undefined) {
769
- return this._state[propertyName];
770
- }
771
- return [];
772
- },
773
- set() {
774
- throw new Error("Cannot set slots directly, use the DOM APIs");
775
- },
776
- });
873
+ const propertyName = slotData.propertyName || slotName;
874
+ Object.defineProperty(proto, propertyName, {
875
+ get() {
876
+ if (this._state[propertyName] !== undefined) {
877
+ return this._state[propertyName];
878
+ }
879
+ return [];
880
+ },
881
+ set() {
882
+ throw new Error("Cannot set slot content directly, use the DOM APIs (appendChild, removeChild, etc...)");
883
+ },
884
+ });
885
+ }
777
886
  }
778
887
  }
779
888
 
@@ -782,7 +891,7 @@ class UI5Element extends HTMLElement {
782
891
  * @protected
783
892
  */
784
893
  static get metadata() {
785
- return metadata;
894
+ return {};
786
895
  }
787
896
 
788
897
  /**
@@ -793,6 +902,58 @@ class UI5Element extends HTMLElement {
793
902
  return "";
794
903
  }
795
904
 
905
+ /**
906
+ * Returns the Static Area CSS for this UI5 Web Component Class
907
+ * @protected
908
+ */
909
+ static get staticAreaStyles() {
910
+ return "";
911
+ }
912
+
913
+ /**
914
+ * Returns an array with the dependencies for this UI5 Web Component, which could be:
915
+ * - composed components (used in its shadow root or static area item)
916
+ * - slotted components that the component may need to communicate with
917
+ *
918
+ * @protected
919
+ */
920
+ static get dependencies() {
921
+ return [];
922
+ }
923
+
924
+ /**
925
+ * Returns a list of the unique dependencies for this UI5 Web Component
926
+ *
927
+ * @public
928
+ */
929
+ static getUniqueDependencies() {
930
+ if (!uniqueDependenciesCache.has(this)) {
931
+ const filtered = this.dependencies.filter((dep, index, deps) => deps.indexOf(dep) === index);
932
+ uniqueDependenciesCache.set(this, filtered);
933
+ }
934
+
935
+ return uniqueDependenciesCache.get(this);
936
+ }
937
+
938
+ /**
939
+ * Returns a promise that resolves whenever all dependencies for this UI5 Web Component have resolved
940
+ *
941
+ * @returns {Promise<any[]>}
942
+ */
943
+ static whenDependenciesDefined() {
944
+ return Promise.all(this.getUniqueDependencies().map(dep => dep.define()));
945
+ }
946
+
947
+ /**
948
+ * Hook that will be called upon custom element definition
949
+ *
950
+ * @protected
951
+ * @returns {Promise<void>}
952
+ */
953
+ static async onDefine() {
954
+ return Promise.resolve();
955
+ }
956
+
796
957
  /**
797
958
  * Registers a UI5 Web Component in the browser window object
798
959
  * @public
@@ -800,17 +961,32 @@ class UI5Element extends HTMLElement {
800
961
  */
801
962
  static async define() {
802
963
  await boot();
964
+
965
+ await Promise.all([
966
+ this.whenDependenciesDefined(),
967
+ this.onDefine(),
968
+ ]);
969
+
803
970
  const tag = this.getMetadata().getTag();
971
+ const altTag = this.getMetadata().getAltTag();
804
972
 
805
- const definedLocally = DefinitionsSet.has(tag);
973
+ const definedLocally = isTagRegistered(tag);
806
974
  const definedGlobally = customElements.get(tag);
807
975
 
808
976
  if (definedGlobally && !definedLocally) {
809
- console.warn(`Skipping definition of tag ${tag}, because it was already defined by another instance of ui5-webcomponents.`); // eslint-disable-line
977
+ recordTagRegistrationFailure(tag);
810
978
  } else if (!definedGlobally) {
811
979
  this._generateAccessors();
812
- DefinitionsSet.add(tag);
980
+ registerTag(tag);
813
981
  window.customElements.define(tag, this);
982
+ preloadLinks(this);
983
+
984
+ if (altTag && !customElements.get(altTag)) {
985
+ registerTag(altTag);
986
+ window.customElements.define(altTag, getClassCopy(this, () => {
987
+ console.log(`The ${altTag} tag is deprecated and will be removed in the next release, please use ${tag} instead.`); // eslint-disable-line
988
+ }));
989
+ }
814
990
  }
815
991
  return this;
816
992
  }