@ui5/webcomponents-base 1.0.2 → 1.1.0

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 (45) hide show
  1. package/.eslintignore +1 -0
  2. package/CHANGELOG.md +19 -0
  3. package/dist/Boot.js +32 -14
  4. package/dist/CustomElementsRegistry.js +60 -4
  5. package/dist/Device.js +6 -0
  6. package/dist/FeaturesRegistry.js +4 -1
  7. package/dist/Keys.js +17 -0
  8. package/dist/Runtimes.js +109 -0
  9. package/dist/StaticAreaItem.js +3 -0
  10. package/dist/UI5Element.js +7 -2
  11. package/dist/UI5ElementMetadata.js +8 -0
  12. package/dist/features/F6Navigation.js +106 -0
  13. package/dist/generated/VersionInfo.js +10 -0
  14. package/dist/resources/bundle.esm.js +8 -8
  15. package/dist/resources/bundle.esm.js.map +1 -1
  16. package/dist/sap/base/security/encodeCSS.js +14 -0
  17. package/dist/sap/base/security/encodeXML.js +23 -0
  18. package/dist/sap/base/strings/toHex.js +8 -0
  19. package/dist/util/FocusableElements.js +8 -6
  20. package/dist/util/generateHighlightedMarkup.js +1 -1
  21. package/dist/util/isNodeHidden.js +1 -1
  22. package/dist/util/metaUrl.js +3 -0
  23. package/hash.txt +1 -1
  24. package/lib/generate-version-info/index.js +27 -0
  25. package/package-scripts.js +3 -1
  26. package/package.json +3 -3
  27. package/src/Boot.js +32 -14
  28. package/src/CustomElementsRegistry.js +60 -4
  29. package/src/Device.js +6 -0
  30. package/src/FeaturesRegistry.js +4 -1
  31. package/src/Keys.js +17 -0
  32. package/src/Runtimes.js +109 -0
  33. package/src/StaticAreaItem.js +3 -0
  34. package/src/UI5Element.js +7 -2
  35. package/src/UI5ElementMetadata.js +8 -0
  36. package/src/features/F6Navigation.js +106 -0
  37. package/src/util/FocusableElements.js +8 -6
  38. package/src/util/generateHighlightedMarkup.js +1 -1
  39. package/src/util/isNodeHidden.js +1 -1
  40. package/src/util/metaUrl.js +3 -0
  41. package/used-modules.txt +4 -1
  42. package/dist/util/encodeCSS.js +0 -24
  43. package/dist/util/encodeXML.js +0 -35
  44. package/src/util/encodeCSS.js +0 -24
  45. package/src/util/encodeXML.js +0 -35
@@ -0,0 +1,106 @@
1
+ import { registerFeature } from "../../dist/FeaturesRegistry.js";
2
+ import { isF6Next, isF6Previous } from "../../dist/Keys.js";
3
+ import { getFirstFocusableElement } from "../../dist/util/FocusableElements.js";
4
+
5
+ class F6Navigation {
6
+ init() {
7
+ this.keydownHandler = this._keydownHandler.bind(this);
8
+ this.attachEventListeners();
9
+ this.selectedGroup = null;
10
+ this.groups = [];
11
+ }
12
+
13
+ attachEventListeners() {
14
+ document.addEventListener("keydown", this.keydownHandler);
15
+ }
16
+
17
+ async _keydownHandler(event) {
18
+ if (isF6Next(event)) {
19
+ this.updateGroups();
20
+ if (this.groups.length < 1) {
21
+ return;
22
+ }
23
+
24
+ const nextIndex = this.groups.indexOf(this.selectedGroup);
25
+ let nextElement = null;
26
+
27
+ if (nextIndex > -1) {
28
+ if (nextIndex + 1 >= this.groups.length) {
29
+ nextElement = this.groups[0];
30
+ } else {
31
+ nextElement = this.groups[nextIndex + 1];
32
+ }
33
+ } else {
34
+ nextElement = this.groups[0];
35
+ }
36
+
37
+ const elementToFocus = await getFirstFocusableElement(nextElement.isUI5Element ? nextElement.getDomRef() : nextElement, true);
38
+ elementToFocus.focus();
39
+ }
40
+
41
+ if (isF6Previous(event)) {
42
+ this.updateGroups();
43
+ if (this.groups.length < 1) {
44
+ return;
45
+ }
46
+
47
+ const nextIndex = this.groups.indexOf(this.selectedGroup);
48
+ let nextElement = null;
49
+
50
+ if (nextIndex > -1) {
51
+ if (nextIndex - 1 < 0) {
52
+ nextElement = this.groups[this.groups.length - 1];
53
+ } else {
54
+ // Handle the situation where the first focusable element of two neighbor groups is the same
55
+ // For example:
56
+ // <ui5-flexible-column-layout>
57
+ // <ui5-list>
58
+ // <ui5-li>List Item</ui5-li>
59
+ // </ui5-list>
60
+ // </ui5-flexible-column-layout>
61
+ // Here for both FCL & List the firstFoccusableElement is the same (the ui5-li)
62
+
63
+ const firstFocusable = await getFirstFocusableElement(this.groups[nextIndex - 1], true);
64
+ const shouldSkipParent = firstFocusable === await getFirstFocusableElement(this.groups[nextIndex], true);
65
+
66
+ nextElement = this.groups[shouldSkipParent ? nextIndex - 2 : nextIndex - 1];
67
+ }
68
+ } else {
69
+ nextElement = this.groups[this.groups.length - 1];
70
+ }
71
+
72
+ const elementToFocus = await getFirstFocusableElement(nextElement.isUI5Element ? nextElement.getDomRef() : nextElement, true);
73
+ elementToFocus.focus();
74
+ }
75
+ }
76
+
77
+ removeEventListeners() {
78
+ document.removeEventListener("keydown", this.keydownHandler);
79
+ }
80
+
81
+ updateGroups() {
82
+ this.setSelectedGroup(document.activeElement);
83
+ this.setGroups();
84
+ }
85
+
86
+ setGroups() {
87
+ this.groups = Array.from(document.querySelectorAll("[data-sap-ui-fastnavgroup='true']")).filter(group => group.clientWidth && window.getComputedStyle(group).visibility !== "hidden");
88
+ }
89
+
90
+ setSelectedGroup(element) {
91
+ while (element && element.getAttribute("data-sap-ui-fastnavgroup") !== "true" && element !== document.querySelector("html")) {
92
+ element = element.parentElement ? element.parentNode : element.parentNode.host;
93
+ }
94
+
95
+ this.selectedGroup = element;
96
+ }
97
+
98
+ destroy() {
99
+ this.removeEventListeners();
100
+ }
101
+ }
102
+
103
+ const F6HelperInstance = new F6Navigation();
104
+ registerFeature("F6Navigation", F6HelperInstance);
105
+
106
+ export default F6Navigation;
@@ -5,27 +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
24
  const isElemFocusable = el => {
25
25
  return el.hasAttribute("data-ui5-focus-redirect") || !isNodeHidden(el);
26
26
  };
27
27
 
28
- const findFocusableElement = async (container, forward) => {
28
+ const findFocusableElement = async (container, forward, startFromContainer) => {
29
29
  let child;
30
30
 
31
31
  if (container.shadowRoot) {
@@ -33,8 +33,10 @@ const findFocusableElement = async (container, forward) => {
33
33
  } else if (container.assignedNodes && container.assignedNodes()) {
34
34
  const assignedElements = container.assignedNodes();
35
35
  child = forward ? assignedElements[0] : assignedElements[assignedElements.length - 1];
36
+ } else if (startFromContainer) {
37
+ child = container;
36
38
  } else {
37
- child = forward ? container.firstChild : container.lastChild;
39
+ child = forward ? container.firstElementChild : container.lastElementChild;
38
40
  }
39
41
 
40
42
  let focusableDescendant;
@@ -1,5 +1,5 @@
1
1
  import escapeRegex from "./escapeRegex.js";
2
- import encodeXML from "./encodeXML.js";
2
+ import encodeXML from "../sap/base/security/encodeXML.js";
3
3
 
4
4
  // utility to replace all occurances of a string
5
5
  function replaceAll(text, find, replace, caseInsensitive) {
@@ -3,7 +3,7 @@ const isNodeHidden = node => {
3
3
  return false;
4
4
  }
5
5
 
6
- return (node.offsetWidth <= 0 && node.offsetHeight <= 0) || node.style.visibility === "hidden";
6
+ return (node.offsetWidth <= 0 && node.offsetHeight <= 0) || (node.style && node.style.visibility === "hidden");
7
7
  };
8
8
 
9
9
  export default isNodeHidden;
@@ -0,0 +1,3 @@
1
+ const metaUrl = import.meta.url;
2
+
3
+ export default metaUrl;
package/used-modules.txt CHANGED
@@ -4,4 +4,7 @@ sap/base/util/now.js
4
4
  sap/base/Log.js
5
5
  sap/base/assert.js
6
6
  sap/base/security/URLListValidator.js
7
- sap/base/security/sanitizeHTML.js
7
+ sap/base/security/sanitizeHTML.js
8
+ sap/base/strings/toHex.js
9
+ sap/base/security/encodeXML.js
10
+ sap/base/security/encodeCSS.js
@@ -1,24 +0,0 @@
1
- const rCSS = /[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff\u2028\u2029][0-9A-Fa-f]?/g; // eslint-disable-line
2
-
3
- const toHex = (iChar, iLength) => {
4
- let sHex = iChar.toString(16);
5
- if (iLength) {
6
- sHex = sHex.padStart(iLength, "0");
7
- }
8
- return sHex;
9
- };
10
-
11
- const fnCSS = sChar => {
12
- const iChar = sChar.charCodeAt(0);
13
- if (sChar.length === 1) {
14
- return `\\${toHex(iChar)}`;
15
- }
16
-
17
- return `\\${toHex(iChar)} ${sChar.substr(1)}`;
18
- };
19
-
20
- const encodeCSS = string => {
21
- return string.replace(rCSS, fnCSS);
22
- };
23
-
24
- export default encodeCSS;
@@ -1,35 +0,0 @@
1
- const fnToHex = (iChar, iLength) => {
2
- let sHex = iChar.toString(16);
3
- if (iLength) {
4
- sHex = sHex.padStart(iLength, "0");
5
- }
6
- return sHex;
7
- };
8
-
9
- const rHtml = /[\x00-\x2b\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\xff\u2028\u2029]/g, // eslint-disable-line no-control-regex
10
- rHtmlReplace = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]/, // eslint-disable-line no-control-regex
11
- mHtmlLookup = {
12
- "<": "&lt;",
13
- ">": "&gt;",
14
- "&": "&amp;",
15
- "\"": "&quot;",
16
- };
17
-
18
- const fnHtml = sChar => {
19
- let sEncoded = mHtmlLookup[sChar];
20
- if (!sEncoded) {
21
- if (rHtmlReplace.test(sChar)) {
22
- sEncoded = "&#xfffd;";
23
- } else {
24
- sEncoded = `&#x${fnToHex(sChar.charCodeAt(0))};`;
25
- }
26
- mHtmlLookup[sChar] = sEncoded;
27
- }
28
- return sEncoded;
29
- };
30
-
31
- const fnEncodeXML = sString => {
32
- return sString.replace(rHtml, fnHtml);
33
- };
34
-
35
- export default fnEncodeXML;
@@ -1,24 +0,0 @@
1
- const rCSS = /[\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\xff\u2028\u2029][0-9A-Fa-f]?/g; // eslint-disable-line
2
-
3
- const toHex = (iChar, iLength) => {
4
- let sHex = iChar.toString(16);
5
- if (iLength) {
6
- sHex = sHex.padStart(iLength, "0");
7
- }
8
- return sHex;
9
- };
10
-
11
- const fnCSS = sChar => {
12
- const iChar = sChar.charCodeAt(0);
13
- if (sChar.length === 1) {
14
- return `\\${toHex(iChar)}`;
15
- }
16
-
17
- return `\\${toHex(iChar)} ${sChar.substr(1)}`;
18
- };
19
-
20
- const encodeCSS = string => {
21
- return string.replace(rCSS, fnCSS);
22
- };
23
-
24
- export default encodeCSS;
@@ -1,35 +0,0 @@
1
- const fnToHex = (iChar, iLength) => {
2
- let sHex = iChar.toString(16);
3
- if (iLength) {
4
- sHex = sHex.padStart(iLength, "0");
5
- }
6
- return sHex;
7
- };
8
-
9
- const rHtml = /[\x00-\x2b\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\xff\u2028\u2029]/g, // eslint-disable-line no-control-regex
10
- rHtmlReplace = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f-\x9f]/, // eslint-disable-line no-control-regex
11
- mHtmlLookup = {
12
- "<": "&lt;",
13
- ">": "&gt;",
14
- "&": "&amp;",
15
- "\"": "&quot;",
16
- };
17
-
18
- const fnHtml = sChar => {
19
- let sEncoded = mHtmlLookup[sChar];
20
- if (!sEncoded) {
21
- if (rHtmlReplace.test(sChar)) {
22
- sEncoded = "&#xfffd;";
23
- } else {
24
- sEncoded = `&#x${fnToHex(sChar.charCodeAt(0))};`;
25
- }
26
- mHtmlLookup[sChar] = sEncoded;
27
- }
28
- return sEncoded;
29
- };
30
-
31
- const fnEncodeXML = sString => {
32
- return sString.replace(rHtml, fnHtml);
33
- };
34
-
35
- export default fnEncodeXML;