@ui5/webcomponents-base 0.0.0-bef62af04 → 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 (129) hide show
  1. package/.eslintignore +3 -1
  2. package/CHANGELOG.md +97 -0
  3. package/README.md +26 -2
  4. package/bundle.esm.js +6 -2
  5. package/dist/Boot.js +32 -14
  6. package/dist/CSP.js +59 -0
  7. package/dist/CustomElementsRegistry.js +60 -4
  8. package/dist/Device.js +15 -1
  9. package/dist/EventProvider.js +19 -25
  10. package/dist/FeaturesRegistry.js +4 -1
  11. package/dist/FontFace.js +7 -95
  12. package/dist/InitialConfiguration.js +11 -7
  13. package/dist/Keys.js +29 -0
  14. package/dist/ManagedStyles.js +83 -0
  15. package/dist/Render.js +3 -1
  16. package/dist/Runtimes.js +107 -0
  17. package/dist/StaticAreaItem.js +14 -9
  18. package/dist/SystemCSSVars.js +4 -25
  19. package/dist/UI5Element.js +20 -23
  20. package/dist/UI5ElementMetadata.js +17 -1
  21. package/dist/asset-registries/Icons.js +25 -14
  22. package/dist/asset-registries/Illustrations.js +10 -3
  23. package/dist/asset-registries/LocaleData.js +11 -2
  24. package/dist/assets-meta/IconCollectionsAlias.js +18 -0
  25. package/dist/config/Theme.js +14 -0
  26. package/dist/css/FontFace.css +45 -0
  27. package/dist/css/OverrideFontFace.css +32 -0
  28. package/dist/css/SystemCSSVars.css +17 -0
  29. package/dist/delegate/ItemNavigation.js +66 -0
  30. package/dist/features/F6Navigation.js +106 -0
  31. package/dist/generated/AssetParameters.js +1 -1
  32. package/dist/generated/VersionInfo.js +10 -0
  33. package/dist/generated/css/FontFace.css.js +5 -0
  34. package/dist/generated/css/OverrideFontFace.css.js +5 -0
  35. package/dist/generated/css/SystemCSSVars.css.js +5 -0
  36. package/dist/i18nBundle.js +33 -2
  37. package/dist/renderer/LitRenderer.js +6 -4
  38. package/dist/renderer/directives/style-map.js +72 -0
  39. package/dist/resources/bundle.esm.js +19 -8
  40. package/dist/resources/bundle.esm.js.map +1 -1
  41. package/dist/sap/base/Log.js +2 -10
  42. package/dist/sap/base/assert.js +1 -5
  43. package/dist/sap/base/security/encodeCSS.js +14 -0
  44. package/dist/sap/base/security/encodeXML.js +23 -0
  45. package/dist/sap/base/strings/toHex.js +8 -0
  46. package/dist/test-resources/elements/WithStaticArea.js +2 -1
  47. package/dist/test-resources/pages/AllTestElements.html +3 -0
  48. package/dist/test-resources/pages/i18n.html +1 -3
  49. package/dist/test-resources/specs/ConfigurationChange.spec.js +9 -9
  50. package/dist/test-resources/specs/ConfigurationScript.spec.js +24 -24
  51. package/dist/test-resources/specs/ConfigurationURL.spec.js +33 -33
  52. package/dist/test-resources/specs/CustomTheme.spec.js +7 -7
  53. package/dist/test-resources/specs/EventProvider.spec.js +63 -0
  54. package/dist/test-resources/specs/StaticArea.spec.js +55 -13
  55. package/dist/test-resources/specs/Theming.spec.js +11 -11
  56. package/dist/test-resources/specs/UI5ElementInvalidation.js +29 -29
  57. package/dist/test-resources/specs/UI5ElementLifecycle.js +11 -11
  58. package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +11 -11
  59. package/dist/test-resources/specs/UI5ElementMetadataExt.js +8 -8
  60. package/dist/test-resources/specs/UI5ElementPropertyValidation.js +6 -6
  61. package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +36 -36
  62. package/dist/test-resources/specs/UI5ElementShadowDOM.js +9 -9
  63. package/dist/test-resources/specs/UI5ElementSlots.js +9 -9
  64. package/dist/theming/CustomStyle.js +23 -3
  65. package/dist/theming/applyTheme.js +11 -10
  66. package/dist/theming/getEffectiveLinksHrefs.js +20 -0
  67. package/dist/theming/getStylesString.js +4 -2
  68. package/dist/theming/getThemeDesignerTheme.js +25 -5
  69. package/dist/theming/preloadLinks.js +23 -0
  70. package/dist/updateShadowRoot.js +8 -4
  71. package/dist/util/FocusableElements.js +8 -6
  72. package/dist/util/createLinkInHead.js +19 -0
  73. package/dist/util/escapeRegex.js +10 -0
  74. package/dist/util/generateHighlightedMarkup.js +42 -0
  75. package/dist/util/isNodeHidden.js +1 -1
  76. package/hash.txt +1 -1
  77. package/lib/generate-asset-parameters/index.js +0 -1
  78. package/lib/generate-styles/index.js +18 -0
  79. package/lib/generate-version-info/index.js +27 -0
  80. package/package-scripts.js +11 -6
  81. package/package.json +9 -11
  82. package/src/Boot.js +32 -14
  83. package/src/CSP.js +59 -0
  84. package/src/CustomElementsRegistry.js +60 -4
  85. package/src/Device.js +15 -1
  86. package/src/EventProvider.js +19 -25
  87. package/src/FeaturesRegistry.js +4 -1
  88. package/src/FontFace.js +7 -95
  89. package/src/InitialConfiguration.js +11 -7
  90. package/src/Keys.js +29 -0
  91. package/src/ManagedStyles.js +83 -0
  92. package/src/Render.js +3 -1
  93. package/src/Runtimes.js +107 -0
  94. package/src/StaticAreaItem.js +14 -9
  95. package/src/SystemCSSVars.js +4 -25
  96. package/src/UI5Element.js +20 -23
  97. package/src/UI5ElementMetadata.js +17 -1
  98. package/src/asset-registries/Icons.js +25 -14
  99. package/src/asset-registries/Illustrations.js +10 -3
  100. package/src/asset-registries/LocaleData.js +11 -2
  101. package/src/assets-meta/IconCollectionsAlias.js +18 -0
  102. package/src/config/Theme.js +14 -0
  103. package/src/css/FontFace.css +45 -0
  104. package/src/css/OverrideFontFace.css +32 -0
  105. package/src/css/SystemCSSVars.css +17 -0
  106. package/src/delegate/ItemNavigation.js +66 -0
  107. package/src/features/F6Navigation.js +106 -0
  108. package/src/i18nBundle.js +33 -2
  109. package/src/renderer/LitRenderer.js +6 -4
  110. package/src/renderer/directives/style-map.js +72 -0
  111. package/src/theming/CustomStyle.js +23 -3
  112. package/src/theming/applyTheme.js +11 -10
  113. package/src/theming/getEffectiveLinksHrefs.js +20 -0
  114. package/src/theming/getStylesString.js +4 -2
  115. package/src/theming/getThemeDesignerTheme.js +25 -5
  116. package/src/theming/preloadLinks.js +23 -0
  117. package/src/updateShadowRoot.js +8 -4
  118. package/src/util/FocusableElements.js +8 -6
  119. package/src/util/createLinkInHead.js +19 -0
  120. package/src/util/escapeRegex.js +10 -0
  121. package/src/util/generateHighlightedMarkup.js +42 -0
  122. package/src/util/isNodeHidden.js +1 -1
  123. package/used-modules.txt +4 -1
  124. package/dist/config/AssetsPath.js +0 -17
  125. package/dist/theming/createThemePropertiesStyleTag.js +0 -20
  126. package/dist/util/encodeCSS.js +0 -24
  127. package/src/config/AssetsPath.js +0 -17
  128. package/src/theming/createThemePropertiesStyleTag.js +0 -20
  129. package/src/util/encodeCSS.js +0 -24
@@ -1,31 +1,10 @@
1
- import createStyleInHead from "./util/createStyleInHead.js";
2
-
3
- const systemCSSVars = `
4
- :root {
5
- --_ui5_content_density:cozy;
6
- }
7
-
8
- [data-ui5-compact-size],
9
- .ui5-content-density-compact,
10
- .sapUiSizeCompact {
11
- --_ui5_content_density:compact;
12
- }
13
-
14
- [dir="rtl"] {
15
- --_ui5_dir:rtl;
16
- }
17
-
18
- [dir="ltr"] {
19
- --_ui5_dir:ltr;
20
- }
21
- `;
1
+ import { hasStyle, createStyle } from "./ManagedStyles.js";
2
+ import systemCSSVars from "./generated/css/SystemCSSVars.css.js";
22
3
 
23
4
  const insertSystemCSSVars = () => {
24
- if (document.querySelector(`head>style[data-ui5-system-css-vars]`)) {
25
- return;
5
+ if (!hasStyle("data-ui5-system-css-vars")) {
6
+ createStyle(systemCSSVars, "data-ui5-system-css-vars");
26
7
  }
27
-
28
- createStyleInHead(systemCSSVars, { "data-ui5-system-css-vars": "" });
29
8
  };
30
9
 
31
10
  export default insertSystemCSSVars;
package/src/UI5Element.js CHANGED
@@ -18,7 +18,7 @@ import { isSlot, getSlotName, getSlottedElementsList } from "./util/SlotsHelper.
18
18
  import arraysAreEqual from "./util/arraysAreEqual.js";
19
19
  import getClassCopy from "./util/getClassCopy.js";
20
20
  import { markAsRtlAware } from "./locale/RTLAwareRegistry.js";
21
- import isLegacyBrowser from "./isLegacyBrowser.js";
21
+ import preloadLinks from "./theming/preloadLinks.js";
22
22
 
23
23
  let autoId = 0;
24
24
 
@@ -101,6 +101,9 @@ class UI5Element extends HTMLElement {
101
101
  */
102
102
  async connectedCallback() {
103
103
  this.setAttribute(this.constructor.getMetadata().getPureTag(), "");
104
+ if (this.constructor.getMetadata().supportsF6FastNavigation()) {
105
+ this.setAttribute("data-sap-ui-fastnavgroup", "true");
106
+ }
104
107
 
105
108
  const slotsAreManaged = this.constructor.getMetadata().slotsAreManaged();
106
109
 
@@ -251,7 +254,8 @@ class UI5Element extends HTMLElement {
251
254
 
252
255
  // Listen for any invalidation on the child if invalidateOnChildChange is true or an object (ignore when false or not set)
253
256
  if (child.isUI5Element && slotData.invalidateOnChildChange) {
254
- child.attachInvalidate(this._getChildChangeListener(slotName));
257
+ const method = (child.attachInvalidate || child._attachChange).bind(child);
258
+ method(this._getChildChangeListener(slotName));
255
259
  }
256
260
 
257
261
  // Listen for the slotchange event if the child is a slot itself
@@ -311,7 +315,8 @@ class UI5Element extends HTMLElement {
311
315
 
312
316
  children.forEach(child => {
313
317
  if (child && child.isUI5Element) {
314
- child.detachInvalidate(this._getChildChangeListener(slotName));
318
+ const method = (child.detachInvalidate || child._detachChange).bind(child);
319
+ method(this._getChildChangeListener(slotName));
315
320
  }
316
321
 
317
322
  if (isSlot(child)) {
@@ -607,25 +612,27 @@ class UI5Element extends HTMLElement {
607
612
 
608
613
  /**
609
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
610
616
  * Use this method instead of "this.shadowRoot" to read the Shadow DOM, if ever necessary
617
+ *
611
618
  * @public
612
619
  */
613
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
+
614
626
  if (!this.shadowRoot || this.shadowRoot.children.length === 0) {
615
627
  return;
616
628
  }
617
629
 
618
- this._assertShadowRootStructure();
619
-
620
- return this.shadowRoot.children.length === 1
621
- ? this.shadowRoot.children[0] : this.shadowRoot.children[1];
622
- }
623
-
624
- _assertShadowRootStructure() {
625
- const expectedChildrenCount = document.adoptedStyleSheets || isLegacyBrowser() ? 1 : 2;
626
- if (this.shadowRoot.children.length !== expectedChildrenCount) {
630
+ const children = [...this.shadowRoot.children].filter(child => !["link", "style"].includes(child.localName));
631
+ if (children.length !== 1) {
627
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
628
633
  }
634
+
635
+ return children[0];
629
636
  }
630
637
 
631
638
  /**
@@ -651,17 +658,6 @@ class UI5Element extends HTMLElement {
651
658
  return this.getFocusDomRef();
652
659
  }
653
660
 
654
- /**
655
- * Use this method in order to get a reference to an element in the shadow root of the web component or the static area item of the component
656
- * @public
657
- * @method
658
- * @param {String} refName Defines the name of the stable DOM ref
659
- */
660
- getStableDomRef(refName) {
661
- const staticAreaResult = this.staticAreaItem && this.staticAreaItem.getStableDomRef(refName);
662
- return staticAreaResult || this.getDomRef().querySelector(`[data-ui5-stable=${refName}]`);
663
- }
664
-
665
661
  /**
666
662
  * Set the focus to the element, returned by "getFocusDomRef()" (marked by "data-sap-focus-ref")
667
663
  * @public
@@ -988,6 +984,7 @@ class UI5Element extends HTMLElement {
988
984
  this._generateAccessors();
989
985
  registerTag(tag);
990
986
  window.customElements.define(tag, this);
987
+ preloadLinks(this);
991
988
 
992
989
  if (altTag && !customElements.get(altTag)) {
993
990
  registerTag(altTag);
@@ -126,7 +126,7 @@ class UI5ElementMetadata {
126
126
  */
127
127
  hasAttribute(propName) {
128
128
  const propData = this.getProperties()[propName];
129
- return propData.type !== Object && !propData.noAttribute;
129
+ return propData.type !== Object && !propData.noAttribute && !propData.multiple;
130
130
  }
131
131
 
132
132
  /**
@@ -188,6 +188,14 @@ class UI5ElementMetadata {
188
188
  return !!this.metadata.managedSlots;
189
189
  }
190
190
 
191
+ /**
192
+ * Determines whether this control supports F6 fast navigation
193
+ * @public
194
+ */
195
+ supportsF6FastNavigation() {
196
+ return !!this.metadata.fastNavigation;
197
+ }
198
+
191
199
  /**
192
200
  * Returns an object with key-value pairs of properties and their metadata definitions
193
201
  * @public
@@ -212,6 +220,14 @@ class UI5ElementMetadata {
212
220
  return !!this.metadata.languageAware;
213
221
  }
214
222
 
223
+ /**
224
+ * Determines whether this UI5 Element has any theme dependant carachteristics.
225
+ * @returns {boolean}
226
+ */
227
+ isThemeAware() {
228
+ return !!this.metadata.themeAware;
229
+ }
230
+
215
231
  /**
216
232
  * Matches a changed entity (property/slot) with the given name against the "invalidateOnChildChange" configuration
217
233
  * and determines whether this should cause and invalidation
@@ -1,11 +1,12 @@
1
1
  import getSharedResource from "../getSharedResource.js";
2
+ import IconCollectionsAlias from "../assets-meta/IconCollectionsAlias.js";
3
+ import { isTheme } from "../config/Theme.js";
2
4
 
3
5
  const loaders = new Map();
4
6
  const registry = getSharedResource("SVGIcons.registry", new Map());
5
7
  const iconCollectionPromises = getSharedResource("SVGIcons.promises", new Map());
6
8
 
7
9
  const ICON_NOT_FOUND = "ICON_NOT_FOUND";
8
- const DEFAULT_COLLECTION = "SAP-icons";
9
10
 
10
11
  /**
11
12
  * @deprecated
@@ -47,7 +48,7 @@ const _fillRegistry = bundleData => {
47
48
  // set
48
49
  const registerIcon = (name, { pathData, ltr, accData, collection, packageName } = {}) => { // eslint-disable-line
49
50
  if (!collection) {
50
- collection = DEFAULT_COLLECTION;
51
+ collection = _getDefaultCollection();
51
52
  }
52
53
 
53
54
  const key = `${collection}/${name}`;
@@ -67,18 +68,16 @@ const _parseName = name => {
67
68
 
68
69
  let collection;
69
70
  [name, collection] = name.split("/").reverse();
70
- collection = collection || DEFAULT_COLLECTION;
71
- // hardcoded alias in case icon explorer is used, resolve `SAP-icons-TNT` to `tnt`
72
- // aliases can be made a feature in the future if more collections need it or more aliases are needed.
73
- if (collection === "SAP-icons-TNT") {
74
- collection = "tnt";
75
- }
76
- // hardcoded alias in case icon explorer is used, resolve `BusinessSuiteInAppSymbols` to `business-suite`
77
- // aliases can be made a feature in the future if more collections need it or more aliases are needed.
78
- if (collection === "BusinessSuiteInAppSymbols") {
79
- collection = "business-suite";
80
- name = name.replace("icon-", "");
81
- }
71
+ collection = collection || _getDefaultCollection();
72
+
73
+ // Normalize collection name.
74
+ // - resolve `SAP-icons-TNT` to `tnt`.
75
+ // - resolve `BusinessSuiteInAppSymbols` to `business-suite`.
76
+ // - resolve `horizon` to `SAP-icons-v5`,
77
+ // Note: aliases can be made as a feature, if more collections need it or more aliases are needed.
78
+ collection = _normalizeCollection(collection);
79
+ name = name.replace("icon-", "");
80
+
82
81
  const registryKey = `${collection}/${name}`;
83
82
  return { name, collection, registryKey };
84
83
  };
@@ -118,6 +117,18 @@ const _getRegisteredNames = async () => {
118
117
  return Array.from(registry.keys());
119
118
  };
120
119
 
120
+ const _getDefaultCollection = () => {
121
+ return isTheme("sap_horizon") ? "SAP-icons-v5" : "SAP-icons";
122
+ };
123
+
124
+ const _normalizeCollection = collectionName => {
125
+ if (IconCollectionsAlias[collectionName]) {
126
+ return IconCollectionsAlias[collectionName];
127
+ }
128
+
129
+ return collectionName;
130
+ };
131
+
121
132
  export {
122
133
  registerIconBundle,
123
134
  registerIconLoader,
@@ -3,8 +3,8 @@ import getSharedResource from "../getSharedResource.js";
3
3
  const registry = getSharedResource("SVGIllustration.registry", new Map());
4
4
  const ILLUSTRATION_NOT_FOUND = "ILLUSTRATION_NOT_FOUND";
5
5
 
6
- const registerIllustration = (name, { dialogSvg, sceneSvg, spotSvg, title, subtitle } = {}) => { // eslint-disable-line
7
- registry.set(name, {
6
+ const registerIllustration = (name, { dialogSvg, sceneSvg, spotSvg, set, title, subtitle } = {}) => { // eslint-disable-line
7
+ registry.set(`${set}/${name}`, {
8
8
  dialogSvg,
9
9
  sceneSvg,
10
10
  spotSvg,
@@ -14,7 +14,14 @@ const registerIllustration = (name, { dialogSvg, sceneSvg, spotSvg, title, subti
14
14
  };
15
15
 
16
16
  const getIllustrationDataSync = nameProp => {
17
- return registry.get(nameProp) || ILLUSTRATION_NOT_FOUND;
17
+ let set = "fiori";
18
+
19
+ if (nameProp.startsWith("Tnt")) {
20
+ set = "tnt";
21
+ nameProp = nameProp.replace(/^Tnt/, "");
22
+ }
23
+
24
+ return registry.get(`${set}/${nameProp}`) || ILLUSTRATION_NOT_FOUND;
18
25
  };
19
26
 
20
27
  export {
@@ -16,11 +16,20 @@ const M_ISO639_OLD_TO_NEW = {
16
16
  "sh": "sr",
17
17
  };
18
18
 
19
+ const DEV_MODE = false;
20
+
19
21
  const _showAssetsWarningOnce = localeId => {
20
- if (!warningShown) {
22
+ if (warningShown) {
23
+ return;
24
+ }
25
+
26
+ if (!DEV_MODE) {
21
27
  console.warn(`[LocaleData] Supported locale "${localeId}" not configured, import the "Assets.js" module from the webcomponents package you are using.`); /* eslint-disable-line */
22
- warningShown = true;
28
+ } else {
29
+ console.warn(`[LocaleData] Note: in dev mode, CLDR assets might be disabled for performance reasons. Try running "ENABLE_CLDR=1 yarn start" to test CLDR assets.`); /* eslint-disable-line */
23
30
  }
31
+
32
+ warningShown = true;
24
33
  };
25
34
 
26
35
  const calcLocale = (language, region, script) => {
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Supported icon collection names and aliases.
3
+ *
4
+ * Users might specify a collection, using both the key and the value in the following key-value pairs,
5
+ * e.g the following pairs are completely exchangeable:
6
+ * "SAP-icons-TNT/actor" and "tnt/actor", "BusinessSuiteInAppSymbols/3d" and "business-suite/3d",
7
+ * "SAP-icons-v5/accept" and "horizon/accept".
8
+ *
9
+ * Note: technically, in the code we maintain the collections under the "value" name - "tnt", "business-suite",
10
+ * SAP-icons-v5" and "SAP-icons"(which does not have an alias).
11
+ */
12
+ const IconCollectionsAlias = {
13
+ "SAP-icons-TNT": "tnt",
14
+ "BusinessSuiteInAppSymbols": "business-suite",
15
+ "horizon": "SAP-icons-v5",
16
+ };
17
+
18
+ export default IconCollectionsAlias;
@@ -1,4 +1,5 @@
1
1
  import { getTheme as getConfiguredTheme } from "../InitialConfiguration.js";
2
+ import { reRenderAllUI5Elements } from "../Render.js";
2
3
  import applyTheme from "../theming/applyTheme.js";
3
4
 
4
5
  let theme;
@@ -20,9 +21,22 @@ const setTheme = async newTheme => {
20
21
 
21
22
  // Update CSS Custom Properties
22
23
  await applyTheme(theme);
24
+ await reRenderAllUI5Elements({ themeAware: true });
25
+ };
26
+
27
+ /**
28
+ * Returns if the given theme name is the one currently applied.
29
+ * @private
30
+ * @param {String}
31
+ * @returns {boolean}
32
+ */
33
+ const isTheme = _theme => {
34
+ const currentTheme = getTheme();
35
+ return currentTheme === _theme || currentTheme === `${_theme}_exp`;
23
36
  };
24
37
 
25
38
  export {
26
39
  getTheme,
27
40
  setTheme,
41
+ isTheme,
28
42
  };
@@ -0,0 +1,45 @@
1
+ @font-face {
2
+ font-family: "72";
3
+ font-style: normal;
4
+ font-weight: 400;
5
+ src: local("72"),
6
+ url(https://ui5.sap.com/sdk/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular.woff2?ui5-webcomponents) format("woff2"),
7
+ url(https://ui5.sap.com/sdk/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular.woff?ui5-webcomponents) format("woff");
8
+ }
9
+
10
+ @font-face {
11
+ font-family: "72full";
12
+ font-style: normal;
13
+ font-weight: 400;
14
+ src: local('72-full'),
15
+ url(https://ui5.sap.com/sdk/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular-full.woff2?ui5-webcomponents) format("woff2"),
16
+ url(https://ui5.sap.com/sdk/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular-full.woff?ui5-webcomponents) format("woff");
17
+
18
+ }
19
+
20
+ @font-face {
21
+ font-family: "72";
22
+ font-style: normal;
23
+ font-weight: 700;
24
+ src: local('72-Bold'),
25
+ url(https://ui5.sap.com/sdk/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold.woff2?ui5-webcomponents) format("woff2"),
26
+ url(https://ui5.sap.com/sdk/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold.woff?ui5-webcomponents) format("woff");
27
+ }
28
+
29
+ @font-face {
30
+ font-family: "72full";
31
+ font-style: normal;
32
+ font-weight: 700;
33
+ src: local('72-Bold-full'),
34
+ url(https://ui5.sap.com/sdk/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold-full.woff2?ui5-webcomponents) format("woff2"),
35
+ url(https://ui5.sap.com/sdk/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold-full.woff?ui5-webcomponents) format("woff");
36
+ }
37
+
38
+ @font-face {
39
+ font-family: "72Black";
40
+ font-style: bold;
41
+ font-weight: 900;
42
+ src: local('72Black'),
43
+ url(https://openui5nightly.hana.ondemand.com/resources/sap/ui/core/themes/sap_horizon/fonts/72-Black.woff2?ui5-webcomponents) format("woff2"),
44
+ url(https://openui5nightly.hana.ondemand.com/resources/sap/ui/core/themes/sap_horizon/fonts/72-Black.woff?ui5-webcomponents) format("woff");
45
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Some diacritics are supported by the 72 font:
3
+ * * Grave
4
+ * * Acute
5
+ * * Circumflex
6
+ * * Tilde
7
+ *
8
+ * However, the following diacritics and the combination of multiple diacritics (including the supported ones) are not supported:
9
+ * * Breve
10
+ * * Horn
11
+ * * Dot below
12
+ * * Hook above
13
+ *
14
+ *
15
+ * Override for the characters that aren't covered by the '72' font to other system fonts
16
+ *
17
+ * U+0102-0103: A and a with Breve
18
+ * U+01A0-01A1: O and o with Horn
19
+ * U+01AF-01B0: U and u with Horn
20
+ * U+1EA0-1EB7: A and a with diacritics that are not supported by the font and combination of multiple diacritics
21
+ * U+1EB8-1EC7: E and e with diacritics that are not supported by the font and combination of multiple diacritics
22
+ * U+1EC8-1ECB: I and i with diacritics that are not supported by the font and combination of multiple diacritics
23
+ * U+1ECC-1EE3: O and o with diacritics that are not supported by the font and combination of multiple diacritics
24
+ * U+1EE4-1EF1: U and u with diacritics that are not supported by the font and combination of multiple diacritics
25
+ * U+1EF4-1EF7: Y and y with diacritics that are not supported by the font and combination of multiple diacritics
26
+ *
27
+ */
28
+ @font-face {
29
+ font-family: '72override';
30
+ unicode-range: U+0102-0103, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EB7, U+1EB8-1EC7, U+1EC8-1ECB, U+1ECC-1EE3, U+1EE4-1EF1, U+1EF4-1EF7;
31
+ src: local('Arial'), local('Helvetica'), local('sans-serif');
32
+ }
@@ -0,0 +1,17 @@
1
+ :root {
2
+ --_ui5_content_density:cozy;
3
+ }
4
+
5
+ [data-ui5-compact-size],
6
+ .ui5-content-density-compact,
7
+ .sapUiSizeCompact {
8
+ --_ui5_content_density:compact;
9
+ }
10
+
11
+ [dir="rtl"] {
12
+ --_ui5_dir:rtl;
13
+ }
14
+
15
+ [dir="ltr"] {
16
+ --_ui5_dir:ltr;
17
+ }
@@ -5,6 +5,8 @@ import {
5
5
  isRight,
6
6
  isHome,
7
7
  isEnd,
8
+ isPageDown,
9
+ isPageUp,
8
10
  } from "../Keys.js";
9
11
  import getActiveElement from "../util/getActiveElement.js";
10
12
 
@@ -52,6 +54,7 @@ class ItemNavigation {
52
54
  * - currentIndex: the index of the item that will be initially selected (from which navigation will begin)
53
55
  * - navigationMode (Auto|Horizontal|Vertical): whether the items are displayed horizontally (Horizontal), vertically (Vertical) or as a matrix (Auto) meaning the user can navigate in both directions (up/down and left/right)
54
56
  * - rowSize: tells how many items per row there are when the items are not rendered as a flat list but rather as a matrix. Relevant for navigationMode=Auto
57
+ * - skipItemsSize: tells how many items upon PAGE_UP and PAGE_DOWN should be skipped to applying the focus on the next item
55
58
  * - behavior (Static|Cycling): tells what to do when trying to navigate beyond the first and last items
56
59
  * Static means that nothing happens if the user tries to navigate beyond the first/last item.
57
60
  * Cycling means that when the user navigates beyond the last item they go to the first and vice versa.
@@ -85,6 +88,7 @@ class ItemNavigation {
85
88
  this._behavior = options.behavior || ItemNavigationBehavior.Static;
86
89
  this._navigationMode = options.navigationMode || NavigationMode.Auto;
87
90
  this._affectedPropertiesNames = options.affectedPropertiesNames || [];
91
+ this._skipItemsSize = options.skipItemsSize || null;
88
92
  }
89
93
 
90
94
  /**
@@ -142,6 +146,10 @@ class ItemNavigation {
142
146
  this._handleHome();
143
147
  } else if (isEnd(event)) {
144
148
  this._handleEnd();
149
+ } else if (isPageUp(event)) {
150
+ this._handlePageUp();
151
+ } else if (isPageDown(event)) {
152
+ this._handlePageDown();
145
153
  } else {
146
154
  return; // if none of the supported keys is pressed, we don't want to prevent the event or update the item navigation
147
155
  }
@@ -222,6 +230,64 @@ class ItemNavigation {
222
230
  this._currentIndex += (homeEndRange - 1 - this._currentIndex % homeEndRange); // eslint-disable-line
223
231
  }
224
232
 
233
+ _handlePageUp() {
234
+ if (this._rowSize > 1) {
235
+ // eslint-disable-next-line
236
+ // TODO: handle page up on matrix (grid) layout - ColorPalette, ProductSwitch.
237
+ return;
238
+ }
239
+ this._handlePageUpFlat();
240
+ }
241
+
242
+ _handlePageDown() {
243
+ if (this._rowSize > 1) {
244
+ // eslint-disable-next-line
245
+ // TODO: handle page up on matrix (grid) layout - ColorPalette, ProductSwitch.
246
+ return;
247
+ }
248
+ this._handlePageDownFlat();
249
+ }
250
+
251
+ /**
252
+ * Handles PAGE_UP in a flat list-like structure, both vertically and horizontally.
253
+ */
254
+ _handlePageUpFlat() {
255
+ if (this._skipItemsSize === null) {
256
+ // Move the focus to the very top (as Home).
257
+ this._currentIndex -= this._currentIndex;
258
+ }
259
+
260
+ if (this._currentIndex + 1 > this._skipItemsSize) {
261
+ // When there are more than "skipItemsSize" number of items to the top,
262
+ // move the focus up/left with the predefined number.
263
+ this._currentIndex -= this._skipItemsSize;
264
+ } else {
265
+ // Otherwise, move the focus to the very top (as Home).
266
+ this._currentIndex -= this._currentIndex;
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Handles PAGE_DOWN in a flat list-like structure, both vertically and horizontally.
272
+ */
273
+ _handlePageDownFlat() {
274
+ if (this._skipItemsSize === null) {
275
+ // Move the focus to the very bottom (as End).
276
+ this._currentIndex = this._getItems().length - 1;
277
+ }
278
+
279
+ const currentToEndRange = this._getItems().length - this._currentIndex - 1;
280
+
281
+ if (currentToEndRange > this._skipItemsSize) {
282
+ // When there are more than "skipItemsSize" number of items until the bottom,
283
+ // move the focus down/right with the predefined number.
284
+ this._currentIndex += this._skipItemsSize;
285
+ } else {
286
+ // Otherwise, move the focus to the very bottom (as End).
287
+ this._currentIndex = this._getItems().length - 1;
288
+ }
289
+ }
290
+
225
291
  _applyTabIndex() {
226
292
  const items = this._getItems();
227
293
  for (let i = 0; i < items.length; i++) {
@@ -0,0 +1,106 @@
1
+ import { registerFeature } from "../FeaturesRegistry.js";
2
+ import { isF6Next, isF6Previous } from "../Keys.js";
3
+ import { getFirstFocusableElement } from "../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;