diff --git a/.jscpd.json b/.jscpd.json index bfb83a7e62a3..f2b18f4b4472 100644 --- a/.jscpd.json +++ b/.jscpd.json @@ -42,6 +42,7 @@ "packages/components/src/components/**/*.spec.tsx", "packages/components/src/components/tag/tag.spec.tsx", "**/**config.ts", + "**/navigation-items.ts", "packages/foundations/assets/icons/functional/fonts/sources/*.json" ], "absolute": true diff --git a/README.md b/README.md index d261c92406bb..76d8c694c5ea 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ Here is an overview of all components you can use: | Floating-Button | 02 - Action | ❌ | ❌ | | Footer | 01 - Layout | ❌ | ✅ | | Grid | 01 - Layout | ❌ | ✅ | -| Header | 01 - Layout | ❌ | ✅ | +| Header | 01 - Layout | Beta | ✅ | | [Icons](packages/components/src/components/icon) | 04 - Data-Display | Beta | ✅ | | Image | 04 - Data-Display | ❌ | ✅ | | Indicator | 04 - Data-Display | ❌ | ❌ | diff --git a/__snapshots__/alert/showcase/chromium/regular/neutral-0/DBAlert-should-match-screenshot.png b/__snapshots__/alert/showcase/chromium/regular/neutral-0/DBAlert-should-match-screenshot.png index bca6053cf870..97845902096c 100644 Binary files a/__snapshots__/alert/showcase/chromium/regular/neutral-0/DBAlert-should-match-screenshot.png and b/__snapshots__/alert/showcase/chromium/regular/neutral-0/DBAlert-should-match-screenshot.png differ diff --git a/__snapshots__/alert/showcase/mobile-chrome/regular/neutral-0/DBAlert-should-match-screenshot.png b/__snapshots__/alert/showcase/mobile-chrome/regular/neutral-0/DBAlert-should-match-screenshot.png index a354371f2f8b..1fd1dd874b53 100644 Binary files a/__snapshots__/alert/showcase/mobile-chrome/regular/neutral-0/DBAlert-should-match-screenshot.png and b/__snapshots__/alert/showcase/mobile-chrome/regular/neutral-0/DBAlert-should-match-screenshot.png differ diff --git a/__snapshots__/alert/showcase/mobile-safari/regular/neutral-0/DBAlert-should-match-screenshot.png b/__snapshots__/alert/showcase/mobile-safari/regular/neutral-0/DBAlert-should-match-screenshot.png index 5d3d9bb5e644..3d455bb8cc1b 100644 Binary files a/__snapshots__/alert/showcase/mobile-safari/regular/neutral-0/DBAlert-should-match-screenshot.png and b/__snapshots__/alert/showcase/mobile-safari/regular/neutral-0/DBAlert-should-match-screenshot.png differ diff --git a/__snapshots__/alert/showcase/webkit/regular/neutral-0/DBAlert-should-match-screenshot.png b/__snapshots__/alert/showcase/webkit/regular/neutral-0/DBAlert-should-match-screenshot.png index 78ed6057f6a4..81769c95c9b3 100644 Binary files a/__snapshots__/alert/showcase/webkit/regular/neutral-0/DBAlert-should-match-screenshot.png and b/__snapshots__/alert/showcase/webkit/regular/neutral-0/DBAlert-should-match-screenshot.png differ diff --git a/__snapshots__/badge/showcase/chromium/regular/neutral-0/DBBadge-should-match-screenshot.png b/__snapshots__/badge/showcase/chromium/regular/neutral-0/DBBadge-should-match-screenshot.png index 607d1430f806..7e36d7be740d 100644 Binary files a/__snapshots__/badge/showcase/chromium/regular/neutral-0/DBBadge-should-match-screenshot.png and b/__snapshots__/badge/showcase/chromium/regular/neutral-0/DBBadge-should-match-screenshot.png differ diff --git a/__snapshots__/badge/showcase/mobile-chrome/regular/neutral-0/DBBadge-should-match-screenshot.png b/__snapshots__/badge/showcase/mobile-chrome/regular/neutral-0/DBBadge-should-match-screenshot.png index 57a04581b2f6..41a4a81fb546 100644 Binary files a/__snapshots__/badge/showcase/mobile-chrome/regular/neutral-0/DBBadge-should-match-screenshot.png and b/__snapshots__/badge/showcase/mobile-chrome/regular/neutral-0/DBBadge-should-match-screenshot.png differ diff --git a/__snapshots__/badge/showcase/mobile-safari/regular/neutral-0/DBBadge-should-match-screenshot.png b/__snapshots__/badge/showcase/mobile-safari/regular/neutral-0/DBBadge-should-match-screenshot.png index 615566e0725b..bc3799424c06 100644 Binary files a/__snapshots__/badge/showcase/mobile-safari/regular/neutral-0/DBBadge-should-match-screenshot.png and b/__snapshots__/badge/showcase/mobile-safari/regular/neutral-0/DBBadge-should-match-screenshot.png differ diff --git a/__snapshots__/badge/showcase/webkit/regular/neutral-0/DBBadge-should-match-screenshot.png b/__snapshots__/badge/showcase/webkit/regular/neutral-0/DBBadge-should-match-screenshot.png index 27044ed8bb75..5266a194834a 100644 Binary files a/__snapshots__/badge/showcase/webkit/regular/neutral-0/DBBadge-should-match-screenshot.png and b/__snapshots__/badge/showcase/webkit/regular/neutral-0/DBBadge-should-match-screenshot.png differ diff --git a/__snapshots__/brand/component/chromium/DBBrand-should-match-screenshot.png b/__snapshots__/brand/component/chromium/DBBrand-should-match-screenshot.png index 74068f817168..db903e7249c5 100644 Binary files a/__snapshots__/brand/component/chromium/DBBrand-should-match-screenshot.png and b/__snapshots__/brand/component/chromium/DBBrand-should-match-screenshot.png differ diff --git a/__snapshots__/brand/component/mobile-chrome/DBBrand-should-match-screenshot.png b/__snapshots__/brand/component/mobile-chrome/DBBrand-should-match-screenshot.png index 74068f817168..db903e7249c5 100644 Binary files a/__snapshots__/brand/component/mobile-chrome/DBBrand-should-match-screenshot.png and b/__snapshots__/brand/component/mobile-chrome/DBBrand-should-match-screenshot.png differ diff --git a/__snapshots__/brand/component/mobile-safari/DBBrand-should-match-screenshot.png b/__snapshots__/brand/component/mobile-safari/DBBrand-should-match-screenshot.png index c2293578e32a..414117368f46 100644 Binary files a/__snapshots__/brand/component/mobile-safari/DBBrand-should-match-screenshot.png and b/__snapshots__/brand/component/mobile-safari/DBBrand-should-match-screenshot.png differ diff --git a/__snapshots__/brand/component/webkit/DBBrand-should-match-screenshot.png b/__snapshots__/brand/component/webkit/DBBrand-should-match-screenshot.png index c2293578e32a..414117368f46 100644 Binary files a/__snapshots__/brand/component/webkit/DBBrand-should-match-screenshot.png and b/__snapshots__/brand/component/webkit/DBBrand-should-match-screenshot.png differ diff --git a/__snapshots__/button/showcase/chromium/regular/neutral-0/DBButton-should-match-screenshot.png b/__snapshots__/button/showcase/chromium/regular/neutral-0/DBButton-should-match-screenshot.png index 3d57ef700610..56cc622e69e5 100644 Binary files a/__snapshots__/button/showcase/chromium/regular/neutral-0/DBButton-should-match-screenshot.png and b/__snapshots__/button/showcase/chromium/regular/neutral-0/DBButton-should-match-screenshot.png differ diff --git a/__snapshots__/button/showcase/mobile-chrome/regular/neutral-0/DBButton-should-match-screenshot.png b/__snapshots__/button/showcase/mobile-chrome/regular/neutral-0/DBButton-should-match-screenshot.png index c601ee04a10a..205274c2c6b1 100644 Binary files a/__snapshots__/button/showcase/mobile-chrome/regular/neutral-0/DBButton-should-match-screenshot.png and b/__snapshots__/button/showcase/mobile-chrome/regular/neutral-0/DBButton-should-match-screenshot.png differ diff --git a/__snapshots__/button/showcase/mobile-safari/regular/neutral-0/DBButton-should-match-screenshot.png b/__snapshots__/button/showcase/mobile-safari/regular/neutral-0/DBButton-should-match-screenshot.png index dfcc6dadb7d1..8afaf9f8239e 100644 Binary files a/__snapshots__/button/showcase/mobile-safari/regular/neutral-0/DBButton-should-match-screenshot.png and b/__snapshots__/button/showcase/mobile-safari/regular/neutral-0/DBButton-should-match-screenshot.png differ diff --git a/__snapshots__/button/showcase/webkit/regular/neutral-0/DBButton-should-match-screenshot.png b/__snapshots__/button/showcase/webkit/regular/neutral-0/DBButton-should-match-screenshot.png index 16036e9aee81..d0818a2137d4 100644 Binary files a/__snapshots__/button/showcase/webkit/regular/neutral-0/DBButton-should-match-screenshot.png and b/__snapshots__/button/showcase/webkit/regular/neutral-0/DBButton-should-match-screenshot.png differ diff --git a/__snapshots__/infotext/showcase/chromium/regular/neutral-0/DBInfotext-should-match-screenshot.png b/__snapshots__/infotext/showcase/chromium/regular/neutral-0/DBInfotext-should-match-screenshot.png index 0b8ead7dadd7..9b5ca4b097c4 100644 Binary files a/__snapshots__/infotext/showcase/chromium/regular/neutral-0/DBInfotext-should-match-screenshot.png and b/__snapshots__/infotext/showcase/chromium/regular/neutral-0/DBInfotext-should-match-screenshot.png differ diff --git a/__snapshots__/infotext/showcase/mobile-chrome/regular/neutral-0/DBInfotext-should-match-screenshot.png b/__snapshots__/infotext/showcase/mobile-chrome/regular/neutral-0/DBInfotext-should-match-screenshot.png index db43ca208ab8..2d7d0164124f 100644 Binary files a/__snapshots__/infotext/showcase/mobile-chrome/regular/neutral-0/DBInfotext-should-match-screenshot.png and b/__snapshots__/infotext/showcase/mobile-chrome/regular/neutral-0/DBInfotext-should-match-screenshot.png differ diff --git a/__snapshots__/infotext/showcase/mobile-safari/regular/neutral-0/DBInfotext-should-match-screenshot.png b/__snapshots__/infotext/showcase/mobile-safari/regular/neutral-0/DBInfotext-should-match-screenshot.png index d277f960e40a..154edf8c7277 100644 Binary files a/__snapshots__/infotext/showcase/mobile-safari/regular/neutral-0/DBInfotext-should-match-screenshot.png and b/__snapshots__/infotext/showcase/mobile-safari/regular/neutral-0/DBInfotext-should-match-screenshot.png differ diff --git a/__snapshots__/infotext/showcase/webkit/regular/neutral-0/DBInfotext-should-match-screenshot.png b/__snapshots__/infotext/showcase/webkit/regular/neutral-0/DBInfotext-should-match-screenshot.png index f2b6679b5c78..fff41fdb01b2 100644 Binary files a/__snapshots__/infotext/showcase/webkit/regular/neutral-0/DBInfotext-should-match-screenshot.png and b/__snapshots__/infotext/showcase/webkit/regular/neutral-0/DBInfotext-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/chromium/regular/neutral-0/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/chromium/regular/neutral-0/DBInput-should-match-screenshot.png index 3e9fce71965a..a0706dd03757 100644 Binary files a/__snapshots__/input/showcase/chromium/regular/neutral-0/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/chromium/regular/neutral-0/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/mobile-chrome/regular/neutral-0/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/mobile-chrome/regular/neutral-0/DBInput-should-match-screenshot.png index bbd0965eb8ce..ac368d2f0e6c 100644 Binary files a/__snapshots__/input/showcase/mobile-chrome/regular/neutral-0/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/mobile-chrome/regular/neutral-0/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/mobile-safari/regular/neutral-0/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/mobile-safari/regular/neutral-0/DBInput-should-match-screenshot.png index 3e96491e0a23..20c149f2cd9b 100644 Binary files a/__snapshots__/input/showcase/mobile-safari/regular/neutral-0/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/mobile-safari/regular/neutral-0/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/input/showcase/webkit/regular/neutral-0/DBInput-should-match-screenshot.png b/__snapshots__/input/showcase/webkit/regular/neutral-0/DBInput-should-match-screenshot.png index f22d18161cc3..0ef1e8f7f152 100644 Binary files a/__snapshots__/input/showcase/webkit/regular/neutral-0/DBInput-should-match-screenshot.png and b/__snapshots__/input/showcase/webkit/regular/neutral-0/DBInput-should-match-screenshot.png differ diff --git a/__snapshots__/link/showcase/chromium/regular/neutral-0/DBLink-should-match-screenshot.png b/__snapshots__/link/showcase/chromium/regular/neutral-0/DBLink-should-match-screenshot.png index 33fda26d64f8..de37b652f658 100644 Binary files a/__snapshots__/link/showcase/chromium/regular/neutral-0/DBLink-should-match-screenshot.png and b/__snapshots__/link/showcase/chromium/regular/neutral-0/DBLink-should-match-screenshot.png differ diff --git a/__snapshots__/link/showcase/mobile-chrome/regular/neutral-0/DBLink-should-match-screenshot.png b/__snapshots__/link/showcase/mobile-chrome/regular/neutral-0/DBLink-should-match-screenshot.png index be1ba90ca19a..d2a06008ab48 100644 Binary files a/__snapshots__/link/showcase/mobile-chrome/regular/neutral-0/DBLink-should-match-screenshot.png and b/__snapshots__/link/showcase/mobile-chrome/regular/neutral-0/DBLink-should-match-screenshot.png differ diff --git a/__snapshots__/link/showcase/mobile-safari/regular/neutral-0/DBLink-should-match-screenshot.png b/__snapshots__/link/showcase/mobile-safari/regular/neutral-0/DBLink-should-match-screenshot.png index 217227fe3686..e7698fc11958 100644 Binary files a/__snapshots__/link/showcase/mobile-safari/regular/neutral-0/DBLink-should-match-screenshot.png and b/__snapshots__/link/showcase/mobile-safari/regular/neutral-0/DBLink-should-match-screenshot.png differ diff --git a/__snapshots__/link/showcase/webkit/regular/neutral-0/DBLink-should-match-screenshot.png b/__snapshots__/link/showcase/webkit/regular/neutral-0/DBLink-should-match-screenshot.png index 169229c875ef..13ebf98df703 100644 Binary files a/__snapshots__/link/showcase/webkit/regular/neutral-0/DBLink-should-match-screenshot.png and b/__snapshots__/link/showcase/webkit/regular/neutral-0/DBLink-should-match-screenshot.png differ diff --git a/__snapshots__/main-navigation/component/chromium/DBMainNavigation-should-match-screenshot.png b/__snapshots__/main-navigation/component/chromium/DBMainNavigation-should-match-screenshot.png new file mode 100644 index 000000000000..97cbc3a732a4 Binary files /dev/null and b/__snapshots__/main-navigation/component/chromium/DBMainNavigation-should-match-screenshot.png differ diff --git a/__snapshots__/main-navigation/component/mobile-chrome/DBMainNavigation-should-match-screenshot.png b/__snapshots__/main-navigation/component/mobile-chrome/DBMainNavigation-should-match-screenshot.png new file mode 100644 index 000000000000..97cbc3a732a4 Binary files /dev/null and b/__snapshots__/main-navigation/component/mobile-chrome/DBMainNavigation-should-match-screenshot.png differ diff --git a/__snapshots__/main-navigation/component/mobile-safari/DBMainNavigation-should-match-screenshot.png b/__snapshots__/main-navigation/component/mobile-safari/DBMainNavigation-should-match-screenshot.png new file mode 100644 index 000000000000..887e69763682 Binary files /dev/null and b/__snapshots__/main-navigation/component/mobile-safari/DBMainNavigation-should-match-screenshot.png differ diff --git a/__snapshots__/main-navigation/component/webkit/DBMainNavigation-should-match-screenshot.png b/__snapshots__/main-navigation/component/webkit/DBMainNavigation-should-match-screenshot.png new file mode 100644 index 000000000000..887e69763682 Binary files /dev/null and b/__snapshots__/main-navigation/component/webkit/DBMainNavigation-should-match-screenshot.png differ diff --git a/__snapshots__/navigation-item/component/chromium/DBNavigationItem-should-match-screenshot.png b/__snapshots__/navigation-item/component/chromium/DBNavigationItem-should-match-screenshot.png index 3108f1799cb6..07b2d75c171e 100644 Binary files a/__snapshots__/navigation-item/component/chromium/DBNavigationItem-should-match-screenshot.png and b/__snapshots__/navigation-item/component/chromium/DBNavigationItem-should-match-screenshot.png differ diff --git a/__snapshots__/navigation-item/component/mobile-chrome/DBNavigationItem-should-match-screenshot.png b/__snapshots__/navigation-item/component/mobile-chrome/DBNavigationItem-should-match-screenshot.png index 3108f1799cb6..07b2d75c171e 100644 Binary files a/__snapshots__/navigation-item/component/mobile-chrome/DBNavigationItem-should-match-screenshot.png and b/__snapshots__/navigation-item/component/mobile-chrome/DBNavigationItem-should-match-screenshot.png differ diff --git a/__snapshots__/navigation-item/component/mobile-safari/DBNavigationItem-should-match-screenshot.png b/__snapshots__/navigation-item/component/mobile-safari/DBNavigationItem-should-match-screenshot.png index 502adcb41313..651982f10623 100644 Binary files a/__snapshots__/navigation-item/component/mobile-safari/DBNavigationItem-should-match-screenshot.png and b/__snapshots__/navigation-item/component/mobile-safari/DBNavigationItem-should-match-screenshot.png differ diff --git a/__snapshots__/navigation-item/component/webkit/DBNavigationItem-should-match-screenshot.png b/__snapshots__/navigation-item/component/webkit/DBNavigationItem-should-match-screenshot.png index 502adcb41313..651982f10623 100644 Binary files a/__snapshots__/navigation-item/component/webkit/DBNavigationItem-should-match-screenshot.png and b/__snapshots__/navigation-item/component/webkit/DBNavigationItem-should-match-screenshot.png differ diff --git a/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-chromium-linux.png b/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-chromium-linux.png index 3108f1799cb6..01086111906e 100644 Binary files a/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-chromium-linux.png and b/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-chromium-linux.png differ diff --git a/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-mobile-chrome-linux.png b/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-mobile-chrome-linux.png index 3108f1799cb6..01086111906e 100644 Binary files a/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-mobile-chrome-linux.png and b/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-mobile-chrome-linux.png differ diff --git a/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-mobile-safari-linux.png b/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-mobile-safari-linux.png index 502adcb41313..a13d1810fe46 100644 Binary files a/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-mobile-safari-linux.png and b/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-mobile-safari-linux.png differ diff --git a/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-webkit-linux.png b/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-webkit-linux.png index 502adcb41313..a13d1810fe46 100644 Binary files a/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-webkit-linux.png and b/__snapshots__/navigation-item/navigation-item.spec.tsx-snapshots/DBNavigationItem-should-match-screenshot-1-webkit-linux.png differ diff --git a/__snapshots__/navigation-item/showcase/chromium/regular/neutral-0/DBNavigationItem-should-match-screenshot.png b/__snapshots__/navigation-item/showcase/chromium/regular/neutral-0/DBNavigationItem-should-match-screenshot.png index df5c9d9b6d37..df4575ed8228 100644 Binary files a/__snapshots__/navigation-item/showcase/chromium/regular/neutral-0/DBNavigationItem-should-match-screenshot.png and b/__snapshots__/navigation-item/showcase/chromium/regular/neutral-0/DBNavigationItem-should-match-screenshot.png differ diff --git a/__snapshots__/navigation-item/showcase/mobile-chrome/regular/neutral-0/DBNavigationItem-should-match-screenshot.png b/__snapshots__/navigation-item/showcase/mobile-chrome/regular/neutral-0/DBNavigationItem-should-match-screenshot.png index 585bc2c957a4..d12f2eff6bcb 100644 Binary files a/__snapshots__/navigation-item/showcase/mobile-chrome/regular/neutral-0/DBNavigationItem-should-match-screenshot.png and b/__snapshots__/navigation-item/showcase/mobile-chrome/regular/neutral-0/DBNavigationItem-should-match-screenshot.png differ diff --git a/__snapshots__/navigation-item/showcase/mobile-safari/regular/neutral-0/DBNavigationItem-should-match-screenshot.png b/__snapshots__/navigation-item/showcase/mobile-safari/regular/neutral-0/DBNavigationItem-should-match-screenshot.png index 5b266ae1550b..7ac857b034ab 100644 Binary files a/__snapshots__/navigation-item/showcase/mobile-safari/regular/neutral-0/DBNavigationItem-should-match-screenshot.png and b/__snapshots__/navigation-item/showcase/mobile-safari/regular/neutral-0/DBNavigationItem-should-match-screenshot.png differ diff --git a/__snapshots__/navigation-item/showcase/webkit/regular/neutral-0/DBNavigationItem-should-match-screenshot.png b/__snapshots__/navigation-item/showcase/webkit/regular/neutral-0/DBNavigationItem-should-match-screenshot.png index e37a8a9f11fe..313cdebf684c 100644 Binary files a/__snapshots__/navigation-item/showcase/webkit/regular/neutral-0/DBNavigationItem-should-match-screenshot.png and b/__snapshots__/navigation-item/showcase/webkit/regular/neutral-0/DBNavigationItem-should-match-screenshot.png differ diff --git a/__snapshots__/section/showcase/chromium/regular/neutral-0/DBSection-should-match-screenshot.png b/__snapshots__/section/showcase/chromium/regular/neutral-0/DBSection-should-match-screenshot.png index d9df155f4f0c..c42eaef01655 100644 Binary files a/__snapshots__/section/showcase/chromium/regular/neutral-0/DBSection-should-match-screenshot.png and b/__snapshots__/section/showcase/chromium/regular/neutral-0/DBSection-should-match-screenshot.png differ diff --git a/__snapshots__/section/showcase/mobile-chrome/regular/neutral-0/DBSection-should-match-screenshot.png b/__snapshots__/section/showcase/mobile-chrome/regular/neutral-0/DBSection-should-match-screenshot.png index 8303663b640c..4eeba80204ce 100644 Binary files a/__snapshots__/section/showcase/mobile-chrome/regular/neutral-0/DBSection-should-match-screenshot.png and b/__snapshots__/section/showcase/mobile-chrome/regular/neutral-0/DBSection-should-match-screenshot.png differ diff --git a/__snapshots__/section/showcase/mobile-safari/regular/neutral-0/DBSection-should-match-screenshot.png b/__snapshots__/section/showcase/mobile-safari/regular/neutral-0/DBSection-should-match-screenshot.png index ecd2de804e42..7a2147ee2d46 100644 Binary files a/__snapshots__/section/showcase/mobile-safari/regular/neutral-0/DBSection-should-match-screenshot.png and b/__snapshots__/section/showcase/mobile-safari/regular/neutral-0/DBSection-should-match-screenshot.png differ diff --git a/__snapshots__/section/showcase/webkit/regular/neutral-0/DBSection-should-match-screenshot.png b/__snapshots__/section/showcase/webkit/regular/neutral-0/DBSection-should-match-screenshot.png index 3502c235390f..0b0a2ac298f5 100644 Binary files a/__snapshots__/section/showcase/webkit/regular/neutral-0/DBSection-should-match-screenshot.png and b/__snapshots__/section/showcase/webkit/regular/neutral-0/DBSection-should-match-screenshot.png differ diff --git a/package-lock.json b/package-lock.json index a3a9377d2393..98ce51466f91 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3701,32 +3701,10 @@ "postcss-selector-parser": "^6.0.10" } }, - "node_modules/@db-ui/base": { - "version": "0.22.2", - "resolved": "https://registry.npmjs.org/@db-ui/base/-/base-0.22.2.tgz", - "integrity": "sha512-uUW9RynL3134og5awxy1rWHL2zDP4BolzfjzGNq/UqF5KgoNz8e5TvPagieCbXW/5idBffdLqoLak/jSc7fd0A==" - }, "node_modules/@db-ui/components": { "resolved": "packages/components", "link": true }, - "node_modules/@db-ui/core": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@db-ui/core/-/core-2.11.4.tgz", - "integrity": "sha512-juPA7ZwEj9qcb7OiCgVKhrMtibP0N+QJvqSzjfXDMFzNtRTr1AEUzW9BmiVMZGlF8wxfFMKmoIH9Ahl/Cw4KKA==", - "dependencies": { - "@csstools/normalize.css": "^12.0.0", - "@db-ui/base": "^0.22.2" - } - }, - "node_modules/@db-ui/elements": { - "version": "0.24.6", - "resolved": "https://registry.npmjs.org/@db-ui/elements/-/elements-0.24.6.tgz", - "integrity": "sha512-Lz42NO47bU2iu+v0ndV5WhJ3gDF6RNbmV9bU2sJTjUq9uezX6RRR3zT008gvVFka3XuSNDK8kLSKovOkimaXEA==", - "dependencies": { - "@db-ui/core": "^2.11.4" - } - }, "node_modules/@db-ui/eslint-plugin": { "resolved": "packages/eslint", "link": true @@ -3743,14 +3721,6 @@ "resolved": "output/react", "link": true }, - "node_modules/@db-ui/react-elements": { - "version": "0.24.6", - "resolved": "https://registry.npmjs.org/@db-ui/react-elements/-/react-elements-0.24.6.tgz", - "integrity": "sha512-gkwL4BTcfnkyHZph3xgYotPoTuWBOxn519IcH9cjkRG9CAZCPrQQLb4NFD5+wm+nUA+1oRW2nUG4WBJngTkspg==", - "dependencies": { - "@db-ui/elements": "0.24.6" - } - }, "node_modules/@db-ui/v-components": { "resolved": "output/vue/vue3", "link": true @@ -35071,7 +35041,6 @@ "version": "0.1.0", "dependencies": { "@code-hike/mdx": "^0.9.0", - "@db-ui/react-elements": "^0.24.6", "next": "13.4.16", "react": "18.2.0", "react-dom": "18.2.0", @@ -37696,11 +37665,6 @@ "dev": true, "requires": {} }, - "@db-ui/base": { - "version": "0.22.2", - "resolved": "https://registry.npmjs.org/@db-ui/base/-/base-0.22.2.tgz", - "integrity": "sha512-uUW9RynL3134og5awxy1rWHL2zDP4BolzfjzGNq/UqF5KgoNz8e5TvPagieCbXW/5idBffdLqoLak/jSc7fd0A==" - }, "@db-ui/components": { "version": "file:packages/components", "requires": { @@ -37717,23 +37681,6 @@ "sass": "^1.65.1" } }, - "@db-ui/core": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/@db-ui/core/-/core-2.11.4.tgz", - "integrity": "sha512-juPA7ZwEj9qcb7OiCgVKhrMtibP0N+QJvqSzjfXDMFzNtRTr1AEUzW9BmiVMZGlF8wxfFMKmoIH9Ahl/Cw4KKA==", - "requires": { - "@csstools/normalize.css": "^12.0.0", - "@db-ui/base": "^0.22.2" - } - }, - "@db-ui/elements": { - "version": "0.24.6", - "resolved": "https://registry.npmjs.org/@db-ui/elements/-/elements-0.24.6.tgz", - "integrity": "sha512-Lz42NO47bU2iu+v0ndV5WhJ3gDF6RNbmV9bU2sJTjUq9uezX6RRR3zT008gvVFka3XuSNDK8kLSKovOkimaXEA==", - "requires": { - "@db-ui/core": "^2.11.4" - } - }, "@db-ui/eslint-plugin": { "version": "file:packages/eslint" }, @@ -38696,14 +38643,6 @@ "sass": "^1.65.1" } }, - "@db-ui/react-elements": { - "version": "0.24.6", - "resolved": "https://registry.npmjs.org/@db-ui/react-elements/-/react-elements-0.24.6.tgz", - "integrity": "sha512-gkwL4BTcfnkyHZph3xgYotPoTuWBOxn519IcH9cjkRG9CAZCPrQQLb4NFD5+wm+nUA+1oRW2nUG4WBJngTkspg==", - "requires": { - "@db-ui/elements": "0.24.6" - } - }, "@db-ui/v-components": { "version": "file:output/vue/vue3", "requires": { @@ -45347,7 +45286,6 @@ "@babel/cli": "7.22.10", "@babel/preset-react": "7.22.5", "@code-hike/mdx": "^0.9.0", - "@db-ui/react-elements": "^0.24.6", "@mdx-js/loader": "^2.3.0", "@mdx-js/react": "^2.3.0", "@next/mdx": "^13.4.16", diff --git a/packages/components/mitosis.config.js b/packages/components/mitosis.config.js index cf4f98667806..afd4a204408a 100644 --- a/packages/components/mitosis.config.js +++ b/packages/components/mitosis.config.js @@ -20,10 +20,15 @@ module.exports = { attributeChangedCallback(test, json) { const properties = json?.meta?.useMetadata?.component?.properties?.map( - (prop) => prop.name + (prop) => prop.name.toLowerCase() ) || []; return ( - 'this.props[name] = newValue;\n' + + 'const foundProp = this.componentProps.find(prop=> prop.toLowerCase() === name);\n' + + "if (newValue === 'false') {\n" + + '\t\t\tdelete this.props[foundProp];\n' + + '\t\t} else {\n' + + '\t\t\tthis.props[foundProp] = newValue;\n' + + '\t\t}' + ' this.update();' + '}' + 'static get observedAttributes() {\n' + diff --git a/packages/components/overrides/angular/src/components/main-navigation/index.ts b/packages/components/overrides/angular/src/components/main-navigation/index.ts new file mode 100644 index 000000000000..48bd43cb7e94 --- /dev/null +++ b/packages/components/overrides/angular/src/components/main-navigation/index.ts @@ -0,0 +1 @@ +export { DBMainNavigation, DBMainNavigationModule } from './main-navigation'; diff --git a/packages/components/overrides/angular/src/components/sub-navigation/index.ts b/packages/components/overrides/angular/src/components/sub-navigation/index.ts new file mode 100644 index 000000000000..1368a7fcd4b6 --- /dev/null +++ b/packages/components/overrides/angular/src/components/sub-navigation/index.ts @@ -0,0 +1 @@ +export { DBSubNavigation, DBSubNavigationModule } from './sub-navigation'; diff --git a/packages/components/package.json b/packages/components/package.json index ba28bcdb0ccc..8065331e27b1 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -19,9 +19,10 @@ "build:mitosis": "mitosis build", "build:mv-styles": "cpr src build -o -f \"(.ts|.tsx|.md)$\"", "build:sass": "sass build --no-source-map --load-path=node_modules/ --load-path=../../node_modules/ --future-deprecation=import", + "build:z-directives": "cpr overrides/angular ../../output/angular -o", "build:z-post": "node scripts/post-build/index.js", "build:z2-docs": "react-docgen ../../output/react/src/components/**/*.tsx -o ../../output/docs.json -i *.spec.tsx", - "compile:angular": "mitosis build -c mitosis-angular.config.js && node -e \"require('./scripts/post-build/angular.js')(true)\" && cpr ../../output/tmp/angular/src ../../output/angular/src -o", + "compile:angular": "mitosis build -c mitosis-angular.config.js && node -e \"require('./scripts/post-build/angular.js')(true)\" && npm run build:z-directives && cpr ../../output/tmp/angular/src ../../output/angular/src -o", "compile:react": "mitosis build -c mitosis-react.config.js && node -e \"require('./scripts/post-build/react.js')(true)\" && cpr ../../output/tmp/react/src ../../output/react/src -o", "compile:vue": "mitosis build -c mitosis-vue.config.js && node -e \"require('./scripts/post-build/vue.js')(true)\" && cpr ../../output/tmp/vue/vue3/src ../../output/vue/vue3/src -o", "copy-output": "npm-run-all copy:*", diff --git a/packages/components/scripts/post-build/angular.js b/packages/components/scripts/post-build/angular.js index 89bca6952387..85f473cffb02 100644 --- a/packages/components/scripts/post-build/angular.js +++ b/packages/components/scripts/post-build/angular.js @@ -1,6 +1,7 @@ const Replace = require('replace-in-file'); +const FS = require('node:fs'); const { components } = require('./components'); -const { runReplacements } = require('../utils'); +const { runReplacements, getComponentName } = require('../utils'); const changeFile = (component, input) => { return input @@ -38,18 +39,17 @@ const changeFile = (component, input) => { * * @param {*} replacements * @param {*} componentName + * @param {*} upperComponentName * @param {*} valueAccessor 'checked' | 'value' [adopt if needed] */ const setControlValueAccessorReplacements = ( replacements, componentName, + upperComponentName, valueAccessor ) => { // for native angular support (e.g. reactive forms) we have to implement // the ControlValueAccessor interface with all impacts :/ - const upperComponentName = `DB${ - componentName.charAt(0).toUpperCase() + componentName.slice(1) - }`; replacements.push({ from: '} from "@angular/core";', @@ -105,9 +105,71 @@ const setControlValueAccessorReplacements = ( }); }; +/** + * It's not possible to use multiple times in a component. + * In Angular, you have to use a directive for this... + * This is a workaround to replace it in the file. + * @param replacements + * @param componentName {string} + * @param upperComponentName {string} + * @param directives {{name:string, ngContentName?:string}[]} + */ +const setDirectiveReplacements = ( + replacements, + componentName, + upperComponentName, + directives +) => { + for (const directive of directives) { + // Add ng-content multiple times to overwrite all + for (let i = 0; i < 4; i++) { + replacements.push({ + from: ``, + to: `` + }); + } + + replacements.push({ + from: `export class ${upperComponentName} {\n`, + to: + `export class ${upperComponentName} {\n` + + `\t@ContentChild(${directive.name}Directive, { read: TemplateRef }) db${directive.name}: any;\n` + }); + + replacements.push({ + from: 'import { NgModule } from "@angular/core";', + to: + 'import { NgModule } from "@angular/core";\n' + + `import { ${directive.name}Directive } from './${directive.name}.directive';\n` + }); + + FS.writeFileSync( + `../../output/angular/src/components/${componentName}/${directive.name}.directive.ts`, + '/* Angular cannot handle multiple slots with the same name, we need to use Directives for this. */\n' + + "import { Directive } from '@angular/core';" + + ` +@Directive({ +\tselector: '[db${directive.name}]' +}) +export class ${directive.name}Directive {} +` + ); + } + + replacements.push({ + from: 'import { NgModule } from "@angular/core";', + to: "import { NgModule, ContentChild, TemplateRef } from '@angular/core';" + }); +}; + module.exports = (tmp) => { for (const component of components) { const componentName = component.name; + const upperComponentName = `DB${getComponentName(component.name)}`; const file = `../../${ tmp ? 'output/tmp' : 'output' }/angular/src/components/${componentName}/${componentName}.ts`; @@ -118,18 +180,24 @@ module.exports = (tmp) => { const replacements = []; - if ( - component.config && - component.config.angular && - component.config.angular.controlValueAccessor - ) { + if (component.config?.angular?.controlValueAccessor) { setControlValueAccessorReplacements( replacements, componentName, + upperComponentName, component.config.angular.controlValueAccessor // value / checked / ... ); } + if (component.config?.angular?.directives?.length > 0) { + setDirectiveReplacements( + replacements, + componentName, + upperComponentName, + component.config.angular.directives + ); + } + try { Replace.sync(options); runReplacements(replacements, component, 'angular', file); diff --git a/packages/components/scripts/post-build/components.js b/packages/components/scripts/post-build/components.js index 1a404ca58aa7..c29e99e50837 100644 --- a/packages/components/scripts/post-build/components.js +++ b/packages/components/scripts/post-build/components.js @@ -1,17 +1,21 @@ /** * @returns {[{ * name:string, - * defaultStylePath:string, * overwrites?:{ * global?:{from:string,to:string}[], * angular?:{from:string,to:string}[], * react?:{from:string,to:string}[], - * vue?:{from:string,to:string}[] + * vue?:{from:string,to:string}[], + * webComponents?:{from:string,to:string}[] * }, * config?:{ * vue?:{ * vModel?: {modelValue:string, binding:string}[] - * } + * }, + * angular?: { + * controlValueAccessor?: string, + * directives?: {name:string, ngContentName?:string}[] + * } * } * }]} */ @@ -21,13 +25,29 @@ const getComponents = () => [ }, { - name: 'navigation-item' + name: 'main-navigation' }, { - name: 'select' + name: 'navigation-item', + config: { + angular: { + directives: [{ name: 'NavigationContent' }] + } + } }, + { + name: 'select', + config: { + vue: { + vModel: [{ modelValue: 'value', binding: ':value' }] + }, + angular: { + controlValueAccessor: 'value' + } + } + }, { name: 'drawer', overwrites: { @@ -92,7 +112,55 @@ const getComponents = () => [ name: 'page' }, { - name: 'header' + name: 'header', + config: { + angular: { + directives: [ + { name: 'ActionBar', ngContentName: 'action-bar' }, + { + name: 'MetaNavigation', + ngContentName: 'meta-navigation' + }, + { name: 'Navigation' } + ] + } + }, + overwrites: { + global: [ + { + from: '(event) => toggle()', + to: '() => toggle()' + }, + { + from: '(event) => toggle()', + to: '() => toggle()' + } + ], + webComponents: [ + { + from: '', + to: '' + }, + { + from: 'name="meta-navigation"', + to: 'name="meta-navigation-mobile"' + }, + { + from: 'name="action-bar"', + to: 'name="action-bar-mobile"' + }, + { + from: + ' el.removeEventListener("close", this.onDbDrawerDbHeaderClose);\n' + + ' el.addEventListener("close", this.onDbDrawerDbHeaderClose);', + to: 'el.props.onClose = this.onDbDrawerDbHeaderClose;' + }, + { + from: 'if(this.props.drawerOpen) el.setAttribute("open", this.props.drawerOpen);', + to: ' el.setAttribute("open", Boolean(this.props.drawerOpen));' + } + ] + } }, { name: 'brand' diff --git a/packages/components/scripts/post-build/react.js b/packages/components/scripts/post-build/react.js index 9454f034d1f2..00ebb5c7e372 100644 --- a/packages/components/scripts/post-build/react.js +++ b/packages/components/scripts/post-build/react.js @@ -27,6 +27,14 @@ module.exports = (tmp) => { { from: `checked={props.checked}`, to: `defaultChecked={props.checked}` + }, + { + from: 'if (ref.current)', + to: 'if (ref?.current)' + }, + { + from: '[ref.current]', + to: '[ref]' } ]; diff --git a/packages/components/scripts/post-build/web-components.js b/packages/components/scripts/post-build/web-components.js index 0b24f7802e61..2f4e50ed1ede 100644 --- a/packages/components/scripts/post-build/web-components.js +++ b/packages/components/scripts/post-build/web-components.js @@ -64,8 +64,9 @@ const workaroundAttributes = (lines) => { module.exports = () => { for (const component of components) { + const filePath = `../../output/webcomponent/src/components/${component.name}/${component.name}.ts`; const fixImports = { - files: `../../output/webcomponent/src/components/${component.name}/${component.name}.ts`, + files: filePath, processor(input) { let lines = input .split('\n') @@ -88,7 +89,7 @@ module.exports = () => { }; const defaultStyleUrl = { - files: `../../output/webcomponent/src/components/${component.name}/${component.name}.ts`, + files: filePath, from: 'this.state = {', to: `this.state = {stylePath: "components/${component.name}/${component.name}-web-component.css",` }; @@ -96,11 +97,18 @@ module.exports = () => { try { Replace.sync(fixImports); Replace.sync(defaultStyleUrl); - if ( - Fse.pathExistsSync( - `../../output/webcomponent/src/components/${component.name}/${component.name}.ts` - ) - ) { + + if (component?.overwrites?.webComponents) { + for (const over of component.overwrites.webComponents) { + Replace.sync({ + files: filePath, + from: over.from, + to: over.to + }); + } + } + + if (Fse.pathExistsSync(filePath)) { Fse.moveSync( `../../output/webcomponent/src/components/${component.name}/${component.name}.ts`, `../../output/webcomponent/src/components/${component.name}/${component.name}.js` diff --git a/packages/components/src/components/brand/brand.scss b/packages/components/src/components/brand/brand.scss index a403e43a10b8..406f36e81524 100644 --- a/packages/components/src/components/brand/brand.scss +++ b/packages/components/src/components/brand/brand.scss @@ -10,6 +10,8 @@ .db-brand { @extend %brand-display; + font-weight: 700; + a { @extend %brand-display; color: inherit; @@ -21,7 +23,4 @@ .db-logo { max-inline-size: none; block-size: $db-sizing-sm; - @media screen and (min-width: $db-screens-m) { - block-size: $db-sizing-md; - } } diff --git a/packages/components/src/components/drawer/drawer.scss b/packages/components/src/components/drawer/drawer.scss index 6dfb26a0cf16..4efbb4c49f72 100644 --- a/packages/components/src/components/drawer/drawer.scss +++ b/packages/components/src/components/drawer/drawer.scss @@ -81,12 +81,18 @@ $spacings: ( padding-block: map.get($spacing, "block"); .db-drawer-header { - padding-block-end: map.get($spacing, "block"); + padding-block-end: var( + --db-drawer-header-padding-block-end, + map.get($spacing, "block") + ); padding-inline: map.get($spacing, "inline"); } .db-drawer-content { - padding-inline: map.get($spacing, "inline"); + padding-inline: var( + --db-drawer-content-padding-inline, + map.get($spacing, "inline") + ); } } diff --git a/packages/components/src/components/header/docs/Angular.md b/packages/components/src/components/header/docs/Angular.md index dc4db9302141..745abc94bd1a 100644 --- a/packages/components/src/components/header/docs/Angular.md +++ b/packages/components/src/components/header/docs/Angular.md @@ -10,6 +10,12 @@ import { DBHeaderModule } from '@db-ui/ngx-components'; @NgModule({ ... + declarations: [ + ..., + NavigationDirective, // Optional: If you want to use a Navigation + ActionBarDirective, // Optional: If you want to use ActionBar + MetaNavigationDirective, // Optional: If you want to use MetaNavigation + ], imports: [..., DBHeaderModule], ... }) @@ -18,9 +24,59 @@ import { DBHeaderModule } from '@db-ui/ngx-components'; ### Use component +#### Simple + ```html app.component.html Header ``` + +#### Full + +```ts app.component.ts +// File: app.component.ts + +import { Component } from "@angular/core"; + +@Component({ + selector: "app-root", + templateUrl: "./app.component.html" +}) +export class AppComponent { + drawerOpen = false; + + toggleDrawer = (open: boolean) => { + this.drawerOpen = open; + }; +} +``` + +```html app.component.html + + + My Awesome App + + + + + Imprint + Help + + + + Search + + + + + Profile + + + Notification + + Help + + +``` diff --git a/packages/components/src/components/header/docs/React.md b/packages/components/src/components/header/docs/React.md index 398cc07f2189..e95155262fd0 100644 --- a/packages/components/src/components/header/docs/React.md +++ b/packages/components/src/components/header/docs/React.md @@ -4,6 +4,8 @@ For general installation and configuration take a look at the [react-components] ### Use component +#### Simple + ```tsx App.tsx // App.tsx import { DBHeader, DBBrand } from "@db-ui/react-components"; @@ -12,3 +14,51 @@ const App = () => Header} />; export default App; ``` + +#### Full + +```tsx App.tsx +// App.tsx +import { useState } from "react"; +import { DBHeader, DBBrand, DBLink } from "@db-ui/react-components"; + +const [drawerOpen, setDrawerOpen] = useState(false); + +const App = () => ( + My Awesome App} + slotMetaNavigation={ + <> + Imprint + Help + + } + slotCallToAction={ + + Search + + } + slotActionBar={ + <> + + Profile + + + Notification + + + Help + + + } + > + + // https://github.com/db-ui/mono/blob/main/packages/components/src/components/main-navigation/docs/React.md + + +); + +export default App; +``` diff --git a/packages/components/src/components/header/docs/Vue.md b/packages/components/src/components/header/docs/Vue.md index 52bf40685392..c8195e757db8 100644 --- a/packages/components/src/components/header/docs/Vue.md +++ b/packages/components/src/components/header/docs/Vue.md @@ -4,6 +4,8 @@ For general installation and configuration take a look at the [v-components](htt ### Use component +#### Simple + ```vue App.vue + + +``` diff --git a/packages/components/src/components/header/header-web-component.scss b/packages/components/src/components/header/header-web-component.scss index cd12960b3a36..b4e100192732 100644 --- a/packages/components/src/components/header/header-web-component.scss +++ b/packages/components/src/components/header/header-web-component.scss @@ -1 +1,11 @@ +@use "@db-ui/foundations/build/scss/helpers/functions" as *; @forward "header"; + +.db-header-navigation-bar { + block-size: to-rem(32); + inline-size: auto; +} + +.db-header-divider { + block-size: to-rem(32); +} diff --git a/packages/components/src/components/header/header.lite.tsx b/packages/components/src/components/header/header.lite.tsx index b440bcf1355d..ac0caa175b30 100644 --- a/packages/components/src/components/header/header.lite.tsx +++ b/packages/components/src/components/header/header.lite.tsx @@ -1,19 +1,23 @@ import { onMount, + onUpdate, Show, Slot, useMetadata, useStore } from '@builder.io/mitosis'; import { DBHeaderState, DBHeaderProps } from './model'; -import { cls } from '../../utils'; +import { addAttributeToChildren, cls, uuid } from '../../utils'; +import { DBButton } from '../button'; +import { DBDrawer } from '../drawer'; +import { DEFAULT_ID } from '../../shared/constants'; useMetadata({ isAttachedToShadowDom: true, component: { // MS Power Apps includeIcon: false, - properties: [] + properties: [{ name: 'drawerOpen', type: 'TwoOptions' }] } }); @@ -21,35 +25,108 @@ export default function DBHeader(props: DBHeaderProps) { // This is used as forwardRef let component: any; // jscpd:ignore-start - const state = useStore({}); + const state = useStore({ + _id: DEFAULT_ID, + initialized: false, + forcedToMobile: false, + defaultValues: { + burgerMenuLabel: 'BurgerMenu' + }, + toggle: () => { + if (props.onToggle) { + props.onToggle(!props.drawerOpen); + } + } + }); onMount(() => { + state.initialized = true; + state._id = props.id || 'header-' + uuid(); if (props.stylePath) { state.stylePath = props.stylePath; } }); + + onUpdate(() => { + if (state.initialized && document && state._id && props.forceMobile) { + const headerElement = document.getElementById( + state._id + ) as HTMLElement; + if (headerElement) { + // Adds this attribute to the header to enable all styling which would have + // @media screen and (min-width: $db-screens-m) to show mobile navigation on a desktop device + addAttributeToChildren(headerElement, { + key: 'force-mobile', + value: '' + }); + } + state.forcedToMobile = true; + } + }, [state.initialized]); + // jscpd:ignore-end return ( ); } diff --git a/packages/components/src/components/header/header.scss b/packages/components/src/components/header/header.scss index afd7e60f470a..2258f6f8fa55 100644 --- a/packages/components/src/components/header/header.scss +++ b/packages/components/src/components/header/header.scss @@ -1,44 +1,192 @@ @use "@db-ui/foundations/build/scss/variables" as *; @use "@db-ui/foundations/build/scss/variables.global" as *; @use "@db-ui/foundations/build/scss/helpers/functions" as *; +@use "@db-ui/foundations/build/scss/helpers/component" as *; +@use "@db-ui/foundations/build/scss/tonality" as *; .db-header { background-color: $db-colors-neutral-bg; box-shadow: $db-elevation-4; display: flex; - justify-content: space-between; - align-items: center; + flex-direction: column; + margin-block-end: $db-spacing-fixed-2xs; position: relative; - /* Mobile header should always be 56px */ - min-block-size: to-rem(56); + min-block-size: $default-mobile-header-height; - gap: $db-spacing-fixed-md; - padding-inline: $db-spacing-fixed-md; + @include screen("m") { + --db-drawer-max-width: #{$db-screens-s}; + } .db-link { display: inline-block; } - .desktop-navigation, - .meta-navigation { + &[data-on-forcing-mobile="true"] { + /* + We make the header invisible for a short time if the user passes in force-mobile property. + We do it because otherwise we see the default desktop-navigation for some mil. sec. + */ + visibility: hidden; + } +} + +.db-header-navigation-bar { + display: flex; + position: relative; + padding: $db-spacing-fixed-xs $db-spacing-fixed-md; + gap: $db-spacing-fixed-xs; + inline-size: 100%; + align-items: center; + + @include screen("m") { + padding: $db-spacing-fixed-md; + } +} + +.db-header-meta-navigation { + @extend %db-ui-functional; + @include divider("top"); + display: flex; + flex-direction: column; + gap: $db-spacing-fixed-sm; + justify-content: end; + background-color: $db-colors-neutral-bg-2-enabled; + + padding: $db-spacing-fixed-md; + + @include screen("m") { + padding: $db-spacing-fixed-xs $db-spacing-fixed-md; + margin: 0; + flex-direction: row; + } + + &:empty { display: none; } +} - @media screen and (min-width: $db-screens-m) { - /* Desktop header should always be 80px */ - min-block-size: to-rem(80); +.db-header-navigation-container { + display: inherit; + flex: 1 1 auto; + inline-size: 100%; + gap: inherit; + align-items: center; +} - .mobile-navigation { - display: none; +.db-header-call-to-action { + margin-inline-start: auto; +} + +.db-header-brand-container:not(:has(> :nth-child(1))) { + display: none; +} + +.db-header-action-container:has(> .db-header-action-bar:empty) { + @include screen("m") { + display: none; + } +} + +.db-header-brand-container { + @include screen("m") { + @include divider("left", "after"); + + &::after { + position: inherit; + block-size: 100%; + margin-inline: $db-spacing-fixed-sm; } + } +} - .meta-navigation { - display: inherit; +.db-header-action-container { + @include divider("left"); + + &::before { + position: inherit; + block-size: 100%; + + @include screen("m") { + margin-inline-end: $db-spacing-fixed-sm; } + } +} - .desktop-navigation { - display: inherit; +.db-header-brand-container, +.db-header-action-container { + align-items: center; + block-size: 100%; + display: inherit; + gap: inherit; + flex: 0 1 auto; + flex-grow: 0; + flex-shrink: 0; +} + +.db-header-action-bar { + @include divider("top"); + flex: 0 1 auto; + flex-grow: 0; + flex-shrink: 0; + padding-block-start: $db-spacing-fixed-xs; + + @include screen("m") { + &::before { + display: none; } } } + +.db-header-drawer-navigation { + display: flex; + flex-direction: column; + flex: 1 1 auto; + block-size: 100%; + overflow: auto; + justify-content: space-between; +} + +.db-header-navigation { + padding-block: $db-spacing-fixed-md; +} + +.db-header-navigation, +.db-header-action-bar { + display: flex; + gap: $db-spacing-fixed-sm; + padding-inline: $db-spacing-fixed-md; + + @include screen("m") { + gap: $db-spacing-fixed-xs; + padding: 0; + } +} + +.db-header-drawer { + --db-drawer-content-padding-inline: 0; + // 1px for box shadow of header + --db-drawer-header-padding-block-end: calc(1px + #{$db-spacing-fixed-xs}); + padding-block-end: 0; + + & .db-drawer-content { + display: flex; + flex-direction: column; + block-size: 100%; + overflow: hidden; + } +} + +[data-hide-on="mobile"] { + display: none; + + @include screen("m") { + display: inherit; + } +} + +[data-hide-on="desktop"] { + @include screen("m") { + display: none; + } +} diff --git a/packages/components/src/components/header/model.ts b/packages/components/src/components/header/model.ts index 38cc716477dd..ab6acd18d314 100644 --- a/packages/components/src/components/header/model.ts +++ b/packages/components/src/components/header/model.ts @@ -1,14 +1,41 @@ -import { GlobalProps, GlobalState } from '../../shared/model'; +import { + GlobalProps, + GlobalState, + InitializedState, + ToggleEventProps, + ToggleEventState +} from '../../shared/model'; export interface DBHeaderDefaultProps { slotBrand?: any; - slotDesktopNavigation?: any; - slotMobileNavigation?: any; slotMetaNavigation?: any; + slotCallToAction?: any; + slotActionBar?: any; + drawerOpen?: boolean; + + /** + * Forces the header to use mobile layout for desktop as well. + * You should only use this setting if you really can't provide a smaller navigation. + * Overwrite size of the drawer with '--db-drawer-max-width: xxx' + */ + forceMobile?: boolean; + + /** + * This attribute sets the label for the burger menu button for mobile headers. + */ + + burgerMenuLabel?: string; } -export type DBHeaderProps = DBHeaderDefaultProps & GlobalProps; +export type DBHeaderProps = DBHeaderDefaultProps & + GlobalProps & + ToggleEventProps; -export interface DBHeaderDefaultState {} +export interface DBHeaderDefaultState { + forcedToMobile?: boolean; +} -export type DBHeaderState = DBHeaderDefaultState & GlobalState; +export type DBHeaderState = DBHeaderDefaultState & + GlobalState & + ToggleEventState & + InitializedState; diff --git a/packages/components/src/components/input/input.scss b/packages/components/src/components/input/input.scss index 5e12a876461a..3bc6616c86c4 100644 --- a/packages/components/src/components/input/input.scss +++ b/packages/components/src/components/input/input.scss @@ -159,7 +159,7 @@ &:has(input:is(:focus, :not(:placeholder-shown))) { &::after { - transform: rotate(180deg); + transform: rotate(-180deg); } } diff --git a/packages/components/src/components/input/model.ts b/packages/components/src/components/input/model.ts index b9a38b463724..78f9b1a4f2b2 100644 --- a/packages/components/src/components/input/model.ts +++ b/packages/components/src/components/input/model.ts @@ -51,7 +51,6 @@ export type DBInputProps = DBInputDefaultProps & export type DBInputDefaultState = { _dataListId?: string; - _value?: any; getIcon: (variant?: DefaultVariantType) => string; }; diff --git a/packages/components/src/components/main-navigation/docs/Angular.md b/packages/components/src/components/main-navigation/docs/Angular.md new file mode 100644 index 000000000000..ad52345c1955 --- /dev/null +++ b/packages/components/src/components/main-navigation/docs/Angular.md @@ -0,0 +1,63 @@ +## Angular + +For general installation and configuration look at the [ngx-components](https://www.npmjs.com/package/@db-ui/ngx-components) package. + +### Load component + +```ts app.module.ts +//app.module.ts +import { DBMainNavigationModule } from '@db-ui/ngx-components'; + +@NgModule({ + ... + imports: [..., DBMainNavigationModule], + ... +}) + +``` + +### Use component + +```html app.component.html + + + + + + + + Sub-Navi-Item 1 + + + + + Sub-Sub-Navi-Item 1 + + + + + Sub-Sub-Navi-Item 2 + + + + + + + Sub-Navi-Item 2 + + + + Navi-Item 1 + + + + Navi-Item 2 + + + + + Navi-Item 3 + + + +``` diff --git a/packages/components/src/components/main-navigation/docs/HTML.md b/packages/components/src/components/main-navigation/docs/HTML.md new file mode 100644 index 000000000000..9ca37be2e11b --- /dev/null +++ b/packages/components/src/components/main-navigation/docs/HTML.md @@ -0,0 +1,55 @@ +## HTML + +For general installation and configuration look at the [components](https://www.npmjs.com/package/@db-ui/components) package. + +### Use component + +```html index.html + +... + + + +``` diff --git a/packages/components/src/components/main-navigation/docs/React.md b/packages/components/src/components/main-navigation/docs/React.md new file mode 100644 index 000000000000..3dddcbaead06 --- /dev/null +++ b/packages/components/src/components/main-navigation/docs/React.md @@ -0,0 +1,50 @@ +## React + +For general installation and configuration look at the [react-components](https://www.npmjs.com/package/@db-ui/react-components) package. + +### Use component + +```tsx App.tsx +// App.tsx +import { DBMainNavigation } from "@db-ui/react-components"; + +const App = () => ( + + + + + Sub-Sub-Navi-Item 1 + + + Sub-Sub-Navi-Item 2 + + + } + > + Sub-Navi-Item 1 + + + Sub-Navi-Item 2 + + + } + > + Navi-Item 1 + + + Navi-Item 2 + + + Navi-Item 3 + + +); + +export default App; +``` diff --git a/packages/components/src/components/main-navigation/docs/Vue.md b/packages/components/src/components/main-navigation/docs/Vue.md new file mode 100644 index 000000000000..2d41c5c7bb30 --- /dev/null +++ b/packages/components/src/components/main-navigation/docs/Vue.md @@ -0,0 +1,43 @@ +## Vue + +For general installation and configuration look at the [v-components](https://www.npmjs.com/package/@db-ui/v-components) package. + +### Use component + +```vue App.vue + + + + +``` diff --git a/packages/components/src/components/main-navigation/index.ts b/packages/components/src/components/main-navigation/index.ts new file mode 100644 index 000000000000..846a714dbd69 --- /dev/null +++ b/packages/components/src/components/main-navigation/index.ts @@ -0,0 +1 @@ +export { default as DBMainNavigation } from './main-navigation'; diff --git a/packages/components/src/components/main-navigation/main-navigation-web-component.scss b/packages/components/src/components/main-navigation/main-navigation-web-component.scss new file mode 100644 index 000000000000..7aad751257f4 --- /dev/null +++ b/packages/components/src/components/main-navigation/main-navigation-web-component.scss @@ -0,0 +1 @@ +@forward "main-navigation"; diff --git a/packages/components/src/components/main-navigation/main-navigation.lite.tsx b/packages/components/src/components/main-navigation/main-navigation.lite.tsx new file mode 100644 index 000000000000..251f995f17ba --- /dev/null +++ b/packages/components/src/components/main-navigation/main-navigation.lite.tsx @@ -0,0 +1,36 @@ +import { onMount, Show, useMetadata, useStore } from '@builder.io/mitosis'; +import { DBMainNavigationState, DBMainNavigationProps } from './model'; +import { cls } from '../../utils'; + +useMetadata({ + isAttachedToShadowDom: true, + component: { + // MS Power Apps + includeIcon: false, + properties: [] + } +}); + +export default function DBMainNavigation(props: DBMainNavigationProps) { + // This is used as forwardRef + let component: any; + // jscpd:ignore-start + const state = useStore({}); + + onMount(() => { + if (props.stylePath) { + state.stylePath = props.stylePath; + } + }); + + // jscpd:ignore-end + + return ( + + ); +} diff --git a/packages/components/src/components/main-navigation/main-navigation.scss b/packages/components/src/components/main-navigation/main-navigation.scss new file mode 100644 index 000000000000..185a002d9ca9 --- /dev/null +++ b/packages/components/src/components/main-navigation/main-navigation.scss @@ -0,0 +1,88 @@ +@use "@db-ui/foundations/build/scss/variables" as *; +@use "@db-ui/foundations/build/scss/variables.global" as *; +@use "@db-ui/foundations/build/scss/helpers/component" as *; +@use "../../styles/db-puls" as *; +@use "../../styles/form-components" as *; + +.db-main-navigation { + -webkit-tap-highlight-color: transparent; /* for removing the highlight */ + inline-size: 100%; + + @include screen("m") { + -webkit-tap-highlight-color: inherit; + inline-size: auto; + } + + & > menu { + display: flex; + flex-direction: column; + padding: 0; + margin: 0; + gap: $db-spacing-fixed-sm; + + @include screen("m") { + flex-direction: row; + } + + .db-navigation-item { + .db-navigation-item-expand-button:is(button), + .db-navigation-item-expand-button > button { + // overwrite for main-navigation items + @include screen("m") { + &::after { + --icon-margin-before: #{$db-spacing-fixed-sm}; + --icon-glyph: "⌄"; + transition: $dropdown-icon-transition; + } + + &:hover, + &:focus-visible, + &:has(~ .db-sub-navigation:hover), + &:has(~ .db-sub-navigation:focus-visible), + &:has(~ .db-sub-navigation:focus-within) { + &::after { + transform: rotate(-180deg); + } + } + } + } + + // re overwrite for non main-navigation items + & > menu { + .db-navigation-item-expand-button:is(button), + .db-navigation-item-expand-button > button { + @include screen("m") { + &::after { + --icon-glyph: ">"; + --icon-margin-before: auto; + } + + &:hover, + &:focus-visible, + &:has(~ .db-sub-navigation:hover), + &:has(~ .db-sub-navigation:focus-visible), + &:has(~ .db-sub-navigation:focus-within) { + &::after { + transform: none; + } + } + } + } + } + + &[aria-current="page"] { + // add puls for main-navigation items + @extend %show-db-puls; + + menu { + // hide puls for non main-navigation items + [aria-current="page"] { + &::after { + display: none; + } + } + } + } + } + } +} diff --git a/packages/components/src/components/main-navigation/main-navigation.spec.tsx b/packages/components/src/components/main-navigation/main-navigation.spec.tsx new file mode 100644 index 000000000000..c92f8dfe6de7 --- /dev/null +++ b/packages/components/src/components/main-navigation/main-navigation.spec.tsx @@ -0,0 +1,41 @@ +import { test, expect } from '@playwright/experimental-ct-react'; +import AxeBuilder from '@axe-core/playwright'; + +import { DBMainNavigation } from './index'; +// @ts-ignore - vue can only find it with .ts as file ending +import { DEFAULT_VIEWPORT } from '../../shared/constants.ts'; +import { DBNavigationItem } from '../navigation-item'; + +const comp = ( + + Test1 + Test2 + Test3 + +); + +const testComponent = () => { + test('should match screenshot', async ({ mount }) => { + const component = await mount(comp); + await expect(component).toHaveScreenshot(); + }); +}; + +test.describe('DBMainNavigation', () => { + test.use({ viewport: DEFAULT_VIEWPORT }); + testComponent(); +}); + +test.describe('DBMainNavigation component A11y', () => { + test('DBMainNavigation should not have any automatically detectable accessibility issues', async ({ + page, + mount + }) => { + await mount(comp); + const accessibilityScanResults = await new AxeBuilder({ page }) + .include('.db-main-navigation') + .analyze(); + + expect(accessibilityScanResults.violations).toEqual([]); + }); +}); diff --git a/packages/components/src/components/main-navigation/model.ts b/packages/components/src/components/main-navigation/model.ts new file mode 100644 index 000000000000..1f9a7a7d5ca8 --- /dev/null +++ b/packages/components/src/components/main-navigation/model.ts @@ -0,0 +1,10 @@ +import { GlobalProps, GlobalState, InitializedState } from '../../shared/model'; + +export interface DBMainNavigationDefaultProps {} + +export type DBMainNavigationProps = DBMainNavigationDefaultProps & GlobalProps; + +export interface DBMainNavigationDefaultState {} + +export type DBMainNavigationState = DBMainNavigationDefaultState & + GlobalState; diff --git a/packages/components/src/components/navigation-item/docs/Angular.md b/packages/components/src/components/navigation-item/docs/Angular.md index 3c99ccec7826..ba60f775ef0a 100644 --- a/packages/components/src/components/navigation-item/docs/Angular.md +++ b/packages/components/src/components/navigation-item/docs/Angular.md @@ -10,6 +10,7 @@ import { DBNavigationItemModule } from '@db-ui/ngx-components'; @NgModule({ ... + declarations: [...,NavigationContentDirective], imports: [..., DBNavigationItemModule], ... }) @@ -18,9 +19,34 @@ import { DBNavigationItemModule } from '@db-ui/ngx-components'; ### Use component +We try to set `areaPopup` (has/hasn't sub-navigation) inside the component, but this doesn't work in all frameworks. If you encounter some problems you have the set `areaPopup` with `true/false` for sub-navigation or link + ```html app.component.html - - NavigationItem - + + + + + NavigationItem + + + + + + + Navi-Item 1 + + + + Sub-Navi-Item 1 + + + + + + Sub-Navi-Item 2 + + + + ``` diff --git a/packages/components/src/components/navigation-item/docs/HTML.md b/packages/components/src/components/navigation-item/docs/HTML.md index 88a5cf8ffa51..8219ffbcb108 100644 --- a/packages/components/src/components/navigation-item/docs/HTML.md +++ b/packages/components/src/components/navigation-item/docs/HTML.md @@ -4,17 +4,26 @@ For general installation and configuration take a look at the [components](https ### Use component +If you want to use sub-navigations for mobile you need to add a `eventListner:click` on the `db-navigation-item-expand-button`. This eventListener should set `aria-expanded` to `true` for the `button`. This will open a static overlay for mobile/tablet devices with your `db-sub-navigation`. For desktop devices it works by default with `:hover`. + ```html index.html ... - -
  • - NavigationItem + +
  • + NavigationItem +
  • - -
    - - + +
  • + + + Sub-Navi-Item 1 + Sub-Navi-Item 2 + +
  • ``` diff --git a/packages/components/src/components/navigation-item/docs/React.md b/packages/components/src/components/navigation-item/docs/React.md index df23804a0180..2513b0a096ae 100644 --- a/packages/components/src/components/navigation-item/docs/React.md +++ b/packages/components/src/components/navigation-item/docs/React.md @@ -4,15 +4,36 @@ For general installation and configuration take a look at the [react-components] ### Use component +We try to set `areaPopup` (has/hasn't sub-navigation) inside the component, but this doesn't work in all frameworks. If you encounter some problems you have the set `areaPopup` with `true/false` for sub-navigation or link + ```tsx App.tsx // App.tsx import { Link } from "react-router-dom"; import { DBNavigationItem } from "@db-ui/react-components"; const App = () => ( - - NavigationItem - + <> + {/* Only link */} + + NavigationItem + + + {/* With Sub-Navigation */} + + + Sub-Navi-Item 1 + + + Sub-Navi-Item 2 + + + } + > + Navi-Item 1 + + ); export default App; diff --git a/packages/components/src/components/navigation-item/docs/Vue.md b/packages/components/src/components/navigation-item/docs/Vue.md index 46f9e7d73b97..b33bfe3486f0 100644 --- a/packages/components/src/components/navigation-item/docs/Vue.md +++ b/packages/components/src/components/navigation-item/docs/Vue.md @@ -4,6 +4,8 @@ For general installation and configuration take a look at the [v-components](htt ### Use component +We try to set `areaPopup` (has/hasn't sub-navigation) inside the component, but this doesn't work in all frameworks. If you encounter some problems you have the set `areaPopup` with `true/false` for sub-navigation or link + ```vue App.vue ``` diff --git a/packages/components/src/components/navigation-item/model.ts b/packages/components/src/components/navigation-item/model.ts index 06853189f83c..7d9a5bac566d 100644 --- a/packages/components/src/components/navigation-item/model.ts +++ b/packages/components/src/components/navigation-item/model.ts @@ -7,6 +7,7 @@ import { IconProps, IconState, InitializedState, + NavigationBackButtonProps, WidthProps } from '../../shared/model'; @@ -16,6 +17,12 @@ export interface DBNavigationItemDefaultProps { */ active?: boolean; + /** + * If the attribute is set the item acts like a button with a sub-navigation + */ + + areaPopup?: boolean; + /** * The disabled attribute can be set to [keep a user from clicking on the item](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#disabled). */ @@ -26,19 +33,30 @@ export interface DBNavigationItemDefaultProps { */ slotSubNavigation?: any; + + /** + * This is for mobile navigation only, if it is set the sub-navigation is a static overlay + */ + subNavigationExpanded?: boolean; } export type DBNavigationItemProps = DBNavigationItemDefaultProps & GlobalProps & ClickEventProps & IconProps & - IconAfterProps & - WidthProps; + WidthProps & + NavigationBackButtonProps; export interface DBNavigationItemDefaultState { + handleBackClick: (event: any) => void; hasAreaPopup: boolean; + isSubNavigationExpanded: boolean; subNavigationId: string; - hideSubNavigation?: boolean; + + /** + * Internal state property to show/hide sub-navigation button + */ + hasSubNavigation?: boolean; } export type DBNavigationItemState = DBNavigationItemDefaultState & diff --git a/packages/components/src/components/navigation-item/navigation-item.lite.tsx b/packages/components/src/components/navigation-item/navigation-item.lite.tsx index b6f20a9ad45a..17a4df7901ec 100644 --- a/packages/components/src/components/navigation-item/navigation-item.lite.tsx +++ b/packages/components/src/components/navigation-item/navigation-item.lite.tsx @@ -6,8 +6,10 @@ import { useMetadata, useStore } from '@builder.io/mitosis'; -import { DBNavigationItemProps, DBNavigationItemState } from './model'; +import { DBNavigationItemState, DBNavigationItemProps } from './model'; +import { DBButton } from '../button'; import { cls, uuid } from '../../utils'; +import { DEFAULT_BACK } from '../../shared/constants'; useMetadata({ isAttachedToShadowDom: true, @@ -26,12 +28,21 @@ export default function DBNavigationItem(props: DBNavigationItemProps) { const state = useStore({ initialized: false, hasAreaPopup: false, - hideSubNavigation: false, + hasSubNavigation: true, + isSubNavigationExpanded: false, subNavigationId: 'sub-navigation-' + uuid(), handleClick: (event: any) => { if (props.onClick) { props.onClick(event); } + + if (state.hasAreaPopup) { + state.isSubNavigationExpanded = true; + } + }, + handleBackClick: (event: any) => { + event.stopPropagation(); + state.isSubNavigationExpanded = false; }, iconVisible: (icon?: string) => { return Boolean(icon && icon !== '_' && icon !== 'none'); @@ -46,7 +57,16 @@ export default function DBNavigationItem(props: DBNavigationItemProps) { }); onUpdate(() => { - if (state.initialized && document && state.subNavigationId) { + if (props.subNavigationExpanded !== undefined) { + state.isSubNavigationExpanded = !!props.subNavigationExpanded; + } + }, [props.subNavigationExpanded]); + + onUpdate(() => { + if (props.areaPopup !== undefined) { + state.hasAreaPopup = props.areaPopup; + state.hasSubNavigation = state.hasAreaPopup; + } else if (state.initialized && document && state.subNavigationId) { const subNavigationSlot = document?.getElementById( state.subNavigationId ) as HTMLMenuElement; @@ -55,35 +75,52 @@ export default function DBNavigationItem(props: DBNavigationItemProps) { if (children?.length > 0) { state.hasAreaPopup = true; } else { - state.hideSubNavigation = true; + state.hasSubNavigation = false; } } } - }, [state.initialized]); + }, [state.initialized, props.areaPopup]); // jscpd:ignore-end return (
  • state.handleClick(event)}> + aria-disabled={props.disabled}> - {props.children} - + {props.children} + + + + + +
    + + state.handleBackClick(event) + }> + {props.backButtonText ?? DEFAULT_BACK} + +
    +
    diff --git a/packages/components/src/components/navigation-item/navigation-item.scss b/packages/components/src/components/navigation-item/navigation-item.scss index 6b44e88340e8..3d0c013fdf9b 100644 --- a/packages/components/src/components/navigation-item/navigation-item.scss +++ b/packages/components/src/components/navigation-item/navigation-item.scss @@ -3,17 +3,84 @@ @use "@db-ui/foundations/build/scss/helpers/component" as *; @use "@db-ui/foundations/build/scss/color/color-variants" as *; @use "@db-ui/foundations/build/scss/icon/icons.helpers" as *; +@use "@db-ui/foundations/build/scss/helpers/functions" as *; +@use "@db-ui/foundations/build/scss/helpers/component" as *; +@use "@db-ui/foundations/build/scss/animation/animations" as *; +@use "@db-ui/foundations/build/scss/icon/icons.placeholder" as *; +@use "@db-ui/foundations/build/scss/icon/icons.helpers" as *; +@use "@db-ui/foundations/build/scss/icon/icons.variables" as *; +@use "../../styles/db-puls" as *; -.db-navigation-item { +%icon-passing { + // TODO: Probably we could still simplify the following two blocks of declarations + &[data-icon] { + &::before { + // don't show default icon + display: none; + } + } + + @each $icon-name, $icon-glyph in $icon-glyphs { + &[data-icon="#{$icon-name}"] { + > a, + > .db-navigation-item-expand-button:is(button), + > .db-navigation-item-expand-button > button { + &::before { + @extend %icon; + content: "#{$icon-glyph}"; + margin-inline-end: var( + --icon-margin-after, + #{$db-spacing-fixed-sm} + ); + } + } + } + } +} + +%sub-navi-handler-desktop { + // show sub-navigation on hover + @include screen("m") { + &:hover, + &:focus-visible { + & ~ .db-sub-navigation { + visibility: visible; + } + } + } +} + +@mixin sub-navi-handler-mobile() { + // show/hide sub-navigation by click + &[aria-expanded="true"] { + & ~ .db-sub-navigation { + visibility: visible; + transition: visibility 0ms linear 0ms; + animation: show-right-to-left $animation-show-timing; + + .db-sub-navigation { + inset-block: 0; + } + } + } + + &:not(&[aria-expanded="true"]) { + & ~ .db-sub-navigation { + transition: visibility 0ms linear 410ms; // hide animation is 0.4s + animation: hide-right-to-left $animation-hide-timing; + } + } +} + +%navigation-item { @extend %default-interactive-component; @extend %default-background-transition; @extend %transparent-border; @include get-variant-bg-color(0); - display: inline-flex; cursor: pointer; - - position: relative; + inline-size: 100%; + display: inline-flex; border-radius: $default-card-border-radius; padding: $db-spacing-fixed-xs $db-spacing-fixed-sm; @@ -21,11 +88,11 @@ text-align: center; align-items: center; // Centering the content vertically and horizontally - & > a { - text-decoration: none; - } - - &:hover { + &:hover, + &:focus-visible, + &:has(~ .db-sub-navigation:hover), + &:has(~ .db-sub-navigation:focus-visible), + &:has(~ .db-sub-navigation:focus-within) { @include get-variant-bg-color(0.16); } @@ -33,33 +100,163 @@ @include get-variant-bg-color(0.24); } - @media screen and (min-width: $db-screens-m) { - &:focus { - @include get-variant-bg-color(0.24); - } + &::after { + --icon-margin-before: auto; } +} + +.db-navigation-item { + @extend %db-puls; + @extend %icon-passing; + + display: inline-flex; + position: relative; + inline-size: 100%; - &::before { - margin-inline-end: $db-spacing-fixed-sm; + a { + @extend %navigation-item; + text-decoration: none; } - &::after { - margin-inline-start: $db-spacing-fixed-sm; + .db-navigation-item-expand-button { + @include screen("m", "max") { + @include sub-navi-handler-mobile(); + } + + &:is(button), + & > button { + @extend %sub-navi-handler-desktop; + @extend %navigation-item; + + // default icon for navigation + @include icon(glyph(chevron-right), 24, "outline", "after"); + + font-weight: inherit; + } } &[aria-current="page"] { font-weight: 700; } + &:not([aria-current="page"]) { + // revert for sub-navigation + font-weight: normal; + } + &[data-width="full"] { inline-size: 100%; &::after { - margin-inline-start: auto; + --icon-margin-before: auto; } } - &[data-disabled="true"] { + &[aria-disabled="true"] { opacity: $default-opacity; + pointer-events: none; + } +} + +@mixin sub-navigation-mobile() { + padding: $db-spacing-fixed-md; + inline-size: 100%; + position: fixed; + // additional #{$db-spacing-fixed-regular-3xs} for border + inset-block: calc( + #{$default-mobile-header-height} + #{$db-spacing-fixed-regular-3xs} + ) + calc( + #{$db-sizing-md} + #{$db-spacing-fixed-xs} * 2 + #{$db-spacing-fixed-regular-3xs} + ); +} + +.db-sub-navigation { + margin: 0; + display: flex; + flex-direction: column; + z-index: 70; + inset-inline-start: 0; + background-color: $db-colors-neutral-bg-0-enabled; + + visibility: hidden; + + @include screen("m", "max") { + @include sub-navigation-mobile(); + } + + @include screen("m") { + .db-mobile-navigation-back { + display: none; + } + } + + @include screen("m") { + border-radius: $default-card-border-radius; + box-shadow: $db-elevation-4; + padding: $db-spacing-fixed-sm; + + position: absolute; + min-inline-size: 328px; // We should get this value from UX + + inset-block-start: calc(100% + #{$db-spacing-fixed-md}); + + transition: visibility 1ms linear; // workaround to enable focus with keyboard + + &:hover, + &:focus-within { + visibility: visible; + } + + &::before { + content: ""; + position: absolute; + inset-inline-start: 0; + inline-size: 100%; + // #{$db-spacing-fixed-regular-3xs} for shadows + block-size: calc( + #{$db-spacing-fixed-regular-3xs} + #{$db-spacing-fixed-md} + ); + inset-block-start: calc( + -1 * #{$db-spacing-fixed-md} - #{$db-spacing-fixed-regular-3xs} + ); + } + + .db-sub-navigation { + // 1px for box shadow + inset-block-start: calc(-50% + $db-spacing-fixed-xs + 1px); + inset-inline-start: calc(100% + $db-spacing-fixed-xs); + + &::before { + content: ""; + padding: $db-spacing-fixed-xs; + // #{$db-spacing-fixed-regular-3xs} for box shadow + inset-block-start: #{$db-spacing-fixed-regular-3xs}; + inset-inline-start: calc(-1 * #{$db-spacing-fixed-xs}); + block-size: 100%; + inline-size: $db-spacing-fixed-xs; + } + } + } + + &:empty { + display: none; + } + + .db-navigation-item { + inline-size: 100%; + + &::after { + margin-inline-start: auto; + } } } + +.db-mobile-navigation-back { + @include divider("bottom"); + display: flex; + font-weight: normal; + background-color: $db-colors-neutral-bg-0-enabled; + padding-block-end: $db-spacing-fixed-md; + margin-block-end: $db-spacing-fixed-md; +} diff --git a/packages/components/src/components/page/model.ts b/packages/components/src/components/page/model.ts index 470a2b17409c..ea693de61b94 100644 --- a/packages/components/src/components/page/model.ts +++ b/packages/components/src/components/page/model.ts @@ -4,10 +4,17 @@ export interface DBPageDefaultProps { type?: 'fixedHeaderFooter'; slotHeader?: any; slotFooter?: any; + + /** + * Set this to have a transition with opacity to avoid layout-shifts https://simonhearne.com/2021/layout-shifts-webfonts/ + */ + fadeIn?: boolean; } export type DBPageProps = DBPageDefaultProps & GlobalProps; -export interface DBPageDefaultState {} +export interface DBPageDefaultState { + fontsLoaded?: boolean; +} export type DBPageState = DBPageDefaultState & GlobalState; diff --git a/packages/components/src/components/page/page.lite.tsx b/packages/components/src/components/page/page.lite.tsx index 812cb30f477f..4bbc436fe17a 100644 --- a/packages/components/src/components/page/page.lite.tsx +++ b/packages/components/src/components/page/page.lite.tsx @@ -21,12 +21,23 @@ export default function DBPage(props: DBPageProps) { // This is used as forwardRef let component: any; // jscpd:ignore-start - const state = useStore({}); + const state = useStore({ + fontsLoaded: false + }); onMount(() => { + state.fontsLoaded = !props.fadeIn; if (props.stylePath) { state.stylePath = props.stylePath; } + + if (document && props.fadeIn) { + document.fonts.ready.then(() => { + state.fontsLoaded = true; + }); + } else { + state.fontsLoaded = true; + } }); // jscpd:ignore-end @@ -35,7 +46,9 @@ export default function DBPage(props: DBPageProps) { ref={component} class={cls('db-page', props.className, { 'fixed-header-footer': props.type === 'fixedHeaderFooter' - })}> + })} + data-fade-in={props.fadeIn} + data-fonts-loaded={state.fontsLoaded}> diff --git a/packages/components/src/components/page/page.scss b/packages/components/src/components/page/page.scss index ba2191263ecc..85c284355597 100644 --- a/packages/components/src/components/page/page.scss +++ b/packages/components/src/components/page/page.scss @@ -20,6 +20,17 @@ } .db-page { + opacity: 0; + + &[data-fade-in="true"] { + transition: opacity $db-transition-emotional-straight; + } + + &:not([data-fonts-loaded]), + &[data-fonts-loaded="true"] { + opacity: 1; + } + &.fixed-header-footer { block-size: 100%; min-block-size: 100%; diff --git a/packages/components/src/components/section/section.scss b/packages/components/src/components/section/section.scss index 8015e3707d94..3a1268261eb0 100644 --- a/packages/components/src/components/section/section.scss +++ b/packages/components/src/components/section/section.scss @@ -1,11 +1,12 @@ @use "@db-ui/foundations/build/scss/variables" as *; @use "@db-ui/foundations/build/scss/variables.global" as *; @use "@db-ui/foundations/build/scss/helpers/functions" as *; +@use "@db-ui/foundations/build/scss/helpers/component" as *; .db-section { padding-inline: $db-spacing-fixed-md; - @media screen and (min-width: $db-screens-m) { + @include screen("m") { padding-inline: $db-spacing-fixed-md; } diff --git a/packages/components/src/components/select/model.ts b/packages/components/src/components/select/model.ts index 208be132c9ce..f95aa616f686 100644 --- a/packages/components/src/components/select/model.ts +++ b/packages/components/src/components/select/model.ts @@ -47,7 +47,7 @@ export type DBSelectOptionType = { /** * The main value you select, will be shown as default label if no label is set. */ - value: string | number | readonly string[]; + value: string | string[] | number; }; export type DBSelectProps = DBSelectDefaultProps & @@ -63,6 +63,7 @@ export type DBSelectProps = DBSelectDefaultProps & export interface DBSelectDefaultState { getIcon: (variant?: DefaultVariantType) => string; getOptionLabel: (option: DBSelectOptionType) => string; + _value?: any; } export type DBSelectState = DBSelectDefaultState & diff --git a/packages/components/src/components/select/select.lite.tsx b/packages/components/src/components/select/select.lite.tsx index 44f064b247dc..b987bd99b30d 100644 --- a/packages/components/src/components/select/select.lite.tsx +++ b/packages/components/src/components/select/select.lite.tsx @@ -1,4 +1,11 @@ -import { For, onMount, Show, useMetadata, useStore } from '@builder.io/mitosis'; +import { + For, + onMount, + onUpdate, + Show, + useMetadata, + useStore +} from '@builder.io/mitosis'; import { DBSelectState, DBSelectProps, DBSelectOptionType } from './model'; import { cls } from '../../utils'; import { DEFAULT_ID, DEFAULT_LABEL } from '../../shared/constants'; @@ -45,6 +52,12 @@ export default function DBSelect(props: DBSelectProps) { props.validityChange(!!event.target?.validity?.valid); } } + + // TODO: Replace this with the solution out of https://github.com/BuilderIO/mitosis/issues/833 after this has been "solved" + // VUE:this.$emit("update:value", event.target.value); + + // Angular: propagate change event to work with reactive and template driven forms + this.propagateChange(event.target.value); }, handleBlur: (event: any) => { if (props.onBlur) { @@ -69,7 +82,9 @@ export default function DBSelect(props: DBSelectProps) { }, getOptionLabel: (option: DBSelectOptionType) => { return option.label ?? option.value.toString(); - } + }, + // callback for controlValueAccessor's onChange handler + propagateChange: (_: any) => {} }); onMount(() => { @@ -83,6 +98,12 @@ export default function DBSelect(props: DBSelectProps) { state.stylePath = props.stylePath; } }); + + onUpdate(() => { + if (props.value) { + state._value = props.value; + } + }, [props.value]); // jscpd:ignore-end return ( @@ -97,15 +118,15 @@ export default function DBSelect(props: DBSelectProps) { {/* Required has to be true to use floating label */} {/* data-value is used in css to check if value is set */} + + + + + + + - - -
  • + + + + Search + + + + Profile + + + Notification + + + Help + +
    diff --git a/showcases/angular-showcase/src/app/app.component.ts b/showcases/angular-showcase/src/app/app.component.ts index 798361db46bc..0dff9e12d4ea 100644 --- a/showcases/angular-showcase/src/app/app.component.ts +++ b/showcases/angular-showcase/src/app/app.component.ts @@ -8,14 +8,19 @@ import { COLOR_CONST, TONALITY_CONST } from '../../../../packages/components/src/shared/constants'; -import { getSortedNavigationItems } from './utils/navigation-item'; +import { + getSortedNavigationItems, + NAVIGATION_ITEMS, + NavItem +} from './utils/navigation-item'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent implements OnInit { - navigationItems = getSortedNavigationItems(); + drawerOpen = false; + navigationItems: NavItem[] = getSortedNavigationItems(NAVIGATION_ITEMS); tonalities = TONALITIES; colors = COLORS; @@ -62,4 +67,8 @@ export class AppComponent implements OnInit { queryParamsHandling: 'merge' }); }; + + toggleDrawer = (open: boolean) => { + this.drawerOpen = open; + }; } diff --git a/showcases/angular-showcase/src/app/app.module.ts b/showcases/angular-showcase/src/app/app.module.ts index 581875a946d1..a9d57f3e32ce 100644 --- a/showcases/angular-showcase/src/app/app.module.ts +++ b/showcases/angular-showcase/src/app/app.module.ts @@ -21,8 +21,13 @@ import { DBDrawerModule, DBTagModule, DBNavigationItemModule, + DBMainNavigationModule, DBBadgeModule } from '../../../../output/angular/src'; +import { ActionBarDirective } from '../../../../output/angular/src/components/header/ActionBar.directive'; +import { NavigationDirective } from '../../../../output/angular/src/components/header/Navigation.directive'; +import { MetaNavigationDirective } from '../../../../output/angular/src/components/header/MetaNavigation.directive'; +import { NavigationContentDirective } from '../../../../output/angular/src/components/navigation-item/NavigationContent.directive'; import { BadgeComponent } from './components/badge/badge.component'; import { AppComponent } from './app.component'; import { AppRoutingModule } from './app.routing.module'; @@ -42,13 +47,14 @@ import { TagComponent } from './components/tag/tag.component'; import { DrawerComponent } from './components/drawer/drawer.component'; import { SelectComponent } from './components/select/select.component'; import { NavigationItemComponent } from './components/navigation-item/navigation-item.component'; +import { NavItemComponent } from './nav-item/nav-item.component'; +import { MainNavigationComponent } from './components/main-navigation/main-navigation.component'; @NgModule({ declarations: [ + MainNavigationComponent, BadgeComponent, - NavigationItemComponent, - SelectComponent, TagComponent, AppComponent, @@ -64,13 +70,17 @@ import { NavigationItemComponent } from './components/navigation-item/navigation SectionComponent, CardComponent, DividerComponent, - DrawerComponent + DrawerComponent, + ActionBarDirective, + NavigationDirective, + MetaNavigationDirective, + NavItemComponent, + NavigationContentDirective ], imports: [ DBBadgeModule, - + DBMainNavigationModule, DBNavigationItemModule, - DBTagModule, DBSelectModule, AppRoutingModule, diff --git a/showcases/angular-showcase/src/app/app.routing.module.ts b/showcases/angular-showcase/src/app/app.routing.module.ts index d8b8806292e6..8d0539a8f470 100644 --- a/showcases/angular-showcase/src/app/app.routing.module.ts +++ b/showcases/angular-showcase/src/app/app.routing.module.ts @@ -1,8 +1,8 @@ import { NgModule, NO_ERRORS_SCHEMA } from '@angular/core'; import { RouterModule } from '@angular/router'; -import { NAVIGATION_ITEMS } from './utils/navigation-item'; +import { getRoutes } from './utils/navigation-item'; -const routes: any = NAVIGATION_ITEMS; +const routes: any = getRoutes(); @NgModule({ imports: [RouterModule.forRoot(routes, { useHash: true })], diff --git a/showcases/angular-showcase/src/app/components/main-navigation/main-navigation.component.html b/showcases/angular-showcase/src/app/components/main-navigation/main-navigation.component.html new file mode 100644 index 000000000000..c053db2ed5a1 --- /dev/null +++ b/showcases/angular-showcase/src/app/components/main-navigation/main-navigation.component.html @@ -0,0 +1,61 @@ + + +
    +
    {{ exampleName }}
    + + + + Navi-Item 1 + + + + + Sub-Navi-Item 1 + + + + + Sub-Sub-Navi-Item 1 + + + + + Sub-Sub-Navi-Item 2 + + + + + + + Sub-Navi-Item 2 + + + + + + + Navi-Item 2 + + + + + Navi-Item 3 + + + +
    +
    +
    diff --git a/showcases/angular-showcase/src/app/components/main-navigation/main-navigation.component.ts b/showcases/angular-showcase/src/app/components/main-navigation/main-navigation.component.ts new file mode 100644 index 000000000000..78378a3b711d --- /dev/null +++ b/showcases/angular-showcase/src/app/components/main-navigation/main-navigation.component.ts @@ -0,0 +1,10 @@ +import { Component } from '@angular/core'; +import defaultComponentVariants from '../../../../../shared/main-navigation.json'; + +@Component({ + selector: 'app-main-navigation', + templateUrl: './main-navigation.component.html' +}) +export class MainNavigationComponent { + variants = defaultComponentVariants; +} diff --git a/showcases/angular-showcase/src/app/components/navigation-item/navigation-item.component.html b/showcases/angular-showcase/src/app/components/navigation-item/navigation-item.component.html index 3aba07792a41..4ef1c7ae17f3 100644 --- a/showcases/angular-showcase/src/app/components/navigation-item/navigation-item.component.html +++ b/showcases/angular-showcase/src/app/components/navigation-item/navigation-item.component.html @@ -12,13 +12,38 @@ > {{ exampleName }} + + {{ + exampleName + }} + {{ + exampleName + }} + + + + + + Test1 + + + + + Test2 + + + + + Test3 + + + + diff --git a/showcases/angular-showcase/src/app/nav-item/nav-item.component.html b/showcases/angular-showcase/src/app/nav-item/nav-item.component.html new file mode 100644 index 000000000000..a34c263c9b67 --- /dev/null +++ b/showcases/angular-showcase/src/app/nav-item/nav-item.component.html @@ -0,0 +1,23 @@ + + + + + + + + + {{ navItem.label }} + + {{ + navItem.label + }} + + diff --git a/showcases/angular-showcase/src/app/nav-item/nav-item.component.ts b/showcases/angular-showcase/src/app/nav-item/nav-item.component.ts new file mode 100644 index 000000000000..160da1a45b5e --- /dev/null +++ b/showcases/angular-showcase/src/app/nav-item/nav-item.component.ts @@ -0,0 +1,21 @@ +import { Router } from '@angular/router'; +import { Component, Input } from '@angular/core'; +import { NavItem } from '../utils/navigation-item'; + +@Component({ + selector: 'app-nav-item', + templateUrl: './nav-item.component.html' +}) +export class NavItemComponent { + @Input('navItem') navItem: NavItem; + constructor(private readonly router: Router) {} + + isActive = () => + this.navItem.path === '' + ? this.router.url === '/' + : this.router.url.includes(this.navItem.path); + + getBackButtonText = () => { + return `Back to ${this.navItem.label}`; + }; +} diff --git a/showcases/angular-showcase/src/app/utils/navigation-item.ts b/showcases/angular-showcase/src/app/utils/navigation-item.ts index 40f9640f1c43..696004bfe41f 100644 --- a/showcases/angular-showcase/src/app/utils/navigation-item.ts +++ b/showcases/angular-showcase/src/app/utils/navigation-item.ts @@ -1,5 +1,7 @@ +import { Routes } from '@angular/router'; import { BadgeComponent } from '../components/badge/badge.component'; import { NavigationItemComponent } from '../components/navigation-item/navigation-item.component'; +import { MainNavigationComponent } from '../components/main-navigation/main-navigation.component'; import { SelectComponent } from '../components/select/select.component'; import { TagComponent } from '../components/tag/tag.component'; import { InputComponent } from '../components/input/input.component'; @@ -15,31 +17,121 @@ import { CardComponent } from '../components/card/card.component'; import { DividerComponent } from '../components/divider/divider.component'; import { DrawerComponent } from '../components/drawer/drawer.component'; -export const NAVIGATION_ITEMS: any[] = [ - { path: 'badge', label: 'Badge', component: BadgeComponent }, +export type NavItem = { + path: string; + label: string; + component?: any; + subNavigation?: NavItem[]; +}; + +export const getSortedNavigationItems = (navigationItems: NavItem[]): any[] => + navigationItems.sort((a: NavItem, b: NavItem) => + a.path.localeCompare(b.path) + ); + +export const NAVIGATION_ITEMS: NavItem[] = [ + { + path: '06', + label: '06 Feedback', + subNavigation: getSortedNavigationItems([ + { path: '06/alert', label: 'Alert', component: AlertComponent }, + { path: '06/badge', label: 'Badge', component: BadgeComponent } + ]) + }, { - path: 'navigation-item', - label: 'NavigationItem', - component: NavigationItemComponent + path: '05', + label: '05 Navigation', + subNavigation: getSortedNavigationItems([ + { + path: '05/navigation-item', + label: 'NavigationItem', + component: NavigationItemComponent + }, + { + path: '05/main-navigation', + label: 'MainNavigation', + component: MainNavigationComponent + } + ]) }, - { path: 'divider', label: 'Divider', component: DividerComponent }, - { path: 'select', label: 'Select', component: SelectComponent }, - { path: 'radio', label: 'Radio', component: RadioComponent }, - { path: 'checkbox', label: 'Checkbox', component: CheckboxComponent }, - { path: 'alert', label: 'Alert', component: AlertComponent }, - { path: 'drawer', label: 'Drawer', component: DrawerComponent }, - { path: 'infotext', label: 'Infotext', component: InfotextComponent }, - { path: 'section', label: 'Section', component: SectionComponent }, - { path: 'link', label: 'Link', component: LinkComponent }, - { path: 'tag', label: 'Tag', component: TagComponent }, - { path: 'button', label: 'Button', component: ButtonComponent }, - { path: 'input', label: 'Input', component: InputComponent }, - { path: 'card', label: 'Card', component: CardComponent }, - { path: '', label: 'Home', component: FormComponent, pathMatch: 'full' } + { + path: '04', + label: '04 Data-Display', + subNavigation: getSortedNavigationItems([ + { + path: '04/infotext', + label: 'Infotext', + component: InfotextComponent + }, + { path: '04/tag', label: 'Tag', component: TagComponent } + ]) + }, + { + path: '03', + label: '03 Data-Input', + subNavigation: getSortedNavigationItems([ + { path: '03/input', label: 'Input', component: InputComponent }, + { path: '03/radio', label: 'Radio', component: RadioComponent }, + { + path: '03/checkbox', + label: 'Checkbox', + component: CheckboxComponent + }, + { path: '03/select', label: 'Select', component: SelectComponent } + ]) + }, + { + path: '02', + label: '02 Action', + subNavigation: getSortedNavigationItems([ + { path: '02/link', label: 'Link', component: LinkComponent }, + { path: '02/button', label: 'Button', component: ButtonComponent } + ]) + }, + { + path: '01', + label: '01 Layout', + subNavigation: getSortedNavigationItems([ + { path: '01/card', label: 'Card', component: CardComponent }, + { path: '01/drawer', label: 'Drawer', component: DrawerComponent }, + { + path: '01/divider', + label: 'Divider', + component: DividerComponent + }, + { + path: '01/section', + label: 'Section', + component: SectionComponent + } + ]) + }, + { path: '', label: 'Home', component: FormComponent } ]; -export const getSortedNavigationItems = (): any[] => - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - NAVIGATION_ITEMS.sort((a, b) => a.path.localeCompare(b.path)); +const pushRoute = (routes: Routes, item: NavItem) => { + routes.push({ + path: item.path, + component: item.component, + redirectTo: item.component ? undefined : '/', + pathMatch: 'full' + }); + + if (item.subNavigation) { + for (const subItem of item.subNavigation) { + pushRoute(routes, subItem); + } + } +}; + +export const getRoutes = (): Routes => { + const routes: Routes = []; + + for (const item of NAVIGATION_ITEMS) { + pushRoute(routes, item); + } + + return routes; +}; diff --git a/showcases/e2e/alert/showcase-alert.spec.ts b/showcases/e2e/alert/showcase-alert.spec.ts index 8456df147386..3648492d2805 100644 --- a/showcases/e2e/alert/showcase-alert.spec.ts +++ b/showcases/e2e/alert/showcase-alert.spec.ts @@ -3,5 +3,5 @@ import { test } from '@playwright/test'; import { getDefaultScreenshotTest } from '../default.ts'; test.describe('DBAlert', () => { - getDefaultScreenshotTest('alert'); + getDefaultScreenshotTest('06/alert'); }); diff --git a/showcases/e2e/badge/showcase-badge.spec.ts b/showcases/e2e/badge/showcase-badge.spec.ts index a8061c91ce61..abef1cf36007 100644 --- a/showcases/e2e/badge/showcase-badge.spec.ts +++ b/showcases/e2e/badge/showcase-badge.spec.ts @@ -3,5 +3,5 @@ import { test } from '@playwright/test'; import { getDefaultScreenshotTest } from '../default.ts'; test.describe('DBBadge', () => { - getDefaultScreenshotTest('badge'); + getDefaultScreenshotTest('06/badge'); }); diff --git a/showcases/e2e/button/showcase-button.spec.ts b/showcases/e2e/button/showcase-button.spec.ts index ae6404380c53..66dd462ebc2d 100644 --- a/showcases/e2e/button/showcase-button.spec.ts +++ b/showcases/e2e/button/showcase-button.spec.ts @@ -3,5 +3,5 @@ import { test } from '@playwright/test'; import { getDefaultScreenshotTest } from '../default.ts'; test.describe('DBButton', () => { - getDefaultScreenshotTest('button'); + getDefaultScreenshotTest('02/button'); }); diff --git a/showcases/e2e/default.ts b/showcases/e2e/default.ts index c1896b549253..91b3a0073ec2 100644 --- a/showcases/e2e/default.ts +++ b/showcases/e2e/default.ts @@ -4,7 +4,10 @@ import { COLORS, TONALITIES } from './fixtures/variants.ts'; // @ts-expect-error - required for playwright import { setScrollViewport } from './fixtures/viewport.ts'; -export const getDefaultScreenshotTest = (component: string) => { +export const getDefaultScreenshotTest = ( + path: string, + fixedHeight?: number +) => { for (const tonality of TONALITIES) { for (const color of COLORS) { test(`should match screenshot`, async ({ page }, testInfo) => { @@ -30,10 +33,10 @@ export const getDefaultScreenshotTest = (component: string) => { } await page.goto( - `./#/${component}?tonality=${tonality}&color=${color}`, + `./#/${path}?tonality=${tonality}&color=${color}`, { waitUntil: 'networkidle' } ); - await setScrollViewport(page)(); + await setScrollViewport(page, fixedHeight)(); await expect(page).toHaveScreenshot( [tonality, `${color}.png`], config diff --git a/showcases/e2e/fixtures/viewport.ts b/showcases/e2e/fixtures/viewport.ts index 197c3b6aef2e..d71cae693c41 100644 --- a/showcases/e2e/fixtures/viewport.ts +++ b/showcases/e2e/fixtures/viewport.ts @@ -1,6 +1,6 @@ import type { Page } from '@playwright/test'; -export const setScrollViewport = (page: Page) => { +export const setScrollViewport = (page: Page, fixedHeight?: number) => { return async () => { const header = await page.waitForSelector('.db-header'); const headerHeight: number = await header.evaluate((node) => @@ -13,7 +13,7 @@ export const setScrollViewport = (page: Page) => { await page.setViewportSize({ width: page.viewportSize().width, - height: headerHeight + mainHeight + height: fixedHeight ?? headerHeight + mainHeight }); }; }; diff --git a/showcases/e2e/infotext/showcase-infotext.spec.ts b/showcases/e2e/infotext/showcase-infotext.spec.ts index 9fa7ce64ece4..95e8a90c934d 100644 --- a/showcases/e2e/infotext/showcase-infotext.spec.ts +++ b/showcases/e2e/infotext/showcase-infotext.spec.ts @@ -3,5 +3,5 @@ import { test } from '@playwright/test'; import { getDefaultScreenshotTest } from '../default.ts'; test.describe('DBInfotext', () => { - getDefaultScreenshotTest('infotext'); + getDefaultScreenshotTest('04/infotext'); }); diff --git a/showcases/e2e/input/showcase-input.spec.ts b/showcases/e2e/input/showcase-input.spec.ts index e0bc26329182..f0ff01ead856 100644 --- a/showcases/e2e/input/showcase-input.spec.ts +++ b/showcases/e2e/input/showcase-input.spec.ts @@ -3,5 +3,5 @@ import { test } from '@playwright/test'; import { getDefaultScreenshotTest } from '../default.ts'; test.describe('DBInput', () => { - getDefaultScreenshotTest('input'); + getDefaultScreenshotTest('03/input'); }); diff --git a/showcases/e2e/link/showcase-link.spec.ts b/showcases/e2e/link/showcase-link.spec.ts index dce20a74deb8..112a7a39087d 100644 --- a/showcases/e2e/link/showcase-link.spec.ts +++ b/showcases/e2e/link/showcase-link.spec.ts @@ -3,5 +3,5 @@ import { test } from '@playwright/test'; import { getDefaultScreenshotTest } from '../default.ts'; test.describe('DBLink', () => { - getDefaultScreenshotTest('link'); + getDefaultScreenshotTest('02/link'); }); diff --git a/showcases/e2e/navigation-item/showcase-navigation-item.spec.ts b/showcases/e2e/navigation-item/showcase-navigation-item.spec.ts index 76f63d70db11..21a0aa7b90c9 100644 --- a/showcases/e2e/navigation-item/showcase-navigation-item.spec.ts +++ b/showcases/e2e/navigation-item/showcase-navigation-item.spec.ts @@ -3,5 +3,6 @@ import { test } from '@playwright/test'; import { getDefaultScreenshotTest } from '../default.ts'; test.describe('DBNavigationItem', () => { - getDefaultScreenshotTest('navigation-item'); + // Set fixed height, because of issues with angulars `ngAfterContentInit` + getDefaultScreenshotTest('05/navigation-item', 1800); }); diff --git a/showcases/e2e/section/showcase-section.spec.ts b/showcases/e2e/section/showcase-section.spec.ts index 294c3e60c171..e88e25ce245d 100644 --- a/showcases/e2e/section/showcase-section.spec.ts +++ b/showcases/e2e/section/showcase-section.spec.ts @@ -3,5 +3,5 @@ import { test } from '@playwright/test'; import { getDefaultScreenshotTest } from '../default.ts'; test.describe('DBSection', () => { - getDefaultScreenshotTest('section'); + getDefaultScreenshotTest('01/section'); }); diff --git a/showcases/patternhub/.gitignore b/showcases/patternhub/.gitignore index c31e0b2681ea..afa05f337081 100644 --- a/showcases/patternhub/.gitignore +++ b/showcases/patternhub/.gitignore @@ -38,7 +38,9 @@ public/docs styles/db-ui-components.scss scripts/generated -components +pages/components/ +components/src +!pages/components/readme.mdx !components/src/tsconfig.json !components/component-parser !components/default-page.tsx diff --git a/showcases/patternhub/components/component-parser/data.ts b/showcases/patternhub/components/component-parser/data.ts index 151ce0373143..816fb4b4b445 100644 --- a/showcases/patternhub/components/component-parser/data.ts +++ b/showcases/patternhub/components/component-parser/data.ts @@ -4,8 +4,9 @@ export type ComponentParserType = { export type ComponentType = { index?: string | number; - type?: /* hygen type */ - | 'badge' + type?: /* Template hygen type */ + | 'main-navigation' + | 'badge' | 'navigation-item' | 'tag' | 'select' diff --git a/showcases/patternhub/components/component-parser/index.tsx b/showcases/patternhub/components/component-parser/index.tsx index 24248f0c9107..bf92d5681866 100644 --- a/showcases/patternhub/components/component-parser/index.tsx +++ b/showcases/patternhub/components/component-parser/index.tsx @@ -1,27 +1,27 @@ import { useEffect, useState } from 'react'; -import DBBadge from '../src/components/badge/badge'; - import { - DBInfotext, + DBAlert, + DBBrand, DBButton, + DBCard, + DBCheckbox, + DBDivider, + DBHeader, DBIcon, - DBLink, - DBAlert, + DBInfotext, DBInput, - DBSelect, - DBCheckbox, - DBTag, + DBLink, + DBBadge, + DBMainNavigation, + DBNavigationItem, DBRadio, - DBDivider, - DBCard, - DBBrand, DBSection, - DBHeader, - DBNavigationItem + DBSelect, + DBTag } from '../src'; -import { ComponentParserType, ComponentType } from './data'; +import type { ComponentParserType, ComponentType } from './data'; -const validHosts = ['marketingportal.extranet.deutschebahn.com']; +const validHosts = new Set(['marketingportal.extranet.deutschebahn.com']); const ComponentSwitch = ({ type, @@ -30,54 +30,58 @@ const ComponentSwitch = ({ props, className }: ComponentType) => { - const resolvedContent = - content instanceof Array - ? content.map( - (innerComponent: ComponentType, innerIndex: number) => ( - - ) - ) - : content; + const resolvedContent = Array.isArray(content) + ? content.map((innerComponent: ComponentType, innerIndex: number) => ( + + )) + : content; if (type === 'h1') { return

    {resolvedContent}

    ; } + if (type === 'h2') { return

    {resolvedContent}

    ; } + if (type === 'h3') { return

    {resolvedContent}

    ; } + if (type === 'h4') { return

    {resolvedContent}

    ; } + if (type === 'p') { return

    {resolvedContent}

    ; } + if (type === 'div') { return
    {resolvedContent}
    ; } + if (type === 'flex') { return (
    {resolvedContent}
    ); } + if (type === 'a') { try { const url = new URL('', props.href); const host = url.host; - if (validHosts.includes(host)) { + if (validHosts.has(host)) { return ( ); } - } catch (e) { - console.error(e); + } catch (error: unknown) { + console.error(error); } } + if (type === 'alert') { return ( @@ -98,6 +103,7 @@ const ComponentSwitch = ({ ); } + if (type === 'brand') { return ( @@ -105,6 +111,7 @@ const ComponentSwitch = ({ ); } + if (type === 'button') { return ( @@ -112,6 +119,7 @@ const ComponentSwitch = ({ ); } + if (type === 'card') { return ( @@ -119,6 +127,7 @@ const ComponentSwitch = ({ ); } + if (type === 'divider') { return ( @@ -126,6 +135,7 @@ const ComponentSwitch = ({ ); } + if (type === 'header') { return ( @@ -133,6 +143,7 @@ const ComponentSwitch = ({ ); } + if (type === 'icon') { return ( @@ -140,6 +151,7 @@ const ComponentSwitch = ({ ); } + if (type === 'infotext') { return ( @@ -147,6 +159,7 @@ const ComponentSwitch = ({ ); } + if (type === 'input') { return ( @@ -154,6 +167,7 @@ const ComponentSwitch = ({ ); } + if (type === 'checkbox') { return ( @@ -161,6 +175,7 @@ const ComponentSwitch = ({ ); } + if (type === 'radio') { return ( @@ -168,6 +183,7 @@ const ComponentSwitch = ({ ); } + if (type === 'link') { return ( @@ -175,6 +191,7 @@ const ComponentSwitch = ({ ); } + if (type === 'section') { return ( @@ -207,6 +224,14 @@ const ComponentSwitch = ({ ); } + if (type === 'main-navigation') { + return ( + + {resolvedContent} + + ); + } + if (type === 'badge') { return ( @@ -215,7 +240,7 @@ const ComponentSwitch = ({ ); } - // hygen before + // Template hygen before return {resolvedContent}; }; @@ -226,12 +251,12 @@ const ComponentParser = ({ componentsString }: ComponentParserType) => { useEffect(() => { try { setComponents(JSON.parse(componentsString)); - } catch (e) { - console.error(e); + } catch (error: unknown) { + console.error(error); } }, [componentsString]); - if (components && components instanceof Array) { + if (components && Array.isArray(components)) { return ( <> {components.map((component: ComponentType, index: number) => { diff --git a/showcases/patternhub/components/data.ts b/showcases/patternhub/components/data.ts index 1911acae514c..f7548fb2196e 100644 --- a/showcases/patternhub/components/data.ts +++ b/showcases/patternhub/components/data.ts @@ -1,5 +1,8 @@ -import type { DefaultComponentVariants } from '../../shared/default-component-data'; -import { ReactElement } from 'react'; +import type { ReactElement } from 'react'; +import type { + DefaultComponentExample, + DefaultComponentVariants +} from '../../shared/default-component-data'; export const getVariants = ( defaultComponentVariants: DefaultComponentVariants[], @@ -9,14 +12,12 @@ export const getVariants = ( return defaultComponentVariants.map((variant, index) => ({ ...variant, slotCode: codeSlots?.at(index) ?? 'No code available', - examples: variant.examples.map((example: any) => ({ + examples: variant.examples.map((example: DefaultComponentExample) => ({ ...example, example: getExample({ ...example.props, id: example.props.id ?? example.name, - children: example.props?.children - ? example.props.children - : example.name + children: example.props.children ?? example.name }) })) })); diff --git a/showcases/patternhub/components/default-page.tsx b/showcases/patternhub/components/default-page.tsx index 6dbd170b3aed..967c74aeca60 100644 --- a/showcases/patternhub/components/default-page.tsx +++ b/showcases/patternhub/components/default-page.tsx @@ -1,44 +1,20 @@ -// TODO: Import @db-ui/react-components after those have been migrated -import { - DbBrand, - DbFooter, - DbHeader, - DbMainnavigation, - DbPage, - GithubVersionSwitcher -} from '@db-ui/react-elements'; -import StaticContent from './static-content'; -import { getRouteWithBasePath, ROUTES } from '../data/routes'; -import '@db-ui/core/dist/css/db-ui-core.vars.css'; import { useRouter } from 'next/router'; -import { DbMainnavigationDataType } from '@db-ui/elements/dist/types/components/db-mainnavigation/db-mainnavigation-type'; import { useEffect, useState } from 'react'; - -const getRoutesWithCurrent = ( - routes: DbMainnavigationDataType[], - pathname: string -): DbMainnavigationDataType[] => { - if (!routes) { - return []; - } - - return routes - .map((route) => ({ - ...route, - current: - (route.link === '/' && pathname === '/') || - (route.link !== '/' && pathname.includes(route.link)), - children: route.children - ? getRoutesWithCurrent(route.children, pathname) - : [] - })) - .map((route) => getRouteWithBasePath(route)); -}; +import { + DBBrand, + DBButton, + DBHeader, + DBPage, + DBSection +} from '../../../output/react/src'; +import StaticContent from './static-content'; +import Navigation from './navigation'; const DefaultPage = ({ children }: any) => { const [fullscreen, setFullscreen] = useState(false); const [noH1, setNoH1] = useState(false); const [properties, setProperties] = useState(false); + const [drawerOpen, setDrawerOpen] = useState(false); const router = useRouter(); useEffect(() => { @@ -60,29 +36,60 @@ const DefaultPage = ({ children }: any) => {
    )} {router.isReady && !fullscreen && ( - - - {/* TODO: provide correct https://db-ui.github.io/mono/* path later on in here */} - - {process.env.NEXT_PUBLIC_APP_NAME} - - - {process.env.NEXT_PUBLIC_GITHUB_VERSION_SWITCHER === - 'true' && ( - - )} - -
    {children}
    - - -
    + + {process.env.NEXT_PUBLIC_APP_NAME} + + } + slotMetaNavigation={ + <> + /* TODO: Add github version switcher */ +
    Link1 + Link2 + Link3 + + } + slotCallToAction={ + /* TODO: Use DBSearchBar in future */ + + Search + + } + slotActionBar={ + <> + + Profile + + + Notification + + + Help + + + }> + +
    + }> + {children} + )} ); diff --git a/showcases/patternhub/components/index.tsx b/showcases/patternhub/components/index.tsx index 167ca53642f0..f5a847b23ff2 100644 --- a/showcases/patternhub/components/index.tsx +++ b/showcases/patternhub/components/index.tsx @@ -1,11 +1,11 @@ -import { DBCodeDocs, DBDivider, DBLink } from './src'; +import { useRouter } from 'next/router'; +import { useEffect, useState } from 'react'; import type { DefaultComponentProps, DefaultComponentVariants } from '../../shared/default-component-data'; -import { useRouter } from 'next/router'; import DefaultPage from './default-page'; -import { useEffect, useState } from 'react'; +import { DBCodeDocs, DBDivider, DBLink } from './src'; const VariantList = ({ examples, slotCode }: DefaultComponentVariants) => ( @@ -35,7 +35,6 @@ const DefaultComponent = ({ title, variants }: DefaultComponentProps) => { (variant) => variant.name.toLowerCase() === pageName ); setFoundVariant(foundVariant); - console.log(pageName); } } }, [router]); diff --git a/showcases/patternhub/components/navigation/index.tsx b/showcases/patternhub/components/navigation/index.tsx new file mode 100644 index 000000000000..a929c1c2bdb6 --- /dev/null +++ b/showcases/patternhub/components/navigation/index.tsx @@ -0,0 +1,13 @@ +import { DBMainNavigation } from '../../../../output/react/src'; +import { ROUTES, type NavigationItem } from '../../data/routes'; +import NavItem from './nav-item'; + +const Navigation = () => ( + + {ROUTES.map((navItem: NavigationItem) => ( + + ))} + +); + +export default Navigation; diff --git a/showcases/patternhub/components/navigation/nav-item.tsx b/showcases/patternhub/components/navigation/nav-item.tsx new file mode 100644 index 000000000000..a4987237439e --- /dev/null +++ b/showcases/patternhub/components/navigation/nav-item.tsx @@ -0,0 +1,60 @@ +import { useRouter } from 'next/router'; +import Link from 'next/link'; +import { DBNavigationItem } from '../../../../output/react/src'; +import type { NavigationItem } from '../../data/routes'; + +const NavItem = ({ navItem }: { navItem: NavigationItem }) => { + const router = useRouter(); + + const isActive = + navItem.path === '/' + ? router.pathname === '/' + : router.pathname.includes(navItem.path ?? '') || + Boolean( + navItem.subNavigation?.find((subItem) => + router.pathname.includes(subItem.path ?? '') + ) + ) || + Boolean( + navItem.subNavigation?.find((subItem) => + subItem.subNavigation?.find( + (subSubItem) => + router.pathname.includes( + subSubItem.path ?? '' + ) && + router.pathname.includes(navItem.path ?? '') + ) + ) + ); + + return ( + + {navItem?.subNavigation.map( + (subItem: NavigationItem) => ( + + ) + )} + + ) + }> + {navItem.subNavigation ? ( + navItem.label + ) : ( + + {navItem.label} + + )} + + ); +}; + +export default NavItem; diff --git a/showcases/patternhub/components/static-content.tsx b/showcases/patternhub/components/static-content.tsx index 691896360e44..6f5423745952 100644 --- a/showcases/patternhub/components/static-content.tsx +++ b/showcases/patternhub/components/static-content.tsx @@ -5,8 +5,8 @@ const useStaticContent = () => { const [render, setRender] = useState(typeof window === 'undefined'); useEffect(() => { - // check if the innerHTML is empty as client side navigation - // need to render the component without server-side backup + // Check if the innerHTML is empty as client side navigation + // Need to render the component without server-side backup const isEmpty = (ref?.current as any)?.innerHTML === ''; if (isEmpty) { setRender(true); @@ -19,7 +19,7 @@ const useStaticContent = () => { const StaticContent = ({ children, element = 'div', ...props }: any) => { const [render, ref] = useStaticContent(); - // if we're in the server or a spa navigation, just render it + // If we're in the server or a spa navigation, just render it if (render) { return createElement(element, { ...props, @@ -27,7 +27,7 @@ const StaticContent = ({ children, element = 'div', ...props }: any) => { }); } - // avoid re-render on the client + // Avoid re-render on the client return createElement(element, { ...props, ref, diff --git a/showcases/patternhub/data/routes.ts b/showcases/patternhub/data/routes.ts index 43dc5c4cbe38..35925f99e190 100644 --- a/showcases/patternhub/data/routes.ts +++ b/showcases/patternhub/data/routes.ts @@ -1,54 +1,55 @@ -import type { DbMainnavigationDataType } from '@db-ui/elements/dist/types/components/db-mainnavigation/db-mainnavigation-type'; +export type NavigationItem = { + label: string; + name?: string; + path?: string; + subNavigation?: NavigationItem[]; +}; -const componentChildren = [ +const componentChildren: NavigationItem[] = [ { - label: '01 Layout', - link: '/components/01-layout', - children: [ + label: 'Action', + path: '/components/action', + subNavigation: [ { - label: 'DBCard', - name: 'card' + label: 'DBButton', + name: 'button' }, { - label: 'DBDivider', - name: 'divider' - }, + label: 'DBLink', + name: 'link' + } + ] + }, + { + label: 'Data-Display', + path: '/components/data-display', + subNavigation: [ { - label: 'DBDrawer', - name: 'drawer' + label: 'DBBrand', + name: 'brand' }, { - label: 'DBHeader', - name: 'header' + label: 'DBIcon', + name: 'icon' }, { - label: 'DBPage', - name: 'page' + label: 'DBInfotext', + name: 'infotext' }, { - label: 'DBSection', - name: 'section' + label: 'DBTag', + name: 'tag' } ] }, { - label: '02 Action', - link: '/components/02-action', - children: [ + label: 'Data-Input', + path: '/components/data-input', + subNavigation: [ { - label: 'DBButton', - name: 'button' + label: 'DBCheckbox', + name: 'checkbox' }, - { - label: 'DBLink', - name: 'link' - } - ] - }, - { - label: '03 Data-Input', - link: '/components/03-data-input', - children: [ { label: 'DBInput', name: 'input' @@ -57,10 +58,6 @@ const componentChildren = [ label: 'DBRadio', name: 'radio' }, - { - label: 'DBCheckbox', - name: 'checkbox' - }, { label: 'DBSelect', name: 'select' @@ -68,105 +65,119 @@ const componentChildren = [ ] }, { - label: '04 Data-Display', - link: '/components/04-data-display', - children: [ + label: 'Feedback', + path: '/components/feedback', + subNavigation: [ { - label: 'DBBrand', - name: 'brand' - }, - { - label: 'DBIcon', - name: 'icon' - }, - { - label: 'DBInfotext', - name: 'infotext' + label: 'DBAlert', + name: 'alert' }, { - label: 'DBTag', - name: 'tag' + label: 'DBBadge', + name: 'badge' } ] }, { - label: '05 Navigation', - link: '/components/05-navigation', - children: [ + label: 'Layout', + path: '/components/layout', + subNavigation: [ { - label: 'DBNavigationItem', - name: 'navigation-item' + label: 'DBCard', + name: 'card' + }, + { + label: 'DBDivider', + name: 'divider' + }, + { + label: 'DBDrawer', + name: 'drawer' + }, + { + label: 'DBHeader', + name: 'header' + }, + { + label: 'DBPage', + name: 'page' + }, + { + label: 'DBSection', + name: 'section' } ] }, { - label: '06 Feedback', - link: '/components/06-feedback', - children: [ + label: 'Navigation', + path: '/components/navigation', + subNavigation: [ { - label: 'DBAlert', - name: 'alert' + label: 'DBMainNavigation', + name: 'main-navigation' }, { - label: 'DBBadge', - name: 'badge' + label: 'DBNavigationItem', + name: 'navigation-item' } ] } ]; -export const ROUTES: DbMainnavigationDataType[] = [ +export const ROUTES: NavigationItem[] = [ { label: 'Home', - link: '/' + path: '/' }, { label: 'Foundations', - link: '/foundations', - children: [ + path: '/foundations', + subNavigation: [ + { label: 'Readme', path: '/foundations/readme' }, { label: 'Colors', - link: '/foundations/colors', - children: [ - { label: 'Examples', link: '/foundations/colors/examples' } + path: '/foundations/colors', + subNavigation: [ + { label: 'Readme', path: '/foundations/colors/readme' }, + { label: 'Examples', path: '/foundations/colors/examples' } ] }, - { label: 'Icons', link: '/foundations/icons' } + { label: 'Icons', path: '/foundations/icons' } ] }, { label: 'Components', - link: '/components', - children: componentChildren.map((category) => ({ - ...category, - children: category.children.map((component) => ({ - label: component.label, - link: `/components/${component.name}`, - children: [ - { - label: 'Properties', - link: `/components/${component.name}/properties` - }, - { - label: 'Examples', - link: `/components/${component.name}/examples` - }, - { - label: 'How to use', - link: `/components/${component.name}/how-to-use` - }, - { - label: 'Migration', - link: `/components/${component.name}/migration` - } - ] + path: '/components', + subNavigation: [ + { label: 'Readme', path: '/components/readme' }, + ...componentChildren.map((category) => ({ + ...category, + subNavigation: category?.subNavigation?.map((component) => ({ + label: component.label, + path: `/components/${component.name}`, + subNavigation: [ + { + label: 'Overview', + path: `/components/${component.name}/overview` + }, + { + label: 'Properties', + path: `/components/${component.name}/properties` + }, + { + label: 'Examples', + path: `/components/${component.name}/examples` + }, + { + label: 'How to use', + path: `/components/${component.name}/how-to-use` + }, + { + label: 'Migration', + path: `/components/${component.name}/migration` + } + ] + })) })) - })) + ] } ]; - -export const getRouteWithBasePath = (route: DbMainnavigationDataType) => { - return { - ...route, - link: `${process.env.NEXT_PUBLIC_BASE_PATH ?? ''}${route.link}` - }; -}; diff --git a/showcases/patternhub/package.json b/showcases/patternhub/package.json index 01e417bd3c85..41fb49d97568 100644 --- a/showcases/patternhub/package.json +++ b/showcases/patternhub/package.json @@ -10,7 +10,8 @@ "copy": "npm-run-all copy:*", "copy:components": "cpr ../../output/react/src ./components/src -o", "copy:docs": "cpr ../../docs ./public/docs -o", - "dev": "npm-run-all generate copy next:dev", + "open": "open-cli http://localhost:3000/mono/sub", + "dev": "cross-env NEXT_PUBLIC_BASE_PATH=/mono/sub npm-run-all generate copy -p open next:dev", "generate": "npm-run-all generate:*", "generate:jsx": "node --experimental-specifier-resolution=node scripts/generate-example-jsx.js", "generate:parse-jsx": "babel scripts/generated --out-dir scripts/generated --extensions \".jsx\" --presets=@babel/preset-react", @@ -19,11 +20,10 @@ "next:start": "next start", "postcopy:components": "tsc -p ./components/src --sourceMap false && node --experimental-specifier-resolution=node scripts/generate-docs-mdx.js", "prebuild:app": "cpr ../../node_modules/iframe-resizer/js/ public/iframe-resizer -o", - "start": "npm-run-all generate copy next:start" + "start": "cross-env NEXT_PUBLIC_BASE_PATH=/mono/sub npm-run-all generate copy next:start" }, "dependencies": { "@code-hike/mdx": "^0.9.0", - "@db-ui/react-elements": "^0.24.6", "next": "13.4.16", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/showcases/patternhub/pages/components/01-layout.mdx b/showcases/patternhub/pages/components/01-layout.mdx deleted file mode 100644 index 637b2db79ed1..000000000000 --- a/showcases/patternhub/pages/components/01-layout.mdx +++ /dev/null @@ -1,7 +0,0 @@ -import DefaultPage from "../../components/default-page"; - -# 01 Layout - -TODO: Add docs for layout - -export default ({ children }) => {children}; diff --git a/showcases/patternhub/pages/components/02-action.mdx b/showcases/patternhub/pages/components/02-action.mdx deleted file mode 100644 index 6ce592cd6e04..000000000000 --- a/showcases/patternhub/pages/components/02-action.mdx +++ /dev/null @@ -1,7 +0,0 @@ -import DefaultPage from "../../components/default-page"; - -# 02 Action - -TODO: Add docs for action - -export default ({ children }) => {children}; diff --git a/showcases/patternhub/pages/components/03-data-input.mdx b/showcases/patternhub/pages/components/03-data-input.mdx deleted file mode 100644 index 85e480f6860c..000000000000 --- a/showcases/patternhub/pages/components/03-data-input.mdx +++ /dev/null @@ -1,7 +0,0 @@ -import DefaultPage from "../../components/default-page"; - -# 03 Data Input - -TODO: Add docs for data-input - -export default ({ children }) => {children}; diff --git a/showcases/patternhub/pages/components/04-data-display.mdx b/showcases/patternhub/pages/components/04-data-display.mdx deleted file mode 100644 index 3989d52808ea..000000000000 --- a/showcases/patternhub/pages/components/04-data-display.mdx +++ /dev/null @@ -1,7 +0,0 @@ -import DefaultPage from "../../components/default-page"; - -# 04 Data Display - -TODO: Add docs for data-display - -export default ({ children }) => {children}; diff --git a/showcases/patternhub/pages/components/06-feedback.mdx b/showcases/patternhub/pages/components/06-feedback.mdx deleted file mode 100644 index 7975c308a010..000000000000 --- a/showcases/patternhub/pages/components/06-feedback.mdx +++ /dev/null @@ -1,7 +0,0 @@ -import DefaultPage from "../../components/default-page"; - -# 06 Feedback - -TODO: Add docs for feedback - -export default ({ children }) => {children}; diff --git a/showcases/patternhub/pages/components/index.mdx b/showcases/patternhub/pages/components/readme.mdx similarity index 100% rename from showcases/patternhub/pages/components/index.mdx rename to showcases/patternhub/pages/components/readme.mdx diff --git a/showcases/patternhub/pages/foundations/colors/index.mdx b/showcases/patternhub/pages/foundations/colors/readme.mdx similarity index 100% rename from showcases/patternhub/pages/foundations/colors/index.mdx rename to showcases/patternhub/pages/foundations/colors/readme.mdx diff --git a/showcases/patternhub/pages/foundations/index.mdx b/showcases/patternhub/pages/foundations/readme.mdx similarity index 100% rename from showcases/patternhub/pages/foundations/index.mdx rename to showcases/patternhub/pages/foundations/readme.mdx diff --git a/showcases/patternhub/scripts/generate-docs-mdx.js b/showcases/patternhub/scripts/generate-docs-mdx.js index 76bad98cc513..7524c18b455f 100644 --- a/showcases/patternhub/scripts/generate-docs-mdx.js +++ b/showcases/patternhub/scripts/generate-docs-mdx.js @@ -60,7 +60,10 @@ const generateDocsMdx = async () => { componentName ); if (reactComponent) { - FS.writeFileSync(`${componentPath}/index.tsx`, reactComponent); + FS.writeFileSync( + `${componentPath}/overview.tsx`, + reactComponent + ); } } } diff --git a/showcases/patternhub/scripts/get-example-file.js b/showcases/patternhub/scripts/get-example-file.js index ecee0b1457d2..f155f86e1601 100644 --- a/showcases/patternhub/scripts/get-example-file.js +++ b/showcases/patternhub/scripts/get-example-file.js @@ -57,11 +57,15 @@ const getOption = (optionName, tsType) => { return `${optionName}={(event) => console.log(event)}`; } + if (tsType.name === 'signature' && tsType.raw === '() => void') { + return `${optionName}={() => console.log("${optionName} triggered")}`; + } + if ( tsType.name === 'signature' && - tsType.raw === '(valid: boolean) => void' + tsType.raw.includes('boolean) => void') ) { - return `${optionName}={(valid) => console.log(valid)}`; + return `${optionName}={(event) => console.log(event)}`; } if (tsType.name === 'signature' && tsType.type === 'object') { @@ -78,6 +82,10 @@ const getOption = (optionName, tsType) => { return `${optionName}="https://db-ui.github.io/images/db_logo.svg"`; } + if (optionName.toLowerCase().startsWith('slot')) { + return `${optionName}={
    ${optionName}
    }`; + } + return `${optionName}="account"`; }; @@ -90,6 +98,8 @@ const getExampleFile = (componentName, { displayName, props }) => { let variants = ''; const optionArrays = []; + const isDialog = ['drawer'].includes(componentName); + const propKeys = Object.keys(props).filter( (key) => key !== 'className' && key !== 'children' && key !== 'stylePath' @@ -121,26 +131,46 @@ const getExampleFile = (componentName, { displayName, props }) => { } } - for (const optionArray of uniqueOptionArrays) { - variants += `
    ${optionArray.join( - ', ' - )}:
    <${displayName} ${optionArray + for (const [index, optionArray] of uniqueOptionArrays + .filter( + (optionArray) => + !optionArray.includes('open') && + !optionArray.includes('onClose') + ) + .entries()) { + variants += `
    ${optionArray.join(', ')}:
    ${ + isDialog + ? `{setDialog(${index})}}>Open Dialog` + : '' + }
    <${displayName} ${ + isDialog + ? `open={dialog===${index}} onClose={()=>setDialog(-1)}` + : '' + } ${optionArray .map((opt) => getOption(opt, props[opt].tsType)) .join(' ')}>Test
    \n`; } return ` +${ + isDialog + ? 'import { useState } from "react";\nimport DBButton from "../../../components/src/components/button/button";' + : '' +} import DefaultPage from "../../../components/default-page"; import ${displayName} from "../../../components/src/components/${componentName}/${componentName}"; -export default () => + +export default () => { +${isDialog ? 'const [dialog, setDialog] = useState(-1);' : ''} +return (

    ${displayName} Examples

    -
    Default:
    <${displayName}>Test
    ${variants}
    -
    ; +
    ); +} `; }; diff --git a/showcases/react-showcase/src/app.tsx b/showcases/react-showcase/src/app.tsx index c7e3d854d05c..7aaa4ebd5556 100644 --- a/showcases/react-showcase/src/app.tsx +++ b/showcases/react-showcase/src/app.tsx @@ -1,22 +1,16 @@ -import type { ChangeEvent } from 'react'; -import { Link, Outlet } from 'react-router-dom'; -import { - DBBrand, - DBHeader, - DBPage, - DBNavigationItem -} from '../../../output/react/src'; -import { - COLORS, - TONALITIES -} from '../../../packages/components/src/shared/constants'; -import { getSortedNavigationItems } from './utils/navigation-item'; +import { useState } from 'react'; +import { Outlet } from 'react-router-dom'; +import { DBBrand, DBButton, DBHeader, DBPage } from '../../../output/react/src'; import useQuery from './hooks/use-query'; +import MetaNavigation from './meta-navigation'; +import Navigation from './navigation'; const App = () => { const [tonality, setTonality, color, setColor, pageName, fullscreen] = useQuery(); + const [drawerOpen, setDrawerOpen] = useState(false); + if (pageName || fullscreen) { return (
    @@ -27,64 +21,45 @@ const App = () => { return ( Showcase } - slotDesktopNavigation={ - - } slotMetaNavigation={ -
    - - -
    + + } + slotCallToAction={ + /* TODO: Use DBSearchBar in future */ + + Search + } - /> + slotActionBar={ + <> + + Profile + + + Notification + + + Help + + + }> + + }>
    diff --git a/showcases/react-showcase/src/components/divider/index.tsx b/showcases/react-showcase/src/components/divider/index.tsx index 143a6d922785..780eea023df8 100644 --- a/showcases/react-showcase/src/components/divider/index.tsx +++ b/showcases/react-showcase/src/components/divider/index.tsx @@ -7,7 +7,6 @@ import { getVariants } from '../data'; const getDivider = ({ variant, children }: DBDividerProps) => ( <> - {' '} {children} diff --git a/showcases/react-showcase/src/components/main-navigation/index.tsx b/showcases/react-showcase/src/components/main-navigation/index.tsx new file mode 100644 index 000000000000..0be1c522a242 --- /dev/null +++ b/showcases/react-showcase/src/components/main-navigation/index.tsx @@ -0,0 +1,60 @@ +import { + DBMainNavigation, + DBNavigationItem +} from '../../../../../output/react/src'; +import DefaultComponent from '../index'; +import defaultComponentVariants from '../../../../shared/main-navigation.json'; +import type { DBMainNavigationProps } from '../../../../../output/react/src/components/main-navigation/model'; +import { getVariants } from '../data'; + +const getMainNavigation = ({ children }: DBMainNavigationProps) => ( +
    +
    {children}:
    + + + + + Sub-Sub-Navi-Item 1 + + + Sub-Sub-Navi-Item 2 + + + }> + Sub-Navi-Item 1 + + + Sub-Navi-Item 2 + + + }> + Navi-Item 1 + + + Navi-Item 2 + + + Navi-Item 3 + + +
    +); + +const MainNavigationComponent = () => { + return ( + + ); +}; + +export default MainNavigationComponent; diff --git a/showcases/react-showcase/src/components/navigation-item/index.tsx b/showcases/react-showcase/src/components/navigation-item/index.tsx index 57a13550f3c0..094e4a41d8e6 100644 --- a/showcases/react-showcase/src/components/navigation-item/index.tsx +++ b/showcases/react-showcase/src/components/navigation-item/index.tsx @@ -7,22 +7,34 @@ import { getVariants } from '../data'; const getNavigationItem = ({ children, icon, - iconAfter, disabled, active, - width + width, + areaPopup }: DBNavigationItemProps) => ( { // eslint-disable-next-line no-alert alert(children.toString()); - }}> - {children} + }} + slotSubNavigation={ + areaPopup && ( + <> + + Test1 + + + Test2 + + + ) + }> + {areaPopup ? children : {children}} ); diff --git a/showcases/react-showcase/src/main.tsx b/showcases/react-showcase/src/main.tsx index d01aafe94afc..8fbdf2e6cdd1 100644 --- a/showcases/react-showcase/src/main.tsx +++ b/showcases/react-showcase/src/main.tsx @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom/client'; import { HashRouter, Navigate, Route, Routes } from 'react-router-dom'; import './index.scss'; import App from './app'; -import { NAVIGATION_ITEMS } from './utils/navigation-item'; +import { NAVIGATION_ITEMS, NavigationItem } from './utils/navigation-item'; ReactDOM.createRoot(document.querySelector('#root')!).render( @@ -14,8 +14,17 @@ ReactDOM.createRoot(document.querySelector('#root')!).render( + element={navItem.component}> + {navItem.subNavigation + ? navItem.subNavigation.map((subItem) => ( + + )) + : null} + ))} } /> diff --git a/showcases/react-showcase/src/meta-navigation/index.tsx b/showcases/react-showcase/src/meta-navigation/index.tsx new file mode 100644 index 000000000000..7e099bcb1bfd --- /dev/null +++ b/showcases/react-showcase/src/meta-navigation/index.tsx @@ -0,0 +1,80 @@ +import { useEffect, useState } from 'react'; +import { useSearchParams } from 'react-router-dom'; +import { + COLOR, + COLORS, + TONALITIES, + TONALITY, + COLOR_CONST, + TONALITY_CONST +} from '../../../../packages/components/src/shared/constants'; +import { DBSelect } from '../../../../output/react/src'; + +export type MetaNavigationProps = { + onTonalityChange: (tonality: string) => void; + onColorChange: (color: string) => void; +}; + +const MetaNavigation = ({ + onTonalityChange, + onColorChange +}: MetaNavigationProps) => { + const [searchParameters, setSearchParameters] = useSearchParams(); + const [tonality, setTonality] = useState( + searchParameters.get(TONALITY_CONST) ?? TONALITY.REGULAR + ); + const [color, setColor] = useState( + searchParameters.get(COLOR_CONST) ?? COLOR.NEUTRAL_0 + ); + + useEffect(() => { + for (const [key, value] of searchParameters.entries()) { + if (value) { + if (key === TONALITY_CONST && tonality !== value) { + setTonality(value); + onTonalityChange(value); + } + + if (key === COLOR_CONST && color !== value) { + setColor(value); + onColorChange(value); + } + } + } + }, [searchParameters]); + + useEffect(() => { + setSearchParameters({ tonality, color }); + }, [color, tonality]); + + return ( + <> + { + setTonality(event?.target?.value); + }}> + {TONALITIES.map((ton) => ( + + ))} + + { + setColor(event?.target?.value); + }}> + {COLORS.map((col) => ( + + ))} + + + ); +}; + +export default MetaNavigation; diff --git a/showcases/react-showcase/src/navigation/index.tsx b/showcases/react-showcase/src/navigation/index.tsx new file mode 100644 index 000000000000..34e29c633647 --- /dev/null +++ b/showcases/react-showcase/src/navigation/index.tsx @@ -0,0 +1,22 @@ +import { + getSortedNavigationItems, + NAVIGATION_ITEMS, + type NavigationItem +} from '../utils/navigation-item'; +import { DBMainNavigation } from '../../../../output/react/src'; +import NavItem from './nav-item'; + +const Navigation = () => ( + + {getSortedNavigationItems(NAVIGATION_ITEMS).map( + (navItem: NavigationItem) => ( + + ) + )} + +); + +export default Navigation; diff --git a/showcases/react-showcase/src/navigation/nav-item.tsx b/showcases/react-showcase/src/navigation/nav-item.tsx new file mode 100644 index 000000000000..63c9c8a7b990 --- /dev/null +++ b/showcases/react-showcase/src/navigation/nav-item.tsx @@ -0,0 +1,44 @@ +import { Link, useLocation } from 'react-router-dom'; +import { DBNavigationItem } from '../../../../output/react/src'; +import type { NavigationItem } from '../utils/navigation-item'; + +const NavItem = ({ navItem }: { navItem: NavigationItem }) => { + const location = useLocation(); + + const isActive = + navItem.path === '' + ? location.pathname === '/' + : location.pathname.includes(navItem.path); + + return ( + + {navItem.subNavigation + .map((subItem: NavigationItem) => ({ + ...subItem, + path: `${navItem.path}/${subItem.path}` + })) + .map((subItem: NavigationItem) => ( + + ))} + + ) + }> + {navItem.component ? ( + + {navItem.label} + + ) : ( + navItem.label + )} + + ); +}; + +export default NavItem; diff --git a/showcases/react-showcase/src/utils/navigation-item.tsx b/showcases/react-showcase/src/utils/navigation-item.tsx index dc8e6621b6fe..5a1120715e81 100644 --- a/showcases/react-showcase/src/utils/navigation-item.tsx +++ b/showcases/react-showcase/src/utils/navigation-item.tsx @@ -1,3 +1,4 @@ +import MainNavigationComponent from '../components/main-navigation'; import BadgeComponent from '../components/badge'; import NavigationItemComponent from '../components/navigation-item'; import CheckboxComponent from '../components/checkbox'; @@ -18,33 +19,106 @@ import DividerComponent from '../components/divider'; export type NavigationItem = { path: string; label: string; - component: any; - home?: boolean; + component?: any; + subNavigation?: NavigationItem[]; }; + +export const getSortedNavigationItems = ( + navigationItems: NavigationItem[] +): any[] => + navigationItems.sort((a: NavigationItem, b: NavigationItem) => + a.path.localeCompare(b.path) + ); export const NAVIGATION_ITEMS: NavigationItem[] = [ - { path: 'badge', label: 'Badge', component: }, + { + path: '06', + label: '06 Feedback', + subNavigation: getSortedNavigationItems([ + { path: 'alert', label: 'Alert', component: }, + { path: 'badge', label: 'Badge', component: } + ]) + }, { - path: 'navigation-item', - label: 'NavigationItem', - component: + path: '05', + label: '05 Navigation', + subNavigation: getSortedNavigationItems([ + { + path: 'navigation-item', + label: 'NavigationItem', + component: + }, + { + path: 'main-navigation', + label: 'MainNavigation', + component: + }, + + { + path: 'test', + label: 'Test', + subNavigation: [ + { + path: 'test2', + label: 'NavigationItem', + component: + } + ] + } + ]) }, - { path: 'checkbox', label: 'Checkbox', component: }, - { path: 'divider', label: 'Divider', component: }, - { path: 'tag', label: 'Tag', component: }, - { path: 'select', label: 'Select', component: }, - { path: 'radio', label: 'Radio', component: }, - { path: 'alert', label: 'Alert', component: }, - { path: 'drawer', label: 'Drawer', component: }, - { path: 'infotext', label: 'Infotext', component: }, - { path: 'section', label: 'Section', component: }, - { path: 'link', label: 'Link', component: }, - { path: 'button', label: 'Button', component: }, - { path: 'input', label: 'Input', component: }, - { path: 'card', label: 'Card', component: }, - { path: '', label: 'Home', component: , home: true } + { + path: '04', + label: '04 Data-Display', + subNavigation: getSortedNavigationItems([ + { + path: 'infotext', + label: 'Infotext', + component: + }, + { path: 'tag', label: 'Tag', component: } + ]) + }, + { + path: '03', + label: '03 Data-Input', + subNavigation: getSortedNavigationItems([ + { path: 'input', label: 'Input', component: }, + { path: 'radio', label: 'Radio', component: }, + { + path: 'checkbox', + label: 'Checkbox', + component: + }, + { path: 'select', label: 'Select', component: } + ]) + }, + { + path: '02', + label: '02 Action', + subNavigation: getSortedNavigationItems([ + { path: 'link', label: 'Link', component: }, + { path: 'button', label: 'Button', component: } + ]) + }, + { + path: '01', + label: '01 Layout', + subNavigation: getSortedNavigationItems([ + { path: 'card', label: 'Card', component: }, + { path: 'drawer', label: 'Drawer', component: }, + { + path: 'divider', + label: 'Divider', + component: + }, + { + path: 'section', + label: 'Section', + component: + } + ]) + }, + { path: '', label: 'Home', component: } ]; - -export const getSortedNavigationItems = (): any[] => - NAVIGATION_ITEMS.sort((a, b) => a.path.localeCompare(b.path)); diff --git a/showcases/shared/main-navigation.json b/showcases/shared/main-navigation.json new file mode 100644 index 000000000000..b609838e3242 --- /dev/null +++ b/showcases/shared/main-navigation.json @@ -0,0 +1,22 @@ +[ + { + "name": "Tonality", + "examples": [ + { + "name": "functional", + "className": "db-ui-functional", + "props": {} + }, + { + "name": "regular (Default)", + "className": "db-ui-regular", + "props": {} + }, + { + "name": "expressive", + "className": "db-ui-expressive", + "props": {} + } + ] + } +] diff --git a/showcases/shared/navigation-item.json b/showcases/shared/navigation-item.json index fea5ce2d3499..d6706f180012 100644 --- a/showcases/shared/navigation-item.json +++ b/showcases/shared/navigation-item.json @@ -7,7 +7,7 @@ "className": "db-ui-functional", "props": { "icon": "account", - "iconAfter": "expand-more" + "areaPopup": true } }, { @@ -15,7 +15,7 @@ "className": "db-ui-regular", "props": { "icon": "account", - "iconAfter": "expand-more" + "areaPopup": true } }, { @@ -23,7 +23,7 @@ "className": "db-ui-expressive", "props": { "icon": "account", - "iconAfter": "expand-more" + "areaPopup": true } } ] @@ -35,22 +35,23 @@ "name": "Enabled (Default)", "props": { "icon": "account", - "iconAfter": "expand-more" + "areaPopup": true } }, { - "name": "Disabled", + "name": "Active", "props": { - "disabled": true, + "active": true, "icon": "account", - "iconAfter": "expand-more" + "areaPopup": true } }, { - "name": "Active", + "name": "Disabled", "props": { - "active": true, - "iconAfter": "chevron-right" + "disabled": true, + "icon": "account", + "areaPopup": true } } ] @@ -61,25 +62,28 @@ { "name": "Leading Icon - Text", "props": { - "icon": "account" + "icon": "account", + "areaPopup": false } }, { "name": "Leading Icon - Text - Trailing Icon", "props": { "icon": "account", - "iconAfter": "expand-more" + "areaPopup": true } }, { "name": "Text - Trailing Icon", "props": { - "iconAfter": "expand-more" + "areaPopup": true } }, { "name": "Text", - "props": {} + "props": { + "areaPopup": false + } } ] }, @@ -91,7 +95,7 @@ "style": { "width": "400px" }, "props": { "icon": "account", - "iconAfter": "expand-more" + "areaPopup": true } }, { @@ -100,7 +104,7 @@ "props": { "width": "full", "icon": "account", - "iconAfter": "expand-more" + "areaPopup": true } } ] diff --git a/showcases/vanilla-showcase/src/action-bar.js b/showcases/vanilla-showcase/src/action-bar.js new file mode 100644 index 000000000000..f46ada66d8a9 --- /dev/null +++ b/showcases/vanilla-showcase/src/action-bar.js @@ -0,0 +1,8 @@ +const getActionBar = (mobile) => + `
    + Profile + Notification + Help +
    `; + +export default getActionBar; diff --git a/showcases/vanilla-showcase/src/app-shell.js b/showcases/vanilla-showcase/src/app-shell.js index ed8c569b645f..a2a0bf18e476 100644 --- a/showcases/vanilla-showcase/src/app-shell.js +++ b/showcases/vanilla-showcase/src/app-shell.js @@ -2,8 +2,9 @@ import '../../../output/webcomponent/src/components/page/page.js'; import '../../../output/webcomponent/src/components/header/header.js'; import '../../../output/webcomponent/src/components/brand/brand.js'; import '../../showcase-styles.css'; -import { navigationItems } from './utils/navigation-items.js'; import getQueryParams from './utils/get-query-params.js'; +import getActionBar from './action-bar.js'; +import getNavigation from './navigation.js'; const getClassName = (tonality, color) => { return `db-ui-${tonality} db-bg-${color}`; @@ -23,73 +24,93 @@ const insertParameter = (queryParameters, key, value) => { }; onload = () => { - const selectTonality = document.querySelector('#select-tonality'); - const selectColor = document.querySelector('#select-color'); + const selectTonalities = Array.from( + document.querySelectorAll('#select-tonality') + ); + const selectColors = Array.from(document.querySelectorAll('#select-color')); const content = document.querySelector('#content'); + const header = document.querySelector('#db-header'); const queryParameters = getQueryParams(); const tonality = queryParameters.tonality ?? 'regular'; const color = queryParameters.color ?? 'neutral-0'; content.className = getClassName(tonality, color); - if (selectTonality) { - selectTonality.value = tonality; - selectTonality.addEventListener('change', (event) => { - insertParameter(queryParameters, 'tonality', event.target.value); - }); + if (selectTonalities.length > 0) { + for (const selectTonality of selectTonalities) { + selectTonality.value = tonality; + selectTonality.addEventListener('change', (event) => { + insertParameter( + queryParameters, + 'tonality', + event.target.value + ); + }); + } } - if (selectColor) { - selectColor.value = color; - selectColor.addEventListener('change', (event) => { - insertParameter(queryParameters, 'color', event.target.value); - }); + if (selectColors.length > 0) { + for (const selectColor of selectColors) { + selectColor.value = color; + selectColor.addEventListener('change', (event) => { + insertParameter(queryParameters, 'color', event.target.value); + }); + } + } + + if (header) { + header.props.onToggle = (open) => { + header.setAttribute('drawerOpen', open); + }; } }; +const getMetaNavigation = (mobile) => { + return ` +
    + + +
    `; +}; + const getAppShell = (content) => ` - + Vanilla Showcase - -
    - - -
    + ${getNavigation(true)} + ${getNavigation(false)} + Search + ${getActionBar(true)} + ${getActionBar(false)} + ${getMetaNavigation(true)} + ${getMetaNavigation(false)}
    ${content} diff --git a/showcases/vanilla-showcase/src/navigation.js b/showcases/vanilla-showcase/src/navigation.js new file mode 100644 index 000000000000..c20be18f8c95 --- /dev/null +++ b/showcases/vanilla-showcase/src/navigation.js @@ -0,0 +1,15 @@ +import { navigationItems } from './utils/navigation-items.js'; + +const getNavigation = (mobile) => + ``; + +export default getNavigation; diff --git a/showcases/vue-showcase/src/App.vue b/showcases/vue-showcase/src/App.vue index 50ffdb906803..04a551131f2c 100644 --- a/showcases/vue-showcase/src/App.vue +++ b/showcases/vue-showcase/src/App.vue @@ -3,7 +3,9 @@ import { DBPage, DBHeader, DBBrand, - DBNavigationItem + DBSelect, + DBMainNavigation, + DBButton } from "../../../output/vue/vue3/src"; import { COLOR, @@ -13,10 +15,14 @@ import { COLOR_CONST, TONALITY_CONST } from "../../../packages/components/src/shared/constants"; -import { getSortedNavigationItems } from "./utils/navigation-items"; +import { + getSortedNavigationItems, + navigationItems +} from "./utils/navigation-items"; import { ref, watch } from "vue"; import { useRouter, useRoute } from "vue-router"; +import NavItemComponent from "./NavItemComponent.vue"; const router = useRouter(); const route = useRoute(); @@ -26,6 +32,12 @@ const color = ref(COLOR.NEUTRAL_0); const page = ref(); const fullscreen = ref(); +const drawerOpen = ref(false); + +const toggleDrawer = (open: boolean) => { + drawerOpen.value = open; +}; + const getClassNames = () => { return `db-ui-${tonality.value} db-bg-${color.value}`; }; @@ -58,15 +70,17 @@ watch( } } ); + +const sortedNavigation = getSortedNavigationItems(navigationItems); diff --git a/showcases/vue-showcase/src/main.ts b/showcases/vue-showcase/src/main.ts index 09648e95b426..3c2da48a7910 100644 --- a/showcases/vue-showcase/src/main.ts +++ b/showcases/vue-showcase/src/main.ts @@ -2,9 +2,9 @@ import { createApp } from 'vue'; import { createRouter, createWebHashHistory } from 'vue-router'; import './index.scss'; import App from './App.vue'; -import { navigationItems } from './utils/navigation-items'; +import { getRoutes } from './utils/navigation-items'; -const routes = navigationItems; +const routes = getRoutes(); const router = createRouter({ history: createWebHashHistory('/vue-showcase/'), diff --git a/showcases/vue-showcase/src/utils/navigation-items.ts b/showcases/vue-showcase/src/utils/navigation-items.ts index 5b0315f4df62..900a188e0a1e 100644 --- a/showcases/vue-showcase/src/utils/navigation-items.ts +++ b/showcases/vue-showcase/src/utils/navigation-items.ts @@ -1,5 +1,7 @@ +import type { RouteRecordRaw } from 'vue-router'; import Badge from '../components/badge/Badge.vue'; import NavigationItem from '../components/navigation-item/NavigationItem.vue'; +import MainNavigation from '../components/main-navigation/MainNavigation.vue'; import Select from '../components/select/Select.vue'; import Tag from '../components/tag/Tag.vue'; import Form from '../components/form/Form.vue'; @@ -15,31 +17,116 @@ import Section from '../components/section/Section.vue'; import Card from '../components/card/Card.vue'; import Drawer from '../components/drawer/Drawer.vue'; -export const navigationItems: any[] = [ - { path: '/badge', label: 'Badge', component: Badge }, +export type NavItem = { + path: string; + label: string; + component?: any; + subNavigation?: NavItem[]; +}; + +export const getSortedNavigationItems = (navigationItems: NavItem[]): any[] => + navigationItems.sort((a: NavItem, b: NavItem) => + a.path.localeCompare(b.path) + ); + +export const navigationItems: NavItem[] = [ + { + path: '/06', + label: '06 Feedback', + subNavigation: getSortedNavigationItems([ + { path: '/06/alert', label: 'Alert', component: Alert }, + { path: '/06/badge', label: 'Badge', component: Badge } + ]) + }, { - path: '/navigation-item', - label: 'NavigationItem', - component: NavigationItem + path: '/05', + label: '05 Navigation', + subNavigation: getSortedNavigationItems([ + { + path: '/05/navigation-item', + label: 'NavigationItem', + component: NavigationItem + }, + { + path: '/05/main-navigation', + label: 'MainNavigation', + component: MainNavigation + } + ]) }, - { path: '/tag', label: 'Tag', component: Tag }, - { path: '/', label: 'Home', component: Form }, - { path: '/divider', label: 'Divider', component: Divider }, - { path: '/select', label: 'Select', component: Select }, - { path: '/radio', label: 'Radio', component: Radio }, - { path: '/checkbox', label: 'Checkbox', component: Checkbox }, - { path: '/alert', label: 'Alert', component: Alert }, - { path: '/drawer', label: 'Drawer', component: Drawer }, - { path: '/infotext', label: 'Infotext', component: Infotext }, - { path: '/section', label: 'Section', component: Section }, - { path: '/link', label: 'Link', component: Link }, - { path: '/button', label: 'Button', component: Button }, - { path: '/input', label: 'Input', component: Input }, - { path: '/card', label: 'Card', component: Card } + { + path: '/04', + label: '04 Data-Display', + subNavigation: getSortedNavigationItems([ + { + path: '/04/infotext', + label: 'Infotext', + component: Infotext + }, + { path: '/04/tag', label: 'Tag', component: Tag } + ]) + }, + { + path: '/03', + label: '03 Data-Input', + subNavigation: getSortedNavigationItems([ + { path: '/03/input', label: 'Input', component: Input }, + { path: '/03/radio', label: 'Radio', component: Radio }, + { + path: '/03/checkbox', + label: 'Checkbox', + component: Checkbox + }, + { path: '/03/select', label: 'Select', component: Select } + ]) + }, + { + path: '/02', + label: '02 Action', + subNavigation: getSortedNavigationItems([ + { path: '/02/link', label: 'Link', component: Link }, + { path: '/02/button', label: 'Button', component: Button } + ]) + }, + { + path: '/01', + label: '01 Layout', + subNavigation: getSortedNavigationItems([ + { path: '/01/card', label: 'Card', component: Card }, + { path: '/01/drawer', label: 'Drawer', component: Drawer }, + { + path: '/01/divider', + label: 'Divider', + component: Divider + }, + { + path: '/01/section', + label: 'Section', + component: Section + } + ]) + }, + { path: '/', label: 'Home', component: Form } ]; -export const getSortedNavigationItems = (): any[] => - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - navigationItems.sort((a: any, b: any) => a.path.localeCompare(b.path)); +const pushRoute = (routes: RouteRecordRaw[], item: NavItem) => { + routes.push({ path: item.path, component: item.component }); + + if (item.subNavigation) { + for (const subItem of item.subNavigation) { + pushRoute(routes, subItem); + } + } +}; + +export const getRoutes = (): RouteRecordRaw[] => { + const routes: RouteRecordRaw[] = []; + + for (const item of navigationItems) { + pushRoute(routes, item); + } + + return routes; +};