@ui5/webcomponents-base 0.0.0-c6155714e → 0.0.0-c638668a1

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