diff --git a/core/api.txt b/core/api.txt index 439a457556..f7e7e3c595 100644 --- a/core/api.txt +++ b/core/api.txt @@ -2213,6 +2213,7 @@ ion-tab-button,prop,layout,"icon-bottom" | "icon-end" | "icon-hide" | "icon-star ion-tab-button,prop,mode,"ios" | "md",undefined,false,false ion-tab-button,prop,rel,string | undefined,undefined,false,false ion-tab-button,prop,selected,boolean,false,false,false +ion-tab-button,prop,shape,"rectangular" | "round" | "soft" | undefined,undefined,false,false ion-tab-button,prop,tab,string | undefined,undefined,false,false ion-tab-button,prop,target,string | undefined,undefined,false,false ion-tab-button,prop,theme,"ios" | "md" | "ionic",undefined,false,false diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 5b4a6b1e9c..1d0d42c8e5 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -3504,6 +3504,10 @@ export namespace Components { * The selected tab component */ "selected": boolean; + /** + * Set to `"soft"` for a tab-button with slightly rounded corners, `"round"` for a tab-button with fully rounded corners, or `"rectangular"` for a tab-button without rounded corners. Defaults to `"round"` for the `ionic` theme, undefined for all other themes. + */ + "shape"?: 'soft' | 'round' | 'rectangular'; /** * A tab id must be provided for each `ion-tab`. It's used internally to reference the selected tab or by the router to switch between them. */ @@ -8941,6 +8945,10 @@ declare namespace LocalJSX { * The selected tab component */ "selected"?: boolean; + /** + * Set to `"soft"` for a tab-button with slightly rounded corners, `"round"` for a tab-button with fully rounded corners, or `"rectangular"` for a tab-button without rounded corners. Defaults to `"round"` for the `ionic` theme, undefined for all other themes. + */ + "shape"?: 'soft' | 'round' | 'rectangular'; /** * A tab id must be provided for each `ion-tab`. It's used internally to reference the selected tab or by the router to switch between them. */ diff --git a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Chrome-linux.png index 36cff63981..6a2f7179a4 100644 Binary files a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Chrome-linux.png and b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Firefox-linux.png index 3b522db74e..5cbfee193a 100644 Binary files a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Firefox-linux.png and b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Safari-linux.png index bce88a0be1..c809507817 100644 Binary files a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Safari-linux.png and b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-ltr-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Chrome-linux.png b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Chrome-linux.png index 54aff9fc64..9c0a8c4302 100644 Binary files a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Chrome-linux.png and b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Firefox-linux.png b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Firefox-linux.png index 3e4a2a582f..46cb7e73e6 100644 Binary files a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Firefox-linux.png and b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Safari-linux.png b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Safari-linux.png index 2555a9e3b7..8a175cb91b 100644 Binary files a/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Safari-linux.png and b/core/src/components/tab-bar/test/basic/tab-bar.e2e.ts-snapshots/tab-bar-default-ionic-md-rtl-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/tab-button/tab-button.ionic.scss b/core/src/components/tab-button/tab-button.ionic.scss index 463385df2a..8f2f3ca748 100644 --- a/core/src/components/tab-button/tab-button.ionic.scss +++ b/core/src/components/tab-button/tab-button.ionic.scss @@ -8,8 +8,6 @@ --focus-ring-color: #{globals.$ion-border-focus-default}; --focus-ring-width: #{globals.$ion-border-radius-025}; - @include globals.border-radius(globals.$ion-border-radius-200); - align-content: center; min-height: globals.$ion-scale-1200; @@ -73,3 +71,18 @@ width: globals.$ion-scale-600; height: globals.$ion-scale-600; } + +// Tab Button Shapes +// ------------------------------------------------------------------------------- + +:host(.tab-button-shape-soft) { + @include globals.border-radius(globals.$ion-border-radius-200); +} + +:host(.tab-button-shape-round) { + @include globals.border-radius(globals.$ion-border-radius-400); +} + +:host(.tab-button-shape-rectangular) { + @include globals.border-radius(globals.$ion-border-radius-0); +} diff --git a/core/src/components/tab-button/tab-button.tsx b/core/src/components/tab-button/tab-button.tsx index ab973b9f07..e03b8a69e3 100644 --- a/core/src/components/tab-button/tab-button.tsx +++ b/core/src/components/tab-button/tab-button.tsx @@ -68,6 +68,15 @@ export class TabButton implements ComponentInterface, AnchorInterface { */ @Prop({ mutable: true }) selected = false; + /** + * Set to `"soft"` for a tab-button with slightly rounded corners, + * `"round"` for a tab-button with fully rounded corners, or `"rectangular"` + * for a tab-button without rounded corners. + * + * Defaults to `"round"` for the `ionic` theme, undefined for all other themes. + */ + @Prop() shape?: 'soft' | 'round' | 'rectangular'; + /** * A tab id must be provided for each `ion-tab`. It's used internally to reference * the selected tab or by the router to switch between them. @@ -107,6 +116,22 @@ export class TabButton implements ComponentInterface, AnchorInterface { } } + private getShape(): string | undefined { + const theme = getIonTheme(this); + const { shape } = this; + + // TODO(ROU-11436): Remove theme check when shapes are defined for all themes. + if (theme !== 'ionic') { + return undefined; + } + + if (shape === undefined) { + return 'round'; + } + + return shape; + } + private selectTab(ev: Event | KeyboardEvent) { if (this.tab !== undefined) { if (!this.disabled) { @@ -141,6 +166,7 @@ export class TabButton implements ComponentInterface, AnchorInterface { render() { const { disabled, hasIcon, hasLabel, href, rel, target, layout, selected, tab, inheritedAttributes } = this; const theme = getIonTheme(this); + const shape = this.getShape(); const attrs = { download: this.download, href, @@ -164,6 +190,7 @@ export class TabButton implements ComponentInterface, AnchorInterface { [`tab-layout-${layout}`]: true, 'ion-activatable': true, 'ion-selectable': true, + [`tab-button-shape-${shape}`]: shape !== undefined, 'ion-focusable': true, }} > diff --git a/core/src/components/tab-button/test/shape/index.html b/core/src/components/tab-button/test/shape/index.html new file mode 100644 index 0000000000..614da48e9e --- /dev/null +++ b/core/src/components/tab-button/test/shape/index.html @@ -0,0 +1,55 @@ + + + + + Tab Button - Shape + + + + + + + + + + + + + Tab Button - Shape + + + + + (Only available for ionic theme) + + + + Default Shape + + + + + Soft Shape + + + + + Round Shape + + + + + Rectangular Shape + + + + + + + + + diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts b/core/src/components/tab-button/test/shape/tab-button.e2e.ts new file mode 100644 index 0000000000..a9d31f1c38 --- /dev/null +++ b/core/src/components/tab-button/test/shape/tab-button.e2e.ts @@ -0,0 +1,51 @@ +import { expect } from '@playwright/test'; +import { configs, test } from '@utils/test/playwright'; +import type { E2EPage, E2EPageOptions, ScreenshotFn } from '@utils/test/playwright'; + +class TabButtonFixture { + readonly page: E2EPage; + + constructor(page: E2EPage) { + this.page = page; + } + + async goto(config: E2EPageOptions) { + const { page } = this; + await page.goto(`/src/components/tab-button/test/shape`, config); + } + + async screenshot(screenshotModifier: string, screenshot: ScreenshotFn, buttonId: string) { + const { page } = this; + + const screenshotString = screenshot(`tab-button-${screenshotModifier}`); + const tabButton = page.locator(buttonId); + + await expect(tabButton).toHaveScreenshot(screenshotString); + } +} + +/** + * This behavior does not vary across directions. + */ +configs({ modes: ['ionic-md'], directions: ['ltr'] }).forEach(({ config, screenshot, title }) => { + test.describe(title('tab-button: shape'), () => { + let tabButtonFixture: TabButtonFixture; + + test.beforeEach(async ({ page }) => { + tabButtonFixture = new TabButtonFixture(page); + await tabButtonFixture.goto(config); + }); + + test('should render a soft tab button', async () => { + await tabButtonFixture.screenshot('shape-soft', screenshot, '#soft-tab-button'); + }); + + test('should render a round tab button', async () => { + await tabButtonFixture.screenshot('shape-round', screenshot, '#round-tab-button'); + }); + + test('should render a rectangular tab button', async () => { + await tabButtonFixture.screenshot('shape-rectangular', screenshot, '#rect-tab-button'); + }); + }); +}); diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..e03e4ac09f Binary files /dev/null and b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-rectangular-ionic-md-ltr-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..ce90c00a6e Binary files /dev/null and b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-rectangular-ionic-md-ltr-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png new file mode 100644 index 0000000000..057d33d5d3 Binary files /dev/null and b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-rectangular-ionic-md-ltr-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..98b1834085 Binary files /dev/null and b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-round-ionic-md-ltr-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..a6a33dfdb4 Binary files /dev/null and b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-round-ionic-md-ltr-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png new file mode 100644 index 0000000000..534169aab5 Binary files /dev/null and b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-round-ionic-md-ltr-light-Mobile-Safari-linux.png differ diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png new file mode 100644 index 0000000000..6e5086a417 Binary files /dev/null and b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-soft-ionic-md-ltr-light-Mobile-Chrome-linux.png differ diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png new file mode 100644 index 0000000000..922219804f Binary files /dev/null and b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-soft-ionic-md-ltr-light-Mobile-Firefox-linux.png differ diff --git a/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png new file mode 100644 index 0000000000..1c2e74d329 Binary files /dev/null and b/core/src/components/tab-button/test/shape/tab-button.e2e.ts-snapshots/tab-button-shape-soft-ionic-md-ltr-light-Mobile-Safari-linux.png differ diff --git a/packages/angular/src/directives/proxies.ts b/packages/angular/src/directives/proxies.ts index 8d3dac8cb1..ea1b4e31c2 100644 --- a/packages/angular/src/directives/proxies.ts +++ b/packages/angular/src/directives/proxies.ts @@ -2276,14 +2276,14 @@ export declare interface IonTabBar extends Components.IonTabBar {} @ProxyCmp({ - inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'tab', 'target', 'theme'] + inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'shape', 'tab', 'target', 'theme'] }) @Component({ selector: 'ion-tab-button', changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'tab', 'target', 'theme'], + inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'shape', 'tab', 'target', 'theme'], }) export class IonTabButton { protected el: HTMLElement; diff --git a/packages/angular/standalone/src/directives/proxies.ts b/packages/angular/standalone/src/directives/proxies.ts index df589497e9..8d828c3c64 100644 --- a/packages/angular/standalone/src/directives/proxies.ts +++ b/packages/angular/standalone/src/directives/proxies.ts @@ -2081,14 +2081,14 @@ export declare interface IonTabBar extends Components.IonTabBar {} @ProxyCmp({ defineCustomElementFn: defineIonTabButton, - inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'tab', 'target', 'theme'] + inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'shape', 'tab', 'target', 'theme'] }) @Component({ selector: 'ion-tab-button', changeDetection: ChangeDetectionStrategy.OnPush, template: '', // eslint-disable-next-line @angular-eslint/no-inputs-metadata-property - inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'tab', 'target', 'theme'], + inputs: ['disabled', 'download', 'href', 'layout', 'mode', 'rel', 'selected', 'shape', 'tab', 'target', 'theme'], standalone: true }) export class IonTabButton {