diff --git a/core/api.txt b/core/api.txt index 03f02fade7e..e4e1ca4d603 100644 --- a/core/api.txt +++ b/core/api.txt @@ -2754,6 +2754,7 @@ ion-toolbar,shadow ion-toolbar,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record | undefined,undefined,false,true ion-toolbar,prop,mode,"ios" | "md",undefined,false,false ion-toolbar,prop,theme,"ios" | "md" | "ionic",undefined,false,false +ion-toolbar,prop,titlePlacement,"center" | "end" | "start" | undefined,undefined,false,false ion-toolbar,css-prop,--background,ionic ion-toolbar,css-prop,--background,ios ion-toolbar,css-prop,--background,md diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 9424f0e7fa0..abd6d545e55 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -4463,6 +4463,10 @@ export namespace Components { * The theme determines the visual appearance of the component. */ "theme"?: "ios" | "md" | "ionic"; + /** + * Where to place the title relative to the other toolbar content. `"start"`: The title will appear to the left of the toolbar content in LTR and to the right in RTL. `"center"`: The title will appear in the center of the toolbar. `"end"`: The title will appear to the right of the toolbar content in LTR and to the left in RTL. + */ + "titlePlacement"?: 'start' | 'center' | 'end'; } } export interface IonAccordionGroupCustomEvent extends CustomEvent { @@ -10590,6 +10594,10 @@ declare namespace LocalJSX { * The theme determines the visual appearance of the component. */ "theme"?: "ios" | "md" | "ionic"; + /** + * Where to place the title relative to the other toolbar content. `"start"`: The title will appear to the left of the toolbar content in LTR and to the right in RTL. `"center"`: The title will appear in the center of the toolbar. `"end"`: The title will appear to the right of the toolbar content in LTR and to the left in RTL. + */ + "titlePlacement"?: 'start' | 'center' | 'end'; } interface IonAccordionAttributes { @@ -11382,6 +11390,7 @@ declare namespace LocalJSX { } interface IonToolbarAttributes { "color": Color; + "titlePlacement": 'start' | 'center' | 'end'; } interface IntrinsicElements { diff --git a/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Chrome-linux.png index 5dbf0d9b4f0..f1ccaedf919 100644 Binary files a/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Firefox-linux.png index 718a7cbab13..c88404c74df 100644 Binary files a/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Safari-linux.png index 48f3b106d2f..4f5477d94e1 100644 Binary files a/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/title/test/basic/title.e2e.ts-snapshots/title-basic-ionic-md-ltr-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/index.html b/core/src/components/toolbar/test/title-placement/index.html new file mode 100644 index 00000000000..030b9412a05 --- /dev/null +++ b/core/src/components/toolbar/test/title-placement/index.html @@ -0,0 +1,133 @@ + + + + + Toolbar - Title Placement + + + + + + + + + + + + + Default Placement + + + + + + + + Default Placement + + + Default Placement + + + + + + + + + + Start Placement + + + + + + + + Start Placement + + + Start Placement + + + + + + + + + + Center Placement + + + + + + + + Center Placement + + + Center Placement + + + + + + + + + + End Placement + + + + + + + + End Placement + + + End Placement + + + + + + + + + + Start + Center + End + + + + + + + + diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts new file mode 100644 index 00000000000..3336337ec0f --- /dev/null +++ b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts @@ -0,0 +1,45 @@ +import { expect } from '@playwright/test'; +import { configs, test } from '@utils/test/playwright'; + +/** + * Title placement is only supported by the `ionic` theme. + */ +configs({ modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => { + test.describe(title('toolbar: title-placement'), () => { + ['start', 'center', 'end'].forEach((placement) => { + test(`should not have visual regressions with ${placement} placement`, async ({ page }) => { + const placementTitle = placement.charAt(0).toUpperCase() + placement.slice(1); + + await page.setContent( + ` + + + ${placementTitle} Placement + + + + + + + + ${placementTitle} Placement + + + ${placementTitle} Placement + + + + + + + + `, + config + ); + + const header = page.locator('ion-header'); + await expect(header).toHaveScreenshot(screenshot(`toolbar-title-placement-${placement}`)); + }); + }); + }); +}); diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-ltr-light-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..3bcb62bf5f9 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-ltr-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-ltr-light-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..3d33ed65110 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-ltr-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-ltr-light-Mobile-Safari-linux.png new file mode 100644 index 00000000000..2d0c0dcde5d Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-ltr-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-rtl-light-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..25b10cfe028 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-rtl-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-rtl-light-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..a19711ef0f6 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-rtl-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-rtl-light-Mobile-Safari-linux.png new file mode 100644 index 00000000000..1d44ef4a709 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-center-ionic-md-rtl-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..1ed3e844ff0 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-ltr-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..3c1cf30ec95 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-ltr-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png new file mode 100644 index 00000000000..c3a97b4e7bd Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-ltr-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..29adb227719 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-rtl-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..31bdeb8c5e3 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-rtl-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png new file mode 100644 index 00000000000..8e34feb9cf8 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-end-ionic-md-rtl-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..f32866f1f74 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-ltr-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..b11e6a61443 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-ltr-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png new file mode 100644 index 00000000000..f20de0e0d1b Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-ltr-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png new file mode 100644 index 00000000000..53314d48ddd Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-rtl-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png new file mode 100644 index 00000000000..80cdd5baadd Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-rtl-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png new file mode 100644 index 00000000000..c3028947b22 Binary files /dev/null and b/core/src/components/toolbar/test/title-placement/toolbar.e2e.ts-snapshots/toolbar-title-placement-start-ionic-md-rtl-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/toolbar/toolbar.ionic.scss b/core/src/components/toolbar/toolbar.ionic.scss index a2aae925f63..e030e55ae68 100644 --- a/core/src/components/toolbar/toolbar.ionic.scss +++ b/core/src/components/toolbar/toolbar.ionic.scss @@ -59,10 +59,6 @@ @include globals.padding-horizontal(globals.$ion-space-200); } -:host(.toolbar-title-default) ::slotted(ion-title) { - text-align: center; -} - :host(.toolbar-title-large) ::slotted(ion-title) { @include globals.padding-horizontal(globals.$ion-space-400); } @@ -116,3 +112,18 @@ flex: 0 0 var(--primary-secondary-size, 0); } + +// Toolbar Title Placement +// -------------------------------------------------- + +:host(.toolbar-title-placement-start) ::slotted(ion-title) { + text-align: start; +} + +:host(.toolbar-title-placement-center) ::slotted(ion-title) { + text-align: center; +} + +:host(.toolbar-title-placement-end) ::slotted(ion-title) { + text-align: end; +} diff --git a/core/src/components/toolbar/toolbar.tsx b/core/src/components/toolbar/toolbar.tsx index 34ab353f019..1328e77bd1a 100644 --- a/core/src/components/toolbar/toolbar.tsx +++ b/core/src/components/toolbar/toolbar.tsx @@ -1,5 +1,5 @@ import type { ComponentInterface } from '@stencil/core'; -import { Component, Element, forceUpdate, h, Host, Listen, Prop } from '@stencil/core'; +import { Component, Element, forceUpdate, h, Host, Listen, Prop, Watch } from '@stencil/core'; import { createColorClasses, hostContext } from '@utils/theme'; import { getIonTheme } from '../../global/ionic-global'; @@ -30,6 +30,14 @@ import type { Color, CssClassMap, StyleEventDetail } from '../../interface'; }) export class Toolbar implements ComponentInterface { private childrenStyles = new Map(); + private readonly slotClasses = [ + 'has-start-content', + 'has-end-content', + 'has-primary-content', + 'has-secondary-content', + ]; + private readonly showClasses = ['show-start', 'show-end', 'show-primary', 'show-secondary']; + private readonly slotSizeVars = ['--start-end-size', '--primary-secondary-size']; @Element() el!: HTMLIonToolbarElement; @@ -40,6 +48,14 @@ export class Toolbar implements ComponentInterface { */ @Prop({ reflect: true }) color?: Color; + /** + * Where to place the title relative to the other toolbar content. + * `"start"`: The title will appear to the left of the toolbar content in LTR and to the right in RTL. + * `"center"`: The title will appear in the center of the toolbar. + * `"end"`: The title will appear to the right of the toolbar content in LTR and to the left in RTL. + */ + @Prop() titlePlacement?: 'start' | 'center' | 'end'; + componentWillLoad() { const buttons = Array.from(this.el.querySelectorAll('ion-buttons')); @@ -67,6 +83,24 @@ export class Toolbar implements ComponentInterface { this.updateSlotWidths(); } + @Watch('titlePlacement') + titlePlacementChanged() { + this.updateSlotClasses(); + } + + /** + * Gets the title placement. + * Returns the title placement if it is set, otherwise returns `"center"` + * for `ionic` and `ios`, and `"start"` for `md`. + */ + private getTitlePlacement(): 'start' | 'center' | 'end' { + if (this.titlePlacement !== undefined) { + return this.titlePlacement; + } + + return getIonTheme(this) === 'ionic' || getIonTheme(this) === 'ios' ? 'center' : 'start'; + } + /** * Updates the CSS custom properties for slot widths * This ensures that slots shown by their met conditions @@ -164,7 +198,21 @@ export class Toolbar implements ComponentInterface { return allMeasurementsSuccessful; } + /** + * Removes all slot visibility classes and slot width CSS variables. + */ + private removeSlotClasses() { + this.el.classList.remove(...this.slotClasses, ...this.showClasses); + this.slotSizeVars.forEach((cssVar) => this.el.style.removeProperty(cssVar)); + } + private updateSlotClasses() { + const titlePlacement = this.getTitlePlacement(); + if (titlePlacement !== 'center') { + this.removeSlotClasses(); + return; + } + // Check if slots have content const slots = ['start', 'end', 'primary', 'secondary']; @@ -250,12 +298,15 @@ export class Toolbar implements ComponentInterface { Object.assign(childStyles, style); }); + const titlePlacement = this.getTitlePlacement(); + return ( ', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['color', 'mode', 'theme'], + inputs: ['color', 'mode', 'theme', 'titlePlacement'], }) export class IonToolbar { protected el: HTMLIonToolbarElement; diff --git a/packages/angular/standalone/src/directives/proxies.ts b/packages/angular/standalone/src/directives/proxies.ts index d87c6de83e4..41e27889758 100644 --- a/packages/angular/standalone/src/directives/proxies.ts +++ b/packages/angular/standalone/src/directives/proxies.ts @@ -2298,14 +2298,14 @@ Shorthand for ionToastDidDismiss. @ProxyCmp({ defineCustomElementFn: defineIonToolbar, - inputs: ['color', 'mode', 'theme'] + inputs: ['color', 'mode', 'theme', 'titlePlacement'] }) @Component({ selector: 'ion-toolbar', changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['color', 'mode', 'theme'], + inputs: ['color', 'mode', 'theme', 'titlePlacement'], standalone: true }) export class IonToolbar { diff --git a/packages/vue/src/proxies.ts b/packages/vue/src/proxies.ts index ead6e071923..bf7ab19881d 100644 --- a/packages/vue/src/proxies.ts +++ b/packages/vue/src/proxies.ts @@ -1122,6 +1122,7 @@ export const IonToggle: StencilVueComponent = /*@__PURE__*/ defineContainer('ion-toolbar', defineIonToolbar, [ - 'color' + 'color', + 'titlePlacement' ]);