@ui5/webcomponents-base 0.0.0-cc312800a → 0.0.0-cf50976ce

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 (209) hide show
  1. package/.eslintignore +3 -1
  2. package/CHANGELOG.md +280 -0
  3. package/README.md +53 -7
  4. package/bundle.esm.js +13 -11
  5. package/dist/Boot.js +34 -18
  6. package/dist/CSP.js +59 -0
  7. package/dist/CustomElementsRegistry.js +60 -4
  8. package/dist/CustomElementsScope.js +20 -98
  9. package/dist/CustomElementsScopeUtils.js +108 -0
  10. package/dist/Device.js +22 -1
  11. package/dist/EventProvider.js +19 -25
  12. package/dist/FeaturesRegistry.js +4 -1
  13. package/dist/FontFace.js +7 -95
  14. package/dist/InitialConfiguration.js +31 -14
  15. package/dist/Keys.js +62 -0
  16. package/dist/ManagedStyles.js +83 -0
  17. package/dist/Render.js +3 -1
  18. package/dist/Runtimes.js +107 -0
  19. package/dist/StaticAreaItem.js +15 -10
  20. package/dist/SystemCSSVars.js +4 -25
  21. package/dist/UI5Element.js +71 -60
  22. package/dist/UI5ElementMetadata.js +18 -2
  23. package/dist/asset-registries/Icons.js +26 -9
  24. package/dist/asset-registries/Illustrations.js +30 -0
  25. package/dist/asset-registries/LocaleData.js +18 -4
  26. package/dist/asset-registries/Themes.js +6 -2
  27. package/dist/asset-registries/i18n.js +3 -1
  28. package/dist/assets/bundle.esm.83f057b4.js +43 -0
  29. package/dist/assets-meta/IconCollectionsAlias.js +18 -0
  30. package/dist/config/Icons.js +52 -0
  31. package/dist/config/Theme.js +25 -0
  32. package/dist/css/BusyIndicator.css +80 -0
  33. package/dist/css/FontFace.css +66 -0
  34. package/dist/css/OverrideFontFace.css +32 -0
  35. package/dist/css/SystemCSSVars.css +17 -0
  36. package/dist/delegate/ItemNavigation.js +75 -4
  37. package/dist/delegate/ScrollEnablement.js +7 -1
  38. package/dist/features/F6Navigation.js +110 -0
  39. package/dist/features/OpenUI5Enablement.js +119 -0
  40. package/dist/generated/AssetParameters.js +1 -1
  41. package/dist/generated/VersionInfo.js +10 -0
  42. package/dist/generated/css/BusyIndicator.css.js +5 -0
  43. package/dist/generated/css/FontFace.css.js +5 -0
  44. package/dist/generated/css/OverrideFontFace.css.js +5 -0
  45. package/dist/generated/css/SystemCSSVars.css.js +5 -0
  46. package/dist/i18nBundle.js +34 -3
  47. package/dist/renderer/LitRenderer.js +39 -18
  48. package/dist/renderer/directives/style-map.js +72 -0
  49. package/dist/renderer/executeTemplate.js +19 -2
  50. package/dist/sap/base/Log.js +241 -0
  51. package/dist/sap/base/assert.js +8 -0
  52. package/dist/sap/base/security/URLListValidator.js +148 -0
  53. package/dist/sap/base/security/encodeCSS.js +14 -0
  54. package/dist/sap/base/security/encodeXML.js +23 -0
  55. package/dist/sap/base/security/sanitizeHTML.js +16 -0
  56. package/dist/sap/base/strings/toHex.js +8 -0
  57. package/dist/sap/base/util/now.js +7 -0
  58. package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +3585 -0
  59. package/dist/theming/CustomStyle.js +23 -3
  60. package/dist/theming/applyTheme.js +11 -10
  61. package/dist/theming/getEffectiveLinksHrefs.js +27 -0
  62. package/dist/theming/getEffectiveStyle.js +9 -0
  63. package/dist/theming/getStylesString.js +4 -2
  64. package/dist/theming/getThemeDesignerTheme.js +25 -5
  65. package/dist/theming/preloadLinks.js +23 -0
  66. package/dist/types/DOMReference.js +24 -0
  67. package/dist/types/DataType.js +12 -0
  68. package/dist/types/Float.js +4 -0
  69. package/dist/types/Integer.js +4 -0
  70. package/dist/types/InvisibleMessageMode.js +30 -0
  71. package/dist/updateShadowRoot.js +9 -6
  72. package/dist/util/AriaLabelHelper.js +6 -8
  73. package/dist/util/Caret.js +1 -14
  74. package/dist/util/ColorConversion.js +30 -2
  75. package/dist/util/FocusableElements.js +13 -7
  76. package/dist/util/HTMLSanitizer.js +7 -0
  77. package/dist/util/InvisibleMessage.js +69 -0
  78. package/dist/util/PopupUtils.js +1 -1
  79. package/dist/util/TabbableElements.js +5 -1
  80. package/dist/util/createLinkInHead.js +19 -0
  81. package/dist/util/escapeRegex.js +10 -0
  82. package/dist/util/generateHighlightedMarkup.js +42 -0
  83. package/dist/util/getEffectiveScrollbarStyle.js +5 -0
  84. package/dist/util/getNormalizedTarget.js +16 -0
  85. package/dist/util/isDefaultSlotProvided.js +11 -0
  86. package/dist/util/isNodeHidden.js +1 -1
  87. package/dist/util/isNodeTabbable.js +4 -4
  88. package/hash.txt +1 -1
  89. package/index.js +1 -1
  90. package/lib/generate-asset-parameters/index.js +8 -5
  91. package/lib/generate-styles/index.js +26 -0
  92. package/lib/generate-version-info/index.js +32 -0
  93. package/package-scripts.js +36 -23
  94. package/package.json +18 -9
  95. package/src/Boot.js +34 -18
  96. package/src/CSP.js +59 -0
  97. package/src/CustomElementsRegistry.js +60 -4
  98. package/src/CustomElementsScope.js +20 -98
  99. package/src/CustomElementsScopeUtils.js +108 -0
  100. package/src/Device.js +22 -1
  101. package/src/EventProvider.js +19 -25
  102. package/src/FeaturesRegistry.js +4 -1
  103. package/src/FontFace.js +7 -95
  104. package/src/InitialConfiguration.js +31 -14
  105. package/src/Keys.js +62 -0
  106. package/src/ManagedStyles.js +83 -0
  107. package/src/Render.js +3 -1
  108. package/src/Runtimes.js +107 -0
  109. package/src/StaticAreaItem.js +15 -10
  110. package/src/SystemCSSVars.js +4 -25
  111. package/src/UI5Element.js +71 -60
  112. package/src/UI5ElementMetadata.js +18 -2
  113. package/src/asset-registries/Icons.js +26 -9
  114. package/src/asset-registries/Illustrations.js +30 -0
  115. package/src/asset-registries/LocaleData.js +18 -4
  116. package/src/asset-registries/Themes.js +6 -2
  117. package/src/asset-registries/i18n.js +3 -1
  118. package/src/assets-meta/IconCollectionsAlias.js +18 -0
  119. package/src/config/Icons.js +52 -0
  120. package/src/config/Theme.js +25 -0
  121. package/src/css/BusyIndicator.css +80 -0
  122. package/src/css/FontFace.css +66 -0
  123. package/src/css/OverrideFontFace.css +32 -0
  124. package/src/css/SystemCSSVars.css +17 -0
  125. package/src/delegate/ItemNavigation.js +75 -4
  126. package/src/delegate/ScrollEnablement.js +7 -1
  127. package/src/features/F6Navigation.js +110 -0
  128. package/src/features/OpenUI5Enablement.js +119 -0
  129. package/src/i18nBundle.js +34 -3
  130. package/src/renderer/LitRenderer.js +39 -18
  131. package/src/renderer/directives/style-map.js +72 -0
  132. package/src/renderer/executeTemplate.js +19 -2
  133. package/src/theming/CustomStyle.js +23 -3
  134. package/src/theming/applyTheme.js +11 -10
  135. package/src/theming/getEffectiveLinksHrefs.js +27 -0
  136. package/src/theming/getEffectiveStyle.js +9 -0
  137. package/src/theming/getStylesString.js +4 -2
  138. package/src/theming/getThemeDesignerTheme.js +25 -5
  139. package/src/theming/preloadLinks.js +23 -0
  140. package/src/types/DOMReference.js +24 -0
  141. package/src/types/DataType.js +12 -0
  142. package/src/types/Float.js +4 -0
  143. package/src/types/Integer.js +4 -0
  144. package/src/types/InvisibleMessageMode.js +30 -0
  145. package/src/updateShadowRoot.js +9 -6
  146. package/src/util/AriaLabelHelper.js +6 -8
  147. package/src/util/Caret.js +1 -14
  148. package/src/util/ColorConversion.js +30 -2
  149. package/src/util/FocusableElements.js +13 -7
  150. package/src/util/HTMLSanitizer.js +7 -0
  151. package/src/util/InvisibleMessage.js +69 -0
  152. package/src/util/PopupUtils.js +1 -1
  153. package/src/util/TabbableElements.js +5 -1
  154. package/src/util/createLinkInHead.js +19 -0
  155. package/src/util/escapeRegex.js +10 -0
  156. package/src/util/generateHighlightedMarkup.js +42 -0
  157. package/src/util/getEffectiveScrollbarStyle.js +5 -0
  158. package/src/util/getNormalizedTarget.js +16 -0
  159. package/src/util/isDefaultSlotProvided.js +11 -0
  160. package/src/util/isNodeHidden.js +1 -1
  161. package/src/util/isNodeTabbable.js +4 -4
  162. package/used-modules.txt +10 -0
  163. package/config/.eslintrc.js +0 -3
  164. package/config/rollup.config.js +0 -1
  165. package/dist/config/AssetsPath.js +0 -17
  166. package/dist/isLegacyBrowser.js +0 -3
  167. package/dist/renderer/ifDefined.js +0 -21
  168. package/dist/renderer/scopeHTML.js +0 -32
  169. package/dist/resources/bundle.esm.js +0 -121
  170. package/dist/resources/bundle.esm.js.map +0 -1
  171. package/dist/test-resources/assets/Themes.js +0 -17
  172. package/dist/test-resources/elements/Child.js +0 -35
  173. package/dist/test-resources/elements/Generic.js +0 -84
  174. package/dist/test-resources/elements/GenericExt.js +0 -26
  175. package/dist/test-resources/elements/NoShadowDOM.js +0 -13
  176. package/dist/test-resources/elements/Parent.js +0 -41
  177. package/dist/test-resources/elements/WithStaticArea.js +0 -76
  178. package/dist/test-resources/pages/AllTestElements.html +0 -39
  179. package/dist/test-resources/pages/Configuration.html +0 -18
  180. package/dist/test-resources/pages/ConfigurationScript.html +0 -34
  181. package/dist/test-resources/pages/assets/messagebundle_de.properties +0 -1
  182. package/dist/test-resources/pages/assets/messagebundle_en.properties +0 -1
  183. package/dist/test-resources/pages/assets/messagebundle_es.properties +0 -1
  184. package/dist/test-resources/pages/assets/messagebundle_fr.properties +0 -1
  185. package/dist/test-resources/pages/i18n.html +0 -35
  186. package/dist/test-resources/specs/ConfigurationChange.spec.js +0 -27
  187. package/dist/test-resources/specs/ConfigurationScript.spec.js +0 -63
  188. package/dist/test-resources/specs/ConfigurationURL.spec.js +0 -47
  189. package/dist/test-resources/specs/CustomTheme.spec.js +0 -27
  190. package/dist/test-resources/specs/StaticArea.spec.js +0 -36
  191. package/dist/test-resources/specs/Theming.spec.js +0 -33
  192. package/dist/test-resources/specs/UI5ElementInvalidation.js +0 -242
  193. package/dist/test-resources/specs/UI5ElementLifecycle.js +0 -98
  194. package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +0 -75
  195. package/dist/test-resources/specs/UI5ElementMetadataExt.js +0 -42
  196. package/dist/test-resources/specs/UI5ElementPropertyValidation.js +0 -14
  197. package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +0 -67
  198. package/dist/test-resources/specs/UI5ElementShadowDOM.js +0 -24
  199. package/dist/test-resources/specs/UI5ElementSlots.js +0 -36
  200. package/dist/theming/createThemePropertiesStyleTag.js +0 -20
  201. package/dist/util/encodeCSS.js +0 -24
  202. package/dist/util/findNodeOwner.js +0 -35
  203. package/src/config/AssetsPath.js +0 -17
  204. package/src/isLegacyBrowser.js +0 -3
  205. package/src/renderer/ifDefined.js +0 -21
  206. package/src/renderer/scopeHTML.js +0 -32
  207. package/src/theming/createThemePropertiesStyleTag.js +0 -20
  208. package/src/util/encodeCSS.js +0 -24
  209. package/src/util/findNodeOwner.js +0 -35
@@ -1,7 +1,8 @@
1
1
  import { reRenderAllUI5Elements } from "../Render.js";
2
+ import getSharedResource from "../getSharedResource.js";
2
3
  import EventProvider from "../EventProvider.js";
3
4
 
4
- const eventProvider = new EventProvider();
5
+ const eventProvider = getSharedResource("CustomStyle.eventProvider", new EventProvider());
5
6
  const CUSTOM_CSS_CHANGE = "CustomCSSChange";
6
7
 
7
8
  const attachCustomCSSChange = listener => {
@@ -16,14 +17,33 @@ const fireCustomCSSChange = tag => {
16
17
  return eventProvider.fireEvent(CUSTOM_CSS_CHANGE, tag);
17
18
  };
18
19
 
19
- const customCSSFor = {};
20
+ const customCSSFor = getSharedResource("CustomStyle.customCSSFor", {});
21
+
22
+ // Listen to the eventProvider, in case other copies of this CustomStyle module fire this
23
+ // event, and this copy would therefore need to reRender the ui5 webcomponents; but
24
+ // don't reRender if it was this copy that fired the event to begin with.
25
+ let skipRerender;
26
+ attachCustomCSSChange(tag => {
27
+ if (!skipRerender) {
28
+ reRenderAllUI5Elements({ tag });
29
+ }
30
+ });
20
31
 
21
32
  const addCustomCSS = (tag, css) => {
22
33
  if (!customCSSFor[tag]) {
23
34
  customCSSFor[tag] = [];
24
35
  }
25
36
  customCSSFor[tag].push(css);
26
- fireCustomCSSChange(tag);
37
+
38
+ skipRerender = true;
39
+ try {
40
+ // The event is fired and the attached event listeners are all called synchronously
41
+ // The skipRerender flag will be used to avoid calling reRenderAllUI5Elements twice when it is this copy
42
+ // of CustomStyle.js which is firing the `CustomCSSChange` event.
43
+ fireCustomCSSChange(tag);
44
+ } finally {
45
+ skipRerender = false;
46
+ }
27
47
 
28
48
  return reRenderAllUI5Elements({ tag });
29
49
  };
@@ -1,10 +1,10 @@
1
1
  import { getThemeProperties, getRegisteredPackages, isThemeRegistered } from "../asset-registries/Themes.js";
2
- import createThemePropertiesStyleTag from "./createThemePropertiesStyleTag.js";
2
+ import { removeStyle, createOrUpdateStyle } from "../ManagedStyles.js";
3
3
  import getThemeDesignerTheme from "./getThemeDesignerTheme.js";
4
4
  import { fireThemeLoaded } from "./ThemeLoaded.js";
5
5
  import { getFeature } from "../FeaturesRegistry.js";
6
6
 
7
- const BASE_THEME_PACKAGE = "@ui5/webcomponents-theme-base";
7
+ const BASE_THEME_PACKAGE = "@ui5/webcomponents-theming";
8
8
 
9
9
  const isThemeBaseRegistered = () => {
10
10
  const registeredPackages = getRegisteredPackages();
@@ -16,15 +16,14 @@ const loadThemeBase = async theme => {
16
16
  return;
17
17
  }
18
18
 
19
- const cssText = await getThemeProperties(BASE_THEME_PACKAGE, theme);
20
- createThemePropertiesStyleTag(cssText, BASE_THEME_PACKAGE);
19
+ const cssData = await getThemeProperties(BASE_THEME_PACKAGE, theme);
20
+ if (cssData) {
21
+ createOrUpdateStyle(cssData, "data-ui5-theme-properties", BASE_THEME_PACKAGE);
22
+ }
21
23
  };
22
24
 
23
25
  const deleteThemeBase = () => {
24
- const styleElement = document.head.querySelector(`style[data-ui5-theme-properties="${BASE_THEME_PACKAGE}"]`);
25
- if (styleElement) {
26
- styleElement.parentElement.removeChild(styleElement);
27
- }
26
+ removeStyle("data-ui5-theme-properties", BASE_THEME_PACKAGE);
28
27
  };
29
28
 
30
29
  const loadComponentPackages = async theme => {
@@ -34,8 +33,10 @@ const loadComponentPackages = async theme => {
34
33
  return;
35
34
  }
36
35
 
37
- const cssText = await getThemeProperties(packageName, theme);
38
- createThemePropertiesStyleTag(cssText, packageName);
36
+ const cssData = await getThemeProperties(packageName, theme);
37
+ if (cssData) {
38
+ createOrUpdateStyle(cssData, "data-ui5-theme-properties", packageName);
39
+ }
39
40
  });
40
41
  };
41
42
 
@@ -0,0 +1,27 @@
1
+ import { getUrl } from "../CSP.js";
2
+ import { getFeature } from "../FeaturesRegistry.js";
3
+
4
+ const flatten = arr => {
5
+ return arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? flatten(val) : val), []);
6
+ };
7
+
8
+ const getEffectiveLinksHrefs = (ElementClass, forStaticArea = false) => {
9
+ let stylesData = ElementClass[forStaticArea ? "staticAreaStyles" : "styles"];
10
+ const OpenUI5Enablement = getFeature("OpenUI5Enablement");
11
+
12
+ if (!stylesData) {
13
+ return;
14
+ }
15
+
16
+ if (!Array.isArray(stylesData)) {
17
+ stylesData = [stylesData];
18
+ }
19
+
20
+ if (OpenUI5Enablement) {
21
+ stylesData.push(OpenUI5Enablement.getBusyIndicatorStyles());
22
+ }
23
+
24
+ return flatten(stylesData).filter(data => !!data).map(data => getUrl(data.packageName, data.fileName));
25
+ };
26
+
27
+ export default getEffectiveLinksHrefs;
@@ -1,5 +1,6 @@
1
1
  import { getCustomCSS, attachCustomCSSChange } from "./CustomStyle.js";
2
2
  import getStylesString from "./getStylesString.js";
3
+ import { getFeature } from "../FeaturesRegistry.js";
3
4
 
4
5
  const effectiveStyleMap = new Map();
5
6
 
@@ -10,9 +11,15 @@ attachCustomCSSChange(tag => {
10
11
  const getEffectiveStyle = (ElementClass, forStaticArea = false) => {
11
12
  const tag = ElementClass.getMetadata().getTag();
12
13
  const key = `${tag}_${forStaticArea ? "static" : "normal"}`;
14
+ const OpenUI5Enablement = getFeature("OpenUI5Enablement");
13
15
 
14
16
  if (!effectiveStyleMap.has(key)) {
15
17
  let effectiveStyle;
18
+ let busyIndicatorStyles = "";
19
+
20
+ if (OpenUI5Enablement) {
21
+ busyIndicatorStyles = getStylesString(OpenUI5Enablement.getBusyIndicatorStyles());
22
+ }
16
23
 
17
24
  if (forStaticArea) {
18
25
  effectiveStyle = getStylesString(ElementClass.staticAreaStyles);
@@ -21,6 +28,8 @@ const getEffectiveStyle = (ElementClass, forStaticArea = false) => {
21
28
  const builtInStyles = getStylesString(ElementClass.styles);
22
29
  effectiveStyle = `${builtInStyles} ${customStyle}`;
23
30
  }
31
+
32
+ effectiveStyle = `${effectiveStyle} ${busyIndicatorStyles}`;
24
33
  effectiveStyleMap.set(key, effectiveStyle);
25
34
  }
26
35
 
@@ -1,9 +1,11 @@
1
1
  const getStylesString = styles => {
2
2
  if (Array.isArray(styles)) {
3
- return flatten(styles.filter(style => !!style)).join(" ");
3
+ return flatten(styles.filter(style => !!style)).map(style => {
4
+ return typeof style === "string" ? style : style.content;
5
+ }).join(" ");
4
6
  }
5
7
 
6
- return styles;
8
+ return typeof styles === "string" ? styles : styles.content;
7
9
  };
8
10
 
9
11
  const flatten = arr => {
@@ -1,15 +1,26 @@
1
+ const warnings = new Set();
2
+
1
3
  const getThemeMetadata = () => {
2
4
  // Check if the class was already applied, most commonly to the link/style tag with the CSS Variables
3
- let el = document.querySelector(".sapThemeMetaData-Base-baseLib");
5
+ let el = document.querySelector(".sapThemeMetaData-Base-baseLib") || document.querySelector(".sapThemeMetaData-UI5-sap-ui-core");
4
6
  if (el) {
5
7
  return getComputedStyle(el).backgroundImage;
6
8
  }
7
9
 
8
10
  el = document.createElement("span");
9
11
  el.style.display = "none";
12
+
13
+ // Try with sapThemeMetaData-Base-baseLib first
10
14
  el.classList.add("sapThemeMetaData-Base-baseLib");
11
15
  document.body.appendChild(el);
12
- const metadata = getComputedStyle(el).backgroundImage;
16
+ let metadata = getComputedStyle(el).backgroundImage;
17
+
18
+ // Try with sapThemeMetaData-UI5-sap-ui-core only if the previous selector was not found
19
+ if (metadata === "none") {
20
+ el.classList.add("sapThemeMetaData-UI5-sap-ui-core");
21
+ metadata = getComputedStyle(el).backgroundImage;
22
+ }
23
+
13
24
  document.body.removeChild(el);
14
25
 
15
26
  return metadata;
@@ -24,14 +35,20 @@ const parseThemeMetadata = metadataString => {
24
35
  try {
25
36
  paramsString = decodeURIComponent(paramsString);
26
37
  } catch (ex) {
27
- console.warn("Malformed theme metadata string, unable to decodeURIComponent"); // eslint-disable-line
38
+ if (!warnings.has("decode")) {
39
+ console.warn("Malformed theme metadata string, unable to decodeURIComponent"); // eslint-disable-line
40
+ warnings.add("decode");
41
+ }
28
42
  return;
29
43
  }
30
44
  }
31
45
  try {
32
46
  return JSON.parse(paramsString);
33
47
  } catch (ex) {
34
- console.warn("Malformed theme metadata string, unable to parse JSON"); // eslint-disable-line
48
+ if (!warnings.has("parse")) {
49
+ console.warn("Malformed theme metadata string, unable to parse JSON"); // eslint-disable-line
50
+ warnings.add("parse");
51
+ }
35
52
  }
36
53
  }
37
54
  };
@@ -44,7 +61,10 @@ const processThemeMetadata = metadata => {
44
61
  themeName = metadata.Path.match(/\.([^.]+)\.css_variables$/)[1];
45
62
  baseThemeName = metadata.Extends[0];
46
63
  } catch (ex) {
47
- console.warn("Malformed theme metadata Object", metadata); // eslint-disable-line
64
+ if (!warnings.has("object")) {
65
+ console.warn("Malformed theme metadata Object", metadata); // eslint-disable-line
66
+ warnings.add("object");
67
+ }
48
68
  return;
49
69
  }
50
70
 
@@ -0,0 +1,23 @@
1
+ import getEffectiveLinksHrefs from "./getEffectiveLinksHrefs.js";
2
+ import createLinkInHead from "../util/createLinkInHead.js";
3
+ import { shouldUseLinks, shouldPreloadLinks } from "../CSP.js";
4
+
5
+ const preloaded = new Set();
6
+
7
+ const preloadLinks = ElementClass => {
8
+ if (!shouldUseLinks() || !shouldPreloadLinks()) {
9
+ return;
10
+ }
11
+
12
+ const linksHrefs = getEffectiveLinksHrefs(ElementClass, false) || [];
13
+ const staticAreaLinksHrefs = getEffectiveLinksHrefs(ElementClass, true) || [];
14
+
15
+ [...linksHrefs, ...staticAreaLinksHrefs].forEach(href => {
16
+ if (!preloaded.has(href)) {
17
+ createLinkInHead(href, { rel: "preload", as: "style" });
18
+ preloaded.add(href);
19
+ }
20
+ });
21
+ };
22
+
23
+ export default preloadLinks;
@@ -0,0 +1,24 @@
1
+ import DataType from "./DataType.js";
2
+
3
+ /**
4
+ * @class
5
+ * DOM Element reference or ID.
6
+ * <b>Note:</b> If an ID is passed, it is expected to be part of the same <code>document</code> element as the consuming component.
7
+ *
8
+ * @public
9
+ */
10
+ class DOMReference extends DataType {
11
+ static isValid(value) {
12
+ return (typeof value === "string" || value instanceof HTMLElement);
13
+ }
14
+
15
+ static propertyToAttribute(propertyValue) {
16
+ if (propertyValue instanceof HTMLElement) {
17
+ return null;
18
+ }
19
+
20
+ return propertyValue;
21
+ }
22
+ }
23
+
24
+ export default DOMReference;
@@ -11,6 +11,18 @@ class DataType {
11
11
  static isValid(value) {
12
12
  }
13
13
 
14
+ static attributeToProperty(attributeValue) {
15
+ return attributeValue;
16
+ }
17
+
18
+ static propertyToAttribute(propertyValue) {
19
+ return `${propertyValue}`;
20
+ }
21
+
22
+ static valuesAreEqual(value1, value2) {
23
+ return value1 === value2;
24
+ }
25
+
14
26
  static generateTypeAccessors(types) {
15
27
  Object.keys(types).forEach(type => {
16
28
  Object.defineProperty(this, type, {
@@ -5,6 +5,10 @@ class Float extends DataType {
5
5
  // Assuming that integers are floats as well!
6
6
  return Number(value) === value;
7
7
  }
8
+
9
+ static attributeToProperty(attributeValue) {
10
+ return parseFloat(attributeValue);
11
+ }
8
12
  }
9
13
 
10
14
  export default Float;
@@ -4,6 +4,10 @@ class Integer extends DataType {
4
4
  static isValid(value) {
5
5
  return Number.isInteger(value);
6
6
  }
7
+
8
+ static attributeToProperty(attributeValue) {
9
+ return parseInt(attributeValue);
10
+ }
7
11
  }
8
12
 
9
13
  export default Integer;
@@ -0,0 +1,30 @@
1
+ import DataType from "./DataType.js";
2
+
3
+ /**
4
+ * Enumeration for different mode behaviors of the <code>InvisibleMessage</code>.
5
+ * @private
6
+ */
7
+ const InvisibleMessageModes = {
8
+
9
+ /**
10
+ * Indicates that updates to the region should be presented at the next graceful opportunity,
11
+ * such as at the end of reading the current sentence, or when the user pauses typing.
12
+ */
13
+ Polite: "Polite",
14
+
15
+ /**
16
+ * Indicates that updates to the region have the highest priority and should be presented to the user immediately.
17
+ */
18
+ Assertive: "Assertive",
19
+
20
+ };
21
+
22
+ class InvisibleMessageMode extends DataType {
23
+ static isValid(value) {
24
+ return !!InvisibleMessageModes[value];
25
+ }
26
+ }
27
+
28
+ InvisibleMessageMode.generateTypeAccessors(InvisibleMessageModes);
29
+
30
+ export default InvisibleMessageModes;
@@ -1,7 +1,8 @@
1
1
  import executeTemplate from "./renderer/executeTemplate.js";
2
2
  import getConstructableStyle from "./theming/getConstructableStyle.js";
3
3
  import getEffectiveStyle from "./theming/getEffectiveStyle.js";
4
- import isLegacyBrowser from "./isLegacyBrowser.js";
4
+ import getEffectiveLinksHrefs from "./theming/getEffectiveLinksHrefs.js";
5
+ import { shouldUseLinks } from "./CSP.js";
5
6
 
6
7
  /**
7
8
  * Updates the shadow root of a UI5Element or its static area item
@@ -9,18 +10,20 @@ import isLegacyBrowser from "./isLegacyBrowser.js";
9
10
  * @param forStaticArea
10
11
  */
11
12
  const updateShadowRoot = (element, forStaticArea = false) => {
12
- let styleToPrepend;
13
+ let styleStrOrHrefsArr;
13
14
  const template = forStaticArea ? "staticAreaTemplate" : "template";
14
15
  const shadowRoot = forStaticArea ? element.staticAreaItem.shadowRoot : element.shadowRoot;
15
16
  const renderResult = executeTemplate(element.constructor[template], element);
16
17
 
17
- if (document.adoptedStyleSheets) { // Chrome
18
+ if (shouldUseLinks()) {
19
+ styleStrOrHrefsArr = getEffectiveLinksHrefs(element.constructor, forStaticArea);
20
+ } else if (document.adoptedStyleSheets) { // Chrome
18
21
  shadowRoot.adoptedStyleSheets = getConstructableStyle(element.constructor, forStaticArea);
19
- } else if (!isLegacyBrowser()) { // FF, Safari
20
- styleToPrepend = getEffectiveStyle(element.constructor, forStaticArea);
22
+ } else { // FF, Safari
23
+ styleStrOrHrefsArr = getEffectiveStyle(element.constructor, forStaticArea);
21
24
  }
22
25
 
23
- element.constructor.render(renderResult, shadowRoot, styleToPrepend, { eventContext: element });
26
+ element.constructor.render(renderResult, shadowRoot, styleStrOrHrefsArr, forStaticArea, { host: element });
24
27
  };
25
28
 
26
29
  export default updateShadowRoot;
@@ -1,9 +1,7 @@
1
- import findNodeOwner from "./findNodeOwner.js";
2
-
3
1
  const getEffectiveAriaLabelText = el => {
4
- if (!el.ariaLabelledby) {
5
- if (el.ariaLabel) {
6
- return el.ariaLabel;
2
+ if (!el.accessibleNameRef) {
3
+ if (el.accessibleName) {
4
+ return el.accessibleName;
7
5
  }
8
6
 
9
7
  return undefined;
@@ -15,12 +13,12 @@ const getEffectiveAriaLabelText = el => {
15
13
  /**
16
14
  *
17
15
  * @param {HTMLElement} el Defines the HTMLElement, for which you need to get all related texts
18
- * @param {HTMLElement} ownerDocument (Optional) Defines the HTMLElement(might document or custom element) where the you want to search for the texts.
16
+ * @param {Document|HTMLElement} ownerDocument (Optional) Defines the document or element where you want to search for the texts
19
17
  * @param {String} readyIds (Optional) Defines a string of elements ids. The text of these elements will be returned. If used you should provide either el or ownerDocument
20
18
  */
21
19
  const getAriaLabelledByTexts = (el, ownerDocument, readyIds = "") => {
22
- const ids = (readyIds && readyIds.split(" ")) || el.ariaLabelledby.split(" ");
23
- const owner = ownerDocument || findNodeOwner(el);
20
+ const ids = (readyIds && readyIds.split(" ")) || el.accessibleNameRef.split(" ");
21
+ const owner = ownerDocument || el.getRootNode();
24
22
  let result = "";
25
23
 
26
24
  ids.forEach((elementId, index) => {
@@ -6,20 +6,7 @@ const getCaretPosition = field => {
6
6
  // Initialize
7
7
  let caretPos = 0;
8
8
 
9
- // IE Support
10
- if (document.selection) {
11
- // Set focus on the element
12
- field.focus();
13
-
14
- // To get cursor position, get empty selection range
15
- const selection = document.selection.createRange();
16
-
17
- // Move selection start to 0 position
18
- selection.moveStart("character", -field.value.length);
19
-
20
- // The caret position is selection length
21
- caretPos = selection.text.length;
22
- } else if (field.selectionStart || field.selectionStart === "0") { // Firefox support
9
+ if (field.selectionStart || field.selectionStart === "0") { // Firefox support
23
10
  caretPos = field.selectionDirection === "backward" ? field.selectionStart : field.selectionEnd;
24
11
  }
25
12
 
@@ -163,7 +163,7 @@ const getRGBColor = color => {
163
163
  }
164
164
 
165
165
  if (color.startsWith("rgb")) {
166
- return RGBToRGB(color);
166
+ return RGBStringToRGBObject(color);
167
167
  }
168
168
 
169
169
  // HEX
@@ -209,7 +209,7 @@ const RGBAToRGB = color => {
209
209
  * Return an object with the properties for each of the main colors(red, green, blue)
210
210
  * @param {String} color Receives a color in the following format: "rgb(0, 0, 0)
211
211
  */
212
- const RGBToRGB = color => {
212
+ const RGBStringToRGBObject = color => {
213
213
  const openingBracketIndex = color.indexOf("("),
214
214
  closingBraketIndex = color.indexOf(")"),
215
215
  commasIndexes = [];
@@ -319,6 +319,32 @@ const HEXToRGB = hex => {
319
319
  return rgbValues;
320
320
  };
321
321
 
322
+ /**
323
+ * Returns the hex value of the color as string
324
+ * @param {Object} color Receives an object with the properties for each of the main colors(r, g, b)
325
+ */
326
+ const RGBtoHEX = color => {
327
+ const hexMap = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E"];
328
+ let hexValue = "#";
329
+
330
+ let divisionNumber = color.r / 16;
331
+ let remainder = color.r % 16;
332
+ hexValue += String(hexMap[Math.floor(divisionNumber)]);
333
+ hexValue += String(hexMap[remainder]);
334
+
335
+ divisionNumber = color.g / 16;
336
+ remainder = color.g % 16;
337
+ hexValue += String(hexMap[Math.floor(divisionNumber)]);
338
+ hexValue += String(hexMap[remainder]);
339
+
340
+ divisionNumber = color.b / 16;
341
+ remainder = color.b % 16;
342
+ hexValue += String(hexMap[Math.floor(divisionNumber)]);
343
+ hexValue += String(hexMap[remainder]);
344
+
345
+ return hexValue;
346
+ };
347
+
322
348
  const RGBToHSL = (color = {
323
349
  r: undefined,
324
350
  g: undefined,
@@ -367,4 +393,6 @@ export {
367
393
  HSLToRGB,
368
394
  HEXToRGB,
369
395
  RGBToHSL,
396
+ RGBStringToRGBObject,
397
+ RGBtoHEX,
370
398
  };
@@ -5,23 +5,27 @@ const isFocusTrap = el => {
5
5
  return el.hasAttribute("data-ui5-focus-trap");
6
6
  };
7
7
 
8
- const getFirstFocusableElement = async container => {
8
+ const getFirstFocusableElement = async (container, startFromContainer) => {
9
9
  if (!container || isNodeHidden(container)) {
10
10
  return null;
11
11
  }
12
12
 
13
- return findFocusableElement(container, true);
13
+ return findFocusableElement(container, true, startFromContainer);
14
14
  };
15
15
 
16
- const getLastFocusableElement = async container => {
16
+ const getLastFocusableElement = async (container, startFromContainer) => {
17
17
  if (!container || isNodeHidden(container)) {
18
18
  return null;
19
19
  }
20
20
 
21
- return findFocusableElement(container, false);
21
+ return findFocusableElement(container, false, startFromContainer);
22
22
  };
23
23
 
24
- const findFocusableElement = async (container, forward) => {
24
+ const isElemFocusable = el => {
25
+ return el.hasAttribute("data-ui5-focus-redirect") || !isNodeHidden(el);
26
+ };
27
+
28
+ const findFocusableElement = async (container, forward, startFromContainer) => {
25
29
  let child;
26
30
 
27
31
  if (container.shadowRoot) {
@@ -29,8 +33,10 @@ const findFocusableElement = async (container, forward) => {
29
33
  } else if (container.assignedNodes && container.assignedNodes()) {
30
34
  const assignedElements = container.assignedNodes();
31
35
  child = forward ? assignedElements[0] : assignedElements[assignedElements.length - 1];
36
+ } else if (startFromContainer) {
37
+ child = container;
32
38
  } else {
33
- child = forward ? container.firstChild : container.lastChild;
39
+ child = forward ? container.firstElementChild : container.lastElementChild;
34
40
  }
35
41
 
36
42
  let focusableDescendant;
@@ -48,7 +54,7 @@ const findFocusableElement = async (container, forward) => {
48
54
  return null;
49
55
  }
50
56
 
51
- if (child.nodeType === 1 && !isNodeHidden(child) && !isFocusTrap(child)) {
57
+ if (child.nodeType === 1 && isElemFocusable(child) && !isFocusTrap(child)) {
52
58
  if (isNodeClickable(child)) {
53
59
  return (child && typeof child.focus === "function") ? child : null;
54
60
  }
@@ -0,0 +1,7 @@
1
+ import sanitizeHTML from "../sap/base/security/sanitizeHTML.js";
2
+ import URLListValidator from "../sap/base/security/URLListValidator.js";
3
+
4
+ export {
5
+ URLListValidator,
6
+ sanitizeHTML,
7
+ };
@@ -0,0 +1,69 @@
1
+ import InvisibleMessageMode from "../types/InvisibleMessageMode.js";
2
+ import getSingletonElementInstance from "./getSingletonElementInstance.js";
3
+ import { attachBoot } from "../Boot.js";
4
+
5
+ let politeSpan;
6
+ let assertiveSpan;
7
+
8
+ const setOutOfViewportStyles = el => {
9
+ el.style.position = "absolute";
10
+ el.style.clip = "rect(1px,1px,1px,1px)";
11
+ el.style.userSelect = "none";
12
+ el.style.left = "-1000px";
13
+ el.style.top = "-1000px";
14
+ el.style.pointerEvents = "none";
15
+ };
16
+
17
+ attachBoot(() => {
18
+ if (politeSpan && assertiveSpan) {
19
+ return;
20
+ }
21
+
22
+ politeSpan = document.createElement("span");
23
+ assertiveSpan = document.createElement("span");
24
+
25
+ politeSpan.classList.add("ui5-invisiblemessage-polite");
26
+ assertiveSpan.classList.add("ui5-invisiblemessage-assertive");
27
+
28
+ politeSpan.setAttribute("aria-live", "polite");
29
+ assertiveSpan.setAttribute("aria-live", "assertive");
30
+
31
+ politeSpan.setAttribute("role", "alert");
32
+ assertiveSpan.setAttribute("role", "alert");
33
+
34
+ setOutOfViewportStyles(politeSpan);
35
+ setOutOfViewportStyles(assertiveSpan);
36
+
37
+ getSingletonElementInstance("ui5-static-area").appendChild(politeSpan);
38
+ getSingletonElementInstance("ui5-static-area").appendChild(assertiveSpan);
39
+ });
40
+
41
+ /**
42
+ * Inserts the string into the respective span, depending on the mode provided.
43
+ *
44
+ * @param {string} message String to be announced by the screen reader.
45
+ * @param {sap.ui.core.InvisibleMessageMode} mode The mode to be inserted in the aria-live attribute.
46
+ * @public
47
+ */
48
+ const announce = (message, mode) => {
49
+ // If no type is presented, fallback to polite announcement.
50
+ const span = mode === InvisibleMessageMode.Assertive ? assertiveSpan : politeSpan;
51
+
52
+ // Set textContent to empty string in order to trigger screen reader's announcement.
53
+ span.textContent = "";
54
+ span.textContent = message;
55
+
56
+ if (mode !== InvisibleMessageMode.Assertive && mode !== InvisibleMessageMode.Polite) {
57
+ console.warn(`You have entered an invalid mode. Valid values are: "Polite" and "Assertive". The framework will automatically set the mode to "Polite".`); // eslint-disable-line
58
+ }
59
+
60
+ // clear the span in order to avoid reading it out while in JAWS reading node
61
+ setTimeout(() => {
62
+ // ensure that we clear the text node only if no announce is made in the meantime
63
+ if (span.textContent === message) {
64
+ span.textContent = "";
65
+ }
66
+ }, 3000);
67
+ };
68
+
69
+ export default announce;
@@ -62,7 +62,7 @@ const isClickInRect = (event, rect) => {
62
62
  const getClosedPopupParent = el => {
63
63
  const parent = el.parentElement || (el.getRootNode && el.getRootNode().host);
64
64
 
65
- if (parent && ((parent.openBy && parent.isUI5Element) || (parent.open && parent.isUI5Element) || parent === document.documentElement)) {
65
+ if (parent && ((parent.showAt && parent.isUI5Element) || (parent.open && parent.isUI5Element) || parent === document.documentElement)) {
66
66
  return parent;
67
67
  }
68
68
 
@@ -17,7 +17,7 @@ const getTabbables = (nodes, tabbables) => {
17
17
  }
18
18
 
19
19
  Array.from(nodes).forEach(currentNode => {
20
- if (currentNode.nodeType === Node.TEXT_NODE || currentNode.nodeType === Node.COMMENT_NODE) {
20
+ if (currentNode.nodeType === Node.TEXT_NODE || currentNode.nodeType === Node.COMMENT_NODE || currentNode.hasAttribute("data-sap-no-tab-ref")) {
21
21
  return;
22
22
  }
23
23
 
@@ -27,6 +27,10 @@ const getTabbables = (nodes, tabbables) => {
27
27
  currentNode = Array.from(children).find(node => node.tagName !== "STYLE");
28
28
  }
29
29
 
30
+ if (!currentNode) {
31
+ return;
32
+ }
33
+
30
34
  if (isNodeTabbable(currentNode)) {
31
35
  tabbablesNodes.push(currentNode);
32
36
  }