feat(tabs): add tabs component from core

This commit is contained in:
Brandy Carney
2017-07-05 11:47:46 -04:00
parent 25eb7dc3f5
commit 576f83df40
9 changed files with 1202 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
import { Component, h } from '@stencil/core';
import { VNodeData } from '../../utils/interfaces';
@Component({
tag: 'ion-tab-bar',
host: {
theme: 'tabbar'
}
})
export class TabBar {
@Prop() tabs: [Tab] = [];
@Prop() onTabSelected: Function;
@Prop() selectedIndex: number = 0;
/**
* @prop {string} Set the tabbar layout: `icon-top`, `icon-start`, `icon-end`, `icon-bottom`, `icon-hide`, `title-hide`.
*/
@Prop() tabsLayout: string = 'icon-top'
hostData(): VNodeData {
return {
attrs: {
'role': 'tablist'
},
class: {
'tabbar': true
}
}
}
handleTabButtonClick(tab, index) {
this.onTabSelected && this.onTabSelected(tab, index);
}
render() {
return (
<div class="tabbar" role="tablist">
{this.tabs.map((tab, index) => {
return (
<ion-tab-button role="tab"
tab={tab}
selectedIndex={this.selectedIndex}
index={index}
onClick={this.handleTabButtonClick.bind(this, tab, index)}
layout={this.tabsLayout}></ion-tab-button>
)
})}
</div>
)
}
}

View File

@@ -0,0 +1,78 @@
import { Component, h } from '@stencil/core';
import { VNodeData } from '../../utils/interfaces';
@Component({
tag: 'ion-tab-button',
host: {
theme: 'tab-button'
}
})
export class TabButton {
@Prop() tab: Tab;
@Prop() layout: string;
@Prop() selectedIndex: number;
@Prop() index: number;
hostData(): VNodeData {
const tab = this.tab;
if(!tab) return {};
// attr.id
// attr.aria-controls
const hasTitle = !!tab.tabTitle;
const hasIcon = !!tab.tabIcon && this.layout !== 'icon-hide';
const hasTitleOnly = (hasTitle && !hasIcon);
const hasIconOnly = (hasIcon && !hasTitle);
const hasBadge = !!tab.tabBadge;
// class.disable-hover
// class.tab-disabled
// class.tab-hidden
return {
attrs: {
'aria-selected': this.selectedIndex == this.index
},
class: {
'has-title': hasTitle,
'has-icon': hasIcon,
'has-title-only': hasTitleOnly,
'has-icon-only': hasIconOnly,
'has-badge': hasBadge
}
};
}
render() {
if(!this.tab) {
return null;
}
const tab = this.tab
// TODO: Apply these on host?
let { id, ariaControls, ariaSelected, hasTitle, hasIcon, hasTitleOnly,
iconOnly, hasBadge, disableHover, tabDisabled, tabHidden } = {};
const items = []
if(tab.tabIcon) {
items.push(<ion-icon class="tab-button-icon" name={tab.tabIcon}></ion-icon>);
}
if(tab.tabTitle) {
items.push(<span class="tab-button-text">{tab.tabTitle}</span>);
}
if(tab.tabBadge) {
items.push(<ion-badge class="tab-badge" color={tab.tabBadgeStyle}>{tab.tabBadge}</ion-badge>);
}
items.push(<div class="button-effect"></div>);
return (items)
}
}

View File

@@ -0,0 +1,13 @@
import { Component, h } from '@stencil/core';
@Component({
tag: 'ion-tab-highlight'
})
export class TabHighlight {
render() {
return (
<div></div>
);
}
}

View File

@@ -0,0 +1,110 @@
import { Component, h, Ionic } from '@stencil/core';
import { VNodeData } from '../../utils/interfaces';
@Component({
tag: 'ion-tab',
host: {
theme: 'tab'
}
})
export class Tab {
/**
* @prop {Page} Set the root component for this tab.
*/
@Prop() root: string;
/**
* @prop {object} Any nav-params to pass to the root componentof this tab.
*/
@Prop() rootParams: any;
/**
* @prop {boolean} If true, the tab is selected
*/
@State() isSelected: Boolean = false;
/**
* @prop {string} The title of the tab button.
*/
@Prop() tabTitle: string;
/**
* @prop {string} The icon for the tab button.
*/
@Prop() tabIcon: string;
/**
* @prop {string} The badge for the tab button.
*/
@Prop() tabBadge: string;
/**
* @prop {string} The badge color for the tab button.
*/
@Prop() tabBadgeStyle: string;
/**
* @prop {boolean} If true, enable the tab. If false,
* the user cannot interact with this element.
* Default: `true`.
*/
@Prop() enabled: boolean = true;
/**
* @prop {boolean} If true, the tab button is visible within the
* tabbar. Default: `true`.
*/
@Prop() shown: boolean = true;
/**
* @prop {boolean} If true, hide the tabs on child pages.
*/
@Prop() tabsHideOnSubPages: boolean = false;
/**
* @prop {Tab} Emitted when the current tab is selected.
*/
@Prop() onSelected: Function;
hostData(): VNodeData {
return {
style: {
display: !this.isSelected && 'none' || ''
},
attrs: {
'role': 'tabpanel'
//'id': _tabId,
//aria-labelledby: _btnId
},
class: {
}
};
}
ionViewDidLoad() {
setTimeout(() => {
Ionic.emit(this, 'ionTabDidLoad', {
detail: {
tab: this
}
})
}, 0)
}
ionViewDidUnload() {
Ionic.emit(this, 'ionTabDidLoad', {
detail: {
tab: this
}
})
}
render() {
const RootComponent = this.root;
return [
<RootComponent />,
<div class="nav-decor"></div>
]
}
}

View File

@@ -0,0 +1,175 @@
@import "../../themes/ionic.globals.ios";
@import "./tabs";
// iOS Tabs
// --------------------------------------------------
/// @prop - Border on the tabbar (border-top when [tabsPlacement=bottom] and border-bottom when [tabsPlacement=top])
$tabs-ios-border: $hairlines-width solid $tabs-ios-border-color !default;
// deprecated
$tabs-ios-tab-padding: null !default;
/// @prop - Padding top on the tab button
$tabs-ios-tab-padding-top: 0 !default;
/// @prop - Padding end on the tab button
$tabs-ios-tab-padding-end: 2px !default;
/// @prop - Padding bottom on the tab button
$tabs-ios-tab-padding-bottom: $tabs-ios-tab-padding-top !default;
/// @prop - Padding start on the tab button
$tabs-ios-tab-padding-start: $tabs-ios-tab-padding-end !default;
/// @prop - Max width of the tab button
$tabs-ios-tab-max-width: 240px !default;
/// @prop - Minimum height of the tab button
$tabs-ios-tab-min-height: 49px !default;
/// @prop - Text color of the inactive tab button
$tabs-ios-tab-text-color: $tabs-ios-tab-color-inactive !default;
/// @prop - Text color of the active tab button
$tabs-ios-tab-text-color-active: $tabs-ios-tab-color-active !default;
/// @prop - Icon color of the inactive tab button
$tabs-ios-tab-icon-color: $tabs-ios-tab-color-inactive !default;
/// @prop - Icon color of the active tab button
$tabs-ios-tab-icon-color-active: $tabs-ios-tab-color-active !default;
/// @prop - Font size of the tab button text
$tabs-ios-tab-font-size: 10px !default;
/// @prop - Size of the tab button icon
$tabs-ios-tab-icon-size: 30px !default;
.tabs-ios .tabbar {
justify-content: center;
border-top: $tabs-ios-border;
background: $tabs-ios-background;
}
.tabs-ios[tabsPlacement=top] .tabbar {
border-top: 0;
border-bottom: $tabs-ios-border;
}
.tabs-ios .tab-button {
max-width: $tabs-ios-tab-max-width;
min-height: $tabs-ios-tab-min-height;
font-size: $tabs-ios-tab-font-size;
color: $tabs-ios-tab-text-color;
@include deprecated-variable(padding, $tabs-ios-tab-padding) {
@include padding($tabs-ios-tab-padding-top, $tabs-ios-tab-padding-end, $tabs-ios-tab-padding-bottom, $tabs-ios-tab-padding-start);
}
}
.tabs-ios .tab-button:hover:not(.disable-hover),
.tabs-ios .tab-button[aria-selected=true] {
color: $tabs-ios-tab-text-color-active;
}
.tabs-ios .tab-button[aria-selected=true] .tab-button-icon {
color: $tabs-ios-tab-icon-color-active;
}
.tabs-ios .tab-button-text {
@include margin(0, null, 1px, null);
min-height: $tabs-ios-tab-font-size + 1;
}
.tabs-ios .has-title-only .tab-button-text {
font-size: $tabs-ios-tab-font-size + 2;
}
.tabs-ios .tab-button-icon {
@include margin(4px, null, 1px, null);
min-width: $tabs-ios-tab-icon-size + 5;
height: $tabs-ios-tab-icon-size;
font-size: $tabs-ios-tab-icon-size;
color: $tabs-ios-tab-icon-color;
}
.tabs-ios .tab-button-icon::before {
vertical-align: top;
}
.tabs-ios[tabsLayout=icon-right] .tab-button .tab-button-text, // deprecated
.tabs-ios[tabsLayout=icon-left] .tab-button .tab-button-text, // deprecated
.tabs-ios[tabsLayout=icon-end] .tab-button .tab-button-text,
.tabs-ios[tabsLayout=icon-start] .tab-button .tab-button-text {
font-size: 1.4rem;
line-height: 1.1;
}
.tabs-ios[tabsLayout=icon-right] .tab-button ion-icon, // deprecated
.tabs-ios[tabsLayout=icon-left] .tab-button ion-icon, // deprecated
.tabs-ios[tabsLayout=icon-end] .tab-button ion-icon,
.tabs-ios[tabsLayout=icon-start] .tab-button ion-icon {
min-width: 24px;
height: 26px;
font-size: 24px;
}
.tabs-ios[tabsLayout=icon-hide] .tab-button,
.tabs-ios .tab-button.has-title-only {
min-height: $tabs-ios-tab-min-height - 8;
}
.tabs-ios[tabsLayout=icon-hide] .tab-button .tab-button-text,
.tabs-ios .tab-button.has-title-only .tab-button-text {
@include margin(2px, 0);
font-size: 1.4rem;
line-height: 1.1;
}
.tabs-ios[tabsLayout=title-hide] .tab-button,
.tabs-ios .tab-button.icon-only {
min-height: $tabs-ios-tab-min-height - 8;
}
// iOS Tabbar Color Mixin
// --------------------------------------------------
@mixin tabbar-ios($color-name, $color-base, $color-contrast) {
.tabs-ios-#{$color-name} .tabbar {
border-color: darken($color-base, 10%);
background-color: $color-base;
}
.tabs-ios-#{$color-name} .tab-button,
.tabs-ios-#{$color-name} .tab-button-icon,
.tabs-ios-#{$color-name} .tab-button:hover:not(.disable-hover),
.tabs-ios-#{$color-name} .tab-button:hover:not(.disable-hover) .tab-button-icon {
color: rgba($color-contrast, .7);
}
.tabs-ios-#{$color-name} .tab-button[aria-selected=true],
.tabs-ios-#{$color-name} .tab-button[aria-selected=true] .tab-button-icon {
color: $color-contrast;
}
}
// iOS Tabbar Color Generation
// --------------------------------------------------
@each $color-name, $color-base, $color-contrast in get-colors($colors-ios) {
@include tabbar-ios($color-name, $color-base, $color-contrast);
}

View File

@@ -0,0 +1,344 @@
@import "../../themes/ionic.globals.md";
@import "./tabs";
// Material Design Tabs
// --------------------------------------------------
// deprecated
$tabs-md-tab-padding: null !default;
/// @prop - Padding top on the tab button
$tabs-md-tab-padding-top: 0 !default;
/// @prop - Padding end on the tab button
$tabs-md-tab-padding-end: $tabs-md-tab-padding-top !default;
/// @prop - Padding bottom on the tab button
$tabs-md-tab-padding-bottom: $tabs-md-tab-padding-top !default;
/// @prop - Padding start on the tab button
$tabs-md-tab-padding-start: $tabs-md-tab-padding-end !default;
/// @prop - Minimum height of the tab button
$tabs-md-tab-min-height: 5.6rem !default;
/// @prop - Font size of the inactive tab button text
$tabs-md-tab-font-size: 1.2rem !default;
/// @prop - Font weight of the tab button text
$tabs-md-tab-font-weight: normal !default;
/// @prop - Opacity of the inactive tab button
$tabs-md-tab-opacity: .7 !default;
/// @prop - Text color of the inactive tab button
$tabs-md-tab-text-color: rgba($tabs-md-tab-color-inactive, $tabs-md-tab-opacity) !default;
/// @prop - Text color of the active tab button
$tabs-md-tab-text-color-active: $tabs-md-tab-color-active !default;
/// @prop - Icon color of the inactive tab button
$tabs-md-tab-icon-color: rgba($tabs-md-tab-color-inactive, $tabs-md-tab-opacity) !default;
/// @prop - Icon color of the active tab button
$tabs-md-tab-icon-color-active: $tabs-md-tab-color-active !default;
// deprecated
$tabs-md-tab-padding-active: null !default;
/// @prop - Padding top of the active tab button
$tabs-md-tab-padding-active-top: 0 !default;
/// @prop - Padding end of the active tab button
$tabs-md-tab-padding-active-end: $tabs-md-tab-padding-active-top !default;
/// @prop - Padding bottom of the active tab button
$tabs-md-tab-padding-active-bottom: $tabs-md-tab-padding-active-top !default;
/// @prop - Padding start of the active tab button
$tabs-md-tab-padding-active-start: $tabs-md-tab-padding-active-end !default;
/// @prop - Font size of the active tab button text
$tabs-md-tab-font-size-active: 1.4rem !default;
// deprecated
$tabs-md-tab-text-margin: null !default;
/// @prop - Margin top on the tab button text
$tabs-md-tab-text-margin-top: 0 !default;
/// @prop - Margin end on the tab button text
$tabs-md-tab-text-margin-end: $tabs-md-tab-text-margin-top !default;
/// @prop - Margin bottom on the tab button text
$tabs-md-tab-text-margin-bottom: $tabs-md-tab-text-margin-top !default;
/// @prop - Margin start on the tab button text
$tabs-md-tab-text-margin-start: $tabs-md-tab-text-margin-end !default;
/// @prop - Capitalization of the tab button text
$tabs-md-tab-text-capitalization: none !default;
// deprecated
$tabs-md-tab-text-transform-origin: null !default;
/// @prop - Transform origin x for the tab button text
$tabs-md-tab-text-transform-origin-x: 50% !default;
/// @prop - Transform origin y for the tab button text
$tabs-md-tab-text-transform-origin-y: 80% !default;
/// @prop - Transform for the active tab button text
$tabs-md-tab-text-transform-active: scale3d($tabs-md-tab-font-size-active / $tabs-md-tab-font-size, $tabs-md-tab-font-size-active / $tabs-md-tab-font-size, 1) !default;
/// @prop - Text transition for the tab button text
$tabs-md-tab-text-transition: transform .3s ease-in-out !default;
// deprecated
$tabs-md-tab-icon-transform-active: null !default;
/// @prop - Transform x for the active tab button icon when the layout is icon-top, icon-only, or title-only
$tabs-md-tab-icon-transform-x-active: 0 !default;
/// @prop - Transform y for the active tab button icon when the layout is icon-top, icon-only, or title-only
$tabs-md-tab-icon-transform-y-active: -2px !default;
/// @prop - Transform z for the active tab button icon when the layout is icon-top, icon-only, or title-only
$tabs-md-tab-icon-transform-z-active: 0 !default;
// deprecated
$tabs-md-tab-icon-end-transform-active: null !default;
/// @prop - Transform x for the active tab button icon when the layout is icon-right
$tabs-md-tab-icon-right-transform-x-active: 2px !default;
/// @prop - Transform y for the active tab button icon when the layout is icon-right
$tabs-md-tab-icon-right-transform-y-active: 0 !default;
/// @prop - Transform z for the active tab button icon when the layout is icon-right
$tabs-md-tab-icon-right-transform-z-active: 0 !default;
// deprecated
$tabs-md-tab-icon-bottom-transform-active: null !default;
/// @prop - Transform x for the active tab button icon when the layout is icon-bottom
$tabs-md-tab-icon-bottom-transform-x-active: 0 !default;
/// @prop - Transform y for the active tab button icon when the layout is icon-bottom
$tabs-md-tab-icon-bottom-transform-y-active: 2px !default;
/// @prop - Transform z for the active tab button icon when the layout is icon-bottom
$tabs-md-tab-icon-bottom-transform-z-active: 0 !default;
// deprecated
$tabs-md-tab-icon-start-transform-active: null !default;
/// @prop - Transform x for the active tab button icon when the layout is icon-left
$tabs-md-tab-icon-left-transform-x-active: -2px !default;
/// @prop - Transform y for the active tab button icon when the layout is icon-left
$tabs-md-tab-icon-left-transform-y-active: 0 !default;
/// @prop - Transform z for the active tab button icon when the layout is icon-left
$tabs-md-tab-icon-left-transform-z-active: 0 !default;
// deprecated
$tabs-md-tab-icon-transform-origin: null !default;
/// @prop - Transform origin x for the tab button text
$tabs-md-tab-icon-transform-origin-x: 50% !default;
/// @prop - Transform origin y for the tab button text
$tabs-md-tab-icon-transform-origin-y: 150% !default;
/// @prop - Text transition for the tab button icon
$tabs-md-tab-icon-transition: transform .3s ease-in-out !default;
/// @prop - Size of the tab button icon
$tabs-md-tab-icon-size: 2.4rem !default;
.tabs-md .tabbar {
background: $tabs-md-background;
}
// Material Design Tab Button
// --------------------------------------------------
.tabs-md .tab-button {
min-height: $tabs-md-tab-min-height;
font-weight: $tabs-md-tab-font-weight;
color: $tabs-md-tab-text-color;
@include deprecated-variable(padding, $tabs-md-tab-padding) {
@include padding($tabs-md-tab-padding-top, $tabs-md-tab-padding-end, $tabs-md-tab-padding-bottom, $tabs-md-tab-padding-start);
}
}
.tabs-md .tab-button[aria-selected=true] {
color: $tabs-md-tab-text-color-active;
@include deprecated-variable(padding, $tabs-md-tab-padding-active) {
@include padding($tabs-md-tab-padding-active-top, $tabs-md-tab-padding-active-end, $tabs-md-tab-padding-active-bottom, $tabs-md-tab-padding-active-start);
}
}
// Material Design Tab Button Text
// --------------------------------------------------
.tabs-md .tab-button-text {
font-size: $tabs-md-tab-font-size;
text-transform: $tabs-md-tab-text-capitalization;
transition: $tabs-md-tab-text-transition;
@include deprecated-variable(margin, $tabs-md-tab-text-margin) {
@include margin($tabs-md-tab-text-margin-top, $tabs-md-tab-text-margin-end, $tabs-md-tab-text-margin-bottom, $tabs-md-tab-text-margin-start);
}
@include deprecated-variable(transform-origin, $tabs-md-tab-text-transform-origin) {
@include transform-origin($tabs-md-tab-text-transform-origin-x, $tabs-md-tab-text-transform-origin-y);
}
}
.tabs-md .tab-button[aria-selected=true] .tab-button-text {
transform: $tabs-md-tab-text-transform-active;
transition: $tabs-md-tab-text-transition;
}
.tabs-md[tabsLayout=icon-top] .has-icon .tab-button-text {
@include margin(4px, null, 0, null);
}
.tabs-md[tabsLayout=icon-bottom] .tab-button .tab-button-text {
@include margin(0, null, null, null);
}
// Material Design Tab Button Icon
// --------------------------------------------------
.tabs-md .tab-button-icon {
@include margin(1px, null, null, null);
min-width: $tabs-md-tab-icon-size;
font-size: $tabs-md-tab-icon-size;
color: $tabs-md-tab-icon-color;
transition: $tabs-md-tab-icon-transition;
@include deprecated-variable(transform-origin, $tabs-md-tab-icon-transform-origin) {
@include transform-origin($tabs-md-tab-icon-transform-origin-x, $tabs-md-tab-icon-transform-origin-y);
}
}
// Tab layout: icon-top, icon-only, title-only
.tabs-md .tab-button[aria-selected=true] .tab-button-icon {
color: $tabs-md-tab-icon-color-active;
@include deprecated-variable(transform, $tabs-md-tab-icon-transform-active) {
@include transform(translate3d($tabs-md-tab-icon-transform-x-active, $tabs-md-tab-icon-transform-y-active, $tabs-md-tab-icon-transform-z-active));
}
}
// Tab layout: icon-end
.tabs-md[tabsLayout=icon-right] .tab-button[aria-selected=true] .tab-button-icon, // deprecated
.tabs-md[tabsLayout=icon-end] .tab-button[aria-selected=true] .tab-button-icon {
@include deprecated-variable(transform, $tabs-md-tab-icon-end-transform-active) {
@include transform(translate3d($tabs-md-tab-icon-right-transform-x-active, $tabs-md-tab-icon-right-transform-y-active, $tabs-md-tab-icon-right-transform-z-active));
}
}
// Tab layout: icon-bottom
.tabs-md[tabsLayout=icon-bottom] .tab-button[aria-selected=true] .tab-button-icon {
@include deprecated-variable(transform, $tabs-md-tab-icon-bottom-transform-active) {
@include transform(translate3d($tabs-md-tab-icon-bottom-transform-x-active, $tabs-md-tab-icon-bottom-transform-y-active, $tabs-md-tab-icon-bottom-transform-z-active));
}
}
// Tab layout: icon-start
.tabs-md[tabsLayout=icon-left] .tab-button[aria-selected=true] .tab-button-icon, // deprecated
.tabs-md[tabsLayout=icon-start] .tab-button[aria-selected=true] .tab-button-icon {
@include deprecated-variable(transform, $tabs-md-tab-icon-start-transform-active) {
@include transform(translate3d($tabs-md-tab-icon-left-transform-x-active, $tabs-md-tab-icon-left-transform-y-active, $tabs-md-tab-icon-left-transform-z-active));
}
}
// Material Design Tab with Icon or Title only
// --------------------------------------------------
.tabs-md[tabsLayout=icon-hide] .tab-button,
.tabs-md[tabsLayout=title-hide] .tab-button,
.tabs-md .tab-button.icon-only,
.tabs-md .tab-button.has-title-only {
@include padding(0, 10px);
}
// Material Design Tab Highlight
// --------------------------------------------------
.tabs-md[tabsHighlight=true] .tab-highlight {
@include position(null, null, 0, 0);
@include transform-origin(0, 0);
position: absolute;
display: block;
width: 1px;
height: 2px;
background: $tabs-md-tab-color-active;
transform: translateZ(0);
}
.tabs-md[tabsHighlight=true] .tab-highlight.animate {
transition-duration: 300ms;
}
.tabs-md[tabsHighlight=true][tabsPlacement=bottom] > .tabbar > .tab-highlight {
top: 0;
}
// Material Design Tabs Color Mixin
// --------------------------------------------------
@mixin tabbar-md($color-name, $color-base, $color-contrast) {
.tabs-md-#{$color-name} .tabbar {
background-color: $color-base;
}
.tabs-md-#{$color-name} .tab-button,
.tabs-md-#{$color-name} .tab-button-icon {
color: rgba($color-contrast, $tabs-md-tab-opacity);
}
.tabs-md-#{$color-name} .tab-button:hover:not(.disable-hover),
.tabs-md-#{$color-name} .tab-button[aria-selected=true],
.tabs-md-#{$color-name} .tab-button[aria-selected=true] .tab-button-icon {
color: $color-contrast;
}
.tabs-md-#{$color-name}[tabsHighlight=true] .tab-highlight {
background: $color-contrast;
}
}
// Material Design Tabbar Color Generation
// --------------------------------------------------
@each $color-name, $color-base, $color-contrast in get-colors($colors-md) {
@include tabbar-md($color-name, $color-base, $color-contrast);
}

View File

@@ -0,0 +1,153 @@
@import "../../themes/ionic.globals";
// Tabs
// --------------------------------------------------
.tabbar {
@include position(null, null, 0, 0);
position: absolute;
z-index: $z-index-toolbar;
display: flex;
width: 100%;
// default to hidden until ready
//opacity: 0;
}
.tabbar-hidden .tabbar {
display: none;
}
.tabbar.show-tabbar {
opacity: 1;
}
[tabsPlacement=top] > .tabbar {
top: 0;
bottom: auto;
}
.tab-button {
@include margin(0);
@include text-align(center);
@include border-radius(0);
position: relative;
z-index: 0;
display: flex;
overflow: hidden;
flex: 1;
flex-direction: column;
align-items: center;
align-self: center;
justify-content: center;
border: 0;
text-decoration: none;
background: none;
cursor: pointer;
user-select: none;
}
.tab-disabled {
pointer-events: none;
}
.tab-disabled ion-badge,
.tab-disabled ion-icon,
.tab-disabled span {
opacity: .4;
}
.tab-button-text {
@include margin(3px, null, 2px, null);
}
.tab-button-text,
.tab-button-icon {
//display: none;
overflow: hidden;
align-self: center;
min-width: 26px;
max-width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
}
.has-icon .tab-button-icon,
.has-title .tab-button-text {
display: block;
}
.has-title-only .tab-button-text {
white-space: normal;
}
[tabsLayout=icon-bottom] .tab-button .tab-button-icon {
order: 10;
}
[tabsLayout=icon-left] .tab-button, // deprecated
[tabsLayout=icon-right] .tab-button, // deprecated
[tabsLayout=icon-start] .tab-button,
[tabsLayout=icon-end] .tab-button {
flex-direction: row;
}
[tabsLayout=icon-left] .tab-button .tab-button-icon, // deprecated
[tabsLayout=icon-start] .tab-button .tab-button-icon {
@include padding-horizontal(null, 8px);
@include text-align(end);
}
[tabsLayout=icon-right] .tab-button .tab-button-icon, // deprecated
[tabsLayout=icon-end] .tab-button .tab-button-icon {
@include padding-horizontal(8px, null);
@include text-align(start);
order: 10;
}
.tab-hidden,
.tab-highlight,
[tabsLayout=icon-hide] .tab-button-icon,
[tabsLayout=title-hide] .tab-button-text {
display: none;
}
// Tab Badges
// --------------------------------------------------
.tab-badge {
@include position(6%, 4%, null, null); // 4% fallback
@include position(null, calc(50% - 50px), null, null);
@include padding(1px, 6px);
position: absolute;
height: auto;
font-size: 12px;
line-height: 16px;
}
.has-icon .tab-badge {
@include position(null, calc(50% - 30px), null, null);
}
[tabsLayout=icon-bottom] .tab-badge,
[tabsLayout=icon-left] .tab-badge, // deprecated
[tabsLayout=icon-right] .tab-badge, // deprecated
[tabsLayout=icon-start] .tab-badge,
[tabsLayout=icon-end] .tab-badge {
@include position(null, calc(50% - 50px), null, null);
}

View File

@@ -0,0 +1,96 @@
import { Component, h, Listen } from '@stencil/core';
@Component({
tag: 'ion-tabs',
styleUrls: {
ios: 'tabs.ios.scss',
md: 'tabs.md.scss',
wp: 'tabs.wp.scss'
},
host: {
theme: 'tabs'
}
})
export class Tabs {
// Current list of tabs
@State() tabs: [Tab] = []
/**
* @state {number} The selected tab
*/
@State() selectedTab: Tab;
/**
* @state {number} The selected tab index
*/
@State() selectedIndex: number = 0;
/**
* @prop {string} Set the tabbar layout: `icon-top`, `icon-start`, `icon-end`, `icon-bottom`, `icon-hide`, `title-hide`.
*/
@Prop() tabsLayout: string = 'icon-top'
/**
* @prop {string} Set position of the tabbar: `top`, `bottom`.
*/
@Prop() tabsPlacement: string = 'bottom';
/**
* @prop {boolean} If true, show the tab highlight bar under the selected tab.
*/
@Prop() tabsHighlight: boolean = false;
/**
* @output {any} Emitted when the tab changes.
*/
@Prop() ionChange: Function;
/**
* If selectedIndex was changed, grab the reference to the tab it points to.
*/
@PropDidChange('selectedIndex')
handleSelectedIndexChanged() {
this.selectedTab = this.tabs[this.selectedIndex]
}
@Listen('ionTabDidLoad')
tabDidLoad(ev) {
const tab = ev.detail.tab;
// First tab? Select it
if(this.tabs.length == 0) {
this.handleOnTabSelected(tab, 0);
}
this.tabs = [ ...this.tabs, tab ];
}
@Listen('ionTabDidUnload')
tabDidUnload(ev) {
this.tabs = this.tabs.filter(t => t !== ev.detail.tab)
}
handleOnTabSelected(tab, index) {
// Select just this tab
this.tabs.forEach(t => t.isSelected = false);
tab.isSelected = true;
// Store the selected tab and index
this.selectedTab = tab;
this.selectedIndex = index;
// Fire a change event
this.ionChange && this.ionChange(tab)
}
render() {
return [
<ion-tab-bar
tabs={this.tabs}
onTabSelected={this.handleOnTabSelected.bind(this)}
selectedIndex={this.selectedIndex} />,
<slot></slot>
]
}
}

View File

@@ -0,0 +1,178 @@
@import "../../themes/ionic.globals.wp";
@import "./tabs";
// Windows Tabs
// --------------------------------------------------
// deprecated
$tabs-wp-tab-padding: null !default;
/// @prop - Padding top on the tab button
$tabs-wp-tab-padding-top: 12px !default;
/// @prop - Padding end on the tab button
$tabs-wp-tab-padding-end: 10px !default;
/// @prop - Padding bottom on the tab button
$tabs-wp-tab-padding-bottom: 5px !default;
/// @prop - Padding start on the tab button
$tabs-wp-tab-padding-start: 10px !default;
/// @prop - Minimum height of the tab button
$tabs-wp-tab-min-height: 4.8rem !default;
/// @prop - Font size of the tab button text
$tabs-wp-tab-font-size: 1.2rem !default;
/// @prop - Font weight of the tab button text
$tabs-wp-tab-font-weight: normal !default;
/// @prop - Opacity of the inactive tab button
$tabs-wp-tab-opacity: .7 !default;
/// @prop - Text color of the inactive tab button
$tabs-wp-tab-color: rgba($tabs-wp-tab-color-inactive, $tabs-wp-tab-opacity) !default;
/// @prop - Text color of the active tab button
$tabs-wp-tab-color-active: $tabs-wp-tab-color-active !default;
/// @prop - Icon color of the inactive tab button
$tabs-wp-tab-icon-color: rgba($tabs-wp-tab-color-inactive, $tabs-wp-tab-opacity) !default;
/// @prop - Icon color of the active tab button
$tabs-wp-tab-icon-color-active: $tabs-wp-tab-color-active !default;
/// @prop - Border on the inactive tab button (border-top when [tabsPlacement=bottom] and border-bottom when [tabsPlacement=top])
$tabs-wp-tab-border: 2px solid $tabs-wp-border-color !default;
/// @prop - Border color on the active tab button (border-top when [tabsPlacement=bottom] and border-bottom when [tabsPlacement=top])
$tabs-wp-tab-border-color-active: $tabs-wp-tab-color-active !default;
/// @prop - Background of the tab button when pressed
$tabs-wp-tab-background-activated: rgba(0, 0, 0, .1) !default;
/// @prop - Size of the tab button icon
$tabs-wp-tab-icon-size: 2.4rem !default;
.tabs-wp .tabbar {
background: $tabs-wp-background;
}
.tabs-wp .tab-button {
@include border-radius(0);
min-height: $tabs-wp-tab-min-height;
border-bottom: $tabs-wp-tab-border;
font-size: $tabs-wp-tab-font-size;
font-weight: $tabs-wp-tab-font-weight;
color: $tabs-wp-tab-color;
box-shadow: none;
@include deprecated-variable(padding, $tabs-wp-tab-padding) {
@include padding($tabs-wp-tab-padding-top, $tabs-wp-tab-padding-end, $tabs-wp-tab-padding-bottom, $tabs-wp-tab-padding-start);
}
}
.tabs-wp .tab-button[aria-selected=true] {
border-bottom-color: $tabs-wp-tab-border-color-active;
color: $tabs-wp-tab-color-active;
}
.tabs-wp .tab-button.activated {
background: $tabs-wp-tab-background-activated;
}
.tabs-wp[tabsPlacement=bottom] .tab-button {
border-top: $tabs-wp-tab-border;
border-bottom-width: 0;
}
.tabs-wp[tabsPlacement=bottom] .tab-button[aria-selected=true] {
border-top-color: $tabs-wp-tab-border-color-active;
}
// Windows Tab Button Text
// --------------------------------------------------
.tabs-wp .tab-button-text {
@include margin(5px, null);
}
// Windows Tab Button Icon
// --------------------------------------------------
.tabs-wp .tab-button-icon {
min-width: $tabs-wp-tab-icon-size;
font-size: $tabs-wp-tab-icon-size;
color: $tabs-wp-tab-icon-color;
}
.tabs-wp .tab-button[aria-selected=true] .tab-button-icon {
color: $tabs-wp-tab-icon-color-active;
}
.tabs-wp[tabsLayout=icon-bottom] .tab-button {
@include padding(8px, null, 8px, null);
}
.tabs-wp[tabsLayout=icon-right] .tab-button, // deprecated
.tabs-wp[tabsLayout=icon-left] .tab-button, // deprecated
.tabs-wp[tabsLayout=icon-end] .tab-button,
.tabs-wp[tabsLayout=icon-start] .tab-button {
@include padding(null, null, 10px, null);
}
.tabs-wp[tabsLayout=icon-right] .tab-button ion-icon, // deprecated
.tabs-wp[tabsLayout=icon-left] .tab-button ion-icon, // deprecated
.tabs-wp[tabsLayout=icon-end] .tab-button ion-icon,
.tabs-wp[tabsLayout=icon-start] .tab-button ion-icon {
min-width: 24px;
}
.tabs-wp[tabsLayout=icon-hide] .tab-button,
.tabs-wp[tabsLayout=title-hide] .tab-button,
.tabs-wp .tab-button.icon-only,
.tabs-wp .tab-button.has-title-only {
@include padding(6px, 10px);
}
// Windows Tabbar Color Mixin
// --------------------------------------------------
@mixin tabbar-wp($color-name, $color-base, $color-contrast) {
.tabs-wp-#{$color-name} .tabbar {
background-color: $color-base;
}
.tabs-wp-#{$color-name} .tab-button,
.tabs-wp-#{$color-name} .tab-button-icon {
color: rgba($color-contrast, $tabs-wp-tab-opacity);
}
.tabs-wp-#{$color-name} .tab-button:hover:not(.disable-hover),
.tabs-wp-#{$color-name} .tab-button:hover:not(.disable-hover) .tab-button-icon,
.tabs-wp-#{$color-name} .tab-button[aria-selected=true],
.tabs-wp-#{$color-name} .tab-button[aria-selected=true] .tab-button-icon {
border-color: $color-contrast;
color: $color-contrast;
}
}
// Windows Tabbar Color Generation
// --------------------------------------------------
@each $color-name, $color-base, $color-contrast in get-colors($colors-wp) {
@include tabbar-wp($color-name, $color-base, $color-contrast);
}