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