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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/.eslintignore +0 -1
  2. package/CHANGELOG.md +173 -0
  3. package/README.md +28 -6
  4. package/bundle.esm.js +7 -9
  5. package/dist/Boot.js +3 -5
  6. package/dist/CustomElementsRegistry.js +1 -1
  7. package/dist/CustomElementsScope.js +20 -98
  8. package/dist/CustomElementsScopeUtils.js +108 -0
  9. package/dist/Device.js +5 -0
  10. package/dist/Keys.js +24 -0
  11. package/dist/StaticAreaItem.js +1 -1
  12. package/dist/UI5Element.js +24 -2
  13. package/dist/UI5ElementMetadata.js +1 -1
  14. package/dist/asset-registries/Icons.js +4 -8
  15. package/dist/asset-registries/LocaleData.js +7 -2
  16. package/dist/asset-registries/Themes.js +6 -2
  17. package/dist/asset-registries/i18n.js +3 -1
  18. package/dist/assets/bundle.esm.83f057b4.js +43 -0
  19. package/dist/config/Icons.js +52 -0
  20. package/dist/config/Theme.js +11 -0
  21. package/dist/css/BusyIndicator.css +80 -0
  22. package/dist/css/FontFace.css +31 -10
  23. package/dist/delegate/ItemNavigation.js +9 -4
  24. package/dist/features/F6Navigation.js +4 -0
  25. package/dist/features/OpenUI5Enablement.js +119 -0
  26. package/dist/generated/AssetParameters.js +1 -1
  27. package/dist/generated/VersionInfo.js +3 -3
  28. package/dist/generated/css/BusyIndicator.css.js +5 -0
  29. package/dist/generated/css/FontFace.css.js +1 -1
  30. package/dist/i18nBundle.js +1 -1
  31. package/dist/renderer/LitRenderer.js +29 -11
  32. package/dist/renderer/executeTemplate.js +19 -2
  33. package/dist/sap/ui/thirdparty/caja-html-sanitizer.js +1 -1
  34. package/dist/theming/getEffectiveLinksHrefs.js +7 -0
  35. package/dist/theming/getEffectiveStyle.js +9 -0
  36. package/dist/types/DOMReference.js +24 -0
  37. package/dist/updateShadowRoot.js +2 -3
  38. package/dist/util/AriaLabelHelper.js +2 -4
  39. package/dist/util/Caret.js +1 -14
  40. package/dist/util/ColorConversion.js +30 -2
  41. package/dist/util/InvisibleMessage.js +20 -9
  42. package/dist/util/TabbableElements.js +4 -0
  43. package/dist/util/getEffectiveScrollbarStyle.js +5 -0
  44. package/dist/util/getNormalizedTarget.js +16 -0
  45. package/dist/util/isDefaultSlotProvided.js +11 -0
  46. package/hash.txt +1 -1
  47. package/lib/generate-asset-parameters/index.js +8 -4
  48. package/lib/generate-styles/index.js +17 -9
  49. package/lib/generate-version-info/index.js +18 -13
  50. package/package-scripts.js +16 -27
  51. package/package.json +7 -6
  52. package/src/Boot.js +3 -5
  53. package/src/CustomElementsRegistry.js +1 -1
  54. package/src/CustomElementsScope.js +20 -98
  55. package/src/CustomElementsScopeUtils.js +108 -0
  56. package/src/Device.js +5 -0
  57. package/src/Keys.js +24 -0
  58. package/src/StaticAreaItem.js +1 -1
  59. package/src/UI5Element.js +24 -2
  60. package/src/UI5ElementMetadata.js +1 -1
  61. package/src/asset-registries/Icons.js +4 -8
  62. package/src/asset-registries/LocaleData.js +7 -2
  63. package/src/asset-registries/Themes.js +6 -2
  64. package/src/asset-registries/i18n.js +3 -1
  65. package/src/config/Icons.js +52 -0
  66. package/src/config/Theme.js +11 -0
  67. package/src/css/BusyIndicator.css +80 -0
  68. package/src/css/FontFace.css +31 -10
  69. package/src/delegate/ItemNavigation.js +9 -4
  70. package/src/features/F6Navigation.js +4 -0
  71. package/src/features/OpenUI5Enablement.js +119 -0
  72. package/src/i18nBundle.js +1 -1
  73. package/src/renderer/LitRenderer.js +29 -11
  74. package/src/renderer/executeTemplate.js +19 -2
  75. package/src/theming/getEffectiveLinksHrefs.js +7 -0
  76. package/src/theming/getEffectiveStyle.js +9 -0
  77. package/src/types/DOMReference.js +24 -0
  78. package/src/updateShadowRoot.js +2 -3
  79. package/src/util/AriaLabelHelper.js +2 -4
  80. package/src/util/Caret.js +1 -14
  81. package/src/util/ColorConversion.js +30 -2
  82. package/src/util/InvisibleMessage.js +20 -9
  83. package/src/util/TabbableElements.js +4 -0
  84. package/src/util/getEffectiveScrollbarStyle.js +5 -0
  85. package/src/util/getNormalizedTarget.js +16 -0
  86. package/src/util/isDefaultSlotProvided.js +11 -0
  87. package/config/.eslintrc.js +0 -3
  88. package/config/rollup.config.js +0 -1
  89. package/dist/isLegacyBrowser.js +0 -3
  90. package/dist/resources/bundle.esm.js +0 -37
  91. package/dist/resources/bundle.esm.js.map +0 -1
  92. package/dist/test-resources/assets/Themes.js +0 -17
  93. package/dist/test-resources/elements/Child.js +0 -35
  94. package/dist/test-resources/elements/Generic.js +0 -84
  95. package/dist/test-resources/elements/GenericExt.js +0 -26
  96. package/dist/test-resources/elements/NoShadowDOM.js +0 -13
  97. package/dist/test-resources/elements/Parent.js +0 -41
  98. package/dist/test-resources/elements/WithStaticArea.js +0 -77
  99. package/dist/test-resources/pages/AllTestElements.html +0 -42
  100. package/dist/test-resources/pages/Configuration.html +0 -18
  101. package/dist/test-resources/pages/ConfigurationScript.html +0 -34
  102. package/dist/test-resources/pages/assets/messagebundle_de.properties +0 -1
  103. package/dist/test-resources/pages/assets/messagebundle_en.properties +0 -1
  104. package/dist/test-resources/pages/assets/messagebundle_es.properties +0 -1
  105. package/dist/test-resources/pages/assets/messagebundle_fr.properties +0 -1
  106. package/dist/test-resources/pages/i18n.html +0 -33
  107. package/dist/test-resources/specs/ConfigurationChange.spec.js +0 -27
  108. package/dist/test-resources/specs/ConfigurationScript.spec.js +0 -63
  109. package/dist/test-resources/specs/ConfigurationURL.spec.js +0 -93
  110. package/dist/test-resources/specs/CustomTheme.spec.js +0 -27
  111. package/dist/test-resources/specs/EventProvider.spec.js +0 -63
  112. package/dist/test-resources/specs/StaticArea.spec.js +0 -78
  113. package/dist/test-resources/specs/Theming.spec.js +0 -33
  114. package/dist/test-resources/specs/UI5ElementInvalidation.js +0 -242
  115. package/dist/test-resources/specs/UI5ElementLifecycle.js +0 -98
  116. package/dist/test-resources/specs/UI5ElementListenForChildPropChanges.spec.js +0 -75
  117. package/dist/test-resources/specs/UI5ElementMetadataExt.js +0 -42
  118. package/dist/test-resources/specs/UI5ElementPropertyValidation.js +0 -14
  119. package/dist/test-resources/specs/UI5ElementPropsAndAttrs.spec.js +0 -67
  120. package/dist/test-resources/specs/UI5ElementShadowDOM.js +0 -24
  121. package/dist/test-resources/specs/UI5ElementSlots.js +0 -36
  122. package/dist/util/findNodeOwner.js +0 -35
  123. package/src/isLegacyBrowser.js +0 -3
  124. package/src/util/findNodeOwner.js +0 -35
@@ -1,18 +1,26 @@
1
- const fs = require('fs');
1
+ const fs = require('fs').promises;
2
2
  const path = require('path');
3
- const mkdirp = require('mkdirp');
4
3
  const CleanCSS = require('clean-css');
5
4
 
6
- mkdirp.sync("dist/generated/css/");
7
- fs.readdirSync("src/css/").filter(file => file.endsWith(".css")).forEach(file => {
8
- let content = fs.readFileSync(path.join("src/css/", file));
9
- const res = new CleanCSS().minify(`${content}`);
10
- content = `export default {
5
+ const generate = async () => {
6
+ await fs.mkdir("dist/generated/css/", {recursive: true});
7
+
8
+ const files = (await fs.readdir("src/css/")).filter(file => file.endsWith(".css"));
9
+ const filesPromises = files.map(async file => {
10
+ let content = await fs.readFile(path.join("src/css/", file));
11
+ const res = new CleanCSS().minify(`${content}`);
12
+ content = `export default {
11
13
  packageName: "@ui5/webcomponents-base",
12
14
  fileName: "${file}",
13
15
  content: \`${res.styles}\`
14
16
  };`;
15
17
 
16
- fs.writeFileSync(path.join("dist/generated/css/", `${file}.js`), content);
17
- });
18
+ return fs.writeFile(path.join("dist/generated/css/", `${file}.js`), content);
19
+ });
18
20
 
21
+ return Promise.all(filesPromises);
22
+ };
23
+
24
+ generate().then(() => {
25
+ console.log("Styles files generated.");
26
+ });
@@ -1,18 +1,18 @@
1
- const fs = require('fs');
2
- const mkdirp = require('mkdirp');
1
+ const fs = require('fs').promises;
3
2
 
4
- const version = JSON.parse(fs.readFileSync("package.json")).version;
3
+ const generate = async () => {
4
+ const version = JSON.parse(await fs.readFile("package.json")).version;
5
5
 
6
- // Parse version
7
- const matches = version.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(.*)$/);
8
- if (!matches) {
9
- throw new Error("Unsupported version format");
10
- }
6
+ // Parse version
7
+ const matches = version.match(/^([0-9]+)\.([0-9]+)\.([0-9]+)(.*)$/);
8
+ if (!matches) {
9
+ throw new Error("Unsupported version format");
10
+ }
11
11
 
12
- const isNext = version.match(/[a-f0-9]{9}$/);
13
- const buildTime = Math.floor(new Date().getTime() / 1000);
12
+ const isNext = version.match(/[a-f0-9]{9}$/);
13
+ const buildTime = Math.floor(new Date().getTime() / 1000);
14
14
 
15
- const fileContent = `const VersionInfo = {
15
+ const fileContent = `const VersionInfo = {
16
16
  version: "${version}",
17
17
  major: ${matches[1]},
18
18
  minor: ${matches[2]},
@@ -23,5 +23,10 @@ const fileContent = `const VersionInfo = {
23
23
  };
24
24
  export default VersionInfo;`;
25
25
 
26
- mkdirp.sync("dist/generated/");
27
- fs.writeFileSync("dist/generated/VersionInfo.js", fileContent);
26
+ await fs.mkdir("dist/generated/", { recursive: true });
27
+ await fs.writeFile("dist/generated/VersionInfo.js", fileContent);
28
+ }
29
+
30
+ generate().then(() => {
31
+ console.log("Version info file generated.");
32
+ });
@@ -1,29 +1,26 @@
1
1
  const resolve = require("resolve");
2
+ const path = require("path");
2
3
 
3
4
  const assetParametersScript = resolve.sync("@ui5/webcomponents-base/lib/generate-asset-parameters/index.js");
4
5
  const stylesScript = resolve.sync("@ui5/webcomponents-base/lib/generate-styles/index.js");
5
6
  const versionScript = resolve.sync("@ui5/webcomponents-base/lib/generate-version-info/index.js");
6
- const serve = resolve.sync("@ui5/webcomponents-tools/lib/serve/index.js");
7
- const generateHash = resolve.sync("@ui5/webcomponents-tools/lib/hash/generate.js");
8
- const hashIsUpToDate = resolve.sync("@ui5/webcomponents-tools/lib/hash/upToDate.js");
9
7
  const copyUsedModules = resolve.sync("@ui5/webcomponents-tools/lib/copy-list/index.js");
10
- const replaceGlobalCore = resolve.sync("@ui5/webcomponents-tools/lib/replace-global-core/index.js");
11
8
  const esmAbsToRel = resolve.sync("@ui5/webcomponents-tools/lib/esm-abs-to-rel/index.js");
12
- const UP_TO_DATE = `node "${hashIsUpToDate}" dist/ hash.txt && echo "Up to date."`;
9
+
10
+ const LIB = path.join(__dirname, `../tools/lib/`);
11
+
12
+ const viteConfig = `-c "${require.resolve("@ui5/webcomponents-tools/components-package/vite.config.js")}"`;
13
+ const eslintConfig = `--config ${require.resolve("@ui5/webcomponents-tools/components-package/eslint.js")}`;
13
14
 
14
15
  const scripts = {
15
16
  clean: "rimraf dist && rimraf .port",
16
- lint: "eslint . --config config/.eslintrc.js",
17
+ lint: `eslint . ${eslintConfig}`,
17
18
  prepare: "nps clean integrate copy generateAssetParameters generateVersionInfo generateStyles",
18
19
  integrate: {
19
- default: "nps integrate.copy-used-modules integrate.copy-overlay integrate.replace-amd integrate.replace-export-true integrate.replace-export-false integrate.amd-to-es6 integrate.replace-global-core-usage integrate.esm-abs-to-rel integrate.third-party",
20
+ default: "nps integrate.copy-used-modules integrate.replace-amd integrate.amd-to-es6 integrate.esm-abs-to-rel integrate.third-party",
20
21
  "copy-used-modules": `node "${copyUsedModules}" ./used-modules.txt dist/`,
21
- "copy-overlay": `copy-and-watch "overlay/**/*.js" dist/`,
22
22
  "replace-amd": "replace-in-file sap.ui.define define dist/**/*.js",
23
- "replace-export-true": `replace-in-file ", /* bExport= */ true" "" dist/**/*.js`,
24
- "replace-export-false": `replace-in-file ", /* bExport= */ false" "" dist/**/*.js`,
25
23
  "amd-to-es6": "amdtoes6 --src=dist/ --replace --glob=**/*.js",
26
- "replace-global-core-usage": `node "${replaceGlobalCore}" dist/`,
27
24
  "esm-abs-to-rel": `node "${esmAbsToRel}" dist/ dist/`,
28
25
  "third-party": {
29
26
  default: "nps integrate.third-party.copy integrate.third-party.fix",
@@ -32,33 +29,25 @@ const scripts = {
32
29
  },
33
30
  },
34
31
  build: {
35
- default: `${UP_TO_DATE} || nps lint prepare build.bundle hash`,
36
- bundle: "rollup --config config/rollup.config.js",
32
+ default: `nps lint prepare build.bundle`,
33
+ bundle: `vite build ${viteConfig}`,
37
34
  },
38
35
  copy: {
39
- default: "nps copy.src copy.test",
36
+ default: "nps copy.src",
40
37
  src: `copy-and-watch "src/**/*.{js,css}" dist/`,
41
- test: `copy-and-watch "test/**/*.*" dist/test-resources`,
42
38
  },
43
39
  generateAssetParameters: `node "${assetParametersScript}"`,
44
40
  generateVersionInfo: `node "${versionScript}"`,
45
41
  generateStyles: `node "${stylesScript}"`,
46
42
  watch: {
47
- default: 'concurrently "nps watch.test" "nps watch.src" "nps watch.bundle" "nps watch.styles"',
43
+ default: 'concurrently "nps watch.src" "nps watch.styles"',
44
+ withBundle: 'concurrently "nps watch.src" "nps watch.bundle" "nps watch.styles"',
48
45
  src: 'nps "copy.src --watch --skip-initial-copy"',
49
- test: 'nps "copy.test --watch --skip-initial-copy"',
50
- bundle: "rollup --config config/rollup.config.js -w --environment DEV",
46
+ bundle: `node ${LIB}/dev-server/dev-server.js ${viteConfig}`,
51
47
  styles: 'chokidar "src/css/*.css" -c "nps generateStyles"'
52
48
  },
53
- dev: 'concurrently "nps serve" "nps watch"',
54
- start: "nps prepare dev",
55
- serve: `node "${serve}" --dir="dist/" --port=9191 --packageName="@ui5/webcomponents-base"`,
56
- test: {
57
- // --success first - report the exit code of the test run (first command to finish), as serve is always terminated and has a non-0 exit code
58
- default: 'concurrently "nps serve" "nps test.run" --kill-others --success first',
59
- run: "cross-env WDIO_LOG_LEVEL=error FORCE_COLOR=0 wdio config/wdio.conf.js",
60
- },
61
- hash: `node "${generateHash}" dist/ hash.txt`,
49
+ start: "nps prepare watch.withBundle",
50
+ test: `node "${LIB}/test-runner/test-runner.js"`,
62
51
  };
63
52
 
64
53
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ui5/webcomponents-base",
3
- "version": "0.0.0-cf069fb29",
3
+ "version": "0.0.0-cf50976ce",
4
4
  "description": "UI5 Web Components: webcomponents.base",
5
5
  "author": "SAP SE (https://www.sap.com)",
6
6
  "license": "Apache-2.0",
@@ -28,21 +28,22 @@
28
28
  "start": "nps start",
29
29
  "build": "nps build",
30
30
  "test": "nps test",
31
- "hash": "nps hash",
32
31
  "prepublishOnly": "npm run clean && npm run build"
33
32
  },
34
33
  "dependencies": {
35
- "lit-html": "2.0.1"
34
+ "lit-html": "^2.0.1"
36
35
  },
37
36
  "devDependencies": {
38
37
  "@buxlabs/amd-to-es6": "0.16.1",
39
- "@openui5/sap.ui.core": "1.94.0",
40
- "@ui5/webcomponents-tools": "0.0.0-cf069fb29",
41
- "chromedriver": "96.0.0",
38
+ "@openui5/sap.ui.core": "1.101.0",
39
+ "@ui5/webcomponents-tools": "0.0.0-cf50976ce",
40
+ "chromedriver": "104.0.0",
42
41
  "clean-css": "^5.2.2",
43
42
  "copy-and-watch": "^0.1.5",
43
+ "cross-env": "^7.0.3",
44
44
  "eslint": "^7.22.0",
45
45
  "mkdirp": "^1.0.4",
46
+ "replace-in-file": "^6.3.5",
46
47
  "resolve": "^1.20.0"
47
48
  }
48
49
  }
package/src/Boot.js CHANGED
@@ -1,4 +1,3 @@
1
- import EventProvider from "./EventProvider.js";
2
1
  import whenDOMReady from "./util/whenDOMReady.js";
3
2
  import insertFontFace from "./FontFace.js";
4
3
  import insertSystemCSSVars from "./SystemCSSVars.js";
@@ -8,15 +7,15 @@ import { registerCurrentRuntime } from "./Runtimes.js";
8
7
  import { getFeature } from "./FeaturesRegistry.js";
9
8
 
10
9
  let bootPromise;
11
- const eventProvider = new EventProvider();
12
10
 
13
11
  /**
14
12
  * Attach a callback that will be executed on boot
15
13
  * @public
16
14
  * @param listener
17
15
  */
18
- const attachBoot = listener => {
19
- eventProvider.attachEvent("boot", listener);
16
+ const attachBoot = async listener => {
17
+ await boot();
18
+ listener();
20
19
  };
21
20
 
22
21
  const boot = async () => {
@@ -46,7 +45,6 @@ const boot = async () => {
46
45
  OpenUI5Support && OpenUI5Support.attachListeners();
47
46
  insertFontFace();
48
47
  insertSystemCSSVars();
49
- await eventProvider.fireEventAsync("boot");
50
48
 
51
49
  resolve();
52
50
  });
@@ -82,7 +82,7 @@ const displayFailedRegistrations = () => {
82
82
  }
83
83
  });
84
84
 
85
- message = `${message}\n\nTo prevent other runtimes from defining tags that you use, consider using scoping or have third-party libraries use scoping: https://github.com/SAP/ui5-webcomponents/blob/master/docs/2-advanced/03-scoping.md.`;
85
+ message = `${message}\n\nTo prevent other runtimes from defining tags that you use, consider using scoping or have third-party libraries use scoping: https://github.com/SAP/ui5-webcomponents/blob/main/docs/2-advanced/03-scoping.md.`;
86
86
 
87
87
  console.warn(message); // eslint-disable-line
88
88
  };
@@ -1,102 +1,24 @@
1
- let suf;
2
- let rulesObj = {
3
- include: [/^ui5-/],
4
- exclude: [],
5
- };
6
- const tagsCache = new Map(); // true/false means the tag should/should not be cached, undefined means not known yet.
7
-
8
- /**
9
- * Sets the suffix to be used for custom elements scoping, f.e. pass "demo" to get tags such as "ui5-button-demo".
10
- * Note: by default all tags starting with "ui5-" will be scoped, unless you change this by calling "setCustomElementsScopingRules"
11
- *
12
- * @public
13
- * @param suffix The scoping suffix
14
- */
15
- const setCustomElementsScopingSuffix = suffix => {
16
- if (!suffix.match(/^[a-zA-Z0-9_-]+$/)) {
17
- throw new Error("Only alphanumeric characters and dashes allowed for the scoping suffix");
18
- }
19
-
20
- suf = suffix;
21
- };
22
-
23
- /**
24
- * Returns the currently set scoping suffix, or undefined if not set.
25
- *
26
- * @public
27
- * @returns {String|undefined}
28
- */
29
- const getCustomElementsScopingSuffix = () => {
30
- return suf;
31
- };
1
+ import {
2
+ html,
3
+ svg,
4
+ unsafeStatic,
5
+ } from "lit-html/static.js";
32
6
 
33
- /**
34
- * Sets the rules, governing which custom element tags to scope and which not, f.e.
35
- * setCustomElementsScopingRules({include: [/^ui5-/]}, exclude: [/^ui5-mylib-/, /^ui5-carousel$/]);
36
- * will scope all elements starting with "ui5-" but not the ones starting with "ui5-mylib-" and not "ui5-carousel".
37
- *
38
- * @public
39
- * @param rules Object with "include" and "exclude" properties, both arrays of regular expressions. Note that "include"
40
- * rules are applied first and "exclude" rules second.
41
- */
42
- const setCustomElementsScopingRules = rules => {
43
- if (!rules || !rules.include) {
44
- throw new Error(`"rules" must be an object with at least an "include" property`);
45
- }
46
-
47
- if (!Array.isArray(rules.include) || rules.include.some(rule => !(rule instanceof RegExp))) {
48
- throw new Error(`"rules.include" must be an array of regular expressions`);
49
- }
50
-
51
- if (rules.exclude && (!Array.isArray(rules.exclude) || rules.exclude.some(rule => !(rule instanceof RegExp)))) {
52
- throw new Error(`"rules.exclude" must be an array of regular expressions`);
53
- }
54
-
55
- rules.exclude = rules.exclude || [];
56
- rulesObj = rules;
57
- tagsCache.clear(); // reset the cache upon setting new rules
58
- };
59
-
60
- /**
61
- * Returns the rules, governing which custom element tags to scope and which not. By default, all elements
62
- * starting with "ui5-" are scoped. The default rules are: {include: [/^ui5-/]}.
63
- *
64
- * @public
65
- * @returns {Object}
66
- */
67
- const getCustomElementsScopingRules = () => {
68
- return rulesObj;
69
- };
70
-
71
- /**
72
- * Determines whether custom elements with the given tag should be scoped or not.
73
- * The tag is first matched against the "include" rules and then against the "exclude" rules and the
74
- * result is cached until new rules are set.
75
- *
76
- * @public
77
- * @param tag
78
- */
79
- const shouldScopeCustomElement = tag => {
80
- if (!tagsCache.has(tag)) {
81
- const result = rulesObj.include.some(rule => tag.match(rule)) && !rulesObj.exclude.some(rule => tag.match(rule));
82
- tagsCache.set(tag, result);
83
- }
84
-
85
- return tagsCache.get(tag);
86
- };
87
-
88
- /**
89
- * Returns the currently set scoping suffix, if any and if the tag should be scoped, or undefined otherwise.
90
- *
91
- * @public
92
- * @param tag
93
- * @returns {String}
94
- */
95
- const getEffectiveScopingSuffixForTag = tag => {
96
- if (shouldScopeCustomElement(tag)) {
97
- return getCustomElementsScopingSuffix();
98
- }
99
- };
7
+ import {
8
+ setCustomElementsScopingSuffix,
9
+ getCustomElementsScopingSuffix,
10
+ setCustomElementsScopingRules,
11
+ getCustomElementsScopingRules,
12
+ shouldScopeCustomElement,
13
+ getEffectiveScopingSuffixForTag,
14
+ } from "./CustomElementsScopeUtils.js";
15
+ import { registerFeature } from "./FeaturesRegistry.js";
16
+
17
+ registerFeature("LitStatic", {
18
+ html,
19
+ svg,
20
+ unsafeStatic,
21
+ });
100
22
 
101
23
  export {
102
24
  setCustomElementsScopingSuffix,
@@ -0,0 +1,108 @@
1
+ let suf;
2
+ let rulesObj = {
3
+ include: [/^ui5-/],
4
+ exclude: [],
5
+ };
6
+ const tagsCache = new Map(); // true/false means the tag should/should not be cached, undefined means not known yet.
7
+
8
+ /**
9
+ * Sets the suffix to be used for custom elements scoping, f.e. pass "demo" to get tags such as "ui5-button-demo".
10
+ * Note: by default all tags starting with "ui5-" will be scoped, unless you change this by calling "setCustomElementsScopingRules"
11
+ *
12
+ * @public
13
+ * @param suffix The scoping suffix
14
+ */
15
+ const setCustomElementsScopingSuffix = suffix => {
16
+ if (!suffix.match(/^[a-zA-Z0-9_-]+$/)) {
17
+ throw new Error("Only alphanumeric characters and dashes allowed for the scoping suffix");
18
+ }
19
+
20
+ suf = suffix;
21
+ };
22
+
23
+ /**
24
+ * Returns the currently set scoping suffix, or undefined if not set.
25
+ *
26
+ * @public
27
+ * @returns {String|undefined}
28
+ */
29
+ const getCustomElementsScopingSuffix = () => {
30
+ return suf;
31
+ };
32
+
33
+ /**
34
+ * Sets the rules, governing which custom element tags to scope and which not, f.e.
35
+ * setCustomElementsScopingRules({include: [/^ui5-/]}, exclude: [/^ui5-mylib-/, /^ui5-carousel$/]);
36
+ * will scope all elements starting with "ui5-" but not the ones starting with "ui5-mylib-" and not "ui5-carousel".
37
+ *
38
+ * @public
39
+ * @param rules Object with "include" and "exclude" properties, both arrays of regular expressions. Note that "include"
40
+ * rules are applied first and "exclude" rules second.
41
+ */
42
+ const setCustomElementsScopingRules = rules => {
43
+ if (!rules || !rules.include) {
44
+ throw new Error(`"rules" must be an object with at least an "include" property`);
45
+ }
46
+
47
+ if (!Array.isArray(rules.include) || rules.include.some(rule => !(rule instanceof RegExp))) {
48
+ throw new Error(`"rules.include" must be an array of regular expressions`);
49
+ }
50
+
51
+ if (rules.exclude && (!Array.isArray(rules.exclude) || rules.exclude.some(rule => !(rule instanceof RegExp)))) {
52
+ throw new Error(`"rules.exclude" must be an array of regular expressions`);
53
+ }
54
+
55
+ rules.exclude = rules.exclude || [];
56
+ rulesObj = rules;
57
+ tagsCache.clear(); // reset the cache upon setting new rules
58
+ };
59
+
60
+ /**
61
+ * Returns the rules, governing which custom element tags to scope and which not. By default, all elements
62
+ * starting with "ui5-" are scoped. The default rules are: {include: [/^ui5-/]}.
63
+ *
64
+ * @public
65
+ * @returns {Object}
66
+ */
67
+ const getCustomElementsScopingRules = () => {
68
+ return rulesObj;
69
+ };
70
+
71
+ /**
72
+ * Determines whether custom elements with the given tag should be scoped or not.
73
+ * The tag is first matched against the "include" rules and then against the "exclude" rules and the
74
+ * result is cached until new rules are set.
75
+ *
76
+ * @public
77
+ * @param tag
78
+ */
79
+ const shouldScopeCustomElement = tag => {
80
+ if (!tagsCache.has(tag)) {
81
+ const result = rulesObj.include.some(rule => tag.match(rule)) && !rulesObj.exclude.some(rule => tag.match(rule));
82
+ tagsCache.set(tag, result);
83
+ }
84
+
85
+ return tagsCache.get(tag);
86
+ };
87
+
88
+ /**
89
+ * Returns the currently set scoping suffix, if any and if the tag should be scoped, or undefined otherwise.
90
+ *
91
+ * @public
92
+ * @param tag
93
+ * @returns {String}
94
+ */
95
+ const getEffectiveScopingSuffixForTag = tag => {
96
+ if (shouldScopeCustomElement(tag)) {
97
+ return getCustomElementsScopingSuffix();
98
+ }
99
+ };
100
+
101
+ export {
102
+ setCustomElementsScopingSuffix,
103
+ getCustomElementsScopingSuffix,
104
+ setCustomElementsScopingRules,
105
+ getCustomElementsScopingRules,
106
+ shouldScopeCustomElement,
107
+ getEffectiveScopingSuffixForTag,
108
+ };
package/src/Device.js CHANGED
@@ -103,6 +103,10 @@ const isIOS = () => {
103
103
  return iOS;
104
104
  };
105
105
 
106
+ const isAndroid = () => {
107
+ return android || androidPhone;
108
+ };
109
+
106
110
  export {
107
111
  supportsTouch,
108
112
  isIE,
@@ -113,4 +117,5 @@ export {
113
117
  isDesktop,
114
118
  isCombi,
115
119
  isIOS,
120
+ isAndroid,
116
121
  };
package/src/Keys.js CHANGED
@@ -111,6 +111,8 @@ const isSpace = event => (event.key ? (event.key === "Spacebar" || event.key ===
111
111
 
112
112
  const isSpaceShift = event => (event.key ? (event.key === "Spacebar" || event.key === " ") : event.keyCode === KeyCodes.SPACE) && checkModifierKeys(event, false, false, true);
113
113
 
114
+ const isSpaceCtrl = event => (event.key ? (event.key === "Spacebar" || event.key === " ") : event.keyCode === KeyCodes.SPACE) && checkModifierKeys(event, true, false, false);
115
+
114
116
  const isLeft = event => (event.key ? (event.key === "ArrowLeft" || event.key === "Left") : event.keyCode === KeyCodes.ARROW_LEFT) && !hasModifierKeys(event);
115
117
 
116
118
  const isRight = event => (event.key ? (event.key === "ArrowRight" || event.key === "Right") : event.keyCode === KeyCodes.ARROW_RIGHT) && !hasModifierKeys(event);
@@ -153,8 +155,12 @@ const isEnd = event => (event.key ? event.key === "End" : event.keyCode === KeyC
153
155
 
154
156
  const isHomeCtrl = event => (event.key ? event.key === "Home" : event.keyCode === KeyCodes.HOME) && checkModifierKeys(event, true, false, false);
155
157
 
158
+ const isHomeShift = event => (event.key ? event.key === "Home" : event.keyCode === KeyCodes.HOME) && checkModifierKeys(event, false, false, true);
159
+
156
160
  const isEndCtrl = event => (event.key ? event.key === "End" : event.keyCode === KeyCodes.END) && checkModifierKeys(event, true, false, false);
157
161
 
162
+ const isEndShift = event => (event.key ? event.key === "End" : event.keyCode === KeyCodes.END) && checkModifierKeys(event, false, false, true);
163
+
158
164
  const isEscape = event => (event.key ? event.key === "Escape" || event.key === "Esc" : event.keyCode === KeyCodes.ESCAPE) && !hasModifierKeys(event);
159
165
 
160
166
  const isTabNext = event => (event.key ? event.key === "Tab" : event.keyCode === KeyCodes.TAB) && !hasModifierKeys(event);
@@ -165,6 +171,12 @@ const isBackSpace = event => (event.key ? event.key === "Backspace" : event.keyC
165
171
 
166
172
  const isDelete = event => (event.key ? event.key === "Delete" : event.keyCode === KeyCodes.DELETE) && !hasModifierKeys(event);
167
173
 
174
+ const isDeleteShift = event => (event.key ? event.key === "Delete" : event.keyCode === KeyCodes.DELETE) && checkModifierKeys(event, false, false, true);
175
+
176
+ const isInsertShift = event => (event.key ? event.key === "Insert" : event.keyCode === KeyCodes.DELETE) && checkModifierKeys(event, false, false, true);
177
+
178
+ const isInsertCtrl = event => (event.key ? event.key === "Insert" : event.keyCode === KeyCodes.DELETE) && checkModifierKeys(event, true, false, false);
179
+
168
180
  const isPageUp = event => (event.key ? event.key === "PageUp" : event.keyCode === KeyCodes.PAGE_UP) && !hasModifierKeys(event);
169
181
 
170
182
  const isPageDown = event => (event.key ? event.key === "PageDown" : event.keyCode === KeyCodes.PAGE_DOWN) && !hasModifierKeys(event);
@@ -213,6 +225,10 @@ const isShowByArrows = event => {
213
225
 
214
226
  const isShift = event => event.key === "Shift" || event.keyCode === KeyCodes.SHIFT;
215
227
 
228
+ const isCtrlA = event => ((event.key === "A" || event.key === "a") || event.which === KeyCodes.A) && checkModifierKeys(event, true, false, false);
229
+
230
+ const isCtrlV = event => ((event.key === "V" || event.key === "v") || event.which === KeyCodes.V) && checkModifierKeys(event, true, false, false);
231
+
216
232
  const hasModifierKeys = event => event.shiftKey || event.altKey || getCtrlKey(event);
217
233
 
218
234
  const getCtrlKey = event => !!(event.metaKey || event.ctrlKey); // double negation doesn't have effect on boolean but ensures null and undefined are equivalent to false.
@@ -224,6 +240,7 @@ export {
224
240
  isEnterShift,
225
241
  isSpace,
226
242
  isSpaceShift,
243
+ isSpaceCtrl,
227
244
  isLeft,
228
245
  isRight,
229
246
  isUp,
@@ -248,6 +265,8 @@ export {
248
265
  isMinus,
249
266
  isHomeCtrl,
250
267
  isEndCtrl,
268
+ isHomeShift,
269
+ isEndShift,
251
270
  isEscape,
252
271
  isTabNext,
253
272
  isTabPrevious,
@@ -268,4 +287,9 @@ export {
268
287
  isPageUpShiftCtrl,
269
288
  isPageDownShiftCtrl,
270
289
  isShift,
290
+ isCtrlA,
291
+ isCtrlV,
292
+ isDeleteShift,
293
+ isInsertShift,
294
+ isInsertCtrl,
271
295
  };
@@ -2,7 +2,7 @@ import "./StaticArea.js";
2
2
  import updateShadowRoot from "./updateShadowRoot.js";
3
3
  import { renderFinished } from "./Render.js";
4
4
  import getEffectiveContentDensity from "./util/getEffectiveContentDensity.js";
5
- import { getEffectiveScopingSuffixForTag } from "./CustomElementsScope.js";
5
+ import { getEffectiveScopingSuffixForTag } from "./CustomElementsScopeUtils.js";
6
6
  import getEffectiveDir from "./locale/getEffectiveDir.js";
7
7
 
8
8
  /**
package/src/UI5Element.js CHANGED
@@ -46,6 +46,8 @@ function _invalidate(changeInfo) {
46
46
  this._eventProvider.fireEvent("invalidate", { ...changeInfo, target: this });
47
47
  }
48
48
 
49
+ let metadata = {};
50
+
49
51
  /**
50
52
  * Base class for all UI5 Web Components
51
53
  *
@@ -72,6 +74,7 @@ class UI5Element extends HTMLElement {
72
74
  deferredResolve = resolve;
73
75
  });
74
76
  this._domRefReadyPromise._deferredResolve = deferredResolve;
77
+ this._doNotSyncAttributes = new Set(); // attributes that are excluded from attributeChangedCallback synchronization
75
78
 
76
79
  this._initializeState();
77
80
  this._upgradeAllProperties();
@@ -374,6 +377,10 @@ class UI5Element extends HTMLElement {
374
377
  * @private
375
378
  */
376
379
  attributeChangedCallback(name, oldValue, newValue) {
380
+ if (this._doNotSyncAttributes.has(name)) { // This attribute is mutated internally, not by the user
381
+ return;
382
+ }
383
+
377
384
  const properties = this.constructor.getMetadata().getProperties();
378
385
  const realName = name.replace(/^ui5-/, "");
379
386
  const nameInCamelCase = kebabToCamelCase(realName);
@@ -407,7 +414,14 @@ class UI5Element extends HTMLElement {
407
414
  this.removeAttribute(attrName);
408
415
  }
409
416
  } else if (isDescendantOf(propertyTypeClass, DataType)) {
410
- this.setAttribute(attrName, propertyTypeClass.propertyToAttribute(newValue));
417
+ const newAttrValue = propertyTypeClass.propertyToAttribute(newValue);
418
+ if (newAttrValue === null) { // null means there must be no attribute for the current value of the property
419
+ this._doNotSyncAttributes.add(attrName); // skip the attributeChangedCallback call for this attribute
420
+ this.removeAttribute(attrName); // remove the attribute safely (will not trigger synchronization to the property value due to the above line)
421
+ this._doNotSyncAttributes.delete(attrName); // enable synchronization again for this attribute
422
+ } else {
423
+ this.setAttribute(attrName, newAttrValue);
424
+ }
411
425
  } else if (typeof newValue !== "object") {
412
426
  if (attrValue !== newValue) {
413
427
  this.setAttribute(attrName, newValue);
@@ -896,7 +910,15 @@ class UI5Element extends HTMLElement {
896
910
  * @protected
897
911
  */
898
912
  static get metadata() {
899
- return {};
913
+ return metadata;
914
+ }
915
+
916
+ /**
917
+ * Sets a new metadata object for this UI5 Web Component Class
918
+ * @protected
919
+ */
920
+ static set metadata(newMetadata) {
921
+ metadata = newMetadata;
900
922
  }
901
923
 
902
924
  /**
@@ -2,7 +2,7 @@ import DataType from "./types/DataType.js";
2
2
  import isDescendantOf from "./util/isDescendantOf.js";
3
3
  import { camelToKebabCase } from "./util/StringHelper.js";
4
4
  import { getSlottedElements } from "./util/SlotsHelper.js";
5
- import { getEffectiveScopingSuffixForTag } from "./CustomElementsScope.js";
5
+ import { getEffectiveScopingSuffixForTag } from "./CustomElementsScopeUtils.js";
6
6
 
7
7
  /**
8
8
  *