diff --git a/.github/actions/release.js b/.github/actions/release.cjs similarity index 100% rename from .github/actions/release.js rename to .github/actions/release.cjs diff --git a/.github/workflows/release-experimental.yaml b/.github/workflows/release-experimental.yaml index 7e1782df441f..d4d2089af63b 100644 --- a/.github/workflows/release-experimental.yaml +++ b/.github/workflows/release-experimental.yaml @@ -23,4 +23,4 @@ jobs: env: NPM_AUTH_TOKEN: ${{ secrets.NPM_RELEASE_AUTH_TOKEN }} run: | - node ./.github/actions/release.js \ No newline at end of file + node ./.github/actions/release.cjs \ No newline at end of file diff --git a/.gitignore b/.gitignore index 385cfaa390f2..639a94028e39 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ dist packages/compat/test/pages/scoped packages/main/test/pages/scoped packages/fiori/test/pages/scoped +packages/ai/test/pages/scoped # Ignore npm files/folders node_modules diff --git a/CHANGELOG.md b/CHANGELOG.md index 538f0bbf2e81..a28cff16e60a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,32 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* **framework:** always fire languageChange regardless of boot status ([#10029](https://github.com/SAP/ui5-webcomponents/issues/10029)) ([9261ac9](https://github.com/SAP/ui5-webcomponents/commit/9261ac93211ac431b9c1d95d255a6bb8bc3ff815)) +* **localization:** legacy date customization ([#10026](https://github.com/SAP/ui5-webcomponents/issues/10026)) ([273c015](https://github.com/SAP/ui5-webcomponents/commit/273c01597ae483fdfe1996dad733d32e4c9a13a9)) +* scoping issues and document how scoping is used correctly ([#10023](https://github.com/SAP/ui5-webcomponents/issues/10023)) ([ee808c3](https://github.com/SAP/ui5-webcomponents/commit/ee808c309f316fe145b05d292c92328396c655ab)) +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) +* **ui5-notification-list-group:** group header hight is shorter when collapsed ([#9953](https://github.com/SAP/ui5-webcomponents/issues/9953)) ([4c8a76e](https://github.com/SAP/ui5-webcomponents/commit/4c8a76edb5699810addd5c77fac2eabd507568f3)), closes [#9911](https://github.com/SAP/ui5-webcomponents/issues/9911) +* **ui5-page:** fix createElement error caused by adding new style property in the constructor ([#9998](https://github.com/SAP/ui5-webcomponents/issues/9998)) ([fd402e4](https://github.com/SAP/ui5-webcomponents/commit/fd402e41933da5e57456b736332872a0f0006cdf)), closes [#9981](https://github.com/SAP/ui5-webcomponents/issues/9981) +* **ui5-popup:** add role attribute to focus helper element ([#10004](https://github.com/SAP/ui5-webcomponents/issues/10004)) ([82a95ce](https://github.com/SAP/ui5-webcomponents/commit/82a95cebfc93fb4be696b76110f2089be1593db8)), closes [#9982](https://github.com/SAP/ui5-webcomponents/issues/9982) +* **ui5-range-slider:** right click on the slider handle does not throw ([#10015](https://github.com/SAP/ui5-webcomponents/issues/10015)) ([e92caf9](https://github.com/SAP/ui5-webcomponents/commit/e92caf96d9ab4548090820e6bbf7217c43d99fd4)) +* **ui5-slider, ui5-range-slider:** adjust styles according to Fiori specs ([#9973](https://github.com/SAP/ui5-webcomponents/issues/9973)) ([e1182a9](https://github.com/SAP/ui5-webcomponents/commit/e1182a9ee44c6975b93208c16ef584cf0d0104d6)), closes [#9614](https://github.com/SAP/ui5-webcomponents/issues/9614) + + +### Features + +* **create-package:** produce packages of type="module" ([#9993](https://github.com/SAP/ui5-webcomponents/issues/9993)) ([b161f60](https://github.com/SAP/ui5-webcomponents/commit/b161f601253b966fc0bb7a01213165c0963c85ca)) +* **ui5-barcode-scanner-dialog:** added capture region overlay ([#9646](https://github.com/SAP/ui5-webcomponents/issues/9646)) ([19475eb](https://github.com/SAP/ui5-webcomponents/commit/19475eb897d08c5f09ae2583678cc79decca5adc)) +* **ui5-slider, ui5-range-slider:** add input as a tooltip ([#9547](https://github.com/SAP/ui5-webcomponents/issues/9547)) ([6a4dedf](https://github.com/SAP/ui5-webcomponents/commit/6a4dedf47431d7f7dda7c19f54170bc877c2a33d)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) diff --git a/docs/2-advanced/06-scoping.md b/docs/2-advanced/06-scoping.md index 1e48184b17ab..fd96b489ed54 100644 --- a/docs/2-advanced/06-scoping.md +++ b/docs/2-advanced/06-scoping.md @@ -11,10 +11,13 @@ The `scoping` feature lets you add an arbitrary suffix to the names of all UI5 W Example: ```js +// scoping-config.js import { setCustomElementsScopingSuffix } from "@ui5/webcomponents-base/dist/CustomElementsScope.js"; setCustomElementsScopingSuffix("demo"); ``` +** NOTE: ** Setting the scoping suffix should be done before importing any components, as they use the suffix at the top-level of the module - meaning when a component is imported, the suffix has to be known. For this to work, calling the method should be done in a separate module (`scoping-config.js` in the example above) and this module should be imported before any components are imported. + Then all names can only be used with the supplied suffix: ```html @@ -34,7 +37,7 @@ will not have any effect. ## When do I need to use the `scoping` feature? -The `scoping` feature is completely optional. It is not needed for application development, but it is strongly recommended when building **libraries** and **micro-frontends**. +The `scoping` feature is completely optional. It is not needed for application development, but it is strongly recommended when building **libraries** and **micro-frontends**. It ensures that the custom elements that your code uses have not already been reserved by another library or an older version of UI5 Web Components. If, for example, your code may be loaded on demand by unknown applications as a third-party service, there is always the risk that the app diff --git a/lerna.json b/lerna.json index dfdb24bdbb69..622f2016503a 100644 --- a/lerna.json +++ b/lerna.json @@ -14,7 +14,7 @@ "packages/create-package", "packages/compat" ], - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "command": { "publish": { "allowBranch": "*", diff --git a/package.json b/package.json index 2fed4eed8c0d..857323ea161a 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "lint:scope": "wsrun --exclude-missing lint:scope", "link-all": "wsrun link", "unlink-all": "wsrun unlink", - "release": "node ./.github/actions/release.js", + "release": "node ./.github/actions/release.cjs", "prepare": "husky install", "husky:commit-msg": "commitlint -e", "husky:pre-push": "npm-run-all --sequential husky:commit-msg", diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index f8227fdaa136..6e53045294c2 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* scoping issues and document how scoping is used correctly ([#10023](https://github.com/SAP/ui5-webcomponents/issues/10023)) ([ee808c3](https://github.com/SAP/ui5-webcomponents/commit/ee808c309f316fe145b05d292c92328396c655ab)) +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) diff --git a/packages/ai/package.json b/packages/ai/package.json index b3250b0d4a84..4f6d8e3f0a87 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-ai", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: webcomponents.ai", "ui5": { "webComponentsPackage": true @@ -45,13 +45,13 @@ "directory": "packages/ai" }, "dependencies": { - "@ui5/webcomponents": "2.4.0-rc.0", - "@ui5/webcomponents-base": "2.4.0-rc.0", - "@ui5/webcomponents-icons": "2.4.0-rc.0", - "@ui5/webcomponents-theming": "2.4.0-rc.0" + "@ui5/webcomponents": "2.4.0-rc.1", + "@ui5/webcomponents-base": "2.4.0-rc.1", + "@ui5/webcomponents-icons": "2.4.0-rc.1", + "@ui5/webcomponents-theming": "2.4.0-rc.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "2.4.0-rc.0", + "@ui5/webcomponents-tools": "2.4.0-rc.1", "chromedriver": "^128.0.3" } } diff --git a/packages/ai/src/bundle.scoped.config.ts b/packages/ai/src/bundle.scoped.config.ts new file mode 100644 index 000000000000..fc2a2c80f3d1 --- /dev/null +++ b/packages/ai/src/bundle.scoped.config.ts @@ -0,0 +1,3 @@ +import { setCustomElementsScopingSuffix } from "@ui5/webcomponents-base/dist/CustomElementsScope.js"; + +setCustomElementsScopingSuffix("demo"); diff --git a/packages/ai/src/bundle.scoped.esm.ts b/packages/ai/src/bundle.scoped.esm.ts index fc2a2c80f3d1..e918d9c3de5a 100644 --- a/packages/ai/src/bundle.scoped.esm.ts +++ b/packages/ai/src/bundle.scoped.esm.ts @@ -1,3 +1,2 @@ -import { setCustomElementsScopingSuffix } from "@ui5/webcomponents-base/dist/CustomElementsScope.js"; - -setCustomElementsScopingSuffix("demo"); +import "./bundle.scoped.config.js"; +import "./bundle.esm.js"; diff --git a/packages/ai/tsconfig.json b/packages/ai/tsconfig.json index 9b3375e27e69..f3ef5b4c8afe 100644 --- a/packages/ai/tsconfig.json +++ b/packages/ai/tsconfig.json @@ -8,6 +8,8 @@ "outDir": "dist", "experimentalDecorators": true, "verbatimModuleSyntax": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", "paths": { "@ui5/webcomponents-base/dist/*": [ "../base/src/*" diff --git a/packages/base/CHANGELOG.md b/packages/base/CHANGELOG.md index 23091c7a7b58..ad8cfd5e964c 100644 --- a/packages/base/CHANGELOG.md +++ b/packages/base/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* **framework:** always fire languageChange regardless of boot status ([#10029](https://github.com/SAP/ui5-webcomponents/issues/10029)) ([9261ac9](https://github.com/SAP/ui5-webcomponents/commit/9261ac93211ac431b9c1d95d255a6bb8bc3ff815)) +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) diff --git a/packages/base/package.json b/packages/base/package.json index 612c088ad1f6..aa3642463388 100644 --- a/packages/base/package.json +++ b/packages/base/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-base", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: webcomponents.base", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -52,7 +52,7 @@ }, "devDependencies": { "@openui5/sap.ui.core": "1.120.17", - "@ui5/webcomponents-tools": "2.4.0-rc.0", + "@ui5/webcomponents-tools": "2.4.0-rc.1", "chromedriver": "^128.0.3", "clean-css": "^5.2.2", "copy-and-watch": "^0.1.5", diff --git a/packages/base/src/UI5Element.ts b/packages/base/src/UI5Element.ts index cf411638023f..14d4a7dbf3d1 100644 --- a/packages/base/src/UI5Element.ts +++ b/packages/base/src/UI5Element.ts @@ -1271,12 +1271,13 @@ abstract class UI5Element extends HTMLElement { * @public */ static define(): typeof UI5Element { - this.definePromise = Promise.all([ - this.fetchI18nBundles(), - this.fetchCLDR(), - boot(), - this.onDefine(), - ]).then(result => { + const defineSequence = async () => { + await boot(); // boot must finish first, because it initializes configuration + const result = await Promise.all([ + this.fetchI18nBundles(), // uses configuration + this.fetchCLDR(), + this.onDefine(), + ]); const [i18nBundles] = result; Object.entries(this.getMetadata().getI18n()).forEach((pair, index) => { const propertyName = pair[0]; @@ -1284,7 +1285,8 @@ abstract class UI5Element extends HTMLElement { (targetClass as Record)[propertyName] = i18nBundles[index]; }); this.asyncFinished = true; - }); + }; + this.definePromise = defineSequence(); const tag = this.getMetadata().getTag(); diff --git a/packages/base/src/config/Language.ts b/packages/base/src/config/Language.ts index 9147fb8cd0d3..2e64e23f7251 100644 --- a/packages/base/src/config/Language.ts +++ b/packages/base/src/config/Language.ts @@ -43,8 +43,8 @@ const setLanguage = async (language: string): Promise => { curLanguage = language; + await fireLanguageChange(language); if (isBooted()) { - await fireLanguageChange(language); await reRenderAllUI5Elements({ languageAware: true }); } }; diff --git a/packages/base/tsconfig.json b/packages/base/tsconfig.json index 4d4867a07013..5fae63f93e91 100644 --- a/packages/base/tsconfig.json +++ b/packages/base/tsconfig.json @@ -10,6 +10,8 @@ "composite": true, "rootDir": "src", "experimentalDecorators": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", "tsBuildInfoFile": "dist/.tsbuildinfobuild", "paths": { "@ui5/webcomponents-base/dist/ssr-dom.js": ["./src/ssr-dom.ts"], diff --git a/packages/compat/CHANGELOG.md b/packages/compat/CHANGELOG.md index 0db93f98e576..1a2180260e09 100644 --- a/packages/compat/CHANGELOG.md +++ b/packages/compat/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* scoping issues and document how scoping is used correctly ([#10023](https://github.com/SAP/ui5-webcomponents/issues/10023)) ([ee808c3](https://github.com/SAP/ui5-webcomponents/commit/ee808c309f316fe145b05d292c92328396c655ab)) +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) diff --git a/packages/compat/package.json b/packages/compat/package.json index 88f4b3ae1045..6a5dc5a8f20d 100644 --- a/packages/compat/package.json +++ b/packages/compat/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-compat", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: webcomponents.compat", "ui5": { "webComponentsPackage": true @@ -45,13 +45,13 @@ "directory": "packages/compat" }, "dependencies": { - "@ui5/webcomponents": "2.4.0-rc.0", - "@ui5/webcomponents-base": "2.4.0-rc.0", - "@ui5/webcomponents-icons": "2.4.0-rc.0", - "@ui5/webcomponents-theming": "2.4.0-rc.0" + "@ui5/webcomponents": "2.4.0-rc.1", + "@ui5/webcomponents-base": "2.4.0-rc.1", + "@ui5/webcomponents-icons": "2.4.0-rc.1", + "@ui5/webcomponents-theming": "2.4.0-rc.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "2.4.0-rc.0", + "@ui5/webcomponents-tools": "2.4.0-rc.1", "chromedriver": "^128.0.3" } } diff --git a/packages/compat/src/bundle.scoped.config.ts b/packages/compat/src/bundle.scoped.config.ts new file mode 100644 index 000000000000..3fe16329ef22 --- /dev/null +++ b/packages/compat/src/bundle.scoped.config.ts @@ -0,0 +1,5 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { setCustomElementsScopingSuffix, setCustomElementsScopingRules } from "@ui5/webcomponents-base/dist/CustomElementsScope.js"; + +setCustomElementsScopingSuffix("demo"); +// setCustomElementsScopingRules({include: [/^ui5-/], exclude: [/^ui5-button/, /ui5-icon/]}); diff --git a/packages/compat/src/bundle.scoped.esm.ts b/packages/compat/src/bundle.scoped.esm.ts index a31eb8c8f92a..612cd96d3c54 100644 --- a/packages/compat/src/bundle.scoped.esm.ts +++ b/packages/compat/src/bundle.scoped.esm.ts @@ -1,8 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { setCustomElementsScopingSuffix, setCustomElementsScopingRules } from "@ui5/webcomponents-base/dist/CustomElementsScope.js"; - -setCustomElementsScopingSuffix("demo"); -// setCustomElementsScopingRules({include: [/^ui5-/], exclude: [/^ui5-button/, /ui5-icon/]}); +import "./bundle.scoped.config.js"; // eslint-disable-next-line import/first import testAssets from "./bundle.esm.js"; diff --git a/packages/compat/tsconfig.json b/packages/compat/tsconfig.json index 9b3375e27e69..f3ef5b4c8afe 100644 --- a/packages/compat/tsconfig.json +++ b/packages/compat/tsconfig.json @@ -8,6 +8,8 @@ "outDir": "dist", "experimentalDecorators": true, "verbatimModuleSyntax": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", "paths": { "@ui5/webcomponents-base/dist/*": [ "../base/src/*" diff --git a/packages/create-package/CHANGELOG.md b/packages/create-package/CHANGELOG.md index 94fe7a60909f..c9fa24693072 100644 --- a/packages/create-package/CHANGELOG.md +++ b/packages/create-package/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Features + +* **create-package:** produce packages of type="module" ([#9993](https://github.com/SAP/ui5-webcomponents/issues/9993)) ([b161f60](https://github.com/SAP/ui5-webcomponents/commit/b161f601253b966fc0bb7a01213165c0963c85ca)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) **Note:** Version bump only for package @ui5/create-webcomponents-package diff --git a/packages/create-package/create-package.js b/packages/create-package/create-package.js index 2a3139eecd56..496d38ef7ef9 100755 --- a/packages/create-package/create-package.js +++ b/packages/create-package/create-package.js @@ -108,6 +108,7 @@ const generateFilesContent = (packageName, componentName, skipSubfolder) => { ui5: { webComponentsPackage: true, }, + type: "module", scripts: { "clean": "wc-dev clean", "lint": "wc-dev lint", diff --git a/packages/create-package/package.json b/packages/create-package/package.json index cd1dc77aec9b..8c2bcc44ebc6 100644 --- a/packages/create-package/package.json +++ b/packages/create-package/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/create-webcomponents-package", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: create package", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", diff --git a/packages/create-package/template/.eslintignore b/packages/create-package/template/.eslintignore index 85f67b9ed90b..1b13da817f72 100644 --- a/packages/create-package/template/.eslintignore +++ b/packages/create-package/template/.eslintignore @@ -2,4 +2,4 @@ dist test src/generated -.eslintrc.js \ No newline at end of file +.eslintrc.cjs \ No newline at end of file diff --git a/packages/create-package/template/.eslintrc.js b/packages/create-package/template/.eslintrc.cjs similarity index 100% rename from packages/create-package/template/.eslintrc.js rename to packages/create-package/template/.eslintrc.cjs diff --git a/packages/create-package/template/.npsrc.json b/packages/create-package/template/.npsrc.json new file mode 100644 index 000000000000..27e1830331e0 --- /dev/null +++ b/packages/create-package/template/.npsrc.json @@ -0,0 +1,3 @@ +{ + "config": "./package-scripts.cjs" +} \ No newline at end of file diff --git a/packages/create-package/template/config/wdio.conf.js b/packages/create-package/template/config/wdio.conf.cjs similarity index 100% rename from packages/create-package/template/config/wdio.conf.js rename to packages/create-package/template/config/wdio.conf.cjs diff --git a/packages/create-package/template/package-scripts.js b/packages/create-package/template/package-scripts.cjs similarity index 100% rename from packages/create-package/template/package-scripts.js rename to packages/create-package/template/package-scripts.cjs diff --git a/packages/create-package/template/test/pages/css/index.css b/packages/create-package/template/test/pages/css/index.css index d9b2fc5d60f2..9a9f5a42c735 100644 --- a/packages/create-package/template/test/pages/css/index.css +++ b/packages/create-package/template/test/pages/css/index.css @@ -22,6 +22,11 @@ h2 { flex-direction: column; } +.app-logo { + height: 230px; + width: 230px; +} + .app-first-component { margin-bottom: 3rem; } diff --git a/packages/create-package/template/test/pages/img/logo.png b/packages/create-package/template/test/pages/img/logo.png index da5a54aceb2b..8f967f0dcef6 100644 Binary files a/packages/create-package/template/test/pages/img/logo.png and b/packages/create-package/template/test/pages/img/logo.png differ diff --git a/packages/create-package/template/test/pages/index.html b/packages/create-package/template/test/pages/index.html index e840beaec4d7..d00dcea0ddc0 100644 --- a/packages/create-package/template/test/pages/index.html +++ b/packages/create-package/template/test/pages/index.html @@ -21,7 +21,7 @@
- logo +

Hooray! It's Your First Web Component!

diff --git a/packages/create-package/template/test/specs/Demo.spec.js b/packages/create-package/template/test/specs/Demo.spec.js index 013f99cd4eda..99ed33b42792 100644 --- a/packages/create-package/template/test/specs/Demo.spec.js +++ b/packages/create-package/template/test/specs/Demo.spec.js @@ -1,4 +1,4 @@ -const assert = require("assert"); +import { assert } from "chai"; describe("INIT_PACKAGE_VAR_TAG rendering", async () => { before(async () => { diff --git a/packages/create-package/template/tsconfig.json b/packages/create-package/template/tsconfig.json index 77a82457a8ac..60f126645015 100644 --- a/packages/create-package/template/tsconfig.json +++ b/packages/create-package/template/tsconfig.json @@ -7,5 +7,7 @@ "compilerOptions": { "outDir": "dist", "experimentalDecorators": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", }, } \ No newline at end of file diff --git a/packages/fiori/CHANGELOG.md b/packages/fiori/CHANGELOG.md index 9bc9c023c002..88d094a11c5d 100644 --- a/packages/fiori/CHANGELOG.md +++ b/packages/fiori/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) +* **ui5-notification-list-group:** group header hight is shorter when collapsed ([#9953](https://github.com/SAP/ui5-webcomponents/issues/9953)) ([4c8a76e](https://github.com/SAP/ui5-webcomponents/commit/4c8a76edb5699810addd5c77fac2eabd507568f3)), closes [#9911](https://github.com/SAP/ui5-webcomponents/issues/9911) +* **ui5-page:** fix createElement error caused by adding new style property in the constructor ([#9998](https://github.com/SAP/ui5-webcomponents/issues/9998)) ([fd402e4](https://github.com/SAP/ui5-webcomponents/commit/fd402e41933da5e57456b736332872a0f0006cdf)), closes [#9981](https://github.com/SAP/ui5-webcomponents/issues/9981) + + +### Features + +* **ui5-barcode-scanner-dialog:** added capture region overlay ([#9646](https://github.com/SAP/ui5-webcomponents/issues/9646)) ([19475eb](https://github.com/SAP/ui5-webcomponents/commit/19475eb897d08c5f09ae2583678cc79decca5adc)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) diff --git a/packages/fiori/cypress/specs/BarcodeScannerDialog.cy.ts b/packages/fiori/cypress/specs/BarcodeScannerDialog.cy.ts new file mode 100644 index 000000000000..e87df3fb908a --- /dev/null +++ b/packages/fiori/cypress/specs/BarcodeScannerDialog.cy.ts @@ -0,0 +1,349 @@ +import { html } from "lit"; +import "@ui5/webcomponents-icons/dist/camera.js"; +import "../../src/BarcodeScannerDialog.js"; +import type BarcodeScannerDialog from "../../src/BarcodeScannerDialog.js"; + +describe("BarcodeScannerDialog", () => { + let handleScanSuccess: (event: CustomEvent) => void; + let handleScanError: (event: CustomEvent) => void; + + beforeEach(() => { + cy.mount(html` + + Open Scanner Dialog + +
+ + +
+ `); + + cy.get("#dlgScan").as("dialog"); + cy.get("#btnScan").as("button"); + cy.get("@dialog") + .shadow() + .find(".ui5-barcode-scanner-dialog-video") + .as("videoElement"); + + // Add event listener to the button to open the dialog + cy.document().then(doc => { + const dlgScan = doc.querySelector("#dlgScan")!; + const btnScan = doc.querySelector("#btnScan")!; + + btnScan.addEventListener("click", () => { + dlgScan.open = true; + }); + }); + }); + + afterEach(() => { + // Remove event listeners if they were added + cy.document().then(doc => { + const dlgScan = doc.querySelector("#dlgScan")!; + if (handleScanSuccess) { + dlgScan.removeEventListener("scan-success", handleScanSuccess as EventListener); + handleScanSuccess = undefined!; + } + if (handleScanError) { + dlgScan.removeEventListener("scan-error", handleScanError as EventListener); + handleScanError = undefined!; + } + + // Clear the scan result and error + const scanResultElement = doc.querySelector("#scanResult")!; + const scanErrorElement = doc.querySelector("#scanError")!; + scanResultElement.textContent = ""; + scanErrorElement.textContent = ""; + }); + }); + + it("should open and close the dialog", () => { + // Before clicking, the dialog should not be open + cy.get("@dialog") + .shadow() + .find("ui5-dialog") + .should("not.have.attr", "open"); + + // Click the button to open the dialog + cy.get("@button").realClick(); + + // Wait for the video to be ready + cy.get("@videoElement").should($video => { + const videoEl = $video[0] as HTMLVideoElement; + expect(videoEl.readyState, "Video readyState should be >= 1").to.be.at.least(1); + }); + + // Assert that the dialog is open + cy.get("@dialog") + .shadow() + .find("ui5-dialog") + .should("have.attr", "open"); + + // Close the dialog using the close button + cy.get("@dialog") + .shadow() + .find("ui5-dialog [slot=footer] ui5-button") + .realClick(); + + // Verify the dialog is closed + cy.get("@dialog") + .shadow() + .find("ui5-dialog") + .should("not.have.attr", "open"); + }); + + it("closes barcode scanner dialog with escape key", () => { + // Click the button to open the dialog + cy.get("@button").realClick(); + + // Wait for the video to be ready + cy.get("@videoElement").should($video => { + const videoEl = $video[0] as HTMLVideoElement; + expect(videoEl.readyState, "Video readyState should be >= 1").to.be.at.least(1); + }); + + // Assert that the dialog is open + cy.get("@dialog") + .shadow() + .find("ui5-dialog") + .should("have.attr", "open"); + + // Simulate pressing the Escape key + cy.get("@dialog").realPress("Escape"); + + // Verify the dialog is closed + cy.get("@dialog") + .shadow() + .find("ui5-dialog") + .should("not.have.attr", "open"); + }); + + it("opens barcode scanner dialog and checks video stream", () => { + // Click the button to open the dialog + cy.get("@button").realClick(); + + // Wait for the video to be ready + cy.get("@videoElement").should($video => { + const videoEl = $video[0] as HTMLVideoElement; + expect(videoEl.readyState, "Video readyState should be >= 1").to.be.at.least(1); + }); + + // Assert that the dialog is open + cy.get("@dialog") + .shadow() + .find("ui5-dialog") + .should("have.attr", "open"); + + // Check that video.srcObject is not null + cy.get("@videoElement").should($video => { + const videoEl = $video[0] as HTMLVideoElement; + // eslint-disable-next-line no-unused-expressions + expect(videoEl.srcObject, "Video srcObject should not be null").to.not.be.null; + }); + + // Get the overlay canvas element + cy.get("@dialog") + .shadow() + .find(".ui5-barcode-scanner-dialog-overlay") + .as("overlayElement") + .should("be.visible"); + + // Check that the canvas dimensions match the video element's dimensions + cy.get("@videoElement").then($video => { + cy.get("@overlayElement").then($canvas => { + expect( + ($canvas[0] as HTMLCanvasElement).width, + "Canvas width should match video width", + ).to.equal($video[0].clientWidth); + expect( + ($canvas[0] as HTMLCanvasElement).height, + "Canvas height should match video height", + ).to.equal($video[0].clientHeight); + }); + }); + }); + + it("stops media tracks when the dialog is closed", () => { + // Click the button to open the dialog + cy.get("@button").realClick(); + + // Wait for the video to be ready + cy.get("@videoElement").should($video => { + const videoEl = $video[0] as HTMLVideoElement; + expect(videoEl.readyState, "Video readyState should be >= 1").to.be.at.least(1); + }); + + // Assert that the dialog is open + cy.get("@dialog") + .shadow() + .find("ui5-dialog") + .should("have.attr", "open"); + + // Save the media stream + cy.get("@videoElement").then($video => { + const videoEl = $video[0] as HTMLVideoElement; + cy.wrap(videoEl.srcObject).as("mediaStream"); + }); + + // Close the dialog using the close button + cy.get("@dialog") + .shadow() + .find("ui5-dialog [slot=footer] ui5-button") + .realClick(); + + // Verify the dialog is closed + cy.get("@dialog") + .shadow() + .find("ui5-dialog") + .should("not.have.attr", "open"); + + // Check that media tracks are stopped + cy.get("@mediaStream").then(currentSubject => { + const mediaStream = currentSubject as unknown as MediaStream; + const tracksStopped = mediaStream + .getTracks() + .every(track => track.readyState === "ended"); + // eslint-disable-next-line no-unused-expressions + expect(tracksStopped, "All media tracks should be stopped").to.be.true; + }); + + // Check that video srcObject is cleared + cy.get("@videoElement").then($video => { + const videoEl = $video[0] as HTMLVideoElement; + // eslint-disable-next-line no-unused-expressions + expect(videoEl.srcObject, "Video srcObject should be null").to.be.null; + }); + }); + + it("displays the busy indicator while loading", () => { + // Stub the _getUserPermission method to simulate delay + cy.get("@dialog").then($dialog => { + const dlgScan = $dialog.get(0) as BarcodeScannerDialog; + + const stub = cy + .stub(dlgScan, "_getUserPermission") + .callsFake(() => new Promise(() => { })); // Never resolves + cy.wrap(stub).as("getUserPermissionStub"); + }); + + // Open the dialog + cy.get("@button").realClick(); + + // Check that the busy indicator is visible + cy.get("@dialog") + .shadow() + .find(".ui5-barcode-scanner-dialog-busy") + .should("be.visible"); + + // Restore the stub + cy.get("@getUserPermissionStub").then(stub => { + (stub as unknown as sinon.SinonStub).restore(); + }); + }); + + it("handles scan success event", () => { + // Define the event handler function + handleScanSuccess = (event: CustomEvent) => { + const detail = event.detail; + const scanResultElement = document.querySelector("#scanResult")!; + scanResultElement.textContent = detail.text; + }; + + // Get the scanResult element + cy.get("#scanResult").as("scanResult"); + + // Add event listener to display scan result + cy.get("@dialog").then($dialog => { + const dlgScan = $dialog.get(0) as BarcodeScannerDialog; + dlgScan.addEventListener("scan-success", handleScanSuccess as EventListener); + }); + + // Open the dialog + cy.get("@button").realClick(); + + // Simulate scan success + cy.get("@dialog").then($dialog => { + const dlgScan = $dialog.get(0) as BarcodeScannerDialog; + + // Simulate the scan success + dlgScan.fireEvent("scan-success", { + text: "mocked-scan-result", + rawBytes: new Uint8Array(), + }); + }); + + // Check that the scan result is displayed + cy.get("@scanResult").should("have.text", "mocked-scan-result"); + }); + + it("handles scan error event", () => { + // Define the event handler function + handleScanError = (event: CustomEvent) => { + const detail = event.detail; + const scanErrorElement = document.querySelector("#scanError")!; + scanErrorElement.textContent = detail.message; + }; + + // Get the scanError element + cy.get("#scanError").as("scanError"); + + // Add event listener to display scan error + cy.get("@dialog").then($dialog => { + const dlgScan = $dialog.get(0) as BarcodeScannerDialog; + dlgScan.addEventListener("scan-error", handleScanError as EventListener); + }); + + // Open the dialog + cy.get("@button").realClick(); + + // Simulate scan error + cy.get("@dialog").then($dialog => { + const dlgScan = $dialog.get(0) as BarcodeScannerDialog; + + // Simulate the scan error + dlgScan.fireEvent("scan-error", { + message: "mocked-scan-error", + }); + }); + + // Check that the scan error is displayed + cy.get("@scanError").should("have.text", "mocked-scan-error"); + }); + + it("handles permission denied error", () => { + // Define the event handler function + handleScanError = (event: CustomEvent) => { + const detail = event.detail; + const scanErrorElement = document.querySelector("#scanError")!; + scanErrorElement.textContent = detail.message; + }; + + // Get the scanError element + cy.get("#scanError").as("scanError"); + + // Stub getUserMedia to reject with "Permission denied" + cy.window().then(win => { + const stub = cy + .stub(win.navigator.mediaDevices, "getUserMedia") + .rejects(new DOMException("Permission denied", "NotAllowedError")); + cy.wrap(stub).as("getUserMediaStub"); + }); + + // Add event listener to display scan error + cy.get("@dialog").then($dialog => { + const dlgScan = $dialog.get(0) as BarcodeScannerDialog; + dlgScan.addEventListener("scan-error", handleScanError as EventListener); + }); + + // Open the dialog + cy.get("@button").realClick(); + + // Check that the scan error is displayed + cy.get("@scanError").should("contain.text", "Permission denied"); + + // Restore the stub + cy.get("@getUserMediaStub").then(stub => { + (stub as unknown as sinon.SinonStub).restore(); + }); + }); +}); diff --git a/packages/fiori/package.json b/packages/fiori/package.json index e00517953db7..523e2864a9d8 100644 --- a/packages/fiori/package.json +++ b/packages/fiori/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-fiori", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: webcomponents.fiori", "ui5": { "webComponentsPackage": true @@ -53,14 +53,14 @@ "directory": "packages/fiori" }, "dependencies": { - "@ui5/webcomponents": "2.4.0-rc.0", - "@ui5/webcomponents-base": "2.4.0-rc.0", - "@ui5/webcomponents-icons": "2.4.0-rc.0", - "@ui5/webcomponents-theming": "2.4.0-rc.0", + "@ui5/webcomponents": "2.4.0-rc.1", + "@ui5/webcomponents-base": "2.4.0-rc.1", + "@ui5/webcomponents-icons": "2.4.0-rc.1", + "@ui5/webcomponents-theming": "2.4.0-rc.1", "@zxing/library": "^0.17.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "2.4.0-rc.0", + "@ui5/webcomponents-tools": "2.4.0-rc.1", "chromedriver": "^128.0.3", "lit": "^2.0.0" } diff --git a/packages/fiori/src/BarcodeScannerDialog.hbs b/packages/fiori/src/BarcodeScannerDialog.hbs index 00f29115596b..a1c293ee9499 100644 --- a/packages/fiori/src/BarcodeScannerDialog.hbs +++ b/packages/fiori/src/BarcodeScannerDialog.hbs @@ -1,19 +1,11 @@ - +
- + +
- -
+ \ No newline at end of file diff --git a/packages/fiori/src/BarcodeScannerDialog.ts b/packages/fiori/src/BarcodeScannerDialog.ts index cedaa80e845f..8b6f61a97363 100644 --- a/packages/fiori/src/BarcodeScannerDialog.ts +++ b/packages/fiori/src/BarcodeScannerDialog.ts @@ -8,7 +8,9 @@ import customElement from "@ui5/webcomponents-base/dist/decorators/customElement import property from "@ui5/webcomponents-base/dist/decorators/property.js"; import event from "@ui5/webcomponents-base/dist/decorators/event.js"; import i18n from "@ui5/webcomponents-base/dist/decorators/i18n.js"; +import { getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import type { Result, Exception } from "@zxing/library/esm5/index.js"; +import type { Interval } from "@ui5/webcomponents-base/dist/types.js"; // eslint-disable-next-line import/no-extraneous-dependencies import ZXing from "@ui5/webcomponents-fiori/dist/ssr-zxing.js"; @@ -86,6 +88,7 @@ type BarcodeScannerDialogScanErrorEventDetail = { /** * Fired when the user closes the component. + * @since 2.0.0 * @public */ @event("close", { @@ -101,12 +104,12 @@ type BarcodeScannerDialogScanErrorEventDetail = { @event("scan-success", { detail: { /** - * @public - */ + * @public + */ text: { type: String }, /** - * @public - */ + * @public + */ rawBytes: { type: Object }, }, bubbles: true, @@ -120,8 +123,8 @@ type BarcodeScannerDialogScanErrorEventDetail = { @event("scan-error", { detail: { /** - * @public - */ + * @public + */ message: { type: String }, }, bubbles: true, @@ -134,12 +137,12 @@ class BarcodeScannerDialog extends UI5Element { * @public * @default false * @since 1.24.0 - */ + */ @property({ type: Boolean }) open = false; /** - * Indicates whether a loading indicator should be displayed in the dialog. + * Indicates whether a loading indicator should be displayed while the scanner is loading. * @default false * @private */ @@ -147,59 +150,84 @@ class BarcodeScannerDialog extends UI5Element { loading = false; /** - * Indicates whether the user has granted permissions to use the camera. + * Indicates whether the scanner is ready to scan. * @default false * @private */ @property({ type: Boolean, noAttribute: true }) - permissionsGranted = false; + isReadyToScan = false; - _codeReader: InstanceType; dialog?: Dialog; @i18n("@ui5/webcomponents-fiori") static i18nBundle: I18nBundle; + _codeReader: InstanceType; + _tempCanvas!: HTMLCanvasElement; + _scanInterval!: Interval | null; + _handleVideoPlayingBound: () => void; + _handleCaptureRegionBound: () => void; constructor() { super(); this._codeReader = new BrowserMultiFormatReader(); + this._handleVideoPlayingBound = this._handleVideoPlaying.bind(this); + this._handleCaptureRegionBound = this._handleDrawCaptureRegion.bind(this); } - onAfterRendering() { - if (this.open) { - if (this.loading) { - return; - } - - if (!this._hasGetUserMedia()) { - this.fireDecoratorEvent("scan-error", { message: "getUserMedia() is not supported by your browser" }); - return; - } - - if (!this.permissionsGranted) { - this.loading = true; - } - - this._getUserPermission() - .then(() => { - this.permissionsGranted = true; - }) - .catch(err => { - this.fireDecoratorEvent("scan-error", { message: err }); - this.loading = false; - }); - } else { + static async onDefine() { + BarcodeScannerDialog.i18nBundle = await getI18nBundle("@ui5/webcomponents-fiori"); + } + + async onAfterRendering() { + if (!this._hasGetUserMedia()) { + this.fireDecoratorEvent("scan-error", { message: "getUserMedia() is not supported by your browser" }); + return; + } + + if (!this.open || this.loading) { + return; + } + + if (!this.isReadyToScan) { + this.loading = true; + } + + const video = this._getVideoElement(); + if (video.srcObject) { + return; + } + + try { + const stream = await this._getUserPermission(); + video.addEventListener("loadeddata", this._handleVideoPlayingBound); + video.srcObject = stream; + } catch (error) { + this.fireDecoratorEvent("scan-error", { message: (error as Error).message }); this.loading = false; } } + onEnterDOM() { + super.onEnterDOM(); + window.addEventListener("resize", this._handleCaptureRegionBound); + } + + onExitDOM() { + super.onExitDOM(); + window.removeEventListener("resize", this._handleCaptureRegionBound); + } + get _open() { - return this.open && this.permissionsGranted; + return this.open && this.isReadyToScan; } - /** - * PRIVATE METHODS - */ + get _cancelButtonText() { + return BarcodeScannerDialog.i18nBundle.getText(BARCODE_SCANNER_DIALOG_CANCEL_BUTTON_TXT); + } + + get _busyIndicatorText() { + return BarcodeScannerDialog.i18nBundle.getText(BARCODE_SCANNER_DIALOG_LOADING_TXT); + } _hasGetUserMedia() { return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia); @@ -213,48 +241,220 @@ class BarcodeScannerDialog extends UI5Element { return this.shadowRoot!.querySelector(".ui5-barcode-scanner-dialog-video")!; } - _closeDialog() { - this.open = false; + _getOverlayCanvasElement() { + return this.shadowRoot!.querySelector(".ui5-barcode-scanner-dialog-overlay")!; } - _fireCloseEvent() { - this.open = false; - this.fireDecoratorEvent("close"); - } + /** + * CALCULATIONS + * + * The following methods are used to calculate the capture region + * and draw it on the overlay canvas. + * The capture region is a square area in the center of the video element + * where the barcode scanning is performed. + * The region is defined as a proportion of the video element's dimensions. + * The overlay canvas is used to draw a semi-transparent black overlay + * over the video element and a red border around the capture region. + * The overlay canvas is updated on every frame to ensure the capture region is always visible. + * The capture region is used to crop the video frame and extract the barcode image. + * The extracted image is then processed by the zxing-js library to decode the barcode. + */ - _startReader() { - this._decodeFromCamera(); + _calculateCaptureRegion(clientWidth: number, clientHeight: number) { + // Define the maximum scan size as a proportion of the video element + const maxScanProportion = 0.66666667; // 2:3 + // Calculate maximum square dimension based on video dimensions and max proportion + const maxScanDimension = Math.min(clientWidth, clientHeight) * maxScanProportion; + // Calculate offset to center the square scan region + const xOffset = (clientWidth - maxScanDimension) / 2; + const yOffset = (clientHeight - maxScanDimension) / 2; + // Calculate the width and height of the scan region + const scanWidth = Math.floor(maxScanDimension); + const scanHeight = Math.floor(maxScanDimension); + + return { + scanHeight, + scanWidth, + xOffset, + yOffset, + }; } - _resetReader() { + _drawCaptureRegion() { const videoElement = this._getVideoElement(); - videoElement.pause(); - this._codeReader.reset(); + const canvasElement = this._getOverlayCanvasElement(); + const context = canvasElement.getContext("2d")!; + + const videoClientWidth = videoElement.clientWidth; + const videoClientHeight = videoElement.clientHeight; + + // Set canvas dimensions to match the video element's dimensions + canvasElement.width = videoClientWidth; + canvasElement.height = videoClientHeight; + + // Clear the canvas + context.clearRect(0, 0, videoClientWidth, videoClientHeight); + // Calculate the capture region + const captureRegion = this._calculateCaptureRegion(videoClientWidth, videoClientHeight); + + // Draw a semi-transparent black overlay over the video + context.fillStyle = "rgba(0, 0, 0, 0.5)"; + context.fillRect(0, 0, videoClientWidth, videoClientHeight); + context.clearRect(captureRegion.xOffset, captureRegion.yOffset, captureRegion.scanWidth, captureRegion.scanHeight); + + // Draw red border around the capture region + context.strokeStyle = "red"; + context.lineWidth = 1; + context.strokeRect(captureRegion.xOffset, captureRegion.yOffset, captureRegion.scanWidth, captureRegion.scanHeight); + + // Display the overlay + canvasElement.style.display = "block"; } - _decodeFromCamera() { - const videoElement = this._getVideoElement(); - this._codeReader.decodeFromVideoDevice(null, videoElement, (result: Result, err?: Exception) => { - this.loading = false; - if (result) { - this.fireDecoratorEvent("scan-success", - { - text: result.getText(), - rawBytes: result.getRawBytes(), - }); - } - if (err && !(err instanceof NotFoundException)) { - this.fireDecoratorEvent("scan-error", { message: err.message }); - } - }).catch((err: Error) => this.fireDecoratorEvent("scan-error", { message: err.message })); + _getTempCanvasElement() { + if (!this._tempCanvas) { + this._tempCanvas = document.createElement("canvas"); + } + return this._tempCanvas; } - get _cancelButtonText() { - return BarcodeScannerDialog.i18nBundle.getText(BARCODE_SCANNER_DIALOG_CANCEL_BUTTON_TXT); + _captureFrame() { + const video = this._getVideoElement(); + const tempCanvas = this._getTempCanvasElement(); + const context = tempCanvas.getContext("2d")!; + + const videoWidth = video.videoWidth; + const videoHeight = video.videoHeight; + const clientWidth = video.clientWidth; + const clientHeight = video.clientHeight; + + const captureRegion = this._calculateCaptureRegion(clientWidth, clientHeight); + + // Calculate the ratio of videoSize to clientSize + const ratioX = videoWidth / clientWidth; + const ratioY = videoHeight / clientHeight; + const scale = Math.min(ratioX, ratioY); + + // Calculate the scaled capture region + const scaledXOffset = captureRegion.xOffset * scale; + const scaledYOffset = captureRegion.yOffset * scale; + const scaledScanWidth = captureRegion.scanWidth * scale; + const scaledScanHeight = captureRegion.scanHeight * scale; + + // Set canvas dimensions to match the capture region dimensions + tempCanvas.width = captureRegion.scanWidth; + tempCanvas.height = captureRegion.scanHeight; + + // Clear the canvas + context.clearRect(0, 0, tempCanvas.width, tempCanvas.height); + + // Correct positioning if aspect ratios are different + const positionX = (videoWidth - clientWidth * scale) / 2; + const positionY = (videoHeight - clientHeight * scale) / 2; + + // Calculate final source position considering the video element's offset + const finalXOffset = scaledXOffset + positionX; + const finalYOffset = scaledYOffset + positionY; + + // Draw the portion of the video on the canvas + context.drawImage( + video, + finalXOffset, finalYOffset, scaledScanWidth, scaledScanHeight, // Source rectangle + 0, 0, tempCanvas.width, tempCanvas.height, // Destination rectangle + ); + + return tempCanvas; } - get _busyIndicatorText() { - return BarcodeScannerDialog.i18nBundle.getText(BARCODE_SCANNER_DIALOG_LOADING_TXT); + /** + * HANDLERS + */ + + async _processFrame() { + try { + const canvas = this._captureFrame(); + const dataUrl = canvas.toDataURL(); + const result = await this._codeReader.decodeFromImageUrl(dataUrl); + + this._handleScanSuccess(result); + } catch (error) { + this._handleScanError(error as Exception); + } + } + + _handleScanSuccess(result: Result) { + this.fireDecoratorEvent("scan-success", { + text: result.getText(), + rawBytes: result.getRawBytes(), + }); + } + + _handleScanError(error: Exception) { + if (error instanceof NotFoundException) { + return; + } + + this.fireDecoratorEvent("scan-error", { message: error.message }); + } + + _handleVideoPlaying() { + const FRAME_PROCESSING_INTERVAL = 200; // 5 frames per second + + this.loading = false; + this.isReadyToScan = true; + + // Wait for the next animation frame before drawing the capture region + requestAnimationFrame(() => { + this._drawCaptureRegion(); + }); + + // Ensure any existing interval is cleared before setting a new one + if (this._scanInterval) { + clearInterval(this._scanInterval); + } + + this._scanInterval = setInterval(() => { + this._processFrame(); + }, FRAME_PROCESSING_INTERVAL); + } + + _handleDrawCaptureRegion() { + this._drawCaptureRegion(); + } + + _closeDialog() { + this._resetReader(); + this.open = false; + this.fireDecoratorEvent("close"); + } + + _resetReader() { + const video = this._getVideoElement(); + video.pause(); + + if (video.srcObject) { + const stream = video.srcObject as MediaStream; + const tracks = stream.getTracks(); + tracks.forEach(track => track.stop()); + } + + video.srcObject = null; + video.removeEventListener("loadeddata", this._handleVideoPlayingBound); + + if (this._scanInterval) { + clearInterval(this._scanInterval); + this._scanInterval = null; + } + + if (this._codeReader) { + this._codeReader.reset(); + } + + const overlay = this._getOverlayCanvasElement(); + overlay.style.display = "none"; + + // Reset the ready state + this.isReadyToScan = false; } } diff --git a/packages/fiori/src/themes/BarcodeScannerDialog.css b/packages/fiori/src/themes/BarcodeScannerDialog.css index ed9d417658ef..a78877072a1e 100644 --- a/packages/fiori/src/themes/BarcodeScannerDialog.css +++ b/packages/fiori/src/themes/BarcodeScannerDialog.css @@ -1,34 +1,45 @@ -.ui5-barcode-scanner-dialog-root::part(content) { - padding: .4375rem; -} - -/* video */ -.ui5-barcode-scanner-dialog-video-wrapper, -.ui5-barcode-scanner-dialog-video { - height:100%; - width: 100%; -} - -.ui5-barcode-scanner-dialog-video { - object-fit: cover; -} - -/* footer */ -.ui5-barcode-scanner-dialog-footer { - display: flex; - justify-content: flex-end; - width: 100%; -} - -/* busy indicator */ -.ui5-barcode-scanner-dialog-busy { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - z-index: 1; -} - -.ui5-barcode-scanner-dialog-busy:not([active]) { - display: none; -} +.ui5-barcode-scanner-dialog-root::part(content) { + padding: .4375rem; +} + +.ui5-barcode-scanner-dialog-video-wrapper { + position: relative; +} + +/* video */ +.ui5-barcode-scanner-dialog-video-wrapper, +.ui5-barcode-scanner-dialog-video, +.ui5-barcode-scanner-dialog-overlay { + height: 100%; + width: 100%; +} + +.ui5-barcode-scanner-dialog-video { + object-fit: cover; +} + +.ui5-barcode-scanner-dialog-overlay { + display: none; + position: absolute; + inset: 0; +} + +/* footer */ +.ui5-barcode-scanner-dialog-footer { + display: flex; + justify-content: flex-end; + width: 100%; +} + +/* busy indicator */ +.ui5-barcode-scanner-dialog-busy { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 1; +} + +.ui5-barcode-scanner-dialog-busy:not([active]) { + display: none; +} \ No newline at end of file diff --git a/packages/fiori/test/pages/styles/NotificationListGroupItem.css b/packages/fiori/test/pages/styles/NotificationListGroupItem.css index 03af9ad0de7b..06e6fc045871 100644 --- a/packages/fiori/test/pages/styles/NotificationListGroupItem.css +++ b/packages/fiori/test/pages/styles/NotificationListGroupItem.css @@ -40,6 +40,7 @@ .notificationsPopoverHeader { display: flex; + flex: 1; flex-direction: column; } diff --git a/packages/fiori/test/specs/BarcodeScannerDialog.spec.js b/packages/fiori/test/specs/BarcodeScannerDialog.spec.js deleted file mode 100644 index bb0dc937637d..000000000000 --- a/packages/fiori/test/specs/BarcodeScannerDialog.spec.js +++ /dev/null @@ -1,25 +0,0 @@ -import { assert } from "chai"; - -describe("BarcodeScannerDialog Behavior", () => { - before(async () => { - await browser.url(`test/pages/BarcodeScannerDialog.html`); - }); - - it("fires scan-error when no permissions granted", async () => { - // Setup: deny permissions to access the camera - await browser.setPermissions({ name: 'camera' }, 'denied'); - const btnScan = await browser.$("#btnScan"), - scanError = await browser.$("#scanError"); - - await btnScan.click(); - - await browser.waitUntil(async () => { - return (await scanError.getText()).length > 0; - }, 25000, "expect scan-error output"); - - // assert - const scanErrorText = await scanError.getText(); - assert.ok(scanErrorText.length, "fires scan-error when no permissions"); - }); - -}); diff --git a/packages/fiori/tsconfig.json b/packages/fiori/tsconfig.json index b09867c8255a..4d295ceadb8b 100644 --- a/packages/fiori/tsconfig.json +++ b/packages/fiori/tsconfig.json @@ -11,6 +11,8 @@ "rootDir": "src", "tsBuildInfoFile": "dist/.tsbuildinfo", "verbatimModuleSyntax": true, + "module": "NodeNext", + "moduleResolution": "NodeNext", "paths": { "@ui5/webcomponents-base/dist/*": [ "../base/src/*" diff --git a/packages/icons-business-suite/CHANGELOG.md b/packages/icons-business-suite/CHANGELOG.md index a22f7268f7dc..2b1e1a20adc9 100644 --- a/packages/icons-business-suite/CHANGELOG.md +++ b/packages/icons-business-suite/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) **Note:** Version bump only for package @ui5/webcomponents-icons-business-suite diff --git a/packages/icons-business-suite/package.json b/packages/icons-business-suite/package.json index 24dbf538db2d..4b9bc8efa16e 100644 --- a/packages/icons-business-suite/package.json +++ b/packages/icons-business-suite/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-icons-business-suite", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: SAP Fiori Tools icon set", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -28,9 +28,9 @@ "directory": "packages/icons-business-suite" }, "dependencies": { - "@ui5/webcomponents-base": "2.4.0-rc.0" + "@ui5/webcomponents-base": "2.4.0-rc.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "2.4.0-rc.0" + "@ui5/webcomponents-tools": "2.4.0-rc.1" } } diff --git a/packages/icons-business-suite/tsconfig.json b/packages/icons-business-suite/tsconfig.json index 5bd6b2c18608..8b9c95c62797 100644 --- a/packages/icons-business-suite/tsconfig.json +++ b/packages/icons-business-suite/tsconfig.json @@ -10,6 +10,8 @@ "allowSyntheticDefaultImports": true, "composite": true, "rootDir": "src", + "module": "NodeNext", + "moduleResolution": "NodeNext", "tsBuildInfoFile": "dist/.tsbuildinfo", "paths": { "@ui5/webcomponents-base/dist/*": [ diff --git a/packages/icons-tnt/CHANGELOG.md b/packages/icons-tnt/CHANGELOG.md index 37ae05887981..6343e7694806 100644 --- a/packages/icons-tnt/CHANGELOG.md +++ b/packages/icons-tnt/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) **Note:** Version bump only for package @ui5/webcomponents-icons-tnt diff --git a/packages/icons-tnt/package.json b/packages/icons-tnt/package.json index 5eddbade3883..6663972d97bd 100644 --- a/packages/icons-tnt/package.json +++ b/packages/icons-tnt/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-icons-tnt", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: SAP Fiori Tools icon set", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -28,9 +28,9 @@ "directory": "packages/icons-tnt" }, "dependencies": { - "@ui5/webcomponents-base": "2.4.0-rc.0" + "@ui5/webcomponents-base": "2.4.0-rc.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "2.4.0-rc.0" + "@ui5/webcomponents-tools": "2.4.0-rc.1" } } diff --git a/packages/icons-tnt/tsconfig.json b/packages/icons-tnt/tsconfig.json index 5bd6b2c18608..8b9c95c62797 100644 --- a/packages/icons-tnt/tsconfig.json +++ b/packages/icons-tnt/tsconfig.json @@ -10,6 +10,8 @@ "allowSyntheticDefaultImports": true, "composite": true, "rootDir": "src", + "module": "NodeNext", + "moduleResolution": "NodeNext", "tsBuildInfoFile": "dist/.tsbuildinfo", "paths": { "@ui5/webcomponents-base/dist/*": [ diff --git a/packages/icons/CHANGELOG.md b/packages/icons/CHANGELOG.md index 55ceddfc5fe7..19d3a1ef71da 100644 --- a/packages/icons/CHANGELOG.md +++ b/packages/icons/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) **Note:** Version bump only for package @ui5/webcomponents-icons diff --git a/packages/icons/package.json b/packages/icons/package.json index 41b19dc3fe1e..f4a9f6ee3fc1 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-icons", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: webcomponents.SAP-icons", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -28,9 +28,9 @@ "directory": "packages/icons" }, "dependencies": { - "@ui5/webcomponents-base": "2.4.0-rc.0" + "@ui5/webcomponents-base": "2.4.0-rc.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "2.4.0-rc.0" + "@ui5/webcomponents-tools": "2.4.0-rc.1" } } diff --git a/packages/icons/tsconfig.json b/packages/icons/tsconfig.json index 5bd6b2c18608..8b9c95c62797 100644 --- a/packages/icons/tsconfig.json +++ b/packages/icons/tsconfig.json @@ -10,6 +10,8 @@ "allowSyntheticDefaultImports": true, "composite": true, "rootDir": "src", + "module": "NodeNext", + "moduleResolution": "NodeNext", "tsBuildInfoFile": "dist/.tsbuildinfo", "paths": { "@ui5/webcomponents-base/dist/*": [ diff --git a/packages/localization/CHANGELOG.md b/packages/localization/CHANGELOG.md index bd1665854ef0..98a582ddf3a1 100644 --- a/packages/localization/CHANGELOG.md +++ b/packages/localization/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* **localization:** legacy date customization ([#10026](https://github.com/SAP/ui5-webcomponents/issues/10026)) ([273c015](https://github.com/SAP/ui5-webcomponents/commit/273c01597ae483fdfe1996dad733d32e4c9a13a9)) +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) **Note:** Version bump only for package @ui5/webcomponents-localization diff --git a/packages/localization/package.json b/packages/localization/package.json index 678b816d2187..c9a0c874263f 100644 --- a/packages/localization/package.json +++ b/packages/localization/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-localization", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "Localization for UI5 Web Components", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -33,7 +33,7 @@ "@babel/generator": "^7.23.6", "@babel/parser": "^7.23.6", "@openui5/sap.ui.core": "1.120.17", - "@ui5/webcomponents-tools": "2.4.0-rc.0", + "@ui5/webcomponents-tools": "2.4.0-rc.1", "babel-plugin-amd-to-esm": "^2.0.3", "chromedriver": "^128.0.3", "estree-walk": "^2.2.0", @@ -42,6 +42,6 @@ }, "dependencies": { "@types/openui5": "^1.113.0", - "@ui5/webcomponents-base": "2.4.0-rc.0" + "@ui5/webcomponents-base": "2.4.0-rc.1" } } diff --git a/packages/localization/src/sap/base/i18n/Formatting.ts b/packages/localization/src/sap/base/i18n/Formatting.ts new file mode 100644 index 000000000000..fabe9e81ddee --- /dev/null +++ b/packages/localization/src/sap/base/i18n/Formatting.ts @@ -0,0 +1,13 @@ +import { getLegacyDateCalendarCustomizing } from "@ui5/webcomponents-base/dist/config/FormatSettings.js"; + +const emptyFn = () => {}; + +/** + * OpenUI5 Formatting Shim + */ +const Formatting = { + getABAPDateFormat: emptyFn, + getCustomIslamicCalendarData: getLegacyDateCalendarCustomizing, +}; + +export default Formatting; diff --git a/packages/localization/src/sap/ui/core/FormatSettings.ts b/packages/localization/src/sap/ui/core/FormatSettings.ts index 23b2ab830a06..c38b368283d1 100644 --- a/packages/localization/src/sap/ui/core/FormatSettings.ts +++ b/packages/localization/src/sap/ui/core/FormatSettings.ts @@ -1,5 +1,4 @@ import getLocale from "@ui5/webcomponents-base/dist/locale/getLocale.js"; -import { getLegacyDateCalendarCustomizing } from "@ui5/webcomponents-base/dist/config/FormatSettings.js"; const emptyFn = () => {}; @@ -10,7 +9,6 @@ const FormatSettings = { getFormatLocale: getLocale, getLegacyDateFormat: emptyFn, getCustomLocaleData: emptyFn, - getLegacyDateCalendarCustomizing, }; export default FormatSettings; diff --git a/packages/localization/tsconfig.json b/packages/localization/tsconfig.json index 8fad119a3d3c..3e870b404b12 100644 --- a/packages/localization/tsconfig.json +++ b/packages/localization/tsconfig.json @@ -7,6 +7,8 @@ "outDir": "dist", "composite": true, "rootDir": "src", + "module": "NodeNext", + "moduleResolution": "NodeNext", "tsBuildInfoFile": "dist/.tsbuildinfo", "paths": { "@ui5/webcomponents-base/dist/*": [ diff --git a/packages/localization/used-modules.txt b/packages/localization/used-modules.txt index bd8112b962d2..a62e0e5f3598 100644 --- a/packages/localization/used-modules.txt +++ b/packages/localization/used-modules.txt @@ -2,7 +2,6 @@ # ./ui5loader-autoconfig.js # sap/base/Log.js -sap/base/i18n/Formatting.js sap/base/assert.js # sap/base/config.js sap/base/config/MemoryConfigurationProvider.js diff --git a/packages/main/CHANGELOG.md b/packages/main/CHANGELOG.md index 169c002cae3a..35e78858eba5 100644 --- a/packages/main/CHANGELOG.md +++ b/packages/main/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* **localization:** legacy date customization ([#10026](https://github.com/SAP/ui5-webcomponents/issues/10026)) ([273c015](https://github.com/SAP/ui5-webcomponents/commit/273c01597ae483fdfe1996dad733d32e4c9a13a9)) +* scoping issues and document how scoping is used correctly ([#10023](https://github.com/SAP/ui5-webcomponents/issues/10023)) ([ee808c3](https://github.com/SAP/ui5-webcomponents/commit/ee808c309f316fe145b05d292c92328396c655ab)) +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) +* **ui5-popup:** add role attribute to focus helper element ([#10004](https://github.com/SAP/ui5-webcomponents/issues/10004)) ([82a95ce](https://github.com/SAP/ui5-webcomponents/commit/82a95cebfc93fb4be696b76110f2089be1593db8)), closes [#9982](https://github.com/SAP/ui5-webcomponents/issues/9982) +* **ui5-range-slider:** right click on the slider handle does not throw ([#10015](https://github.com/SAP/ui5-webcomponents/issues/10015)) ([e92caf9](https://github.com/SAP/ui5-webcomponents/commit/e92caf96d9ab4548090820e6bbf7217c43d99fd4)) +* **ui5-slider, ui5-range-slider:** adjust styles according to Fiori specs ([#9973](https://github.com/SAP/ui5-webcomponents/issues/9973)) ([e1182a9](https://github.com/SAP/ui5-webcomponents/commit/e1182a9ee44c6975b93208c16ef584cf0d0104d6)), closes [#9614](https://github.com/SAP/ui5-webcomponents/issues/9614) + + +### Features + +* **ui5-slider, ui5-range-slider:** add input as a tooltip ([#9547](https://github.com/SAP/ui5-webcomponents/issues/9547)) ([6a4dedf](https://github.com/SAP/ui5-webcomponents/commit/6a4dedf47431d7f7dda7c19f54170bc877c2a33d)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) diff --git a/packages/main/cypress/specs/Form.cy.ts b/packages/main/cypress/specs/Form.cy.ts index de83d8118a65..2519abcf643d 100644 --- a/packages/main/cypress/specs/Form.cy.ts +++ b/packages/main/cypress/specs/Form.cy.ts @@ -4,6 +4,58 @@ import "../../src/FormItem.js"; import "../../src/FormGroup.js"; describe("General API", () => { + it("tests calculated state of Form with default layout and label-span", () => { + cy.mount(html` + + + Name: + Red Point Stores + + + + + + Twitter: + @sap + + + + + + Name: + Red Point Stores + + + `); + + cy.get("[ui5-form]") + .as("form"); + + cy.get("@form") + .should("have.prop", "columnsS", 1); + + cy.get("@form") + .should("have.prop", "labelSpanS", 12); + + cy.get("@form") + .should("have.prop", "columnsM", 1); + + cy.get("@form") + .should("have.prop", "labelSpanM", 4); + + cy.get("@form") + .should("have.prop", "columnsL", 2); + + cy.get("@form") + .should("have.prop", "labelSpanL", 4); + + cy.get("@form") + .should("have.prop", "columnsXl", 3); + + cy.get("@form") + .should("have.prop", "labelSpanXl", 4); + }); + it("tests calculated state of Form with layout='S1 M2 L3 XL6' and label-span='S12 M4 L4 XL4'", () => { cy.mount(html` diff --git a/packages/main/package.json b/packages/main/package.json index bb3913af4560..1df755146185 100644 --- a/packages/main/package.json +++ b/packages/main/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: webcomponents.main", "ui5": { "webComponentsPackage": true @@ -50,15 +50,15 @@ "directory": "packages/main" }, "dependencies": { - "@ui5/webcomponents-base": "2.4.0-rc.0", - "@ui5/webcomponents-icons": "2.4.0-rc.0", - "@ui5/webcomponents-icons-business-suite": "2.4.0-rc.0", - "@ui5/webcomponents-icons-tnt": "2.4.0-rc.0", - "@ui5/webcomponents-localization": "2.4.0-rc.0", - "@ui5/webcomponents-theming": "2.4.0-rc.0" + "@ui5/webcomponents-base": "2.4.0-rc.1", + "@ui5/webcomponents-icons": "2.4.0-rc.1", + "@ui5/webcomponents-icons-business-suite": "2.4.0-rc.1", + "@ui5/webcomponents-icons-tnt": "2.4.0-rc.1", + "@ui5/webcomponents-localization": "2.4.0-rc.1", + "@ui5/webcomponents-theming": "2.4.0-rc.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "2.4.0-rc.0", + "@ui5/webcomponents-tools": "2.4.0-rc.1", "chromedriver": "^128.0.3", "lit": "^2.0.0" } diff --git a/packages/main/src/Form.ts b/packages/main/src/Form.ts index 0eeaea192fc3..48c626eac56f 100644 --- a/packages/main/src/Form.ts +++ b/packages/main/src/Form.ts @@ -83,7 +83,7 @@ type ItemsInfo = { * - **S** (< 600px) – 1 column is recommended (default: 1) * - **M** (600px - 1022px) – up to 2 columns are recommended (default: 1) * - **L** (1023px - 1439px) - up to 3 columns are recommended (default: 2) - * - **XL** (> 1439px) – up to 6 columns are recommended (default: 2) + * - **XL** (> 1439px) – up to 6 columns are recommended (default: 3) * * To change the layout, use the `layout` property - f.e. layout="S1 M2 L3 XL6". * @@ -156,13 +156,13 @@ class Form extends UI5Element { * - `S` - 1 column by default (1 column is recommended) * - `M` - 1 column by default (up to 2 columns are recommended) * - `L` - 2 columns by default (up to 3 columns are recommended) - * - `XL` - 2 columns by default (up to 6 columns are recommended) + * - `XL` - 3 columns by default (up to 6 columns are recommended) * - * @default "S1 M1 L2 XL2" + * @default "S1 M1 L2 XL3" * @public */ @property() - layout = "S1 M1 L2 XL2" + layout = "S1 M1 L2 XL3" /** * Defines the width proportion of the labels and fields of a FormItem by breakpoint. @@ -246,7 +246,7 @@ class Form extends UI5Element { labelSpanL = 4; @property({ type: Number }) - columnsXl = 2; + columnsXl = 3; @property({ type: Number }) labelSpanXl = 4; diff --git a/packages/main/src/FormGroup.ts b/packages/main/src/FormGroup.ts index 079e11bcd548..579cb55deb18 100644 --- a/packages/main/src/FormGroup.ts +++ b/packages/main/src/FormGroup.ts @@ -83,6 +83,7 @@ class FormGroup extends UI5Element implements IFormItem { @property() itemSpacing: `${FormItemSpacing}` = "Normal"; + @property() labelSpan = "S12 M4 L4 XL4"; onBeforeRendering() { diff --git a/packages/main/src/List.hbs b/packages/main/src/List.hbs index 3ffa7d4e7653..81f530ab158a 100644 --- a/packages/main/src/List.hbs +++ b/packages/main/src/List.hbs @@ -99,6 +99,7 @@ {{#if loading}} {{/if}} diff --git a/packages/main/src/RangeSlider.hbs b/packages/main/src/RangeSlider.hbs index 6ac3e9b8e866..621dc3b735f2 100644 --- a/packages/main/src/RangeSlider.hbs +++ b/packages/main/src/RangeSlider.hbs @@ -41,9 +41,10 @@ aria-valuemin="{{min}}" aria-valuemax="{{max}}" aria-valuenow="{{startValue}}" - aria-labelledby="ui5-slider-startHandleDesc" + aria-labelledby="{{_ariaLabelledByStartHandleText}}" aria-disabled="{{_ariaDisabled}}" - .aria-describedby="{{_ariaDescribedByHandleText}}" + aria-describedby="{{_ariaDescribedByHandleText}}" + aria-keyshortcuts="F2" >
@@ -79,9 +80,10 @@ aria-valuemin="{{min}}" aria-valuemax="{{max}}" aria-valuenow="{{endValue}}" - aria-labelledby="ui5-slider-endHandleDesc" - .aria-describedby="{{_ariaDescribedByHandleText}}" + aria-labelledby="{{_ariaLabelledByEndHandleText}}" + aria-describedby="{{_ariaDescribedByHandleText}}" aria-disabled="{{_ariaDisabled}}" + aria-keyshortcuts="F2" >
diff --git a/packages/main/src/RangeSlider.ts b/packages/main/src/RangeSlider.ts index b012c79f030c..8a67184ccfd0 100644 --- a/packages/main/src/RangeSlider.ts +++ b/packages/main/src/RangeSlider.ts @@ -316,7 +316,7 @@ class RangeSlider extends SliderBase implements IFormInputElement { _onInputFocusOut(e: FocusEvent) { const tooltipInput = e.target as Input; - const oppositeTooltipInput: Input = tooltipInput.hasAttribute("data-sap-ui-start-value") ? this.shadowRoot!.querySelector("ui5-input[data-sap-ui-end-value]")! : this.shadowRoot!.querySelector("ui5-input[data-sap-ui-start-value]")!; + const oppositeTooltipInput: Input = tooltipInput.hasAttribute("data-sap-ui-start-value") ? this.shadowRoot!.querySelector("[ui5-input][data-sap-ui-end-value]")! : this.shadowRoot!.querySelector("[ui5-input][data-sap-ui-start-value]")!; const relatedTarget = e.relatedTarget as HTMLElement; if (this.startValue > this.endValue) { @@ -483,6 +483,10 @@ class RangeSlider extends SliderBase implements IFormInputElement { * @private */ _onmousedown(e: TouchEvent | MouseEvent) { + if ((e as MouseEvent)?.button && (e as MouseEvent)?.button !== 0) { + return; + } + // If step is 0 no interaction is available because there is no constant // (equal for all user environments) quantitative representation of the value if (this.disabled || this._effectiveStep === 0 || (e.target as HTMLElement).hasAttribute("ui5-input")) { @@ -841,8 +845,8 @@ class RangeSlider extends SliderBase implements IFormInputElement { _onInputKeydown(e: KeyboardEvent): void { const targetedInput = e.target as Input; - const startValueInput = this.shadowRoot!.querySelector("ui5-input[data-sap-ui-start-value]") as Input; - const endValueInput = this.shadowRoot!.querySelector("ui5-input[data-sap-ui-end-value]") as Input; + const startValueInput = this.shadowRoot!.querySelector("[ui5-input][data-sap-ui-start-value]") as Input; + const endValueInput = this.shadowRoot!.querySelector("[ui5-input][data-sap-ui-end-value]") as Input; const startValue = parseFloat(startValueInput.value); const endValue = parseFloat(endValueInput.value); @@ -875,8 +879,8 @@ class RangeSlider extends SliderBase implements IFormInputElement { } _updateInputValue() { - const startValueInput = this.shadowRoot!.querySelector("ui5-input[data-sap-ui-start-value]") as Input; - const endValueInput = this.shadowRoot!.querySelector("ui5-input[data-sap-ui-end-value]") as Input; + const startValueInput = this.shadowRoot!.querySelector("[ui5-input][data-sap-ui-start-value]") as Input; + const endValueInput = this.shadowRoot!.querySelector("[ui5-input][data-sap-ui-end-value]") as Input; if (!startValueInput && !endValueInput) { return; @@ -903,8 +907,8 @@ class RangeSlider extends SliderBase implements IFormInputElement { } _saveInputValues() { - const startValueInput = this.shadowRoot!.querySelector("ui5-input[data-sap-ui-start-value]") as Input; - const endValueInput = this.shadowRoot!.querySelector("ui5-input[data-sap-ui-end-value]") as Input; + const startValueInput = this.shadowRoot!.querySelector("[ui5-input][data-sap-ui-start-value]") as Input; + const endValueInput = this.shadowRoot!.querySelector("[ui5-input][data-sap-ui-end-value]") as Input; if (this.editableTooltip && startValueInput && endValueInput) { const inputStartValue = parseFloat(startValueInput.value); @@ -1029,6 +1033,14 @@ class RangeSlider extends SliderBase implements IFormInputElement { return this.shadowRoot!.querySelector(".ui5-slider-progress")!; } + get _ariaLabelledByStartHandleText() { + return this.accessibleName ? ["ui5-slider-accName", "ui5-slider-startHandleDesc"].join(" ").trim() : "ui5-slider-startHandleDesc"; + } + + get _ariaLabelledByEndHandleText() { + return this.accessibleName ? ["ui5-slider-accName", "ui5-slider-endHandleDesc"].join(" ").trim() : "ui5-slider-endHandleDesc"; + } + get _ariaLabelledByInputText() { return RangeSlider.i18nBundle.getText(SLIDER_TOOLTIP_INPUT_LABEL); } diff --git a/packages/main/src/Select.ts b/packages/main/src/Select.ts index 25da57d6e33a..dde52d32285b 100644 --- a/packages/main/src/Select.ts +++ b/packages/main/src/Select.ts @@ -68,14 +68,14 @@ import SelectPopoverCss from "./generated/themes/SelectPopover.css.js"; * Interface for components that may be slotted inside `ui5-select` as options * @public */ -type IOption = ListItemBase & { +interface IOption extends ListItemBase { tooltip?: string, icon?: string, value?: string, additionalText?: string, - focused?: boolean, + focused: boolean, effectiveDisplayText: string, -}; +} type SelectChangeEventDetail = { selectedOption: IOption, diff --git a/packages/main/src/Slider.hbs b/packages/main/src/Slider.hbs index 21bb8cf6c1fe..37ed3cbfda7f 100644 --- a/packages/main/src/Slider.hbs +++ b/packages/main/src/Slider.hbs @@ -27,7 +27,7 @@ aria-valuemin="{{min}}" aria-valuemax="{{max}}" aria-valuenow="{{value}}" - aria-labelledby="{{_ariaLabelledByHandleText}} ui5-sliderDesc" + aria-labelledby="{{_ariaLabelledByHandleText}}" aria-disabled="{{_ariaDisabled}}" aria-keyshortcuts="F2" aria-describedby="{{_ariaDescribedByHandleText}}" diff --git a/packages/main/src/Slider.ts b/packages/main/src/Slider.ts index 23ecac8dcab5..9c0aac29595c 100644 --- a/packages/main/src/Slider.ts +++ b/packages/main/src/Slider.ts @@ -266,7 +266,7 @@ class Slider extends SliderBase implements IFormInputElement { } _onInputFocusOut(e: FocusEvent) { - const tooltipInput = this.shadowRoot!.querySelector("ui5-input") as Input; + const tooltipInput = this.shadowRoot!.querySelector("[ui5-input]") as Input; this._tooltipVisibility = SliderBase.TOOLTIP_VISIBILITY.HIDDEN; this._updateValueFromInput(e); @@ -279,7 +279,7 @@ class Slider extends SliderBase implements IFormInputElement { } _updateInputValue() { - const tooltipInput = this.shadowRoot!.querySelector("ui5-input") as Input; + const tooltipInput = this.shadowRoot!.querySelector("[ui5-input]") as Input; if (!tooltipInput) { return; diff --git a/packages/main/src/SliderBase.ts b/packages/main/src/SliderBase.ts index 9e9551ee9590..e9ac5ff37560 100644 --- a/packages/main/src/SliderBase.ts +++ b/packages/main/src/SliderBase.ts @@ -795,11 +795,11 @@ abstract class SliderBase extends UI5Element { } get _ariaDescribedByHandleText() { - return this.editableTooltip ? "ui5-slider-accName ui5-slider-InputDesc" : undefined; + return this.editableTooltip ? "ui5-slider-InputDesc" : undefined; } get _ariaLabelledByHandleText() { - return this.accessibleName ? "ui5-slider-accName" : undefined; + return this.accessibleName ? "ui5-slider-accName ui5-slider-sliderDesc" : "ui5-slider-sliderDesc"; } get _ariaDescribedByInputText() { diff --git a/packages/main/src/Table.ts b/packages/main/src/Table.ts index c379aaed1d0f..cb75c5c1f126 100644 --- a/packages/main/src/Table.ts +++ b/packages/main/src/Table.ts @@ -465,7 +465,7 @@ class Table extends UI5Element { get styles() { const headerStyleMap = this.headerRow?.[0]?.cells?.reduce((headerStyles, headerCell) => { - if (headerCell.horizontalAlign !== undefined) { + if (headerCell.horizontalAlign !== undefined && !headerCell._popin) { headerStyles[`--horizontal-align-${headerCell._individualSlot}`] = headerCell.horizontalAlign; } return headerStyles; diff --git a/packages/main/src/TableCellBase.ts b/packages/main/src/TableCellBase.ts index 3f3cc1c06b0d..22232d40c53d 100644 --- a/packages/main/src/TableCellBase.ts +++ b/packages/main/src/TableCellBase.ts @@ -34,7 +34,7 @@ abstract class TableCellBase extends UI5Element { /** * Determines the horizontal alignment of table cells. - * Note: All values valid for justify-content can be used not just the ones inside the enum. + * **Note:** All values valid for justify-content can be used, not just the ones inside the enumeration. * @default undefined * @public */ diff --git a/packages/main/src/bundle.scoped.config.ts b/packages/main/src/bundle.scoped.config.ts new file mode 100644 index 000000000000..3fe16329ef22 --- /dev/null +++ b/packages/main/src/bundle.scoped.config.ts @@ -0,0 +1,5 @@ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { setCustomElementsScopingSuffix, setCustomElementsScopingRules } from "@ui5/webcomponents-base/dist/CustomElementsScope.js"; + +setCustomElementsScopingSuffix("demo"); +// setCustomElementsScopingRules({include: [/^ui5-/], exclude: [/^ui5-button/, /ui5-icon/]}); diff --git a/packages/main/src/bundle.scoped.esm.ts b/packages/main/src/bundle.scoped.esm.ts index a31eb8c8f92a..612cd96d3c54 100644 --- a/packages/main/src/bundle.scoped.esm.ts +++ b/packages/main/src/bundle.scoped.esm.ts @@ -1,8 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { setCustomElementsScopingSuffix, setCustomElementsScopingRules } from "@ui5/webcomponents-base/dist/CustomElementsScope.js"; - -setCustomElementsScopingSuffix("demo"); -// setCustomElementsScopingRules({include: [/^ui5-/], exclude: [/^ui5-button/, /ui5-icon/]}); +import "./bundle.scoped.config.js"; // eslint-disable-next-line import/first import testAssets from "./bundle.esm.js"; diff --git a/packages/main/src/themes/Form.css b/packages/main/src/themes/Form.css index 28fd2c90948b..ccf84c66e7ee 100644 --- a/packages/main/src/themes/Form.css +++ b/packages/main/src/themes/Form.css @@ -15,10 +15,11 @@ .ui5-form-header { display: flex; - height: 2.75rem; + min-height: 2.75rem; align-items: center; border-bottom: 1px solid var(--sapGroup_TitleBorderColor); - padding: 0 1rem 0 1rem; + padding: 0.875rem 1rem; + box-sizing: border-box; } .ui5-form-layout { diff --git a/packages/main/src/themes/FormLayout.css b/packages/main/src/themes/FormLayout.css index 56b87013a9dc..30357addeab0 100644 --- a/packages/main/src/themes/FormLayout.css +++ b/packages/main/src/themes/FormLayout.css @@ -1,6 +1,6 @@ /* * The Form layout is divided into one or more columns. -* XL - max. 4 columns, L - max. 3 columns, M - max. 2 columns and S - 1 column. +* XL - max. 6 columns, L - max. 3 columns, M - max. 2 columns and S - 1 column. */ /* * S max-width: 600px - container padding 24px @@ -76,10 +76,10 @@ } } -/* XL - 2 columns by default, up to 6 */ +/* XL - 3 columns by default, up to 6 */ @container (min-width: 1441px) { .ui5-form-layout { - grid-template-columns: repeat(2, 1fr); + grid-template-columns: repeat(3, 1fr); } :host([columns-xl="1"]) .ui5-form-layout { diff --git a/packages/main/src/themes/GrowingButton.css b/packages/main/src/themes/GrowingButton.css index 1574536cdaa7..8283785feb8a 100644 --- a/packages/main/src/themes/GrowingButton.css +++ b/packages/main/src/themes/GrowingButton.css @@ -61,7 +61,11 @@ font-weight: bold; } -:host([loading]) [growing-button-text]{ +:host([loading]) .ui5-list-growing-button-busy-indicator:not([_is-busy]) { + display: none; +} + +:host([loading]) .ui5-list-growing-button-busy-indicator[_is-busy] + [growing-button-text]{ padding-left: 0.5rem; } diff --git a/packages/main/src/themes/ListItemBase.css b/packages/main/src/themes/ListItemBase.css index 3a34f0672ca7..e259cf92a626 100644 --- a/packages/main/src/themes/ListItemBase.css +++ b/packages/main/src/themes/ListItemBase.css @@ -15,7 +15,7 @@ } /* actionable (type="Active" + desktop) */ -:host([actionable]:not([disabled]):not(ui5-li-group-header)) { +:host([actionable]:not([disabled]):not([ui5-li-group-header])) { cursor: pointer; } @@ -30,7 +30,7 @@ } /* hovered */ -:host([actionable]:not([active]):not([selected]):not(ui5-li-group-header):hover) { +:host([actionable]:not([active]):not([selected]):not([ui5-li-group-header]):hover) { background-color: var(--sapList_Hover_Background); } diff --git a/packages/main/test/pages/DatePicker_legacy_test_page.html b/packages/main/test/pages/DatePicker_legacy_test_page.html new file mode 100644 index 000000000000..b9cfc79f5c91 --- /dev/null +++ b/packages/main/test/pages/DatePicker_legacy_test_page.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/main/test/pages/HAlignTable.html b/packages/main/test/pages/HAlignTable.html index 1a64c4933b0e..206d8bd4f5e8 100644 --- a/packages/main/test/pages/HAlignTable.html +++ b/packages/main/test/pages/HAlignTable.html @@ -10,7 +10,7 @@
- + Product Supplier diff --git a/packages/main/test/pages/form/FormGroups3.html b/packages/main/test/pages/form/FormGroups3.html index ebe0ab6b4341..c5f008df32f5 100644 --- a/packages/main/test/pages/form/FormGroups3.html +++ b/packages/main/test/pages/form/FormGroups3.html @@ -18,9 +18,9 @@ + + + + + + + + +
+ + +
+ + + Name: + Red Point Stores + + + + ZIP Code/City: + 411 Maintown + + + + Street: + Main St 1618 + + + + Country: + Germany + + +
+
+ + + + diff --git a/packages/main/test/pages/form/FormMultipleColumns.html b/packages/main/test/pages/form/FormMultipleColumns.html index ffafa7688748..d6a8be6ac8e3 100644 --- a/packages/main/test/pages/form/FormMultipleColumns.html +++ b/packages/main/test/pages/form/FormMultipleColumns.html @@ -20,9 +20,9 @@
Column Layout: - S1 M3 L4 XL4 - S2 M3 L5 XL5 - S2 M3 L5 XL6 + S1 M3 L4 XL4 + S2 M3 L5 XL5 + S2 M3 L5 XL6 S2 M4 L5 XL7 S2 M3 L6 XL8 S3 M4 L6 XL8 diff --git a/packages/main/test/specs/DatePicker.spec.js b/packages/main/test/specs/DatePicker.spec.js index 220269fa0e2e..23e2a2894bb5 100644 --- a/packages/main/test/specs/DatePicker.spec.js +++ b/packages/main/test/specs/DatePicker.spec.js @@ -1412,4 +1412,20 @@ describe("Date Picker Tests", () => { await datepicker.closePicker(); }); + + describe("Legacy date customization", () => { + it.only("Customization of legacy dates in Islamic calendar", async () => { + // According to the Islamic calendar, Rab. I 9, 1446 AH should be displayed on Thursday, + // but it needs to be configured using the legacyDateCalendarCustomizing setting. + datepicker.page = "test/pages/DatePicker_legacy_test_page.html"; + + await datepicker.open(); + + datepicker.id = "#dp"; + + const currentSelection = await datepicker.getDisplayedDay(11); + + assert.strictEqual(await currentSelection.getText(), "9", "Legacy date customization is applied"); + }); + }); }); diff --git a/packages/main/test/specs/Slider.spec.js b/packages/main/test/specs/Slider.spec.js index 245fa4fe6960..9b95b5d2c899 100644 --- a/packages/main/test/specs/Slider.spec.js +++ b/packages/main/test/specs/Slider.spec.js @@ -409,7 +409,7 @@ describe("Accessibility", async () => { const sliderHandle = await slider.shadow$(".ui5-slider-handle"); assert.strictEqual(await sliderHandle.getAttribute("aria-labelledby"), - "ui5-slider-accName ui5-sliderDesc", "aria-labelledby is set correctly"); + "ui5-slider-accName ui5-slider-sliderDesc", "aria-labelledby is set correctly"); assert.strictEqual(await sliderHandle.getAttribute("aria-valuemin"), `${await slider.getProperty("min")}`, "aria-valuemin is set correctly"); assert.strictEqual(await sliderHandle.getAttribute("aria-valuemax"), diff --git a/packages/main/test/specs/Table.spec.js b/packages/main/test/specs/Table.spec.js index 69325edaf986..6469745f29c7 100644 --- a/packages/main/test/specs/Table.spec.js +++ b/packages/main/test/specs/Table.spec.js @@ -396,6 +396,72 @@ describe("Table - Horizontal alignment of cells", async () => { assert.equal(justifyContent.value, index === rowWithChangedCell ? customAlignmentCell : alignment, "justify-content correctly set."); } }); + + it("test horizontalAlign behavior with one by one popping in", async() => { + let table = await browser.$("#table"); + assert.ok(table.isExisting(), "Table exists"); + + const headerRow = await table.$("ui5-table-header-row"); + const headerCells = await headerRow.$$("ui5-table-header-cell"); + + const testWidths = [ + {width: 1120, poppedIn: []}, + {width: 900, poppedIn: ["priceCol"]}, + {width: 800, poppedIn: ["priceCol", "weightCol"]}, + {width: 500, poppedIn: ["priceCol", "weightCol", "dimensionsCol"]}, + {width: 300, poppedIn: ["priceCol", "weightCol", "dimensionsCol", "supplierCol"]} + ]; + + for (const testWidth of testWidths) { + await table.setProperty("style", `width: ${testWidth.width}px`); + assert.strictEqual(await table.getSize("width"), testWidth.width, `Table is ${testWidth.width} wide`); + + for (const [index, headerCell] of headerCells.entries()) { + const headerRole = await headerCell.getAttribute("role"); + const headerId = await headerCell.getAttribute("id"); + const slotName = await headerCell.getAttribute("slot"); + + let expectRole = true; + if (testWidth.poppedIn.includes(headerId)) { + expectRole = false; + } + + assert.strictEqual(headerRole === ROLE_COLUMN_HEADER, expectRole, `Cell has role (width: ${testWidth.width}): (${expectRole})`) + assert.strictEqual(await headerRow.shadow$(`slot[name=${slotName}]`).isExisting(), expectRole, `Header cell ${slotName} has been rendered (width: ${testWidth.width}): ${expectRole}`); + + const style = await headerCell.getAttribute("style"); + const justifyContentHeaderCellUncomputed = style.match(/justify-content: ([^;]+)/)[1]; + const cssVariable = `var(--horizontal-align-default-${index+1})`; + assert.equal(justifyContentHeaderCellUncomputed, cssVariable); + + // justify-content should be the default value in case the cell is inside the popin area + if (!expectRole) { + const tableRows = await table.$$("ui5-table-row"); + for (const row of tableRows) { + const rowCells = await row.$$("ui5-table-cell"); + const justifyContent = await rowCells[index].getCSSProperty("justify-content"); + + assert.equal(justifyContent.value, "normal", "justify-content correctly set."); + } + } + } + } + + /* const justifyContentHeaderCell = await headerCell.getCSSProperty("justify-content"); + const style = await headerCell.getAttribute("style"); + const justifyContentHeaderCellUncomputed = style.match(/justify-content: ([^;]+)/)[1]; + const cssVariable = "var(--horizontal-align-default-1)"; + assert.equal(justifyContentHeaderCell.value, alignment, "justify-content correctly set."); + assert.equal(justifyContentHeaderCellUncomputed, cssVariable, "horizontalAlign not set"); + + const tableRows = await table.$$("ui5-table-row"); + for (const row of tableRows) { + const rowCells = await row.$$("ui5-table-cell"); + const justifyContent = await rowCells[3].getCSSProperty("justify-content"); + + assert.equal(justifyContent.value, alignment, "justify-content correctly set."); + } */ + }); }); // Tests for the fixed header, whether it is shown correctly and behaves as expected diff --git a/packages/main/tsconfig.json b/packages/main/tsconfig.json index 2241117db0c9..a1850462744a 100644 --- a/packages/main/tsconfig.json +++ b/packages/main/tsconfig.json @@ -10,6 +10,8 @@ "composite": true, "rootDir": "src", "tsBuildInfoFile": "dist/.tsbuildinfo", + "module": "NodeNext", + "moduleResolution": "NodeNext", "verbatimModuleSyntax": true, "paths": { "@ui5/webcomponents-base/dist/*": [ diff --git a/packages/theming/CHANGELOG.md b/packages/theming/CHANGELOG.md index 0728c3e06cd8..6a4689fad841 100644 --- a/packages/theming/CHANGELOG.md +++ b/packages/theming/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) **Note:** Version bump only for package @ui5/webcomponents-theming diff --git a/packages/theming/package.json b/packages/theming/package.json index 4a2cdfcf876c..01f7c5b21d97 100644 --- a/packages/theming/package.json +++ b/packages/theming/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-theming", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: webcomponents.theming", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -31,10 +31,10 @@ }, "dependencies": { "@sap-theming/theming-base-content": "11.17.1", - "@ui5/webcomponents-base": "2.4.0-rc.0" + "@ui5/webcomponents-base": "2.4.0-rc.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "2.4.0-rc.0", + "@ui5/webcomponents-tools": "2.4.0-rc.1", "globby": "^13.1.1", "json-beautify": "^1.1.1", "nps": "^5.10.0", diff --git a/packages/theming/tsconfig.json b/packages/theming/tsconfig.json index 8e62e3101cb3..4b8cd5fdbdac 100644 --- a/packages/theming/tsconfig.json +++ b/packages/theming/tsconfig.json @@ -8,6 +8,8 @@ "experimentalDecorators": true, "composite": true, "rootDir": "src", + "module": "NodeNext", + "moduleResolution": "NodeNext", "tsBuildInfoFile": "dist/.tsbuildinfo", "paths": { "@ui5/webcomponents-base/dist/*": [ diff --git a/packages/tools/CHANGELOG.md b/packages/tools/CHANGELOG.md index 6fcd2abe3c84..255b9f0484c2 100644 --- a/packages/tools/CHANGELOG.md +++ b/packages/tools/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + + +### Bug Fixes + +* scoping issues and document how scoping is used correctly ([#10023](https://github.com/SAP/ui5-webcomponents/issues/10023)) ([ee808c3](https://github.com/SAP/ui5-webcomponents/commit/ee808c309f316fe145b05d292c92328396c655ab)) +* **tools:** revert tsconfig moduleResolution to node ([#10014](https://github.com/SAP/ui5-webcomponents/issues/10014)) ([0724b92](https://github.com/SAP/ui5-webcomponents/commit/0724b9289ad04f88972d4978ed37e76f13abca13)) + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) diff --git a/packages/tools/lib/scoping/get-all-tags.js b/packages/tools/lib/scoping/get-all-tags.js index 7147477dc46b..cef4c6408bbb 100644 --- a/packages/tools/lib/scoping/get-all-tags.js +++ b/packages/tools/lib/scoping/get-all-tags.js @@ -4,8 +4,15 @@ const glob = require("glob"); const getTag = file => { const fileContent = String(fs.readFileSync(file)).replace(/\n/g, ""); - const matches = fileContent.match(/\btag\b:\s*\"(.*?)\"/); - return matches ? matches[1] : undefined; + let matches = fileContent.match(/\btag\b:\s*\"(.*?)\"/); + if (matches) { + return matches[1]; + } + matches = fileContent.match(/@customElement\("(.*?)"\)/); + if (matches) { + return matches[1]; + } + return undefined; }; const getPackageTags = (packageDir) => { diff --git a/packages/tools/package.json b/packages/tools/package.json index 94f387a22516..691a0d919a24 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-tools", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "description": "UI5 Web Components: webcomponents.tools", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", diff --git a/packages/tools/tsconfig.json b/packages/tools/tsconfig.json index de6379eeb681..0b25ea76ce84 100644 --- a/packages/tools/tsconfig.json +++ b/packages/tools/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "module": "NodeNext", "target": "ES2021", "lib": [ "DOM", @@ -12,5 +11,6 @@ "sourceMap": true, "inlineSources": true, "strict": true, + "moduleResolution": "node", } } \ No newline at end of file diff --git a/packages/website/CHANGELOG.md b/packages/website/CHANGELOG.md index e89e007a3f1c..0408df826d88 100644 --- a/packages/website/CHANGELOG.md +++ b/packages/website/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [2.4.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v2.4.0-rc.0...v2.4.0-rc.1) (2024-10-17) + +**Note:** Version bump only for package @ui5/webcomponents-website + + + + + # [2.4.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v2.3.1-rc.0...v2.4.0-rc.0) (2024-10-10) diff --git a/packages/website/docs/_components_pages/main/Form/Form.mdx b/packages/website/docs/_components_pages/main/Form/Form.mdx index 59fb87109f5b..1216bc9680fb 100644 --- a/packages/website/docs/_components_pages/main/Form/Form.mdx +++ b/packages/website/docs/_components_pages/main/Form/Form.mdx @@ -10,6 +10,7 @@ import Layout from "../../../_samples/main/Form/Layout/Layout.md"; import LabelSpan from "../../../_samples/main/Form/LabelSpan/LabelSpan.md"; import LabelsOnTop from "../../../_samples/main/Form/LabelsOnTop/LabelsOnTop.md"; import GroupColumnSpan from "../../../_samples/main/Form/GroupColumnSpan/GroupColumnSpan.md"; +import HeaderTextWrapping from "../../../_samples/main/Form/HeaderTextWrapping/HeaderTextWrapping.md"; import ItemColumnSpan from "../../../_samples/main/Form/ItemColumnSpan/ItemColumnSpan.md"; import FreeStyleForm from "../../../_samples/main/Form/FreeStyleForm/FreeStyleForm.md"; import CustomHeader from "../../../_samples/main/Form/CustomHeader/CustomHeader.md"; @@ -26,6 +27,7 @@ import CustomHeader from "../../../_samples/main/Form/CustomHeader/CustomHeader. ### Layout Use the Form#**layout** property to define the number of columns to distribute the form content by breakpoint. +- S1 M1 L2 XL3 - 1 cols in S, 1 cols in M, 2 cols in L and 3 cols in XL (default layout) - S1 M2 L3 XL5 - 1 cols in S, 2 cols in M, 3 cols in L and 5 cols in XL - S1 M2 L4 XL6 - 1 cols in S, 2 cols in M, 4 cols in L and 6 cols in XL - S2 M3 L5 XL7 - 2 cols in S, 3 cols in M, 5 cols in L and 7 cols in XL @@ -80,6 +82,12 @@ The FormItem#**columnSpan** defines to how many columns the form item should exp +### Header Text Wrapping + +The Form header text **is wrapping** when doesn't fit the available space. + + + ### Custom Header The Form provides a **header** slot that allows the usage of custom form header. diff --git a/packages/website/docs/_components_pages/main/Table/TableCell.mdx b/packages/website/docs/_components_pages/main/Table/TableCell.mdx index 0db76d953d13..b1399636d1c3 100644 --- a/packages/website/docs/_components_pages/main/Table/TableCell.mdx +++ b/packages/website/docs/_components_pages/main/Table/TableCell.mdx @@ -11,14 +11,14 @@ import HAlign from "../../../_samples/main/Table/HAlign/HAlign.md"; ## Horizontal cell alignment -Control the horizontal alignment of cells by utilizing the `horizontalAlign` property. +Controls the horizontal alignment of cells by using the `horizontalAlign` property. -Please note that the behaviour of `horizontalAlign` depends on where you set it: -1. `horizontalAlign` is set on `TableHeaderCell` level
-Changes the horizontal alignment of the `TableHeaderCell` and their corresponding `TableCells`. -2. `horizontalAlign` is set on `TableCell` level only
+Please note that the behavior of `horizontalAlign` depends on where you set it: +- `horizontalAlign` is set on `TableHeaderCell` level
+Changes the horizontal alignment of the `TableHeaderCell` and its corresponding `TableCell`. +- `horizontalAlign` is set on `TableCell` level only
The horizontal alignment is only changed for this one `TableCell` -3. `horizontalAlign` is set on `TableHeaderCell` and `TableCell` level
-Changing the `horizontalAlign` property on `TableHeaderCell` level changes only the `TableHeaderCell` itself and those `TableCells` without a `horizontalAlign` property. +- `horizontalAlign` is set on `TableHeaderCell` and `TableCell` level
+Changing the `horizontalAlign` property on `TableHeaderCell` level changes only the `TableHeaderCell` itself and those `TableCell` without a `horizontalAlign` property. \ No newline at end of file diff --git a/packages/website/docs/_components_pages/main/Table/TableHeaderCell.mdx b/packages/website/docs/_components_pages/main/Table/TableHeaderCell.mdx index b8306ab9f36e..defc3b8e2481 100644 --- a/packages/website/docs/_components_pages/main/Table/TableHeaderCell.mdx +++ b/packages/website/docs/_components_pages/main/Table/TableHeaderCell.mdx @@ -21,14 +21,14 @@ import HAlign from "../../../_samples/main/Table/HAlign/HAlign.md"; ## Horizontal cell alignment -Control the horizontal alignment of cells by utilizing the `horizontalAlign` property. +Controls the horizontal alignment of cells by using the `horizontalAlign` property. -Please note that the behaviour of `horizontalAlign` depends on where you set it: -1. `horizontalAlign` is set on `TableHeaderCell` level
-Changes the horizontal alignment of the `TableHeaderCell` and their corresponding `TableCells`. -2. `horizontalAlign` is set on `TableCell` level only
+Please note that the behavior of `horizontalAlign` depends on where you set it: +- `horizontalAlign` is set on `TableHeaderCell` level
+Changes the horizontal alignment of the `TableHeaderCell` and its corresponding `TableCell`. +- `horizontalAlign` is set on `TableCell` level only
The horizontal alignment is only changed for this one `TableCell` -3. `horizontalAlign` is set on `TableHeaderCell` and `TableCell` level
-Changing the `horizontalAlign` property on `TableHeaderCell` level changes only the `TableHeaderCell` itself and those `TableCells` without a `horizontalAlign` property. +- `horizontalAlign` is set on `TableHeaderCell` and `TableCell` level
+Changing the `horizontalAlign` property on `TableHeaderCell` level changes only the `TableHeaderCell` itself and those `TableCell` without a `horizontalAlign` property. \ No newline at end of file diff --git a/packages/website/docs/_samples/fiori/NotificationList/InShellBar/main.css b/packages/website/docs/_samples/fiori/NotificationList/InShellBar/main.css index 86a5bfc4715c..149a3b790f4d 100644 --- a/packages/website/docs/_samples/fiori/NotificationList/InShellBar/main.css +++ b/packages/website/docs/_samples/fiori/NotificationList/InShellBar/main.css @@ -14,6 +14,7 @@ .notificationsPopoverHeader { display: flex; + flex: 1; flex-direction: column; } diff --git a/packages/website/docs/_samples/main/Form/CustomHeader/sample.html b/packages/website/docs/_samples/main/Form/CustomHeader/sample.html index 562e768e10a1..06e6d46924fa 100644 --- a/packages/website/docs/_samples/main/Form/CustomHeader/sample.html +++ b/packages/website/docs/_samples/main/Form/CustomHeader/sample.html @@ -12,7 +12,7 @@ - + Address diff --git a/packages/website/docs/_samples/main/Form/HeaderTextWrapping/HeaderTextWrapping.md b/packages/website/docs/_samples/main/Form/HeaderTextWrapping/HeaderTextWrapping.md new file mode 100644 index 000000000000..17798ecc59ab --- /dev/null +++ b/packages/website/docs/_samples/main/Form/HeaderTextWrapping/HeaderTextWrapping.md @@ -0,0 +1,4 @@ +import html from '!!raw-loader!./sample.html'; +import js from '!!raw-loader!./main.js'; + + diff --git a/packages/website/docs/_samples/main/Form/HeaderTextWrapping/main.js b/packages/website/docs/_samples/main/Form/HeaderTextWrapping/main.js new file mode 100644 index 000000000000..0818d9b83fcb --- /dev/null +++ b/packages/website/docs/_samples/main/Form/HeaderTextWrapping/main.js @@ -0,0 +1,29 @@ +import "@ui5/webcomponents/dist/Form.js"; +import "@ui5/webcomponents/dist/FormItem.js"; + + +// The following code is required only for the sample +import "@ui5/webcomponents/dist/Label.js"; +import "@ui5/webcomponents/dist/Text.js"; +import "@ui5/webcomponents/dist/Slider.js"; + +const slider = document.getElementById("slider"); +const txtLayout = document.getElementById("txtLayout"); +const container = document.getElementById("container"); + +slider.addEventListener("ui5-input", () => { + const width = (slider.value / 100 * 1500); + container.style.width = `${width}px`; + txtLayout.innerHTML = getLayoutByWidth(width); +}); + +const getLayoutByWidth = (width) => { + if (width > 599 && width <= 1023) { + return "M"; + } else if (width >= 1024 && width <= 1439) { + return "L" + } else if (width >= 1440) { + return "XL" + } + return "S"; +}; diff --git a/packages/website/docs/_samples/main/Form/HeaderTextWrapping/sample.html b/packages/website/docs/_samples/main/Form/HeaderTextWrapping/sample.html new file mode 100644 index 000000000000..b2225aa4c488 --- /dev/null +++ b/packages/website/docs/_samples/main/Form/HeaderTextWrapping/sample.html @@ -0,0 +1,47 @@ + + + + + + + + Sample + + + + + + + + +
+ + + Name: + Red Point Stores + + + + ZIP Code/City: + 411 Maintown + + + + Street: + Main St 1618 + + + + Country: + Germany + + +
+ + + + + + + + diff --git a/packages/website/docs/_samples/main/Form/Layout/sample.html b/packages/website/docs/_samples/main/Form/Layout/sample.html index 72c6b933d831..b92d267ff408 100644 --- a/packages/website/docs/_samples/main/Form/Layout/sample.html +++ b/packages/website/docs/_samples/main/Form/Layout/sample.html @@ -18,6 +18,103 @@
+ + + + + Name: + Red Point Stores + + + + ZIP Code/City: + 411 Maintown + + + + Street: + Main St 1618 + + + + Country: + Germany + + + + WebSite: + sap.com + + + + + + Twitter: + @sap + + + + Email: + john.smith@sap.com + + + + Tel: + +49 6227 747474 + + + + SMS: + +49 6227 747474 + + + + Mobile: + +49 6227 747474 + + + + Pager: + +49 6227 747474 + + + + Fax: + +49 6227 747474 + + + + + + + Name: + Red Point Stores + + + + ZIP Code/City: + 411 Maintown + + + + Street: + Main St 1618 + + + + Country: + Germany + + + + WebSite: + sap.com + + + + +

+ diff --git a/packages/website/package.json b/packages/website/package.json index 016eab00914d..dcc2ec66d816 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-website", - "version": "2.4.0-rc.0", + "version": "2.4.0-rc.1", "private": true, "scripts": { "generate-local-cdn": "rimraf ./local-cdn && node ./build-scripts/local-cdn.mjs",