diff --git a/.changeset/bright-insects-unite.md b/.changeset/bright-insects-unite.md new file mode 100644 index 0000000000..1b9e20b4d1 --- /dev/null +++ b/.changeset/bright-insects-unite.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-components': patch +--- + +Switched mega dropdown content to one column on mobile. diff --git a/.changeset/calm-rabbits-pull.md b/.changeset/calm-rabbits-pull.md new file mode 100644 index 0000000000..36ee70ea3d --- /dev/null +++ b/.changeset/calm-rabbits-pull.md @@ -0,0 +1,6 @@ +--- +'@swisspost/design-system-components': minor +'@swisspost/design-system-styles': minor +--- + +Added composable footer component. diff --git a/.changeset/dry-trainers-stare.md b/.changeset/dry-trainers-stare.md new file mode 100644 index 0000000000..9c39d2ade3 --- /dev/null +++ b/.changeset/dry-trainers-stare.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-components': patch +--- + +Fixed opening state of megadropdown trigger and expanded detection. diff --git a/.changeset/four-beers-leave.md b/.changeset/four-beers-leave.md new file mode 100644 index 0000000000..7b61eca6d8 --- /dev/null +++ b/.changeset/four-beers-leave.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-documentation': patch +--- + +Added scss file import documentation to palette. diff --git a/.changeset/gold-news-repair.md b/.changeset/gold-news-repair.md new file mode 100644 index 0000000000..f10c73d5a3 --- /dev/null +++ b/.changeset/gold-news-repair.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-components': minor +--- + +Added the `post-megadropdown` component. diff --git a/.changeset/gorgeous-glasses-end.md b/.changeset/gorgeous-glasses-end.md new file mode 100644 index 0000000000..9c85b5a1f4 --- /dev/null +++ b/.changeset/gorgeous-glasses-end.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-components': patch +--- + +Fix tab isolation in nested `post-tabs` components by scoping tab queries and interactions to the current instance. diff --git a/.changeset/gorgeous-needles-run.md b/.changeset/gorgeous-needles-run.md new file mode 100644 index 0000000000..732850bd1a --- /dev/null +++ b/.changeset/gorgeous-needles-run.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-components': patch +--- + +Added a fixed slot `post-list-item` on the `post-list-item` host element, so it is no longer necessary to add it manually. diff --git a/.changeset/heavy-eyes-live.md b/.changeset/heavy-eyes-live.md new file mode 100644 index 0000000000..e2d5076e51 --- /dev/null +++ b/.changeset/heavy-eyes-live.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-components': patch +--- + +Fixed the used `headingLevel` in the `post-accorddion-item` component. The component now uses the value from its closest `post-accorddion` parent component, if this is specified and falls back to `h2` if not specified. diff --git a/.changeset/hungry-penguins-turn.md b/.changeset/hungry-penguins-turn.md new file mode 100644 index 0000000000..f18caa33d0 --- /dev/null +++ b/.changeset/hungry-penguins-turn.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-styles': patch +--- + +Fixed the `btn-icon` styles, so icons within can no longer be rendered too small, because of the inline-padding on the button. diff --git a/.changeset/nervous-lizards-laugh.md b/.changeset/nervous-lizards-laugh.md new file mode 100644 index 0000000000..944f941bc9 --- /dev/null +++ b/.changeset/nervous-lizards-laugh.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-styles': minor +--- + +Removed outdated portal-specific styles, including subnavigation-related rules. diff --git a/.changeset/new-cougars-count.md b/.changeset/new-cougars-count.md new file mode 100644 index 0000000000..a06891fb5e --- /dev/null +++ b/.changeset/new-cougars-count.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-components': minor +--- + +Added the parts `button` and `body` in the `post-accordion-item` component, so one can override styles from the outside. diff --git a/.changeset/nice-cycles-provide.md b/.changeset/nice-cycles-provide.md new file mode 100644 index 0000000000..a87368195c --- /dev/null +++ b/.changeset/nice-cycles-provide.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-components': patch +--- + +Updated the `post-togglebutton` to function like a real button, including support for keyboard navigation and proper focus styles. diff --git a/.changeset/nine-baboons-rule.md b/.changeset/nine-baboons-rule.md new file mode 100644 index 0000000000..ecc4c1652d --- /dev/null +++ b/.changeset/nine-baboons-rule.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-styles': patch +--- + +Fixed the appstore-badge styles to get rid of the inline gap below. diff --git a/.changeset/old-spiders-travel.md b/.changeset/old-spiders-travel.md new file mode 100644 index 0000000000..7f4fc4731a --- /dev/null +++ b/.changeset/old-spiders-travel.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-styles': minor +--- + +Added the possibility to define a `$child-selector` parameter with our list mixins, so they can be used also with custom elements. diff --git a/.changeset/pre.json b/.changeset/pre.json index dd59e1d095..0a150682b6 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -33,7 +33,9 @@ "blue-kings-beg", "brave-kings-dance", "breezy-cups-add", + "bright-insects-unite", "brown-badgers-dream", + "calm-rabbits-pull", "chatty-kiwis-travel", "chatty-spoons-unite", "chilled-owls-walk", @@ -47,6 +49,7 @@ "dirty-mayflies-taste", "dirty-squids-hunt", "dry-moons-walk", + "dry-trainers-stare", "dull-falcons-hope", "eight-turkeys-matter", "eleven-keys-work", @@ -64,13 +67,18 @@ "gold-chairs-grin", "gold-chefs-rule", "gold-dryers-drop", + "gold-news-repair", "gorgeous-flowers-flow", + "gorgeous-glasses-end", + "gorgeous-needles-run", "great-humans-talk", "grumpy-lobsters-agree", "grumpy-parrots-wonder", + "heavy-eyes-live", "heavy-rats-explode", "hip-gifts-give", "honest-numbers-end", + "hungry-penguins-turn", "itchy-meals-drum", "khaki-cougars-itch", "kind-buses-trade", @@ -87,11 +95,16 @@ "metal-rivers-look", "nasty-ads-greet", "neat-suits-provide", + "nervous-lizards-laugh", "nervous-rocks-shop", + "new-cougars-count", "new-goats-impress", "new-pianos-mix", + "nice-cycles-provide", "nice-ligers-attend", + "nine-baboons-rule", "ninety-nails-float", + "old-spiders-travel", "orange-maps-tan", "pink-weeks-relate", "plenty-apricots-raise", @@ -108,6 +121,7 @@ "quick-mails-joke", "quiet-apes-rhyme", "rare-dryers-count", + "real-gorillas-behave", "red-cobras-cry", "red-lies-lick", "red-moose-do", @@ -128,25 +142,32 @@ "slimy-plums-sniff", "slimy-rockets-pull", "slow-fishes-reply", + "smooth-bugs-explode", "soft-moles-whisper", + "soft-pugs-dream", "strange-bottles-impress", "strange-mice-bake", "stupid-walls-tie", "tame-terms-push", + "tender-laws-confess", "thirty-cats-juggle", "three-lies-do", "tidy-dolls-walk", "tidy-keys-push", "tidy-paws-type", "tiny-socks-count", + "tough-cheetahs-clean", "tricky-crews-agree", + "twenty-chairs-kick", "twenty-items-drum", + "violet-poems-attend", "warm-drinks-prove", "weak-falcons-study", "weak-jars-rhyme", "wild-bugs-work", "wise-spies-shave", "wise-tomatoes-brake", + "yellow-gifts-sit", "yellow-yaks-jog" ] } diff --git a/.changeset/real-gorillas-behave.md b/.changeset/real-gorillas-behave.md new file mode 100644 index 0000000000..e90fc39826 --- /dev/null +++ b/.changeset/real-gorillas-behave.md @@ -0,0 +1,6 @@ +--- +'@swisspost/design-system-documentation': minor +'@swisspost/design-system-components': minor +--- + +Added the `post-breadcrumb` component to provide a standalone breadcrumb navigation solution. diff --git a/.changeset/smooth-bugs-explode.md b/.changeset/smooth-bugs-explode.md new file mode 100644 index 0000000000..9a822cca5d --- /dev/null +++ b/.changeset/smooth-bugs-explode.md @@ -0,0 +1,6 @@ +--- +'@swisspost/design-system-components': major +'@swisspost/design-system-documentation': patch +--- + +Updated the `post-togglebutton` component to offer greater flexibility. You can now control the visibility of elements within the `post-togglebutton` using the `data-showwhen="toggled"` and `data-showwhen="untoggled"` attributes. Any content without a `data-showwhen` attribute will always be visible, regardless of the toggle state. diff --git a/.changeset/soft-pugs-dream.md b/.changeset/soft-pugs-dream.md new file mode 100644 index 0000000000..10b4189721 --- /dev/null +++ b/.changeset/soft-pugs-dream.md @@ -0,0 +1,6 @@ +--- +'@swisspost/design-system-documentation': minor +'@swisspost/design-system-styles': minor +--- + +Updated the utility classes for sizing. diff --git a/.changeset/tender-laws-confess.md b/.changeset/tender-laws-confess.md new file mode 100644 index 0000000000..49878a3ecc --- /dev/null +++ b/.changeset/tender-laws-confess.md @@ -0,0 +1,6 @@ +--- +'@swisspost/design-system-documentation': minor +'@swisspost/design-system-components': minor +--- + +Added the css parts `button` and `body` in the `post-accorddion-item` component. diff --git a/.changeset/twenty-chairs-kick.md b/.changeset/twenty-chairs-kick.md new file mode 100644 index 0000000000..751cef6c67 --- /dev/null +++ b/.changeset/twenty-chairs-kick.md @@ -0,0 +1,6 @@ +--- +'@swisspost/design-system-documentation': minor +'@swisspost/design-system-styles': minor +--- + +Updated `.btn-link` to look like a regular link and old `.btn-link` is now `.btn-tertiary .px-0`. diff --git a/.changeset/violet-poems-attend.md b/.changeset/violet-poems-attend.md new file mode 100644 index 0000000000..cfec36d36d --- /dev/null +++ b/.changeset/violet-poems-attend.md @@ -0,0 +1,6 @@ +--- +'@swisspost/design-system-documentation': minor +'@swisspost/design-system-styles': minor +--- + +Implemented new pixel based sizes. diff --git a/.github/actions/preview/message/create/action.yaml b/.github/actions/preview/message/create/action.yaml index 3d56790012..61d2e82b8c 100644 --- a/.github/actions/preview/message/create/action.yaml +++ b/.github/actions/preview/message/create/action.yaml @@ -5,14 +5,20 @@ inputs: access-token: description: The access token to use for commenting. required: true + issue-number: + description: The issue number from the caller workflow. + required: true runs: using: composite steps: - uses: actions/github-script@v7 + env: + ISSUE_NUMBER: ${{ inputs.issue-number }} with: github-token: ${{ inputs.access-token }} script: | + const { ISSUE_NUMBER } = process.env const commentTitle = '**Related Previews**' const commentInitialBody = 'Preview URLs will be added here, once they are ready... ![loader](https://github.com/swisspost/design-system/assets/9716662/49a75898-7093-4ffb-9460-071ff194459d)' @@ -25,7 +31,7 @@ runs: await github.rest.issues.createComment({ repo: context.repo.repo, owner: context.repo.owner, - issue_number: context.issue.number, + issue_number: ISSUE_NUMBER, body: `${commentTitle}\n${commentInitialBody}` }) @@ -45,7 +51,7 @@ runs: comments = (await github.rest.issues.listComments({ repo: context.repo.repo, owner: context.repo.owner, - issue_number: context.issue.number + issue_number: ISSUE_NUMBER })).data || [] previewComment = comments.find(c => c.user.login === 'swisspost-bot' && c.body.includes(commentTitle)) diff --git a/.github/workflows/build-documentation.yaml b/.github/workflows/build-documentation.yaml index 168fd01d45..99783a8e4a 100644 --- a/.github/workflows/build-documentation.yaml +++ b/.github/workflows/build-documentation.yaml @@ -25,11 +25,6 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Create preview message - uses: ./.github/actions/preview/message/create - with: - access-token: ${{ secrets.SWISSPOSTDEVS_ACCESS_TOKEN }} - - name: Setup uses: ./.github/actions/setup-pnpm diff --git a/.github/workflows/deploy-demo.yaml b/.github/workflows/deploy-demo.yaml new file mode 100644 index 0000000000..101553f1f7 --- /dev/null +++ b/.github/workflows/deploy-demo.yaml @@ -0,0 +1,54 @@ +### +# +# Not used for v9 anymore +# But since workflows run always from the `main` branch we need to keep it for older versions +# +### + +name: Deploy Demo App Preview to Netlify +on: + workflow_run: + workflows: ['Build Demo App'] + types: + - completed + +jobs: + deploy: + runs-on: ubuntu-latest + if: > + ${{ github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.workflow_run.head_branch }} + + - name: Setup + uses: ./.github/actions/setup-pnpm + + - name: Download build artifacts + uses: ./.github/actions/artifact-download + id: build + with: + name: design-system-demo + folder: build-output + + - name: Deploy demo app to netlify + uses: swisspost/design-system/.github/actions/deploy-to-netlify@release/v8 + id: deploy + with: + id: ${{ steps.build.outputs.id }} + netlify_auth_token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + netlify_site_id: ${{ secrets.NETLIFY_SITE_ID }} + netlify_site_url: swisspost-web-frontend.netlify.app + folder: ${{ steps.build.outputs.folder }} + package_name: '@swisspost/design-system-demo' + + - name: Update preview message + uses: ./.github/actions/preview/message/update + with: + access-token: ${{ secrets.SWISSPOSTDEVS_ACCESS_TOKEN }} + issue-number: ${{ steps.build.outputs.id }} + preview-url: ${{ steps.deploy.outputs.preview-url }} diff --git a/.github/workflows/deploy-documentation.yaml b/.github/workflows/deploy-documentation.yaml index 1f4043aebc..7b54c52c35 100644 --- a/.github/workflows/deploy-documentation.yaml +++ b/.github/workflows/deploy-documentation.yaml @@ -26,6 +26,12 @@ jobs: name: design-system-documentation folder: build-output + - name: Create preview message + uses: ./.github/actions/preview/message/create + with: + access-token: ${{ secrets.SWISSPOSTDEVS_ACCESS_TOKEN }} + issue-number: ${{ steps.build.outputs.id }} + - name: Get netlify config id: netlify-config uses: actions/github-script@v7 diff --git a/packages/components-angular/CHANGELOG.md b/packages/components-angular/CHANGELOG.md index dac8ffd293..dfef9566ba 100644 --- a/packages/components-angular/CHANGELOG.md +++ b/packages/components-angular/CHANGELOG.md @@ -1,5 +1,13 @@ # @swisspost/design-system-components-angular-workspace +## 1.1.10-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-components@9.0.0-next.9 + - @swisspost/design-system-styles@9.0.0-next.9 + ## 1.1.10-next.8 ### Patch Changes diff --git a/packages/components-angular/package.json b/packages/components-angular/package.json index 77476b8813..f3fcec1e57 100644 --- a/packages/components-angular/package.json +++ b/packages/components-angular/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-components-angular-workspace", - "version": "1.1.10-next.8", + "version": "1.1.10-next.9", "scripts": { "start": "ng serve --port 9210", "build": "ng build components", @@ -18,8 +18,8 @@ "@angular/platform-browser": "18.2.13", "@angular/platform-browser-dynamic": "18.2.13", "@angular/router": "18.2.13", - "@swisspost/design-system-components": "workspace:9.0.0-next.8", - "@swisspost/design-system-styles": "workspace:9.0.0-next.8", + "@swisspost/design-system-components": "workspace:9.0.0-next.9", + "@swisspost/design-system-styles": "workspace:9.0.0-next.9", "rxjs": "7.8.1", "tslib": "2.6.3", "zone.js": "0.14.8" diff --git a/packages/components-angular/projects/components/CHANGELOG.md b/packages/components-angular/projects/components/CHANGELOG.md index 9711a4ec09..f08d9d448d 100644 --- a/packages/components-angular/projects/components/CHANGELOG.md +++ b/packages/components-angular/projects/components/CHANGELOG.md @@ -1,5 +1,12 @@ # @swisspost/design-system-components-angular +## 9.0.0-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-components@9.0.0-next.9 + ## 9.0.0-next.8 ### Patch Changes diff --git a/packages/components-angular/projects/components/package.json b/packages/components-angular/projects/components/package.json index 845bdc6452..bd4a0c44b7 100644 --- a/packages/components-angular/projects/components/package.json +++ b/packages/components-angular/projects/components/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-components-angular", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "Swiss Post Design System - Angular Wrapper Components", "author": "Swiss Post ", "license": "Apache-2.0", @@ -19,7 +19,7 @@ }, "dependencies": { "tslib": "2.6.3", - "@swisspost/design-system-components": "workspace:9.0.0-next.8" + "@swisspost/design-system-components": "workspace:9.0.0-next.9" }, "peerDependencies": { "@angular/common": "^16.0.0 || ^17.0.0 || ^18.0.0", diff --git a/packages/components-react/CHANGELOG.md b/packages/components-react/CHANGELOG.md index 8c9419a1cd..816d41a2c6 100644 --- a/packages/components-react/CHANGELOG.md +++ b/packages/components-react/CHANGELOG.md @@ -1,5 +1,12 @@ # @swisspost/design-system-components-react +## 9.0.0-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-components@9.0.0-next.9 + ## 9.0.0-next.8 ### Patch Changes diff --git a/packages/components-react/package.json b/packages/components-react/package.json index 6db0c2c351..9d8dad0a91 100644 --- a/packages/components-react/package.json +++ b/packages/components-react/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-components-react", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "Design System React Components for easy integration with the React ecosystem", "author": "Swiss Post ", "license": "Apache-2.0", @@ -29,7 +29,7 @@ "lint": "eslint src/**/*.ts" }, "dependencies": { - "@swisspost/design-system-components": "workspace:9.0.0-next.8" + "@swisspost/design-system-components": "workspace:9.0.0-next.9" }, "devDependencies": { "@types/node": "20.14.14", diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 22e837531b..f40588bf27 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,5 +1,44 @@ # @swisspost/design-system-components +## 9.0.0-next.9 + +### Major Changes + +- Updated the `post-togglebutton` component to offer greater flexibility. You can now control the visibility of elements within the `post-togglebutton` using the `data-showwhen="toggled"` and `data-showwhen="untoggled"` attributes. Any content without a `data-showwhen` attribute will always be visible, regardless of the toggle state. (by [@alizedebray](https://github.com/alizedebray) with [#4223](https://github.com/swisspost/design-system/pull/4223)) + +### Minor Changes + +- Added composable footer component. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + +- Added the `post-megadropdown` component. (by [@leagrdv](https://github.com/leagrdv) with [#4177](https://github.com/swisspost/design-system/pull/4177)) + +- Added the parts `button` and `body` in the `post-accordion-item` component, so one can override styles from the outside. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + +- Added the `post-breadcrumb` component to provide a standalone breadcrumb navigation solution. (by [@alionazherdetska](https://github.com/alionazherdetska) with [#4065](https://github.com/swisspost/design-system/pull/4065)) + +- Added the css parts `button` and `body` in the `post-accorddion-item` component. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + +- Added the `post-language-switch` component that enables users to change the language of a page. (by [@leagrdv](https://github.com/leagrdv) with [#4044](https://github.com/swisspost/design-system/pull/4044)) + +### Patch Changes + +- Switched mega dropdown content to one column on mobile. (by [@leagrdv](https://github.com/leagrdv) with [#4300](https://github.com/swisspost/design-system/pull/4300)) + +- Fixed opening state of megadropdown trigger and expanded detection. (by [@leagrdv](https://github.com/leagrdv) with [#4299](https://github.com/swisspost/design-system/pull/4299)) + +- Fix tab isolation in nested `post-tabs` components by scoping tab queries and interactions to the current instance. (by [@alionazherdetska](https://github.com/alionazherdetska) with [#4211](https://github.com/swisspost/design-system/pull/4211)) + +- Added a fixed slot `post-list-item` on the `post-list-item` host element, so it is no longer necessary to add it manually. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + +- Fixed the used `headingLevel` in the `post-accorddion-item` component. The component now uses the value from its closest `post-accorddion` parent component, if this is specified and falls back to `h2` if not specified. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + +- Updated the `post-togglebutton` to function like a real button, including support for keyboard navigation and proper focus styles. (by [@alizedebray](https://github.com/alizedebray) with [#4242](https://github.com/swisspost/design-system/pull/4242)) + +- Fixed an issue with the post-list component where the `horizontal` property could not be set programmatically. Also, reduced the specificity of the component's styles to make customization easier. (by [@alizedebray](https://github.com/alizedebray) with [#4137](https://github.com/swisspost/design-system/pull/4137)) +- Updated dependencies: + - @swisspost/design-system-styles@9.0.0-next.9 + - @swisspost/design-system-icons@9.0.0-next.9 + ## 9.0.0-next.8 ### Minor Changes diff --git a/packages/components/cypress/e2e/footer.cy.ts b/packages/components/cypress/e2e/footer.cy.ts new file mode 100644 index 0000000000..77c7719d2b --- /dev/null +++ b/packages/components/cypress/e2e/footer.cy.ts @@ -0,0 +1,54 @@ +const FOOTER_ID = 'd97528b3-a9ef-4201-bf28-9caf6e8997dc'; + +describe('Footer', () => { + describe('Structure & Props', () => { + beforeEach(() => { + cy.getComponent('footer', FOOTER_ID); + cy.get('@footer').find('> footer h2.visually-hidden').as('label'); + }); + + it('should render', () => { + cy.get('@footer').should('exist'); + }); + + it('should set label text according to "label" prop', () => { + cy.get('@label').should('have.text', 'Footer label'); + }); + + it('should render the post-accorddion on mobile', () => { + cy.viewport('iphone-3'); + cy.get('@footer').find('post-accorddion').as('accorddion'); + + cy.get('@accorddion').should('exist'); + }); + + it('should have accorddion-items with slotted elements on mobile', () => { + cy.viewport('iphone-3'); + cy.get('@footer').find('post-accorddion').as('accorddion'); + cy.get('@accorddion').find('post-accordion-item').as('accordionItems'); + + cy.get('@accordionItems').should('have.length', 4); + cy.get('@accordionItems') + .find('slot[name="header"]') + .each($slot => { + const headerSlot = $slot.get(0) as HTMLSlotElement; + + expect(headerSlot.assignedElements().length).to.be.greaterThan(0); + }); + cy.get('@accordionItems') + .find('slot:not([name])') + .each($slot => { + const slotDefault = $slot.get(0) as HTMLSlotElement; + + expect(slotDefault.assignedElements().length).to.be.greaterThan(0); + }); + }); + }); + + describe('Accessibility', () => { + it('Has no detectable a11y violations', () => { + cy.getSnapshots('footer'); + cy.checkA11y('#root-inner'); + }); + }); +}); diff --git a/packages/components/cypress/e2e/togglebutton.cy.ts b/packages/components/cypress/e2e/togglebutton.cy.ts index 3df5fa773f..cdf2ec0895 100644 --- a/packages/components/cypress/e2e/togglebutton.cy.ts +++ b/packages/components/cypress/e2e/togglebutton.cy.ts @@ -1,114 +1,113 @@ const TOGGLE_BUTTON_ID = '1a6f47c2-5e8a-45a0-b1c3-9f7e2b834c24'; describe('togglebutton', () => { - beforeEach(() => { - cy.visit('/iframe.html?id=snapshots--toggle-button'); - cy.get('post-togglebutton', { timeout: 30000 }).should('be.visible'); - }); + describe('default', () => { + beforeEach(() => { + cy.getComponent('togglebutton', TOGGLE_BUTTON_ID); + }); - describe('default behavior', () => { - it('should toggle state when clicked', () => { - cy.get('post-togglebutton') - .first() - .as('button') - .shadow() - .find('slot[name="untoggled"]') - .should('exist'); + it('should show expected content', () => { + cy.get('@togglebutton').find('[data-showwhen="toggled"]').should('be.hidden'); + cy.get('@togglebutton').find('[data-showwhen="untoggled"]').should('be.visible'); + }); - cy.get('@button').click(); + it('should have correct ARIA attributes', () => { + cy.get('@togglebutton') + .should('have.attr', 'role', 'button') + .and('have.attr', 'aria-pressed', 'false') + .and('have.attr', 'tabindex', '0'); + }); + + it('should toggle state when clicked', () => { + cy.get('@togglebutton').click(); - cy.get('@button').shadow().find('slot[name="toggled"]').should('exist'); + cy.get('@togglebutton').find('[data-showwhen="toggled"]').should('be.visible'); + cy.get('@togglebutton').find('[data-showwhen="untoggled"]').should('be.hidden'); + cy.get('@togglebutton').should('have.attr', 'aria-pressed', 'true'); }); it('should toggle state when pressing Enter key', () => { - cy.get('post-togglebutton') - .first() - .as('button') - .shadow() - .find('slot[name="untoggled"]') - .should('exist'); + cy.get('@togglebutton').trigger('keydown', { key: 'Enter' }); - cy.get('@button').trigger('keydown', { key: 'Enter' }); + cy.get('@togglebutton').find('[data-showwhen="toggled"]').should('be.visible'); + cy.get('@togglebutton').find('[data-showwhen="untoggled"]').should('be.hidden'); + cy.get('@togglebutton').should('have.attr', 'aria-pressed', 'true'); + }); + }); - cy.get('@button').shadow().find('slot[name="toggled"]').should('exist'); + describe('initially toggled', () => { + beforeEach(() => { + cy.getComponent('togglebutton', TOGGLE_BUTTON_ID, 'initially-toggled'); + }); + + it('should show expected content', () => { + cy.get('@togglebutton').find('[data-showwhen="toggled"]').should('be.visible'); + cy.get('@togglebutton').find('[data-showwhen="untoggled"]').should('be.hidden'); }); it('should have correct ARIA attributes', () => { - cy.get('post-togglebutton') - .first() - .as('button') + cy.get('@togglebutton') .should('have.attr', 'role', 'button') - .and('have.attr', 'aria-pressed', 'false') + .and('have.attr', 'aria-pressed', 'true') .and('have.attr', 'tabindex', '0'); - - cy.get('@button').click(); - - cy.get('@button').should('have.attr', 'aria-pressed', 'true'); }); - }); - describe('initial state', () => { - it('should respect initial toggled state', () => { - cy.get('post-togglebutton[toggled]') - .first() - .as('toggledButton') - .shadow() - .find('slot[name="toggled"]') - .should('exist'); + it('should toggle state when clicked', () => { + cy.get('@togglebutton').click(); - cy.get('@toggledButton').should('have.attr', 'aria-pressed', 'true'); + cy.get('@togglebutton').find('[data-showwhen="toggled"]').should('be.hidden'); + cy.get('@togglebutton').find('[data-showwhen="untoggled"]').should('be.visible'); + cy.get('@togglebutton').should('have.attr', 'aria-pressed', 'false'); }); - it('should respect untoggled state', () => { - cy.get('post-togglebutton:not([toggled])') - .first() - .as('untoggledButton') - .shadow() - .find('slot[name="untoggled"]') - .should('exist'); + it('should toggle state when pressing Enter key', () => { + cy.get('@togglebutton').trigger('keydown', { key: 'Enter' }); - cy.get('@untoggledButton').should('have.attr', 'aria-pressed', 'false'); + cy.get('@togglebutton').find('[data-showwhen="toggled"]').should('be.hidden'); + cy.get('@togglebutton').find('[data-showwhen="untoggled"]').should('be.visible'); + cy.get('@togglebutton').should('have.attr', 'aria-pressed', 'false'); }); }); - describe('slot content', () => { - it('should display correct slot content based on toggle state', () => { - cy.get('post-togglebutton').first().as('button'); + describe('content visibility', () => { + beforeEach(() => { + cy.getComponent('togglebutton', TOGGLE_BUTTON_ID, 'content-visibility'); + }); - cy.get('@button').shadow().find('slot[name="untoggled"]').should('exist'); + it('should display correct contents on initial state', () => { + cy.get('@togglebutton').find('[data-showwhen="toggled"]').should('be.hidden'); + cy.get('@togglebutton').find('[data-showwhen="untoggled"]').should('be.visible'); + cy.get('@togglebutton').find(':not([data-showwhen])').should('be.visible'); + }); - cy.get('@button').click(); + it('should display correct contents when clicked', () => { + cy.get('@togglebutton').click(); - cy.get('@button').shadow().find('slot[name="toggled"]').should('exist'); + cy.get('@togglebutton').find('[data-showwhen="toggled"]').should('be.visible'); + cy.get('@togglebutton').find('[data-showwhen="untoggled"]').should('be.hidden'); + cy.get('@togglebutton').find(':not([data-showwhen])').should('be.visible'); + }); - cy.get('@button').click(); + it('should display correct contents when clicked twice', () => { + cy.get('@togglebutton').dblclick(); - cy.get('@button').shadow().find('slot[name="untoggled"]').should('exist'); + cy.get('@togglebutton').find('[data-showwhen="toggled"]').should('be.hidden'); + cy.get('@togglebutton').find('[data-showwhen="untoggled"]').should('be.visible'); + cy.get('@togglebutton').find(':not([data-showwhen])').should('be.visible'); }); }); +}); - describe('version attribute', () => { - it('should have the correct version data attribute', () => { - cy.get('post-togglebutton').first().should('have.attr', 'data-version'); - }); +describe('Accessibility', () => { + beforeEach(() => { + cy.getSnapshots('togglebutton'); }); - describe('Accessibility', () => { - beforeEach(() => { - cy.injectAxe(); - }); - - it('Has no detectable a11y violations on load for all variants', () => { - cy.checkA11y('#root-inner'); - }); + it('Has no detectable a11y violations on load for all variants', () => { + cy.checkA11y('#root-inner'); + }); - it('Should be keyboard navigable', () => { - cy.get('post-togglebutton') - .first() - .focus() - .should('have.focus') - .trigger('keydown', { key: 'Enter' }) - .should('have.attr', 'aria-pressed', 'true'); - }); + it('Should be keyboard navigable', () => { + cy.get('post-togglebutton').first().focus().should('have.focus'); }); }); diff --git a/packages/components/package.json b/packages/components/package.json index 2068ff5214..d261b38173 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-components", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "A collection of web components built with Stencil JS for the Swiss Post Design System.", "license": "Apache-2.0", "main": "dist/index.cjs.js", @@ -40,8 +40,8 @@ "dependencies": { "@floating-ui/dom": "1.6.8", "@oddbird/popover-polyfill": "0.3.7", - "@swisspost/design-system-icons": "workspace:9.0.0-next.8", - "@swisspost/design-system-styles": "workspace:9.0.0-next.8", + "@swisspost/design-system-icons": "workspace:9.0.0-next.9", + "@swisspost/design-system-styles": "workspace:9.0.0-next.9", "ally.js": "1.4.1", "long-press-event": "2.5.0", "nanoid": "5.0.9" diff --git a/packages/components/src/animations/slide.ts b/packages/components/src/animations/slide.ts index 2bd21d7cd4..7ab26f7392 100644 --- a/packages/components/src/animations/slide.ts +++ b/packages/components/src/animations/slide.ts @@ -2,10 +2,10 @@ const easing: string = 'ease'; const duration: number = 500; const fill: FillMode = 'forwards'; -export const slideUp = (el: HTMLElement, translateSize: string = '8rem'): Animation => { +export const slideUp = (el: HTMLElement, translateSize: string = '100%'): Animation => { return el.animate( [ - { transform: `translateY(-${translateSize})` }, // Starting position (no translation) + { transform: `translateY(${translateSize})` }, // Starting position (no translation) { transform: 'translateY(0)' }, // End position ], { @@ -16,11 +16,11 @@ export const slideUp = (el: HTMLElement, translateSize: string = '8rem'): Animat ); }; -export const slideDown = (el: HTMLElement, translateSize: string = '8rem'): Animation => { +export const slideDown = (el: HTMLElement, translateSize: string = '100%'): Animation => { return el.animate( [ { transform: 'translateY(0)' }, // Starting position (no translation) - { transform: `translateY(-${translateSize})` }, // End position + { transform: `translateY(${translateSize})` }, // End position ], { duration: duration, diff --git a/packages/components/src/components.d.ts b/packages/components/src/components.d.ts index 9acbc7fda6..76172f1f38 100644 --- a/packages/components/src/components.d.ts +++ b/packages/components/src/components.d.ts @@ -97,6 +97,16 @@ export namespace Components { */ "type": BannerType; } + interface PostBreadcrumb { + /** + * The text label for the home breadcrumb item. + */ + "homeText": string; + /** + * The URL for the home breadcrumb item. + */ + "homeUrl": string; + } interface PostBreadcrumbItem { /** * The optional URL to which the breadcrumb item will link. @@ -174,7 +184,17 @@ export namespace Components { */ "update": () => Promise; } + interface PostFooter { + /** + * The label to add to the footer (visually hidden). + */ + "label": string; + } interface PostHeader { + /** + * Toggles the mobile navigation. + */ + "toggleMobileMenu": () => Promise; } /** * @class PostIcon - representing a stencil component @@ -218,10 +238,6 @@ export namespace Components { * The ISO 639 language code, formatted according to [RFC 5646 (also known as BCP 47)](https://datatracker.ietf.org/doc/html/rfc5646). For example, "de". */ "code": string; - /** - * Used on parent component (post-language-switch) to detect elements that are manually added - */ - "generated": boolean; /** * The full name of the language. For example, "Deutsch". */ @@ -248,10 +264,6 @@ export namespace Components { * A descriptive text for the list of language options */ "description": string; - /** - * The name of the language switch, which will be used on the dropdown as an ID - */ - "name": string; /** * Variant that determines the rendering of the language switch either as a list (used on mobile in the header) or a dropdown (used on desktop in the header) */ @@ -279,25 +291,20 @@ export namespace Components { } interface PostMegadropdown { /** - * Hide megadropdown - * @returns boolean - */ - "hide": () => Promise; - /** - * Show megadropdown - * @param element HTMLElement - * @returns boolean + * Displays the popover dropdown + * @param target - The HTML element relative to which the popover dropdown should be displayed. */ - "show": (element: HTMLElement) => Promise; + "show": (target: HTMLElement) => Promise; /** - * Toggle megadropdown - * @param element HTMLElement - * @param force boolean - * @returns boolean + * Toggles the dropdown visibility based on its current state. */ - "toggle": (element: HTMLElement, force?: boolean) => Promise; + "toggle": (target: HTMLElement) => Promise; } interface PostMegadropdownTrigger { + /** + * ID of the mega dropdown element that this trigger is linked to. Used to open and close the specified mega dropdown. + */ + "for": string; } interface PostMenu { /** @@ -495,9 +502,9 @@ export interface PostMainnavigationCustomEvent extends CustomEvent { detail: T; target: HTMLPostMainnavigationElement; } -export interface PostMegadropdownTriggerCustomEvent extends CustomEvent { +export interface PostMegadropdownCustomEvent extends CustomEvent { detail: T; - target: HTMLPostMegadropdownTriggerElement; + target: HTMLPostMegadropdownElement; } export interface PostMenuCustomEvent extends CustomEvent { detail: T; @@ -557,6 +564,12 @@ declare global { prototype: HTMLPostBannerElement; new (): HTMLPostBannerElement; }; + interface HTMLPostBreadcrumbElement extends Components.PostBreadcrumb, HTMLStencilElement { + } + var HTMLPostBreadcrumbElement: { + prototype: HTMLPostBreadcrumbElement; + new (): HTMLPostBreadcrumbElement; + }; interface HTMLPostBreadcrumbItemElement extends Components.PostBreadcrumbItem, HTMLStencilElement { } var HTMLPostBreadcrumbItemElement: { @@ -613,6 +626,12 @@ declare global { prototype: HTMLPostCollapsibleTriggerElement; new (): HTMLPostCollapsibleTriggerElement; }; + interface HTMLPostFooterElement extends Components.PostFooter, HTMLStencilElement { + } + var HTMLPostFooterElement: { + prototype: HTMLPostFooterElement; + new (): HTMLPostFooterElement; + }; interface HTMLPostHeaderElement extends Components.PostHeader, HTMLStencilElement { } var HTMLPostHeaderElement: { @@ -686,25 +705,25 @@ declare global { prototype: HTMLPostMainnavigationElement; new (): HTMLPostMainnavigationElement; }; - interface HTMLPostMegadropdownElement extends Components.PostMegadropdown, HTMLStencilElement { - } - var HTMLPostMegadropdownElement: { - prototype: HTMLPostMegadropdownElement; - new (): HTMLPostMegadropdownElement; - }; - interface HTMLPostMegadropdownTriggerElementEventMap { - "postToggle": any; + interface HTMLPostMegadropdownElementEventMap { + "postToggleMegadropdown": boolean; } - interface HTMLPostMegadropdownTriggerElement extends Components.PostMegadropdownTrigger, HTMLStencilElement { - addEventListener(type: K, listener: (this: HTMLPostMegadropdownTriggerElement, ev: PostMegadropdownTriggerCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; + interface HTMLPostMegadropdownElement extends Components.PostMegadropdown, HTMLStencilElement { + addEventListener(type: K, listener: (this: HTMLPostMegadropdownElement, ev: PostMegadropdownCustomEvent) => any, options?: boolean | AddEventListenerOptions): void; addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; addEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void; - removeEventListener(type: K, listener: (this: HTMLPostMegadropdownTriggerElement, ev: PostMegadropdownTriggerCustomEvent) => any, options?: boolean | EventListenerOptions): void; + removeEventListener(type: K, listener: (this: HTMLPostMegadropdownElement, ev: PostMegadropdownCustomEvent) => any, options?: boolean | EventListenerOptions): void; removeEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | EventListenerOptions): void; removeEventListener(type: K, listener: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | EventListenerOptions): void; removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void; } + var HTMLPostMegadropdownElement: { + prototype: HTMLPostMegadropdownElement; + new (): HTMLPostMegadropdownElement; + }; + interface HTMLPostMegadropdownTriggerElement extends Components.PostMegadropdownTrigger, HTMLStencilElement { + } var HTMLPostMegadropdownTriggerElement: { prototype: HTMLPostMegadropdownTriggerElement; new (): HTMLPostMegadropdownTriggerElement; @@ -832,11 +851,13 @@ declare global { "post-avatar": HTMLPostAvatarElement; "post-back-to-top": HTMLPostBackToTopElement; "post-banner": HTMLPostBannerElement; + "post-breadcrumb": HTMLPostBreadcrumbElement; "post-breadcrumb-item": HTMLPostBreadcrumbItemElement; "post-card-control": HTMLPostCardControlElement; "post-closebutton": HTMLPostClosebuttonElement; "post-collapsible": HTMLPostCollapsibleElement; "post-collapsible-trigger": HTMLPostCollapsibleTriggerElement; + "post-footer": HTMLPostFooterElement; "post-header": HTMLPostHeaderElement; "post-icon": HTMLPostIconElement; "post-language-option": HTMLPostLanguageOptionElement; @@ -929,6 +950,16 @@ declare namespace LocalJSX { */ "type"?: BannerType; } + interface PostBreadcrumb { + /** + * The text label for the home breadcrumb item. + */ + "homeText"?: string; + /** + * The URL for the home breadcrumb item. + */ + "homeUrl"?: string; + } interface PostBreadcrumbItem { /** * The optional URL to which the breadcrumb item will link. @@ -1002,6 +1033,12 @@ declare namespace LocalJSX { */ "for"?: string; } + interface PostFooter { + /** + * The label to add to the footer (visually hidden). + */ + "label": string; + } interface PostHeader { } /** @@ -1046,10 +1083,6 @@ declare namespace LocalJSX { * The ISO 639 language code, formatted according to [RFC 5646 (also known as BCP 47)](https://datatracker.ietf.org/doc/html/rfc5646). For example, "de". */ "code": string; - /** - * Used on parent component (post-language-switch) to detect elements that are manually added - */ - "generated"?: boolean; /** * The full name of the language. For example, "Deutsch". */ @@ -1076,10 +1109,6 @@ declare namespace LocalJSX { * A descriptive text for the list of language options */ "description"?: string; - /** - * The name of the language switch, which will be used on the dropdown as an ID - */ - "name"?: string; /** * Variant that determines the rendering of the language switch either as a list (used on mobile in the header) or a dropdown (used on desktop in the header) */ @@ -1110,12 +1139,16 @@ declare namespace LocalJSX { "onPostToggle"?: (event: PostMainnavigationCustomEvent) => void; } interface PostMegadropdown { + /** + * Emits when the dropdown is shown or hidden. The event payload is a boolean: `true` when the dropdown was opened, `false` when it was closed. + */ + "onPostToggleMegadropdown"?: (event: PostMegadropdownCustomEvent) => void; } interface PostMegadropdownTrigger { /** - * Emits after each toggle + * ID of the mega dropdown element that this trigger is linked to. Used to open and close the specified mega dropdown. */ - "onPostToggle"?: (event: PostMegadropdownTriggerCustomEvent) => void; + "for": string; } interface PostMenu { /** @@ -1255,11 +1288,13 @@ declare namespace LocalJSX { "post-avatar": PostAvatar; "post-back-to-top": PostBackToTop; "post-banner": PostBanner; + "post-breadcrumb": PostBreadcrumb; "post-breadcrumb-item": PostBreadcrumbItem; "post-card-control": PostCardControl; "post-closebutton": PostClosebutton; "post-collapsible": PostCollapsible; "post-collapsible-trigger": PostCollapsibleTrigger; + "post-footer": PostFooter; "post-header": PostHeader; "post-icon": PostIcon; "post-language-option": PostLanguageOption; @@ -1293,6 +1328,7 @@ declare module "@stencil/core" { "post-avatar": LocalJSX.PostAvatar & JSXBase.HTMLAttributes; "post-back-to-top": LocalJSX.PostBackToTop & JSXBase.HTMLAttributes; "post-banner": LocalJSX.PostBanner & JSXBase.HTMLAttributes; + "post-breadcrumb": LocalJSX.PostBreadcrumb & JSXBase.HTMLAttributes; "post-breadcrumb-item": LocalJSX.PostBreadcrumbItem & JSXBase.HTMLAttributes; /** * @class PostCardControl - representing a stencil component @@ -1301,6 +1337,7 @@ declare module "@stencil/core" { "post-closebutton": LocalJSX.PostClosebutton & JSXBase.HTMLAttributes; "post-collapsible": LocalJSX.PostCollapsible & JSXBase.HTMLAttributes; "post-collapsible-trigger": LocalJSX.PostCollapsibleTrigger & JSXBase.HTMLAttributes; + "post-footer": LocalJSX.PostFooter & JSXBase.HTMLAttributes; "post-header": LocalJSX.PostHeader & JSXBase.HTMLAttributes; /** * @class PostIcon - representing a stencil component diff --git a/packages/components/src/components/post-accordion-item/post-accordion-item.tsx b/packages/components/src/components/post-accordion-item/post-accordion-item.tsx index 7421822a10..235d9ce6e1 100644 --- a/packages/components/src/components/post-accordion-item/post-accordion-item.tsx +++ b/packages/components/src/components/post-accordion-item/post-accordion-item.tsx @@ -4,6 +4,8 @@ import { HEADING_LEVELS, HeadingLevel } from '@/types'; import { checkEmptyOrOneOf } from '@/utils'; /** + * @part button - The pseudo-element, used to override styles on the components internal header `button` element. + * @part body - The pseudo-element, used to override styles on the components internal `body` element. * @slot logo - Slot for the placing a logo before the header. * @slot header - Slot for placing custom content within the accordion item's header. * @slot default - Slot for placing content within the accordion item's body. @@ -79,14 +81,19 @@ export class PostAccordionItem { } render() { - const HeadingTag = `h${this.headingLevel ?? 2}`; + const headingLevel = this.host.closest('post-accorddion')?.getAttribute('heading-level'); + const HeadingTag = `h${headingLevel ?? this.headingLevel ?? 2}`; return (
- + + + {visibleItems.map((item) => ( + { + if (e.key === 'Enter' || e.key === ' ') { + const linkElement = (e.currentTarget as HTMLElement).querySelector('a'); + linkElement?.click(); + e.preventDefault(); + } + }} + > + {item.url ? {item.text} : {item.text}} + + ))} + +
+ + ) : ( + visibleItems.map((item) => ( + + {item.text} + + )) + )} + + {this.lastItem && ( + + {this.lastItem.text} + + )} + + + {/* Hidden items for width calculation */} +
+ + {this.homeText} + + + {this.breadcrumbItems.map((item) => ( + + {item.text} + + ))} +
+ +
+ ); + } +} diff --git a/packages/components/src/components/post-breadcrumb/readme.md b/packages/components/src/components/post-breadcrumb/readme.md new file mode 100644 index 0000000000..916ff74906 --- /dev/null +++ b/packages/components/src/components/post-breadcrumb/readme.md @@ -0,0 +1,41 @@ +# post-breadcrumbs-new + + + + + + +## Properties + +| Property | Attribute | Description | Type | Default | +| ---------- | ----------- | -------------------------------------------- | -------- | ----------- | +| `homeText` | `home-text` | The text label for the home breadcrumb item. | `string` | `'Home'` | +| `homeUrl` | `home-url` | The URL for the home breadcrumb item. | `string` | `undefined` | + + +## Dependencies + +### Depends on + +- [post-icon](../post-icon) +- [post-menu-trigger](../post-menu-trigger) +- [post-menu](../post-menu) +- [post-menu-item](../post-menu-item) +- [post-breadcrumb-item](../post-breadcrumb-item) + +### Graph +```mermaid +graph TD; + post-breadcrumb --> post-icon + post-breadcrumb --> post-menu-trigger + post-breadcrumb --> post-menu + post-breadcrumb --> post-menu-item + post-breadcrumb --> post-breadcrumb-item + post-menu --> post-popovercontainer + post-breadcrumb-item --> post-icon + style post-breadcrumb fill:#f9f,stroke:#333,stroke-width:4px +``` + +---------------------------------------------- + +*Built with [StencilJS](https://stenciljs.com/)* diff --git a/packages/components/src/components/post-closebutton/post-closebutton.tsx b/packages/components/src/components/post-closebutton/post-closebutton.tsx index 68d13ef51a..0d447ab844 100644 --- a/packages/components/src/components/post-closebutton/post-closebutton.tsx +++ b/packages/components/src/components/post-closebutton/post-closebutton.tsx @@ -15,7 +15,7 @@ export class PostClosebutton { return ( diff --git a/packages/components/src/components/post-language-switch/readme.md b/packages/components/src/components/post-language-switch/readme.md index c2079be7d3..8beb610dfa 100644 --- a/packages/components/src/components/post-language-switch/readme.md +++ b/packages/components/src/components/post-language-switch/readme.md @@ -9,7 +9,6 @@ | ------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | ----------- | | `caption` | `caption` | A title for the list of language options | `string` | `undefined` | | `description` | `description` | A descriptive text for the list of language options | `string` | `undefined` | -| `name` | `name` | The name of the language switch, which will be used on the dropdown as an ID | `string` | `undefined` | | `variant` | `variant` | Variant that determines the rendering of the language switch either as a list (used on mobile in the header) or a dropdown (used on desktop in the header) | `"dropdown" \| "list"` | `'list'` | diff --git a/packages/components/src/components/post-list-item/post-list-item.tsx b/packages/components/src/components/post-list-item/post-list-item.tsx index fdb5c6b012..14707488ae 100644 --- a/packages/components/src/components/post-list-item/post-list-item.tsx +++ b/packages/components/src/components/post-list-item/post-list-item.tsx @@ -18,7 +18,7 @@ export class PostListItem { render() { return ( - + ); diff --git a/packages/components/src/components/post-mainnavigation/post-mainnavigation.scss b/packages/components/src/components/post-mainnavigation/post-mainnavigation.scss index 7496c6c553..c6f08ed52b 100644 --- a/packages/components/src/components/post-mainnavigation/post-mainnavigation.scss +++ b/packages/components/src/components/post-mainnavigation/post-mainnavigation.scss @@ -1,52 +1,90 @@ @use '@swisspost/design-system-styles/mixins/button'; @use '@swisspost/design-system-styles/mixins/icons'; -@use '@swisspost/design-system-styles/mixins/media'; @use '@swisspost/design-system-styles/mixins/utilities'; +@use '@swisspost/design-system-styles/mixins/media'; @use '@swisspost/design-system-styles/functions/tokens'; @use '@swisspost/design-system-styles/tokens/elements'; @use '@swisspost/design-system-styles/variables/animation'; +@use '@swisspost/design-system-styles/components/header/mixins' as header-mx; + +$nav-height: var(--post-core-dimension-56); post-mainnavigation { // reset links and buttons post-list-item { - a { + > a { text-decoration: none; border-radius: 0; } - button { + post-megadropdown-trigger button { @include button.reset-button; text-align: start; + @include utilities.focus-style; } - a, - button { + > a, + > button, + post-megadropdown-trigger button { + display: flex; + align-items: center; + justify-content: space-between; + &:hover { color: tokens.get('post-link-hover-fg', elements.$post-link); } + + &:focus-visible { + border-radius: var(--post-core-dimension-4); + z-index: 1; + } } } // desktop styles @include media.min(lg) { - post-list > [role="list"] { - flex-direction: row; + nav { + position: relative; + max-width: 100vw; + max-height: $nav-height; + user-select: none; + } + + post-list { + margin-inline: var(--post-core-dimension-4); + + > [role='list'] { + flex-direction: row; + max-width: 100vw; + transition: transform animation.$transition-base-timing; + } } post-list-item { - a, - button { + > a, + > button, + post-megadropdown-trigger button { padding-inline: var(--post-core-dimension-12); - height: var(--post-core-dimension-56); - border-block: var(--post-core-dimension-4) solid transparent; - display: flex; - align-items: center; + height: $nav-height; gap: var(--post-core-dimension-4); font-size: var(--post-core-font-size-16); + border-block: 0 solid transparent; + border-block-end-color: currentColor; + + &:hover { + border-block-width: var(--post-core-dimension-2); + } + + &.selected, + &[aria-expanded='true'] { + border-block-width: var(--post-core-dimension-4); + font-weight: var(--post-core-font-weight-700); + } } // styles specific to for the mega-dropdown buttons - button { + > button, + post-megadropdown-trigger button { padding-inline-end: var(--post-core-dimension-12); transition: border-block-end-color animation.$transition-base-timing; @@ -58,29 +96,29 @@ post-mainnavigation { transition: transform animation.$transition-base-timing; } - &.selected { - border-block-end-color: currentColor; - font-weight: var(--post-core-font-weight-700); - - &::after { - transform: rotate(180deg); - } + &.selected::after, + &[aria-expanded='true']::after { + transform: rotate(180deg); } } } + + [slot='back-button'] { + display: none; + } } // tablet/mobile styles @include media.max(lg) { + post-list > [role='list'] { + transform: none !important; + } + post-list-item { - a, - button { - display: block; - width: 100%; - padding-block: var(--post-core-dimension-12); - padding-inline-end: var(--post-core-dimension-12); - border-bottom: var(--post-core-dimension-1) solid currentColor; - font-weight: var(--post-core-font-weight-700); + > a, + > button, + post-megadropdown-trigger button { + @include header-mx.mobile-header-interactive; } } } diff --git a/packages/components/src/components/post-mainnavigation/post-mainnavigation.tsx b/packages/components/src/components/post-mainnavigation/post-mainnavigation.tsx index dc82772c1b..ad7b8c4557 100644 --- a/packages/components/src/components/post-mainnavigation/post-mainnavigation.tsx +++ b/packages/components/src/components/post-mainnavigation/post-mainnavigation.tsx @@ -1,4 +1,4 @@ -import { Component, Event, EventEmitter, Host, Listen, h } from '@stencil/core'; +import { Component, Event, EventEmitter, Host, h, Element } from '@stencil/core'; @Component({ tag: 'post-mainnavigation', @@ -6,28 +6,31 @@ import { Component, Event, EventEmitter, Host, Listen, h } from '@stencil/core'; styleUrl: './post-mainnavigation.scss', }) export class PostMainnavigation { + private header: HTMLPostHeaderElement | null; + + @Element() host: HTMLPostMainnavigationElement; + /** * Gets emitted when a user closes the main navigation on mobile */ @Event() postToggle: EventEmitter; - @Listen('postToggle') - handleMegadropdownToggled(event) { - // Find next element sibling - let megalodon; - let target = event.target; - while (target !== null) { - if (target.tagName === 'POST-MEGADROPDOWN') { - megalodon = target; - break; - } - target = target.nextElementSibling; - } - if (megalodon) megalodon.toggle(event.target); + /** + * Retrieves a reference to the closest 'post-header' element when the main navigation is added to the DOM. + */ + connectedCallback() { + this.header = this.host.closest('post-header'); + } + + /** + * Cleans up references and disconnects the MutationObserver when the main navigation is removed from the DOM. + */ + disconnectedCallback() { + this.header = null; } private handleBackButtonClick() { - this.postToggle.emit(); + if (this.header) this.header.toggleMobileMenu(); } render() { diff --git a/packages/components/src/components/post-megadropdown-trigger/post-megadropdown-trigger.scss b/packages/components/src/components/post-megadropdown-trigger/post-megadropdown-trigger.scss index 48bb062ea7..33bbd29e3e 100644 --- a/packages/components/src/components/post-megadropdown-trigger/post-megadropdown-trigger.scss +++ b/packages/components/src/components/post-megadropdown-trigger/post-megadropdown-trigger.scss @@ -1,3 +1,3 @@ -:host { - display: inline-block; +post-megadropdown-trigger { + width: 100%; } diff --git a/packages/components/src/components/post-megadropdown-trigger/post-megadropdown-trigger.tsx b/packages/components/src/components/post-megadropdown-trigger/post-megadropdown-trigger.tsx index 246c9d2c95..f63d1add6e 100644 --- a/packages/components/src/components/post-megadropdown-trigger/post-megadropdown-trigger.tsx +++ b/packages/components/src/components/post-megadropdown-trigger/post-megadropdown-trigger.tsx @@ -1,27 +1,83 @@ -import { Component, Event, EventEmitter, Host, State, h } from '@stencil/core'; +import { Component, Element, Prop, h, Host, State, Watch } from '@stencil/core'; +import { version } from '@root/package.json'; +import { checkType } from '@/utils'; @Component({ tag: 'post-megadropdown-trigger', - shadow: true, - styleUrl: './post-megadropdown-trigger.scss', + styleUrl: 'post-megadropdown-trigger.scss', + shadow: false, }) export class PostMegadropdownTrigger { /** - * Emits after each toggle + * ID of the mega dropdown element that this trigger is linked to. Used to open and close the specified mega dropdown. */ - @Event() postToggle: EventEmitter; + @Prop() for!: string; - @State() toggled = false; + @Element() host: HTMLPostMegadropdownTriggerElement; - private handleClick() { - this.toggled = !this.toggled; - this.postToggle.emit(); + /** + * Manages the accessibility attribute `aria-expanded` to indicate whether the associated mega dropdown is expanded or collapsed. + */ + @State() ariaExpanded: boolean = false; + + /** + * Reference to the slotted button within the trigger, if present. + * Used to manage click and key events for mega dropdown control. + */ + private slottedButton: HTMLButtonElement | null = null; + + /** + * Watch for changes to the `for` property to validate its type and ensure it is a string. + * @param forValue - The new value of the `for` property. + */ + @Watch('for') + validateControlFor(forValue = this.for) { + checkType(forValue, 'string', 'The "for" property is required and should be a string.'); + } + + private get megadropdown(): HTMLPostMegadropdownElement | null { + const ref = document.getElementById(this.for); + return ref && ref.localName === 'post-megadropdown' + ? (ref as HTMLPostMegadropdownElement) + : null; + } + + private handleToggle() { + if (this.megadropdown) { + this.megadropdown.toggle(this.host); + } else { + console.warn(`No post-megadropdown found with ID: ${this.for}`); + } + } + + componentDidLoad() { + this.validateControlFor(); + + // Check if the mega dropdown attached to the trigger is expanded or not + document.addEventListener('postToggleMegadropdown', (event: CustomEvent) => { + if ((event.target as HTMLPostMegadropdownElement).id === this.for) { + this.ariaExpanded = event.detail; + if (this.slottedButton) { + this.slottedButton.setAttribute('aria-expanded', this.ariaExpanded.toString()); + } + } + }); + + this.slottedButton = this.host.querySelector('button'); + if (this.slottedButton) { + this.slottedButton.setAttribute('aria-haspopup', 'menu'); + this.slottedButton.addEventListener('click', () => { + this.handleToggle(); + }); + } else { + console.warn('No button found within post-megadropdown-trigger'); + } } render() { return ( - - diff --git a/packages/components/src/components/post-megadropdown-trigger/readme.md b/packages/components/src/components/post-megadropdown-trigger/readme.md index 870d32aabc..9488d51aa9 100644 --- a/packages/components/src/components/post-megadropdown-trigger/readme.md +++ b/packages/components/src/components/post-megadropdown-trigger/readme.md @@ -5,11 +5,11 @@ -## Events +## Properties -| Event | Description | Type | -| ------------ | ----------------------- | ------------------ | -| `postToggle` | Emits after each toggle | `CustomEvent` | +| Property | Attribute | Description | Type | Default | +| ------------------ | --------- | ------------------------------------------------------------------------------------------------------------------- | -------- | ----------- | +| `for` _(required)_ | `for` | ID of the mega dropdown element that this trigger is linked to. Used to open and close the specified mega dropdown. | `string` | `undefined` | ---------------------------------------------- diff --git a/packages/components/src/components/post-megadropdown/post-megadropdown.scss b/packages/components/src/components/post-megadropdown/post-megadropdown.scss index ffc7413fc4..3871f4d11c 100644 --- a/packages/components/src/components/post-megadropdown/post-megadropdown.scss +++ b/packages/components/src/components/post-megadropdown/post-megadropdown.scss @@ -1,6 +1,24 @@ @use '@swisspost/design-system-styles/mixins/media'; @use '@swisspost/design-system-styles/variables/color'; +@keyframes slide-in { + 0% { + transform: translateX(100%); + } + 100% { + transform: translateX(0%); + } +} + +@keyframes slide-out { + from { + transform: translateX(0%); + } + to { + transform: translateX(100%); + } +} + *, ::before, ::after { @@ -8,64 +26,179 @@ } post-popovercontainer { + --post-global-header-height: 72px; + --post-main-header-height: 56px; + --post-header-height: calc(var(--post-global-header-height) + var(--post-main-header-height)); + background-color: #fafafa; + border: none; + border-top: 1px solid #e1e0dc; width: 100%; - border-bottom: 1px solid black; + border-radius: 0; + box-shadow: 0 8px 6px rgba(0, 0, 0, 16%); @include media.max(lg) { - // Overrides floating-ui inline styles on mobile + --post-global-header-height: 64px; position: absolute; - top: var(--header-height) !important; + top: var(--post-header-height) !important; bottom: 0; left: 0; width: 100%; height: auto; + + &.slide-in { + animation: slide-in; + animation-duration: 350ms; + animation-fill-mode: forwards; + } + + &.slide-out { + animation: slide-out; + animation-duration: 350ms; + animation-fill-mode: forwards; + } } } .megadropdown { - display: flex; - gap: 1rem; - padding: 1.5rem; - border-radius: 0 0 3px 3px; + padding: 31px 40px 40px; @include media.max(lg) { - flex-direction: column; + padding: 16px 32px 24px; + } + + .megadropdown-content { + gap: 1.5rem; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(15vw, 100%), 1fr)); + grid-auto-rows: 1fr auto; + grid-auto-flow: dense; + + @include media.max(lg) { + grid-template-columns: repeat(auto-fit, minmax(min(35vw, 100%), 1fr)); + } + + @include media.max(sm) { + grid-template-columns: 1fr; + } + } + + h2 { + display: none; + margin-top: 0; + margin-bottom: 8px; + font-weight: 900; + + a { + text-decoration: none; + font-weight: inherit; + border-bottom: 0; + border-top: 0; + } + + @include media.max(lg) { + display: block; + font-size: 20px; + } + } + + // Unset styles added by parent main navigation + a:hover { + border-block-width: 0; + + &::after { + content: unset; + } } post-list { - display: flex; - flex-direction: column; - gap: 0.5rem; + display: grid; + grid-row: span 2; + grid-template-rows: subgrid; + row-gap: 0px; + + > [role='list'] { + flex-direction: unset; + display: unset; + } + + > * { + width: 100%; + } + + .list-title { + display: flex; + flex-direction: column-reverse; + height: 100%; + + h3 { + font-size: 20px; + border-bottom: 1px solid #050400; + padding: 15px 12px 14px 0; + display: block; + font-weight: 900; + + a { + text-decoration: none; + width: 100%; + font-size: inherit; + display: inline-block; + font-weight: inherit; + height: unset; + padding: 0; + border: 0; + } + + @include media.max(lg) { + font-size: 16px; + padding: 12px 12px 11px 0; + } + } + } } post-list-item { - border-bottom: 1px solid gray; + border-bottom: 1px solid #050400; > a { - padding-block: 0.25rem; + padding: 13px 12px 12px 0; display: block; text-decoration: none; + width: 100%; + border-bottom: 0; + height: auto; + border-top: 0; + + @include media.max(lg) { + padding: 12px 12px 11px 0; + } } } -} -.back-button { - display: none; + .back-button { + display: none; + margin-bottom: 2rem; - @include media.max(lg) { - display: block; - } -} + .btn { + width: auto; + } -post-closebutton { - margin-left: auto; + post-icon { + transform: rotate(180deg); + } - @include media.max(lg) { - display: none; + @include media.max(lg) { + display: block; + } } -} -h3 { - font-size: 20px; + .close-button { + position: absolute; + top: 1rem; + right: 1rem; + + @include media.max(lg) { + display: none; + } + } } diff --git a/packages/components/src/components/post-megadropdown/post-megadropdown.tsx b/packages/components/src/components/post-megadropdown/post-megadropdown.tsx index 3709c59e5a..03d0ff5db9 100644 --- a/packages/components/src/components/post-megadropdown/post-megadropdown.tsx +++ b/packages/components/src/components/post-megadropdown/post-megadropdown.tsx @@ -1,56 +1,105 @@ -import { Component, Host, Method, h } from '@stencil/core'; +import { Component, Element, Event, EventEmitter, h, Host, Method, State } from '@stencil/core'; @Component({ tag: 'post-megadropdown', + styleUrl: 'post-megadropdown.scss', shadow: false, - styleUrl: './post-megadropdown.scss', }) export class PostMegadropdown { private popoverRef: HTMLPostPopovercontainerElement; + @Element() host: HTMLPostMegadropdownElement; + /** - * Show megadropdown - * @param element HTMLElement - * @returns boolean + * Holds the current visibility state of the dropdown. + * This state is internally managed to track whether the dropdown is open (`true`) or closed (`false`), + * and updates automatically when the dropdown is toggled. */ - @Method() - async show(element: HTMLElement) { - return this.popoverRef.show(element); + @State() isVisible: boolean = false; + + @State() animationClass: string | null = null; + + /** + * Emits when the dropdown is shown or hidden. + * The event payload is a boolean: `true` when the dropdown was opened, `false` when it was closed. + **/ + @Event() postToggleMegadropdown: EventEmitter; + + componentDidLoad() { + this.popoverRef.addEventListener('postToggle', (event: CustomEvent) => { + this.isVisible = event.detail; + this.postToggleMegadropdown.emit(this.isVisible); + }); + + this.popoverRef.addEventListener('animationend', () => { + if (this.animationClass === 'slide-out') { + this.hide(); + } + }); } /** - * Hide megadropdown - * @returns boolean + * Toggles the dropdown visibility based on its current state. */ @Method() - async hide() { - return this.popoverRef.hide(); + async toggle(target: HTMLElement) { + this.isVisible ? this.hide() : await this.show(target); } /** - * Toggle megadropdown - * @param element HTMLElement - * @param force boolean - * @returns boolean + * Displays the popover dropdown + * + * @param target - The HTML element relative to which the popover dropdown should be displayed. */ @Method() - async toggle(element: HTMLElement, force?: boolean) { - return this.popoverRef.toggle(element, force ?? undefined); + async show(target: HTMLElement) { + if (this.popoverRef) { + await this.popoverRef.show(target); + this.animationClass = 'slide-in'; + } else { + console.error('show: popoverRef is null or undefined'); + } + } + + /** + * Hides the popover dropdown + */ + private hide() { + if (this.popoverRef) { + this.popoverRef.hide(); + } else { + console.error('hide: popoverRef is null or undefined'); + } } private handleBackButtonClick() { - this.hide(); + this.animationClass = 'slide-out'; + } + + private handleCloseButtonClick() { + this.popoverRef.hide(); } render() { return ( - - (this.popoverRef = el)}> + + (this.popoverRef = el)} + >
this.handleBackButtonClick()} class="back-button">
- +
this.handleCloseButtonClick()} class="close-button"> + +
+ +
+ +
diff --git a/packages/components/src/components/post-megadropdown/readme.md b/packages/components/src/components/post-megadropdown/readme.md index 532147ae8e..368d1a787f 100644 --- a/packages/components/src/components/post-megadropdown/readme.md +++ b/packages/components/src/components/post-megadropdown/readme.md @@ -5,50 +5,46 @@ -## Methods - -### `hide() => Promise` +## Events -Hide megadropdown +| Event | Description | Type | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | +| `postToggleMegadropdown` | Emits when the dropdown is shown or hidden. The event payload is a boolean: `true` when the dropdown was opened, `false` when it was closed. | `CustomEvent` | -#### Returns - -Type: `Promise` -boolean +## Methods -### `show(element: HTMLElement) => Promise` +### `show(target: HTMLElement) => Promise` -Show megadropdown +Displays the popover dropdown #### Parameters -| Name | Type | Description | -| --------- | ------------- | ----------- | -| `element` | `HTMLElement` | HTMLElement | +| Name | Type | Description | +| -------- | ------------- | ------------------------------------------------------------------------------ | +| `target` | `HTMLElement` | - The HTML element relative to which the popover dropdown should be displayed. | #### Returns Type: `Promise` -boolean -### `toggle(element: HTMLElement, force?: boolean) => Promise` -Toggle megadropdown +### `toggle(target: HTMLElement) => Promise` + +Toggles the dropdown visibility based on its current state. #### Parameters -| Name | Type | Description | -| --------- | ------------- | ----------- | -| `element` | `HTMLElement` | HTMLElement | -| `force` | `boolean` | boolean | +| Name | Type | Description | +| -------- | ------------- | ----------- | +| `target` | `HTMLElement` | | #### Returns -Type: `Promise` +Type: `Promise` + -boolean ## Dependencies diff --git a/packages/components/src/components/post-menu-item/readme.md b/packages/components/src/components/post-menu-item/readme.md index d6c88bc316..eeeef359b7 100644 --- a/packages/components/src/components/post-menu-item/readme.md +++ b/packages/components/src/components/post-menu-item/readme.md @@ -5,6 +5,19 @@ +## Dependencies + +### Used by + + - [post-breadcrumb](../post-breadcrumb) + +### Graph +```mermaid +graph TD; + post-breadcrumb --> post-menu-item + style post-menu-item fill:#f9f,stroke:#333,stroke-width:4px +``` + ---------------------------------------------- *Built with [StencilJS](https://stenciljs.com/)* diff --git a/packages/components/src/components/post-menu-trigger/readme.md b/packages/components/src/components/post-menu-trigger/readme.md index 5198f2ceaf..d8af67b195 100644 --- a/packages/components/src/components/post-menu-trigger/readme.md +++ b/packages/components/src/components/post-menu-trigger/readme.md @@ -16,11 +16,13 @@ ### Used by + - [post-breadcrumb](../post-breadcrumb) - [post-language-switch](../post-language-switch) ### Graph ```mermaid graph TD; + post-breadcrumb --> post-menu-trigger post-language-switch --> post-menu-trigger style post-menu-trigger fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/packages/components/src/components/post-menu/post-menu.tsx b/packages/components/src/components/post-menu/post-menu.tsx index dd5c90f3bf..865a24a729 100644 --- a/packages/components/src/components/post-menu/post-menu.tsx +++ b/packages/components/src/components/post-menu/post-menu.tsx @@ -2,6 +2,7 @@ import { Component, Element, Event, EventEmitter, h, Host, Method, Prop, State } import { Placement } from '@floating-ui/dom'; import { version } from '@root/package.json'; import { isFocusable } from '@/utils/is-focusable'; +import { getRoot } from '@/utils'; @Component({ tag: 'post-menu', @@ -20,7 +21,7 @@ export class PostMenu { TAB: 'Tab', HOME: 'Home', END: 'End', - ESCAPE: 'Escape' + ESCAPE: 'Escape', }; @Element() host: HTMLPostMenuElement; @@ -45,7 +46,10 @@ export class PostMenu { **/ @Event() toggleMenu: EventEmitter; + private root?: Document | ShadowRoot; + connectedCallback() { + this.root = getRoot(this.host); this.host.addEventListener('keydown', this.handleKeyDown); this.host.addEventListener('click', this.handleClick); } @@ -79,7 +83,7 @@ export class PostMenu { async show(target: HTMLElement) { if (this.popoverRef) { await this.popoverRef.show(target); - this.lastFocusedElement = document.activeElement as HTMLElement; + this.lastFocusedElement = this.root.activeElement as HTMLElement; // Use root's activeElement const menuItems = this.getSlottedItems(); if (menuItems.length > 0) { @@ -131,7 +135,7 @@ export class PostMenu { return; } - const currentFocusedElement = document.activeElement as HTMLElement; + const currentFocusedElement = this.root.activeElement as HTMLElement; // Use root's activeElement let currentIndex = menuItems.findIndex(el => el === currentFocusedElement); switch (e.key) { @@ -185,7 +189,7 @@ export class PostMenu { return ( (this.popoverRef = e)}> -
+
diff --git a/packages/components/src/components/post-menu/readme.md b/packages/components/src/components/post-menu/readme.md index 2372e47c18..3361253421 100644 --- a/packages/components/src/components/post-menu/readme.md +++ b/packages/components/src/components/post-menu/readme.md @@ -64,10 +64,18 @@ Type: `Promise` +## Shadow Parts + +| Part | Description | +| --------------------- | ----------- | +| `"popover-container"` | | + + ## Dependencies ### Used by + - [post-breadcrumb](../post-breadcrumb) - [post-language-switch](../post-language-switch) ### Depends on @@ -78,6 +86,7 @@ Type: `Promise` ```mermaid graph TD; post-menu --> post-popovercontainer + post-breadcrumb --> post-menu post-language-switch --> post-menu style post-menu fill:#f9f,stroke:#333,stroke-width:4px ``` diff --git a/packages/components/src/components/post-tabs/post-tabs.tsx b/packages/components/src/components/post-tabs/post-tabs.tsx index b03617b3bc..22f5a8400f 100644 --- a/packages/components/src/components/post-tabs/post-tabs.tsx +++ b/packages/components/src/components/post-tabs/post-tabs.tsx @@ -21,9 +21,11 @@ export class PostTabs { private hiding: Animation; private isLoaded = false; - private get tabs(): NodeListOf { - return this.host.querySelectorAll('post-tab-header'); - } + private get tabs(): HTMLPostTabHeaderElement[] { + return Array.from(this.host.querySelectorAll('post-tab-header')).filter(tab => + tab.closest('post-tabs') === this.host + ); + } @Element() host: HTMLPostTabsElement; @@ -45,7 +47,7 @@ export class PostTabs { this.moveMisplacedTabs(); this.enableTabs(); - const initiallyActivePanel = this.activePanel || this.tabs.item(0).panel; + const initiallyActivePanel = this.activePanel || this.tabs[0]?.panel; void this.show(initiallyActivePanel); this.isLoaded = true; @@ -128,7 +130,7 @@ export class PostTabs { // if the currently active tab was removed from the DOM then select the first one if (this.activeTab && !this.activeTab.isConnected) { - void this.show(this.tabs.item(0).panel); + void this.show(this.tabs[0]?.panel); } } diff --git a/packages/components/src/components/post-togglebutton/post-togglebutton.scss b/packages/components/src/components/post-togglebutton/post-togglebutton.scss index 3657761313..88ee2219af 100644 --- a/packages/components/src/components/post-togglebutton/post-togglebutton.scss +++ b/packages/components/src/components/post-togglebutton/post-togglebutton.scss @@ -1,3 +1,30 @@ +@use '@swisspost/design-system-styles/mixins/utilities'; +@use '@swisspost/design-system-styles/functions/tokens'; +@use '@swisspost/design-system-styles/tokens/helpers'; + :host { cursor: pointer; + outline-offset: tokens.get('focus-outline-offset', helpers.$post-focus) !important; + outline: tokens.get('focus-outline-color', helpers.$post-focus) none + tokens.get('focus-outline-width', helpers.$post-focus) !important; +} + +:host(:focus-visible) { + outline-style: tokens.get('focus-border-style', helpers.$post-focus) !important; + + @include utilities.high-contrast-mode() { + outline-color: Highlight !important; + } +} + +:host([aria-pressed="true"]) { + ::slotted([data-showwhen="untoggled"]) { + display: none; + } +} + +:host([aria-pressed="false"]) { + ::slotted([data-showwhen="toggled"]) { + display: none; + } } diff --git a/packages/components/src/components/post-togglebutton/post-togglebutton.tsx b/packages/components/src/components/post-togglebutton/post-togglebutton.tsx index 0f5d884884..b0eb329d9d 100644 --- a/packages/components/src/components/post-togglebutton/post-togglebutton.tsx +++ b/packages/components/src/components/post-togglebutton/post-togglebutton.tsx @@ -1,9 +1,9 @@ -import { Component, Host, h, Prop } from '@stencil/core'; +import { Component, Host, h, Prop, Watch, Element } from '@stencil/core'; import { version } from '@root/package.json'; +import { checkType } from '@/utils'; /** - * @slot toggled - Slot for content displayed when the button is in the "on" state. - * @slot untoggled - Slot for content displayed when the button is in the "off" state. + * @slot default - Slot for the content of the button. */ @Component({ @@ -12,18 +12,39 @@ import { version } from '@root/package.json'; shadow: true, }) export class PostTogglebutton { + @Element() host: HTMLPostTogglebuttonElement; + /** * If `true`, the button is in the "on" state, otherwise it is in the "off" state. */ - @Prop({ reflect: true, mutable: true }) toggled: boolean = false; + @Prop({ mutable: true }) toggled: boolean = false; + + @Watch('toggled') + validateToggled(value = this.toggled) { + checkType( + value, + 'boolean', + 'The "toggled" property of the post-togglebutton must be a boolean.', + ); + } + + componentWillLoad() { + this.validateToggled(); + + // add event listener to not override listener that might be set on the host + this.host.addEventListener('click', () => this.handleClick()); + this.host.addEventListener('keydown', (e: KeyboardEvent) => this.handleKeydown(e)); + } private handleClick = () => { this.toggled = !this.toggled; }; private handleKeydown = (event: KeyboardEvent) => { - if (event.key === 'Enter') { - this.toggled = !this.toggled; + // perform a click when enter or spaced are pressed to mimic the button behavior + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); // prevents the page from scrolling when space is pressed + this.host.click(); } }; @@ -31,19 +52,12 @@ export class PostTogglebutton { return ( - - + ); } diff --git a/packages/components/src/components/post-togglebutton/readme.md b/packages/components/src/components/post-togglebutton/readme.md index 7a5198c2dc..4d3c6be785 100644 --- a/packages/components/src/components/post-togglebutton/readme.md +++ b/packages/components/src/components/post-togglebutton/readme.md @@ -14,10 +14,9 @@ ## Slots -| Slot | Description | -| ------------- | ----------------------------------------------------------------- | -| `"toggled"` | Slot for content displayed when the button is in the "on" state. | -| `"untoggled"` | Slot for content displayed when the button is in the "off" state. | +| Slot | Description | +| ----------- | ----------------------------------- | +| `"default"` | Slot for the content of the button. | ---------------------------------------------- diff --git a/packages/components/src/index.html b/packages/components/src/index.html index 172bd137c5..60605cbfb7 100644 --- a/packages/components/src/index.html +++ b/packages/components/src/index.html @@ -22,12 +22,16 @@ - = Menu + + Menu + + + Application title - @@ -66,10 +80,14 @@

Main Navigation

- Briefe - - -

Briefe title

+ Briefe + + + Schliessen +

Briefe title

Briefe senden

Briefe Schweiz @@ -84,14 +102,17 @@

Schritt für Schritt

Waren Ausland Express und Kurier
- Schliessen
- Pakete - - -

Pakete title

+ Pakete + + + Schliessen +

Pakete title

Pakete senden

Pakete Schweiz @@ -106,7 +127,6 @@

Schritt für Schritt

Waren Ausland Express und Kurier
- Schliessen
diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index 8dd02245f9..ee02397ab8 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -3,33 +3,35 @@ export { Components, JSX } from './components'; // Export every single component so it gets included in the dist output export { PostAccordion } from './components/post-accordion/post-accordion'; export { PostAccordionItem } from './components/post-accordion-item/post-accordion-item'; +export { PostAvatar } from './components/post-avatar/post-avatar'; export { PostBackToTop } from './components/post-back-to-top/post-back-to-top'; export { PostBanner } from './components/post-banner/post-banner'; +export { PostBreadcrumb } from './components/post-breadcrumb/post-breadcrumb'; export { PostBreadcrumbItem } from './components/post-breadcrumb-item/post-breadcrumb-item'; -export { PostAvatar } from './components/post-avatar/post-avatar'; export { PostCardControl } from './components/post-card-control/post-card-control'; export { PostClosebutton } from './components/post-closebutton/post-closebutton'; export { PostCollapsible } from './components/post-collapsible/post-collapsible'; export { PostCollapsibleTrigger } from './components/post-collapsible-trigger/post-collapsible-trigger'; +export { PostFooter } from './components/post-footer/post-footer'; +export { PostHeader } from './components/post-header/post-header'; export { PostIcon } from './components/post-icon/post-icon'; export { PostLanguageOption } from './components/post-language-option/post-language-option'; export { PostLanguageSwitch } from './components/post-language-switch/post-language-switch'; +export { PostList } from './components/post-list/post-list'; +export { PostListItem } from './components/post-list-item/post-list-item'; export { PostLogo } from './components/post-logo/post-logo'; +export { PostMainnavigation } from './components/post-mainnavigation/post-mainnavigation'; +export { PostMegadropdown } from './components/post-megadropdown/post-megadropdown'; +export { PostMegadropdownTrigger } from './components/post-megadropdown-trigger/post-megadropdown-trigger'; export { PostMenu } from './components/post-menu/post-menu'; -export { PostMenuTrigger } from './components/post-menu-trigger/post-menu-trigger'; export { PostMenuItem } from './components/post-menu-item/post-menu-item'; +export { PostMenuTrigger } from './components/post-menu-trigger/post-menu-trigger'; export { PostPopover } from './components/post-popover/post-popover'; export { PostPopovercontainer } from './components/post-popovercontainer/post-popovercontainer'; export { PostRating } from './components/post-rating/post-rating'; export { PostTabs } from './components/post-tabs/post-tabs'; export { PostTabHeader } from './components/post-tab-header/post-tab-header'; export { PostTabPanel } from './components/post-tab-panel/post-tab-panel'; -export { PostTooltip } from './components/post-tooltip/post-tooltip'; export { PostTag } from './components/post-tag/post-tag'; export { PostTogglebutton } from './components/post-togglebutton/post-togglebutton'; -export { PostList } from './components/post-list/post-list'; -export { PostListItem } from './components/post-list-item/post-list-item'; -export { PostHeader } from './components/post-header/post-header'; -export { PostMainnavigation } from './components/post-mainnavigation/post-mainnavigation'; -export { PostMegadropdown } from './components/post-megadropdown/post-megadropdown'; -export { PostMegadropdownTrigger } from './components/post-megadropdown-trigger/post-megadropdown-trigger'; +export { PostTooltip } from './components/post-tooltip/post-tooltip'; diff --git a/packages/components/src/utils/breakpoints.ts b/packages/components/src/utils/breakpoints.ts new file mode 100644 index 0000000000..01e5066434 --- /dev/null +++ b/packages/components/src/utils/breakpoints.ts @@ -0,0 +1,61 @@ +type MapItem = { + minWidth: number; + key: string; + name: string; +}; +type ListenerType = 'key' | 'name'; + +export class Breakpoint { + private readonly breakpointMap: MapItem[]; + private readonly current = { + key: '', + name: '', + }; + + constructor() { + if (!this.breakpointMap) { + const styles = getComputedStyle(document.documentElement); + const keys = styles.getPropertyValue('--post-breakpoint-keys').split(', '); + const names = styles.getPropertyValue('--post-breakpoint-names').split(', '); + + this.breakpointMap = styles + .getPropertyValue('--post-breakpoint-widths') + .split(', ') + .map((width, i) => { + return { + minWidth: Number(width), + key: keys[i], + name: names[i], + }; + }) + .reverse(); + + window.addEventListener('resize', () => this.updateHandler(), { passive: true }); + } + } + + private updateHandler(emitEvents = true) { + const calculated = this.breakpointMap.find(({ minWidth }) => innerWidth >= minWidth); + + if (this.current.key !== calculated.key) { + this.current.key = calculated.key; + if (emitEvents) this.dispatchEvent('key'); + } + + if (this.current.name !== calculated.name) { + this.current.name = calculated.name; + if (emitEvents) this.dispatchEvent('name'); + } + } + + private dispatchEvent(type: ListenerType) { + window.dispatchEvent(new CustomEvent(`postBreakpoint:${type}`, { detail: this.current[type] })); + } + + public get(type: ListenerType) { + this.updateHandler(false); + return this.current[type]; + } +} + +export const breakpoint = new Breakpoint(); diff --git a/packages/components/src/utils/tests/index.spec.ts b/packages/components/src/utils/tests/index.spec.ts new file mode 100644 index 0000000000..91b04ea5b8 --- /dev/null +++ b/packages/components/src/utils/tests/index.spec.ts @@ -0,0 +1,16 @@ +import * as fs from 'fs'; + +const file = fs.readFileSync('./src/utils/index.ts').toString(); +const exportModuleMatches = file.matchAll(/^export \* from '(?:\.\/)?(.*)';$/gm); +const exportModuleNames = [...exportModuleMatches].map(m => m[1]); +const exportModuleExceptionNames = ['breakpoint']; + +describe('packages/components/src/utils/index.ts', () => { + exportModuleExceptionNames.forEach(moduleName => { + const exportModuleName = exportModuleNames.find(m => m === moduleName); + + it(`should NOT export utility "${moduleName}"`, () => { + expect(exportModuleName).toBeUndefined(); + }); + }); +}); diff --git a/packages/documentation/.storybook/manager.ts b/packages/documentation/.storybook/manager.ts index c52ce3e90d..ec30bb63de 100644 --- a/packages/documentation/.storybook/manager.ts +++ b/packages/documentation/.storybook/manager.ts @@ -17,6 +17,7 @@ addons.setConfig({ 'layout', 'raw-components', 'components', + 'modules', 'utilities', 'templates', 'guidelines', diff --git a/packages/documentation/.storybook/preview.ts b/packages/documentation/.storybook/preview.ts index e10fe379cf..c5ff54491d 100644 --- a/packages/documentation/.storybook/preview.ts +++ b/packages/documentation/.storybook/preview.ts @@ -54,6 +54,10 @@ const preview: Preview = { // Category - Components 'Components', + // Category - Modules + 'Modules', + ['Header', 'Footer'], + // Category - Utilities 'Utilities', diff --git a/packages/documentation/CHANGELOG.md b/packages/documentation/CHANGELOG.md index b7c127a363..9ea15657c3 100644 --- a/packages/documentation/CHANGELOG.md +++ b/packages/documentation/CHANGELOG.md @@ -1,5 +1,32 @@ # @swisspost/design-system-documentation +## 6.0.0-next.10 + +### Minor Changes + +- Added the `post-breadcrumb` component to provide a standalone breadcrumb navigation solution. (by [@alionazherdetska](https://github.com/alionazherdetska) with [#4065](https://github.com/swisspost/design-system/pull/4065)) + +- Updated the utility classes for sizing. (by [@myrta2302](https://github.com/myrta2302) with [#4012](https://github.com/swisspost/design-system/pull/4012)) + +- Added the css parts `button` and `body` in the `post-accorddion-item` component. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + +- Updated `.btn-link` to look like a regular link and old `.btn-link` is now `.btn-tertiary .px-0`. (by [@leagrdv](https://github.com/leagrdv) with [#4200](https://github.com/swisspost/design-system/pull/4200)) + +- Implemented new pixel based sizes. (by [@myrta2302](https://github.com/myrta2302) with [#4012](https://github.com/swisspost/design-system/pull/4012)) + +- Added the `post-language-switch` component that enables users to change the language of a page. (by [@leagrdv](https://github.com/leagrdv) with [#4044](https://github.com/swisspost/design-system/pull/4044)) + +### Patch Changes + +- Updated the `post-togglebutton` component to offer greater flexibility. You can now control the visibility of elements within the `post-togglebutton` using the `data-showwhen="toggled"` and `data-showwhen="untoggled"` attributes. Any content without a `data-showwhen` attribute will always be visible, regardless of the toggle state. (by [@alizedebray](https://github.com/alizedebray) with [#4223](https://github.com/swisspost/design-system/pull/4223)) +- Updated dependencies: + - @swisspost/design-system-components@9.0.0-next.9 + - @swisspost/design-system-styles@9.0.0-next.9 + - @swisspost/design-system-components-react@9.0.0-next.9 + - @swisspost/internet-header@2.0.0-next.9 + - @swisspost/design-system-tokens@9.0.0-next.9 + - @swisspost/design-system-icons@9.0.0-next.9 + ## 6.0.0-next.9 ### Major Changes diff --git a/packages/documentation/cypress/snapshots/components/breadcrumb.snapshot.ts b/packages/documentation/cypress/snapshots/components/breadcrumb.snapshot.ts new file mode 100644 index 0000000000..d8757cd4dd --- /dev/null +++ b/packages/documentation/cypress/snapshots/components/breadcrumb.snapshot.ts @@ -0,0 +1,7 @@ +describe('Breadcrumb', () => { + it('default', () => { + cy.visit('/iframe.html?id=snapshots--breadcrumb'); + cy.get('post-breadcrumb.hydrated', { timeout: 30000 }).should('be.visible'); + cy.percySnapshot('Breadcrumb', { widths: [400] }); + }); +}); diff --git a/packages/documentation/cypress/snapshots/modules/footer.snapshot.ts b/packages/documentation/cypress/snapshots/modules/footer.snapshot.ts new file mode 100644 index 0000000000..634b8645c0 --- /dev/null +++ b/packages/documentation/cypress/snapshots/modules/footer.snapshot.ts @@ -0,0 +1,7 @@ +describe('Footer', () => { + it('default', () => { + cy.visit('/iframe.html?id=snapshots--footer'); + cy.get('post-footer[data-hydrated]', { timeout: 30000 }).should('be.visible'); + cy.percySnapshot('Footer', { widths: [320, 600, 1024, 1440] }); + }); +}); diff --git a/packages/documentation/cypress/snapshots/utilities/sizing.snapshot.ts b/packages/documentation/cypress/snapshots/utilities/sizing.snapshot.ts new file mode 100644 index 0000000000..e539797cc7 --- /dev/null +++ b/packages/documentation/cypress/snapshots/utilities/sizing.snapshot.ts @@ -0,0 +1,22 @@ +describe('Sizing', () => { + // Parent based sizing classes [e.g. .quarter, .third, .half, etc.] + it('Sizing Percentages', () => { + cy.visit('/iframe.html?id=snapshots--percentage-sizing'); + cy.get('.snapshot', { timeout: 30000 }).should('be.visible'); + cy.percySnapshot('Sizing', { widths: [320, 1440] }); + }); + + // Percentage sizing classes relative to viewport [e.g. vh-25, vw-33, min-vh-50, max-vw-100, etc.] + it('Sizing Viewport Percentages', () => { + cy.visit('/iframe.html?id=snapshots--percentage-vp-sizing'); + cy.get('.snapshot', { timeout: 30000 }).should('be.visible'); + cy.percySnapshot('Sizing', { widths: [320, 1440] }); + }); + + // Pixel based sizing classes [e.g. h-80, w-56, max-w-24, min-h-24, etc.] + it('Sizing Pixel Based', () => { + cy.visit('/iframe.html?id=snapshots--pixel-sizing'); + cy.get('.snapshot', { timeout: 30000 }).should('be.visible'); + cy.percySnapshot('Sizing', { widths: [320, 1440] }); + }); +}); diff --git a/packages/documentation/package.json b/packages/documentation/package.json index 6c16faee3d..275e7f7bf1 100644 --- a/packages/documentation/package.json +++ b/packages/documentation/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-documentation", - "version": "6.0.0-next.9", + "version": "6.0.0-next.10", "description": "Swiss Post Design System Documentation.", "author": "Swiss Post ", "license": "Apache-2.0", @@ -28,12 +28,12 @@ "lint": "eslint **/*.{ts,tsx,mdx}" }, "dependencies": { - "@swisspost/design-system-components": "workspace:9.0.0-next.8", - "@swisspost/design-system-components-react": "workspace:9.0.0-next.8", - "@swisspost/design-system-icons": "workspace:9.0.0-next.8", - "@swisspost/design-system-styles": "workspace:9.0.0-next.8", - "@swisspost/design-system-tokens": "workspace:9.0.0-next.8", - "@swisspost/internet-header": "workspace:2.0.0-next.8", + "@swisspost/design-system-components": "workspace:9.0.0-next.9", + "@swisspost/design-system-components-react": "workspace:9.0.0-next.9", + "@swisspost/design-system-icons": "workspace:9.0.0-next.9", + "@swisspost/design-system-styles": "workspace:9.0.0-next.9", + "@swisspost/design-system-tokens": "workspace:9.0.0-next.9", + "@swisspost/internet-header": "workspace:2.0.0-next.9", "bootstrap": "5.3.3" }, "devDependencies": { @@ -54,8 +54,8 @@ "@storybook/types": "8.3.6", "@storybook/web-components": "8.3.6", "@storybook/web-components-vite": "8.3.6", - "@swisspost/design-system-components-angular": "workspace:9.0.0-next.8", - "@swisspost/design-system-intranet-header": "workspace:9.0.0-next.8", + "@swisspost/design-system-components-angular": "workspace:9.0.0-next.9", + "@swisspost/design-system-intranet-header": "workspace:9.0.0-next.9", "@types/css-modules": "1.0.5", "@types/mdx": "2.0.13", "@types/react": "18.3.3", diff --git a/packages/documentation/public/_redirects b/packages/documentation/public/_redirects index 9537b51f5f..a9163cf506 100644 --- a/packages/documentation/public/_redirects +++ b/packages/documentation/public/_redirects @@ -11,3 +11,4 @@ + diff --git a/packages/documentation/public/assets/versions.json b/packages/documentation/public/assets/versions.json index 3aff9f35d1..8c103ea1da 100644 --- a/packages/documentation/public/assets/versions.json +++ b/packages/documentation/public/assets/versions.json @@ -1,7 +1,7 @@ [ { "title": "Version 9", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "Pattern documentation, code snippets and implementation guidelines for the Design System Styles.", "url": "https://design-system.post.ch", "dependencies": { @@ -9,22 +9,50 @@ "@ng-bootstrap/ng-bootstrap": "^17.0.0", "bootstrap": "~5.3.0", "@swisspost/design-system-changelog-github": "1.0.2", - "@swisspost/design-system-components": "9.0.0-next.8", - "@swisspost/design-system-components-angular-workspace": "1.1.10-next.8", - "@swisspost/design-system-components-angular": "9.0.0-next.8", - "@swisspost/design-system-components-react": "9.0.0-next.8", - "@swisspost/design-system-documentation": "6.0.0-next.9", - "@swisspost/design-system-icons": "9.0.0-next.8", - "@swisspost/internet-header": "2.0.0-next.8", - "@swisspost/design-system-intranet-header-workspace": "3.0.22-next.8", - "@swisspost/design-system-intranet-header": "9.0.0-next.8", - "@swisspost/design-system-intranet-header-showcase": "1.0.10-next.8", - "@swisspost/design-system-migrations": "9.0.0-next.8", - "@swisspost/design-system-nextjs-integration": "0.1.14-next.8", - "@swisspost/design-system-styles": "9.0.0-next.8", - "@swisspost/design-system-styles-primeng-workspace": "1.0.6-next.8", - "@swisspost/design-system-styles-primeng": "9.0.0-next.8", - "@swisspost/design-system-tokens": "9.0.0-next.8" + "@swisspost/design-system-components": "9.0.0-next.9", + "@swisspost/design-system-components-angular-workspace": "1.1.10-next.9", + "@swisspost/design-system-components-angular": "9.0.0-next.9", + "@swisspost/design-system-components-react": "9.0.0-next.9", + "@swisspost/design-system-documentation": "6.0.0-next.10", + "@swisspost/design-system-icons": "9.0.0-next.9", + "@swisspost/internet-header": "2.0.0-next.9", + "@swisspost/design-system-intranet-header-workspace": "3.0.22-next.9", + "@swisspost/design-system-intranet-header": "9.0.0-next.9", + "@swisspost/design-system-intranet-header-showcase": "1.0.10-next.9", + "@swisspost/design-system-migrations": "9.0.0-next.9", + "@swisspost/design-system-nextjs-integration": "0.1.14-next.9", + "@swisspost/design-system-styles": "9.0.0-next.9", + "@swisspost/design-system-styles-primeng-workspace": "1.0.6-next.9", + "@swisspost/design-system-styles-primeng": "9.0.0-next.9", + "@swisspost/design-system-tokens": "9.0.0-next.9" + } + }, + { + "title": "Version 9", + "version": "9.0.0-next.8", + "description": "Pattern documentation, code snippets and implementation guidelines for the Design System Styles.", + "url": "https://swisspost-design-system-version-9.netlify.app", + "dependencies": { + "@angular/core": "^18.0.0", + "@ng-bootstrap/ng-bootstrap": "^17.0.0", + "bootstrap": "~5.3.0", + "@swisspost/design-system-changelog-github": "1.0.2", + "@swisspost/design-system-components": "9.0.0-next.2", + "@swisspost/design-system-components-angular-workspace": "1.1.10-next.2", + "@swisspost/design-system-components-angular": "9.0.0-next.2", + "@swisspost/design-system-components-react": "9.0.0-next.2", + "@swisspost/design-system-documentation": "6.0.0-next.2", + "@swisspost/design-system-icons": "9.0.0-next.2", + "@swisspost/internet-header": "1.14.6-next.2", + "@swisspost/design-system-intranet-header-workspace": "3.0.22-next.2", + "@swisspost/design-system-intranet-header": "9.0.0-next.2", + "@swisspost/design-system-intranet-header-showcase": "1.0.10-next.2", + "@swisspost/design-system-migrations": "9.0.0-next.2", + "@swisspost/design-system-nextjs-integration": "0.1.14-next.2", + "@swisspost/design-system-styles": "9.0.0-next.2", + "@swisspost/design-system-styles-primeng-workspace": "1.0.6-next.2", + "@swisspost/design-system-styles-primeng": "9.0.0-next.2", + "@swisspost/design-system-tokens": "9.0.0-next.2" } }, { diff --git a/packages/documentation/src/stories/components/accordion/accordion-item.stories.ts b/packages/documentation/src/stories/components/accordion/accordion-item.stories.ts index b1063223b5..879ded9536 100644 --- a/packages/documentation/src/stories/components/accordion/accordion-item.stories.ts +++ b/packages/documentation/src/stories/components/accordion/accordion-item.stories.ts @@ -12,15 +12,33 @@ const meta: Meta = { }, }, argTypes: { - collapsed: { + 'collapsed': { control: false, // disable the control since it is not usable on the story }, - headingLevel: { + 'headingLevel': { name: 'heading-level', control: false, // disable the control since it is not usable on the story table: { - disable:true, - } + disable: true, + }, + }, + 'css-shadow-parts-button': { + name: 'button', + table: { + type: { + summary: 'css selector', + detail: '::part(button) { ... }', + }, + }, + }, + 'css-shadow-parts-body': { + name: 'body', + table: { + type: { + summary: 'css selector', + detail: '::part(body) { ... }', + }, + }, }, }, }; diff --git a/packages/documentation/src/stories/components/breadcrumb/breadcrumb.mdx b/packages/documentation/src/stories/components/breadcrumb/breadcrumb.mdx new file mode 100644 index 0000000000..3e546a981a --- /dev/null +++ b/packages/documentation/src/stories/components/breadcrumb/breadcrumb.mdx @@ -0,0 +1,29 @@ +import { Meta, Canvas, Controls } from '@storybook/blocks'; +import * as BreadcrumbStories from './breadcrumb.stories'; + + + +# Post Breadcrumb + +
+ The breadcrumb is a secondary navigation pattern that helps users understand the hierarchy among levels and navigate back through them. +
+ +The `` is a container for `` components, used to display a navigational trail, showing the user's location within the app and enabling quick access to parent pages. + +## `` + + + + +## Concatenated Breadcrumb + +When space is constrained, the breadcrumb concatenates middle items into a dropdown menu. + + + + +## `` + + + diff --git a/packages/documentation/src/stories/components/breadcrumb/breadcrumb.snapshot.stories.ts b/packages/documentation/src/stories/components/breadcrumb/breadcrumb.snapshot.stories.ts new file mode 100644 index 0000000000..666932dc92 --- /dev/null +++ b/packages/documentation/src/stories/components/breadcrumb/breadcrumb.snapshot.stories.ts @@ -0,0 +1,45 @@ +import { Args, StoryContext, StoryObj } from '@storybook/web-components'; +import meta, { Default, Concatenated } from './breadcrumb.stories'; +import { html } from 'lit'; +import { schemes } from '@/shared/snapshots/schemes'; + +const { id, ...metaWithoutId } = meta; + +export default { + ...metaWithoutId, + title: 'Snapshots', +}; + +type Story = StoryObj; + +export const BreadcrumbSnapshots: Story = { + render: (_args: Args, context: StoryContext) => { + const scenarios = [ + { label: 'Default', story: Default.render?.(context.args, context) || html`

Error rendering Default

` }, + { label: 'Concatenated', story: Concatenated.render?.(context.args, context) || html`

Error rendering Concatenated

` }, + { + label: 'Long Text', + story: html` + + This is a very long breadcrumb item + Another long breadcrumb item + Yet another long item that tests wrapping behavior + + `, + }, + ]; + + return schemes(() => html` +
+ ${scenarios.map( + (scenario) => html` +
+

${scenario.label}

+ ${scenario.story} +
+ ` + )} +
+ `); + }, +}; diff --git a/packages/documentation/src/stories/components/breadcrumb/breadcrumb.stories.ts b/packages/documentation/src/stories/components/breadcrumb/breadcrumb.stories.ts new file mode 100644 index 0000000000..b218e22640 --- /dev/null +++ b/packages/documentation/src/stories/components/breadcrumb/breadcrumb.stories.ts @@ -0,0 +1,91 @@ +import type { Args, StoryObj } from '@storybook/web-components'; +import { html } from 'lit'; +import { MetaComponent } from '@root/types'; + +const meta: MetaComponent = { + id: 'b7db7391-f893-4b1e-a125-b30c6f0b028b', + title: 'Components/Breadcrumb', + tags: ['package:WebComponents'], + parameters: { + badges: [], + design: { + type: 'figma', + url: 'https://www.figma.com/design/JIT5AdGYqv6bDRpfBPV8XR/Foundations-%26-Components-Next-Level?node-id=1787-20607&node-type=instance&m=dev', + }, + }, + args: { + homeUrl: '/', + homeText: 'Home', + }, + argTypes: { + homeUrl: { + name: 'Home URL', + description: 'URL for the home breadcrumb link.', + control: { type: 'text' }, + table: { category: 'Props' }, + }, + homeText: { + name: 'Home Text', + description: 'Text for the home breadcrumb link.', + control: { type: 'text' }, + table: { category: 'Props' }, + }, + }, +}; + +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + render: (args: Args) => html` + + Section 1 + Section 2 + Section 3 + + `, +}; + +export const Concatenated: Story = { + render: (args: Args) => html` + + Section 1 + Section 2 + Section 3 + Section 4 + Section 5 + Section 6 + Section 7 + Section 8 + Section 9 + Section 10 + + `, +}; + +export const BreadcrumbItem: Story = { + render: (args: Args) => html` + ${args.content} + `, + args: { + url: '/section1', + content: 'Section 1', + }, + argTypes: { + url: { + name: 'URL', + description: 'The URL of the breadcrumb item.', + control: { type: 'text' }, + table: { category: 'Props' }, + }, + content: { + name: 'Content', + description: 'The visible label of the breadcrumb item.', + control: { type: 'text' }, + table: { category: 'Props' }, + }, + homeUrl: { table: { disable: true } }, + homeText: { table: { disable: true } }, + }, +}; diff --git a/packages/documentation/src/stories/components/button/button.stories.ts b/packages/documentation/src/stories/components/button/button.stories.ts index c0e1457666..1cdcd7f4aa 100644 --- a/packages/documentation/src/stories/components/button/button.stories.ts +++ b/packages/documentation/src/stories/components/button/button.stories.ts @@ -86,10 +86,11 @@ const meta: MetaComponent = { 'btn-primary': 'Primary', 'btn-secondary': 'Secondary', 'btn-tertiary': 'Tertiary', - 'btn-link': 'Link (no padding)', + 'btn-tertiary px-0': 'Tertiary (no padding)', + 'btn-link': 'Link', }, }, - options: ['btn-primary', 'btn-secondary', 'btn-tertiary', 'btn-link'], + options: ['btn-primary', 'btn-secondary', 'btn-tertiary', 'btn-tertiary px-0', 'btn-link'], table: { category: 'General', }, diff --git a/packages/documentation/src/stories/components/card-control/web-component/card-control.stories.ts b/packages/documentation/src/stories/components/card-control/web-component/card-control.stories.ts index 0bfc6ed35d..eb5f0a4275 100644 --- a/packages/documentation/src/stories/components/card-control/web-component/card-control.stories.ts +++ b/packages/documentation/src/stories/components/card-control/web-component/card-control.stories.ts @@ -279,7 +279,9 @@ export const FormIntegration: Story = { ${args.radioValidity === 'false' ? invalidFeedback : nothing}
- +
`; diff --git a/packages/documentation/src/stories/components/form-footer/form-footer.stories.ts b/packages/documentation/src/stories/components/form-footer/form-footer.stories.ts index 4d358a5bd1..c7105939c0 100644 --- a/packages/documentation/src/stories/components/form-footer/form-footer.stories.ts +++ b/packages/documentation/src/stories/components/form-footer/form-footer.stories.ts @@ -134,7 +134,7 @@ export function render(args: Args) { ? html` ` : null} ${args.showTertiaryButton - ? html`` diff --git a/packages/documentation/src/stories/components/header/language-switch/language-switch.docs.mdx b/packages/documentation/src/stories/components/language-switch/language-switch.docs.mdx similarity index 100% rename from packages/documentation/src/stories/components/header/language-switch/language-switch.docs.mdx rename to packages/documentation/src/stories/components/language-switch/language-switch.docs.mdx diff --git a/packages/documentation/src/stories/components/header/language-switch/language-switch.snapshot.stories.ts b/packages/documentation/src/stories/components/language-switch/language-switch.snapshot.stories.ts similarity index 100% rename from packages/documentation/src/stories/components/header/language-switch/language-switch.snapshot.stories.ts rename to packages/documentation/src/stories/components/language-switch/language-switch.snapshot.stories.ts diff --git a/packages/documentation/src/stories/components/header/language-switch/language-switch.stories.ts b/packages/documentation/src/stories/components/language-switch/language-switch.stories.ts similarity index 98% rename from packages/documentation/src/stories/components/header/language-switch/language-switch.stories.ts rename to packages/documentation/src/stories/components/language-switch/language-switch.stories.ts index 013f6d01d9..e3cb30133e 100644 --- a/packages/documentation/src/stories/components/header/language-switch/language-switch.stories.ts +++ b/packages/documentation/src/stories/components/language-switch/language-switch.stories.ts @@ -4,7 +4,7 @@ import { MetaComponent } from '@root/types'; const meta: MetaComponent = { id: 'decbb10c-2b39-4f47-b67d-337d8111a3ae', - title: 'Components/Header/Language Switch', + title: 'Components/Language Switch', tags: ['package:WebComponents'], component: 'post-language-switch', render: renderLanguageSwitch, diff --git a/packages/documentation/src/stories/components/select-custom/select-custom-basic.sample.html b/packages/documentation/src/stories/components/select-custom/select-custom-basic.sample.html index eb42edb536..0a98a341b4 100644 --- a/packages/documentation/src/stories/components/select-custom/select-custom-basic.sample.html +++ b/packages/documentation/src/stories/components/select-custom/select-custom-basic.sample.html @@ -12,7 +12,7 @@ Default custom-select -
+
+ + + + © Copyright 2024 by Swiss Post Ltd. + All rights reserved. + `; +} + +export const Default: Story = {}; diff --git a/packages/documentation/src/stories/components/header/components/header.markup.ts b/packages/documentation/src/stories/modules/header/components/header.markup.ts similarity index 68% rename from packages/documentation/src/stories/components/header/components/header.markup.ts rename to packages/documentation/src/stories/modules/header/components/header.markup.ts index f110177cf7..d6bf86c4f4 100644 --- a/packages/documentation/src/stories/components/header/components/header.markup.ts +++ b/packages/documentation/src/stories/modules/header/components/header.markup.ts @@ -6,12 +6,16 @@ export default html` - = Menu + + Menu + + + - @@ -49,10 +63,14 @@ export default html` - Briefe - - -

Briefe title

+ Briefe + + + Schliessen +

Briefe title

Briefe senden

Briefe Schweiz @@ -67,14 +85,17 @@ export default html` Waren Ausland Express und Kurier
- Schliessen
- Pakete - - -

Pakete title

+ Pakete + + + Schliessen +

Pakete title

Pakete senden

Pakete Schweiz @@ -89,7 +110,6 @@ export default html` Waren Ausland Express und Kurier
- Schliessen
diff --git a/packages/documentation/src/stories/components/header/header.docs.mdx b/packages/documentation/src/stories/modules/header/header.docs.mdx similarity index 100% rename from packages/documentation/src/stories/components/header/header.docs.mdx rename to packages/documentation/src/stories/modules/header/header.docs.mdx diff --git a/packages/documentation/src/stories/components/header/header.stories.ts b/packages/documentation/src/stories/modules/header/header.stories.ts similarity index 95% rename from packages/documentation/src/stories/components/header/header.stories.ts rename to packages/documentation/src/stories/modules/header/header.stories.ts index 9b2cc7b912..06546b6b31 100644 --- a/packages/documentation/src/stories/components/header/header.stories.ts +++ b/packages/documentation/src/stories/modules/header/header.stories.ts @@ -4,7 +4,7 @@ import HeaderMarkup from './components/header.markup'; const meta: MetaComponent = { id: 'header', - title: 'Components/Header', + title: 'Modules/Header', tags: ['package:HTML'], parameters: { layout: 'fullscreen', diff --git a/packages/documentation/src/stories/components/breadcrumbs/breadcrumbs.docs.mdx b/packages/documentation/src/stories/raw-components/breadcrumbs/breadcrumbs.docs.mdx similarity index 100% rename from packages/documentation/src/stories/components/breadcrumbs/breadcrumbs.docs.mdx rename to packages/documentation/src/stories/raw-components/breadcrumbs/breadcrumbs.docs.mdx diff --git a/packages/documentation/src/stories/components/breadcrumbs/breadcrumbs.stories.ts b/packages/documentation/src/stories/raw-components/breadcrumbs/breadcrumbs.stories.ts similarity index 96% rename from packages/documentation/src/stories/components/breadcrumbs/breadcrumbs.stories.ts rename to packages/documentation/src/stories/raw-components/breadcrumbs/breadcrumbs.stories.ts index 60dcfad632..96fcb2f2de 100644 --- a/packages/documentation/src/stories/components/breadcrumbs/breadcrumbs.stories.ts +++ b/packages/documentation/src/stories/raw-components/breadcrumbs/breadcrumbs.stories.ts @@ -7,7 +7,7 @@ import { MetaComponent } from '@root/types'; const meta: MetaComponent = { id: '4347e5bf-8bf2-4f44-9075-9faaa53591ed', - title: 'Components/Breadcrumbs', + title: 'Raw Components/Internet Header/Breadcrumbs', component: 'swisspost-internet-breadcrumbs', tags: ['package:InternetHeader'], render: renderInternetBreadcrumbs, diff --git a/packages/documentation/src/stories/components/breadcrumbs/custom-items.ts b/packages/documentation/src/stories/raw-components/breadcrumbs/custom-items.ts similarity index 100% rename from packages/documentation/src/stories/components/breadcrumbs/custom-items.ts rename to packages/documentation/src/stories/raw-components/breadcrumbs/custom-items.ts diff --git a/packages/documentation/src/stories/components/footer/custom-footer-config.ts b/packages/documentation/src/stories/raw-components/footer/custom-footer-config.ts similarity index 100% rename from packages/documentation/src/stories/components/footer/custom-footer-config.ts rename to packages/documentation/src/stories/raw-components/footer/custom-footer-config.ts diff --git a/packages/documentation/src/stories/components/footer/footer.docs.mdx b/packages/documentation/src/stories/raw-components/footer/footer.docs.mdx similarity index 100% rename from packages/documentation/src/stories/components/footer/footer.docs.mdx rename to packages/documentation/src/stories/raw-components/footer/footer.docs.mdx diff --git a/packages/documentation/src/stories/components/footer/footer.stories.ts b/packages/documentation/src/stories/raw-components/footer/footer.stories.ts similarity index 97% rename from packages/documentation/src/stories/components/footer/footer.stories.ts rename to packages/documentation/src/stories/raw-components/footer/footer.stories.ts index 2c0dbec051..85fd8c1677 100644 --- a/packages/documentation/src/stories/components/footer/footer.stories.ts +++ b/packages/documentation/src/stories/raw-components/footer/footer.stories.ts @@ -6,7 +6,7 @@ import { MetaComponent } from '@root/types'; const meta: MetaComponent = { id: '27fc009d-3eec-43a9-b3a2-55531e721817', - title: 'Components/Footer', + title: 'Raw Components/Internet Header/Footer', component: 'swisspost-internet-footer', tags: ['package:InternetHeader'], render: renderInternetFooter, diff --git a/packages/documentation/src/stories/components/internet-header/config/custom-config.ts b/packages/documentation/src/stories/raw-components/internet-header/config/custom-config.ts similarity index 100% rename from packages/documentation/src/stories/components/internet-header/config/custom-config.ts rename to packages/documentation/src/stories/raw-components/internet-header/config/custom-config.ts diff --git a/packages/documentation/src/stories/components/internet-header/config/language-switch-overrides.ts b/packages/documentation/src/stories/raw-components/internet-header/config/language-switch-overrides.ts similarity index 100% rename from packages/documentation/src/stories/components/internet-header/config/language-switch-overrides.ts rename to packages/documentation/src/stories/raw-components/internet-header/config/language-switch-overrides.ts diff --git a/packages/documentation/src/stories/components/internet-header/config/os-flyout-overrides.ts b/packages/documentation/src/stories/raw-components/internet-header/config/os-flyout-overrides.ts similarity index 100% rename from packages/documentation/src/stories/components/internet-header/config/os-flyout-overrides.ts rename to packages/documentation/src/stories/raw-components/internet-header/config/os-flyout-overrides.ts diff --git a/packages/documentation/src/stories/components/internet-header/header.docs.mdx b/packages/documentation/src/stories/raw-components/internet-header/header.docs.mdx similarity index 100% rename from packages/documentation/src/stories/components/internet-header/header.docs.mdx rename to packages/documentation/src/stories/raw-components/internet-header/header.docs.mdx diff --git a/packages/documentation/src/stories/components/internet-header/header.scss b/packages/documentation/src/stories/raw-components/internet-header/header.scss similarity index 100% rename from packages/documentation/src/stories/components/internet-header/header.scss rename to packages/documentation/src/stories/raw-components/internet-header/header.scss diff --git a/packages/documentation/src/stories/components/internet-header/header.stories.ts b/packages/documentation/src/stories/raw-components/internet-header/header.stories.ts similarity index 99% rename from packages/documentation/src/stories/components/internet-header/header.stories.ts rename to packages/documentation/src/stories/raw-components/internet-header/header.stories.ts index 07fafdddef..d51fe7b296 100644 --- a/packages/documentation/src/stories/components/internet-header/header.stories.ts +++ b/packages/documentation/src/stories/raw-components/internet-header/header.stories.ts @@ -8,7 +8,7 @@ import { MetaComponent } from '@root/types'; const meta: MetaComponent = { id: 'ebb11274-091b-4cb7-9a3f-3e0451c9a865', - title: 'Components/Internet Header', + title: 'Raw Components/Internet Header', tags: ['package:InternetHeader'], component: 'swisspost-internet-header', parameters: { diff --git a/packages/documentation/src/stories/utilities/sizing/sizing.docs.mdx b/packages/documentation/src/stories/utilities/sizing/sizing.docs.mdx index 2305a8a96e..eab0361910 100644 --- a/packages/documentation/src/stories/utilities/sizing/sizing.docs.mdx +++ b/packages/documentation/src/stories/utilities/sizing/sizing.docs.mdx @@ -13,60 +13,49 @@ import * as SizingStories from './sizing.stories'; ## Height & Width -Height and width can be set using `h-*` and `w-*` prefixes, max-height and max-width can be set using prefixes `mh-*` and `mw-*` . +Height and width can be set using our utility classes `h-{size}` and `w-{size}`, max-height and max-width can be set with `max-h-{size}` and `max-w-{size}` and min-height and min-width can be set with `min-h-{size}` and `min-w-{size}`. ### Parent Based -Bootstrap offers sizing classes with the suffixes bellow. They allow you to set a height / width as a percentage of the parent element (see [Bootstrap Sizing](https://getbootstrap.com/docs/5.3/utilities/sizing/) for reference). +The design system offers classes for percentage based sizing with the suffixes bellow. They allow you to set a height / width as a percentage of the parent element. -> - `*-25` -> - `*-50` -> - `*-75` -> - `*-100` +- `*-auto` +- `*-quarter` +- `*-third` +- `*-half` +- `*-two-thirds` +- `*-three-quarters` +- `*-full` -#### Example +### Example - +
- +
-### Relative to breakpoints - -For width, we offer additionally `.w-{breakpoint}-{size}` classes (e.g. `w-md-100`) so that you can size only for some specific breakpoints. +### Pixel Based -See Full-width button for a practical example. +Additional pixel-based sizing classes allow precise height `h-{size}` and width `w-{size}` definitions in pixels (e.g., `w-12` for 12px width and `h-26` for 26px height). -### Post-Sizes +See all available sizes in the example bellow. -Post sizes can be used as suffixes in the same way. To find out which size name to use, see the "Size name in classes" column in the reference table above or use the "Example Post-Sizes" below. +### Example -#### Sass variables - -{/* prettier-ignore */} -
-

Sizing variables are deprecated

-

The current set of the post-specific sizing variables is deprecated in favour of a new naming system that is consistent with the Design. For further information, please read the discussion on sizing variables on GitHub and have a look at the implementation in Figma.

-

There is a new solution with updated naming system up coming for spacing sizes.

+ +
+
- key !== 'parameters') - .map(([key, value]) => `$${key}: ${formatAsMap(value)};`) - .join('\n')} -> +### Relative to breakpoints - -
- -
+For width and height, the design system provides additionally `.w-{breakpoint}-{size}` classes (e.g. `w-md-full`, `h-md-56`) so that you can set different sizes for specific breakpoints. + +See Full-width button for a practical example. -## Viewport Based +### Viewport Based -There is the possibility to set the width and height relative to the viewport. +There is the possibility to set the width and height as a percentage relative to the viewport. Available percentages: `25`, `33`, `50`, `66`, `75`, `100`. > - `min-vh-100` > - `min-vw-100` diff --git a/packages/documentation/src/stories/utilities/sizing/sizing.module.scss b/packages/documentation/src/stories/utilities/sizing/sizing.module.scss index e747d1f7da..3413b40b27 100644 --- a/packages/documentation/src/stories/utilities/sizing/sizing.module.scss +++ b/packages/documentation/src/stories/utilities/sizing/sizing.module.scss @@ -1,7 +1,21 @@ +@use 'sass:list'; +@use 'sass:map'; @use '@swisspost/design-system-styles/core' as post; +@use '@swisspost/design-system-styles/variables/sizing' as tokens; :export { - @each $key, $value in post.$post-sizes { - #{$key}: #{$value}; + @each $key, $value in tokens.$post-percentage-sizes { + pcsizes_#{$key}: #{$value}; + } + @each $key, $value in tokens.$post-px-sizes { + pxsizes_#{$key}: #{$value}; + } + @each $breakpoint in post.$grid-breakpoints-list { + @if (map.get(post.$grid-breakpoints, $breakpoint) == 0) { + firstBreakpoint_#{$breakpoint}: $breakpoint; + } + @if (map.get(post.$grid-breakpoints, $breakpoint) != 0) { + breakpoints_#{$breakpoint}: $breakpoint; + } } } diff --git a/packages/documentation/src/stories/utilities/sizing/sizing.snapshot.stories.ts b/packages/documentation/src/stories/utilities/sizing/sizing.snapshot.stories.ts new file mode 100644 index 0000000000..be6d562b5c --- /dev/null +++ b/packages/documentation/src/stories/utilities/sizing/sizing.snapshot.stories.ts @@ -0,0 +1,139 @@ +import type { StoryObj } from '@storybook/web-components'; +import { html } from 'lit'; +import './sizing.styles.scss'; +import meta from './sizing.stories'; +import { COLOR_SCHEMES, schemes } from '@/shared/snapshots/schemes'; + +const { id, ...metaWithoutId } = meta; + +export default { + ...metaWithoutId, + title: 'Snapshots', +}; + +const samples = [ + { w: 'third', h: 'full', maxW: 'third', minW: 'full', maxH: 'half', minH: 'two-thirds' }, + { w: 'quarter', h: 'half', maxW: 'quarter', minW: 'half', maxH: 'full', minH: 'quarter' }, + { w: 'half', h: 'quarter', maxW: 'half', minW: 'quarter', maxH: 'two-thirds', minH: 'third' }, + { + w: 'three-quarters', + h: 'quarter', + maxW: 'three-quarters', + minW: 'three-quarters', + maxH: 'quarter', + minH: 'half', + }, + { w: 'full', h: 'half', maxW: 'full', minW: 'third', maxH: 'auto', minH: 'auto' }, +]; + +const vpSamples = [ + { w: '33', h: '100', maxvW: '33', minvW: '100', maxvH: '50', minvH: '66' }, + { w: '50', h: '50', maxvW: '25', minvW: '50', maxvH: '100', minvH: '25' }, + { w: '50', h: '25', maxvW: '50', minvW: '25', maxvH: '66', minvH: '33' }, + { + w: '75', + h: '25', + maxvW: '75', + minvW: '25', + maxvH: '50', + minvH: '25', + }, + { w: '100', h: '50', maxvW: '100', minvW: '33', maxvH: 'auto', minvH: 'auto' }, +]; + +const pxSamples = [ + { w: '12', h: '18', maxW: '33', minW: '12', maxH: '48', minH: '22' }, + { w: '24', h: '36', maxW: '32', minW: '20', maxH: '40', minH: '24' }, + { w: '40', h: '56', maxW: '48', minW: '24', maxH: '56', minH: '32' }, + { w: '28', h: '64', maxW: '80', minW: '56', maxH: '96', minH: '36' }, + { w: '96', h: '48', maxW: '100', minW: '40', maxH: '112', minH: '48' }, + { w: '64', h: '56', maxW: '80', minW: '32', maxH: '78', minH: '64' }, + { w: '20', h: '15', maxW: '22', minW: '12', maxH: '32', minH: '18' }, + { w: '32', h: '22', maxW: '40', minW: '24', maxH: '36', minH: '20' }, + { w: '78', h: '96', maxW: '80', minW: '40', maxH: '112', minH: '56' }, + { w: '48', h: '80', maxW: '96', minW: '50', maxH: '112', minH: '56' }, + { w: '80', h: '96', maxW: '112', minW: '64', maxH: '100', minH: '36' }, +]; +function generateClassNames(sample: Record, isViewport = false) { + const prefix = isViewport ? 'v' : ''; + + const classNames = ['content']; + + classNames.push(prefix + 'h-' + sample.h); + classNames.push(prefix + 'w-' + sample.w); + + if (sample['max' + prefix + 'H'] && sample['max' + prefix + 'H'] !== 'none') { + classNames.push('max-vh-' + sample['max' + prefix + 'H']); + } + + if (sample['max' + prefix + 'W'] && sample['max' + prefix + 'W'] !== 'none') { + classNames.push('max-vw-' + sample['max' + prefix + 'W']); + } + + if (sample['min' + prefix + 'H'] && sample['min' + prefix + 'H'] !== 'none') { + classNames.push('min-vh-' + sample['min' + prefix + 'H']); + } + + if (sample['min' + prefix + 'W'] && sample['min' + prefix + 'W'] !== 'none') { + classNames.push('min-vw-' + sample['min' + prefix + 'W']); + } + + return classNames.filter(Boolean).join(' '); +} + +export const PercentageSizing: StoryObj = { + render() { + return schemes( + () => { + return html` + ${samples.map(sample => { + return html`
+
+
`; + })}; + `; + }, + { filter: scheme => scheme === COLOR_SCHEMES.light }, + ); + }, +}; + +export const PercentageVpSizing: StoryObj = { + render() { + return schemes( + () => { + return html` +
+ ${vpSamples.map(sample => { + return html` +
+
+
+
+
+ `; + })} +
+ `; + }, + { filter: scheme => scheme === COLOR_SCHEMES.light }, + ); + }, +}; + +export const PixelSizing: StoryObj = { + render() { + return schemes( + () => { + return html` + ${pxSamples.map(sample => { + return html`
+
+
`; + })} + `; + }, + { filter: scheme => scheme === COLOR_SCHEMES.light }, + ); + }, +}; diff --git a/packages/documentation/src/stories/utilities/sizing/sizing.stories.ts b/packages/documentation/src/stories/utilities/sizing/sizing.stories.ts index 38558d2899..f28ebe9daa 100644 --- a/packages/documentation/src/stories/utilities/sizing/sizing.stories.ts +++ b/packages/documentation/src/stories/utilities/sizing/sizing.stories.ts @@ -1,14 +1,14 @@ -import type { Args, StoryObj } from '@storybook/web-components'; +import type { Args, StoryObj, StoryFn, StoryContext } from '@storybook/web-components'; import { html } from 'lit'; -import './sizing.styles.scss'; -import scss from './sizing.module.scss'; +import sizing from './sizing.module.scss'; +import { parse } from '@/utils/sass-export'; import { MetaExtended } from '@root/types'; +import './sizing.styles.scss'; +import { camelToKebabCase } from '@/utils/naming'; -export const SCSS_VARIABLES = scss; - -const sizingOptions = ['auto', ...Object.keys(SCSS_VARIABLES)]; - -const sizeOptionsPercent = ['auto', '25', '50', '75', '100']; +const sizes: Record = parse(sizing); +const percentageSizes = Object.keys(sizes.pcsizes); +const pixelSizes = Object.keys(sizes.pxsizes); const meta: MetaExtended = { render: renderSizing, @@ -18,45 +18,25 @@ const meta: MetaExtended = { badges: [], }, args: { - height: 'bigger-giant', - width: 'bigger-giant', - maxHeight: 'null', - maxWidth: 'null', + height: 'none', + width: 'none', + maxHeight: 'none', + maxWidth: 'none', + minHeight: 'none', + minWidth: 'none', }, - argTypes: { - height: { - name: 'height', - description: 'Set the height of the rectangle', - control: { - type: 'select', - }, - options: sizingOptions, - }, - width: { - name: 'width', - description: 'Set the width of the rectangle', - control: { - type: 'select', - }, - options: sizingOptions, - }, - maxHeight: { - name: 'max-height', - description: 'Set the maximum height of the rectangle', - control: { - type: 'select', - }, - options: ['none', ...sizingOptions], - }, - maxWidth: { - name: 'max-width', - description: 'Set the maximum width of the rectangle', - control: { - type: 'select', - }, - options: ['none', ...sizingOptions], + decorators: [ + (story: StoryFn, context: StoryContext) => { + const storyTemplate = html` +
+
+ ${story(context.args, context)} +
+
+ `; + return storyTemplate; }, - }, + ], }; export default meta; @@ -64,33 +44,73 @@ export default meta; type Story = StoryObj; function renderSizing(args: Args) { - const maximumHeight = args.maxHeight && args.maxHeight !== 'null' ? `mh-${args.maxHeight}` : ''; - const maximumWidth = args.maxWidth && args.maxWidth !== 'null' ? `mw-${args.maxWidth}` : ''; - const classes = `content h-${args.height} w-${args.width} ${maximumHeight} ${maximumWidth}`; + const classNames = [ + `content`, + `h-${args.height}`, + `w-${args.width}`, + args.maxHeight && args.maxHeight !== 'none' ? `max-h-${args.maxHeight}` : '', + args.maxWidth && args.maxWidth !== 'none' ? `max-w-${args.maxWidth}` : '', + args.minHeight && args.minHeight !== 'none' ? `min-h-${args.minHeight}` : '', + args.minWidth && args.minWidth !== 'none' ? `min-w-${args.minWidth}` : '', + ] + .filter(Boolean) + .join(' '); - return html` -
-
-
-
-
-
-
- `; + return html`
`; } -export const Sizes: Story = {}; -export const SizesPercent: Story = { +const pcArgTypes = [ + { name: 'height', category: 'Height', options: percentageSizes }, + { name: 'width', category: 'Width', options: percentageSizes }, + { name: 'maxHeight', category: 'Height', options: percentageSizes }, + { name: 'maxWidth', category: 'Width', options: percentageSizes }, + { name: 'minHeight', category: 'Height', options: percentageSizes }, + { name: 'minWidth', category: 'Width', options: percentageSizes }, +]; + +export const PercentSizes: Story = { args: { - width: '25', - height: '100', + width: 'quarter', + height: 'full', }, - argTypes: { - height: { - options: sizeOptionsPercent, - }, - width: { - options: sizeOptionsPercent, - }, + argTypes: Object.fromEntries( + pcArgTypes.map(argType => [ + argType.name, + { + name: camelToKebabCase(argType.name), + description: `Set the ${camelToKebabCase(argType.name).toLowerCase()} of the rectangle`, + control: { type: 'select' }, + options: argType.options, + table: { category: argType.category }, + }, + ]), + ), +}; + +const pxArgTypes = [ + { name: 'height', category: 'Height', options: pixelSizes }, + { name: 'width', category: 'Width', options: pixelSizes }, + { name: 'maxHeight', category: 'Height', options: pixelSizes }, + { name: 'maxWidth', category: 'Width', options: pixelSizes }, + { name: 'minHeight', category: 'Height', options: pixelSizes }, + { name: 'minWidth', category: 'Width', options: pixelSizes }, +]; + +export const PxSizes: Story = { + args: { + width: '100', + height: '80', }, + argTypes: Object.fromEntries( + pxArgTypes.map(argType => [ + argType.name, + { + name: camelToKebabCase(argType.name), + description: `Set the ${camelToKebabCase(argType.name).toLowerCase()} of the rectangle`, + control: { type: 'select' }, + options: argType.options, + table: { category: argType.category }, + }, + ]), + ), }; diff --git a/packages/documentation/src/stories/utilities/sizing/sizing.styles.scss b/packages/documentation/src/stories/utilities/sizing/sizing.styles.scss index 6d46035c47..84f5536836 100644 --- a/packages/documentation/src/stories/utilities/sizing/sizing.styles.scss +++ b/packages/documentation/src/stories/utilities/sizing/sizing.styles.scss @@ -2,7 +2,35 @@ .sizing-example { .content { - background-color: post.$white; + background-color: post.$gray-40; + } + + .grid-item { + width: 20vw; + height: 20vw; border: 1px solid post.$gray-40; + + div { + background-color: post.$gray-40; + } + } +} + +.sizing-example .grid { + display: grid; + grid-template-columns: 100vw; + grid-template-rows: 100vh; + gap: 30px; + .grid-item { + width: 100vw; + height: 100vh; } } + +.sizing-example.snapshot, +.sizing-px-example.snapshot { + display: flex; + width: 20vw; + height: 20vw; + border: 1px solid post.$gray-40 !important; +} diff --git a/packages/documentation/src/stories/utilities/spacing/spacing.stories.ts b/packages/documentation/src/stories/utilities/spacing/spacing.stories.ts index 4abdc3b371..6e93e63899 100644 --- a/packages/documentation/src/stories/utilities/spacing/spacing.stories.ts +++ b/packages/documentation/src/stories/utilities/spacing/spacing.stories.ts @@ -47,7 +47,7 @@ function withLegend(template: TemplateResult, ...legendItems: string[]) { ${legendItems.map( item => html`
  • -
    +
    ${item}
  • `, diff --git a/packages/documentation/src/utils/naming.ts b/packages/documentation/src/utils/naming.ts new file mode 100644 index 0000000000..a57c671fae --- /dev/null +++ b/packages/documentation/src/utils/naming.ts @@ -0,0 +1,3 @@ +export function camelToKebabCase(str: string) { + return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase(); +} diff --git a/packages/icons/CHANGELOG.md b/packages/icons/CHANGELOG.md index a7bace80e0..807dd0d607 100644 --- a/packages/icons/CHANGELOG.md +++ b/packages/icons/CHANGELOG.md @@ -1,5 +1,7 @@ # @swisspost/design-system-icons +## 9.0.0-next.9 + ## 9.0.0-next.8 ### Minor Changes diff --git a/packages/icons/package.json b/packages/icons/package.json index b03a924ce3..0f3b5682c3 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-icons", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "A collection of Swiss Post icons intended for use with the Design System.", "author": "Swiss Post ", "license": "Apache-2.0", diff --git a/packages/internet-header/CHANGELOG.md b/packages/internet-header/CHANGELOG.md index 2db462b044..f7dd748648 100644 --- a/packages/internet-header/CHANGELOG.md +++ b/packages/internet-header/CHANGELOG.md @@ -1,5 +1,12 @@ # @swisspost/internet-header +## 2.0.0-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-styles@9.0.0-next.9 + ## 2.0.0-next.8 ### Patch Changes diff --git a/packages/internet-header/package.json b/packages/internet-header/package.json index 76ecec1354..6dde983e09 100644 --- a/packages/internet-header/package.json +++ b/packages/internet-header/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/internet-header", - "version": "2.0.0-next.8", + "version": "2.0.0-next.9", "description": "The header for client facing applications.", "author": "Swiss Post ", "license": "Apache-2.0", @@ -43,7 +43,7 @@ "generate": "stencil generate" }, "dependencies": { - "@swisspost/design-system-styles": "workspace:9.0.0-next.8", + "@swisspost/design-system-styles": "workspace:9.0.0-next.9", "body-scroll-lock": "4.0.0-beta.0", "iframe-resizer": "4.4.5", "jquery": "3.7.1", diff --git a/packages/intranet-header-workspace/CHANGELOG.md b/packages/intranet-header-workspace/CHANGELOG.md index 0f5df4ea7d..97f5d85a8c 100644 --- a/packages/intranet-header-workspace/CHANGELOG.md +++ b/packages/intranet-header-workspace/CHANGELOG.md @@ -1,5 +1,12 @@ # @swisspost/design-system-intranet-header-workspace +## 3.0.22-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-styles@9.0.0-next.9 + ## 3.0.22-next.8 ### Patch Changes diff --git a/packages/intranet-header-workspace/package.json b/packages/intranet-header-workspace/package.json index 95956f194b..de134fc131 100644 --- a/packages/intranet-header-workspace/package.json +++ b/packages/intranet-header-workspace/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-intranet-header-workspace", - "version": "3.0.22-next.8", + "version": "3.0.22-next.9", "license": "Apache-2.0", "private": true, "scripts": { @@ -23,7 +23,7 @@ "@angular/router": "18.2.13", "@ng-bootstrap/ng-bootstrap": "17.0.0", "@popperjs/core": "2.11.8", - "@swisspost/design-system-styles": "workspace:9.0.0-next.8", + "@swisspost/design-system-styles": "workspace:9.0.0-next.9", "rxjs": "7.8.1", "tslib": "2.6.3", "watch": "1.0.2", diff --git a/packages/intranet-header-workspace/projects/intranet-header-showcase/CHANGELOG.md b/packages/intranet-header-workspace/projects/intranet-header-showcase/CHANGELOG.md index b21c4ce804..aafbc814da 100644 --- a/packages/intranet-header-workspace/projects/intranet-header-showcase/CHANGELOG.md +++ b/packages/intranet-header-workspace/projects/intranet-header-showcase/CHANGELOG.md @@ -1,5 +1,12 @@ # @swisspost/design-system-intranet-header-showcase +## 1.0.10-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-intranet-header@9.0.0-next.9 + ## 1.0.10-next.8 ### Patch Changes diff --git a/packages/intranet-header-workspace/projects/intranet-header-showcase/package.json b/packages/intranet-header-workspace/projects/intranet-header-showcase/package.json index c18ba6a52f..75ca1ed84b 100644 --- a/packages/intranet-header-workspace/projects/intranet-header-showcase/package.json +++ b/packages/intranet-header-workspace/projects/intranet-header-showcase/package.json @@ -1,9 +1,9 @@ { "name": "@swisspost/design-system-intranet-header-showcase", - "version": "1.0.10-next.8", + "version": "1.0.10-next.9", "license": "Apache-2.0", "private": true, "dependencies": { - "@swisspost/design-system-intranet-header": "workspace:9.0.0-next.8" + "@swisspost/design-system-intranet-header": "workspace:9.0.0-next.9" } } diff --git a/packages/intranet-header-workspace/projects/intranet-header/CHANGELOG.md b/packages/intranet-header-workspace/projects/intranet-header/CHANGELOG.md index 7e2cc17e10..49b833b831 100644 --- a/packages/intranet-header-workspace/projects/intranet-header/CHANGELOG.md +++ b/packages/intranet-header-workspace/projects/intranet-header/CHANGELOG.md @@ -1,5 +1,12 @@ # @swisspost/design-system-intranet-header +## 9.0.0-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-styles@9.0.0-next.9 + ## 9.0.0-next.8 ### Patch Changes diff --git a/packages/intranet-header-workspace/projects/intranet-header/package.json b/packages/intranet-header-workspace/projects/intranet-header/package.json index cee0dd96ac..b395ba1e61 100644 --- a/packages/intranet-header-workspace/projects/intranet-header/package.json +++ b/packages/intranet-header-workspace/projects/intranet-header/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-intranet-header", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "Intranet header for internal Swiss Post applications as an Angular component.", "author": "Swiss Post ", "license": "Apache-2.0", @@ -18,11 +18,11 @@ "linkDirectory": true }, "dependencies": { - "@swisspost/design-system-styles": "workspace:9.0.0-next.8", + "@swisspost/design-system-styles": "workspace:9.0.0-next.9", "tslib": "2.6.3" }, "devDependencies": { - "@swisspost/design-system-intranet-header-workspace": "workspace:3.0.22-next.8" + "@swisspost/design-system-intranet-header-workspace": "workspace:3.0.22-next.9" }, "peerDependencies": { "@angular/common": "^16.0.0 || ^17.0.0 || ^18.0.0", diff --git a/packages/migrations/CHANGELOG.md b/packages/migrations/CHANGELOG.md index 95272121a5..e52c6ddcde 100644 --- a/packages/migrations/CHANGELOG.md +++ b/packages/migrations/CHANGELOG.md @@ -1,5 +1,7 @@ # @swisspost/design-system-migrations +## 9.0.0-next.9 + ## 9.0.0-next.8 ## 9.0.0-next.7 diff --git a/packages/migrations/package.json b/packages/migrations/package.json index 856c6ed0fa..92123fafcd 100644 --- a/packages/migrations/package.json +++ b/packages/migrations/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-migrations", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "Scripts to migrate an Angular application from one Design System version to another.", "author": "Swiss Post ", "license": "Apache-2.0", diff --git a/packages/migrations/src/utils/constants.ts b/packages/migrations/src/utils/constants.ts index 1da92da3a0..f2f4d69cf3 100644 --- a/packages/migrations/src/utils/constants.ts +++ b/packages/migrations/src/utils/constants.ts @@ -1,6 +1,7 @@ export const breakpoints = [ 'xs', 'sm', 'rg', 'md', 'lg', 'xl', 'xxl' ]; const bootstrapSizes = [ '0', '1', '2', '3', '4', '5', 'auto' ]; + const postSizes = [ 'hair', 'line', diff --git a/packages/nextjs-integration/CHANGELOG.md b/packages/nextjs-integration/CHANGELOG.md index 26d7a15efb..940f3dfe9c 100644 --- a/packages/nextjs-integration/CHANGELOG.md +++ b/packages/nextjs-integration/CHANGELOG.md @@ -1,5 +1,14 @@ # @swisspost/design-system-nextjs-integration +## 0.1.14-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-styles@9.0.0-next.9 + - @swisspost/design-system-components-react@9.0.0-next.9 + - @swisspost/internet-header@2.0.0-next.9 + ## 0.1.14-next.8 ### Patch Changes diff --git a/packages/nextjs-integration/package.json b/packages/nextjs-integration/package.json index a343f8f10b..be32dc764c 100644 --- a/packages/nextjs-integration/package.json +++ b/packages/nextjs-integration/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-nextjs-integration", - "version": "0.1.14-next.8", + "version": "0.1.14-next.9", "private": true, "scripts": { "dev": "next dev", @@ -9,9 +9,9 @@ "lint": "next lint" }, "dependencies": { - "@swisspost/design-system-components-react": "workspace:9.0.0-next.8", - "@swisspost/design-system-styles": "workspace:9.0.0-next.8", - "@swisspost/internet-header": "workspace:2.0.0-next.8", + "@swisspost/design-system-components-react": "workspace:9.0.0-next.9", + "@swisspost/design-system-styles": "workspace:9.0.0-next.9", + "@swisspost/internet-header": "workspace:2.0.0-next.9", "next": "15.0.1", "react": "^18", "react-dom": "^18" diff --git a/packages/styles-primeng-workspace/CHANGELOG.md b/packages/styles-primeng-workspace/CHANGELOG.md index b4d766e1b4..1208e871ef 100644 --- a/packages/styles-primeng-workspace/CHANGELOG.md +++ b/packages/styles-primeng-workspace/CHANGELOG.md @@ -1,5 +1,12 @@ # @swisspost/design-system-styles-primeng-workspace +## 1.0.6-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-styles@9.0.0-next.9 + ## 1.0.6-next.8 ### Patch Changes diff --git a/packages/styles-primeng-workspace/package.json b/packages/styles-primeng-workspace/package.json index 5a58e45f77..60cb3e674e 100644 --- a/packages/styles-primeng-workspace/package.json +++ b/packages/styles-primeng-workspace/package.json @@ -1,7 +1,7 @@ { "name": "@swisspost/design-system-styles-primeng-workspace", "description": "Showcase for a Post like custom prime-ng theme", - "version": "1.0.6-next.8", + "version": "1.0.6-next.9", "license": "Apache-2.0", "private": true, "scripts": { @@ -22,7 +22,7 @@ "@angular/platform-browser": "18.2.13", "@angular/platform-browser-dynamic": "18.2.13", "@angular/router": "18.2.13", - "@swisspost/design-system-styles": "workspace:9.0.0-next.8", + "@swisspost/design-system-styles": "workspace:9.0.0-next.9", "primeng": "17.18.7", "rxjs": "7.8.1", "tslib": "2.6.3", diff --git a/packages/styles-primeng-workspace/projects/styles-primeng/CHANGELOG.md b/packages/styles-primeng-workspace/projects/styles-primeng/CHANGELOG.md index e384aee8c3..3395842e1d 100644 --- a/packages/styles-primeng-workspace/projects/styles-primeng/CHANGELOG.md +++ b/packages/styles-primeng-workspace/projects/styles-primeng/CHANGELOG.md @@ -1,5 +1,12 @@ # @swisspost/design-system-styles-primeng +## 9.0.0-next.9 + +### Patch Changes + +- Updated dependencies: + - @swisspost/design-system-styles@9.0.0-next.9 + ## 9.0.0-next.8 ### Patch Changes diff --git a/packages/styles-primeng-workspace/projects/styles-primeng/package.json b/packages/styles-primeng-workspace/projects/styles-primeng/package.json index 90f2fe1261..82bed38adc 100644 --- a/packages/styles-primeng-workspace/projects/styles-primeng/package.json +++ b/packages/styles-primeng-workspace/projects/styles-primeng/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-styles-primeng", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "Swiss Post styles for PrimeNg datatable.", "author": "Swiss Post ", "license": "Apache-2.0", @@ -23,7 +23,7 @@ "primeng": "^17.18.0" }, "dependencies": { - "@swisspost/design-system-styles": "workspace:9.0.0-next.8", + "@swisspost/design-system-styles": "workspace:9.0.0-next.9", "tslib": "2.6.3" }, "sideEffects": false, diff --git a/packages/styles/CHANGELOG.md b/packages/styles/CHANGELOG.md index 3edf73590f..de60763ac3 100644 --- a/packages/styles/CHANGELOG.md +++ b/packages/styles/CHANGELOG.md @@ -1,5 +1,27 @@ # @swisspost/design-system-styles +## 9.0.0-next.9 + +### Minor Changes + +- Added composable footer component. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + +- Removed outdated portal-specific styles, including subnavigation-related rules. (by [@alionazherdetska](https://github.com/alionazherdetska) with [#4186](https://github.com/swisspost/design-system/pull/4186)) + +- Added the possibility to define a `$child-selector` parameter with our list mixins, so they can be used also with custom elements. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + +- Updated the utility classes for sizing. (by [@myrta2302](https://github.com/myrta2302) with [#4012](https://github.com/swisspost/design-system/pull/4012)) + +- Updated `.btn-link` to look like a regular link and old `.btn-link` is now `.btn-tertiary .px-0`. (by [@leagrdv](https://github.com/leagrdv) with [#4200](https://github.com/swisspost/design-system/pull/4200)) + +- Implemented new pixel based sizes. (by [@myrta2302](https://github.com/myrta2302) with [#4012](https://github.com/swisspost/design-system/pull/4012)) + +### Patch Changes + +- Fixed the `btn-icon` styles, so icons within can no longer be rendered too small, because of the inline-padding on the button. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + +- Fixed the appstore-badge styles to get rid of the inline gap below. (by [@oliverschuerch](https://github.com/oliverschuerch) with [#4190](https://github.com/swisspost/design-system/pull/4190)) + ## 9.0.0-next.8 ### Major Changes diff --git a/packages/styles/package.json b/packages/styles/package.json index 2c1fd2a663..83cf01001d 100644 --- a/packages/styles/package.json +++ b/packages/styles/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-styles", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "Design System Styles for the Swiss Post web platform.", "author": "Swiss Post ", "license": "Apache-2.0", @@ -49,8 +49,8 @@ "gulp-sourcemaps": "3.0.0" }, "devDependencies": { - "@swisspost/design-system-icons": "workspace:9.0.0-next.8", - "@swisspost/design-system-tokens": "workspace:9.0.0-next.8", + "@swisspost/design-system-icons": "workspace:9.0.0-next.9", + "@swisspost/design-system-tokens": "workspace:9.0.0-next.9", "@types/node": "20.14.14", "autoprefixer": "10.4.19", "copyfiles": "2.4.1", diff --git a/packages/styles/src/components/_index.scss b/packages/styles/src/components/_index.scss index 2f9f104eca..51cda318d0 100644 --- a/packages/styles/src/components/_index.scss +++ b/packages/styles/src/components/_index.scss @@ -1,5 +1,7 @@ @forward './../variables/options'; +@use 'breakpoints'; +@use 'globals'; @use 'appstore-badge'; @use 'avatar'; @use 'badge'; @@ -27,6 +29,7 @@ @use 'switch'; @use 'form-hint'; @use 'form-input'; +@use 'header'; @use 'icon-button'; @use 'icon-close-button'; @use 'lead'; diff --git a/packages/styles/src/components/appstore-badge.scss b/packages/styles/src/components/appstore-badge.scss index 0c4005bb9d..6c76601ba7 100644 --- a/packages/styles/src/components/appstore-badge.scss +++ b/packages/styles/src/components/appstore-badge.scss @@ -7,9 +7,12 @@ tokens.$default-map: components.$post-app-store-badge; .app-store-badge { display: inline-flex; border-radius: tokens.get('app-store-border-radius'); + height: tokens.get('app-store-height'); + vertical-align: text-bottom; img { display: block; - height: tokens.get('app-store-height'); + width: auto; + height: 100%; } } diff --git a/packages/styles/src/components/breakpoints.scss b/packages/styles/src/components/breakpoints.scss new file mode 100644 index 0000000000..3e36eafb96 --- /dev/null +++ b/packages/styles/src/components/breakpoints.scss @@ -0,0 +1,17 @@ +@use 'sass:list'; +@use 'sass:map'; +@use 'sass:math'; +@use '../variables/breakpoints'; + +:root { + $breakpoint-list: (); + + @each $key, $value in breakpoints.$grid-breakpoints { + $unitless-value: math.div($value, $value * 0 + 1); + $breakpoint-list: list.append($breakpoint-list, $unitless-value, comma); + } + + --post-breakpoint-widths: #{$breakpoint-list}; + --post-breakpoint-keys: #{map.keys(breakpoints.$grid-breakpoints)}; + --post-breakpoint-names: #{map.values(breakpoints.$grid-breakpoints-key-name-map)}; +} diff --git a/packages/styles/src/components/button.scss b/packages/styles/src/components/button.scss index d2560ce8d2..0eaed65339 100644 --- a/packages/styles/src/components/button.scss +++ b/packages/styles/src/components/button.scss @@ -19,6 +19,7 @@ @use './../placeholders/button' as button-ph; @use '../functions/tokens'; @use '../tokens/components'; +@use '../tokens/elements'; tokens.$default-map: components.$post-button; @@ -39,9 +40,13 @@ tokens.$default-map: components.$post-button; color: var(--post-gray-80); font-family: inherit; font-weight: tokens.get('button-label-font-weight'); - text-decoration: none !important; // For tags, !important for hover + text-decoration: none; white-space: nowrap; // Long content should never break in buttons + &:hover { + text-decoration: none; + } + @include button-mx.button-size(); &:disabled { @@ -88,8 +93,6 @@ tokens.$default-map: components.$post-button; } } -// Tertiary -.btn-link, .btn-tertiary { // Styles to improve accessibility in high contrast mode @include utilities.high-contrast-mode() { @@ -105,8 +108,16 @@ tokens.$default-map: components.$post-button; } } -// Tertiary with no padding (overrides the padding defined by the sizing classes above) .btn-link { - padding-inline-start: 0; - padding-inline-end: 0; + text-decoration: tokens.get('link-decoration', elements.$post-link); + border: 0 none; + border-radius: tokens.get('link-border-radius', elements.$post-link); + min-height: 0; + font-size: inherit; + font-weight: inherit; + padding: 0; + + &:hover { + color: tokens.get('link-hover-fg', elements.$post-link); + } } diff --git a/packages/styles/src/components/globals/_index.scss b/packages/styles/src/components/globals/_index.scss new file mode 100644 index 0000000000..99119af291 --- /dev/null +++ b/packages/styles/src/components/globals/_index.scss @@ -0,0 +1,3 @@ +@forward './../../variables/options'; + +@use 'post-footer'; diff --git a/packages/styles/src/components/globals/post-footer.scss b/packages/styles/src/components/globals/post-footer.scss new file mode 100644 index 0000000000..087415d8ab --- /dev/null +++ b/packages/styles/src/components/globals/post-footer.scss @@ -0,0 +1,92 @@ +@use '../../variables/color'; +@use '../../mixins/media'; +@use '../../mixins/list'; + +post-footer { + // mobile + --post-footer-grid-list-title-display: none; + --post-footer-grid-list-title-gap: 0; + --post-footer-grid-list-item-gap: 8px; + + --post-footer-socialmedia-list-item-gap: 8px; + --post-footer-app-list-item-gap: 8px; + --post-footer-businesssector-list-item-gap: 8px; + --post-footer-meta-list-item-gap: 8px; + + // tablet sm + @include media.min(sm) { + --post-footer-grid-list-title-display: block; + --post-footer-grid-list-title-gap: 8px; + + --post-footer-socialmedia-list-item-gap: 16px; + --post-footer-businesssector-list-item-gap: 24px; + --post-footer-meta-list-item-gap: 16px; + } + + // desktop lg + @include media.min(lg) { + --post-footer-meta-list-item-gap: 24px; + } + + :is(h3, .h3) { + margin: 0; + font-size: inherit; + } + + a { + &:not(.btn-icon, .app-store-badge) { + display: block; + text-decoration: none; + } + } + + post-list { + &[slot|='grid'] { + :is(h3, .h3) { + display: var(--post-footer-grid-list-title-display); + margin-block-end: var(--post-footer-grid-list-title-gap); + } + + > [role='list'] { + @include list.list-bullet($child-selector: 'post-list-item'); + margin-block: 0; + padding-inline-start: 0; + list-style: none; + + > post-list-item { + &::before { + display: none; + } + + ~ post-list-item { + margin-block-start: var(--post-footer-grid-list-item-gap); + } + } + } + } + + &:is([slot='socialmedia'], [slot='app'], [slot='businesssectors'], [slot='meta']) { + > [role='list'] { + @include list.list-inline($child-selector: 'post-list-item'); + margin: 0; + } + } + + &[slot='socialmedia'] > [role='list'] { + gap: var(--post-footer-socialmedia-list-item-gap); + } + + &[slot='app'] > [role='list'] { + gap: var(--post-footer-app-list-item-gap); + } + + &[slot='businesssectors'] > [role='list'] { + gap: var(--post-footer-businesssector-list-item-gap); + } + + &[slot='meta'] > [role='list'] { + row-gap: 0; + column-gap: var(--post-footer-meta-list-item-gap); + } + } +} diff --git a/packages/styles/src/components/header/_mixins.scss b/packages/styles/src/components/header/_mixins.scss new file mode 100644 index 0000000000..c033808a6c --- /dev/null +++ b/packages/styles/src/components/header/_mixins.scss @@ -0,0 +1,34 @@ +@use '../../mixins/icons'; + +@mixin subsidiary-header-interactive() { + text-decoration: none; + display: inline-flex; + align-items: center; + gap: var(--post-core-dimension-6); + border-radius: var(--post-core-dimension-24); + font-size: var(--post-core-font-size-16); + padding: var(--post-core-dimension-3) var(--post-core-dimension-10); +} + +@mixin mobile-header-interactive() { + width: 100%; + height: var(--post-core-dimension-48); + padding-inline-end: var(--post-core-dimension-6); + gap: var(--post-core-dimension-16); + border-block: var(--post-core-dimension-1) solid transparent; + border-block-end-color: currentColor; + font-weight: var(--post-core-font-weight-700); + + &:hover, + &.selected { + border-block-width: var(--post-core-dimension-3); + } + + &:hover::after { + content: ''; + display: block; + @include icons.icon(3020); + width: var(--post-core-dimension-24); + height: var(--post-core-dimension-24); + } +} diff --git a/packages/styles/src/components/header/index.scss b/packages/styles/src/components/header/index.scss new file mode 100644 index 0000000000..674e266c8e --- /dev/null +++ b/packages/styles/src/components/header/index.scss @@ -0,0 +1,60 @@ +@use '../../mixins/media'; +@use '../../mixins/utilities'; + +@use 'mixins' as *; + +post-header { + ul[slot="meta-navigation"] { + gap: var(--post-core-dimension-4); + + @include media.max(lg) { + flex-direction: column; + + a, + button { + justify-content: space-between; + border-radius: 0; + @include mobile-header-interactive; + + @include utilities.focus-style-custom { + border-radius: var(--post-core-dimension-4); + } + } + } + } + + a, + post-togglebutton { + &:not(post-mainnavigation *) { + @include subsidiary-header-interactive; + + @include media.min(sm) { + post-icon { + height: var(--post-core-dimension-22); + width: var(--post-core-dimension-22); + } + } + + @include media.max(sm) { + padding: var(--post-core-dimension-8); + + post-icon { + height: var(--post-core-dimension-24); + width: var(--post-core-dimension-24); + } + + .visually-hidden-sm { + @include utilities.visuallyhidden; + } + } + } + } + + a.selected, + post-togglebutton[aria-pressed='true'] { + &:not(post-mainnavigation *) { + color: var(--post-core-color-brand-white); + background: var(--post-core-color-sandgrey-100); + } + } +} diff --git a/packages/styles/src/components/icon-close-button.scss b/packages/styles/src/components/icon-close-button.scss index c8eb34d175..8cf04ff0c1 100644 --- a/packages/styles/src/components/icon-close-button.scss +++ b/packages/styles/src/components/icon-close-button.scss @@ -16,6 +16,7 @@ tokens.$default-map: components.$post-close; color: tokens.get('close-enabled-fg'); > post-icon { + min-width: tokens.get('close-icon-size'); width: tokens.get('close-icon-size'); height: tokens.get('close-icon-size'); } diff --git a/packages/styles/src/components/sizing.scss b/packages/styles/src/components/sizing.scss index 228e836d8e..bf76e9bf87 100644 --- a/packages/styles/src/components/sizing.scss +++ b/packages/styles/src/components/sizing.scss @@ -3,33 +3,16 @@ @use 'sass:map'; @use './../themes/bootstrap/core' as *; @use './../variables/spacing'; +@use './../variables/sizing'; @use './../variables/breakpoints'; @use './../mixins/utilities'; -// Post sizes -@each $breakpoint in map.keys(breakpoints.$grid-breakpoints) { - @include media-breakpoint-up($breakpoint) { - $infix: if($breakpoint == 'xs', '', '-#{$breakpoint}'); - - @each $prop, - $abbrev - in (/* Deprecated */ line-height: lh, height: h, max-height: mh, width: w, max-width: mw) - { - @each $size, $length in spacing.$post-sizes { - .#{$abbrev}#{$infix}-#{$size} { - #{$prop}: $length !important; - } - } - } - } -} - // Post breakpoints width - e.g. w-sm-100 @each $breakpoint in map.keys(breakpoints.$grid-breakpoints) { @include media-breakpoint-up($breakpoint) { @if $breakpoint != 'xs' { @each $prop, $abbrev in (width: w) { - @each $size, $length in spacing.$sizes { + @each $size, $length in sizing.$post-percentage-sizes { .#{$abbrev}-#{$breakpoint}-#{$size} { #{$prop}: $length !important; } diff --git a/packages/styles/src/index.scss b/packages/styles/src/index.scss index 97fa256ba6..2f92769c20 100644 --- a/packages/styles/src/index.scss +++ b/packages/styles/src/index.scss @@ -4,6 +4,3 @@ @use './utilities'; @use './elements'; @use './components'; - -// Portal specific styles -@use './layouts/portal'; diff --git a/packages/styles/src/layouts/portal/_index.scss b/packages/styles/src/layouts/portal/_index.scss deleted file mode 100644 index c067e7178e..0000000000 --- a/packages/styles/src/layouts/portal/_index.scss +++ /dev/null @@ -1 +0,0 @@ -@use './subnavigation'; diff --git a/packages/styles/src/layouts/portal/_subnavigation.scss b/packages/styles/src/layouts/portal/_subnavigation.scss deleted file mode 100644 index 538ea92584..0000000000 --- a/packages/styles/src/layouts/portal/_subnavigation.scss +++ /dev/null @@ -1,5 +0,0 @@ -.subnavigation-list { - width: 100%; - margin: 0; - padding: 0; -} diff --git a/packages/styles/src/mixins/_icon-button.scss b/packages/styles/src/mixins/_icon-button.scss index ec62913afc..78a3544d8a 100644 --- a/packages/styles/src/mixins/_icon-button.scss +++ b/packages/styles/src/mixins/_icon-button.scss @@ -13,12 +13,15 @@ tokens.$default-map: components.$post-icon-button; 'lg': 'large', ); $actual-size: map.get($size-map, $size); - min-width: tokens.get('icon-button-#{$actual-size}-outer'); + padding: 0; width: tokens.get('icon-button-#{$actual-size}-outer'); height: tokens.get('icon-button-#{$actual-size}-outer'); + min-height: 0; + vertical-align: text-bottom; > post-icon { - min-width: tokens.get('icon-button-#{$actual-size}-icon'); + display: block; + width: tokens.get('icon-button-#{$actual-size}-icon'); height: tokens.get('icon-button-#{$actual-size}-icon'); } } diff --git a/packages/styles/src/mixins/list.scss b/packages/styles/src/mixins/_list.scss similarity index 86% rename from packages/styles/src/mixins/list.scss rename to packages/styles/src/mixins/_list.scss index c654fb92e1..03a136a240 100644 --- a/packages/styles/src/mixins/list.scss +++ b/packages/styles/src/mixins/_list.scss @@ -1,7 +1,7 @@ @use '../functions/tokens'; @use '../tokens/elements'; -@mixin list-bullet() { +@mixin list-bullet($child-selector: 'li') { list-style: none; margin-block: tokens.get('list-bullet-margin-block', elements.$post-listbullet); padding-inline-start: calc( @@ -11,12 +11,12 @@ )} ); - > li { + > #{$child-selector} { margin: 0; padding-inline: 0; padding-block: tokens.get('list-bullet-item-text-padding-block', elements.$post-listbullet); - ~ li { + ~ #{$child-selector} { margin-block-start: tokens.get('list-bullet-item-gap-block', elements.$post-listbullet); } @@ -42,7 +42,7 @@ } } -@mixin list-number() { +@mixin list-number($child-selector: 'li') { margin-block: tokens.get('list-number-item-gap-block', elements.$post-listnumber); padding-inline-end: tokens.get('list-number-item-gap-block', elements.$post-listnumber); padding-inline-start: calc( @@ -50,7 +50,7 @@ tokens.get('list-number-item-icon-gap-inline', elements.$post-listnumber) ); - > li { + > #{$child-selector} { margin-block-end: tokens.get('list-number-margin-block', elements.$post-listnumber); padding-inline-start: tokens.get('list-number-item-icon-gap-inline', elements.$post-listnumber); padding-block: tokens.get('list-number-item-text-padding-block', elements.$post-listnumber); @@ -61,8 +61,8 @@ } } -@mixin list-inline() { - @include list-unstyled() { +@mixin list-inline($child-selector: 'li') { + @include list-unstyled($child-selector) { display: flex; flex-wrap: wrap; row-gap: tokens.get('list-bullet-item-gap-block', elements.$post-listbullet); @@ -73,14 +73,14 @@ } } -@mixin list-revert() { +@mixin list-revert($child-selector: 'li') { all: revert; @content; - > li { + > #{$child-selector} { all: revert; - ~ li { + ~ #{$child-selector} { all: revert; } @@ -90,17 +90,17 @@ } } -@mixin list-unstyled() { +@mixin list-unstyled($child-selector: 'li') { all: unset; display: block; list-style: none; @content; - > li { + > #{$child-selector} { all: unset; display: list-item; - ~ li { + ~ #{$child-selector} { all: unset; display: list-item; } diff --git a/packages/styles/src/themes/bootstrap/_utilities.scss b/packages/styles/src/themes/bootstrap/_utilities.scss index 0696634c6c..e8d4bde6d1 100644 --- a/packages/styles/src/themes/bootstrap/_utilities.scss +++ b/packages/styles/src/themes/bootstrap/_utilities.scss @@ -26,6 +26,17 @@ $utilities: map.remove($utilities, 'gap'); $utilities: map.remove($utilities, 'row-gap'); $utilities: map.remove($utilities, 'column-gap'); +$utilities: map.remove($utilities, 'width'); +$utilities: map.remove($utilities, 'height'); +$utilities: map.remove($utilities, 'max-width'); +$utilities: map.remove($utilities, 'max-height'); +$utilities: map.remove($utilities, 'min-width'); +$utilities: map.remove($utilities, 'min-height'); +$utilities: map.remove($utilities, 'viewport-width'); +$utilities: map.remove($utilities, 'viewport-height'); +$utilities: map.remove($utilities, 'min-viewport-width'); +$utilities: map.remove($utilities, 'min-viewport-height'); + $utilities: map.remove($utilities, 'flex'); $utilities: map.remove($utilities, 'flex-direction'); $utilities: map.remove($utilities, 'align-items'); @@ -34,7 +45,9 @@ $utilities: map.remove($utilities, 'align-self'); $utilities: map.remove($utilities, 'flex-grow'); $utilities: map.remove($utilities, 'flex-shrink'); $utilities: map.remove($utilities, 'flex-wrap'); + $utilities: map.remove($utilities, 'order'); + $utilities: map.remove($utilities, 'justify-content'); $utilities: map.remove($utilities, 'display'); diff --git a/packages/styles/src/utilities/_variables.scss b/packages/styles/src/utilities/_variables.scss index d09cf091b1..04b78b2890 100644 --- a/packages/styles/src/utilities/_variables.scss +++ b/packages/styles/src/utilities/_variables.scss @@ -2,6 +2,7 @@ @use './functions' as *; +@use '../variables/sizing' as *; /* Utilities are generated with our utility API using bellow $utilities map. @@ -28,6 +29,126 @@ $position-values: ( ); $utilities: ( + 'width': ( + responsive: true, + property: width, + class: w, + values: $post-combined-sizes, + ), + 'height': ( + responsive: true, + property: height, + class: h, + values: $post-combined-sizes, + ), + 'max-width': ( + responsive: true, + property: max-width, + class: max-w, + values: $post-combined-sizes, + ), + 'max-height': ( + responsive: true, + property: max-height, + class: max-h, + values: $post-combined-sizes, + ), + 'min-width': ( + responsive: true, + property: min-width, + class: min-w, + values: $post-combined-sizes, + ), + 'min-height': ( + responsive: true, + property: min-height, + class: min-h, + values: $post-combined-sizes, + ), + 'viewport-width': ( + responsive: true, + property: width, + class: vw, + values: ( + 0: 0, + 25: 25vw, + 33: 25vw, + 50: 50vw, + 66: 66vw, + 75: 75vw, + 100: 100vw, + ), + ), + 'viewport-height': ( + responsive: true, + property: height, + class: vh, + values: ( + 0: 0, + 25: 25vh, + 33: 33vh, + 50: 50vh, + 66: 66vh, + 75: 75vh, + 100: 100vh, + ), + ), + 'min-viewport-width': ( + responsive: true, + property: min-width, + class: min-vw, + values: ( + 0: 0, + 25: 25vw, + 33: 25vw, + 50: 50vw, + 66: 66vw, + 75: 75vw, + 100: 100vw, + ), + ), + 'min-viewport-height': ( + responsive: true, + property: min-height, + class: min-vh, + values: ( + 0: 0, + 25: 25vh, + 33: 33vh, + 50: 50vh, + 66: 66vh, + 75: 75vh, + 100: 100vh, + ), + ), + 'max-viewport-width': ( + responsive: true, + property: max-width, + class: max-vw, + values: ( + 0: 0, + 25: 25vw, + 33: 25vw, + 50: 50vw, + 66: 66vw, + 75: 75vw, + 100: 100vw, + ), + ), + 'max-viewport-height': ( + responsive: true, + property: max-height, + class: max-vh, + values: ( + 0: 0, + 25: 25vh, + 33: 33vh, + 50: 50vh, + 66: 66vh, + 75: 75vh, + 100: 100vh, + ), + ), 'align': ( property: vertical-align, class: align, diff --git a/packages/styles/src/variables/_breakpoints.scss b/packages/styles/src/variables/_breakpoints.scss index b78ff9ea19..06fa9bf964 100644 --- a/packages/styles/src/variables/_breakpoints.scss +++ b/packages/styles/src/variables/_breakpoints.scss @@ -5,3 +5,11 @@ $grid-breakpoints: ( lg: 1024px, xl: 1280px, ) !default; + +$grid-breakpoints-key-name-map: ( + xs: 'mobile', + sm: 'tablet', + md: 'tablet', + lg: 'desktop', + xl: 'desktop', +); diff --git a/packages/styles/src/variables/_index.scss b/packages/styles/src/variables/_index.scss index aff8c98c7e..a2a1c02cbc 100644 --- a/packages/styles/src/variables/_index.scss +++ b/packages/styles/src/variables/_index.scss @@ -11,5 +11,6 @@ @forward 'icons'; @forward 'options'; @forward 'spacing'; +@forward 'sizing'; @forward 'type'; @forward 'components'; diff --git a/packages/styles/src/variables/_sizing.scss b/packages/styles/src/variables/_sizing.scss new file mode 100644 index 0000000000..139cde6afa --- /dev/null +++ b/packages/styles/src/variables/_sizing.scss @@ -0,0 +1,69 @@ +@use 'sass:map'; + +@use '../functions/tokens'; +@use '../tokens/utilities'; + +tokens.$default-map: utilities.$post-spacing; + +// Sizing +// +// Control the default sizing by modifying these variables. + +// Post-Sizes +$post-px-sizes: () !default; +$post-px-sizes: map.merge( + ( + '0': tokens.get('post-utility-gap-0'), + '1': tokens.get('post-utility-gap-1'), + '2': tokens.get('post-utility-gap-2'), + '3': tokens.get('post-utility-gap-3'), + '4': tokens.get('post-utility-gap-4'), + '5': tokens.get('post-utility-gap-5'), + '6': tokens.get('post-utility-gap-6'), + '8': tokens.get('post-utility-gap-8'), + '10': tokens.get('post-utility-gap-10'), + '11': tokens.get('post-utility-gap-11'), + '12': tokens.get('post-utility-gap-12'), + '14': tokens.get('post-utility-gap-14'), + '15': tokens.get('post-utility-gap-15'), + '16': tokens.get('post-utility-gap-16'), + '18': tokens.get('post-utility-gap-18'), + '19': tokens.get('post-utility-gap-19'), + '20': tokens.get('post-utility-gap-20'), + '22': tokens.get('post-utility-gap-22'), + '24': tokens.get('post-utility-gap-24'), + '26': tokens.get('post-utility-gap-26'), + '28': tokens.get('post-utility-gap-28'), + '30': tokens.get('post-utility-gap-30'), + '32': tokens.get('post-utility-gap-32'), + '34': tokens.get('post-utility-gap-34'), + '36': tokens.get('post-utility-gap-36'), + '40': tokens.get('post-utility-gap-40'), + '48': tokens.get('post-utility-gap-48'), + '56': tokens.get('post-utility-gap-56'), + '64': tokens.get('post-utility-gap-64'), + '78': tokens.get('post-utility-gap-78'), + '80': tokens.get('post-utility-gap-80'), + '96': tokens.get('post-utility-gap-96'), + '100': tokens.get('post-utility-gap-100'), + '112': tokens.get('post-utility-gap-112'), + ), + $post-px-sizes +); + +// This variable affects the `.h-*` and `.w-*` classes. +$post-percentage-sizes: () !default; +$post-percentage-sizes: map.merge( + ( + 'quarter': 25%, + 'third': 33%, + 'half': 50%, + 'two-thirds': 66%, + 'three-quarters': 75%, + 'full': 100%, + auto: auto, + ), + $post-percentage-sizes +); + +$post-combined-sizes: map.merge($post-px-sizes, $post-percentage-sizes); diff --git a/packages/styles/src/variables/_spacing.scss b/packages/styles/src/variables/_spacing.scss index 7c7ee7b242..b4d8528415 100644 --- a/packages/styles/src/variables/_spacing.scss +++ b/packages/styles/src/variables/_spacing.scss @@ -55,19 +55,6 @@ $post-sizes: map.merge( $post-sizes ); -// This variable affects the `.h-*` and `.w-*` classes. -$sizes: () !default; -$sizes: map.merge( - ( - 25: 25%, - 50: 50%, - 75: 75%, - 100: 100%, - auto: auto, - ), - $sizes -); - // Abstand Gross, Section $size-curve-giant: ( 'xs': $size-huge, diff --git a/packages/styles/tests/layouts/portal/index.test.scss b/packages/styles/tests/layouts/portal/index.test.scss deleted file mode 100644 index 477d1c3bf2..0000000000 --- a/packages/styles/tests/layouts/portal/index.test.scss +++ /dev/null @@ -1 +0,0 @@ -@use 'src/layouts/portal'; diff --git a/packages/tokens/CHANGELOG.md b/packages/tokens/CHANGELOG.md index ee303ee4eb..7df602c786 100644 --- a/packages/tokens/CHANGELOG.md +++ b/packages/tokens/CHANGELOG.md @@ -1,5 +1,7 @@ # @swisspost/design-system-tokens +## 9.0.0-next.9 + ## 9.0.0-next.8 ## 9.0.0-next.7 diff --git a/packages/tokens/package.json b/packages/tokens/package.json index ed53edebf7..08f97ec4b3 100644 --- a/packages/tokens/package.json +++ b/packages/tokens/package.json @@ -1,6 +1,6 @@ { "name": "@swisspost/design-system-tokens", - "version": "9.0.0-next.8", + "version": "9.0.0-next.9", "description": "Design Tokens for the Swiss Post Design System.", "author": "Swiss Post ", "license": "Apache-2.0", diff --git a/packages/tokens/tokensstudio-generated/tokens.json b/packages/tokens/tokensstudio-generated/tokens.json index f9f4255a0d..fe27410856 100644 --- a/packages/tokens/tokensstudio-generated/tokens.json +++ b/packages/tokens/tokensstudio-generated/tokens.json @@ -1247,7 +1247,7 @@ "disabled": { "bg": { "$type": "color", - "$value": "{post.core.color.brand.white}" + "$value": "{post.core.color.colorless}" }, "fg": { "$type": "color", @@ -1948,10 +1948,18 @@ } }, "input": { - "enabled": { + "disabled": { + "bg": { + "$type": "color", + "$value": "{post.core.color.colorless}" + }, "border": { "$type": "color", - "$value": "{post.core.color.sandgrey.080}" + "$value": "{post.core.color.sandgrey.alpha.lightsand.60}" + }, + "fg": { + "$type": "color", + "$value": "{post.core.color.sandgrey.alpha.lightsand.60}" } } } @@ -7113,6 +7121,12 @@ "text": { "$type": "spacing", "$value": "{post.device.spacing.padding.block.7}" + }, + "container": { + "text": { + "$type": "spacing", + "$value": "{post.device.spacing.padding.block.9}" + } } }, "inline": { @@ -8957,7 +8971,6 @@ "post.scheme.color.interactive.notification.error.bg": "6165ecb63010c190df5bf65b59d442a4f802a05d", "post.scheme.color.interactive.notification.error.icon": "6a602959aae6c213148ff0f586280a123ebff780", "post.scheme.color.interactive.notification.error.stroke": "f6a25a2fe2b3146d1684d3906e635ef9505a4c23", - "post.scheme.color.interactive.input.enabled.border": "0acd1351445659355ab8d6f7f370fe1c217ebe91", "post.scheme.color.surface.default.bg": "76160b240c5dee3ecddf678e49fb08e554103e19", "post.scheme.color.surface.default.fg": "0497e52aa5f3173648ad5d0a10d8433eb3f229d4", "post.scheme.color.surface.default.stroke": "acff34c0c7e3f3b7360988406c18af0b164393ff", @@ -8989,16 +9002,17 @@ "post.cargo.scheme.color.surface.accent.bg": "2dc2983e13aad7ec4e60552838d56966fa9908d6", "post.cargo.scheme.color.surface.accent.fg": "e724294b65aca52dcb29118010534f0482bd0881", "post.cargo.scheme.color.surface.accent.fg-accent": "9d2202f6c4937b0a006f5bf8886480984ab8efb2", + "post.scheme.color.interactive.input.disabled.bg": "751b8e0c0c47287585e354becf6a35bc76d3ef30", + "post.scheme.color.interactive.input.disabled.border": "03fcc579a4ae77e80ca5f0e8b4a33c17b07b9944", + "post.scheme.color.interactive.input.disabled.fg": "ab50ae4da2b62ef7e661bbd499b51e51b20b6289", "post.scheme.color.signal.neutral-dark": "790da7ad43fa67de3b2da99582d332791fb09e9f", "post.scheme.color.signal.neutral": "daad7eeff08d93aeed6c1ad67af23e58bdffd198", "post.scheme.color.interactive.input.enabled.bg": "ee1559ba9c687a96a4f52b60241ad08d6af675ef", "post.scheme.color.interactive.input.enabled.fg": "c0b646bc7315b3eb57777ada948f08b0fd3d718d", + "post.scheme.color.interactive.input.enabled.border": "0acd1351445659355ab8d6f7f370fe1c217ebe91", "post.scheme.color.interactive.input.hover.bg": "9e0464752dbef48d2c13c82b1865fb29baa976d6", "post.scheme.color.interactive.input.hover.fg": "4191ea628c0c943fa24e832a57e02fce109f0a73", - "post.scheme.color.interactive.input.hover.border": "69ac281e1d33ebdb46f1512dd957323d89a6cc66", - "post.scheme.color.interactive.input.disabled.bg": "751b8e0c0c47287585e354becf6a35bc76d3ef30", - "post.scheme.color.interactive.input.disabled.fg": "ab50ae4da2b62ef7e661bbd499b51e51b20b6289", - "post.scheme.color.interactive.input.disabled.border": "03fcc579a4ae77e80ca5f0e8b4a33c17b07b9944" + "post.scheme.color.interactive.input.hover.border": "69ac281e1d33ebdb46f1512dd957323d89a6cc66" } }, { @@ -10490,6 +10504,7 @@ "post.switch.element.handle": "c09fd2baa596cab64d62c4fb1fca8fa8c26291c5", "post.switch.gap.inline.text": "247b45d301bcca98b2d94934a5bf224368055263", "post.switch.padding.block.text": "fdf8cc0d615a1cd0116f36d0e88f0909474b74c2", + "post.switch.padding.block.container.text": "29cbdc47443a3446365e6d2120aabaadd5072b50", "post.switch.padding.inline.handle": "b512bd24b1efc090fbf71338c7581b91be49db5c", "post.switch.border-radius.round": "4cc09b8f409accc41f0553e1fb332ba603b3e501", "post.switch.border-width": "c45a9f2a969bb1f731fbb1f2c1433a57d238be0e", @@ -10597,14 +10612,14 @@ "post.toast.color.error-icon": "3096bb0553257be18a766df213ba83685ab63040", "post.validation.group.gap.inline": "a76607434c393d743d38b71824d9d76e533acca2", "post.validation.group.icon.size": "ce5d0ae47c1f80a7ea39a6e5b25a00055c450e7d", + "post.validation.group.icon.block.start": "e52e3d301a820f000d2cd339f1fab72a5f09ce81", + "post.validation.group.icon.block.end": "f30710c36d79b96b33c33ad8e67524cc1ae3cd7a", + "post.validation.group.padding.inline.start": "37c8364dbc202912a5a557a5f8cc026e1f84a3bf", "post.validation.error": "796bdb2fc917b5948438070371ae60d214216795", "post.validation.success": "b59a525aa81840396e6310baa880de4a66d23371", "post.validation.input.padding.block": "4006573d3a03f1b053a844aaf89e14742a3d3646", "post.validation.input.padding.inline": "8df0e5f5587acbb1f7acb67a97e200e2175d6469", - "post.validation.font-size": "67f550629b478f48c1579f8acb13edceabbaee4f", - "post.validation.group.padding.inline.start": "37c8364dbc202912a5a557a5f8cc026e1f84a3bf", - "post.validation.group.icon.block.start": "e52e3d301a820f000d2cd339f1fab72a5f09ce81", - "post.validation.group.icon.block.end": "f30710c36d79b96b33c33ad8e67524cc1ae3cd7a" + "post.validation.font-size": "67f550629b478f48c1579f8acb13edceabbaee4f" } }, { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 147b78436b..93cd856493 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,10 +47,10 @@ importers: specifier: 0.3.7 version: 0.3.7 '@swisspost/design-system-icons': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../icons '@swisspost/design-system-styles': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../styles/dist ally.js: specifier: 1.4.1 @@ -159,10 +159,10 @@ importers: specifier: 18.2.13 version: 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8)))(rxjs@7.8.1) '@swisspost/design-system-components': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../components '@swisspost/design-system-styles': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../styles/dist rxjs: specifier: 7.8.1 @@ -241,7 +241,7 @@ importers: specifier: ^16.0.0 || ^17.0.0 || ^18.0.0 version: 18.1.1(rxjs@7.8.1)(zone.js@0.14.8) '@swisspost/design-system-components': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../../../components tslib: specifier: 2.6.3 @@ -251,7 +251,7 @@ importers: packages/components-react: dependencies: '@swisspost/design-system-components': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../components devDependencies: '@types/node': @@ -303,22 +303,22 @@ importers: packages/documentation: dependencies: '@swisspost/design-system-components': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../components '@swisspost/design-system-components-react': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../components-react '@swisspost/design-system-icons': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../icons '@swisspost/design-system-styles': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../styles/dist '@swisspost/design-system-tokens': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../tokens/dist '@swisspost/internet-header': - specifier: workspace:2.0.0-next.8 + specifier: workspace:2.0.0-next.9 version: link:../internet-header bootstrap: specifier: 5.3.3 @@ -376,10 +376,10 @@ importers: specifier: 8.3.6 version: 8.3.6(lit@3.1.4)(storybook@8.2.7(@babel/preset-env@7.25.3(@babel/core@7.25.2)))(typescript@5.5.4)(vite@5.4.8(@types/node@22.7.9)(less@4.2.0)(sass-embedded@1.78.0)(sass@1.78.0)(terser@5.31.6)) '@swisspost/design-system-components-angular': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../components-angular/dist/components '@swisspost/design-system-intranet-header': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../intranet-header-workspace/dist/intranet-header '@types/css-modules': specifier: 1.0.5 @@ -520,7 +520,7 @@ importers: packages/internet-header: dependencies: '@swisspost/design-system-styles': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../styles/dist body-scroll-lock: specifier: 4.0.0-beta.0 @@ -671,7 +671,7 @@ importers: specifier: 2.11.8 version: 2.11.8 '@swisspost/design-system-styles': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../styles/dist rxjs: specifier: 7.8.1 @@ -765,21 +765,21 @@ importers: specifier: ^16.0.0 || ^17.0.0 || ^18.0.0 version: 18.1.1(rxjs@7.8.1)(zone.js@0.14.8) '@swisspost/design-system-styles': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../../../styles/dist tslib: specifier: 2.6.3 version: 2.6.3 devDependencies: '@swisspost/design-system-intranet-header-workspace': - specifier: workspace:3.0.22-next.8 + specifier: workspace:3.0.22-next.9 version: link:../.. publishDirectory: ../../dist/intranet-header packages/intranet-header-workspace/projects/intranet-header-showcase: dependencies: '@swisspost/design-system-intranet-header': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../../dist/intranet-header packages/migrations: @@ -825,13 +825,13 @@ importers: packages/nextjs-integration: dependencies: '@swisspost/design-system-components-react': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../components-react '@swisspost/design-system-styles': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../styles/dist '@swisspost/internet-header': - specifier: workspace:2.0.0-next.8 + specifier: workspace:2.0.0-next.9 version: link:../internet-header next: specifier: 15.0.1 @@ -893,10 +893,10 @@ importers: version: 3.0.0 devDependencies: '@swisspost/design-system-icons': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../icons '@swisspost/design-system-tokens': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../tokens/dist '@types/node': specifier: 20.14.14 @@ -987,7 +987,7 @@ importers: specifier: 18.2.13 version: 18.2.13(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8))(@angular/platform-browser@18.2.13(@angular/animations@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8)))(@angular/common@18.2.13(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8))(rxjs@7.8.1))(@angular/core@18.2.13(rxjs@7.8.1)(zone.js@0.14.8)))(rxjs@7.8.1) '@swisspost/design-system-styles': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../styles/dist primeng: specifier: 17.18.7 @@ -1063,7 +1063,7 @@ importers: specifier: ^18.0.0 version: 18.1.1(rxjs@7.8.1)(zone.js@0.14.8) '@swisspost/design-system-styles': - specifier: workspace:9.0.0-next.8 + specifier: workspace:9.0.0-next.9 version: link:../../../styles/dist primeng: specifier: ^17.18.0 @@ -15803,7 +15803,7 @@ snapshots: axios@1.7.7: dependencies: - follow-redirects: 1.15.6(debug@4.3.7) + follow-redirects: 1.15.6(debug@4.3.6) form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -18513,7 +18513,7 @@ snapshots: http-proxy-middleware@2.0.6(@types/express@4.17.21): dependencies: '@types/http-proxy': 1.17.15 - http-proxy: 1.18.1(debug@4.3.7) + http-proxy: 1.18.1 is-glob: 4.0.3 is-plain-obj: 3.0.0 micromatch: 4.0.8 @@ -18533,6 +18533,14 @@ snapshots: transitivePeerDependencies: - supports-color + http-proxy@1.18.1: + dependencies: + eventemitter3: 4.0.7 + follow-redirects: 1.15.6(debug@4.3.6) + requires-port: 1.0.0 + transitivePeerDependencies: + - debug + http-proxy@1.18.1(debug@4.3.7): dependencies: eventemitter3: 4.0.7 @@ -18548,7 +18556,7 @@ snapshots: corser: 2.0.1 he: 1.2.0 html-encoding-sniffer: 3.0.0 - http-proxy: 1.18.1(debug@4.3.7) + http-proxy: 1.18.1 mime: 1.6.0 minimist: 1.2.8 opener: 1.5.2 @@ -19684,7 +19692,7 @@ snapshots: dom-serialize: 2.2.1 glob: 7.2.3 graceful-fs: 4.2.11 - http-proxy: 1.18.1(debug@4.3.7) + http-proxy: 1.18.1 isbinaryfile: 4.0.10 lodash: 4.17.21 log4js: 6.9.1