Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2177,8 +2177,10 @@ ion-tab,method,setActive,setActive() => Promise<void>

ion-tab-bar,shadow
ion-tab-bar,prop,color,"danger" | "dark" | "light" | "medium" | "primary" | "secondary" | "success" | "tertiary" | "warning" | string & Record<never, never> | undefined,undefined,false,true
ion-tab-bar,prop,expand,"compact" | "full",'full',false,false
ion-tab-bar,prop,mode,"ios" | "md",undefined,false,false
ion-tab-bar,prop,selectedTab,string | undefined,undefined,false,false
ion-tab-bar,prop,shape,"rectangular" | "round" | "soft" | undefined,undefined,false,false
ion-tab-bar,prop,theme,"ios" | "md" | "ionic",undefined,false,false
ion-tab-bar,prop,translucent,boolean,false,false,false
ion-tab-bar,css-prop,--background,ionic
Expand Down
16 changes: 16 additions & 0 deletions core/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3411,6 +3411,10 @@ export namespace Components {
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* Set to `"compact"` to display a width based on the items inside the tab bar. This value will only work for the `ionic` theme. Set to `"full"` to display a full width tab bar. Defaults to `"full"`.
*/
"expand": 'compact' | 'full';
/**
* The mode determines the platform behaviors of the component.
*/
Expand All @@ -3419,6 +3423,10 @@ export namespace Components {
* The selected tab component
*/
"selectedTab"?: string;
/**
* Set to `"soft"` for a tab bar with slightly rounded corners, `"round"` for a tab bar with fully rounded corners, or `"rectangular"` for a tab bar without rounded corners. Defaults to `"round"` for the `"ionic"` theme, undefined for all other themes.
*/
"shape"?: 'soft' | 'round' | 'rectangular';
/**
* The theme determines the visual appearance of the component.
*/
Expand Down Expand Up @@ -8765,6 +8773,10 @@ declare namespace LocalJSX {
* The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics).
*/
"color"?: Color;
/**
* Set to `"compact"` to display a width based on the items inside the tab bar. This value will only work for the `ionic` theme. Set to `"full"` to display a full width tab bar. Defaults to `"full"`.
*/
"expand"?: 'compact' | 'full';
/**
* The mode determines the platform behaviors of the component.
*/
Expand All @@ -8775,6 +8787,10 @@ declare namespace LocalJSX {
* The selected tab component
*/
"selectedTab"?: string;
/**
* Set to `"soft"` for a tab bar with slightly rounded corners, `"round"` for a tab bar with fully rounded corners, or `"rectangular"` for a tab bar without rounded corners. Defaults to `"round"` for the `"ionic"` theme, undefined for all other themes.
*/
"shape"?: 'soft' | 'round' | 'rectangular';
/**
* The theme determines the visual appearance of the component.
*/
Expand Down
34 changes: 22 additions & 12 deletions core/src/components/tab-bar/tab-bar.common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,13 @@
align-items: center;
justify-content: center;

width: auto;

/* stylelint-disable */
padding-right: var(--ion-safe-area-right);
padding-bottom: var(--ion-safe-area-bottom, 0);
padding-left: var(--ion-safe-area-left);
/* stylelint-enable */

border-top: var(--border);

background: var(--background);
color: var(--color);

text-align: center;

contain: strict;
user-select: none;

/* stylelint-disable-next-line declaration-no-important */
Expand All @@ -41,9 +32,6 @@
}

:host([slot="top"]) {
padding-top: var(--ion-safe-area-top, 0);
padding-bottom: 0;

border-top: 0;
border-bottom: var(--border);
}
Expand All @@ -52,3 +40,25 @@
/* stylelint-disable-next-line declaration-no-important */
display: none !important;
}

// Tab Bar Expand
// --------------------------------------------------

/* Full */
:host(.tab-bar-full) {
width: auto;

contain: strict;

/* stylelint-disable */
padding-bottom: var(--ion-safe-area-bottom, 0);

padding-right: var(--ion-safe-area-right);
padding-left: var(--ion-safe-area-left);
/* stylelint-enable */
}

:host([slot="top"].tab-bar-full) {
padding-top: var(--ion-safe-area-top, 0);
padding-bottom: 0;
}
62 changes: 57 additions & 5 deletions core/src/components/tab-bar/tab-bar.ionic.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,68 @@
*/
min-height: calc(globals.$ionic-scale-1400 - calc(globals.$ionic-space-100 * 2));

padding-top: calc(globals.$ionic-space-100 + var(--ion-safe-area-top, 0));
padding-bottom: calc(globals.$ionic-space-100 + var(--ion-safe-area-bottom, 0));
gap: globals.$ionic-space-300;

// TODO(ROU-10853): replace this value with a layer token
z-index: 10;
}

// Tab Bar Expand
// --------------------------------------------------

/* Full */
:host(.tab-bar-full) {
/* stylelint-disable */
padding-top: globals.$ionic-space-100;
padding-bottom: calc(globals.$ionic-space-100 + var(--ion-safe-area-bottom, 0));

padding-right: calc(globals.$ionic-space-400 + var(--ion-safe-area-right, 0));
padding-left: calc(globals.$ionic-space-400 + var(--ion-safe-area-left, 0));
/* stylelint-enable */
}

gap: globals.$ionic-space-300;
:host([slot="top"].tab-bar-full) {
padding-top: calc(globals.$ionic-space-100 + var(--ion-safe-area-top, 0));
padding-bottom: globals.$ionic-space-100;
}

// TODO(ROU-10853): replace this value with a layer token
z-index: 10;
/* Compact */
:host(.tab-bar-compact) {
@include globals.padding(globals.$ionic-space-100, globals.$ionic-space-400);

position: absolute;

align-self: center;

width: fit-content;

box-shadow: #{globals.$ionic-elevation-200};

contain: content;
}

:host([slot="top"].tab-bar-compact) {
top: calc(globals.$ionic-space-100 + var(--ion-safe-area-top, 0));
}

:host([slot="bottom"].tab-bar-compact) {
bottom: calc(globals.$ionic-space-100 + var(--ion-safe-area-bottom, 0));
}

// Tab Bar Shapes
// --------------------------------------------------

/* Soft */
:host(.tab-bar-soft) {
@include globals.border-radius(globals.$ionic-border-radius-400);
}

/* Round */
:host(.tab-bar-round) {
@include globals.border-radius(globals.$ionic-border-radius-full);
}

/* Rectangular */
:host(.tab-bar-rectangular) {
@include globals.border-radius(globals.$ionic-border-radius-0);
}
41 changes: 40 additions & 1 deletion core/src/components/tab-bar/tab-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,26 @@ export class TabBar implements ComponentInterface {
*/
@Prop() translucent = false;

/**
* Set to `"compact"` to display a width based on the items
* inside the tab bar. This value will only work for the
* `ionic` theme.
*
* Set to `"full"` to display a full width tab bar.
*
* Defaults to `"full"`.
*/
@Prop() expand: 'compact' | 'full' = 'full';

/**
* Set to `"soft"` for a tab bar with slightly rounded corners,
* `"round"` for a tab bar with fully rounded corners, or
* `"rectangular"` for a tab bar without rounded corners.
*
* Defaults to `"round"` for the `"ionic"` theme, undefined for all other themes.
*/
@Prop() shape?: 'soft' | 'round' | 'rectangular';

/** @internal */
@Event() ionTabBarChanged!: EventEmitter<TabBarChangedEventDetail>;

Expand Down Expand Up @@ -96,9 +116,26 @@ export class TabBar implements ComponentInterface {
this.ionTabBarLoaded.emit();
}

private getShape(): string | undefined {
const theme = getIonTheme(this);
const { shape } = this;

// TODO(ROU-11234): Remove theme check when shapes are defined for all themes.
if (theme !== 'ionic') {
return undefined;
}

if (shape === undefined) {
return 'round';
}

return shape;
}

render() {
const { color, translucent, keyboardVisible } = this;
const { color, translucent, keyboardVisible, expand } = this;
const theme = getIonTheme(this);
const shape = this.getShape();
const shouldHide = keyboardVisible && this.el.getAttribute('slot') !== 'top';

return (
Expand All @@ -109,6 +146,8 @@ export class TabBar implements ComponentInterface {
[theme]: true,
'tab-bar-translucent': translucent,
'tab-bar-hidden': shouldHide,
[`tab-bar-${expand}`]: true,
[`tab-bar-${shape}`]: shape !== undefined,
})}
>
<slot></slot>
Expand Down
6 changes: 6 additions & 0 deletions core/src/components/tab-bar/test/basic/tab-bar.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ configs({ modes: ['ionic-md', 'md', 'ios'] }).forEach(({ title, screenshot, conf
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<style>
:root {
background: #ccc7c7;
}
</style>

<ion-tab-bar selected-tab="2">
<ion-tab-button tab="1">
<ion-icon name="home-outline"></ion-icon>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
82 changes: 82 additions & 0 deletions core/src/components/tab-bar/test/expand/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Tab Bar - Expand</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
/>
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
<link rel="stylesheet" href="../../../../../css/ionic.bundle.css" />
<link rel="stylesheet" href="../../../../../scripts/testing/styles.css" />
</head>

<body>
<ion-app>
<ion-content>
<h2>Default</h2>
<ion-tab-bar>
<ion-tab-button tab="1">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>

<ion-tab-button tab="2">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>

<ion-tab-button tab="3">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>
</ion-tab-bar>

<h2>Full</h2>
<ion-tab-bar expand="full">
<ion-tab-button tab="1">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>

<ion-tab-button tab="2">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>

<ion-tab-button tab="3">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>
</ion-tab-bar>

<h2>Compact</h2>
<ion-tab-bar expand="compact">
<ion-tab-button tab="1">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>

<ion-tab-button tab="2">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>

<ion-tab-button tab="3">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>
</ion-tab-bar>
</ion-content>
</ion-app>

<style>
ion-content {
--background: #f6f6f6;
}
</style>
</body>
</html>
45 changes: 45 additions & 0 deletions core/src/components/tab-bar/test/expand/tab-bar.e2e.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';

/**
* This behavior only applies to the `ionic` theme.
*/
configs({ directions: ['ltr'], modes: ['ionic-md'] }).forEach(({ title, screenshot, config }) => {
test.describe(title('tab-bar: expand'), () => {
test.describe(title('compact'), () => {
test('should not have visual regressions', async ({ page }) => {
await page.setContent(
`
<style>
:root {
background: #ccc7c7;
}
</style>

<ion-tab-bar expand="compact">
<ion-tab-button tab="1">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>

<ion-tab-button tab="2">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>

<ion-tab-button tab="3">
<ion-icon name="triangle-outline"></ion-icon>
<ion-label>Label</ion-label>
</ion-tab-button>
</ion-tab-bar>
`,
config
);

const tabBar = page.locator('ion-tab-bar');

await expect(tabBar).toHaveScreenshot(screenshot(`tab-bar-expand-compact`));
});
});
});
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading