diff --git a/src/components/dialog/dialog-title/dialog-title.scss b/src/components/dialog/dialog-title/dialog-title.scss index a71da6504f..3b20d50edb 100644 --- a/src/components/dialog/dialog-title/dialog-title.scss +++ b/src/components/dialog/dialog-title/dialog-title.scss @@ -1,16 +1,13 @@ @use '../../core/styles' as sbb; -// Box-sizing rules contained in typography are not traversing Shadow DOM boundaries. We need to include box-sizing mixin in every component. -@include sbb.box-sizing; - :host { - --sbb-dialog-header-padding-block: var(--sbb-spacing-responsive-s) 0; + --sbb-dialog-title-padding-block: var(--sbb-spacing-responsive-s) 0; display: contents; } :host([data-overflows]) { - --sbb-dialog-header-padding-block: var(--sbb-spacing-responsive-s); + --sbb-dialog-title-padding-block: var(--sbb-spacing-responsive-s); } .sbb-title { @@ -28,7 +25,7 @@ align-items: start; justify-content: space-between; padding-inline: var(--sbb-dialog-padding-inline); - padding-block: var(--sbb-dialog-header-padding-block); + padding-block: var(--sbb-dialog-title-padding-block); background-color: var(--sbb-dialog-background-color); border-block-end: var(--sbb-dialog-title-border); z-index: var(--sbb-dialog-z-index, var(--sbb-overlay-default-z-index)); diff --git a/src/components/dialog/dialog-title/dialog-title.ts b/src/components/dialog/dialog-title/dialog-title.ts index 5c87cd8477..8514883db3 100644 --- a/src/components/dialog/dialog-title/dialog-title.ts +++ b/src/components/dialog/dialog-title/dialog-title.ts @@ -8,7 +8,7 @@ import { SbbLanguageController } from '../../core/controllers.js'; import type { Breakpoint } from '../../core/dom.js'; import { EventEmitter } from '../../core/eventing.js'; import { i18nCloseDialog, i18nGoBack } from '../../core/i18n.js'; -import { SbbTitleElement } from '../../title.js'; +import { SbbTitleBase } from '../../title.js'; import style from './dialog-title.scss?lit&inline'; @@ -19,14 +19,10 @@ import '../../button/transparent-button.js'; * It displays a title inside a dialog header. * * @event {CustomEvent} requestBackAction - Emits whenever the back button is clicked. - * @cssprop --sbb-title-margin-block-start - This property is inherited from `SbbTitleElement` - * and is not relevant to dialog title margin customization. - * @cssprop --sbb-title-margin-block-end - This property is inherited from `SbbTitleElement` - * and is not relevant to dialog title margin customization. */ @customElement('sbb-dialog-title') -export class SbbDialogTitleElement extends SbbTitleElement { - public static override styles: CSSResultGroup = [SbbTitleElement.styles, style]; +export class SbbDialogTitleElement extends SbbTitleBase { + public static override styles: CSSResultGroup = [SbbTitleBase.styles, style]; public static readonly events: Record = { backClick: 'requestBackAction', } as const; diff --git a/src/components/dialog/dialog-title/readme.md b/src/components/dialog/dialog-title/readme.md index 24bd3d75a1..4bdcc0838c 100644 --- a/src/components/dialog/dialog-title/readme.md +++ b/src/components/dialog/dialog-title/readme.md @@ -42,16 +42,16 @@ If a back button is displayed it emits a `requestBackAction` event on click. ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ------------------------- | --------------------------- | ------- | ---------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `backButton` | `back-button` | public | `boolean` | `false` | Whether a back button is displayed next to the title. | -| `accessibilityCloseLabel` | `accessibility-close-label` | public | `\| string \| undefined` | | This will be forwarded as aria-label to the close button element. | -| `accessibilityBackLabel` | `accessibility-back-label` | public | `\| string \| undefined` | | This will be forwarded as aria-label to the back button element. | -| `hideOnScroll` | `hide-on-scroll` | public | `Breakpoint \| boolean` | `false` | Whether to hide the title up to a certain breakpoint. | -| `level` | `level` | public | `SbbTitleLevel` | `'2'` | Title level | -| `visualLevel` | `visual-level` | public | `SbbTitleLevel \| undefined` | `'3'` | Visual level for the title. Optional, if not set, the value of level will be used. | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | -| `visuallyHidden` | `visually-hidden` | public | `boolean \| undefined` | | Sometimes we need a title in the markup to present a proper hierarchy to the screen readers while we do not want to let that title appear visually. In this case we set visuallyHidden to true | +| Name | Attribute | Privacy | Type | Default | Description | +| ------------------------- | --------------------------- | ------- | ---------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `backButton` | `back-button` | public | `boolean` | `false` | Whether a back button is displayed next to the title. | +| `accessibilityCloseLabel` | `accessibility-close-label` | public | `\| string \| undefined` | | This will be forwarded as aria-label to the close button element. | +| `accessibilityBackLabel` | `accessibility-back-label` | public | `\| string \| undefined` | | This will be forwarded as aria-label to the back button element. | +| `hideOnScroll` | `hide-on-scroll` | public | `Breakpoint \| boolean` | `false` | Whether to hide the title up to a certain breakpoint. | +| `level` | `level` | public | `SbbTitleLevel` | `'2'` | Title level | +| `visualLevel` | `visual-level` | public | `SbbTitleLevel \| undefined` | `'3'` | Visual level for the title. Optional, if not set, the value of level will be used. | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `visuallyHidden` | `visually-hidden` | public | `boolean \| undefined` | | Sometimes we need a title in the markup to present a proper hierarchy to the screen readers while we do not want to let that title appear visually. In this case we set visuallyHidden to true. | ## Events @@ -59,13 +59,6 @@ If a back button is displayed it emits a `requestBackAction` event on click. | ------------------- | ------------------- | ------------------------------------------ | -------------- | | `requestBackAction` | `CustomEvent` | Emits whenever the back button is clicked. | | -## CSS Properties - -| Name | Default | Description | -| -------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------- | -| `--sbb-title-margin-block-start` | `var(--sbb-spacing-responsive-m)` | This property is inherited from `SbbTitleElement` and is not relevant to dialog title margin customization. | -| `--sbb-title-margin-block-end` | `var(--sbb-spacing-responsive-s)` | This property is inherited from `SbbTitleElement` and is not relevant to dialog title margin customization. | - ## Slots | Name | Description | diff --git a/src/components/title.ts b/src/components/title.ts index 62673b3a5c..fe3b1ad626 100644 --- a/src/components/title.ts +++ b/src/components/title.ts @@ -1 +1,2 @@ export * from './title/title.js'; +export * from './title/title-base.js'; diff --git a/src/components/title/readme.md b/src/components/title/readme.md index fa057357bb..62f3237e1d 100644 --- a/src/components/title/readme.md +++ b/src/components/title/readme.md @@ -35,12 +35,12 @@ If the title is needed, but it must to not be displayed, it's possible to use th ## Properties -| Name | Attribute | Privacy | Type | Default | Description | -| ---------------- | ----------------- | ------- | ---------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `level` | `level` | public | `SbbTitleLevel` | `'1'` | Title level | -| `visualLevel` | `visual-level` | public | `SbbTitleLevel \| undefined` | | Visual level for the title. Optional, if not set, the value of level will be used. | -| `visuallyHidden` | `visually-hidden` | public | `boolean \| undefined` | | Sometimes we need a title in the markup to present a proper hierarchy to the screen readers while we do not want to let that title appear visually. In this case we set visuallyHidden to true | -| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| Name | Attribute | Privacy | Type | Default | Description | +| ---------------- | ----------------- | ------- | ---------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `negative` | `negative` | public | `boolean` | `false` | Negative coloring variant flag. | +| `level` | `level` | public | `SbbTitleLevel` | `'1'` | Title level | +| `visualLevel` | `visual-level` | public | `SbbTitleLevel \| undefined` | | Visual level for the title. Optional, if not set, the value of level will be used. | +| `visuallyHidden` | `visually-hidden` | public | `boolean \| undefined` | | Sometimes we need a title in the markup to present a proper hierarchy to the screen readers while we do not want to let that title appear visually. In this case we set visuallyHidden to true. | ## CSS Properties diff --git a/src/components/title/title-base.ts b/src/components/title/title-base.ts new file mode 100644 index 0000000000..67a7a9740f --- /dev/null +++ b/src/components/title/title-base.ts @@ -0,0 +1,58 @@ +import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit'; +import { LitElement } from 'lit'; +import { property } from 'lit/decorators.js'; +import { html, unsafeStatic } from 'lit/static-html.js'; + +import { hostAttributes } from '../core/decorators.js'; +import { SbbNegativeMixin } from '../core/mixins.js'; + +import style from './title-common.scss?lit&inline'; + +export type SbbTitleLevel = '1' | '2' | '3' | '4' | '5' | '6'; + +/** + * It displays a title with a heading role. + * + * @slot - Use the unnamed slot to display the title. + */ +@hostAttributes({ + role: 'heading', +}) +export abstract class SbbTitleBase extends SbbNegativeMixin(LitElement) { + public static override styles: CSSResultGroup = style; + + /** Title level */ + @property({ reflect: true }) public level: SbbTitleLevel = '1'; + + /** Visual level for the title. Optional, if not set, the value of level will be used. */ + @property({ attribute: 'visual-level', reflect: true }) + public visualLevel?: SbbTitleLevel; + + /** + * Sometimes we need a title in the markup to present a proper hierarchy + * to the screen readers while we do not want to let that title appear + * visually. In this case we set visuallyHidden to true. + */ + @property({ attribute: 'visually-hidden', reflect: true, type: Boolean }) + public visuallyHidden?: boolean; + + protected override willUpdate(changedProperties: PropertyValues): void { + super.willUpdate(changedProperties); + + if (changedProperties.has('level')) { + this.setAttribute('aria-level', this.level); + } + } + + protected override render(): TemplateResult { + const TAGNAME = `h${this.level}`; + + /* eslint-disable lit/binding-positions */ + return html` + <${unsafeStatic(TAGNAME)} class="sbb-title" role="presentation"> + + + `; + /* eslint-enable lit/binding-positions */ + } +} diff --git a/src/components/title/title-common.scss b/src/components/title/title-common.scss new file mode 100644 index 0000000000..f8a5f6e818 --- /dev/null +++ b/src/components/title/title-common.scss @@ -0,0 +1,53 @@ +@use '../core/styles' as sbb; + +// Box-sizing rules contained in typography are not traversing Shadow DOM boundaries. We need to include box-sizing mixin in every component. +@include sbb.box-sizing; + +:host { + --sbb-title-text-color-normal: var( + --sbb-title-text-color-normal-override, + var(--sbb-color-charcoal) + ); + + display: block; +} + +:host([negative]) { + @include sbb.title--negative; +} + +:host([id]) { + @include sbb.scroll-margin-block-start; +} + +.sbb-title { + color: var(--sbb-title-text-color-normal); + + :host([visually-hidden]) & { + @include sbb.screen-reader-only; + } + + :host(:is([level='1']:not([visual-level]), [visual-level='1'])) & { + @include sbb.title-1($exclude-spacing: true); + } + + :host(:is([level='2']:not([visual-level]), [visual-level='2'])) & { + @include sbb.title-2($exclude-spacing: true); + } + + :host(:is([level='3']:not([visual-level]), [visual-level='3'])) & { + @include sbb.title-3($exclude-spacing: true); + } + + :host(:is([level='4']:not([visual-level]), [visual-level='4'])) & { + @include sbb.title-4($exclude-spacing: true); + } + + :host(:is([level='5']:not([visual-level]), [visual-level='5'])) & { + @include sbb.title-5($exclude-spacing: true); + } + + :host(:is([level='6']:not([visual-level]), [visual-level='6'])) & { + @include sbb.title-6($exclude-spacing: true); + } +} diff --git a/src/components/title/title.scss b/src/components/title/title.scss index 15a341ae80..020abf0044 100644 --- a/src/components/title/title.scss +++ b/src/components/title/title.scss @@ -1,17 +1,9 @@ @use '../core/styles' as sbb; -// Box-sizing rules contained in typography are not traversing Shadow DOM boundaries. We need to include box-sizing mixin in every component. -@include sbb.box-sizing; - :host { - --sbb-title-text-color-normal: var( - --sbb-title-text-color-normal-override, - var(--sbb-color-charcoal) - ); --sbb-title-margin-block-start: 0; --sbb-title-margin-block-end: 0; - display: block; margin-block: var(--sbb-title-margin-block-start) var(--sbb-title-margin-block-end); } @@ -45,43 +37,3 @@ :host(:where([level='6']:not([visual-level]), [visual-level='6']):where(:not([visually-hidden]))) { --sbb-title-margin-block-end: var(--sbb-spacing-fixed-1x); } - -:host([negative]) { - @include sbb.title--negative; -} - -:host([id]) { - @include sbb.scroll-margin-block-start; -} - -.sbb-title { - color: var(--sbb-title-text-color-normal); - - :host([visually-hidden]) & { - @include sbb.screen-reader-only; - } - - :host(:is([level='1']:not([visual-level]), [visual-level='1'])) & { - @include sbb.title-1($exclude-spacing: true); - } - - :host(:is([level='2']:not([visual-level]), [visual-level='2'])) & { - @include sbb.title-2($exclude-spacing: true); - } - - :host(:is([level='3']:not([visual-level]), [visual-level='3'])) & { - @include sbb.title-3($exclude-spacing: true); - } - - :host(:is([level='4']:not([visual-level]), [visual-level='4'])) & { - @include sbb.title-4($exclude-spacing: true); - } - - :host(:is([level='5']:not([visual-level]), [visual-level='5'])) & { - @include sbb.title-5($exclude-spacing: true); - } - - :host(:is([level='6']:not([visual-level]), [visual-level='6'])) & { - @include sbb.title-6($exclude-spacing: true); - } -} diff --git a/src/components/title/title.ts b/src/components/title/title.ts index 0d5801fe79..15d638428e 100644 --- a/src/components/title/title.ts +++ b/src/components/title/title.ts @@ -1,63 +1,16 @@ -import type { CSSResultGroup, PropertyValues, TemplateResult } from 'lit'; -import { LitElement } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; -import { html, unsafeStatic } from 'lit/static-html.js'; - -import { hostAttributes } from '../core/decorators.js'; -import { SbbNegativeMixin } from '../core/mixins.js'; +import type { CSSResultGroup } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import { SbbTitleBase } from './title-base.js'; import style from './title.scss?lit&inline'; -export type SbbTitleLevel = '1' | '2' | '3' | '4' | '5' | '6'; - /** - * It displays a title wrapped into a heading tag. - * - * @slot - Use the unnamed slot to display the title. * @cssprop [--sbb-title-margin-block-start=var(--sbb-spacing-responsive-m)] - Margin block start of the title. * @cssprop [--sbb-title-margin-block-end=var(--sbb-spacing-responsive-s)] - Margin block end of the title. */ @customElement('sbb-title') -@hostAttributes({ - role: 'heading', -}) -export class SbbTitleElement extends SbbNegativeMixin(LitElement) { - public static override styles: CSSResultGroup = style; - - /** Title level */ - @property({ reflect: true }) public level: SbbTitleLevel = '1'; - - /** Visual level for the title. Optional, if not set, the value of level will be used. */ - @property({ attribute: 'visual-level', reflect: true }) - public visualLevel?: SbbTitleLevel; - - /** - * Sometimes we need a title in the markup to present a proper hierarchy - * to the screen readers while we do not want to let that title appear - * visually. In this case we set visuallyHidden to true - */ - @property({ attribute: 'visually-hidden', reflect: true, type: Boolean }) - public visuallyHidden?: boolean; - - protected override willUpdate(changedProperties: PropertyValues): void { - super.willUpdate(changedProperties); - - if (changedProperties.has('level')) { - this.setAttribute('aria-level', this.level); - } - } - - protected override render(): TemplateResult { - const TAGNAME = `h${this.level}`; - - /* eslint-disable lit/binding-positions */ - return html` - <${unsafeStatic(TAGNAME)} class="sbb-title" role="presentation"> - - - `; - /* eslint-enable lit/binding-positions */ - } +export class SbbTitleElement extends SbbTitleBase { + public static override styles: CSSResultGroup = [SbbTitleBase.styles, style]; } declare global {