diff --git a/packages/angular-standalone-test-app/src/preview-examples/content-header-no-back.html b/packages/angular-standalone-test-app/src/preview-examples/content-header-no-back.html index b29415b708f..eca87875097 100644 --- a/packages/angular-standalone-test-app/src/preview-examples/content-header-no-back.html +++ b/packages/angular-standalone-test-app/src/preview-examples/content-header-no-back.html @@ -12,11 +12,11 @@ headerTitle="Content title" headerSubtitle="Subtitle" > - Button1 - + Button1 + Button2 - + Button3 diff --git a/packages/angular-standalone-test-app/src/preview-examples/content-header-with-slot.html b/packages/angular-standalone-test-app/src/preview-examples/content-header-with-slot.html index c94bf9c7019..969f5f59324 100644 --- a/packages/angular-standalone-test-app/src/preview-examples/content-header-with-slot.html +++ b/packages/angular-standalone-test-app/src/preview-examples/content-header-with-slot.html @@ -13,7 +13,8 @@ header-subtitle="Subtitle" > Label - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 + Important diff --git a/packages/angular-standalone-test-app/src/preview-examples/content-header.html b/packages/angular-standalone-test-app/src/preview-examples/content-header.html index 9dc2c413a9f..a30da7ffe2c 100644 --- a/packages/angular-standalone-test-app/src/preview-examples/content-header.html +++ b/packages/angular-standalone-test-app/src/preview-examples/content-header.html @@ -12,7 +12,7 @@ headerTitle="Content title" headerSubtitle="Subtitle" > - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 diff --git a/packages/angular-test-app/src/preview-examples/content-header-no-back.html b/packages/angular-test-app/src/preview-examples/content-header-no-back.html index 9eb7105b1db..3b9c1f73f9e 100644 --- a/packages/angular-test-app/src/preview-examples/content-header-no-back.html +++ b/packages/angular-test-app/src/preview-examples/content-header-no-back.html @@ -12,11 +12,11 @@ headerTitle="Content title" headerSubtitle="Subtitle" > - Button1 - + Button1 + Button2 - + Button3 diff --git a/packages/angular-test-app/src/preview-examples/content-header-with-slot.html b/packages/angular-test-app/src/preview-examples/content-header-with-slot.html index c94bf9c7019..969f5f59324 100644 --- a/packages/angular-test-app/src/preview-examples/content-header-with-slot.html +++ b/packages/angular-test-app/src/preview-examples/content-header-with-slot.html @@ -13,7 +13,8 @@ header-subtitle="Subtitle" > Label - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 + Important diff --git a/packages/angular-test-app/src/preview-examples/content-header.html b/packages/angular-test-app/src/preview-examples/content-header.html index 99504615115..2fd47c69365 100644 --- a/packages/angular-test-app/src/preview-examples/content-header.html +++ b/packages/angular-test-app/src/preview-examples/content-header.html @@ -12,7 +12,7 @@ headerTitle="Content title" headerSubtitle="Subtitle" > - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 diff --git a/packages/core/src/components/button/button-mixin.scss b/packages/core/src/components/button/button-mixin.scss index d256326c525..76d36a24e43 100644 --- a/packages/core/src/components/button/button-mixin.scss +++ b/packages/core/src/components/button/button-mixin.scss @@ -94,15 +94,12 @@ display: inline-flex; flex-direction: row; flex-wrap: nowrap; - - overflow: hidden; - align-items: center; justify-content: center; width: 100%; height: 100%; - + overflow: var(--ix-button-inner-overflow, hidden); padding: var(--ix-button-padding, 0 0.5rem); } @@ -112,7 +109,8 @@ --ix-button-border-radius-right: var(--theme-btn--border-radius); display: inline-block; - height: 2rem; + height: var(--ix-button-height, 2rem); + min-height: var(--ix-button-min-height, 2rem); vertical-align: middle; cursor: pointer; @@ -131,9 +129,10 @@ .content { display: inline-block; position: relative; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; + overflow: var(--ix-button-content-overflow, hidden); + white-space: var(--ix-button-text-white-space, nowrap); + text-overflow: var(--ix-button-content-text-overflow, ellipsis); + word-break: var(--ix-button-word-break, normal); } .content-start { diff --git a/packages/core/src/components/content-header/content-header.scss b/packages/core/src/components/content-header/content-header.scss index b973297e24f..08356455e8e 100644 --- a/packages/core/src/components/content-header/content-header.scss +++ b/packages/core/src/components/content-header/content-header.scss @@ -18,12 +18,10 @@ flex-direction: column; flex: 1 1 0; min-width: 0; - white-space: nowrap; margin-right: 0.5rem; .titleOverflow { - overflow: hidden; - text-overflow: ellipsis; + overflow-wrap: break-word; } .headerTitleRow { @@ -51,4 +49,19 @@ .buttons { flex: 0 0 auto; } + + .actions { + flex: 0 0 auto; + display: flex; + flex-wrap: wrap; + align-items: center; + + ::slotted([slot='secondary-actions']) { + --ix-button-height: 2rem; + --ix-button-text-white-space: normal; + --ix-button-word-break: break-word; + --ix-button-inner-overflow: visible; + --ix-button-content-overflow: visible; + } + } } diff --git a/packages/core/src/components/content-header/content-header.tsx b/packages/core/src/components/content-header/content-header.tsx index d4d7ace2bc1..65797ca0dbd 100644 --- a/packages/core/src/components/content-header/content-header.tsx +++ b/packages/core/src/components/content-header/content-header.tsx @@ -7,13 +7,25 @@ * LICENSE file in the root directory of this source tree. */ -import { iconArrowLeft } from '@siemens/ix-icons/icons'; -import { Component, Event, EventEmitter, h, Host, Prop } from '@stencil/core'; +import { iconArrowLeft, iconMoreMenu } from '@siemens/ix-icons/icons'; +import { + Component, + Element, + Event, + EventEmitter, + h, + Host, + Prop, + State, +} from '@stencil/core'; import type { ContentHeaderVariant } from './content-header.types'; +const SMALL_BREAKPOINT_QUERY = '(max-width: 48em)'; + /** * @slot header - Content to be placed in the header area next to the title - * @slot - Default slot for action buttons or other content + * @slot secondary-actions - Secondary action buttons that collapse into the overflow menu on small viewports + * @slot - Default slot for primary content that remains visible at all viewport sizes */ @Component({ tag: 'ix-content-header', @@ -21,6 +33,8 @@ import type { ContentHeaderVariant } from './content-header.types'; shadow: true, }) export class ContentHeader { + @Element() hostElement!: HTMLIxContentHeaderElement; + /** * Variant of content header */ @@ -46,12 +60,85 @@ export class ContentHeader { */ @Event() backButtonClick!: EventEmitter; + @State() isSmallBreakpoint = false; + @State() hasSecondaryActions = false; + + mediaQuery?: MediaQueryList; + hasDisconnected = false; + secondarySlot: HTMLSlotElement | null = null; + + readonly mediaQueryHandler = (e: MediaQueryListEvent) => { + this.isSmallBreakpoint = e.matches; + }; + + readonly slotChangeHandler = () => this.checkSecondarySlot(); + + checkSecondarySlot() { + this.hasSecondaryActions = Array.from(this.hostElement.childNodes).some( + (node) => { + if (node.nodeType === Node.TEXT_NODE) { + return false; + } + return (node as Element).getAttribute?.('slot') === 'secondary-actions'; + } + ); + } + + componentWillLoad() { + if (globalThis.window !== undefined) { + this.mediaQuery = globalThis.window.matchMedia(SMALL_BREAKPOINT_QUERY); + this.isSmallBreakpoint = this.mediaQuery.matches; + this.mediaQuery.addEventListener('change', this.mediaQueryHandler); + } + } + + componentDidLoad() { + this.checkSecondarySlot(); + + const slot = this.hostElement.shadowRoot?.querySelector( + 'slot[name="secondary-actions"]' + ) as HTMLSlotElement | null; + + if (slot) { + this.secondarySlot = slot; + slot.addEventListener('slotchange', this.slotChangeHandler); + } + } + + connectedCallback() { + if (this.hasDisconnected && globalThis.window !== undefined) { + this.mediaQuery = globalThis.window.matchMedia(SMALL_BREAKPOINT_QUERY); + this.isSmallBreakpoint = this.mediaQuery.matches; + this.mediaQuery.addEventListener('change', this.mediaQueryHandler); + + const slot = this.hostElement.shadowRoot?.querySelector( + 'slot[name="secondary-actions"]' + ) as HTMLSlotElement | null; + + if (slot) { + this.secondarySlot = slot; + slot.addEventListener('slotchange', this.slotChangeHandler); + } + } + } + + disconnectedCallback() { + if (this.mediaQuery) { + this.mediaQuery.removeEventListener('change', this.mediaQueryHandler); + } + this.secondarySlot?.removeEventListener( + 'slotchange', + this.slotChangeHandler + ); + this.hasDisconnected = true; + } + render() { return ( {this.hasBackButton ? ( this.backButtonClick.emit()} @@ -75,8 +162,8 @@ export class ContentHeader { {!!this.headerSubtitle && ( )} -
- -
+ + {this.isSmallBreakpoint ? ( +
+ + {this.hasSecondaryActions && ( + + + + )} +
+ ) : ( +
+ + +
+ )}
); } diff --git a/packages/html-test-app/src/preview-examples/content-header-no-back.html b/packages/html-test-app/src/preview-examples/content-header-no-back.html index c8eeaa65e4e..b32ef5aefcf 100644 --- a/packages/html-test-app/src/preview-examples/content-header-no-back.html +++ b/packages/html-test-app/src/preview-examples/content-header-no-back.html @@ -33,13 +33,13 @@ header-title="Content title" header-subtitle="Subtitle" > - + Button1 - + Button2 - + Button3 diff --git a/packages/html-test-app/src/preview-examples/content-header-with-slot.html b/packages/html-test-app/src/preview-examples/content-header-with-slot.html index d9d65524278..4d2a459cbc0 100644 --- a/packages/html-test-app/src/preview-examples/content-header-with-slot.html +++ b/packages/html-test-app/src/preview-examples/content-header-with-slot.html @@ -30,9 +30,10 @@ header-subtitle="Subtitle" > Label - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 + Important diff --git a/packages/html-test-app/src/preview-examples/content-header.html b/packages/html-test-app/src/preview-examples/content-header.html index 5eecdaf7146..3a2ae65304f 100644 --- a/packages/html-test-app/src/preview-examples/content-header.html +++ b/packages/html-test-app/src/preview-examples/content-header.html @@ -20,9 +20,9 @@ header-title="Content title" header-subtitle="Subtitle" > - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 diff --git a/packages/react-test-app/src/preview-examples/content-header-no-back.tsx b/packages/react-test-app/src/preview-examples/content-header-no-back.tsx index a1f46370ae7..a282b976c07 100644 --- a/packages/react-test-app/src/preview-examples/content-header-no-back.tsx +++ b/packages/react-test-app/src/preview-examples/content-header-no-back.tsx @@ -21,13 +21,13 @@ export default () => { header-title="Content title" header-subtitle="Subtitle" > - + Button1 - + Button2 - + Button3 diff --git a/packages/react-test-app/src/preview-examples/content-header-with-slot.tsx b/packages/react-test-app/src/preview-examples/content-header-with-slot.tsx index b71e01a30e4..b5e0d8b1364 100644 --- a/packages/react-test-app/src/preview-examples/content-header-with-slot.tsx +++ b/packages/react-test-app/src/preview-examples/content-header-with-slot.tsx @@ -21,9 +21,10 @@ export default () => { Label - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 + Important ); }; diff --git a/packages/react-test-app/src/preview-examples/content-header.tsx b/packages/react-test-app/src/preview-examples/content-header.tsx index 7da1b544556..a1b3bb190d7 100644 --- a/packages/react-test-app/src/preview-examples/content-header.tsx +++ b/packages/react-test-app/src/preview-examples/content-header.tsx @@ -16,9 +16,9 @@ export default () => { header-title="Content title" header-subtitle="Subtitle" > - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 ); }; diff --git a/packages/vue-test-app/src/preview-examples/content-header-no-back.vue b/packages/vue-test-app/src/preview-examples/content-header-no-back.vue index c4e2ee96097..8a5d1549310 100644 --- a/packages/vue-test-app/src/preview-examples/content-header-no-back.vue +++ b/packages/vue-test-app/src/preview-examples/content-header-no-back.vue @@ -22,13 +22,13 @@ import { IxContentHeader, IxIconButton } from '@siemens/ix-vue'; header-title="Content title" header-subtitle="Subtitle" > - + Button1 - + Button2 - + Button3 diff --git a/packages/vue-test-app/src/preview-examples/content-header-with-slot.vue b/packages/vue-test-app/src/preview-examples/content-header-with-slot.vue index 37176cdca8a..3f01abce6fe 100644 --- a/packages/vue-test-app/src/preview-examples/content-header-with-slot.vue +++ b/packages/vue-test-app/src/preview-examples/content-header-with-slot.vue @@ -17,8 +17,9 @@ import { iconInfo } from '@siemens/ix-icons/icons'; diff --git a/packages/vue-test-app/src/preview-examples/content-header.vue b/packages/vue-test-app/src/preview-examples/content-header.vue index cc97abfafe7..ead39eaee3e 100644 --- a/packages/vue-test-app/src/preview-examples/content-header.vue +++ b/packages/vue-test-app/src/preview-examples/content-header.vue @@ -17,8 +17,8 @@ import { IxButton, IxContentHeader } from '@siemens/ix-vue'; header-title="Content title" header-subtitle="Subtitle" > - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 diff --git a/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-basic-1-chromium---classic-dark-linux.png b/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-basic-1-chromium---classic-dark-linux.png index 1b318c78220..9abdd3b8aa7 100644 Binary files a/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-basic-1-chromium---classic-dark-linux.png and b/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-basic-1-chromium---classic-dark-linux.png differ diff --git a/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-basic-1-chromium---classic-light-linux.png b/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-basic-1-chromium---classic-light-linux.png index 688d1120e47..4a25568fc63 100644 Binary files a/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-basic-1-chromium---classic-light-linux.png and b/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-basic-1-chromium---classic-light-linux.png differ diff --git a/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-secondary-1-chromium---classic-dark-linux.png b/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-secondary-1-chromium---classic-dark-linux.png index 3dfb5a3429b..b53a9768206 100644 Binary files a/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-secondary-1-chromium---classic-dark-linux.png and b/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-secondary-1-chromium---classic-dark-linux.png differ diff --git a/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-secondary-1-chromium---classic-light-linux.png b/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-secondary-1-chromium---classic-light-linux.png index fedff546231..e06cfd065be 100644 Binary files a/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-secondary-1-chromium---classic-light-linux.png and b/testing/visual-testing/__screenshots__/tests/content-header/content-header.e2e.ts/content-header-secondary-1-chromium---classic-light-linux.png differ diff --git a/testing/visual-testing/tests/content-header/basic/index.html b/testing/visual-testing/tests/content-header/basic/index.html index 1d877dc1404..467d256ef14 100644 --- a/testing/visual-testing/tests/content-header/basic/index.html +++ b/testing/visual-testing/tests/content-header/basic/index.html @@ -17,9 +17,16 @@ .margin-top { margin-top: 0.375rem; } + ix-pill { margin-left: 0.25rem; } + + .wrap-test-button { + width: 5rem; + min-width: 5rem; + max-width: 5rem; + } @@ -44,9 +53,9 @@ header-title="content title" header-subtitle="subtitle content" > - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 Label - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 + Important + Label - Button1 - Button2 - Button3 + + button text wrapping when it is really long + + + button text wrapping when it is really long + + + button text wrapping when it is really long + + Important - Button1 - + + Button1 + + Button2 - + Button3 + + + diff --git a/testing/visual-testing/tests/content-header/secondary/index.html b/testing/visual-testing/tests/content-header/secondary/index.html index 96fee1d83fe..e51e2cbcd92 100644 --- a/testing/visual-testing/tests/content-header/secondary/index.html +++ b/testing/visual-testing/tests/content-header/secondary/index.html @@ -17,9 +17,16 @@ .margin-top { margin-top: 0.375rem; } + ix-pill { margin-left: 0.25rem; } + + .wrap-test-button { + width: 5rem; + min-width: 5rem; + max-width: 5rem; + } @@ -45,10 +54,11 @@ header-title="content title" header-subtitle="subtitle content" > - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 + Label - Button1 - Button2 - Button3 + Button1 + Button2 + Button3 + Important + Label - Button1 - Button2 - Button3 + + button text wrapping when it is really long + + + button text wrapping when it is really long + + + button text wrapping when it is really long + + Important + - Button1 - + + Button1 + + Button2 - + Button3 + + + diff --git a/testing/visual-testing/tests/content/basic/index.html b/testing/visual-testing/tests/content/basic/index.html index fac6d248086..258ddc1de6d 100644 --- a/testing/visual-testing/tests/content/basic/index.html +++ b/testing/visual-testing/tests/content/basic/index.html @@ -25,7 +25,7 @@ - + Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam