@ui5/webcomponents-base 0.0.0-0742854fd → 0.0.0-11d529e8a
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.
- package/.eslintignore +2 -0
- package/CHANGELOG.md +109 -0
- package/README.md +26 -1
- package/bundle.esm.js +13 -10
- package/dist/AssetRegistry.js +8 -7
- package/dist/Boot.js +43 -0
- package/dist/DOMObserver.js +65 -0
- package/dist/Device.js +58 -779
- package/dist/EventProvider.js +30 -26
- package/dist/FontFace.js +52 -7
- package/dist/InitialConfiguration.js +26 -21
- package/dist/Keys.js +51 -0
- package/dist/MediaRange.js +109 -0
- package/{src/util/parseProperties.js → dist/PropertiesFileFormat.js} +6 -0
- package/dist/Render.js +173 -0
- package/dist/RenderScheduler.js +16 -138
- package/dist/StaticArea.js +1 -29
- package/dist/StaticAreaItem.js +64 -65
- package/dist/Theming.js +2 -1
- package/dist/UI5Element.js +305 -374
- package/dist/UI5ElementMetadata.js +115 -16
- package/dist/asset-registries/Icons.js +110 -14
- package/dist/asset-registries/Illustrations.js +30 -0
- package/dist/asset-registries/LocaleData.js +90 -66
- package/dist/asset-registries/Themes.js +23 -33
- package/dist/asset-registries/i18n.js +61 -50
- package/dist/config/Language.js +18 -20
- package/dist/delegate/ItemNavigation.js +233 -201
- package/dist/delegate/ResizeHandler.js +78 -37
- package/dist/delegate/ScrollEnablement.js +49 -20
- package/dist/features/OpenUI5Support.js +41 -6
- package/dist/generated/AssetParameters.js +1 -1
- package/dist/i18nBundle.js +6 -2
- package/dist/isLegacyBrowser.js +3 -0
- package/dist/locale/applyDirection.js +6 -4
- package/dist/locale/directionChange.js +32 -0
- package/dist/locale/getEffectiveDir.js +28 -0
- package/dist/locale/getLocale.js +12 -2
- package/dist/locale/languageChange.js +1 -1
- package/dist/renderer/LitRenderer.js +19 -18
- package/dist/resources/bundle.esm.js +17 -109
- package/dist/resources/bundle.esm.js.map +1 -1
- package/dist/sap/base/Log.js +241 -0
- package/dist/sap/base/assert.js +8 -0
- package/dist/sap/base/security/URLListValidator.js +148 -0
- package/dist/sap/base/security/sanitizeHTML.js +16 -0
- package/dist/sap/base/util/now.js +7 -0
- package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +3585 -0
- package/dist/test-resources/assets/Themes.js +8 -8
- package/dist/test-resources/elements/Parent.js +6 -2
- package/dist/test-resources/elements/WithStaticArea.js +2 -1
- package/dist/test-resources/pages/AllTestElements.html +3 -3
- package/dist/test-resources/pages/Configuration.html +0 -2
- package/dist/test-resources/pages/ConfigurationScript.html +0 -2
- package/dist/test-resources/pages/i18n.html +1 -6
- package/dist/test-resources/specs/ConfigurationChange.spec.js +10 -8
- package/dist/test-resources/specs/ConfigurationScript.spec.js +25 -23
- package/dist/test-resources/specs/ConfigurationURL.spec.js +65 -17
- package/dist/test-resources/specs/CustomTheme.spec.js +7 -5
- package/dist/test-resources/specs/EventProvider.spec.js +63 -0
- package/dist/test-resources/specs/StaticArea.spec.js +56 -12
- package/dist/test-resources/specs/Theming.spec.js +9 -7
- package/dist/test-resources/specs/UI5ElementInvalidation.js +54 -70
- package/dist/test-resources/specs/UI5ElementLifecycle.js +17 -15
- package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +25 -51
- package/dist/test-resources/specs/UI5ElementMetadataExt.js +9 -7
- package/dist/test-resources/specs/UI5ElementPropertyValidation.js +7 -5
- package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +37 -35
- package/dist/test-resources/specs/UI5ElementShadowDOM.js +10 -8
- package/dist/test-resources/specs/UI5ElementSlots.js +10 -8
- package/dist/theming/CustomStyle.js +2 -2
- package/dist/theming/ThemeLoaded.js +22 -0
- package/dist/theming/applyTheme.js +2 -5
- package/dist/theming/getConstructableStyle.js +7 -6
- package/dist/theming/getEffectiveStyle.js +15 -8
- package/dist/theming/getStylesString.js +1 -1
- package/dist/types/CSSColor.js +9 -0
- package/dist/types/CalendarType.js +1 -1
- package/dist/types/DataType.js +13 -1
- package/dist/types/Float.js +4 -0
- package/dist/types/Integer.js +4 -0
- package/dist/types/InvisibleMessageMode.js +30 -0
- package/dist/types/ItemNavigationBehavior.js +2 -7
- package/dist/types/PopupState.js +1 -1
- package/dist/types/ValueState.js +1 -1
- package/dist/updateShadowRoot.js +26 -0
- package/dist/util/AriaLabelHelper.js +4 -4
- package/dist/util/Caret.js +45 -0
- package/dist/util/ColorConversion.js +370 -0
- package/dist/util/FocusableElements.js +17 -6
- package/dist/util/HTMLSanitizer.js +7 -0
- package/dist/util/InvisibleMessage.js +58 -0
- package/dist/util/PopupUtils.js +93 -0
- package/dist/util/SlotsHelper.js +43 -0
- package/dist/util/TabbableElements.js +1 -1
- package/dist/util/arraysAreEqual.js +15 -0
- package/dist/util/clamp.js +12 -0
- package/dist/util/debounce.js +17 -0
- package/dist/util/encodeCSS.js +24 -0
- package/dist/util/getActiveElement.js +11 -0
- package/dist/util/getClassCopy.js +10 -0
- package/dist/util/getEffectiveContentDensity.js +5 -0
- package/dist/util/isElementInView.js +15 -0
- package/dist/util/isNodeTabbable.js +4 -4
- package/hash.txt +1 -0
- package/index.js +1 -1
- package/package-scripts.js +33 -18
- package/package.json +20 -12
- package/src/AssetRegistry.js +8 -7
- package/src/Boot.js +43 -0
- package/src/DOMObserver.js +65 -0
- package/src/Device.js +58 -779
- package/src/EventProvider.js +30 -26
- package/src/FontFace.js +52 -7
- package/src/InitialConfiguration.js +26 -21
- package/src/Keys.js +51 -0
- package/src/MediaRange.js +109 -0
- package/{dist/util/parseProperties.js → src/PropertiesFileFormat.js} +6 -0
- package/src/Render.js +173 -0
- package/src/RenderScheduler.js +16 -138
- package/src/StaticArea.js +1 -29
- package/src/StaticAreaItem.js +64 -65
- package/src/Theming.js +2 -1
- package/src/UI5Element.js +305 -374
- package/src/UI5ElementMetadata.js +115 -16
- package/src/asset-registries/Icons.js +110 -14
- package/src/asset-registries/Illustrations.js +30 -0
- package/src/asset-registries/LocaleData.js +90 -66
- package/src/asset-registries/Themes.js +23 -33
- package/src/asset-registries/i18n.js +61 -50
- package/src/config/Language.js +18 -20
- package/src/delegate/ItemNavigation.js +233 -201
- package/src/delegate/ResizeHandler.js +78 -37
- package/src/delegate/ScrollEnablement.js +49 -20
- package/src/features/OpenUI5Support.js +41 -6
- package/src/i18nBundle.js +6 -2
- package/src/isLegacyBrowser.js +3 -0
- package/src/locale/applyDirection.js +6 -4
- package/src/locale/directionChange.js +32 -0
- package/src/locale/getEffectiveDir.js +28 -0
- package/src/locale/getLocale.js +12 -2
- package/src/locale/languageChange.js +1 -1
- package/src/renderer/LitRenderer.js +19 -18
- package/src/theming/CustomStyle.js +2 -2
- package/src/theming/ThemeLoaded.js +22 -0
- package/src/theming/applyTheme.js +2 -5
- package/src/theming/getConstructableStyle.js +7 -6
- package/src/theming/getEffectiveStyle.js +15 -8
- package/src/theming/getStylesString.js +1 -1
- package/src/types/CSSColor.js +9 -0
- package/src/types/CalendarType.js +1 -1
- package/src/types/DataType.js +13 -1
- package/src/types/Float.js +4 -0
- package/src/types/Integer.js +4 -0
- package/src/types/InvisibleMessageMode.js +30 -0
- package/src/types/ItemNavigationBehavior.js +2 -7
- package/src/types/PopupState.js +1 -1
- package/src/types/ValueState.js +1 -1
- package/src/updateShadowRoot.js +26 -0
- package/src/util/AriaLabelHelper.js +4 -4
- package/src/util/Caret.js +45 -0
- package/src/util/ColorConversion.js +370 -0
- package/src/util/FocusableElements.js +17 -6
- package/src/util/HTMLSanitizer.js +7 -0
- package/src/util/InvisibleMessage.js +58 -0
- package/src/util/PopupUtils.js +93 -0
- package/src/util/SlotsHelper.js +43 -0
- package/src/util/TabbableElements.js +1 -1
- package/src/util/arraysAreEqual.js +15 -0
- package/src/util/clamp.js +12 -0
- package/src/util/debounce.js +17 -0
- package/src/util/encodeCSS.js +24 -0
- package/src/util/getActiveElement.js +11 -0
- package/src/util/getClassCopy.js +10 -0
- package/src/util/getEffectiveContentDensity.js +5 -0
- package/src/util/isElementInView.js +15 -0
- package/src/util/isNodeTabbable.js +4 -4
- package/used-modules.txt +7 -0
- package/bundle.es5.js +0 -28
- package/dist/SVGIconRegistry.js +0 -62
- package/dist/boot.js +0 -34
- package/dist/compatibility/DOMObserver.js +0 -62
- package/dist/compatibility/patchNodeValue.js +0 -24
- package/dist/compatibility/whenPolyfillLoaded.js +0 -26
- package/dist/config/AssetsPath.js +0 -17
- package/dist/delegate/CustomResize.js +0 -78
- package/dist/delegate/NativeResize.js +0 -44
- package/dist/features/PropertiesFormatSupport.js +0 -8
- package/dist/features/browsersupport/Edge.js +0 -6
- package/dist/features/browsersupport/IE11.js +0 -41
- package/dist/features/browsersupport/IE11WithWebComponentsPolyfill.js +0 -5
- package/dist/renderer/ifDefined.js +0 -21
- package/dist/renderer/scopeHTML.js +0 -32
- package/dist/resources/bundle.es5.js +0 -212
- package/dist/resources/bundle.es5.js.map +0 -1
- package/dist/theming/CSSVarsPonyfill.js +0 -48
- package/dist/theming/adaptCSSForIE.js +0 -95
- package/dist/theming/createComponentStyleTag.js +0 -54
- package/dist/thirdparty/Array.from.js +0 -16
- package/dist/thirdparty/Array.prototype.fill.js +0 -44
- package/dist/thirdparty/Array.prototype.find.js +0 -46
- package/dist/thirdparty/Array.prototype.includes.js +0 -51
- package/dist/thirdparty/Element.prototype.closest.js +0 -11
- package/dist/thirdparty/Element.prototype.matches.js +0 -6
- package/dist/thirdparty/Map.prototype.keys.js +0 -9
- package/dist/thirdparty/Number.isInteger.js +0 -5
- package/dist/thirdparty/Number.isNaN.js +0 -1
- package/dist/thirdparty/Number.parseInt.js +0 -1
- package/dist/thirdparty/Object.assign.js +0 -31
- package/dist/thirdparty/Object.entries.js +0 -11
- package/dist/thirdparty/Symbol.js +0 -2
- package/dist/thirdparty/WeakSet.js +0 -27
- package/dist/thirdparty/es6-string-methods.js +0 -182
- package/dist/thirdparty/events-polyfills.js +0 -89
- package/dist/thirdparty/fetch.js +0 -1
- package/dist/thirdparty/template.js +0 -600
- package/dist/thirdparty/webcomponents-sd-ce-pf.js +0 -318
- package/dist/util/getEffectiveAssetPath.js +0 -12
- package/dist/util/isSlot.js +0 -3
- package/dist/webcomponentsjs/LICENSE.md +0 -19
- package/dist/webcomponentsjs/README.md +0 -229
- package/dist/webcomponentsjs/bundles/webcomponents-ce.js +0 -63
- package/dist/webcomponentsjs/bundles/webcomponents-ce.js.map +0 -1
- package/dist/webcomponentsjs/bundles/webcomponents-sd-ce-pf.js +0 -297
- package/dist/webcomponentsjs/bundles/webcomponents-sd-ce-pf.js.map +0 -1
- package/dist/webcomponentsjs/bundles/webcomponents-sd-ce.js +0 -208
- package/dist/webcomponentsjs/bundles/webcomponents-sd-ce.js.map +0 -1
- package/dist/webcomponentsjs/bundles/webcomponents-sd.js +0 -166
- package/dist/webcomponentsjs/bundles/webcomponents-sd.js.map +0 -1
- package/dist/webcomponentsjs/custom-elements-es5-adapter.js +0 -15
- package/dist/webcomponentsjs/package.json +0 -46
- package/dist/webcomponentsjs/src/entrypoints/custom-elements-es5-adapter-index.js +0 -16
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-bundle-index.js +0 -53
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-ce-index.js +0 -17
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-ce-index.js +0 -19
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-ce-pf-index.js +0 -28
- package/dist/webcomponentsjs/src/entrypoints/webcomponents-sd-index.js +0 -18
- package/dist/webcomponentsjs/webcomponents-bundle.js +0 -298
- package/dist/webcomponentsjs/webcomponents-bundle.js.map +0 -1
- package/dist/webcomponentsjs/webcomponents-loader.js +0 -185
- package/src/SVGIconRegistry.js +0 -62
- package/src/boot.js +0 -34
- package/src/compatibility/DOMObserver.js +0 -62
- package/src/compatibility/patchNodeValue.js +0 -24
- package/src/compatibility/whenPolyfillLoaded.js +0 -26
- package/src/config/AssetsPath.js +0 -17
- package/src/delegate/CustomResize.js +0 -78
- package/src/delegate/NativeResize.js +0 -44
- package/src/features/PropertiesFormatSupport.js +0 -8
- package/src/features/browsersupport/Edge.js +0 -6
- package/src/features/browsersupport/IE11.js +0 -41
- package/src/features/browsersupport/IE11WithWebComponentsPolyfill.js +0 -5
- package/src/renderer/ifDefined.js +0 -21
- package/src/renderer/scopeHTML.js +0 -32
- package/src/theming/CSSVarsPonyfill.js +0 -48
- package/src/theming/adaptCSSForIE.js +0 -95
- package/src/theming/createComponentStyleTag.js +0 -54
- package/src/thirdparty/Array.from.js +0 -16
- package/src/thirdparty/Array.prototype.fill.js +0 -44
- package/src/thirdparty/Array.prototype.find.js +0 -46
- package/src/thirdparty/Array.prototype.includes.js +0 -51
- package/src/thirdparty/Element.prototype.closest.js +0 -11
- package/src/thirdparty/Element.prototype.matches.js +0 -6
- package/src/thirdparty/Map.prototype.keys.js +0 -9
- package/src/thirdparty/Number.isInteger.js +0 -5
- package/src/thirdparty/Number.isNaN.js +0 -1
- package/src/thirdparty/Number.parseInt.js +0 -1
- package/src/thirdparty/Object.assign.js +0 -31
- package/src/thirdparty/Object.entries.js +0 -11
- package/src/thirdparty/Symbol.js +0 -2
- package/src/thirdparty/WeakSet.js +0 -27
- package/src/thirdparty/es6-string-methods.js +0 -182
- package/src/thirdparty/events-polyfills.js +0 -89
- package/src/thirdparty/fetch.js +0 -1
- package/src/thirdparty/template.js +0 -600
- package/src/thirdparty/webcomponents-sd-ce-pf.js +0 -318
- package/src/util/getEffectiveAssetPath.js +0 -12
- package/src/util/isSlot.js +0 -3
package/src/types/Integer.js
CHANGED
|
@@ -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;
|
|
@@ -4,18 +4,13 @@
|
|
|
4
4
|
*/
|
|
5
5
|
const ItemNavigationBehavior = {
|
|
6
6
|
/**
|
|
7
|
-
* Static behavior:
|
|
7
|
+
* Static behavior: navigations stops at the first or last item.
|
|
8
8
|
*/
|
|
9
9
|
Static: "Static",
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Cycling behavior:
|
|
12
|
+
* Cycling behavior: navigating past the last item continues with the first and vice versa.
|
|
13
13
|
*/
|
|
14
14
|
Cyclic: "Cyclic",
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Paging behavior: when border of the items is reached, tou can go up/down based on the rowsize(e.g. DayPicker)
|
|
18
|
-
*/
|
|
19
|
-
Paging: "Paging",
|
|
20
15
|
};
|
|
21
16
|
export default ItemNavigationBehavior;
|
package/src/types/PopupState.js
CHANGED
package/src/types/ValueState.js
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import executeTemplate from "./renderer/executeTemplate.js";
|
|
2
|
+
import getConstructableStyle from "./theming/getConstructableStyle.js";
|
|
3
|
+
import getEffectiveStyle from "./theming/getEffectiveStyle.js";
|
|
4
|
+
import isLegacyBrowser from "./isLegacyBrowser.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Updates the shadow root of a UI5Element or its static area item
|
|
8
|
+
* @param element
|
|
9
|
+
* @param forStaticArea
|
|
10
|
+
*/
|
|
11
|
+
const updateShadowRoot = (element, forStaticArea = false) => {
|
|
12
|
+
let styleToPrepend;
|
|
13
|
+
const template = forStaticArea ? "staticAreaTemplate" : "template";
|
|
14
|
+
const shadowRoot = forStaticArea ? element.staticAreaItem.shadowRoot : element.shadowRoot;
|
|
15
|
+
const renderResult = executeTemplate(element.constructor[template], element);
|
|
16
|
+
|
|
17
|
+
if (document.adoptedStyleSheets) { // Chrome
|
|
18
|
+
shadowRoot.adoptedStyleSheets = getConstructableStyle(element.constructor, forStaticArea);
|
|
19
|
+
} else if (!isLegacyBrowser()) { // FF, Safari
|
|
20
|
+
styleToPrepend = getEffectiveStyle(element.constructor, forStaticArea);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
element.constructor.render(renderResult, shadowRoot, styleToPrepend, { host: element });
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default updateShadowRoot;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import findNodeOwner from "./findNodeOwner.js";
|
|
2
2
|
|
|
3
3
|
const getEffectiveAriaLabelText = el => {
|
|
4
|
-
if (!el.
|
|
5
|
-
if (el.
|
|
6
|
-
return el.
|
|
4
|
+
if (!el.accessibleNameRef) {
|
|
5
|
+
if (el.accessibleName) {
|
|
6
|
+
return el.accessibleName;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
return undefined;
|
|
@@ -19,7 +19,7 @@ const getEffectiveAriaLabelText = el => {
|
|
|
19
19
|
* @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
20
|
*/
|
|
21
21
|
const getAriaLabelledByTexts = (el, ownerDocument, readyIds = "") => {
|
|
22
|
-
const ids = (readyIds && readyIds.split(" ")) || el.
|
|
22
|
+
const ids = (readyIds && readyIds.split(" ")) || el.accessibleNameRef.split(" ");
|
|
23
23
|
const owner = ownerDocument || findNodeOwner(el);
|
|
24
24
|
let result = "";
|
|
25
25
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the caret (cursor) position of the specified text field (field).
|
|
3
|
+
* Return value range is 0-field.value.length.
|
|
4
|
+
*/
|
|
5
|
+
const getCaretPosition = field => {
|
|
6
|
+
// Initialize
|
|
7
|
+
let caretPos = 0;
|
|
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
|
|
23
|
+
caretPos = field.selectionDirection === "backward" ? field.selectionStart : field.selectionEnd;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return caretPos;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const setCaretPosition = (field, caretPos) => {
|
|
30
|
+
if (field.createTextRange) {
|
|
31
|
+
const range = field.createTextRange();
|
|
32
|
+
range.move("character", caretPos);
|
|
33
|
+
range.select();
|
|
34
|
+
} else if (field.selectionStart) {
|
|
35
|
+
field.focus();
|
|
36
|
+
field.setSelectionRange(caretPos, caretPos);
|
|
37
|
+
} else {
|
|
38
|
+
field.focus();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export {
|
|
43
|
+
getCaretPosition,
|
|
44
|
+
setCaretPosition,
|
|
45
|
+
};
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param {String} color Color in one of the following formats: RGBA or HEX
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Map of CSS colors to hex representation
|
|
8
|
+
*/
|
|
9
|
+
const CSSColors = {
|
|
10
|
+
aliceblue: "f0f8ff",
|
|
11
|
+
antiquewhite: "faebd7",
|
|
12
|
+
aqua: "00ffff",
|
|
13
|
+
aquamarine: "7fffd4",
|
|
14
|
+
azure: "f0ffff",
|
|
15
|
+
beige: "f5f5dc",
|
|
16
|
+
bisque: "ffe4c4",
|
|
17
|
+
black: "000000",
|
|
18
|
+
blanchedalmond: "ffebcd",
|
|
19
|
+
blue: "0000ff",
|
|
20
|
+
blueviolet: "8a2be2",
|
|
21
|
+
brown: "a52a2a",
|
|
22
|
+
burlywood: "deb887",
|
|
23
|
+
cadetblue: "5f9ea0",
|
|
24
|
+
chartreuse: "7fff00",
|
|
25
|
+
chocolate: "d2691e",
|
|
26
|
+
coral: "ff7f50",
|
|
27
|
+
cornflowerblue: "6495ed",
|
|
28
|
+
cornsilk: "fff8dc",
|
|
29
|
+
crimson: "dc143c",
|
|
30
|
+
cyan: "00ffff",
|
|
31
|
+
darkblue: "00008b",
|
|
32
|
+
darkcyan: "008b8b",
|
|
33
|
+
darkgoldenrod: "b8860b",
|
|
34
|
+
darkgray: "a9a9a9",
|
|
35
|
+
darkgrey: "a9a9a9",
|
|
36
|
+
darkgreen: "006400",
|
|
37
|
+
darkkhaki: "bdb76b",
|
|
38
|
+
darkmagenta: "8b008b",
|
|
39
|
+
darkolivegreen: "556b2f",
|
|
40
|
+
darkorange: "ff8c00",
|
|
41
|
+
darkorchid: "9932cc",
|
|
42
|
+
darkred: "8b0000",
|
|
43
|
+
darksalmon: "e9967a",
|
|
44
|
+
darkseagreen: "8fbc8f",
|
|
45
|
+
darkslateblue: "483d8b",
|
|
46
|
+
darkslategray: "2f4f4f",
|
|
47
|
+
darkslategrey: "2f4f4f",
|
|
48
|
+
darkturquoise: "00ced1",
|
|
49
|
+
darkviolet: "9400d3",
|
|
50
|
+
deeppink: "ff1493",
|
|
51
|
+
deepskyblue: "00bfff",
|
|
52
|
+
dimgray: "696969",
|
|
53
|
+
dimgrey: "696969",
|
|
54
|
+
dodgerblue: "1e90ff",
|
|
55
|
+
firebrick: "b22222",
|
|
56
|
+
floralwhite: "fffaf0",
|
|
57
|
+
forestgreen: "228b22",
|
|
58
|
+
fuchsia: "ff00ff",
|
|
59
|
+
gainsboro: "dcdcdc",
|
|
60
|
+
ghostwhite: "f8f8ff",
|
|
61
|
+
gold: "ffd700",
|
|
62
|
+
goldenrod: "daa520",
|
|
63
|
+
gray: "808080",
|
|
64
|
+
grey: "808080",
|
|
65
|
+
green: "008000",
|
|
66
|
+
greenyellow: "adff2f",
|
|
67
|
+
honeydew: "f0fff0",
|
|
68
|
+
hotpink: "ff69b4",
|
|
69
|
+
indianred: "cd5c5c",
|
|
70
|
+
indigo: "4b0082",
|
|
71
|
+
ivory: "fffff0",
|
|
72
|
+
khaki: "f0e68c",
|
|
73
|
+
lavender: "e6e6fa",
|
|
74
|
+
lavenderblush: "fff0f5",
|
|
75
|
+
lawngreen: "7cfc00",
|
|
76
|
+
lemonchiffon: "fffacd",
|
|
77
|
+
lightblue: "add8e6",
|
|
78
|
+
lightcoral: "f08080",
|
|
79
|
+
lightcyan: "e0ffff",
|
|
80
|
+
lightgoldenrodyellow: "fafad2",
|
|
81
|
+
lightgray: "d3d3d3",
|
|
82
|
+
lightgrey: "d3d3d3",
|
|
83
|
+
lightgreen: "90ee90",
|
|
84
|
+
lightpink: "ffb6c1",
|
|
85
|
+
lightsalmon: "ffa07a",
|
|
86
|
+
lightseagreen: "20b2aa",
|
|
87
|
+
lightskyblue: "87cefa",
|
|
88
|
+
lightslategray: "778899",
|
|
89
|
+
lightslategrey: "778899",
|
|
90
|
+
lightsteelblue: "b0c4de",
|
|
91
|
+
lightyellow: "ffffe0",
|
|
92
|
+
lime: "00ff00",
|
|
93
|
+
limegreen: "32cd32",
|
|
94
|
+
linen: "faf0e6",
|
|
95
|
+
magenta: "ff00ff",
|
|
96
|
+
maroon: "800000",
|
|
97
|
+
mediumaquamarine: "66cdaa",
|
|
98
|
+
mediumblue: "0000cd",
|
|
99
|
+
mediumorchid: "ba55d3",
|
|
100
|
+
mediumpurple: "9370db",
|
|
101
|
+
mediumseagreen: "3cb371",
|
|
102
|
+
mediumslateblue: "7b68ee",
|
|
103
|
+
mediumspringgreen: "00fa9a",
|
|
104
|
+
mediumturquoise: "48d1cc",
|
|
105
|
+
mediumvioletred: "c71585",
|
|
106
|
+
midnightblue: "191970",
|
|
107
|
+
mintcream: "f5fffa",
|
|
108
|
+
mistyrose: "ffe4e1",
|
|
109
|
+
moccasin: "ffe4b5",
|
|
110
|
+
navajowhite: "ffdead",
|
|
111
|
+
navy: "000080",
|
|
112
|
+
oldlace: "fdf5e6",
|
|
113
|
+
olive: "808000",
|
|
114
|
+
olivedrab: "6b8e23",
|
|
115
|
+
orange: "ffa500",
|
|
116
|
+
orangered: "ff4500",
|
|
117
|
+
orchid: "da70d6",
|
|
118
|
+
palegoldenrod: "eee8aa",
|
|
119
|
+
palegreen: "98fb98",
|
|
120
|
+
paleturquoise: "afeeee",
|
|
121
|
+
palevioletred: "db7093",
|
|
122
|
+
papayawhip: "ffefd5",
|
|
123
|
+
peachpuff: "ffdab9",
|
|
124
|
+
peru: "cd853f",
|
|
125
|
+
pink: "ffc0cb",
|
|
126
|
+
plum: "dda0dd",
|
|
127
|
+
powderblue: "b0e0e6",
|
|
128
|
+
purple: "800080",
|
|
129
|
+
red: "ff0000",
|
|
130
|
+
rosybrown: "bc8f8f",
|
|
131
|
+
royalblue: "4169e1",
|
|
132
|
+
saddlebrown: "8b4513",
|
|
133
|
+
salmon: "fa8072",
|
|
134
|
+
sandybrown: "f4a460",
|
|
135
|
+
seagreen: "2e8b57",
|
|
136
|
+
seashell: "fff5ee",
|
|
137
|
+
sienna: "a0522d",
|
|
138
|
+
silver: "c0c0c0",
|
|
139
|
+
skyblue: "87ceeb",
|
|
140
|
+
slateblue: "6a5acd",
|
|
141
|
+
slategray: "708090",
|
|
142
|
+
slategrey: "708090",
|
|
143
|
+
snow: "fffafa",
|
|
144
|
+
springgreen: "00ff7f",
|
|
145
|
+
steelblue: "4682b4",
|
|
146
|
+
tan: "d2b48c",
|
|
147
|
+
teal: "008080",
|
|
148
|
+
thistle: "d8bfd8",
|
|
149
|
+
tomato: "ff6347",
|
|
150
|
+
turquoise: "40e0d0",
|
|
151
|
+
violet: "ee82ee",
|
|
152
|
+
wheat: "f5deb3",
|
|
153
|
+
white: "ffffff",
|
|
154
|
+
whitesmoke: "f5f5f5",
|
|
155
|
+
yellow: "ffff00",
|
|
156
|
+
yellowgreen: "9acd32",
|
|
157
|
+
transparent: "00000000",
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const getRGBColor = color => {
|
|
161
|
+
if (color.startsWith("rgba")) {
|
|
162
|
+
return RGBAToRGB(color);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (color.startsWith("rgb")) {
|
|
166
|
+
return RGBToRGB(color);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// HEX
|
|
170
|
+
if (color.indexOf("#") === 0) {
|
|
171
|
+
// Shorthand Syntax
|
|
172
|
+
if (color.length === 4) {
|
|
173
|
+
color = `${color[1]}${color[1]}${color[2]}${color[2]}${color[3]}${color[3]}`;
|
|
174
|
+
} else {
|
|
175
|
+
color = color.slice(1, color.length);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Css Color
|
|
180
|
+
if (Object.keys(CSSColors).includes(color)) {
|
|
181
|
+
color = CSSColors[color];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return HEXToRGB(color);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Return an object with the properties for each of the main colors(red, green, blue)
|
|
189
|
+
* @param {String} color Receives a color in the following format: "rgba(0, 0, 0, 1)
|
|
190
|
+
*/
|
|
191
|
+
const RGBAToRGB = color => {
|
|
192
|
+
const openingBracketIndex = color.indexOf("("),
|
|
193
|
+
commasIndexes = [];
|
|
194
|
+
|
|
195
|
+
for (let i = 0; i < color.length; i++) {
|
|
196
|
+
if (color[i] === ",") {
|
|
197
|
+
commasIndexes.push(i);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
r: parseInt(color.slice(openingBracketIndex + 1, commasIndexes[0]).trim()),
|
|
203
|
+
g: parseInt(color.slice(commasIndexes[0] + 1, commasIndexes[1]).trim()),
|
|
204
|
+
b: parseInt(color.slice(commasIndexes[1] + 1, commasIndexes[2]).trim()),
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Return an object with the properties for each of the main colors(red, green, blue)
|
|
210
|
+
* @param {String} color Receives a color in the following format: "rgb(0, 0, 0)
|
|
211
|
+
*/
|
|
212
|
+
const RGBToRGB = color => {
|
|
213
|
+
const openingBracketIndex = color.indexOf("("),
|
|
214
|
+
closingBraketIndex = color.indexOf(")"),
|
|
215
|
+
commasIndexes = [];
|
|
216
|
+
|
|
217
|
+
for (let i = 0; i < color.length; i++) {
|
|
218
|
+
if (color[i] === ",") {
|
|
219
|
+
commasIndexes.push(i);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
r: parseInt(color.slice(openingBracketIndex + 1, commasIndexes[0]).trim()),
|
|
225
|
+
g: parseInt(color.slice(commasIndexes[0] + 1, commasIndexes[1]).trim()),
|
|
226
|
+
b: parseInt(color.slice(commasIndexes[1] + 1, closingBraketIndex).trim()),
|
|
227
|
+
};
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const HSLToRGB = (color = {
|
|
231
|
+
h: undefined,
|
|
232
|
+
s: undefined,
|
|
233
|
+
l: undefined,
|
|
234
|
+
}) => {
|
|
235
|
+
// Formula taken from https://www.rapidtables.com/convert/color/hsl-to-rgb.html
|
|
236
|
+
const C = (1 - Math.abs((2 * color.l) - 1)) * color.s,
|
|
237
|
+
X = C * (1 - Math.abs(((color.h / 60) % 2) - 1)),
|
|
238
|
+
m = color.l - C / 2;
|
|
239
|
+
|
|
240
|
+
let tempColor = {};
|
|
241
|
+
switch (Math.round(color.h / 60)) {
|
|
242
|
+
// 0 ≤ H < 60
|
|
243
|
+
case 0:
|
|
244
|
+
tempColor = {
|
|
245
|
+
r: C,
|
|
246
|
+
g: X,
|
|
247
|
+
b: 0,
|
|
248
|
+
};
|
|
249
|
+
break;
|
|
250
|
+
|
|
251
|
+
// 60 ≤ H < 120
|
|
252
|
+
case 1:
|
|
253
|
+
tempColor = {
|
|
254
|
+
r: X,
|
|
255
|
+
g: C,
|
|
256
|
+
b: 0,
|
|
257
|
+
};
|
|
258
|
+
break;
|
|
259
|
+
|
|
260
|
+
// 120 ≤ H < 180
|
|
261
|
+
case 2:
|
|
262
|
+
tempColor = {
|
|
263
|
+
r: 0,
|
|
264
|
+
g: C,
|
|
265
|
+
b: X,
|
|
266
|
+
};
|
|
267
|
+
break;
|
|
268
|
+
|
|
269
|
+
// 180 ≤ H < 240
|
|
270
|
+
case 3:
|
|
271
|
+
tempColor = {
|
|
272
|
+
r: 0,
|
|
273
|
+
g: X,
|
|
274
|
+
b: C,
|
|
275
|
+
};
|
|
276
|
+
break;
|
|
277
|
+
|
|
278
|
+
// 240 ≤ H < 300
|
|
279
|
+
case 4:
|
|
280
|
+
tempColor = {
|
|
281
|
+
r: X,
|
|
282
|
+
g: 0,
|
|
283
|
+
b: C,
|
|
284
|
+
};
|
|
285
|
+
break;
|
|
286
|
+
|
|
287
|
+
// 300 ≤ H < 360
|
|
288
|
+
default:
|
|
289
|
+
tempColor = {
|
|
290
|
+
r: C,
|
|
291
|
+
g: 0,
|
|
292
|
+
b: X,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
r: Math.floor((tempColor.r + m) * 255),
|
|
298
|
+
g: Math.floor((tempColor.g + m) * 255),
|
|
299
|
+
b: Math.floor((tempColor.b + m) * 255),
|
|
300
|
+
};
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const HEXToRGB = hex => {
|
|
304
|
+
// Please make sure you pass a valid 6 digit hex color
|
|
305
|
+
// In the implementation of this method we assume that the hex argument is a 6 digit valid hex color
|
|
306
|
+
|
|
307
|
+
const rgbValues = {
|
|
308
|
+
r: hex.substr(0, 2),
|
|
309
|
+
g: hex.substr(2, 2),
|
|
310
|
+
b: hex.substr(4, 2),
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const rgbKeys = Object.keys(rgbValues);
|
|
314
|
+
|
|
315
|
+
rgbKeys.forEach(key => {
|
|
316
|
+
rgbValues[key] = parseInt(rgbValues[key], 16);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
return rgbValues;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const RGBToHSL = (color = {
|
|
323
|
+
r: undefined,
|
|
324
|
+
g: undefined,
|
|
325
|
+
b: undefined,
|
|
326
|
+
}) => {
|
|
327
|
+
const R = color.r / 255,
|
|
328
|
+
G = color.g / 255,
|
|
329
|
+
B = color.b / 255,
|
|
330
|
+
max = Math.max(R, G, B),
|
|
331
|
+
min = Math.min(R, G, B),
|
|
332
|
+
delta = max - min;
|
|
333
|
+
|
|
334
|
+
let h,
|
|
335
|
+
s;
|
|
336
|
+
|
|
337
|
+
// Hue calculation
|
|
338
|
+
if (delta === 0) {
|
|
339
|
+
h = 0;
|
|
340
|
+
} else if (max === R) {
|
|
341
|
+
h = 60 * (((G - B) / delta) % 6);
|
|
342
|
+
} else if (max === G) {
|
|
343
|
+
h = 60 * (((B - R) / delta) + 2);
|
|
344
|
+
} else if (max === B) {
|
|
345
|
+
h = 60 * (((R - G) / delta) + 4);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Lightness calculation
|
|
349
|
+
const l = (max + min) / 2;
|
|
350
|
+
|
|
351
|
+
// Saturation calculation
|
|
352
|
+
if (delta === 0) {
|
|
353
|
+
s = 0;
|
|
354
|
+
} else {
|
|
355
|
+
s = delta / (1 - Math.abs(2 * l - 1));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return {
|
|
359
|
+
h,
|
|
360
|
+
s,
|
|
361
|
+
l,
|
|
362
|
+
};
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
export {
|
|
366
|
+
getRGBColor,
|
|
367
|
+
HSLToRGB,
|
|
368
|
+
HEXToRGB,
|
|
369
|
+
RGBToHSL,
|
|
370
|
+
};
|
|
@@ -5,7 +5,7 @@ const isFocusTrap = el => {
|
|
|
5
5
|
return el.hasAttribute("data-ui5-focus-trap");
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
const getFirstFocusableElement = container => {
|
|
8
|
+
const getFirstFocusableElement = async container => {
|
|
9
9
|
if (!container || isNodeHidden(container)) {
|
|
10
10
|
return null;
|
|
11
11
|
}
|
|
@@ -13,7 +13,7 @@ const getFirstFocusableElement = container => {
|
|
|
13
13
|
return findFocusableElement(container, true);
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
const getLastFocusableElement = container => {
|
|
16
|
+
const getLastFocusableElement = async container => {
|
|
17
17
|
if (!container || isNodeHidden(container)) {
|
|
18
18
|
return null;
|
|
19
19
|
}
|
|
@@ -21,7 +21,11 @@ const getLastFocusableElement = container => {
|
|
|
21
21
|
return findFocusableElement(container, false);
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
const
|
|
24
|
+
const isElemFocusable = el => {
|
|
25
|
+
return el.hasAttribute("data-ui5-focus-redirect") || !isNodeHidden(el);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const findFocusableElement = async (container, forward) => {
|
|
25
29
|
let child;
|
|
26
30
|
|
|
27
31
|
if (container.shadowRoot) {
|
|
@@ -35,20 +39,25 @@ const findFocusableElement = (container, forward) => {
|
|
|
35
39
|
|
|
36
40
|
let focusableDescendant;
|
|
37
41
|
|
|
42
|
+
/* eslint-disable no-await-in-loop */
|
|
43
|
+
|
|
38
44
|
while (child) {
|
|
39
45
|
const originalChild = child;
|
|
40
46
|
|
|
41
|
-
|
|
47
|
+
if (child.isUI5Element) {
|
|
48
|
+
child = await child.getFocusDomRefAsync();
|
|
49
|
+
}
|
|
50
|
+
|
|
42
51
|
if (!child) {
|
|
43
52
|
return null;
|
|
44
53
|
}
|
|
45
54
|
|
|
46
|
-
if (child.nodeType === 1 &&
|
|
55
|
+
if (child.nodeType === 1 && isElemFocusable(child) && !isFocusTrap(child)) {
|
|
47
56
|
if (isNodeClickable(child)) {
|
|
48
57
|
return (child && typeof child.focus === "function") ? child : null;
|
|
49
58
|
}
|
|
50
59
|
|
|
51
|
-
focusableDescendant = findFocusableElement(child, forward);
|
|
60
|
+
focusableDescendant = await findFocusableElement(child, forward);
|
|
52
61
|
if (focusableDescendant) {
|
|
53
62
|
return (focusableDescendant && typeof focusableDescendant.focus === "function") ? focusableDescendant : null;
|
|
54
63
|
}
|
|
@@ -57,6 +66,8 @@ const findFocusableElement = (container, forward) => {
|
|
|
57
66
|
child = forward ? originalChild.nextSibling : originalChild.previousSibling;
|
|
58
67
|
}
|
|
59
68
|
|
|
69
|
+
/* eslint-enable no-await-in-loop */
|
|
70
|
+
|
|
60
71
|
return null;
|
|
61
72
|
};
|
|
62
73
|
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
attachBoot(() => {
|
|
9
|
+
if (politeSpan && assertiveSpan) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const styles = `position: absolute;
|
|
14
|
+
clip: rect(1px,1px,1px,1px);
|
|
15
|
+
user-select: none;
|
|
16
|
+
left: -1000px;
|
|
17
|
+
top: -1000px;
|
|
18
|
+
pointer-events: none;`;
|
|
19
|
+
|
|
20
|
+
politeSpan = document.createElement("span");
|
|
21
|
+
assertiveSpan = document.createElement("span");
|
|
22
|
+
|
|
23
|
+
politeSpan.classList.add("ui5-invisiblemessage-polite");
|
|
24
|
+
assertiveSpan.classList.add("ui5-invisiblemessage-assertive");
|
|
25
|
+
|
|
26
|
+
politeSpan.setAttribute("aria-live", "polite");
|
|
27
|
+
assertiveSpan.setAttribute("aria-live", "assertive");
|
|
28
|
+
|
|
29
|
+
politeSpan.setAttribute("role", "alert");
|
|
30
|
+
assertiveSpan.setAttribute("role", "alert");
|
|
31
|
+
|
|
32
|
+
politeSpan.style.cssText = styles;
|
|
33
|
+
assertiveSpan.style.cssText = styles;
|
|
34
|
+
|
|
35
|
+
getSingletonElementInstance("ui5-static-area").appendChild(politeSpan);
|
|
36
|
+
getSingletonElementInstance("ui5-static-area").appendChild(assertiveSpan);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Inserts the string into the respective span, depending on the mode provided.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} message String to be announced by the screen reader.
|
|
43
|
+
* @param {sap.ui.core.InvisibleMessageMode} mode The mode to be inserted in the aria-live attribute.
|
|
44
|
+
*/
|
|
45
|
+
const announce = (message, mode) => {
|
|
46
|
+
// If no type is presented, fallback to polite announcement.
|
|
47
|
+
const span = mode === InvisibleMessageMode.Assertive ? assertiveSpan : politeSpan;
|
|
48
|
+
|
|
49
|
+
// Set textContent to empty string in order to trigger screen reader's announcement.
|
|
50
|
+
span.textContent = "";
|
|
51
|
+
span.textContent = message;
|
|
52
|
+
|
|
53
|
+
if (mode !== InvisibleMessageMode.Assertive && mode !== InvisibleMessageMode.Polite) {
|
|
54
|
+
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
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default announce;
|