@ui5/webcomponents-base 0.0.0-96e98c995 → 0.0.0-974b11d82

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 (107) hide show
  1. package/.eslintignore +1 -0
  2. package/CHANGELOG.md +53 -0
  3. package/bundle.esm.js +3 -1
  4. package/dist/Boot.js +4 -0
  5. package/dist/Boot.js.map +1 -1
  6. package/dist/Device.js +109 -34
  7. package/dist/Device.js.map +1 -1
  8. package/dist/InitialConfiguration.js +1 -1
  9. package/dist/InitialConfiguration.js.map +1 -1
  10. package/dist/UI5Element.d.ts +19 -8
  11. package/dist/UI5Element.js +3 -2
  12. package/dist/UI5Element.js.map +1 -1
  13. package/dist/api.json +1 -1
  14. package/dist/asset-registries/Icons.d.ts +1 -1
  15. package/dist/asset-registries/Icons.js +21 -21
  16. package/dist/asset-registries/Icons.js.map +1 -1
  17. package/dist/asset-registries/Illustrations.d.ts +1 -1
  18. package/dist/asset-registries/Themes.d.ts +1 -0
  19. package/dist/assets/bundle.esm.ea2cc5c5.js +60 -0
  20. package/dist/assets-meta/IconCollectionsAlias.d.ts +24 -10
  21. package/dist/assets-meta/IconCollectionsAlias.js +29 -9
  22. package/dist/assets-meta/IconCollectionsAlias.js.map +1 -1
  23. package/dist/config/FormatSettings.d.ts +5 -1
  24. package/dist/config/FormatSettings.js +5 -1
  25. package/dist/config/FormatSettings.js.map +1 -1
  26. package/dist/config/Icons.d.ts +43 -18
  27. package/dist/config/Icons.js +80 -25
  28. package/dist/config/Icons.js.map +1 -1
  29. package/dist/config/RTL.js +3 -0
  30. package/dist/config/RTL.js.map +1 -1
  31. package/dist/decorators/customElement.d.ts +17 -2
  32. package/dist/decorators/customElement.js +17 -2
  33. package/dist/decorators/customElement.js.map +1 -1
  34. package/dist/delegate/ResizeHandler.d.ts +2 -1
  35. package/dist/delegate/ResizeHandler.js +3 -1
  36. package/dist/delegate/ResizeHandler.js.map +1 -1
  37. package/dist/features/F6Navigation.d.ts +3 -0
  38. package/dist/features/F6Navigation.js +77 -38
  39. package/dist/features/F6Navigation.js.map +1 -1
  40. package/dist/features/LegacyDateFormats.d.ts +18 -0
  41. package/dist/features/LegacyDateFormats.js +20 -0
  42. package/dist/features/LegacyDateFormats.js.map +1 -0
  43. package/dist/features/OpenUI5Support.d.ts +2 -0
  44. package/dist/features/OpenUI5Support.js +1 -0
  45. package/dist/features/OpenUI5Support.js.map +1 -1
  46. package/dist/generated/VersionInfo.js +3 -3
  47. package/dist/generated/css/BusyIndicator.css.d.ts +3 -0
  48. package/dist/generated/css/BusyIndicator.css.js +7 -5
  49. package/dist/generated/css/BusyIndicator.css.js.map +1 -0
  50. package/dist/generated/css/FontFace.css.d.ts +3 -0
  51. package/dist/generated/css/FontFace.css.js +7 -5
  52. package/dist/generated/css/FontFace.css.js.map +1 -0
  53. package/dist/generated/css/OverrideFontFace.css.d.ts +3 -0
  54. package/dist/generated/css/OverrideFontFace.css.js +7 -5
  55. package/dist/generated/css/OverrideFontFace.css.js.map +1 -0
  56. package/dist/generated/css/SystemCSSVars.css.d.ts +3 -0
  57. package/dist/generated/css/SystemCSSVars.css.js +7 -5
  58. package/dist/generated/css/SystemCSSVars.css.js.map +1 -0
  59. package/dist/getSharedResource.js +9 -1
  60. package/dist/getSharedResource.js.map +1 -1
  61. package/dist/global.d.ts +0 -6
  62. package/dist/renderer/LitRenderer.d.ts +3 -3
  63. package/dist/renderer/LitRenderer.js.map +1 -1
  64. package/dist/theming/CustomStyle.js +7 -5
  65. package/dist/theming/CustomStyle.js.map +1 -1
  66. package/dist/theming/getStylesString.d.ts +1 -1
  67. package/dist/updateShadowRoot.js +4 -0
  68. package/dist/updateShadowRoot.js.map +1 -1
  69. package/dist/util/AriaLabelHelper.d.ts +10 -1
  70. package/dist/util/AriaLabelHelper.js +135 -8
  71. package/dist/util/AriaLabelHelper.js.map +1 -1
  72. package/dist/util/FocusableElements.js +11 -2
  73. package/dist/util/FocusableElements.js.map +1 -1
  74. package/dist/util/getClassCopy.d.ts +8 -9
  75. package/lib/generate-styles/index.js +10 -5
  76. package/package-scripts.js +8 -4
  77. package/package.json +2 -2
  78. package/src/Boot.ts +4 -0
  79. package/src/Device.ts +113 -34
  80. package/src/InitialConfiguration.ts +1 -1
  81. package/src/UI5Element.ts +28 -8
  82. package/src/asset-registries/Icons.ts +26 -27
  83. package/src/asset-registries/Illustrations.ts +1 -1
  84. package/src/asset-registries/Themes.ts +5 -0
  85. package/src/assets-meta/IconCollectionsAlias.ts +32 -9
  86. package/src/config/FormatSettings.ts +16 -2
  87. package/src/config/Icons.ts +92 -25
  88. package/src/config/RTL.ts +4 -0
  89. package/src/decorators/customElement.ts +42 -2
  90. package/src/delegate/ResizeHandler.ts +7 -2
  91. package/src/features/F6Navigation.ts +98 -44
  92. package/src/features/LegacyDateFormats.ts +40 -0
  93. package/src/features/OpenUI5Support.ts +5 -0
  94. package/src/generated/css/BusyIndicator.css.ts +9 -0
  95. package/src/generated/css/FontFace.css.ts +9 -0
  96. package/src/generated/css/OverrideFontFace.css.ts +9 -0
  97. package/src/generated/css/SystemCSSVars.css.ts +9 -0
  98. package/src/getSharedResource.ts +10 -1
  99. package/src/global.d.ts +0 -6
  100. package/src/renderer/LitRenderer.ts +2 -2
  101. package/src/theming/CustomStyle.ts +7 -5
  102. package/src/theming/getEffectiveLinksHrefs.ts +1 -1
  103. package/src/theming/getStylesString.ts +1 -1
  104. package/src/updateShadowRoot.ts +5 -0
  105. package/src/util/AriaLabelHelper.ts +167 -12
  106. package/src/util/FocusableElements.ts +12 -2
  107. package/dist/assets/bundle.esm.ba5d36d4.js +0 -56
@@ -1,59 +1,126 @@
1
1
  import { getTheme, isThemeFamily } from "./Theme.js";
2
+ import { getIconCollectionByAlias } from "../assets-meta/IconCollectionsAlias.js";
2
3
 
3
4
  const IconCollectionConfiguration = new Map<string, string>();
4
5
 
5
- enum IconCollection {
6
- v4 = "SAP-icons",
7
- v5 = "SAP-icons-v5",
6
+ // All supported icon collections + unknown custom ones
7
+ type IconCollection = "SAP-icons" | "SAP-icons-v4" | "SAP-icons-v5" | "horizon" | "tnt" | "tnt-v2" | "tnt-v3" | "business-suite" | "business-suite-v1" | "business-suite-v2" | string;
8
+
9
+ // All registered icon collections - all icon collections resolves to these options at the end
10
+ enum RegisteredIconCollection {
11
+ SAPIconsV4 = "SAP-icons-v4",
12
+ SAPIconsV5 = "SAP-icons-v5",
13
+ SAPIconsTNTV2 = "tnt-v2",
14
+ SAPIconsTNTV3 = "tnt-v3",
15
+ SAPBSIconsV1 = "business-suite-v1",
16
+ SAPBSIconsV2 = "business-suite-v2",
8
17
  }
9
18
 
10
19
  /**
11
- * Sets the default icon collection (SAP-icons font v4 or SAP-icons font v5) per theme,
12
- * which will be applied in case icon collection is not specified.
20
+ * Sets the default icon collection for a given theme.
21
+ *
22
+ * SAP Icons is the default icon collection (that resolves to SAP-icons version 5.x in Horizon theme family and SAP-icons version 4.x in all other themes)
23
+ * and to display icons from other collections, you have to specify the icon collection in addition to the icon name, for example: "tnt/actor", "business-suite/1x2-grid-layout", etc.
24
+ * This method allows setting another (built-in or custom) icon collection as default per theme.
25
+ *
26
+ * <b>Usage</b>
27
+ * <b>For example</b>, to make "SAP-icons version 5.x" the default icon collection in "sap_fiori_3":
28
+ *
29
+ * <pre>
30
+ * setDefaultIconCollection("sap_fiori_3", "SAP-icons-v5");
31
+ *
32
+ * <ui5-icon name="home"></ui5-icon>
33
+ * </pre>
34
+ *
35
+ * <b>For example</b>, to make a custom icon collection (with name "my-custom-collection") the default icon collection in "sap_fiori_3":
36
+ *
37
+ * <pre>
38
+ * setDefaultIconCollection("sap_fiori_3", "my-custom-collection");
39
+ *
40
+ * <ui5-icon name="custom-icon-name"></ui5-icon>
41
+ * </pre>
13
42
  *
14
- * Note: by default SAP-icons-v5 is used in all SAP Horizon variants and SAP-icons-v4 for all the rest.
15
43
  * @public
16
- * @param {string} theme
17
- * @param {IconCollection} collectionName
44
+ * @param { string } theme
45
+ * @param { string } collectionName
18
46
  */
19
- const setDefaultIconCollection = (theme: string, collectionName: "horizon" | IconCollection) => {
20
- if (collectionName === "horizon") {
21
- collectionName = IconCollection.v5;
22
- }
23
-
47
+ const setDefaultIconCollection = (theme: string, collectionName: IconCollection) => {
24
48
  IconCollectionConfiguration.set(theme, collectionName);
25
49
  };
26
50
 
27
51
  /**
28
- * Returns the default icon collection (v4 or v5) for given theme,
29
- * that is configured.
52
+ * Returns the configured default icon collection for a given theme.
30
53
  *
31
- * @param {string} theme
54
+ * @param { string } theme
32
55
  * @public
33
- * @returns {string | undefined}
56
+ * @returns { string | undefined }
34
57
  */
35
58
  const getDefaultIconCollection = (theme: string): string | undefined => {
36
59
  return IconCollectionConfiguration.get(theme);
37
60
  };
38
61
 
39
62
  /**
40
- * Returns the effective icon collection that will be applied for icon web components
41
- * whenever namespace is not specified.
42
- * @returns {string}
63
+ * Returns the effective icon collection,
64
+ * based on the default icon collection configuration and the current theme:
65
+ * @param { IconCollection } collectionName
66
+ * @returns { IconCollection } the effective collection name
43
67
  */
44
- const getEffectiveDefaultIconCollection = () => {
68
+ const getEffectiveIconCollection = (collectionName?: IconCollection): IconCollection => {
45
69
  const currentTheme = getTheme();
46
70
  const currentThemeConfiguration = IconCollectionConfiguration.get(currentTheme);
47
71
 
48
- if (currentThemeConfiguration) {
49
- return currentThemeConfiguration;
72
+ // when no collection is set and default collection is configured - return the configured icon collection
73
+ if (!collectionName && currentThemeConfiguration) {
74
+ return getIconCollectionByAlias(currentThemeConfiguration);
50
75
  }
51
76
 
52
- return isThemeFamily("sap_horizon") ? IconCollection.v5 : IconCollection.v4;
77
+ // when collection is set - return the theme dependant icon collection
78
+ // when collection is not set and there is no default icon collection configured - return theme dependant icon collection
79
+ return getIconCollectionByTheme(collectionName);
80
+ };
81
+
82
+ /**
83
+ * Returns the icon theme dependant collection, based on the collection name and current theme as follows:
84
+ *
85
+ * - "no collection" resolves to "SAP-icons-v4" in "Quartz" and "Belize", and to "SAP-icons-v5" in "Horizon" (or as confugred via setDefaultIconCollection)
86
+ * - "SAP-icons-v4" (and its alias "SAP-icons") forces "SAP-icons v4" in any theme and resolves to itself "SAP-icons-v4"
87
+ * - "SAP-icons-v5" (and its alias "horizon") forces "SAP-icons v5" in any theme and resolves to itself "SAP-icons-v5"
88
+ * - "tnt" (and its alias "SAP-icons-TNT") resolves to "tnt-v2" in "Quartz", "Belize", and resolves to "tnt-v3" in "Horizon"
89
+ * - "tnt-v2" forces "TNT icons v2" in any theme and resolves to itself "tnt-v2"
90
+ * - "tnt-v3" forces "TNT icons v3" in any theme and resolves to itself "tnt-v3"
91
+ * - "business-suite" (and its alias "BusinessSuiteInAppSymbols") resolves to "business-suite-v1" in "Quartz", "Belize", and resolves to "business-suite-v2" in "Horizon"
92
+ * - "business-suite-v1" forces "Business Suite icons v1" in any theme and resolves to itself "business-suite-v1"
93
+ * - "business-suite-v2" forces "Business Suite icons v2" in any theme and resolves to itself "business-suite-v2"
94
+ *
95
+ * <b>Note:</b> "SAP-icons-v4", "SAP-icons-v5", "tnt-v2", "tnt-v3", "business-suite-v1" and "business-suite-v2" are just returned
96
+ * @param { IconCollection } collectionName
97
+ * @returns { RegisteredIconCollection } the registered collection name
98
+ */
99
+ const getIconCollectionByTheme = (collectionName?: IconCollection): RegisteredIconCollection => {
100
+ const horizonThemeFamily = isThemeFamily("sap_horizon");
101
+
102
+ if (!collectionName) {
103
+ return horizonThemeFamily ? RegisteredIconCollection.SAPIconsV5 : RegisteredIconCollection.SAPIconsV4;
104
+ }
105
+
106
+ if (collectionName === "tnt") {
107
+ return horizonThemeFamily ? RegisteredIconCollection.SAPIconsTNTV3 : RegisteredIconCollection.SAPIconsTNTV2;
108
+ }
109
+
110
+ if (collectionName === "business-suite") {
111
+ return horizonThemeFamily ? RegisteredIconCollection.SAPBSIconsV2 : RegisteredIconCollection.SAPBSIconsV1;
112
+ }
113
+
114
+ return collectionName as RegisteredIconCollection;
53
115
  };
54
116
 
55
117
  export {
56
118
  setDefaultIconCollection,
57
119
  getDefaultIconCollection,
58
- getEffectiveDefaultIconCollection,
120
+ getEffectiveIconCollection,
121
+ RegisteredIconCollection,
122
+ };
123
+
124
+ export type {
125
+ IconCollection,
59
126
  };
package/src/config/RTL.ts CHANGED
@@ -29,6 +29,10 @@ const impliesRTL = (language: string) => {
29
29
  * @returns {boolean} whether RTL should be used
30
30
  */
31
31
  const getRTL = (): boolean => {
32
+ if (typeof document === "undefined") {
33
+ return false;
34
+ }
35
+
32
36
  const configurationRTL = getConfiguredRTL();
33
37
 
34
38
  if (configurationRTL !== undefined) {
@@ -1,16 +1,56 @@
1
+ import type UI5Element from "../UI5Element.js";
2
+ import type { Renderer } from "../UI5Element.js";
3
+ import type { TemplateFunction as Template } from "../renderer/executeTemplate.js";
4
+ import type { ComponentStylesData as Styles } from "../types.js";
5
+
1
6
  /**
2
7
  * Returns a custom element class decorator.
3
8
  *
4
- * @param { string } tag
9
+ * @param { string | object } tagNameOrComponentSettings
5
10
  * @returns { ClassDecorator }
6
11
  */
7
- const customElement = (tag: string): ClassDecorator => {
12
+ const customElement = (tagNameOrComponentSettings: string | {
13
+ tag?: string,
14
+ renderer?: Renderer,
15
+ styles?: Styles,
16
+ template?: Template,
17
+ dependencies?: Array<typeof UI5Element>,
18
+ staticAreaStyles?: Styles,
19
+ staticAreaTemplate?: Template,
20
+ languageAware?: boolean,
21
+ themeAware?: boolean,
22
+ fastNavigation?: boolean,
23
+ }): ClassDecorator => {
8
24
  return (target: any) => {
9
25
  if (!Object.prototype.hasOwnProperty.call(target, "decoratorMetadata")) {
10
26
  target.decoratorMetadata = {};
11
27
  }
12
28
 
29
+ if (typeof tagNameOrComponentSettings === "string") {
30
+ target.decoratorMetadata.tag = tagNameOrComponentSettings;
31
+ return;
32
+ }
33
+
34
+ const {
35
+ tag,
36
+ languageAware = false,
37
+ themeAware = false,
38
+ fastNavigation = false,
39
+ } = tagNameOrComponentSettings;
40
+
13
41
  target.decoratorMetadata.tag = tag;
42
+ target.decoratorMetadata.languageAware = languageAware;
43
+ target.decoratorMetadata.themeAware = themeAware;
44
+ target.decoratorMetadata.fastNavigation = fastNavigation;
45
+
46
+ ["render", "renderer", "template", "staticAreaTemplate", "styles", "staticAreaStyles", "dependencies"].forEach((customElementEntity: string) => {
47
+ const _customElementEntity = customElementEntity === "render" ? "renderer" : customElementEntity;
48
+ const customElementEntityValue = tagNameOrComponentSettings[_customElementEntity as keyof typeof tag];
49
+
50
+ customElementEntityValue && Object.defineProperty(target, customElementEntity, {
51
+ get: () => customElementEntityValue,
52
+ });
53
+ });
14
54
  };
15
55
  };
16
56
 
@@ -1,6 +1,6 @@
1
1
  import { instanceOfUI5Element } from "../UI5Element.js";
2
2
 
3
- type ResizeObserverCallback = () => void;
3
+ type ResizeObserverCallback = () => Promise<void> | void;
4
4
 
5
5
  let resizeObserver: ResizeObserver;
6
6
  const observedElements = new Map<HTMLElement, Array<ResizeObserverCallback>>();
@@ -10,7 +10,9 @@ const getResizeObserver = () => {
10
10
  resizeObserver = new window.ResizeObserver(entries => {
11
11
  entries.forEach(entry => {
12
12
  const callbacks = observedElements.get(entry.target as HTMLElement);
13
- callbacks?.forEach((callback: ResizeObserverCallback) => callback());
13
+ // Callbacks could be async and we need to handle returned promises to comply with the eslint "no-misused-promises" rule.
14
+ // Although Promise.all awaits all, we don't additonal task after calling the callbacks and should not make any difference.
15
+ callbacks && Promise.all(callbacks.map((callback: ResizeObserverCallback) => callback()));
14
16
  });
15
17
  });
16
18
  }
@@ -93,3 +95,6 @@ class ResizeHandler {
93
95
  }
94
96
 
95
97
  export default ResizeHandler;
98
+ export type {
99
+ ResizeObserverCallback,
100
+ };
@@ -3,6 +3,7 @@ import { isF6Next, isF6Previous } from "../Keys.js";
3
3
  import { instanceOfUI5Element } from "../UI5Element.js";
4
4
  import { getFirstFocusableElement } from "../util/FocusableElements.js";
5
5
  import getFastNavigationGroups from "../util/getFastNavigationGroups.js";
6
+ import isElementClickable from "../util/isElementClickable.js";
6
7
 
7
8
  class F6Navigation {
8
9
  static _instance: F6Navigation;
@@ -19,56 +20,61 @@ class F6Navigation {
19
20
  document.addEventListener("keydown", this.keydownHandler);
20
21
  }
21
22
 
22
- async _keydownHandler(event: KeyboardEvent) {
23
- if (isF6Next(event)) {
24
- this.updateGroups();
23
+ async groupElementToFocus(nextElement: HTMLElement) {
24
+ const nextElementDomRef = instanceOfUI5Element(nextElement) ? nextElement.getDomRef() : nextElement;
25
25
 
26
- if (this.groups.length < 1) {
27
- return;
26
+ if (nextElementDomRef) {
27
+ if (isElementClickable(nextElementDomRef)) {
28
+ return nextElementDomRef;
28
29
  }
29
30
 
30
- event.preventDefault();
31
+ const elementToFocus = await getFirstFocusableElement(nextElementDomRef);
31
32
 
32
- let nextIndex = -1;
33
- let nextElement;
34
- if (this.selectedGroup) {
35
- nextIndex = this.groups.indexOf(this.selectedGroup);
33
+ if (elementToFocus) {
34
+ return elementToFocus;
36
35
  }
36
+ }
37
+ }
38
+
39
+ async findNextFocusableGroupElement(currentIndex: number) {
40
+ let elementToFocus;
37
41
 
38
- if (nextIndex > -1) {
39
- if (nextIndex + 1 >= this.groups.length) {
40
- nextElement = this.groups[0];
42
+ /* eslint-disable no-await-in-loop */
43
+ for (let index = 0; index < this.groups.length; index++) {
44
+ let nextElement;
45
+
46
+ if (currentIndex > -1) {
47
+ if (currentIndex + 1 >= this.groups.length) {
48
+ currentIndex = 0;
49
+ nextElement = this.groups[currentIndex];
41
50
  } else {
42
- nextElement = this.groups[nextIndex + 1];
51
+ currentIndex += 1;
52
+ nextElement = this.groups[currentIndex];
43
53
  }
44
54
  } else {
45
- nextElement = this.groups[0];
55
+ currentIndex = 0;
56
+ nextElement = this.groups[currentIndex];
46
57
  }
47
58
 
48
- const nextElementDomRef = instanceOfUI5Element(nextElement) ? nextElement.getDomRef() : nextElement;
59
+ elementToFocus = await this.groupElementToFocus(nextElement);
49
60
 
50
- if (nextElementDomRef) {
51
- const elementToFocus = await getFirstFocusableElement(nextElementDomRef, true);
52
- elementToFocus?.focus();
61
+ if (elementToFocus) {
62
+ break;
53
63
  }
54
64
  }
65
+ /* eslint-enable no-await-in-loop */
55
66
 
56
- if (isF6Previous(event)) {
57
- this.updateGroups();
58
-
59
- if (this.groups.length < 1) {
60
- return;
61
- }
67
+ return elementToFocus;
68
+ }
62
69
 
63
- event.preventDefault();
70
+ async findPreviousFocusableGroupElement(currentIndex: number) {
71
+ let elementToFocus;
64
72
 
65
- let nextIndex = -1;
73
+ /* eslint-disable no-await-in-loop */
74
+ for (let index = 0; index < this.groups.length; index++) {
66
75
  let nextElement;
67
- if (this.selectedGroup) {
68
- nextIndex = this.groups.indexOf(this.selectedGroup);
69
- }
70
76
 
71
- if (nextIndex > 0) {
77
+ if (currentIndex > 0) {
72
78
  // Handle the situation where the first focusable element of two neighbor groups is the same
73
79
  // For example:
74
80
  // <ui5-flexible-column-layout>
@@ -77,22 +83,70 @@ class F6Navigation {
77
83
  // </ui5-list>
78
84
  // </ui5-flexible-column-layout>
79
85
  // Here for both FCL & List the firstFoccusableElement is the same (the ui5-li)
86
+ const firstFocusable = await this.groupElementToFocus(this.groups[currentIndex - 1]);
87
+ const shouldSkipParent = firstFocusable === await this.groupElementToFocus(this.groups[currentIndex]);
80
88
 
81
- const firstFocusable = await getFirstFocusableElement(this.groups[nextIndex - 1], true);
82
- const shouldSkipParent = firstFocusable === await getFirstFocusableElement(this.groups[nextIndex], true);
89
+ currentIndex = shouldSkipParent ? currentIndex - 2 : currentIndex - 1;
83
90
 
84
- nextElement = this.groups[shouldSkipParent ? nextIndex - 2 : nextIndex - 1];
91
+ if (currentIndex < 0) {
92
+ currentIndex = this.groups.length - 1;
93
+ }
94
+
95
+ nextElement = this.groups[currentIndex];
85
96
  } else {
86
- nextElement = this.groups[this.groups.length - 1];
97
+ currentIndex = this.groups.length - 1;
98
+ nextElement = this.groups[currentIndex];
87
99
  }
88
100
 
89
- const nextElementDomRef = instanceOfUI5Element(nextElement) ? nextElement.getDomRef() : nextElement;
101
+ elementToFocus = await this.groupElementToFocus(nextElement);
90
102
 
91
- if (nextElementDomRef) {
92
- const elementToFocus = await getFirstFocusableElement(nextElementDomRef, true);
93
- elementToFocus?.focus();
103
+ if (elementToFocus) {
104
+ break;
94
105
  }
95
106
  }
107
+ /* eslint-enable no-await-in-loop */
108
+
109
+ return elementToFocus;
110
+ }
111
+
112
+ async _keydownHandler(event: KeyboardEvent) {
113
+ const forward = isF6Next(event);
114
+ const backward = isF6Previous(event);
115
+ if (!(forward || backward)) {
116
+ return;
117
+ }
118
+
119
+ this.updateGroups();
120
+
121
+ if (this.groups.length < 1) {
122
+ return;
123
+ }
124
+
125
+ event.preventDefault();
126
+
127
+ let elementToFocus;
128
+
129
+ if (this.groups.length === 0) {
130
+ elementToFocus = await this.groupElementToFocus(this.groups[0]);
131
+
132
+ return elementToFocus?.focus();
133
+ }
134
+
135
+ let currentIndex = -1;
136
+
137
+ if (this.selectedGroup) {
138
+ currentIndex = this.groups.indexOf(this.selectedGroup);
139
+ }
140
+
141
+ if (forward) {
142
+ elementToFocus = await this.findNextFocusableGroupElement(currentIndex);
143
+ }
144
+
145
+ if (backward) {
146
+ elementToFocus = await this.findPreviousFocusableGroupElement(currentIndex);
147
+ }
148
+
149
+ elementToFocus?.focus();
96
150
  }
97
151
 
98
152
  removeEventListeners() {
@@ -109,19 +163,19 @@ class F6Navigation {
109
163
  let element: Element | null | ParentNode = this.deepActive(root);
110
164
 
111
165
  while (element && (element as Element).getAttribute("data-sap-ui-fastnavgroup") !== "true" && element !== htmlElement) {
112
- element = element.parentElement ? element.parentNode : (element.parentNode as ShadowRoot).host;
166
+ element = element.parentElement ? element.parentNode : (element.parentNode as ShadowRoot).host;
113
167
  }
114
168
 
115
169
  this.selectedGroup = element as HTMLElement;
116
- }
170
+ }
117
171
 
118
- deepActive(root: DocumentOrShadowRoot): Element | null {
172
+ deepActive(root: DocumentOrShadowRoot): Element | null {
119
173
  if (root.activeElement && root.activeElement.shadowRoot) {
120
- return this.deepActive(root.activeElement.shadowRoot);
174
+ return this.deepActive(root.activeElement.shadowRoot);
121
175
  }
122
176
 
123
177
  return root.activeElement;
124
- }
178
+ }
125
179
 
126
180
  destroy() {
127
181
  this.removeEventListeners();
@@ -0,0 +1,40 @@
1
+ import { getFormatSettings } from "../InitialConfiguration.js";
2
+ import type { FormatSettings } from "../config/FormatSettings.js";
3
+ import { registerFeature } from "../FeaturesRegistry.js";
4
+
5
+ // Allows specifying the customizing data for Islamic calendar support
6
+ // dateFormat - The date format
7
+ // islamicMonthStart - The Islamic date in string format // 14360101
8
+ // gregDate - Corresponding Gregorian date to the Islamic one in string format // 20141024
9
+ type IslamicToGregorianMapping = {
10
+ dateFormat: string,
11
+ islamicMonthStart: string,
12
+ gregDate: string,
13
+ };
14
+ type LegacyDateCalendarCustomizing = Array<IslamicToGregorianMapping>;
15
+
16
+ let formatSettings: FormatSettings;
17
+
18
+ class LegacyDateFormats {
19
+ /**
20
+ * Returns the currently set customizing data for Islamic calendar support
21
+ *
22
+ * @return {object[]} Returns an array that contains the customizing data.
23
+ * @public
24
+ */
25
+ static getLegacyDateCalendarCustomizing(this: void): LegacyDateCalendarCustomizing {
26
+ if (formatSettings === undefined) {
27
+ formatSettings = getFormatSettings();
28
+ }
29
+
30
+ return formatSettings.legacyDateCalendarCustomizing || [];
31
+ }
32
+ }
33
+
34
+ registerFeature("LegacyDateFormats", LegacyDateFormats);
35
+
36
+ export default LegacyDateFormats;
37
+ export type {
38
+ FormatSettings,
39
+ LegacyDateCalendarCustomizing,
40
+ };
@@ -2,6 +2,7 @@ import { registerFeature } from "../FeaturesRegistry.js";
2
2
  import { setTheme } from "../config/Theme.js";
3
3
  import { getCurrentZIndex } from "../util/PopupUtils.js";
4
4
  import { CLDRData } from "../asset-registries/LocaleData.js";
5
+ import type { LegacyDateCalendarCustomizing } from "../features/LegacyDateFormats.js";
5
6
 
6
7
  type OpenUI5Popup = {
7
8
  setInitialZIndex: (zIndex: number) => void,
@@ -22,6 +23,9 @@ type OpenUI5CoreConfiguration = {
22
23
  getRTL: () => string,
23
24
  getCalendarType: () => string,
24
25
  getLocale: () => string,
26
+ getFormatSettings: () => {
27
+ getLegacyDateCalendarCustomizing: () => LegacyDateCalendarCustomizing;
28
+ }
25
29
  };
26
30
 
27
31
  type LocaleData = {
@@ -76,6 +80,7 @@ class OpenUI5Support {
76
80
  calendarType: config.getCalendarType(),
77
81
  formatSettings: {
78
82
  firstDayOfWeek: LocaleData ? LocaleData.getInstance(config.getLocale()).getFirstDayOfWeek() : undefined,
83
+ legacyDateCalendarCustomizing: config.getFormatSettings().getLegacyDateCalendarCustomizing(),
79
84
  },
80
85
  };
81
86
  }
@@ -0,0 +1,9 @@
1
+ import type { StyleData } from "../../types.js";
2
+
3
+ const styleData: StyleData = {
4
+ packageName: "@ui5/webcomponents-base",
5
+ fileName: "BusyIndicator.css",
6
+ content: `.busy-indicator-wrapper{position:relative;height:100%;width:100%}.busy-indicator-overlay{display:var(--ui5_web_components_busy_indicator_display);position:absolute;inset:0;background:var(--ui5_web_components_busy_indicator_background-color);z-index:99}.busy-indicator-busy-area{display:var(--ui5_web_components_busy_indicator_display);position:absolute;z-index:99;inset:0;justify-content:center;align-items:center;background-color:inherit;flex-direction:column;color:var(--_ui5_busy_indicator_color)}:host([__is-busy]) .busy-indicator-wrapper>:not(.busy-indicator-busy-area):not(.busy-indicator-overlay):not([busy-indicator-before-span]){--ui5_web_components_busy_indicator_display:none}.busy-indicator-busy-area:focus{outline:var(--_ui5_busy_indicator_focus_outline);outline-offset:-.125rem}.busy-indicator-circle{width:1rem;height:1rem;display:inline-block;background-color:currentColor;border-radius:50%}.circle-animation-0{animation:grow 1.6s infinite cubic-bezier(.32,.06,.85,1.11)}.circle-animation-1{animation:grow 1.6s infinite cubic-bezier(.32,.06,.85,1.11);animation-delay:.2s}.circle-animation-2{animation:grow 1.6s infinite cubic-bezier(.32,.06,.85,1.11);animation-delay:.4s}.sapUiLocalBusy{--ui5_web_components_busy_indicator_display:none}.busy-indicator-wrapper [ui5-busy-indicator]{display:none}@keyframes grow{0%,100%,50%{-webkit-transform:scale(.5);-moz-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}25%{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}`,
7
+ };
8
+
9
+ export default styleData;
@@ -0,0 +1,9 @@
1
+ import type { StyleData } from "../../types.js";
2
+
3
+ const styleData: StyleData = {
4
+ packageName: "@ui5/webcomponents-base",
5
+ fileName: "FontFace.css",
6
+ content: `@font-face{font-family:"72";font-style:normal;font-weight:400;src:local("72"),url(https://sdk.openui5.org/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular.woff2?ui5-webcomponents) format("woff2")}@font-face{font-family:"72full";font-style:normal;font-weight:400;src:local('72-full'),url(https://sdk.openui5.org/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Regular-full.woff2?ui5-webcomponents) format("woff2")}@font-face{font-family:"72";font-style:normal;font-weight:700;src:local('72-Bold'),url(https://sdk.openui5.org/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold.woff2?ui5-webcomponents) format("woff2")}@font-face{font-family:"72full";font-style:normal;font-weight:700;src:local('72-Bold-full'),url(https://sdk.openui5.org/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold-full.woff2?ui5-webcomponents) format("woff2")}@font-face{font-family:'72-Bold';font-style:normal;src:local('72-Bold'),url(https://sdk.openui5.org/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold.woff2?ui5-webcomponents) format("woff2")}@font-face{font-family:'72-Boldfull';font-style:normal;src:url(https://sdk.openui5.org/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Bold-full.woff2?ui5-webcomponents) format("woff2")}@font-face{font-family:'72-Light';font-style:normal;src:local('72-Light'),url(https://sdk.openui5.org/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Light.woff2?ui5-webcomponents) format("woff2")}@font-face{font-family:'72-Lightfull';font-style:normal;src:url(https://sdk.openui5.org/resources/sap/ui/core/themes/sap_fiori_3/fonts/72-Light-full.woff2?ui5-webcomponents) format("woff2")}@font-face{font-family:"72Black";font-style:bold;font-weight:900;src:local('72Black'),url(https://sdk.openui5.org/resources/sap/ui/core/themes/sap_horizon/fonts/72-Black.woff2?ui5-webcomponents) format("woff2")}`,
7
+ };
8
+
9
+ export default styleData;
@@ -0,0 +1,9 @@
1
+ import type { StyleData } from "../../types.js";
2
+
3
+ const styleData: StyleData = {
4
+ packageName: "@ui5/webcomponents-base",
5
+ fileName: "OverrideFontFace.css",
6
+ content: `@font-face{font-family:'72override';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;src:local('Arial'),local('Helvetica'),local('sans-serif')}`,
7
+ };
8
+
9
+ export default styleData;
@@ -0,0 +1,9 @@
1
+ import type { StyleData } from "../../types.js";
2
+
3
+ const styleData: StyleData = {
4
+ packageName: "@ui5/webcomponents-base",
5
+ fileName: "SystemCSSVars.css",
6
+ content: `:root{--_ui5_content_density:cozy}.sapUiSizeCompact,.ui5-content-density-compact,[data-ui5-compact-size]{--_ui5_content_density:compact}[dir=rtl]{--_ui5_dir:rtl}[dir=ltr]{--_ui5_dir:ltr}`,
7
+ };
8
+
9
+ export default styleData;
@@ -1,6 +1,11 @@
1
1
  import getSingletonElementInstance from "./util/getSingletonElementInstance.js";
2
2
 
3
- const getSharedResourcesInstance = () => getSingletonElementInstance("ui5-shared-resources", document.head);
3
+ const getSharedResourcesInstance = (): Record<string, unknown> | null => {
4
+ if (typeof document === "undefined") {
5
+ return null;
6
+ }
7
+ return getSingletonElementInstance("ui5-shared-resources", document.head) as unknown as Record<string, unknown>;
8
+ };
4
9
 
5
10
  /**
6
11
  * Use this method to initialize/get resources that you would like to be shared among UI5 Web Components runtime instances.
@@ -15,6 +20,10 @@ const getSharedResource = <T>(namespace: string, initialValue: T): T => {
15
20
  const parts = namespace.split(".");
16
21
  let current = getSharedResourcesInstance() as Record<string, any>;
17
22
 
23
+ if (!current) {
24
+ return initialValue;
25
+ }
26
+
18
27
  for (let i = 0; i < parts.length; i++) {
19
28
  const part = parts[i];
20
29
  const lastPart = i === parts.length - 1;
package/src/global.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import { StyleData } from "./types.js";
2
-
3
1
  export {};
4
2
 
5
3
  declare global {
@@ -19,10 +17,6 @@ declare global {
19
17
  chrome: any;
20
18
  v8: any;
21
19
  }
22
- module "*.css.js" {
23
- const content: StyleData;
24
- export default content;
25
- }
26
20
 
27
21
  module "*generated/AssetParameters.js" {
28
22
  const DEFAULT_THEME: string;
@@ -3,13 +3,13 @@ import {
3
3
  html,
4
4
  svg,
5
5
  TemplateResult,
6
- RenderOptions,
7
6
  } from "lit-html";
8
7
 
9
8
  import { getFeature } from "../FeaturesRegistry.js";
10
9
  import type { LitStatic } from "../CustomElementsScope.js";
11
10
  import type OpenUI5Enablement from "../features/OpenUI5Enablement.js";
12
11
  import type UI5Element from "../UI5Element.js";
12
+ import type { Renderer, RendererOptions } from "../UI5Element.js";
13
13
  import { TemplateFunctionResult } from "./executeTemplate.js";
14
14
 
15
15
  const effectiveHtml = (strings: TemplateStringsArray, ...values: Array<unknown>) => {
@@ -24,7 +24,7 @@ const effectiveSvg = (strings: TemplateStringsArray, ...values: Array<unknown>)
24
24
  return fn(strings, ...values);
25
25
  };
26
26
 
27
- const litRender = (templateResult: TemplateFunctionResult, container: HTMLElement | DocumentFragment, styleStrOrHrefsArr: string | Array<string> | undefined, forStaticArea: boolean, options: RenderOptions) => {
27
+ const litRender: Renderer = (templateResult: TemplateFunctionResult, container: HTMLElement | DocumentFragment, styleStrOrHrefsArr: string | Array<string> | undefined, forStaticArea: boolean, options: RendererOptions) => {
28
28
  const openUI5Enablement = getFeature<typeof OpenUI5Enablement>("OpenUI5Enablement");
29
29
  if (openUI5Enablement && !forStaticArea) {
30
30
  templateResult = openUI5Enablement.wrapTemplateResultInBusyMarkup(effectiveHtml, options.host as UI5Element, templateResult as TemplateResult);