diff --git a/core/src/components.d.ts b/core/src/components.d.ts index 6e7bd07ff1..206f06fa9e 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -6359,6 +6359,7 @@ declare namespace LocalJSX { * The mode determines which platform styles to use. */ "mode"?: "ios" | "md"; + "onIonStyle"?: (event: CustomEvent) => void; "onIonTabBarChanged"?: (event: CustomEvent) => void; /** * The selected tab component diff --git a/core/src/components/fab/fab.scss b/core/src/components/fab/fab.scss index 950be05655..e71e9b9302 100644 --- a/core/src/components/fab/fab.scss +++ b/core/src/components/fab/fab.scss @@ -44,7 +44,7 @@ :host(.fab-vertical-bottom) { - bottom: $fab-content-margin; + bottom: var(--tab-translucent-safe-area, $fab-content-margin); } :host(.fab-vertical-bottom.fab-edge) { diff --git a/core/src/components/footer/footer.scss b/core/src/components/footer/footer.scss index 9682747b41..9fea2c1291 100644 --- a/core/src/components/footer/footer.scss +++ b/core/src/components/footer/footer.scss @@ -15,5 +15,5 @@ ion-footer { } ion-footer ion-toolbar:last-of-type { - padding-bottom: var(--ion-safe-area-bottom, 0); -} \ No newline at end of file + padding-bottom: calc(var(--ion-safe-area-bottom, 0) + var(--tab-translucent-safe-area, 0)); +} diff --git a/core/src/components/tab-bar/tab-bar.tsx b/core/src/components/tab-bar/tab-bar.tsx index d445552397..7bae035293 100644 --- a/core/src/components/tab-bar/tab-bar.tsx +++ b/core/src/components/tab-bar/tab-bar.tsx @@ -1,7 +1,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Host, Prop, State, Watch, h } from '@stencil/core'; import { getIonMode } from '../../global/ionic-global'; -import { Color, TabBarChangedEventDetail } from '../../interface'; +import { Color, StyleEventDetail, TabBarChangedEventDetail } from '../../interface'; import { createColorClasses } from '../../utils/theme'; /** @@ -30,6 +30,8 @@ export class TabBar implements ComponentInterface { */ @Prop({ reflect: true }) color?: Color; + @Event() ionStyle!: EventEmitter; + /** * The selected tab component */ @@ -50,11 +52,28 @@ export class TabBar implements ComponentInterface { */ @Prop() translucent = false; + @Watch('translucent') + translucentChanged() { + // Find all tabs + const tabs = Array.from(this.el.closest('ion-tabs')?.querySelectorAll('ion-tab') ?? []); + for (const tab of tabs) { + if (this.translucent) { + tab.classList.add('tab-bar-translucent'); + } else { + tab.classList.remove('tab-bar-translucent'); + } + } + this.ionStyle.emit({ + 'tab-bar-translucent': this.translucent + }) + } + /** @internal */ @Event() ionTabBarChanged!: EventEmitter; componentWillLoad() { this.selectedTabChanged(); + this.translucentChanged(); } connectedCallback() { diff --git a/core/src/components/tab/tab.scss b/core/src/components/tab/tab.scss index cb5be6d823..a6f49e3c24 100644 --- a/core/src/components/tab/tab.scss +++ b/core/src/components/tab/tab.scss @@ -2,3 +2,9 @@ /* stylelint-disable-next-line declaration-no-important */ display: none !important; } + + +:host(.tab-bar-translucent) ::slotted(ion-content) { + /* stylelint-disable-next-line declaration-no-important */ + --padding-bottom: 50px !important; +} diff --git a/core/src/components/tabs/tabs.ios.scss b/core/src/components/tabs/tabs.ios.scss new file mode 100644 index 0000000000..0708e06924 --- /dev/null +++ b/core/src/components/tabs/tabs.ios.scss @@ -0,0 +1,11 @@ +@import './tabs'; + +:host(.tab-bar-translucent) { + --tab-translucent-safe-area: 60px; +} + +slot[name='bottom']::slotted([translucent]) { + position: absolute; + bottom: 0; + width: 100%; +} diff --git a/core/src/components/tabs/tabs.md.scss b/core/src/components/tabs/tabs.md.scss new file mode 100644 index 0000000000..4314c33a5f --- /dev/null +++ b/core/src/components/tabs/tabs.md.scss @@ -0,0 +1 @@ +@import './tabs'; diff --git a/core/src/components/tabs/tabs.tsx b/core/src/components/tabs/tabs.tsx index fce60622fa..fdadcd044d 100644 --- a/core/src/components/tabs/tabs.tsx +++ b/core/src/components/tabs/tabs.tsx @@ -9,7 +9,10 @@ import { NavOutlet, RouteID, RouteWrite, TabButtonClickEventDetail } from '../.. */ @Component({ tag: 'ion-tabs', - styleUrl: 'tabs.scss', + styleUrls: { + ios: 'tabs.ios.scss', + md: 'tabs.md.scss' + }, shadow: true }) export class Tabs implements NavOutlet { @@ -21,6 +24,8 @@ export class Tabs implements NavOutlet { @State() selectedTab?: HTMLIonTabElement; + @State() private tabCustomClasses: { [key: string]: boolean } = {}; + /** @internal */ @Prop({ mutable: true }) useRouter = false; @@ -182,10 +187,21 @@ export class Tabs implements NavOutlet { } } + private onIonStyle = (ev: any) => { + if (ev.target.tagName === 'ION-TAB-BAR') { + for (const key of Object.keys(ev.detail)) { + this.tabCustomClasses[key] = ev.detail[key]; + } + this.tabCustomClasses = {...this.tabCustomClasses}; + } + } + render() { return (
diff --git a/core/src/components/tabs/test/translucent/index.html b/core/src/components/tabs/test/translucent/index.html new file mode 100644 index 0000000000..2a3cb851ac --- /dev/null +++ b/core/src/components/tabs/test/translucent/index.html @@ -0,0 +1,204 @@ + + + + + + Tab - Translucent + + + + + + + + + + + + + + + + + + Tab One + + + +

Tab One

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
This is the end of the content
+ + + + + + +
+
+ + + + + Tab Two + + + +

Tab Two

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + Tab Two Footer + + +
+ + + + + Tab Three + + + +

Tab Three

+
+
+ + + + + + Tab Three + + + +

Tab Three

+
+
+ + + + Tab One + + + + + Tab Two + + 6 + + + + Tab Three + + 6 + + + + Tab Four + + + + +
+
+ + + + +