diff --git a/.changeset/clean-dodos-joke.md b/.changeset/clean-dodos-joke.md new file mode 100644 index 0000000000..822a6c8ec1 --- /dev/null +++ b/.changeset/clean-dodos-joke.md @@ -0,0 +1,5 @@ +--- +'@swisspost/internet-header': patch +--- + +Improve the main navigation slot placement and styling. diff --git a/.changeset/many-pets-divide.md b/.changeset/many-pets-divide.md new file mode 100644 index 0000000000..ee561400cc --- /dev/null +++ b/.changeset/many-pets-divide.md @@ -0,0 +1,5 @@ +--- +'@swisspost/design-system-documentation': minor +--- + +Add a page on how to add custom content to the internet header main navigation. diff --git a/packages/documentation/src/stories/components/internet-header/components/header/header.stories.ts b/packages/documentation/src/stories/components/internet-header/components/header/header.stories.ts index 9ba76acfbf..acd9b41ba6 100644 --- a/packages/documentation/src/stories/components/internet-header/components/header/header.stories.ts +++ b/packages/documentation/src/stories/components/internet-header/components/header/header.stories.ts @@ -1,8 +1,7 @@ import { Args, Meta, StoryObj } from '@storybook/web-components'; import { BADGE } from '../../../../../../.storybook/constants'; import { html } from 'lit'; -import { spread } from '@open-wc/lit-helpers'; -import { getAttributes } from '../../../../../utils'; +import { spreadArgs } from '../../../../../utils'; import customConfig from './config/custom-config'; import osFlyoutOverrides from './config/os-flyout-overrides'; import languageSwitchOverrides from './config/language-switch-overrides'; @@ -172,10 +171,9 @@ const meta: Meta = { ], }; -function render(args: Args) { - const attributes = getAttributes(args, arg => arg !== null && arg !== undefined); +function render({ innerHMTL, ...args }: Args) { return html` - + `; } @@ -217,3 +215,9 @@ export const OSFlyoutOverrides: Story = { }, }, }; + +export const CustomContent: Story = { + args: { + innerHTML: `

Hello, User!

`, + }, +}; diff --git a/packages/documentation/src/stories/components/internet-header/components/header/overrides-stories/header-custom-content.docs.mdx b/packages/documentation/src/stories/components/internet-header/components/header/overrides-stories/header-custom-content.docs.mdx new file mode 100644 index 0000000000..3d820b1ba3 --- /dev/null +++ b/packages/documentation/src/stories/components/internet-header/components/header/overrides-stories/header-custom-content.docs.mdx @@ -0,0 +1,12 @@ +import { Meta, Canvas, Controls } from '@storybook/blocks'; +import * as HeaderStories from './header-custom-content.stories'; +import '../header.scss'; + + + +
+

Internet Header with Custom Content

+

When you need to add your own content to the main navigation.

+
+ + diff --git a/packages/documentation/src/stories/components/internet-header/components/header/overrides-stories/header-custom-content.stories.ts b/packages/documentation/src/stories/components/internet-header/components/header/overrides-stories/header-custom-content.stories.ts new file mode 100644 index 0000000000..a7e63f4528 --- /dev/null +++ b/packages/documentation/src/stories/components/internet-header/components/header/overrides-stories/header-custom-content.stories.ts @@ -0,0 +1,8 @@ +import * as HeaderStories from '../header.stories'; + +export default { + ...HeaderStories.default, + title: 'Components/Internet Header/Header/Custom Content', +}; + +export const Default = HeaderStories.CustomContent; diff --git a/packages/internet-header/cypress/e2e/main-slot.cy.ts b/packages/internet-header/cypress/e2e/main-slot.cy.ts new file mode 100644 index 0000000000..481fdc6f7d --- /dev/null +++ b/packages/internet-header/cypress/e2e/main-slot.cy.ts @@ -0,0 +1,101 @@ +import { prepare } from '../support/prepare-story'; + +describe('main-navigation', () => { + describe('slotted element: false', () => { + beforeEach(() => { + prepare('Internet Header/Header', 'Default'); + }); + + it('should not have any custom content', () => { + cy.get('swisspost-internet-header').find('[slot=main]').should('not.exist'); + cy.get('swisspost-internet-header') + .shadow() + .find('.main-navigation-custom-content') + .should('not.exist'); + }); + }); + + describe('slotted element: true', () => { + beforeEach(() => { + prepare('Internet Header/Header/Custom Content', 'Default'); + + cy.get('swisspost-internet-header').find('[slot=main]').as('slotted-element'); + cy.get('swisspost-internet-header') + .shadow() + .find('.main-navigation-custom-content') + .as('custom-content'); + }); + + it('should have custom content', () => { + cy.get('@slotted-element').should('exist'); + cy.get('@custom-content').should('exist'); + }); + + it('should show custom content on mobile', () => { + cy.viewport('iphone-6+'); + cy.get('@custom-content').should('exist'); + }); + + it('should show custom content before the search', () => { + cy.get('@custom-content').next().should('have.prop', 'tagName').should('eq', 'POST-SEARCH'); + }); + + it('should show custom content before the login when the search is disabled', () => { + cy.changeArg('search', false); + + cy.get('@custom-content') + .next() + .should('have.prop', 'tagName') + .should('eq', 'POST-KLP-LOGIN-WIDGET'); + }); + + it('should show custom content before the language switch when the search, login and meta are disabled', () => { + cy.changeArg('meta', false); + cy.changeArg('search', false); + cy.changeArg('login', false); + + cy.get('@custom-content') + .next() + .should('have.prop', 'tagName') + .should('eq', 'POST-LANGUAGE-SWITCH'); + }); + + it('should show a border on the left of the custom content', () => { + cy.get('@custom-content').should('not.have.css', 'border-left-width', '0px'); + }); + + it('should not stretched the header when the slotted element is high', () => { + cy.get('@custom-content') + .invoke('outerHeight') + .then(headerHeight => { + if (typeof headerHeight === 'undefined') + throw new Error('No Height found for .main-navigation-custom-content'); + + cy.get('@slotted-element').invoke('css', 'height', `${headerHeight + 100}px`); + cy.get('@custom-content').invoke('outerHeight').should('eq', headerHeight); + }); + }); + + it('should not squash other navigation elements when the slotted element is wide', async () => { + cy.document().then(document => { + cy.get('@slotted-element').invoke('css', 'width', `${document.body.clientWidth}px`); + }); + + cy.get('swisspost-internet-header') + .shadow() + .get('#post-internet-header-search-button, #post-klp-login-widget') + .then($navigationControls => { + cy.get('.main-link').then($mainLinks => + $mainLinks.toArray().concat($navigationControls.toArray()), + ); + }) + .each($el => { + cy.wrap($el).should(() => { + const { scrollWidth, clientWidth } = $el.get(0); + expect(clientWidth).not.to.equal(0); + expect(scrollWidth).not.to.be.greaterThan(clientWidth); + }); + }); + }); + }); +}); diff --git a/packages/internet-header/src/components/post-internet-header/post-internet-header.scss b/packages/internet-header/src/components/post-internet-header/post-internet-header.scss index 399bc0a865..9d751908b2 100644 --- a/packages/internet-header/src/components/post-internet-header/post-internet-header.scss +++ b/packages/internet-header/src/components/post-internet-header/post-internet-header.scss @@ -72,7 +72,7 @@ display: flex; & > .main-navigation-controls { - flex: 0 0 auto; + flex: 0 1 auto; } } @@ -108,9 +108,17 @@ & > * { border-left: 1px solid color.$gray-10; + flex: 0 0 auto; } } +.main-navigation-custom-content { + max-height: var(--header-height); + display: flex; + align-items: center; + flex-shrink: 1; +} + .menu-button { display: flex; align-items: center; diff --git a/packages/internet-header/src/components/post-internet-header/post-internet-header.tsx b/packages/internet-header/src/components/post-internet-header/post-internet-header.tsx index f620eab341..4f6359c383 100644 --- a/packages/internet-header/src/components/post-internet-header/post-internet-header.tsx +++ b/packages/internet-header/src/components/post-internet-header/post-internet-header.tsx @@ -130,6 +130,7 @@ export class PostInternetHeader { @State() activeFlyout: string | null = null; @State() activeDropdownElement: DropdownElement | null = null; + @State() isMainSlotEmpty = true; @Element() host: HTMLSwisspostInternetHeaderElement; /** @@ -431,6 +432,11 @@ export class PostInternetHeader { ); } + private handleMainSlotChange(e: Event) { + const mainSlot = e.target as HTMLSlotElement; + this.isMainSlotEmpty = mainSlot.assignedElements().length === 0; + } + render() { if (!state.localizedConfig?.header) { console.error(new Error('Internet Header: Config cannot be loaded')); @@ -505,6 +511,9 @@ export class PostInternetHeader { diff --git a/packages/internet-header/src/components/post-main-navigation/post-main-navigation.scss b/packages/internet-header/src/components/post-main-navigation/post-main-navigation.scss index 5753ef86ad..9e3264e0bb 100644 --- a/packages/internet-header/src/components/post-main-navigation/post-main-navigation.scss +++ b/packages/internet-header/src/components/post-main-navigation/post-main-navigation.scss @@ -12,6 +12,7 @@ display: block; min-width: 0; height: var(--header-height); + flex-shrink: 0; } :host(.no-animation) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 63ab80ff8a..0c317cdc47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9390,7 +9390,7 @@ packages: engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: browserslist: 4.22.2 caniuse-lite: 1.0.30001566 @@ -9406,7 +9406,7 @@ packages: engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: browserslist: 4.22.2 caniuse-lite: 1.0.30001566 @@ -9422,7 +9422,7 @@ packages: engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: browserslist: 4.21.10 caniuse-lite: 1.0.30001538 @@ -13293,7 +13293,7 @@ packages: resolution: {integrity: sha512-9QUHam5JyXwGUxaaMvoFQVT44tohpEFpM8xBdPfdwTYGM0AItS1iTQz0MpsF8Jroh7GF5Jt2GVPaYgvy8qD2Fw==} engines: {node: ^10 || ^12 || >=14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.0.0 dependencies: fancy-log: 1.3.3 plugin-error: 1.0.1 @@ -13748,7 +13748,7 @@ packages: resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: postcss: 8.4.32 dev: true @@ -17573,7 +17573,7 @@ packages: resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} peerDependencies: - postcss: '>=8.4.31' + postcss: '>=8.0.9' ts-node: '>=9.0.0' peerDependenciesMeta: postcss: @@ -17590,7 +17590,7 @@ packages: resolution: {integrity: sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==} engines: {node: '>= 14.15.0'} peerDependencies: - postcss: '>=8.4.31' + postcss: ^7.0.0 || ^8.0.1 webpack: ^5.0.0 dependencies: cosmiconfig: 8.2.0 @@ -17608,7 +17608,7 @@ packages: resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: postcss: 8.4.32 dev: true @@ -17617,7 +17617,7 @@ packages: resolution: {integrity: sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: icss-utils: 5.1.0(postcss@8.4.32) postcss: 8.4.32 @@ -17629,7 +17629,7 @@ packages: resolution: {integrity: sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: postcss: 8.4.32 postcss-selector-parser: 6.0.13 @@ -17639,7 +17639,7 @@ packages: resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.1.0 dependencies: icss-utils: 5.1.0(postcss@8.4.32) postcss: 8.4.32 @@ -17653,7 +17653,7 @@ packages: resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} engines: {node: '>=12.0'} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.3.3 dependencies: postcss: 8.4.32 dev: true @@ -17662,7 +17662,7 @@ packages: resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} engines: {node: '>=12.0'} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.4.29 dependencies: postcss: 8.4.32 dev: true @@ -17679,7 +17679,7 @@ packages: resolution: {integrity: sha512-FUzyxfI5l2tKmXdYc6VTu3TWZsInayEKPbiyW+P6vmmIrrb4I6CGX0BFoewgYHLK+oIL5FECEK02REYRpBvUCw==} engines: {node: '>=10'} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.0.0 dependencies: make-dir: 3.1.0 mime: 2.5.2 @@ -19631,7 +19631,7 @@ packages: resolution: {integrity: sha512-+Rr2Dd4b72CWA4qoj1Kk+y449nP/WJsrD0nzQAWkmPPIuyVcy2GMIcfNr0Z8JJOLjRvtlkKxa49FCNXMePBikQ==} engines: {node: ^14.13.1 || >=16.13.0 || >=18.0.0} peerDependencies: - postcss: '>=8.4.31' + postcss: ^8.4.21 stylelint: ^15.2.0 || >=15 dependencies: postcss: 8.4.32