-
Notifications
You must be signed in to change notification settings - Fork 134
fix(content-header): allow button label text to wrap on long text and… #2582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
22029b6
798ef5c
ee53886
330237d
8ff3402
a3aa642
730187b
eee9263
44a429e
94cdf7f
6470dc4
971380b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,20 +7,34 @@ | |
| * 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'; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check for changeset files related to content-header
fd -e md . .changeset/ --exec grep -l 'content-header' {} \; || echo "No changeset found for content-header"Repository: siemens/ix Length of output: 92 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== .changeset files (names) =="
ls -1 .changeset 2>/dev/null || echo "(no .changeset dir)"
echo
echo "== Search for content-header / ContentHeader in .changeset =="
rg -n --no-heading "content-header|ContentHeader" .changeset || echo "No matches."
echo
echo "== Search for likely keywords in .changeset =="
rg -n --no-heading "dropdown|responsive|secondary actions|secondary actions|more menu|small viewport" .changeset || echo "No matches."Repository: siemens/ix Length of output: 354 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== .changeset markdown files =="
fd -e md . .changeset --exec basename {} \; | sort | uniq
echo
echo "== Search all changesets for broader terms =="
for pat in "content" "header" "dropdown" "responsive" "secondary" "menu"; do
echo "--- pattern: $pat ---"
rg -n --no-heading "$pat" .changeset --glob '*.md' || echo "No matches for $pat"
echo
doneRepository: siemens/ix Length of output: 708 Add a changeset for the ContentHeader responsive + dropdown behavior 🤖 Prompt for AI AgentsSource: Coding guidelines |
||
| 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', | ||
| styleUrl: 'content-header.scss', | ||
| shadow: true, | ||
| }) | ||
| export class ContentHeader { | ||
| @Element() hostElement!: HTMLIxContentHeaderElement; | ||
|
|
||
| /** | ||
| * Variant of content header | ||
| */ | ||
|
|
@@ -46,12 +60,85 @@ export class ContentHeader { | |
| */ | ||
| @Event() backButtonClick!: EventEmitter<void>; | ||
|
|
||
| @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); | ||
| } | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| 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 ( | ||
| <Host> | ||
| {this.hasBackButton ? ( | ||
| <ix-icon-button | ||
| class={'backButton'} | ||
| class="backButton" | ||
| variant="tertiary" | ||
| icon={iconArrowLeft} | ||
| onClick={() => this.backButtonClick.emit()} | ||
|
|
@@ -75,8 +162,8 @@ export class ContentHeader { | |
| </div> | ||
| {!!this.headerSubtitle && ( | ||
| <ix-typography | ||
| format={'h6'} | ||
| text-color={'soft'} | ||
| format="h6" | ||
| text-color="soft" | ||
| class={{ | ||
| subtitle: this.variant === 'secondary', | ||
| titleOverflow: true, | ||
|
|
@@ -87,9 +174,27 @@ export class ContentHeader { | |
| </ix-typography> | ||
| )} | ||
| </div> | ||
| <div class="buttons"> | ||
| <slot /> | ||
| </div> | ||
|
|
||
| {this.isSmallBreakpoint ? ( | ||
| <div class="actions"> | ||
| <slot /> | ||
| {this.hasSecondaryActions && ( | ||
| <ix-dropdown-button | ||
| icon={iconMoreMenu} | ||
| variant="tertiary" | ||
| label="" | ||
| aria-label="More actions" | ||
| > | ||
| <slot name="secondary-actions" /> | ||
| </ix-dropdown-button> | ||
| )} | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| </div> | ||
| ) : ( | ||
| <div class="actions"> | ||
| <slot name="secondary-actions" /> | ||
| <slot /> | ||
| </div> | ||
| )} | ||
| </Host> | ||
| ); | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.