diff --git a/src/components/app/structure.scss b/src/components/app/structure.scss index fa9e3583e45..0c81a2465ad 100644 --- a/src/components/app/structure.scss +++ b/src/components/app/structure.scss @@ -219,6 +219,7 @@ ion-content.js-scroll > scroll-content { [nav-viewport], [nav-portal], +[tab-portal], .nav-decor { display: none; } diff --git a/src/components/content/content.ts b/src/components/content/content.ts index edf40a43fc9..9619eff5492 100644 --- a/src/components/content/content.ts +++ b/src/components/content/content.ts @@ -524,7 +524,7 @@ export class Content extends Ion { ele = parentEle; let tabbarEle: HTMLElement; - while (ele && ele.tagName !== 'ION-MODAL') { + while (ele && ele.tagName !== 'ION-MODAL' && !ele.classList.contains('tab-subpage')) { if (ele.tagName === 'ION-TABS') { tabbarEle = ele.firstElementChild; diff --git a/src/components/tabs/tab.ts b/src/components/tabs/tab.ts index 3fa3abde939..2485b43d005 100644 --- a/src/components/tabs/tab.ts +++ b/src/components/tabs/tab.ts @@ -290,7 +290,20 @@ export class Tab extends NavControllerBase { * @private */ loadPage(viewCtrl: ViewController, viewport: ViewContainerRef, opts: NavOptions, done: Function) { + let isTabSubPage = (this.parent.subPages && viewCtrl.index > 0); + + if (isTabSubPage) { + viewport = this.parent.portal; + } + super.loadPage(viewCtrl, viewport, opts, () => { + if (isTabSubPage) { + // add the .tab-subpage css class to tabs pages that should act like subpages + let pageEleRef = viewCtrl.pageRef(); + if (pageEleRef) { + this._renderer.setElementClass(pageEleRef.nativeElement, 'tab-subpage', true); + } + } done(); }); } diff --git a/src/components/tabs/tabs.ts b/src/components/tabs/tabs.ts index dffb4b35420..38985572c41 100644 --- a/src/components/tabs/tabs.ts +++ b/src/components/tabs/tabs.ts @@ -150,6 +150,7 @@ import { ViewController } from '../nav/view-controller'; +
`, directives: [Badge, Icon, NgClass, NgFor, NgIf, TabButton, TabHighlight], encapsulation: ViewEncapsulation.None, @@ -173,6 +174,11 @@ export class Tabs extends Ion { */ selectHistory: string[] = []; + /** + * @private + */ + subPages: boolean; + /** * @input {number} The default selected tab index when first loaded. If a selected index isn't provided then it will use `0`, the first tab. */ @@ -218,6 +224,11 @@ export class Tabs extends Ion { */ @ViewChild('tabbar') private _tabbar: ElementRef; + /** + * @private + */ + @ViewChild('portal', {read: ViewContainerRef}) portal: ViewContainerRef; + /** * @private */ @@ -237,11 +248,13 @@ export class Tabs extends Ion { this.parent = parent; this.id = 't' + (++tabIds); this._sbPadding = _config.getBoolean('statusbarPadding'); + this.subPages = _config.getBoolean('tabsHideOnSubPages'); this._useHighlight = _config.getBoolean('tabsHighlight'); // TODO deprecated 07-07-2016 beta.11 if (_config.get('tabSubPages') !== null) { - console.warn('Config option "tabSubPages" has been deprecated. The Material Design spec now supports Bottom Navigation: https://material.google.com/components/bottom-navigation.html'); + console.warn('Config option "tabSubPages" has been deprecated. Please use "tabsHideOnSubPages" instead.'); + this.subPages = _config.getBoolean('tabSubPages'); } // TODO deprecated 07-07-2016 beta.11 diff --git a/src/components/tabs/test/advanced/index.ts b/src/components/tabs/test/advanced/index.ts index 5a8976b140b..38c6ee2df7e 100644 --- a/src/components/tabs/test/advanced/index.ts +++ b/src/components/tabs/test/advanced/index.ts @@ -323,8 +323,10 @@ class Tab3Page1 { @Component({ - template: '' + template: '' }) -class E2EApp {} +class E2EApp { + root = TabsPage; +} ionicBootstrap(E2EApp); diff --git a/src/config/config.ts b/src/config/config.ts index da90afc72e7..20907c5095d 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -103,6 +103,7 @@ import { isObject, isDefined, isFunction, isArray } from '../util/util'; * | `tabsHighlight` | `boolean` | Whether to show a highlight line under the tab when it is selected. | * | `tabsLayout` | `string` | The layout to use for all tabs. Available options: `"icon-top"`, `"icon-left"`, `"icon-right"`, `"icon-bottom"`, `"icon-hide"`, `"title-hide"`. | * | `tabsPlacement` | `string` | The position of the tabs relative to the content. Available options: `"top"`, `"bottom"` | + * | `tabsHideOnSubPages` | `boolean` | Whether to hide the tabs on child pages or not. If `true` it will not show the tabs on child pages. | * | `toastEnter` | `string` | The name of the transition to use while a toast is presented. | * | `toastLeave` | `string` | The name of the transition to use while a toast is dismissed. | * diff --git a/src/config/modes.ts b/src/config/modes.ts index c691cfa7abf..25d82a5baa6 100644 --- a/src/config/modes.ts +++ b/src/config/modes.ts @@ -39,6 +39,7 @@ Config.setModeConfig('ios', { tabsHighlight: false, tabsPlacement: 'bottom', + tabsHideOnSubPages: false, toastEnter: 'toast-slide-in', toastLeave: 'toast-slide-out', @@ -81,7 +82,8 @@ Config.setModeConfig('md', { spinner: 'crescent', tabsHighlight: true, - tabsPlacement: 'bottom', + tabsPlacement: 'top', + tabsHideOnSubPages: true, toastEnter: 'toast-md-slide-in', toastLeave: 'toast-md-slide-out', @@ -125,6 +127,7 @@ Config.setModeConfig('wp', { tabsHighlight: false, tabsPlacement: 'top', + tabsHideOnSubPages: true, toastEnter: 'toast-wp-slide-in', toastLeave: 'toast-wp-slide-out', diff --git a/src/decorators/page.ts b/src/decorators/page.ts index bd02cab98b5..f76ed24c931 100644 --- a/src/decorators/page.ts +++ b/src/decorators/page.ts @@ -38,6 +38,7 @@ export function Page(config: PageMetadata) { config.selector = 'ion-page'; config.host = config.host || {}; config.host['[hidden]'] = '_hidden'; + config.host['[class.tab-subpage]'] = '_tabSubPage'; var annotations = _reflect.getMetadata('annotations', cls) || []; annotations.push(new Component(config)); _reflect.defineMetadata('annotations', annotations, cls); diff --git a/src/platform/cordova.ios.scss b/src/platform/cordova.ios.scss index 9e0609fae91..aa2a1945ea9 100644 --- a/src/platform/cordova.ios.scss +++ b/src/platform/cordova.ios.scss @@ -10,6 +10,7 @@ $cordova-ios-statusbar-padding-modal-max-width: $cordova-statusbar-paddi ion-nav > ion-page, ion-nav > ion-page > ion-header, ion-tab > ion-page > ion-header, +ion-tabs > ion-page.tab-subpage > ion-header, ion-menu { @include toolbar-statusbar-padding($toolbar-ios-height, $content-ios-padding); @include toolbar-title-statusbar-padding($toolbar-ios-height, $content-ios-padding); diff --git a/src/platform/cordova.md.scss b/src/platform/cordova.md.scss index cb8dc1d3518..4897a4e2782 100644 --- a/src/platform/cordova.md.scss +++ b/src/platform/cordova.md.scss @@ -10,6 +10,7 @@ $cordova-md-statusbar-padding-modal-max-width: $cordova-statusbar-paddin ion-nav > ion-page, ion-nav > ion-page > ion-header, ion-tab > ion-page > ion-header, +ion-tabs > ion-page.tab-subpage > ion-header, ion-menu { @include toolbar-statusbar-padding($toolbar-md-height, $content-md-padding); } diff --git a/src/platform/cordova.wp.scss b/src/platform/cordova.wp.scss index b45a38f2273..230a426fb95 100644 --- a/src/platform/cordova.wp.scss +++ b/src/platform/cordova.wp.scss @@ -10,6 +10,7 @@ $cordova-wp-statusbar-padding-modal-max-width: $cordova-statusbar-paddin ion-nav > ion-page, ion-nav > ion-page > ion-header, ion-tab > ion-page > ion-header, +ion-tabs > ion-page.tab-subpage > ion-header, ion-menu { @include toolbar-statusbar-padding($toolbar-wp-height, $content-wp-padding); }