mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
refactor(tabs): apply design-doc (#16048)
This commit is contained in:
@@ -21,7 +21,7 @@ export class StackController {
|
||||
ref: enteringRef,
|
||||
element: (enteringRef && enteringRef.location && enteringRef.location.nativeElement) as HTMLElement,
|
||||
url: this.getUrl(route),
|
||||
fullpath: document.location.pathname,
|
||||
fullpath: document.location!.pathname,
|
||||
deactivatedId: -1
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ export class TabsDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('ionTabbarClick', ['$event'])
|
||||
@HostListener('ionTabButtonClick', ['$event'])
|
||||
onTabbarClick(ev: UIEvent) {
|
||||
const tabElm: HTMLIonTabElement = ev.detail as any;
|
||||
if (this.router && tabElm && tabElm.href) {
|
||||
|
||||
@@ -72,7 +72,8 @@ export const DIRECTIVES = [
|
||||
d.Spinner,
|
||||
d.SplitPane,
|
||||
d.Tab,
|
||||
d.Tabbar,
|
||||
d.TabBar,
|
||||
d.TabButton,
|
||||
d.Tabs,
|
||||
d.Text,
|
||||
d.Textarea,
|
||||
|
||||
@@ -813,33 +813,42 @@ export class SplitPane {
|
||||
}
|
||||
|
||||
export declare interface Tab extends StencilComponents<'IonTab'> {}
|
||||
@Component({ selector: 'ion-tab', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['active', 'btnId', 'delegate', 'label', 'href', 'icon', 'badge', 'badgeColor', 'component', 'name', 'disabled', 'selected', 'show', 'tabsHideOnSubPages'] })
|
||||
@Component({ selector: 'ion-tab', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['active', 'delegate', 'tab', 'component'] })
|
||||
export class Tab {
|
||||
ionSelect: EventEmitter<CustomEvent>;
|
||||
ionTabMutated: EventEmitter<CustomEvent>;
|
||||
|
||||
constructor(r: ElementRef) {
|
||||
const el = r.nativeElement;
|
||||
proxyMethods(this, el, ['setActive']);
|
||||
proxyInputs(this, el, ['active', 'btnId', 'delegate', 'label', 'href', 'icon', 'badge', 'badgeColor', 'component', 'name', 'disabled', 'selected', 'show', 'tabsHideOnSubPages']);
|
||||
proxyOutputs(this, el, ['ionSelect', 'ionTabMutated']);
|
||||
proxyInputs(this, el, ['active', 'delegate', 'tab', 'component']);
|
||||
}
|
||||
}
|
||||
|
||||
export declare interface Tabbar extends StencilComponents<'IonTabbar'> {}
|
||||
@Component({ selector: 'ion-tabbar', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['mode', 'color', 'layout', 'placement', 'selectedTab', 'tabs', 'highlight', 'translucent'] })
|
||||
export class Tabbar {
|
||||
ionTabbarClick: EventEmitter<CustomEvent>;
|
||||
export declare interface TabBar extends StencilComponents<'IonTabBar'> {}
|
||||
@Component({ selector: 'ion-tab-bar', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['mode', 'color', 'layout', 'placement', 'selectedTab', 'translucent'] })
|
||||
export class TabBar {
|
||||
ionTabBarChanged: EventEmitter<CustomEvent>;
|
||||
|
||||
constructor(r: ElementRef) {
|
||||
const el = r.nativeElement;
|
||||
proxyInputs(this, el, ['mode', 'color', 'layout', 'placement', 'selectedTab', 'tabs', 'highlight', 'translucent']);
|
||||
proxyOutputs(this, el, ['ionTabbarClick']);
|
||||
proxyInputs(this, el, ['mode', 'color', 'layout', 'placement', 'selectedTab', 'translucent']);
|
||||
proxyOutputs(this, el, ['ionTabBarChanged']);
|
||||
}
|
||||
}
|
||||
|
||||
export declare interface TabButton extends StencilComponents<'IonTabButton'> {}
|
||||
@Component({ selector: 'ion-tab-button', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['mode', 'color', 'layout', 'href', 'tab', 'disabled'] })
|
||||
export class TabButton {
|
||||
ionTabButtonClick: EventEmitter<CustomEvent>;
|
||||
|
||||
constructor(r: ElementRef) {
|
||||
const el = r.nativeElement;
|
||||
proxyInputs(this, el, ['mode', 'color', 'layout', 'href', 'tab', 'disabled']);
|
||||
proxyOutputs(this, el, ['ionTabButtonClick']);
|
||||
}
|
||||
}
|
||||
|
||||
export declare interface Tabs extends StencilComponents<'IonTabs'> {}
|
||||
@Component({ selector: 'ion-tabs', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['name', 'tabbarHidden', 'useRouter'] })
|
||||
@Component({ selector: 'ion-tabs', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: '<ng-content></ng-content>', inputs: ['name'] })
|
||||
export class Tabs {
|
||||
ionChange: EventEmitter<CustomEvent>;
|
||||
ionNavWillLoad: EventEmitter<CustomEvent>;
|
||||
@@ -849,7 +858,7 @@ export class Tabs {
|
||||
constructor(r: ElementRef) {
|
||||
const el = r.nativeElement;
|
||||
proxyMethods(this, el, ['select', 'setRouteId', 'getRouteId', 'getTab', 'getSelected']);
|
||||
proxyInputs(this, el, ['name', 'tabbarHidden', 'useRouter']);
|
||||
proxyInputs(this, el, ['name']);
|
||||
proxyOutputs(this, el, ['ionChange', 'ionNavWillLoad', 'ionNavWillChange', 'ionNavDidChange']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,8 @@ const DECLARATIONS = [
|
||||
d.Spinner,
|
||||
d.SplitPane,
|
||||
d.Tab,
|
||||
d.Tabbar,
|
||||
d.TabBar,
|
||||
d.TabButton,
|
||||
d.Tabs,
|
||||
d.Text,
|
||||
d.Textarea,
|
||||
|
||||
304
core/src/components.d.ts
vendored
304
core/src/components.d.ts
vendored
@@ -55,6 +55,8 @@ import {
|
||||
Side,
|
||||
SpinnerTypes,
|
||||
StyleEvent,
|
||||
TabbarChangedDetail,
|
||||
TabbarClickDetail,
|
||||
TabbarLayout,
|
||||
TabbarPlacement,
|
||||
TextFieldTypes,
|
||||
@@ -3704,7 +3706,7 @@ export namespace Components {
|
||||
|
||||
interface IonRoute {
|
||||
/**
|
||||
* Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-nav`) when the route matches. The value of this property is not always the tagname of the component to load, in ion-tabs it actually refers to the name of the `ion-tab` to select.
|
||||
* Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-nav`) when the route matches. The value of this property is not always the tagname of the component to load, in `ion-tabs` it actually refers to the name of the `ion-tab` to select.
|
||||
*/
|
||||
'component': string;
|
||||
/**
|
||||
@@ -3718,7 +3720,7 @@ export namespace Components {
|
||||
}
|
||||
interface IonRouteAttributes extends StencilHTMLAttributes {
|
||||
/**
|
||||
* Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-nav`) when the route matches. The value of this property is not always the tagname of the component to load, in ion-tabs it actually refers to the name of the `ion-tab` to select.
|
||||
* Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-nav`) when the route matches. The value of this property is not always the tagname of the component to load, in `ion-tabs` it actually refers to the name of the `ion-tab` to select.
|
||||
*/
|
||||
'component'?: string;
|
||||
/**
|
||||
@@ -4538,146 +4540,13 @@ export namespace Components {
|
||||
'when'?: string | boolean;
|
||||
}
|
||||
|
||||
interface IonTab {
|
||||
/**
|
||||
* If `true`, sets the tab as the active tab.
|
||||
*/
|
||||
'active': boolean;
|
||||
/**
|
||||
* The badge for the tab.
|
||||
*/
|
||||
'badge'?: string;
|
||||
/**
|
||||
* The badge color for the tab button.
|
||||
*/
|
||||
'badgeColor'?: Color;
|
||||
/**
|
||||
* hidden
|
||||
*/
|
||||
'btnId'?: string;
|
||||
/**
|
||||
* The component to display inside of the tab.
|
||||
*/
|
||||
'component'?: ComponentRef;
|
||||
/**
|
||||
* hidden
|
||||
*/
|
||||
'delegate'?: FrameworkDelegate;
|
||||
/**
|
||||
* If `true`, the user cannot interact with the tab. Defaults to `false`.
|
||||
*/
|
||||
'disabled': boolean;
|
||||
/**
|
||||
* The URL which will be used as the `href` within this tab's button anchor.
|
||||
*/
|
||||
'href'?: string;
|
||||
/**
|
||||
* The icon for the tab.
|
||||
*/
|
||||
'icon'?: string;
|
||||
/**
|
||||
* The label of the tab.
|
||||
*/
|
||||
'label'?: string;
|
||||
/**
|
||||
* The name of the tab.
|
||||
*/
|
||||
'name'?: string;
|
||||
/**
|
||||
* If `true`, the tab will be selected. Defaults to `false`.
|
||||
*/
|
||||
'selected': boolean;
|
||||
/**
|
||||
* Set the active component for the tab
|
||||
*/
|
||||
'setActive': () => Promise<void>;
|
||||
/**
|
||||
* If `true`, the tab button is visible within the tabbar. Defaults to `true`.
|
||||
*/
|
||||
'show': boolean;
|
||||
/**
|
||||
* If `true`, hide the tabs on child pages.
|
||||
*/
|
||||
'tabsHideOnSubPages': boolean;
|
||||
}
|
||||
interface IonTabAttributes extends StencilHTMLAttributes {
|
||||
/**
|
||||
* If `true`, sets the tab as the active tab.
|
||||
*/
|
||||
'active'?: boolean;
|
||||
/**
|
||||
* The badge for the tab.
|
||||
*/
|
||||
'badge'?: string;
|
||||
/**
|
||||
* The badge color for the tab button.
|
||||
*/
|
||||
'badgeColor'?: Color;
|
||||
/**
|
||||
* hidden
|
||||
*/
|
||||
'btnId'?: string;
|
||||
/**
|
||||
* The component to display inside of the tab.
|
||||
*/
|
||||
'component'?: ComponentRef;
|
||||
/**
|
||||
* hidden
|
||||
*/
|
||||
'delegate'?: FrameworkDelegate;
|
||||
/**
|
||||
* If `true`, the user cannot interact with the tab. Defaults to `false`.
|
||||
*/
|
||||
'disabled'?: boolean;
|
||||
/**
|
||||
* The URL which will be used as the `href` within this tab's button anchor.
|
||||
*/
|
||||
'href'?: string;
|
||||
/**
|
||||
* The icon for the tab.
|
||||
*/
|
||||
'icon'?: string;
|
||||
/**
|
||||
* The label of the tab.
|
||||
*/
|
||||
'label'?: string;
|
||||
/**
|
||||
* The name of the tab.
|
||||
*/
|
||||
'name'?: string;
|
||||
/**
|
||||
* Emitted when the current tab is selected.
|
||||
*/
|
||||
'onIonSelect'?: (event: CustomEvent<void>) => void;
|
||||
/**
|
||||
* Emitted when the tab props mutates. Used internally.
|
||||
*/
|
||||
'onIonTabMutated'?: (event: CustomEvent<void>) => void;
|
||||
/**
|
||||
* If `true`, the tab will be selected. Defaults to `false`.
|
||||
*/
|
||||
'selected'?: boolean;
|
||||
/**
|
||||
* If `true`, the tab button is visible within the tabbar. Defaults to `true`.
|
||||
*/
|
||||
'show'?: boolean;
|
||||
/**
|
||||
* If `true`, hide the tabs on child pages.
|
||||
*/
|
||||
'tabsHideOnSubPages'?: boolean;
|
||||
}
|
||||
|
||||
interface IonTabbar {
|
||||
interface IonTabBar {
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* If `true`, show the tab highlight bar under the selected tab.
|
||||
*/
|
||||
'highlight': boolean;
|
||||
/**
|
||||
* Set the layout of the text and icon in the tabbar. Available options: `"icon-top"`, `"icon-start"`, `"icon-end"`, `"icon-bottom"`, `"icon-hide"`, `"label-hide"`.
|
||||
* Set the layout of the text and icon in the tabbar.
|
||||
*/
|
||||
'layout': TabbarLayout;
|
||||
/**
|
||||
@@ -4685,33 +4554,87 @@ export namespace Components {
|
||||
*/
|
||||
'mode': Mode;
|
||||
/**
|
||||
* Set the position of the tabbar, relative to the content. Available options: `"top"`, `"bottom"`.
|
||||
* Set the position of the tabbar, relative to the content.
|
||||
*/
|
||||
'placement': TabbarPlacement;
|
||||
/**
|
||||
* The selected tab component
|
||||
*/
|
||||
'selectedTab'?: HTMLIonTabElement;
|
||||
'selectedTab'?: string;
|
||||
/**
|
||||
* The tabs to render
|
||||
*/
|
||||
'tabs': HTMLIonTabElement[];
|
||||
/**
|
||||
* If `true`, the tabbar will be translucent. Defaults to `false`.
|
||||
* If `true`, the tab bar will be translucent. Defaults to `false`.
|
||||
*/
|
||||
'translucent': boolean;
|
||||
}
|
||||
interface IonTabbarAttributes extends StencilHTMLAttributes {
|
||||
interface IonTabBarAttributes extends StencilHTMLAttributes {
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* If `true`, show the tab highlight bar under the selected tab.
|
||||
* Set the layout of the text and icon in the tabbar.
|
||||
*/
|
||||
'highlight'?: boolean;
|
||||
'layout'?: TabbarLayout;
|
||||
/**
|
||||
* Set the layout of the text and icon in the tabbar. Available options: `"icon-top"`, `"icon-start"`, `"icon-end"`, `"icon-bottom"`, `"icon-hide"`, `"label-hide"`.
|
||||
* The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`.
|
||||
*/
|
||||
'mode'?: Mode;
|
||||
'onIonTabBarChanged'?: (event: CustomEvent<TabbarChangedDetail>) => void;
|
||||
/**
|
||||
* Set the position of the tabbar, relative to the content.
|
||||
*/
|
||||
'placement'?: TabbarPlacement;
|
||||
/**
|
||||
* The selected tab component
|
||||
*/
|
||||
'selectedTab'?: string;
|
||||
/**
|
||||
* If `true`, the tab bar will be translucent. Defaults to `false`.
|
||||
*/
|
||||
'translucent'?: boolean;
|
||||
}
|
||||
|
||||
interface IonTabButton {
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* The selected tab component
|
||||
*/
|
||||
'disabled': boolean;
|
||||
/**
|
||||
* The URL which will be used as the `href` within this tab's button anchor.
|
||||
*/
|
||||
'href'?: string;
|
||||
/**
|
||||
* Set the layout of the text and icon in the tabbar.
|
||||
*/
|
||||
'layout': TabbarLayout;
|
||||
/**
|
||||
* The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`.
|
||||
*/
|
||||
'mode': Mode;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
'tab'?: string;
|
||||
}
|
||||
interface IonTabButtonAttributes extends StencilHTMLAttributes {
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* The selected tab component
|
||||
*/
|
||||
'disabled'?: boolean;
|
||||
/**
|
||||
* The URL which will be used as the `href` within this tab's button anchor.
|
||||
*/
|
||||
'href'?: string;
|
||||
/**
|
||||
* Set the layout of the text and icon in the tabbar.
|
||||
*/
|
||||
'layout'?: TabbarLayout;
|
||||
/**
|
||||
@@ -4721,23 +4644,40 @@ export namespace Components {
|
||||
/**
|
||||
* Emitted when the tab bar is clicked
|
||||
*/
|
||||
'onIonTabbarClick'?: (event: CustomEvent<HTMLIonTabElement>) => void;
|
||||
'onIonTabButtonClick'?: (event: CustomEvent<TabbarClickDetail>) => void;
|
||||
/**
|
||||
* Set the position of the tabbar, relative to the content. Available options: `"top"`, `"bottom"`.
|
||||
* 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.
|
||||
*/
|
||||
'placement'?: TabbarPlacement;
|
||||
'tab'?: string;
|
||||
}
|
||||
|
||||
interface IonTab {
|
||||
'active': boolean;
|
||||
/**
|
||||
* The selected tab component
|
||||
* The component to display inside of the tab.
|
||||
*/
|
||||
'selectedTab'?: HTMLIonTabElement;
|
||||
'component'?: ComponentRef;
|
||||
'delegate'?: FrameworkDelegate;
|
||||
/**
|
||||
* The tabs to render
|
||||
* Set the active component for the tab
|
||||
*/
|
||||
'tabs'?: HTMLIonTabElement[];
|
||||
'setActive': () => Promise<void>;
|
||||
/**
|
||||
* If `true`, the tabbar will be translucent. Defaults to `false`.
|
||||
* 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.
|
||||
*/
|
||||
'translucent'?: boolean;
|
||||
'tab'?: string;
|
||||
}
|
||||
interface IonTabAttributes extends StencilHTMLAttributes {
|
||||
'active'?: boolean;
|
||||
/**
|
||||
* The component to display inside of the tab.
|
||||
*/
|
||||
'component'?: ComponentRef;
|
||||
'delegate'?: FrameworkDelegate;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
'tab'?: string;
|
||||
}
|
||||
|
||||
interface IonTabs {
|
||||
@@ -4749,7 +4689,7 @@ export namespace Components {
|
||||
/**
|
||||
* Get the tab at the given index
|
||||
*/
|
||||
'getTab': (tabOrIndex: string | number | HTMLIonTabElement) => Promise<HTMLIonTabElement | undefined>;
|
||||
'getTab': (tab: string | HTMLIonTabElement) => Promise<HTMLIonTabElement | undefined>;
|
||||
/**
|
||||
* A unique name for the tabs.
|
||||
*/
|
||||
@@ -4757,16 +4697,8 @@ export namespace Components {
|
||||
/**
|
||||
* Index or the Tab instance, of the tab to select.
|
||||
*/
|
||||
'select': (tabOrIndex: number | HTMLIonTabElement) => Promise<boolean>;
|
||||
'select': (tab: string | HTMLIonTabElement) => Promise<boolean>;
|
||||
'setRouteId': (id: string) => Promise<RouteWrite>;
|
||||
/**
|
||||
* If `true`, the tabbar will be hidden. Defaults to `false`.
|
||||
*/
|
||||
'tabbarHidden': boolean;
|
||||
/**
|
||||
* If `true`, the tabs will use the router and `selectedTab` will not do anything.
|
||||
*/
|
||||
'useRouter': boolean;
|
||||
}
|
||||
interface IonTabsAttributes extends StencilHTMLAttributes {
|
||||
/**
|
||||
@@ -4789,14 +4721,6 @@ export namespace Components {
|
||||
* Emitted when the navigation will load a component.
|
||||
*/
|
||||
'onIonNavWillLoad'?: (event: CustomEvent<void>) => void;
|
||||
/**
|
||||
* If `true`, the tabbar will be hidden. Defaults to `false`.
|
||||
*/
|
||||
'tabbarHidden'?: boolean;
|
||||
/**
|
||||
* If `true`, the tabs will use the router and `selectedTab` will not do anything.
|
||||
*/
|
||||
'useRouter'?: boolean;
|
||||
}
|
||||
|
||||
interface IonText {
|
||||
@@ -5456,8 +5380,9 @@ declare global {
|
||||
'IonSlides': Components.IonSlides;
|
||||
'IonSpinner': Components.IonSpinner;
|
||||
'IonSplitPane': Components.IonSplitPane;
|
||||
'IonTabBar': Components.IonTabBar;
|
||||
'IonTabButton': Components.IonTabButton;
|
||||
'IonTab': Components.IonTab;
|
||||
'IonTabbar': Components.IonTabbar;
|
||||
'IonTabs': Components.IonTabs;
|
||||
'IonText': Components.IonText;
|
||||
'IonTextarea': Components.IonTextarea;
|
||||
@@ -5559,8 +5484,9 @@ declare global {
|
||||
'ion-slides': Components.IonSlidesAttributes;
|
||||
'ion-spinner': Components.IonSpinnerAttributes;
|
||||
'ion-split-pane': Components.IonSplitPaneAttributes;
|
||||
'ion-tab-bar': Components.IonTabBarAttributes;
|
||||
'ion-tab-button': Components.IonTabButtonAttributes;
|
||||
'ion-tab': Components.IonTabAttributes;
|
||||
'ion-tabbar': Components.IonTabbarAttributes;
|
||||
'ion-tabs': Components.IonTabsAttributes;
|
||||
'ion-text': Components.IonTextAttributes;
|
||||
'ion-textarea': Components.IonTextareaAttributes;
|
||||
@@ -6102,18 +6028,24 @@ declare global {
|
||||
new (): HTMLIonSplitPaneElement;
|
||||
};
|
||||
|
||||
interface HTMLIonTabBarElement extends Components.IonTabBar, HTMLStencilElement {}
|
||||
var HTMLIonTabBarElement: {
|
||||
prototype: HTMLIonTabBarElement;
|
||||
new (): HTMLIonTabBarElement;
|
||||
};
|
||||
|
||||
interface HTMLIonTabButtonElement extends Components.IonTabButton, HTMLStencilElement {}
|
||||
var HTMLIonTabButtonElement: {
|
||||
prototype: HTMLIonTabButtonElement;
|
||||
new (): HTMLIonTabButtonElement;
|
||||
};
|
||||
|
||||
interface HTMLIonTabElement extends Components.IonTab, HTMLStencilElement {}
|
||||
var HTMLIonTabElement: {
|
||||
prototype: HTMLIonTabElement;
|
||||
new (): HTMLIonTabElement;
|
||||
};
|
||||
|
||||
interface HTMLIonTabbarElement extends Components.IonTabbar, HTMLStencilElement {}
|
||||
var HTMLIonTabbarElement: {
|
||||
prototype: HTMLIonTabbarElement;
|
||||
new (): HTMLIonTabbarElement;
|
||||
};
|
||||
|
||||
interface HTMLIonTabsElement extends Components.IonTabs, HTMLStencilElement {}
|
||||
var HTMLIonTabsElement: {
|
||||
prototype: HTMLIonTabsElement;
|
||||
@@ -6263,8 +6195,9 @@ declare global {
|
||||
'ion-slides': HTMLIonSlidesElement
|
||||
'ion-spinner': HTMLIonSpinnerElement
|
||||
'ion-split-pane': HTMLIonSplitPaneElement
|
||||
'ion-tab-bar': HTMLIonTabBarElement
|
||||
'ion-tab-button': HTMLIonTabButtonElement
|
||||
'ion-tab': HTMLIonTabElement
|
||||
'ion-tabbar': HTMLIonTabbarElement
|
||||
'ion-tabs': HTMLIonTabsElement
|
||||
'ion-text': HTMLIonTextElement
|
||||
'ion-textarea': HTMLIonTextareaElement
|
||||
@@ -6366,8 +6299,9 @@ declare global {
|
||||
'ion-slides': HTMLIonSlidesElement;
|
||||
'ion-spinner': HTMLIonSpinnerElement;
|
||||
'ion-split-pane': HTMLIonSplitPaneElement;
|
||||
'ion-tab-bar': HTMLIonTabBarElement;
|
||||
'ion-tab-button': HTMLIonTabButtonElement;
|
||||
'ion-tab': HTMLIonTabElement;
|
||||
'ion-tabbar': HTMLIonTabbarElement;
|
||||
'ion-tabs': HTMLIonTabsElement;
|
||||
'ion-text': HTMLIonTextElement;
|
||||
'ion-textarea': HTMLIonTextareaElement;
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Animation, AnimationBuilder, AnimationController, Config } from '../../
|
||||
|
||||
import { Animator } from './animator';
|
||||
|
||||
/** @hidden */
|
||||
/** @internal */
|
||||
@Component({
|
||||
tag: 'ion-animation-controller'
|
||||
})
|
||||
|
||||
@@ -132,7 +132,6 @@ export class Button implements ComponentInterface {
|
||||
const form = this.el.closest('form');
|
||||
if (form) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
const fakeButton = document.createElement('button');
|
||||
fakeButton.type = this.type;
|
||||
|
||||
@@ -40,7 +40,10 @@ export class ItemDivider implements ComponentInterface {
|
||||
|
||||
hostData() {
|
||||
return {
|
||||
class: createColorClasses(this.color)
|
||||
class: {
|
||||
...createColorClasses(this.color),
|
||||
'item': true,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,10 @@ export class ItemGroup implements ComponentInterface {
|
||||
|
||||
hostData() {
|
||||
return {
|
||||
class: createThemedClasses(this.mode, 'item-group')
|
||||
class: {
|
||||
...createThemedClasses(this.mode, 'item-group'),
|
||||
'item': true,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// iOS Label
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
:host-context(.item) {
|
||||
@include margin($label-ios-margin-top, $label-ios-margin-end, $label-ios-margin-bottom, $label-ios-margin-start);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Material Design Label
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
:host-context(.item) {
|
||||
@include margin($label-md-margin-top, $label-md-margin-end, $label-md-margin-bottom, $label-md-margin-start);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Label
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
:host-context(.item) {
|
||||
/**
|
||||
* @prop --color: Color of the label
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Gesture, GestureDetail, Mode, PickerColumn } from '../../interface';
|
||||
import { hapticSelectionChanged } from '../../utils';
|
||||
import { clamp } from '../../utils/helpers';
|
||||
|
||||
/** @hidden */
|
||||
@Component({
|
||||
tag: 'ion-picker-column'
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Component, ComponentInterface, Method, Prop } from '@stencil/core';
|
||||
import { OverlayController, PickerOptions } from '../../interface';
|
||||
import { createOverlay, dismissOverlay, getOverlay } from '../../utils/overlays';
|
||||
|
||||
/** @hidden */
|
||||
/** @internal */
|
||||
@Component({
|
||||
tag: 'ion-picker-controller'
|
||||
})
|
||||
|
||||
@@ -9,11 +9,11 @@ Router is a component that can take a component, and render it when the Browser
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type |
|
||||
| ---------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| `componentProps` | -- | A key value `{ 'red': true, 'blue': 'white'}` containing props that should be passed to the defined component when rendered. | `undefined \| { [key: string]: any; }` |
|
||||
| `component` | `component` | Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-nav`) when the route matches. The value of this property is not always the tagname of the component to load, in ion-tabs it actually refers to the name of the `ion-tab` to select. | `string` |
|
||||
| `url` | `url` | Relative path that needs to match in order for this route to apply. Accepts paths similar to expressjs so that you can define parameters in the url /foo/:bar where bar would be available in incoming props. | `string` |
|
||||
| Property | Attribute | Description | Type |
|
||||
| ---------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
||||
| `componentProps` | -- | A key value `{ 'red': true, 'blue': 'white'}` containing props that should be passed to the defined component when rendered. | `undefined \| { [key: string]: any; }` |
|
||||
| `component` | `component` | Name of the component to load/select in the navigation outlet (`ion-tabs`, `ion-nav`) when the route matches. The value of this property is not always the tagname of the component to load, in `ion-tabs` it actually refers to the name of the `ion-tab` to select. | `string` |
|
||||
| `url` | `url` | Relative path that needs to match in order for this route to apply. Accepts paths similar to expressjs so that you can define parameters in the url /foo/:bar where bar would be available in incoming props. | `string` |
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
@@ -18,7 +18,7 @@ export class Route implements ComponentInterface {
|
||||
* when the route matches.
|
||||
*
|
||||
* The value of this property is not always the tagname of the component to load,
|
||||
* in ion-tabs it actually refers to the name of the `ion-tab` to select.
|
||||
* in `ion-tabs` it actually refers to the name of the `ion-tab` to select.
|
||||
*/
|
||||
@Prop() component!: string;
|
||||
|
||||
|
||||
@@ -105,26 +105,38 @@
|
||||
class TabsPage extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<ion-tabs>
|
||||
<ion-tab component="tab-one"
|
||||
label="Plain List"
|
||||
icon="star"></ion-tab>
|
||||
<ion-tabs>
|
||||
|
||||
<ion-tab component="tab-two"
|
||||
label="Schedule"
|
||||
icon="globe"></ion-tab>
|
||||
<ion-tab tab="tab-one" component="tab-one"></ion-tab>
|
||||
<ion-tab tab="tab-two" component="tab-two"></ion-tab>
|
||||
<ion-tab tab="tab-three" component="tab-three"></ion-tab>
|
||||
<ion-tab tab="tab-four">
|
||||
inline tab 4
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab name="tab3"
|
||||
label="Stopwatch"
|
||||
icon="logo-facebook"
|
||||
component="tab-three"></ion-tab>
|
||||
<ion-tab-bar>
|
||||
|
||||
<ion-tab name="tab4"
|
||||
label="Messages"
|
||||
icon="chatboxes"
|
||||
name="tab-four">
|
||||
inline tab 4
|
||||
</ion-tab>
|
||||
<ion-tab-button tab="tab-one">
|
||||
<ion-label>Plain List</ion-label>
|
||||
<ion-icon name="star"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab-two">
|
||||
<ion-label>Schedule</ion-label>
|
||||
<ion-icon name="globe"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab-three">
|
||||
<ion-label>Stopwatch</ion-label>
|
||||
<ion-icon name="logo-facebook"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab-four">
|
||||
<ion-label>Messages</ion-label>
|
||||
<ion-icon name="star"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
</ion-tab-bar>
|
||||
</ion-tabs>
|
||||
`;
|
||||
}
|
||||
@@ -194,8 +206,8 @@
|
||||
<ion-route url="/second-page" component="page-two"> </ion-route>
|
||||
<ion-route url="/three/:prop1" component="page-three"> </ion-route>
|
||||
</ion-route>
|
||||
<ion-route url="/three" component="tab3"> </ion-route>
|
||||
<ion-route url="/four" component="tab4"> </ion-route>
|
||||
<ion-route url="/three" component="tab-three"> </ion-route>
|
||||
<ion-route url="/four" component="tab-four"> </ion-route>
|
||||
</ion-route>
|
||||
|
||||
</ion-router>
|
||||
|
||||
42
core/src/components/tab-bar/readme.md
Normal file
42
core/src/components/tab-bar/readme.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# ion-tab-bar
|
||||
|
||||
Tab bar is the UI component that implements the array of button of `ion-tabs`. It's provided by default when `ion-tabs` is used, though, this "implicit" tab bar can not be customized.
|
||||
|
||||
In order to have a custom tabbar, it should be provided in user's markup as direct children of `ion-tabs`:
|
||||
|
||||
```html
|
||||
<style>
|
||||
ion-tab-bar {
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-tabs>
|
||||
<!-- User tabs -->
|
||||
<ion-tab></ion-tab>
|
||||
<ion-tab></ion-tab>
|
||||
|
||||
<!-- User provided ion-tab-bar that can be customized -->
|
||||
<ion-tab-bar color="dark" layout="icon-only">
|
||||
</ion-tabs>
|
||||
```
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type |
|
||||
| ------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| `color` | `color` | 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). | `string \| undefined` |
|
||||
| `layout` | `layout` | Set the layout of the text and icon in the tabbar. | `"icon-bottom" \| "icon-end" \| "icon-hide" \| "icon-start" \| "icon-top" \| "label-hide"` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`. | `"ios" \| "md"` |
|
||||
| `placement` | `placement` | Set the position of the tabbar, relative to the content. | `"bottom" \| "top"` |
|
||||
| `selectedTab` | `selected-tab` | The selected tab component | `string \| undefined` |
|
||||
| `translucent` | `translucent` | If `true`, the tab bar will be translucent. Defaults to `false`. | `boolean` |
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
*Built with [StencilJS](https://stenciljs.com/)*
|
||||
@@ -1,2 +1,11 @@
|
||||
export type TabbarLayout = 'icon-top' | 'icon-start' | 'icon-end' | 'icon-bottom' | 'icon-hide' | 'label-hide';
|
||||
export type TabbarPlacement = 'top' | 'bottom';
|
||||
|
||||
export interface TabbarChangedDetail {
|
||||
tab?: string;
|
||||
}
|
||||
|
||||
export interface TabbarClickDetail {
|
||||
tab?: string;
|
||||
href?: string;
|
||||
}
|
||||
21
core/src/components/tab-bar/tab-bar.ios.scss
Normal file
21
core/src/components/tab-bar/tab-bar.ios.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
@import "./tab-bar";
|
||||
@import "../../themes/ionic.globals.ios";
|
||||
|
||||
// iOS Tabs
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
// default color / background
|
||||
--background: #{$tabbar-ios-background};
|
||||
--border: #{$hairlines-width solid $tabbar-ios-border-color};
|
||||
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
// iOS Translucent Tabbar
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.tabbar-translucent) {
|
||||
background-color: #{current-color(base, .8)};
|
||||
backdrop-filter: saturate(210%) blur(20px);
|
||||
}
|
||||
10
core/src/components/tab-bar/tab-bar.md.scss
Normal file
10
core/src/components/tab-bar/tab-bar.md.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
@import "./tab-bar";
|
||||
@import "../../themes/ionic.globals.md";
|
||||
|
||||
:host {
|
||||
// default color / background
|
||||
--background: #{$tabbar-md-background};
|
||||
--border: #{1px solid $tabbar-md-border-color};
|
||||
|
||||
height: 56px;
|
||||
}
|
||||
51
core/src/components/tab-bar/tab-bar.scss
Normal file
51
core/src/components/tab-bar/tab-bar.scss
Normal file
@@ -0,0 +1,51 @@
|
||||
@import "../../themes/ionic.globals";
|
||||
|
||||
:host {
|
||||
@include padding-horizontal(
|
||||
var(--ion-safe-area-left),
|
||||
var(--ion-safe-area-right)
|
||||
);
|
||||
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
order: 1;
|
||||
|
||||
width: auto;
|
||||
|
||||
background: var(--background);
|
||||
color: var(--color);
|
||||
|
||||
contain: strict;
|
||||
user-select: none;
|
||||
z-index: $z-index-toolbar;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
:host(.ion-color) {
|
||||
--background: #{current-color(base)};
|
||||
}
|
||||
|
||||
:host(.ion-color) ::slotted(ion-tab-button) {
|
||||
--color: #{current-color(contrast, .7)};
|
||||
--color-selected: #{current-color(contrast)};
|
||||
--background-focused: #{current-color(shade)};
|
||||
}
|
||||
|
||||
:host(.placement-top) {
|
||||
order: -1;
|
||||
|
||||
border-bottom: var(--border);
|
||||
}
|
||||
|
||||
:host(.placement-bottom) {
|
||||
padding-bottom: var(--ion-safe-area-bottom, 0);
|
||||
|
||||
border-top: var(--border);
|
||||
}
|
||||
|
||||
:host(.tabbar-hidden) {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none !important;
|
||||
}
|
||||
101
core/src/components/tab-bar/tab-bar.tsx
Normal file
101
core/src/components/tab-bar/tab-bar.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Prop, QueueApi, State, Watch } from '@stencil/core';
|
||||
|
||||
import { Color, Mode, TabbarChangedDetail, TabbarLayout, TabbarPlacement } from '../../interface';
|
||||
import { createColorClasses } from '../../utils/theme';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-tab-bar',
|
||||
styleUrls: {
|
||||
ios: 'tab-bar.ios.scss',
|
||||
md: 'tab-bar.md.scss'
|
||||
},
|
||||
shadow: true
|
||||
})
|
||||
export class TabBar implements ComponentInterface {
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
@Prop({ context: 'queue' }) queue!: QueueApi;
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
@State() keyboardVisible = false;
|
||||
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
* Possible values are: `"ios"` or `"md"`.
|
||||
*/
|
||||
@Prop() mode!: Mode;
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
@Prop() color?: Color;
|
||||
|
||||
/**
|
||||
* Set the layout of the text and icon in the tabbar.
|
||||
*/
|
||||
@Prop() layout: TabbarLayout = 'icon-top';
|
||||
|
||||
/**
|
||||
* Set the position of the tabbar, relative to the content.
|
||||
*/
|
||||
@Prop() placement: TabbarPlacement = 'bottom';
|
||||
|
||||
/**
|
||||
* The selected tab component
|
||||
*/
|
||||
@Prop() selectedTab?: string;
|
||||
@Watch('selectedTab')
|
||||
selectedTabChanged() {
|
||||
this.ionTabBarChanged.emit({
|
||||
tab: this.selectedTab
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If `true`, the tab bar will be translucent. Defaults to `false`.
|
||||
*/
|
||||
@Prop() translucent = false;
|
||||
|
||||
/** @internal */
|
||||
@Event() ionTabBarChanged!: EventEmitter<TabbarChangedDetail>;
|
||||
|
||||
@Listen('body:keyboardWillHide')
|
||||
protected onKeyboardWillHide() {
|
||||
setTimeout(() => this.keyboardVisible = false, 50);
|
||||
}
|
||||
|
||||
@Listen('body:keyboardWillShow')
|
||||
protected onKeyboardWillShow() {
|
||||
if (this.placement === 'bottom') {
|
||||
this.keyboardVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
componentWillLoad() {
|
||||
this.selectedTabChanged();
|
||||
}
|
||||
|
||||
hostData() {
|
||||
const { color, translucent, placement, keyboardVisible } = this;
|
||||
return {
|
||||
role: 'tablist',
|
||||
'aria-hidden': keyboardVisible ? 'true' : null,
|
||||
'slot': 'tabbar',
|
||||
class: {
|
||||
...createColorClasses(color),
|
||||
'tabbar-translucent': translucent,
|
||||
[`placement-${placement}`]: true,
|
||||
'tabbar-hidden': keyboardVisible,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<slot></slot>
|
||||
);
|
||||
}
|
||||
}
|
||||
10
core/src/components/tab-bar/test/scenarios/e2e.ts
Normal file
10
core/src/components/tab-bar/test/scenarios/e2e.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
it('tab-bar: scenarios', async () => {
|
||||
const page = await newE2EPage({
|
||||
url: '/src/components/tab-bar/test/scenarios?ionic:_testing=true'
|
||||
});
|
||||
|
||||
const compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
});
|
||||
194
core/src/components/tab-bar/test/scenarios/index.html
Normal file
194
core/src/components/tab-bar/test/scenarios/index.html
Normal file
@@ -0,0 +1,194 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Tab - Colors</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="../../../../../dist/ionic.js"></script>
|
||||
<link rel="stylesheet" href="../../../../../css/ionic.bundle.css">
|
||||
<link rel="stylesheet" href="../../../../../scripts/testing/styles.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
|
||||
<!-- Default -->
|
||||
<ion-tab-bar selected-tab="1">
|
||||
|
||||
<ion-tab-button tab='1'>
|
||||
<ion-label>Recents</ion-label>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='2'>
|
||||
<ion-label>Favorites</ion-label>
|
||||
<ion-badge>6</ion-badge>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='3'>
|
||||
<ion-label>Settings</ion-label>
|
||||
</ion-tab-button>
|
||||
|
||||
</ion-tab-bar>
|
||||
|
||||
|
||||
<!-- Icons -->
|
||||
<ion-tab-bar color="primary" selected-tab="1">
|
||||
<ion-tab-button tab='1'>
|
||||
<ion-icon name="call"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='2' selected-tab="1">
|
||||
<ion-icon name="heart"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='3'>
|
||||
<ion-icon name="settings"></ion-icon>
|
||||
</ion-tab-button>
|
||||
</ion-tab-bar>
|
||||
|
||||
<!-- Icons on top of text -->
|
||||
<ion-tab-bar color="secondary" selected-tab="1">
|
||||
<ion-tab-button tab='1'>
|
||||
<ion-label>Location</ion-label>
|
||||
<ion-icon name="navigate"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='2'>
|
||||
<ion-badge>6</ion-badge>
|
||||
<ion-icon name="heart"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='3'>
|
||||
<ion-label>Radio</ion-label>
|
||||
<ion-icon name="musical-notes"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
</ion-tab-bar>
|
||||
|
||||
|
||||
<!-- Icons below text -->
|
||||
<ion-tab-bar color="dark" selected-tab="1">
|
||||
|
||||
<ion-tab-button tab='1' layout="icon-bottom">
|
||||
<ion-label>Recents</ion-label>
|
||||
<ion-icon name="call"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='2' layout="icon-top">
|
||||
<ion-badge>6</ion-badge>
|
||||
<ion-label>Favorites</ion-label>
|
||||
<ion-icon name="heart"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='3' layout="icon-bottom">
|
||||
<ion-label>Settings</ion-label>
|
||||
<ion-icon name="settings"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
</ion-tab-bar>
|
||||
|
||||
|
||||
<!-- Icons right of text -->
|
||||
<ion-tab-bar color="danger" selected-tab="1">
|
||||
<ion-tab-button tab='1' layout="icon-end">
|
||||
<ion-label>Recents</ion-label>
|
||||
<ion-icon name="call"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='2' layout="icon-end">
|
||||
<ion-label>Favorites</ion-label>
|
||||
<ion-icon name="heart"></ion-icon>
|
||||
<ion-badge>6</ion-badge>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='3' layout="icon-end">
|
||||
<ion-label>Settings</ion-label>
|
||||
<ion-icon name="settings"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
</ion-tab-bar>
|
||||
|
||||
|
||||
<!-- Icons left of text -->
|
||||
<ion-tab-bar color="light" selected-tab="1">
|
||||
<ion-tab-button tab='1' layout="icon-start">
|
||||
<ion-label>Recents</ion-label>
|
||||
<ion-icon name="call"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='2' layout="icon-start">
|
||||
<ion-label>Favorites</ion-label>
|
||||
<ion-icon name="heart"></ion-icon>
|
||||
<ion-badge color="danger">6</ion-badge>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='3' layout="icon-start">
|
||||
<ion-label>Settings</ion-label>
|
||||
<ion-icon name="settings"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
</ion-tab-bar>
|
||||
|
||||
|
||||
<!-- No icons -->
|
||||
<ion-tab-bar color="primary" selected-tab="1">
|
||||
<ion-tab-button tab='1' layout="icon-hide">
|
||||
<ion-label>Recents</ion-label>
|
||||
<ion-icon name="call"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='2' layout="icon-hide">
|
||||
<ion-label>Favorites</ion-label>
|
||||
<ion-icon name="heart"></ion-icon>
|
||||
<ion-badge color="danger">6</ion-badge>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='3' layout="icon-hide">
|
||||
<ion-label>Settings</ion-label>
|
||||
<ion-icon name="settings"></ion-icon>
|
||||
</ion-tab-button>
|
||||
</ion-tab-bar>
|
||||
|
||||
|
||||
<!-- No label -->
|
||||
<ion-tab-bar color="secondary" selected-tab="1">
|
||||
<ion-tab-button tab='1' layout="label-hide">
|
||||
<ion-label>Recents</ion-label>
|
||||
<ion-icon name="navigate"></ion-icon>
|
||||
<ion-badge>6</ion-badge>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='2' layout="label-hide">
|
||||
<ion-label>Favorites</ion-label>
|
||||
<ion-icon name="heart"></ion-icon>
|
||||
<ion-badge color="danger">6</ion-badge>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='3' layout="label-hide">
|
||||
<ion-label>Settings</ion-label>
|
||||
<ion-icon name="settings"></ion-icon>
|
||||
</ion-tab-button>
|
||||
</ion-tab-bar>
|
||||
|
||||
|
||||
<!-- No overflow text -->
|
||||
<ion-tab-bar color="danger" selected-tab="1">
|
||||
<ion-tab-button tab='1'>
|
||||
<ion-label>Indiana Jones and the Raiders of the Lost Ark</ion-label>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='2'>
|
||||
<ion-label>Indiana Jones and the Temple of Doom</ion-label>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab='3'>
|
||||
<ion-label>Indiana Jones and the Last Crusade</ion-label>
|
||||
</ion-tab-button>
|
||||
</ion-tab-bar>
|
||||
|
||||
</ion-app>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
42
core/src/components/tab-button/readme.md
Normal file
42
core/src/components/tab-button/readme.md
Normal file
@@ -0,0 +1,42 @@
|
||||
# ion-tab-bar
|
||||
|
||||
Tab bar is the UI component that implements the array of button of `ion-tabs`. It's provided by default when `ion-tabs` is used, though, this "implicit" tab bar can not be customized.
|
||||
|
||||
In order to have a custom tab bar, it should be provided in user's markup as direct children of `ion-tabs`:
|
||||
|
||||
```html
|
||||
<style>
|
||||
ion-tab-bar {
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-tabs>
|
||||
<!-- User tabs -->
|
||||
<ion-tab></ion-tab>
|
||||
<ion-tab></ion-tab>
|
||||
|
||||
<!-- User provided ion-tab-bar that can be customized -->
|
||||
<ion-tab-bar color="dark" layout="icon-only">
|
||||
</ion-tabs>
|
||||
```
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type |
|
||||
| ---------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| `color` | `color` | 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). | `string \| undefined` |
|
||||
| `disabled` | `disabled` | The selected tab component | `boolean` |
|
||||
| `href` | `href` | The URL which will be used as the `href` within this tab's button anchor. | `string \| undefined` |
|
||||
| `layout` | `layout` | Set the layout of the text and icon in the tabbar. | `"icon-bottom" \| "icon-end" \| "icon-hide" \| "icon-start" \| "icon-top" \| "label-hide"` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`. | `"ios" \| "md"` |
|
||||
| `tab` | `tab` | 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. | `string \| undefined` |
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
*Built with [StencilJS](https://stenciljs.com/)*
|
||||
72
core/src/components/tab-button/tab-button.ios.scss
Normal file
72
core/src/components/tab-button/tab-button.ios.scss
Normal file
@@ -0,0 +1,72 @@
|
||||
@import "./tab-button";
|
||||
@import "./tab-button.ios.vars";
|
||||
|
||||
:host {
|
||||
--padding-top: #{$tab-button-ios-padding-top};
|
||||
--padding-end: #{$tab-button-ios-padding-end};
|
||||
--padding-bottom: #{$tab-button-ios-padding-bottom};
|
||||
--padding-start: #{$tab-button-ios-padding-start};
|
||||
--color: #{$tab-button-ios-text-color};
|
||||
--color-selected: #{$tabbar-ios-color-activated};
|
||||
--background: transparent;
|
||||
--background-focused: #{$tabbar-ios-background-focused};
|
||||
|
||||
max-width: $tab-button-ios-max-width;
|
||||
|
||||
font-size: $tab-button-ios-font-size;
|
||||
}
|
||||
|
||||
:host(.tab-has-label-only) ::slotted(ion-label) {
|
||||
@include margin(2px, 0);
|
||||
|
||||
font-size: $tab-button-ios-font-size + 2;
|
||||
font-size: 14px;
|
||||
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
::slotted(ion-label) {
|
||||
@include margin(0, null, 1px, null);
|
||||
|
||||
min-height: $tab-button-ios-font-size + 1;
|
||||
}
|
||||
|
||||
::slotted(ion-icon) {
|
||||
@include margin(4px, null, null, null);
|
||||
|
||||
font-size: $tab-button-ios-icon-size;
|
||||
}
|
||||
|
||||
::slotted(ion-icon::before) {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
|
||||
// iOS TabButton Layout
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.tab-layout-icon-end) ::slotted(ion-label),
|
||||
:host(.tab-layout-icon-start) ::slotted(ion-label),
|
||||
:host(.tab-layout-icon-hide) ::slotted(ion-label) {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
|
||||
font-size: 14px;
|
||||
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-end) ::slotted(ion-icon),
|
||||
:host(.tab-layout-icon-start) ::slotted(ion-icon) {
|
||||
min-width: 24px;
|
||||
height: 26px;
|
||||
|
||||
margin-top: 2px;
|
||||
margin-bottom: 1px;
|
||||
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
:host(.tab-layout-label-hide) ::slotted(ion-icon) {
|
||||
@include margin(0);
|
||||
}
|
||||
88
core/src/components/tab-button/tab-button.md.scss
Normal file
88
core/src/components/tab-button/tab-button.md.scss
Normal file
@@ -0,0 +1,88 @@
|
||||
@import "./tab-button";
|
||||
@import "./tab-button.md.vars";
|
||||
|
||||
// Material Design Tab Button
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
--padding-top: #{$tab-button-md-padding-top};
|
||||
--padding-end: #{$tab-button-md-padding-end};
|
||||
--padding-bottom: #{$tab-button-md-padding-bottom};
|
||||
--padding-start: #{$tab-button-md-padding-start};
|
||||
--color: #{$tab-button-md-text-color};
|
||||
--color-selected: #{$tabbar-md-color-activated};
|
||||
--background: transparent;
|
||||
--background-focused: #{$tabbar-md-background-focused};
|
||||
|
||||
max-width: 168px;
|
||||
|
||||
font-size: $tab-button-md-font-size;
|
||||
font-weight: $tab-button-md-font-weight;
|
||||
}
|
||||
|
||||
|
||||
// Material Design Tab Button Text
|
||||
// --------------------------------------------------
|
||||
|
||||
::slotted(ion-label) {
|
||||
@include margin($tab-button-md-text-margin-top, $tab-button-md-text-margin-end, $tab-button-md-text-margin-bottom, $tab-button-md-text-margin-start);
|
||||
@include transform-origin(center, bottom);
|
||||
|
||||
transition: $tab-button-md-text-transition;
|
||||
|
||||
text-transform: $tab-button-md-text-capitalization;
|
||||
}
|
||||
|
||||
::slotted(.tab-selected) ::slotted(ion-label) {
|
||||
transform: #{$tab-button-md-text-transform-active};
|
||||
|
||||
transition: $tab-button-md-text-transition;
|
||||
}
|
||||
|
||||
// Material Design Tab Button Icon
|
||||
// --------------------------------------------------
|
||||
|
||||
::slotted(ion-icon) {
|
||||
@include transform-origin(center, center);
|
||||
|
||||
width: $tab-button-md-icon-size;
|
||||
height: $tab-button-md-icon-size;
|
||||
|
||||
transition: $tab-button-md-icon-transition;
|
||||
|
||||
font-size: $tab-button-md-icon-size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Material Design TabButton Layout
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.tab-layout-icon-top) ::slotted(ion-label) {
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-bottom) ::slotted(ion-label) {
|
||||
margin-top: -2px;
|
||||
// --label-transform: transform-origin(center, top);
|
||||
}
|
||||
|
||||
:host(.tab-selected) ::slotted(ion-label) {
|
||||
transform: #{$tab-button-md-text-transform-active};
|
||||
}
|
||||
|
||||
:host(.tab-selected) ::slotted(ion-icon) {
|
||||
transform: #{$tab-button-md-icon-transform-active};
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-end.tab-selected) ::slotted(ion-icon) {
|
||||
transform: #{$tab-button-md-icon-right-transform-active};
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-bottom.tab-selected) ::slotted(ion-icon) {
|
||||
transform: #{$tab-button-md-icon-bottom-transform-active};
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-start.tab-selected) ::slotted(ion-icon) {
|
||||
transform: #{$tab-button-md-icon-left-transform-active};
|
||||
}
|
||||
169
core/src/components/tab-button/tab-button.scss
Normal file
169
core/src/components/tab-button/tab-button.scss
Normal file
@@ -0,0 +1,169 @@
|
||||
@import "../../themes/ionic.globals";
|
||||
|
||||
:host {
|
||||
--badge-end: 4%;
|
||||
|
||||
flex: 1;
|
||||
|
||||
height: 100%;
|
||||
|
||||
color: var(--color);
|
||||
}
|
||||
|
||||
a {
|
||||
@include text-inherit();
|
||||
@include margin(0);
|
||||
@include padding(
|
||||
var(--padding-top),
|
||||
var(--padding-end),
|
||||
var(--padding-bottom),
|
||||
var(--padding-start),
|
||||
);
|
||||
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
border: 0;
|
||||
|
||||
outline: none;
|
||||
|
||||
background: var(--background);
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
a:focus-visible {
|
||||
background: var(--background-focused);
|
||||
}
|
||||
|
||||
@media (any-hover: hover) {
|
||||
a:hover {
|
||||
color: var(--color-selected);
|
||||
}
|
||||
}
|
||||
|
||||
:host(.tab-selected) {
|
||||
color: var(--color-selected);
|
||||
}
|
||||
|
||||
:host(.tab-hidden) {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:host(.tab-disabled) {
|
||||
pointer-events: none;
|
||||
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
::slotted(ion-label) {
|
||||
order: 0;
|
||||
}
|
||||
|
||||
::slotted(ion-icon) {
|
||||
order: -1;
|
||||
|
||||
height: 1em;
|
||||
}
|
||||
|
||||
::slotted(ion-label),
|
||||
::slotted(ion-icon) {
|
||||
display: block;
|
||||
|
||||
align-self: center;
|
||||
|
||||
min-width: 26px;
|
||||
max-width: 100%;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
:host(.tab-has-label-only) ::slotted(ion-label) {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Tab Badges
|
||||
// --------------------------------------------------
|
||||
|
||||
::slotted(ion-badge) {
|
||||
@include position(null, var(--badge-end), null, null);
|
||||
@include padding(1px, 6px);
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
position: absolute;
|
||||
|
||||
height: auto;
|
||||
|
||||
font-size: 12px;
|
||||
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
|
||||
// Tab Button Layout
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.tab-layout-icon-start) a {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-end) a {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-bottom) a {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-start) a,
|
||||
:host(.tab-layout-icon-end) a,
|
||||
:host(.tab-layout-icon-hide) a,
|
||||
:host(.tab-layout-label-hide) a,
|
||||
:host(.tab-has-icon-only) a,
|
||||
:host(.tab-has-label-only) a {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-hide) ::slotted(ion-icon) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host(.tab-layout-label-hide) ::slotted(ion-label) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-top),
|
||||
:host(.tab-layout-icon-bottom),
|
||||
:host(.tab-layout-icon-only),
|
||||
:host(.tab-layout-label-hide),
|
||||
:host(.tab-has-icon-only) {
|
||||
--badge-end: #{calc(50% - 30px)};
|
||||
}
|
||||
|
||||
:host(.tab-layout-icon-hide),
|
||||
:host(.tab-layout-icon-start),
|
||||
:host(.tab-layout-icon-end),
|
||||
:host(.tab-has-label-only) {
|
||||
--badge-end: #{calc(50% - 50px)};
|
||||
}
|
||||
128
core/src/components/tab-button/tab-button.tsx
Normal file
128
core/src/components/tab-button/tab-button.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Prop, QueueApi, State } from '@stencil/core';
|
||||
|
||||
import { Color, Mode, TabbarClickDetail, TabbarLayout } from '../../interface';
|
||||
import { createColorClasses } from '../../utils/theme';
|
||||
import { TabbarChangedDetail } from '../tab-bar/tab-bar-interface';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-tab-button',
|
||||
styleUrls: {
|
||||
ios: 'tab-button.ios.scss',
|
||||
md: 'tab-button.md.scss'
|
||||
},
|
||||
shadow: true
|
||||
})
|
||||
export class TabButton implements ComponentInterface {
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
@Prop({ context: 'queue' }) queue!: QueueApi;
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
/**
|
||||
* The selected tab component
|
||||
*/
|
||||
@State() selected = false;
|
||||
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
* Possible values are: `"ios"` or `"md"`.
|
||||
*/
|
||||
@Prop() mode!: Mode;
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
@Prop() color?: Color;
|
||||
|
||||
/**
|
||||
* Set the layout of the text and icon in the tabbar.
|
||||
*/
|
||||
@Prop() layout: TabbarLayout = 'icon-top';
|
||||
|
||||
/**
|
||||
* The URL which will be used as the `href` within this tab's button anchor.
|
||||
*/
|
||||
@Prop() href?: string;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@Prop() tab?: string;
|
||||
|
||||
/**
|
||||
* The selected tab component
|
||||
*/
|
||||
@Prop() disabled = false;
|
||||
|
||||
/**
|
||||
* Emitted when the tab bar is clicked
|
||||
* @internal
|
||||
*/
|
||||
@Event() ionTabButtonClick!: EventEmitter<TabbarClickDetail>;
|
||||
|
||||
@Listen('parent:ionTabBarChanged')
|
||||
onTabbarChanged(ev: CustomEvent<TabbarChangedDetail>) {
|
||||
this.selected = this.tab === ev.detail.tab;
|
||||
}
|
||||
|
||||
@Listen('click')
|
||||
onClick(ev: Event) {
|
||||
if (!this.disabled) {
|
||||
this.ionTabButtonClick.emit({
|
||||
tab: this.tab,
|
||||
href: this.href
|
||||
});
|
||||
}
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
componentWillLoad() {
|
||||
if (this.tab === undefined) {
|
||||
console.warn('ion-tab-button needs a tab, so it can be selected');
|
||||
}
|
||||
}
|
||||
|
||||
private get hasLabel() {
|
||||
return !!this.el.querySelector('ion-label');
|
||||
}
|
||||
|
||||
private get hasIcon() {
|
||||
return !!this.el.querySelector('ion-icon');
|
||||
}
|
||||
|
||||
hostData() {
|
||||
const { color, tab, selected, layout, disabled, hasLabel, hasIcon } = this;
|
||||
return {
|
||||
'role': 'tab',
|
||||
'ion-activatable': true,
|
||||
'aria-selected': selected ? 'true' : null,
|
||||
'id': `tab-button-${tab}`,
|
||||
'aria-controls': `tab-view-${tab}`,
|
||||
class: {
|
||||
...createColorClasses(color),
|
||||
|
||||
'tab-selected': selected,
|
||||
'tab-disabled': disabled,
|
||||
'tab-has-label': hasLabel,
|
||||
'tab-has-icon': hasIcon,
|
||||
'tab-has-label-only': hasLabel && !hasIcon,
|
||||
'tab-has-icon-only': hasIcon && !hasLabel,
|
||||
[`tab-layout-${layout}`]: true,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { mode, href } = this;
|
||||
return (
|
||||
<a href={href || '#'}>
|
||||
<slot></slot>
|
||||
{mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -12,30 +12,12 @@ See the [Tabs API Docs](../Tabs/) for more details on configuring Tabs.
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type |
|
||||
| -------------------- | ------------------------ | --------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||
| `active` | `active` | If `true`, sets the tab as the active tab. | `boolean` |
|
||||
| `badgeColor` | `badge-color` | The badge color for the tab button. | `string \| undefined` |
|
||||
| `badge` | `badge` | The badge for the tab. | `string \| undefined` |
|
||||
| `btnId` | `btn-id` | hidden | `string \| undefined` |
|
||||
| `component` | `component` | The component to display inside of the tab. | `Function \| HTMLElement \| null \| string \| undefined` |
|
||||
| `delegate` | -- | hidden | `FrameworkDelegate \| undefined` |
|
||||
| `disabled` | `disabled` | If `true`, the user cannot interact with the tab. Defaults to `false`. | `boolean` |
|
||||
| `href` | `href` | The URL which will be used as the `href` within this tab's button anchor. | `string \| undefined` |
|
||||
| `icon` | `icon` | The icon for the tab. | `string \| undefined` |
|
||||
| `label` | `label` | The label of the tab. | `string \| undefined` |
|
||||
| `name` | `name` | The name of the tab. | `string \| undefined` |
|
||||
| `selected` | `selected` | If `true`, the tab will be selected. Defaults to `false`. | `boolean` |
|
||||
| `show` | `show` | If `true`, the tab button is visible within the tabbar. Defaults to `true`. | `boolean` |
|
||||
| `tabsHideOnSubPages` | `tabs-hide-on-sub-pages` | If `true`, hide the tabs on child pages. | `boolean` |
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Detail | Description |
|
||||
| --------------- | ------ | ---------------------------------------------------- |
|
||||
| `ionSelect` | | Emitted when the current tab is selected. |
|
||||
| `ionTabMutated` | | Emitted when the tab props mutates. Used internally. |
|
||||
| Property | Attribute | Description | Type |
|
||||
| ----------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||
| `active` | `active` | | `boolean` |
|
||||
| `component` | `component` | The component to display inside of the tab. | `Function \| HTMLElement \| null \| string \| undefined` |
|
||||
| `delegate` | -- | | `FrameworkDelegate \| undefined` |
|
||||
| `tab` | `tab` | 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. | `string \| undefined` |
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Build, Component, ComponentInterface, Element, Event, EventEmitter, Method, Prop, Watch } from '@stencil/core';
|
||||
import { Build, Component, ComponentInterface, Element, Method, Prop } from '@stencil/core';
|
||||
|
||||
import { Color, ComponentRef, FrameworkDelegate } from '../../interface';
|
||||
import { ComponentRef, FrameworkDelegate } from '../../interface';
|
||||
import { attachComponent } from '../../utils/framework-delegate';
|
||||
|
||||
@Component({
|
||||
@@ -13,94 +13,24 @@ export class Tab implements ComponentInterface {
|
||||
private loaded = false;
|
||||
@Element() el!: HTMLIonTabElement;
|
||||
|
||||
/**
|
||||
* If `true`, sets the tab as the active tab.
|
||||
*/
|
||||
/** @internal */
|
||||
@Prop({ mutable: true }) active = false;
|
||||
|
||||
/** hidden */
|
||||
@Prop() btnId?: string;
|
||||
|
||||
/** hidden */
|
||||
/** @internal */
|
||||
@Prop() delegate?: FrameworkDelegate;
|
||||
|
||||
/**
|
||||
* The label of the tab.
|
||||
* 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.
|
||||
*/
|
||||
@Prop() label?: string;
|
||||
|
||||
/**
|
||||
* The URL which will be used as the `href` within this tab's button anchor.
|
||||
*/
|
||||
@Prop() href?: string;
|
||||
|
||||
/**
|
||||
* The icon for the tab.
|
||||
*/
|
||||
@Prop() icon?: string;
|
||||
|
||||
/**
|
||||
* The badge for the tab.
|
||||
*/
|
||||
@Prop() badge?: string;
|
||||
|
||||
/**
|
||||
* The badge color for the tab button.
|
||||
*/
|
||||
@Prop() badgeColor?: Color;
|
||||
@Prop() tab?: string;
|
||||
|
||||
/**
|
||||
* The component to display inside of the tab.
|
||||
*/
|
||||
@Prop() component?: ComponentRef;
|
||||
|
||||
/**
|
||||
* The name of the tab.
|
||||
*/
|
||||
@Prop({ mutable: true }) name?: string;
|
||||
|
||||
/**
|
||||
* If `true`, the user cannot interact with the tab. Defaults to `false`.
|
||||
*/
|
||||
@Prop() disabled = false;
|
||||
|
||||
/**
|
||||
* If `true`, the tab will be selected. Defaults to `false`.
|
||||
*/
|
||||
@Prop() selected = false;
|
||||
|
||||
@Watch('selected')
|
||||
selectedChanged(selected: boolean) {
|
||||
if (selected) {
|
||||
this.ionSelect.emit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If `true`, the tab button is visible within the tabbar. Defaults to `true`.
|
||||
*/
|
||||
@Prop() show = true;
|
||||
|
||||
/**
|
||||
* If `true`, hide the tabs on child pages.
|
||||
*/
|
||||
@Prop() tabsHideOnSubPages = false;
|
||||
|
||||
/**
|
||||
* Emitted when the current tab is selected.
|
||||
*/
|
||||
@Event() ionSelect!: EventEmitter<void>;
|
||||
|
||||
/**
|
||||
* Emitted when the tab props mutates. Used internally.
|
||||
*/
|
||||
@Event() ionTabMutated!: EventEmitter<void>;
|
||||
|
||||
componentWillLoad() {
|
||||
// Set default name
|
||||
if (this.name === undefined && typeof this.component === 'string') {
|
||||
this.name = this.component;
|
||||
}
|
||||
|
||||
if (Build.isDev) {
|
||||
if (this.component !== undefined && this.el.childElementCount > 0) {
|
||||
@@ -109,18 +39,12 @@ export class Tab implements ComponentInterface {
|
||||
` or` +
|
||||
`- Remove the embedded content inside the ion-tab: <ion-tab></ion-tab>`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Watch('label')
|
||||
@Watch('href')
|
||||
@Watch('show')
|
||||
@Watch('disabled')
|
||||
@Watch('badge')
|
||||
@Watch('badgeColor')
|
||||
@Watch('icon')
|
||||
onPropChanged() {
|
||||
this.ionTabMutated.emit();
|
||||
if (this.tab === undefined) {
|
||||
console.error(`Tab views need to have an unique id attribute:
|
||||
<ion-tab tab="my-unique-id">`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Set the active component for the tab */
|
||||
@@ -139,11 +63,12 @@ export class Tab implements ComponentInterface {
|
||||
}
|
||||
|
||||
hostData() {
|
||||
const { btnId, active, component } = this;
|
||||
const { tab, active, component } = this;
|
||||
return {
|
||||
'aria-labelledby': btnId,
|
||||
'aria-hidden': !active ? 'true' : null,
|
||||
'role': 'tabpanel',
|
||||
'aria-hidden': !active ? 'true' : null,
|
||||
'aria-labelledby': `tab-button-${tab}`,
|
||||
'id': `tab-view-${tab}`,
|
||||
'class': {
|
||||
'ion-page': component === undefined,
|
||||
'tab-hidden': !active
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
# ion-tabbar
|
||||
|
||||
Tabbar is the UI component that implements the array of button of `ion-tabs`. It's provided by default when `ion-tabs` is used, though, this "implicit" tabbar can not be customized.
|
||||
|
||||
In order to have a custom tabbar, it should be provided in user's markup as direct children of `ion-tabs`:
|
||||
|
||||
```html
|
||||
<style>
|
||||
ion-tabbar {
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<ion-tabs>
|
||||
<!-- User tabs -->
|
||||
<ion-tab></ion-tab>
|
||||
<ion-tab></ion-tab>
|
||||
|
||||
<!-- User provided ion-tabbar that can be customized -->
|
||||
<ion-tabbar color="dark" layout="icon-only">
|
||||
</ion-tabs>
|
||||
```
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type |
|
||||
| ------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
||||
| `color` | `color` | 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). | `string \| undefined` |
|
||||
| `highlight` | `highlight` | If `true`, show the tab highlight bar under the selected tab. | `boolean` |
|
||||
| `layout` | `layout` | Set the layout of the text and icon in the tabbar. Available options: `"icon-top"`, `"icon-start"`, `"icon-end"`, `"icon-bottom"`, `"icon-hide"`, `"label-hide"`. | `"icon-bottom" \| "icon-end" \| "icon-hide" \| "icon-start" \| "icon-top" \| "label-hide"` |
|
||||
| `mode` | `mode` | The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`. | `"ios" \| "md"` |
|
||||
| `placement` | `placement` | Set the position of the tabbar, relative to the content. Available options: `"top"`, `"bottom"`. | `"bottom" \| "top"` |
|
||||
| `selectedTab` | -- | The selected tab component | `HTMLIonTabElement \| undefined` |
|
||||
| `tabs` | -- | The tabs to render | `HTMLIonTabElement[]` |
|
||||
| `translucent` | `translucent` | If `true`, the tabbar will be translucent. Defaults to `false`. | `boolean` |
|
||||
|
||||
|
||||
## Events
|
||||
|
||||
| Event | Detail | Description |
|
||||
| ---------------- | ----------------- | ----------------------------------- |
|
||||
| `ionTabbarClick` | HTMLIonTabElement | Emitted when the tab bar is clicked |
|
||||
|
||||
|
||||
----------------------------------------------
|
||||
|
||||
*Built with [StencilJS](https://stenciljs.com/)*
|
||||
@@ -1,32 +0,0 @@
|
||||
@import "./tab-button";
|
||||
@import "./tab-button.ios.vars";
|
||||
|
||||
.tab-btn {
|
||||
@include padding($tab-button-ios-padding-top, $tab-button-ios-padding-end, $tab-button-ios-padding-bottom, $tab-button-ios-padding-start);
|
||||
max-width: $tab-button-ios-max-width;
|
||||
}
|
||||
|
||||
.tab-btn-text {
|
||||
@include margin(0, null, 1px, null);
|
||||
|
||||
min-height: $tab-button-ios-font-size + 1;
|
||||
}
|
||||
|
||||
.tab-btn-has-label-only .tab-btn-text {
|
||||
@include margin(2px, 0);
|
||||
|
||||
font-size: $tab-button-ios-font-size + 2;
|
||||
font-size: 14px;
|
||||
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.tab-btn-icon {
|
||||
@include margin(4px, null, null, null);
|
||||
|
||||
font-size: $tab-button-ios-icon-size;
|
||||
}
|
||||
|
||||
.tab-btn-icon::before {
|
||||
vertical-align: top;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
@import "./tab-button";
|
||||
@import "./tab-button.md.vars";
|
||||
|
||||
// Material Design Tab Button
|
||||
// --------------------------------------------------
|
||||
|
||||
.tab-btn {
|
||||
@include padding($tab-button-md-padding-top, $tab-button-md-padding-end, $tab-button-md-padding-bottom, $tab-button-md-padding-start);
|
||||
|
||||
max-width: 168px;
|
||||
}
|
||||
|
||||
// Material Design Tab Button Text
|
||||
// --------------------------------------------------
|
||||
|
||||
.tab-btn-text {
|
||||
@include margin($tab-button-md-text-margin-top, $tab-button-md-text-margin-end, $tab-button-md-text-margin-bottom, $tab-button-md-text-margin-start);
|
||||
@include transform-origin(center, bottom);
|
||||
|
||||
transform: var(--label-transform);
|
||||
|
||||
transition: $tab-button-md-text-transition;
|
||||
|
||||
text-transform: $tab-button-md-text-capitalization;
|
||||
}
|
||||
|
||||
.tab-btn-selected .tab-btn-text {
|
||||
transform: #{$tab-button-md-text-transform-active};
|
||||
|
||||
transition: $tab-button-md-text-transition;
|
||||
}
|
||||
|
||||
// Material Design Tab Button Icon
|
||||
// --------------------------------------------------
|
||||
|
||||
.tab-btn-icon {
|
||||
@include transform-origin(center, center);
|
||||
|
||||
width: $tab-button-md-icon-size;
|
||||
height: $tab-button-md-icon-size;
|
||||
|
||||
transform: var(--icon-transform);
|
||||
|
||||
transition: $tab-button-md-icon-transition;
|
||||
|
||||
font-size: $tab-button-md-icon-size;
|
||||
}
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
@import "../../themes/ionic.globals";
|
||||
|
||||
|
||||
.tab-btn {
|
||||
@include text-inherit();
|
||||
@include margin(0);
|
||||
@include padding(0);
|
||||
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
border: 0;
|
||||
|
||||
outline: none;
|
||||
|
||||
background: transparent;
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
.tab-btn:focus-visible {
|
||||
background: var(--background-focused);
|
||||
}
|
||||
|
||||
@media (any-hover: hover) {
|
||||
.tab-btn:hover {
|
||||
color: var(--color-selected);
|
||||
}
|
||||
}
|
||||
|
||||
.tab-btn-selected {
|
||||
color: var(--color-selected);
|
||||
}
|
||||
|
||||
.tab-btn-hidden {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.tab-btn-disabled {
|
||||
pointer-events: none;
|
||||
|
||||
opacity: .4;
|
||||
}
|
||||
|
||||
.tab-btn-text {
|
||||
@include margin(var(--label-margin-top), null, var(--label-margin-bottom), null);
|
||||
|
||||
display: var(--label-display, block);
|
||||
|
||||
font-size: var(--label-font-size);
|
||||
|
||||
line-height: var(--label-line-height);
|
||||
}
|
||||
|
||||
.tab-btn-icon {
|
||||
@include margin(var(--icon-margin-top), null, var(--icon-margin-bottom), null);
|
||||
|
||||
display: var(--icon-display, block);
|
||||
|
||||
min-width: var(--icon-min-width);
|
||||
height: var(--icon-height, 1em);
|
||||
|
||||
font-size: var(--icon-font-size);
|
||||
}
|
||||
|
||||
.tab-btn-text,
|
||||
.tab-btn-icon {
|
||||
align-self: center;
|
||||
|
||||
min-width: 26px;
|
||||
max-width: 100%;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
|
||||
white-space: nowrap;
|
||||
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.tab-btn-has-label-only .tab-btn-text {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.tab-btn-has-icon-only,
|
||||
.tab-btn-has-label-only {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
// Tab Badges
|
||||
// --------------------------------------------------
|
||||
|
||||
.tab-btn-badge {
|
||||
@include position(6%, 4%, null, null); // 4% fallback
|
||||
@include position(null, calc(50% - 30px), null, null);
|
||||
@include padding(1px, 6px);
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
position: absolute;
|
||||
|
||||
height: auto;
|
||||
|
||||
font-size: 12px;
|
||||
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.tab-btn-has-label-only .tab-btn-badge {
|
||||
@include position-horizontal(null, #{calc(50% - 50px)});
|
||||
}
|
||||
|
||||
.tab-btn-has-icon-only .tab-btn-badge {
|
||||
@include position-horizontal(null, #{calc(50% - 30px)});
|
||||
}
|
||||
|
||||
.tab-btn-selected .tab-btn-icon {
|
||||
transform: var(--icon-transform-selected);
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
@import "./tabbar";
|
||||
@import "./tabbar.ios.vars";
|
||||
@import "./tab-button.ios";
|
||||
|
||||
// iOS Tabs
|
||||
// --------------------------------------------------
|
||||
|
||||
:host {
|
||||
// default color / background
|
||||
--background: #{$tabbar-ios-background};
|
||||
--color: #{$tab-button-ios-text-color};
|
||||
--color-selected: #{$tabbar-ios-color-activated};
|
||||
--background-focused: #{$tabbar-ios-background-focused};
|
||||
|
||||
justify-content: center;
|
||||
|
||||
height: $tabbar-ios-height;
|
||||
|
||||
border-top: $tabbar-ios-border;
|
||||
|
||||
font-size: $tab-button-ios-font-size;
|
||||
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
:host(.placement-top) {
|
||||
border-top: 0;
|
||||
border-bottom: $tabbar-ios-border;
|
||||
}
|
||||
|
||||
// iOS Translucent Tabbar
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.tabbar-translucent) {
|
||||
background-color: #{current-color(base, .8)};
|
||||
backdrop-filter: $tabbar-ios-translucent-filter;
|
||||
}
|
||||
|
||||
|
||||
// iOS Tabbar Layout
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.layout-icon-end),
|
||||
:host(.layout-icon-start),
|
||||
:host(.layout-icon-hide) {
|
||||
--label-margin-top: 2px;
|
||||
--label-margin-bottom: 2px;
|
||||
--label-font-size: 14px;
|
||||
--label-line-height: 1.1;
|
||||
}
|
||||
|
||||
:host(.layout-icon-end),
|
||||
:host(.layout-icon-start) {
|
||||
--icon-margin-top: 2px;
|
||||
--icon-margin-bottom: 1px;
|
||||
--icon-min-width: 24px;
|
||||
--icon-height: 26px;
|
||||
--icon-font-size: 24px;
|
||||
}
|
||||
|
||||
:host(.layout-label-hide) {
|
||||
--icon-margin: 0;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
@import "../../themes/ionic.globals.ios";
|
||||
|
||||
// iOS Tabs
|
||||
// --------------------------------------------------
|
||||
|
||||
/// @prop - Height of the tabbar
|
||||
$tabbar-ios-height: 50px !default;
|
||||
|
||||
/// @prop - Border on the tabbar (border-top when [tabsPlacement=bottom] and border-bottom when [tabsPlacement=top])
|
||||
$tabbar-ios-border: $hairlines-width solid $tabbar-ios-border-color !default;
|
||||
|
||||
/// @prop - Filter of the translucent tabbar
|
||||
$tabbar-ios-translucent-filter: saturate(210%) blur(20px) !default;
|
||||
@@ -1,42 +0,0 @@
|
||||
@import "./tabbar";
|
||||
@import "./tabbar.md.vars";
|
||||
@import "./tab-button.md";
|
||||
|
||||
:host {
|
||||
// default color / background
|
||||
--color: #{$tab-button-md-text-color};
|
||||
--color-selected: #{$tabbar-md-color-activated};
|
||||
--background: #{$tabbar-md-background};
|
||||
--background-focused: #{$tabbar-md-background-focused};
|
||||
--icon-transform-selected: #{$tab-button-md-icon-transform-active};
|
||||
|
||||
height: $tabbar-md-height;
|
||||
|
||||
border-top: $tabbar-md-border;
|
||||
|
||||
font-size: $tab-button-md-font-size;
|
||||
font-weight: $tab-button-md-font-weight;
|
||||
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
// Material Design Tabbar Layout
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.layout-icon-top) {
|
||||
--label-margin-bottom: -2px;
|
||||
}
|
||||
|
||||
:host(.layout-icon-end) {
|
||||
--icon-transform-selected: #{$tab-button-md-icon-right-transform-active};
|
||||
}
|
||||
|
||||
:host(.layout-icon-bottom) {
|
||||
--label-margin-top: -2px;
|
||||
--label-transform: transform-origin(center, top);
|
||||
--icon-transform-selected: #{$tab-button-md-icon-bottom-transform-active};
|
||||
}
|
||||
|
||||
:host(.layout-icon-start) {
|
||||
--icon-transform-selected: #{$tab-button-md-icon-left-transform-active};
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
@import "../../themes/ionic.globals.md";
|
||||
|
||||
// Material Design Tabs
|
||||
// --------------------------------------------------
|
||||
|
||||
/// @prop - Minimum height of the tabbar
|
||||
$tabbar-md-height: 56px !default;
|
||||
|
||||
/// @prop - Border on the tabbar
|
||||
$tabbar-md-border: 1px solid $tabbar-md-border-color !default;
|
||||
@@ -1,119 +0,0 @@
|
||||
@import "../../themes/ionic.globals";
|
||||
|
||||
:host {
|
||||
@include padding-horizontal(
|
||||
var(--ion-safe-area-left),
|
||||
var(--ion-safe-area-right)
|
||||
);
|
||||
|
||||
display: flex;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
order: 1;
|
||||
|
||||
width: auto;
|
||||
|
||||
background: var(--background);
|
||||
color: var(--color);
|
||||
|
||||
user-select: none;
|
||||
|
||||
z-index: $z-index-toolbar;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
:host(.ion-color) {
|
||||
--background: #{current-color(base)};
|
||||
--color: #{current-color(contrast, .7)};
|
||||
--color-selected: #{current-color(contrast)};
|
||||
}
|
||||
|
||||
:host(.tabbar-hidden) {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:host(.placement-top) {
|
||||
order: -1;
|
||||
}
|
||||
|
||||
:host(.placement-bottom) {
|
||||
padding-bottom: var(--ion-safe-area-bottom, 0);
|
||||
}
|
||||
|
||||
|
||||
// Tab Highlight
|
||||
// --------------------------------------------------
|
||||
|
||||
.tabbar-highlight {
|
||||
@include position(null, null, 0, 0);
|
||||
@include transform-origin(0, 0);
|
||||
|
||||
display: block;
|
||||
position: absolute;
|
||||
|
||||
width: 1px;
|
||||
height: 2px;
|
||||
|
||||
transform: translateZ(0);
|
||||
|
||||
background: currentColor;
|
||||
|
||||
&.animated {
|
||||
transition-duration: 300ms;
|
||||
transition-property: transform;
|
||||
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
will-change: transform;
|
||||
}
|
||||
}
|
||||
|
||||
:host(.placement-top) .tabbar-highlight {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
:host(.placement-bottom) .tabbar-highlight {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
|
||||
// Tab Layout
|
||||
// --------------------------------------------------
|
||||
|
||||
:host(.layout-icon-start) .tab-btn {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
:host(.layout-icon-end) .tab-btn {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
:host(.layout-icon-bottom) .tab-btn {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
:host(.layout-icon-start) .tab-btn,
|
||||
:host(.layout-icon-end) .tab-btn,
|
||||
:host(.layout-icon-hide) .tab-btn,
|
||||
:host(.layout-label-hide) .tab-btn {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
:host(.layout-icon-hide) {
|
||||
--icon-display: none;
|
||||
}
|
||||
|
||||
:host(.layout-label-hide) {
|
||||
--label-display: none;
|
||||
}
|
||||
|
||||
:host(.layout-icon-top) .tab-btn,
|
||||
:host(.layout-icon-bottom) .tab-btn {
|
||||
--badge-end: #{calc(50% - 30px)};
|
||||
}
|
||||
|
||||
:host(.layout-icon-hide) .tab-btn,
|
||||
:host(.layout-icon-start) .tab-btn,
|
||||
:host(.layout-icon-end) .tab-btn {
|
||||
--badge-end: #{calc(50% - 50px)};
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Prop, QueueApi, State, Watch } from '@stencil/core';
|
||||
|
||||
import { Color, Mode, TabbarLayout, TabbarPlacement } from '../../interface';
|
||||
import { createColorClasses } from '../../utils/theme';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-tabbar',
|
||||
styleUrls: {
|
||||
ios: 'tabbar.ios.scss',
|
||||
md: 'tabbar.md.scss'
|
||||
},
|
||||
scoped: true
|
||||
})
|
||||
export class Tabbar implements ComponentInterface {
|
||||
|
||||
/**
|
||||
* The mode determines which platform styles to use.
|
||||
* Possible values are: `"ios"` or `"md"`.
|
||||
*/
|
||||
@Prop() mode!: Mode;
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
@Prop() color?: Color;
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
@Prop({ context: 'queue' }) queue!: QueueApi;
|
||||
@Prop({ context: 'document' }) doc!: Document;
|
||||
|
||||
@State() canScrollLeft = false;
|
||||
@State() canScrollRight = false;
|
||||
@State() keyboardVisible = false;
|
||||
|
||||
/**
|
||||
* Set the layout of the text and icon in the tabbar. Available options: `"icon-top"`, `"icon-start"`, `"icon-end"`, `"icon-bottom"`, `"icon-hide"`, `"label-hide"`.
|
||||
*/
|
||||
@Prop() layout: TabbarLayout = 'icon-top';
|
||||
|
||||
/**
|
||||
* Set the position of the tabbar, relative to the content. Available options: `"top"`, `"bottom"`.
|
||||
*/
|
||||
@Prop() placement: TabbarPlacement = 'bottom';
|
||||
|
||||
/**
|
||||
* The selected tab component
|
||||
*/
|
||||
@Prop() selectedTab?: HTMLIonTabElement;
|
||||
|
||||
/**
|
||||
* The tabs to render
|
||||
*/
|
||||
@Prop() tabs: HTMLIonTabElement[] = [];
|
||||
|
||||
/**
|
||||
* If `true`, show the tab highlight bar under the selected tab.
|
||||
*/
|
||||
@Prop() highlight = false;
|
||||
|
||||
/**
|
||||
* If `true`, the tabbar will be translucent. Defaults to `false`.
|
||||
*/
|
||||
@Prop() translucent = false;
|
||||
|
||||
/**
|
||||
* Emitted when the tab bar is clicked
|
||||
*/
|
||||
@Event() ionTabbarClick!: EventEmitter<HTMLIonTabElement>;
|
||||
|
||||
@Listen('body:keyboardWillHide')
|
||||
protected onKeyboardWillHide() {
|
||||
setTimeout(() => this.keyboardVisible = false, 50);
|
||||
}
|
||||
|
||||
@Listen('body:keyboardWillShow')
|
||||
protected onKeyboardWillShow() {
|
||||
if (this.placement === 'bottom') {
|
||||
this.keyboardVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
componentDidLoad() {
|
||||
this.updateHighlight();
|
||||
}
|
||||
|
||||
@Watch('selectedTab')
|
||||
@Listen('window:resize')
|
||||
private updateHighlight() {
|
||||
if (!this.highlight) {
|
||||
return;
|
||||
}
|
||||
this.queue.read(() => {
|
||||
const btn = this.el.shadowRoot!.querySelector('.tab-btn-selected') as HTMLElement | null;
|
||||
const highlight = this.el.shadowRoot!.querySelector('.tabbar-highlight') as HTMLElement;
|
||||
if (btn && highlight) {
|
||||
highlight.style.transform = `translate3d(${btn.offsetLeft}px,0,0) scaleX(${btn.offsetWidth})`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
hostData() {
|
||||
const { color, translucent, layout, placement, keyboardVisible } = this;
|
||||
return {
|
||||
role: 'tablist',
|
||||
'aria-hidden': keyboardVisible ? 'true' : null,
|
||||
'slot': 'tabbar',
|
||||
class: {
|
||||
...createColorClasses(color),
|
||||
'tabbar-translucent': translucent,
|
||||
[`layout-${layout}`]: true,
|
||||
[`placement-${placement}`]: true,
|
||||
'tabbar-hidden': keyboardVisible,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
renderTabButton(tab: HTMLIonTabElement) {
|
||||
const { icon, label, disabled, badge, badgeColor, href } = tab;
|
||||
const selected = tab === this.selectedTab;
|
||||
const hasLabel = label !== undefined;
|
||||
const hasIcon = icon !== undefined;
|
||||
return (
|
||||
<a
|
||||
role="tab"
|
||||
ion-activatable
|
||||
aria-selected={selected ? 'true' : null}
|
||||
href={href || '#'}
|
||||
class={{
|
||||
'tab-btn': true,
|
||||
'tab-btn-selected': selected,
|
||||
'tab-btn-has-label': hasLabel,
|
||||
'tab-btn-has-icon': hasIcon,
|
||||
'tab-btn-has-label-only': hasLabel && !hasIcon,
|
||||
'tab-btn-has-icon-only': hasIcon && !hasLabel,
|
||||
'tab-btn-has-badge': badge !== undefined,
|
||||
'tab-btn-disabled': disabled,
|
||||
'tab-btn-hidden': !tab.show
|
||||
}}
|
||||
onClick={ev => {
|
||||
if (!tab.disabled) {
|
||||
this.ionTabbarClick.emit(tab);
|
||||
}
|
||||
ev.preventDefault();
|
||||
}}
|
||||
>
|
||||
{icon && <ion-icon class="tab-btn-icon" icon={icon} lazy={false}></ion-icon>}
|
||||
{label && <span class="tab-btn-text">{label}</span>}
|
||||
{badge && <ion-badge class="tab-btn-badge" color={badgeColor}>{badge}</ion-badge>}
|
||||
{this.mode === 'md' && <ion-ripple-effect></ion-ripple-effect>}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
return [
|
||||
this.tabs.map(tab => this.renderTabButton(tab)),
|
||||
this.highlight && <div class="animated tabbar-highlight" />
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -4,23 +4,29 @@ Tabs are a top level navigation component for created multiple stacked navs.
|
||||
The component is a container of individual [Tab](../Tab/) components.
|
||||
|
||||
`ion-tabs` is a styleless component that works as a router outlet in
|
||||
order to handle navigation. When the user does not provide a `ion-tabbar` in their markup, `ion-tabs`, by default provides one. Notice that `ion-tabbar` is the UI component that can be used to switch between tabs.
|
||||
order to handle navigation. When the user does not provide a `ion-tab-bar` in their markup, `ion-tabs`, by default provides one. Notice that `ion-tab-bar` is the UI component that can be used to switch between tabs.
|
||||
|
||||
In order to customize the style of the `ion-tabbar`, it should be included in the user's markup as
|
||||
In order to customize the style of the `ion-tab-bar`, it should be included in the user's markup as
|
||||
direct children of `ion-tabs`, like this:
|
||||
|
||||
```html
|
||||
<style>
|
||||
.my-custom-tabs {
|
||||
font-size: 20px;
|
||||
}
|
||||
</style>
|
||||
<ion-tabs>
|
||||
<ion-tab label="Indiana Jones"></ion-tab>
|
||||
<ion-tab label="Star Wars"></ion-tab>
|
||||
<ion-tab label="Jurassic Park"></ion-tab>
|
||||
<ion-tab tab="home">Home Content</ion-tab>
|
||||
<ion-tab tab="settings">Settings Content</ion-tab>
|
||||
|
||||
<ion-tabbar color="danger" layout="icon-start" placement="top"></ion-tabbar>
|
||||
<ion-tab-bar>
|
||||
|
||||
<ion-tab-button tab="home">
|
||||
<ion-label>Home</ion-label>
|
||||
<ion-icon name="home"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="settings">
|
||||
<ion-label>Settings</ion-label>
|
||||
<ion-icon name="gear"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
</ion-tab-bar>
|
||||
</ion-tabs>
|
||||
```
|
||||
|
||||
@@ -29,11 +35,9 @@ direct children of `ion-tabs`, like this:
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Attribute | Description | Type |
|
||||
| -------------- | --------------- | ------------------------------------------------------------------------------- | --------------------- |
|
||||
| `name` | `name` | A unique name for the tabs. | `string \| undefined` |
|
||||
| `tabbarHidden` | `tabbar-hidden` | If `true`, the tabbar will be hidden. Defaults to `false`. | `boolean` |
|
||||
| `useRouter` | `use-router` | If `true`, the tabs will use the router and `selectedTab` will not do anything. | `boolean` |
|
||||
| Property | Attribute | Description | Type |
|
||||
| -------- | --------- | --------------------------- | --------------------- |
|
||||
| `name` | `name` | A unique name for the tabs. | `string \| undefined` |
|
||||
|
||||
|
||||
## Events
|
||||
@@ -68,15 +72,15 @@ Type: `Promise<HTMLIonTabElement | undefined>`
|
||||
|
||||
|
||||
|
||||
### `getTab(tabOrIndex: string | number | HTMLIonTabElement) => Promise<HTMLIonTabElement | undefined>`
|
||||
### `getTab(tab: string | HTMLIonTabElement) => Promise<HTMLIonTabElement | undefined>`
|
||||
|
||||
Get the tab at the given index
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------------ | --------------------------------------- | ----------- |
|
||||
| `tabOrIndex` | `HTMLIonTabElement \| number \| string` | |
|
||||
| Name | Type | Description |
|
||||
| ----- | ----------------------------- | ----------- |
|
||||
| `tab` | `HTMLIonTabElement \| string` | |
|
||||
|
||||
#### Returns
|
||||
|
||||
@@ -84,15 +88,15 @@ Type: `Promise<HTMLIonTabElement | undefined>`
|
||||
|
||||
|
||||
|
||||
### `select(tabOrIndex: number | HTMLIonTabElement) => Promise<boolean>`
|
||||
### `select(tab: string | HTMLIonTabElement) => Promise<boolean>`
|
||||
|
||||
Index or the Tab instance, of the tab to select.
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------------ | ----------------------------- | ----------- |
|
||||
| `tabOrIndex` | `HTMLIonTabElement \| number` | |
|
||||
| Name | Type | Description |
|
||||
| ----- | ----------------------------- | ----------- |
|
||||
| `tab` | `HTMLIonTabElement \| string` | |
|
||||
|
||||
#### Returns
|
||||
|
||||
|
||||
@@ -22,8 +22,3 @@
|
||||
|
||||
contain: layout size style;
|
||||
}
|
||||
|
||||
:host(.tabbar-hidden) ion-tabbar,
|
||||
:host(.tabbar-hidden)::slotted(ion-tabbar) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Build, Component, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core';
|
||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core';
|
||||
|
||||
import { Config, NavOutlet, RouteID, RouteWrite } from '../../interface';
|
||||
import { Config, NavOutlet, RouteID, RouteWrite, TabbarClickDetail } from '../../interface';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-tabs',
|
||||
@@ -9,11 +9,9 @@ import { Config, NavOutlet, RouteID, RouteWrite } from '../../interface';
|
||||
})
|
||||
export class Tabs implements NavOutlet {
|
||||
|
||||
private ids = -1;
|
||||
private transitioning = false;
|
||||
private tabsId = (++tabIds);
|
||||
private leavingTab?: HTMLIonTabElement;
|
||||
private userTabbarEl?: HTMLIonTabbarElement;
|
||||
private useRouter = false;
|
||||
|
||||
@Element() el!: HTMLStencilElement;
|
||||
|
||||
@@ -28,16 +26,6 @@ export class Tabs implements NavOutlet {
|
||||
*/
|
||||
@Prop() name?: string;
|
||||
|
||||
/**
|
||||
* If `true`, the tabbar will be hidden. Defaults to `false`.
|
||||
*/
|
||||
@Prop() tabbarHidden = false;
|
||||
|
||||
/**
|
||||
* If `true`, the tabs will use the router and `selectedTab` will not do anything.
|
||||
*/
|
||||
@Prop({ mutable: true }) useRouter = false;
|
||||
|
||||
/**
|
||||
* Emitted when the tab changes.
|
||||
*/
|
||||
@@ -59,13 +47,8 @@ export class Tabs implements NavOutlet {
|
||||
@Event() ionNavDidChange!: EventEmitter<void>;
|
||||
|
||||
async componentWillLoad() {
|
||||
if (!this.useRouter) {
|
||||
this.useRouter = !!this.doc.querySelector('ion-router') && !this.el.closest('[no-router]');
|
||||
}
|
||||
this.userTabbarEl = this.el.querySelector('ion-tabbar') || undefined;
|
||||
|
||||
this.initTabs();
|
||||
|
||||
this.useRouter = !!this.doc.querySelector('ion-router') && !this.el.closest('[no-router]');
|
||||
this.tabs = Array.from(this.el.querySelectorAll('ion-tab'));
|
||||
this.ionNavWillLoad.emit();
|
||||
this.componentWillUpdate();
|
||||
}
|
||||
@@ -80,28 +63,23 @@ export class Tabs implements NavOutlet {
|
||||
}
|
||||
|
||||
componentWillUpdate() {
|
||||
const tabbarEl = this.userTabbarEl;
|
||||
if (tabbarEl) {
|
||||
tabbarEl.tabs = this.tabs.slice();
|
||||
tabbarEl.selectedTab = this.selectedTab;
|
||||
const tabbar = this.el.querySelector('ion-tab-bar');
|
||||
if (tabbar) {
|
||||
const tab = this.selectedTab ? this.selectedTab.tab : undefined;
|
||||
tabbar.selectedTab = tab;
|
||||
}
|
||||
}
|
||||
|
||||
@Listen('ionTabMutated')
|
||||
protected onTabMutated() {
|
||||
this.el.forceUpdate();
|
||||
}
|
||||
|
||||
@Listen('ionTabbarClick')
|
||||
protected onTabClicked(ev: CustomEvent<HTMLIonTabElement>) {
|
||||
const selectedTab = ev.detail;
|
||||
const href = selectedTab.href as string | undefined;
|
||||
@Listen('ionTabButtonClick')
|
||||
protected onTabClicked(ev: CustomEvent<TabbarClickDetail>) {
|
||||
const { href, tab } = ev.detail;
|
||||
const selectedTab = this.tabs.find(t => t.tab === tab);
|
||||
if (this.useRouter && href !== undefined) {
|
||||
const router = this.doc.querySelector('ion-router');
|
||||
if (router) {
|
||||
router.push(href);
|
||||
}
|
||||
} else {
|
||||
} else if (selectedTab) {
|
||||
this.select(selectedTab);
|
||||
}
|
||||
}
|
||||
@@ -110,8 +88,8 @@ export class Tabs implements NavOutlet {
|
||||
* Index or the Tab instance, of the tab to select.
|
||||
*/
|
||||
@Method()
|
||||
async select(tabOrIndex: number | HTMLIonTabElement): Promise<boolean> {
|
||||
const selectedTab = await this.getTab(tabOrIndex);
|
||||
async select(tab: string | HTMLIonTabElement): Promise<boolean> {
|
||||
const selectedTab = await this.getTab(tab);
|
||||
if (!this.shouldSwitch(selectedTab)) {
|
||||
return false;
|
||||
}
|
||||
@@ -141,20 +119,21 @@ export class Tabs implements NavOutlet {
|
||||
/** @internal */
|
||||
@Method()
|
||||
async getRouteId(): Promise<RouteID | undefined> {
|
||||
const id = this.selectedTab && this.selectedTab.name;
|
||||
return id !== undefined ? { id, element: this.selectedTab } : undefined;
|
||||
const tabId = this.selectedTab && this.selectedTab.tab;
|
||||
return tabId !== undefined ? { id: tabId, element: this.selectedTab } : undefined;
|
||||
}
|
||||
|
||||
/** Get the tab at the given index */
|
||||
@Method()
|
||||
async getTab(tabOrIndex: string | number | HTMLIonTabElement): Promise<HTMLIonTabElement | undefined> {
|
||||
if (typeof tabOrIndex === 'string') {
|
||||
return this.tabs.find(tab => tab.name === tabOrIndex);
|
||||
async getTab(tab: string | HTMLIonTabElement): Promise<HTMLIonTabElement | undefined> {
|
||||
const tabEl = (typeof tab === 'string')
|
||||
? this.tabs.find(t => t.tab === tab)
|
||||
: tab;
|
||||
|
||||
if (!tabEl) {
|
||||
console.error(`tab with id: "${tabEl}" does not exist`);
|
||||
}
|
||||
if (typeof tabOrIndex === 'number') {
|
||||
return this.tabs[tabOrIndex];
|
||||
}
|
||||
return tabOrIndex;
|
||||
return tabEl;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,47 +144,13 @@ export class Tabs implements NavOutlet {
|
||||
return Promise.resolve(this.selectedTab);
|
||||
}
|
||||
|
||||
private initTabs() {
|
||||
const tabs = this.tabs = Array.from(this.el.querySelectorAll('ion-tab'));
|
||||
tabs.forEach(tab => {
|
||||
const id = `t-${this.tabsId}-${++this.ids}`;
|
||||
tab.btnId = 'tab-' + id;
|
||||
tab.id = 'tabpanel-' + id;
|
||||
});
|
||||
}
|
||||
|
||||
private async initSelect(): Promise<void> {
|
||||
const tabs = this.tabs;
|
||||
// wait for all tabs to be ready
|
||||
await Promise.all(tabs.map(tab => tab.componentOnReady()));
|
||||
if (this.useRouter) {
|
||||
if (Build.isDev) {
|
||||
const tab = tabs.find(t => t.selected);
|
||||
if (tab) {
|
||||
console.warn('When using a router (ion-router) <ion-tab selected="true"> makes no difference' +
|
||||
'Define routes properly the define which tab is selected');
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// find pre-selected tabs
|
||||
const selectedTab = tabs.find(t => t.selected) ||
|
||||
tabs.find(t => t.show && !t.disabled);
|
||||
|
||||
// reset all tabs none is selected
|
||||
for (const tab of tabs) {
|
||||
if (tab !== selectedTab) {
|
||||
tab.selected = false;
|
||||
}
|
||||
}
|
||||
if (selectedTab) {
|
||||
await selectedTab.setActive();
|
||||
}
|
||||
this.selectedTab = selectedTab;
|
||||
if (selectedTab) {
|
||||
selectedTab.selected = true;
|
||||
selectedTab.active = true;
|
||||
}
|
||||
// wait for all tabs to be ready
|
||||
await Promise.all(this.tabs.map(tab => tab.componentOnReady()));
|
||||
await this.select(this.tabs[0]);
|
||||
}
|
||||
|
||||
private setActive(selectedTab: HTMLIonTabElement): Promise<void> {
|
||||
@@ -213,13 +158,6 @@ export class Tabs implements NavOutlet {
|
||||
return Promise.reject('transitioning already happening');
|
||||
}
|
||||
|
||||
// Reset rest of tabs
|
||||
for (const tab of this.tabs) {
|
||||
if (selectedTab !== tab) {
|
||||
tab.selected = false;
|
||||
}
|
||||
}
|
||||
|
||||
this.transitioning = true;
|
||||
this.leavingTab = this.selectedTab;
|
||||
this.selectedTab = selectedTab;
|
||||
@@ -237,7 +175,6 @@ export class Tabs implements NavOutlet {
|
||||
return;
|
||||
}
|
||||
|
||||
selectedTab.selected = true;
|
||||
if (leavingTab !== selectedTab) {
|
||||
if (leavingTab) {
|
||||
leavingTab.active = false;
|
||||
@@ -262,28 +199,12 @@ export class Tabs implements NavOutlet {
|
||||
return selectedTab !== undefined && selectedTab !== leavingTab && !this.transitioning;
|
||||
}
|
||||
|
||||
hostData() {
|
||||
return {
|
||||
class: {
|
||||
'tabbar-hidden': this.tabbarHidden
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return [
|
||||
<div class="tabs-inner">
|
||||
<slot></slot>
|
||||
</div>,
|
||||
<slot name="tabbar">
|
||||
<ion-tabbar
|
||||
tabs={this.tabs.slice()}
|
||||
selectedTab={this.selectedTab}
|
||||
>
|
||||
</ion-tabbar>
|
||||
</slot>
|
||||
<slot name="tabbar"></slot>
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
let tabIds = -1;
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const { register, Page, platforms } = require('../../../../../scripts/e2e');
|
||||
const { getElement, waitAndGetElementById, waitForTransition } = require('../../../../../scripts/e2e/utils');
|
||||
|
||||
class E2ETestPage extends Page {
|
||||
constructor(driver, platform) {
|
||||
super(driver, `http://localhost:3333/src/components/tabs/test/basic?ionic:mode=${platform}`);
|
||||
}
|
||||
}
|
||||
|
||||
platforms.forEach(platform => {
|
||||
describe('tabs/basic', () => {
|
||||
register('should init', driver => {
|
||||
const page = new E2ETestPage(driver, platform);
|
||||
return page.navigate();
|
||||
});
|
||||
|
||||
// register('should check each tab', async (driver, testContext) => {
|
||||
// testContext.timeout(60000);
|
||||
// const page = new E2ETestPage(driver, platform);
|
||||
|
||||
// await waitForTransition(300);
|
||||
|
||||
// const tabTwoButton = await waitAndGetElementById(driver, 'tab-t-0-1');
|
||||
// tabTwoButton.click();
|
||||
// await waitForTransition(600);
|
||||
|
||||
// const tabThreeButton = await waitAndGetElementById(driver, 'tab-t-0-2');
|
||||
// tabThreeButton.click();
|
||||
// await waitForTransition(600);
|
||||
// });
|
||||
});
|
||||
});
|
||||
25
core/src/components/tabs/test/basic/e2e.ts
Normal file
25
core/src/components/tabs/test/basic/e2e.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
it('tab-group: basic', async () => {
|
||||
const page = await newE2EPage({
|
||||
url: '/src/components/tab-group/test/basic?ionic:_testing=true'
|
||||
});
|
||||
|
||||
let compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
|
||||
const button2 = await page.find('.e2eTabTwoButton');
|
||||
await button2.click();
|
||||
compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
|
||||
const button3 = await page.find('.e2eTabThreeButton');
|
||||
await button3.click();
|
||||
compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
|
||||
const button4 = await page.find('.e2eTabFourButton');
|
||||
await button4.click();
|
||||
compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
});
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
<ion-app>
|
||||
<ion-tabs>
|
||||
<ion-tab label="Plain List" icon="star">
|
||||
|
||||
<ion-tab tab="tab-one">
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Tab One</ion-title>
|
||||
@@ -22,13 +23,12 @@
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
<h1>Tab One</h1>
|
||||
|
||||
<ion-button expand="block" onclick="updateBadgeCount()">Update Badge Count</ion-button>
|
||||
<ion-button color="secondary" expand="block" onclick="updateBadgeColor()">Update Badge Color</ion-button>
|
||||
</ion-content>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Schedule" icon="globe" badge="6" badge-color="danger">
|
||||
<ion-tab tab="schedule">
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Tab Two</ion-title>
|
||||
@@ -39,7 +39,7 @@
|
||||
</ion-content>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab id="tabWithBadge" badge="6" badge-color="primary" label="Stopwatch" icon="logo-facebook">
|
||||
<ion-tab tab="tab-three">
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Tab Three</ion-title>
|
||||
@@ -50,7 +50,7 @@
|
||||
</ion-content>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab id="hiddenTab" label="Hidden" icon="alert" show="false">
|
||||
<ion-tab tab="hidden-tab">
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Hidden Tab</ion-title>
|
||||
@@ -61,25 +61,58 @@
|
||||
</ion-content>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab disabled label="Messages" icon="chatboxes" component="page-one">
|
||||
</ion-tab>
|
||||
<ion-tab tab="tab-four" component="page-one"></ion-tab>
|
||||
|
||||
<ion-tabbar></ion-tabbar>
|
||||
<ion-tab-bar>
|
||||
<ion-tab-button href="" tab="tab-one" class="e2eTabOneButton">
|
||||
<ion-label>Plain List</ion-label>
|
||||
<ion-icon name="star"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="schedule" class="e2eTabTwoButton">
|
||||
<ion-label>Schedule</ion-label>
|
||||
<ion-icon name="globe"></ion-icon>
|
||||
<ion-badge color="danger">6</ion-badge>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab-three" class="e2eTabThreeButton" disabled>
|
||||
<ion-label>Stopwatch</ion-label>
|
||||
<ion-icon name="logo-facebook"></ion-icon>
|
||||
<ion-badge color="primary">6</ion-badge>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="hidden-tab" hidden>
|
||||
<ion-label>Hidden</ion-label>
|
||||
<ion-icon name="alert"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab-four" class="e2eTabFourButton">
|
||||
<ion-label>Messages</ion-label>
|
||||
<ion-icon name="chatboxes"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
</ion-tab-bar>
|
||||
</ion-tabs>
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
var tab = document.getElementById('tabWithBadge');
|
||||
|
||||
function updateBadgeCount() {
|
||||
var current = parseInt(tab.badge);
|
||||
tab.badge = ++current;
|
||||
class PageOne extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.innerHTML = `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Page Four</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content padding>
|
||||
Page Four
|
||||
</ion-content>
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('page-one', PageOne);
|
||||
|
||||
function updateBadgeColor() {
|
||||
var current = tab.badgeColor;
|
||||
tab.badgeColor = current === 'primary' ? 'danger' : 'primary';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const { register, Page, platforms } = require('../../../../../scripts/e2e');
|
||||
const { getElement, waitAndGetElementById, waitForTransition } = require('../../../../../scripts/e2e/utils');
|
||||
|
||||
class E2ETestPage extends Page {
|
||||
constructor(driver, platform) {
|
||||
super(driver, `http://localhost:3333/src/components/tabs/test/colors?ionic:mode=${platform}`);
|
||||
}
|
||||
}
|
||||
|
||||
platforms.forEach(platform => {
|
||||
describe('tabs/colors', () => {
|
||||
register('should init', driver => {
|
||||
const page = new E2ETestPage(driver, platform);
|
||||
return page.navigate();
|
||||
});
|
||||
|
||||
// register('should check each tab', async (driver, testContext) => {
|
||||
// testContext.timeout(60000);
|
||||
// const page = new E2ETestPage(driver, platform);
|
||||
|
||||
// await waitForTransition(300);
|
||||
|
||||
// const tabTwoButton = await waitAndGetElementById(driver, 'tab-t-0-1');
|
||||
// tabTwoButton.click();
|
||||
// await waitForTransition(600);
|
||||
|
||||
// const tabThreeButton = await waitAndGetElementById(driver, 'tab-t-0-2');
|
||||
// tabThreeButton.click();
|
||||
// await waitForTransition(600);
|
||||
// });
|
||||
});
|
||||
});
|
||||
@@ -1,114 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Tab - Colors</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">
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../../dist/ionic.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
|
||||
<!-- Default -->
|
||||
<ion-tabs>
|
||||
<ion-tab label="Recents"></ion-tab>
|
||||
<ion-tab label="Favorites" badge="6"></ion-tab>
|
||||
<ion-tab label="Settings"></ion-tab>
|
||||
</ion-tabs>
|
||||
|
||||
|
||||
<!-- Icons -->
|
||||
<ion-tabs selected-index="1">
|
||||
<ion-tab icon="call"></ion-tab>
|
||||
<ion-tab icon="heart"></ion-tab>
|
||||
<ion-tab icon="settings"></ion-tab>
|
||||
<ion-tabbar color="primary"></ion-tabbar>
|
||||
</ion-tabs>
|
||||
|
||||
|
||||
<!-- Icons on top of text -->
|
||||
<ion-tabs selected-index="2">
|
||||
<ion-tab label="Location" icon="navigate"></ion-tab>
|
||||
<ion-tab label="Favorites" badge="6" icon="heart"></ion-tab>
|
||||
<ion-tab label="Radio" icon="musical-notes"></ion-tab>
|
||||
|
||||
<ion-tabbar color="secondary"></ion-tabbar>
|
||||
</ion-tabs>
|
||||
|
||||
|
||||
<!-- Icons below text -->
|
||||
<ion-tabs selected-index="1">
|
||||
<ion-tab label="Recents" icon="call"></ion-tab>
|
||||
<ion-tab label="Favorites" badge="6" icon="heart"></ion-tab>
|
||||
<ion-tab label="Settings" icon="settings"></ion-tab>
|
||||
|
||||
<ion-tabbar layout="icon-bottom" color="dark"></ion-tabbar>
|
||||
</ion-tabs>
|
||||
|
||||
|
||||
<!-- Icons right of text -->
|
||||
<ion-tabs selected-index="0">
|
||||
<ion-tab label="Recents" icon="call"></ion-tab>
|
||||
<ion-tab label="Favorites" badge="6" icon="heart"></ion-tab>
|
||||
<ion-tab label="Settings" icon="settings"></ion-tab>
|
||||
|
||||
<ion-tabbar layout="icon-end" color="danger"></ion-tabbar>
|
||||
</ion-tabs>
|
||||
|
||||
|
||||
<!-- Icons left of text -->
|
||||
<ion-tabs>
|
||||
<ion-tab label="Recents" icon="call"></ion-tab>
|
||||
<ion-tab label="Favorites" badge="6" badge-color="danger" icon="heart"></ion-tab>
|
||||
<ion-tab label="Settings" icon="settings"></ion-tab>
|
||||
|
||||
<ion-tabbar layout="icon-start" color="light"></ion-tabbar>
|
||||
</ion-tabs>
|
||||
|
||||
|
||||
<!-- No icons -->
|
||||
<ion-tabs>
|
||||
<ion-tab label="Recents" icon="call"></ion-tab>
|
||||
<ion-tab label="Favorites" badge="6" badge-color="danger" icon="heart"></ion-tab>
|
||||
<ion-tab label="Settings" icon="settings"></ion-tab>
|
||||
|
||||
<ion-tabbar layout="icon-hide" color="primary"></ion-tabbar>
|
||||
</ion-tabs>
|
||||
|
||||
|
||||
<!-- No label -->
|
||||
<ion-tabs>
|
||||
<ion-tab label="Recents" icon="call"></ion-tab>
|
||||
<ion-tab label="Favorites" badge="6" badge-color="danger" icon="heart"></ion-tab>
|
||||
<ion-tab label="Settings" icon="settings"></ion-tab>
|
||||
|
||||
<ion-tabbar layout="label-hide" color="secondary"></ion-tabbar>
|
||||
</ion-tabs>
|
||||
|
||||
|
||||
<!-- No overflow text -->
|
||||
<ion-tabs>
|
||||
<ion-tab label="Indiana Jones and the Raiders of the Lost Ark"></ion-tab>
|
||||
<ion-tab label="Indiana Jones and the Temple of Doom"></ion-tab>
|
||||
<ion-tab label="Indiana Jones and the Last Crusade"></ion-tab>
|
||||
|
||||
<ion-tabbar color="danger"></ion-tabbar>
|
||||
|
||||
</ion-tabs>
|
||||
|
||||
</ion-app>
|
||||
|
||||
<style>
|
||||
ion-tabs {
|
||||
position: relative;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -252,19 +252,36 @@
|
||||
|
||||
<body>
|
||||
|
||||
<ion-app useRouter='false'>
|
||||
<ion-app>
|
||||
<ion-tabs>
|
||||
<ion-tab label="Plain List" icon="star" path="">
|
||||
<ion-tab tab="plain-list">
|
||||
<ion-nav root="page-one"></ion-nav>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Schedule" icon="globe" path="tab2">
|
||||
<ion-tab tab="schedule">
|
||||
<ion-nav root="page-four"></ion-nav>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Stopwatch" icon="logo-facebook" path="tab3">
|
||||
<ion-tab tab="stopwatch">
|
||||
<ion-nav root="page-seven"></ion-nav>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab-bar>
|
||||
<ion-tab-button tab="plain-list">
|
||||
<ion-label>Plain List</ion-label>
|
||||
<ion-icon name="star"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="schedule">
|
||||
<ion-label>Schedule</ion-label>
|
||||
<ion-icon name="globe"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="stopwatch">
|
||||
<ion-label>Stopwatch</ion-label>
|
||||
<ion-icon name="logo-facebook"></ion-icon>
|
||||
</ion-tab-button>
|
||||
</ion-tab-bar>
|
||||
</ion-tabs>
|
||||
</ion-app>
|
||||
</body>
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const { register, Page, platforms } = require('../../../../../scripts/e2e');
|
||||
const { getElement, waitAndGetElementById, waitForTransition } = require('../../../../../scripts/e2e/utils');
|
||||
|
||||
class E2ETestPage extends Page {
|
||||
constructor(driver, platform) {
|
||||
super(driver, `http://localhost:3333/src/components/tabs/test/placements?ionic:mode=${platform}`);
|
||||
}
|
||||
}
|
||||
|
||||
platforms.forEach(platform => {
|
||||
describe('tabs/placements', () => {
|
||||
register('should init', driver => {
|
||||
const page = new E2ETestPage(driver, platform);
|
||||
return page.navigate();
|
||||
});
|
||||
|
||||
// register('should check each tab', async (driver, testContext) => {
|
||||
// testContext.timeout(60000);
|
||||
// const page = new E2ETestPage(driver, platform);
|
||||
|
||||
// await waitForTransition(300);
|
||||
|
||||
// const tabTwoButton = await waitAndGetElementById(driver, 'tab-t-0-1');
|
||||
// tabTwoButton.click();
|
||||
// await waitForTransition(600);
|
||||
|
||||
// const tabThreeButton = await waitAndGetElementById(driver, 'tab-t-0-2');
|
||||
// tabThreeButton.click();
|
||||
// await waitForTransition(600);
|
||||
// });
|
||||
});
|
||||
});
|
||||
10
core/src/components/tabs/test/placements/e2e.ts
Normal file
10
core/src/components/tabs/test/placements/e2e.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { newE2EPage } from '@stencil/core/testing';
|
||||
|
||||
it('tab-group: placements', async () => {
|
||||
const page = await newE2EPage({
|
||||
url: '/src/components/tab-group/test/placements?ionic:_testing=true'
|
||||
});
|
||||
|
||||
const compare = await page.compareScreenshot();
|
||||
expect(compare).toMatchScreenshot();
|
||||
});
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<ion-app>
|
||||
<ion-tabs>
|
||||
<ion-tab icon="star">
|
||||
<ion-tab tab="star-tab">
|
||||
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab icon="globe">
|
||||
<ion-tab tab="globe-tab">
|
||||
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab icon="logo-facebook">
|
||||
<ion-tab tab="facebook-tab">
|
||||
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
@@ -53,10 +53,23 @@
|
||||
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab disabled icon="chatboxes" component="page-one"></ion-tab>
|
||||
<ion-tab tab="page-one" disabled icon="chatboxes" component="page-one"></ion-tab>
|
||||
|
||||
<ion-tabbar placement="top"></ion-tabbar>
|
||||
<ion-tab-bar placement="top">
|
||||
<ion-tab-button tab="star-tab">
|
||||
<ion-icon name="star"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="globe-tab">
|
||||
<ion-icon name="globe"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="facebook-tab">
|
||||
<ion-icon name="logo-facebook"></ion-icon>
|
||||
</ion-tab-button>
|
||||
</ion-tab-bar>
|
||||
</ion-tabs>
|
||||
|
||||
</ion-app>
|
||||
</body>
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
<ion-app>
|
||||
<ion-tabs>
|
||||
<ion-tab label="Plain List" icon="star" path="">
|
||||
|
||||
<ion-tab tab="tab-one">
|
||||
<ion-header translucent>
|
||||
<ion-toolbar>
|
||||
<ion-title>Tab One</ion-title>
|
||||
@@ -24,10 +24,9 @@
|
||||
<ion-content padding fullscreen>
|
||||
Tab One
|
||||
</ion-content>
|
||||
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Schedule" icon="globe" path="tab2">
|
||||
<ion-tab tab="tab-two">
|
||||
|
||||
<ion-header translucent>
|
||||
<ion-toolbar>
|
||||
@@ -40,7 +39,7 @@
|
||||
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Stopwatch" icon="logo-facebook" path="tab3">
|
||||
<ion-tab tab="tab-three">
|
||||
|
||||
<ion-header translucent>
|
||||
<ion-toolbar>
|
||||
@@ -53,8 +52,29 @@
|
||||
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab disabled label="Messages" icon="chatboxes" component="page-one" path="tab4">
|
||||
</ion-tab>
|
||||
<ion-tab tab="tab-four" component="page-one"></ion-tab>
|
||||
|
||||
<ion-tab-bar>
|
||||
<ion-tab-button tab="tab-one">
|
||||
<ion-label>Plain List</ion-label>
|
||||
<ion-icon name="star"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab-two">
|
||||
<ion-label>Schedule</ion-label>
|
||||
<ion-icon name="globe"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab-three">
|
||||
<ion-label>Stopwatch</ion-label>
|
||||
<ion-icon name="logo-facebook"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab-four">
|
||||
<ion-label>Messages</ion-label>
|
||||
<ion-icon name="chatboxes"></ion-icon>
|
||||
</ion-tab-button>
|
||||
</ion-tab-bar>
|
||||
</ion-tabs>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Tab - Translucent</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../../dist/ionic.js"></script>
|
||||
<script type="text/javascript">
|
||||
window.Ionic.config = { useRouter: true };
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<ion-app>
|
||||
<ion-tabs>
|
||||
<ion-tab label="Today" icon="calendar" path="" root="translucent-page-tab">
|
||||
<ion-route path="" component="translucent-page-tab"></ion-route>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Games" icon="planet" root="page-two">
|
||||
<ion-route path="" component="page-two"></ion-route>
|
||||
<ion-route path="path/to/page/three" component="page-three"></ion-route>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Apps" icon="logo-buffer" root="page-three">
|
||||
<ion-route path="/" component="page-three"></ion-route>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Updates" icon="download" badge="7" badge-style="danger" root="translucent-page-tab">
|
||||
<ion-route component="page-one"></ion-route>
|
||||
<ion-route path="paginaaaa-two" component="page-two"></ion-route>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Search" icon="search">
|
||||
<ion-route path="" component="translucent-page-tab"></ion-route>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tabbar color="primary" translucent></ion-tabbar>
|
||||
</ion-tabs>
|
||||
|
||||
<ion-nav-controller></ion-nav-controller>
|
||||
</ion-app>
|
||||
|
||||
<style>
|
||||
f {
|
||||
display: block;
|
||||
background: blue;
|
||||
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.red {
|
||||
background-color: #ea445a;
|
||||
}
|
||||
|
||||
.green {
|
||||
background-color: #76d672;
|
||||
}
|
||||
|
||||
.blue {
|
||||
background-color: #3478f6;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
background-color: #ffff80;
|
||||
}
|
||||
|
||||
.pink {
|
||||
background-color: #ff6b86;
|
||||
}
|
||||
|
||||
.purple {
|
||||
background-color: #7e34f6;
|
||||
}
|
||||
|
||||
.black {
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.orange {
|
||||
background-color: #f69234;
|
||||
}
|
||||
|
||||
</style>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -15,13 +15,25 @@
|
||||
|
||||
<body>
|
||||
<ion-tabs>
|
||||
<ion-tab label="Tab One" icon="star" path="">
|
||||
<ion-tab tab="tab-one">
|
||||
<div class="div-one" slot="not-initialized">Div One</div>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab label="Tab Two" icon="globe" path="tab2">
|
||||
<ion-tab tab="tab-two">
|
||||
<div class="div-two" slot="not-initialized">Div Two</div>
|
||||
</ion-tab>
|
||||
|
||||
<ion-tab-bar>
|
||||
<ion-tab-button tab="tab-one">
|
||||
<ion-label>Tab One</ion-label>
|
||||
<ion-icon name="star"></ion-icon>
|
||||
</ion-tab-button>
|
||||
|
||||
<ion-tab-button tab="tab-two">
|
||||
<ion-label>Tab Two</ion-label>
|
||||
<ion-icon name="globe"></ion-icon>
|
||||
</ion-tab-button>
|
||||
</ion-tab-bar>
|
||||
</ion-tabs>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -34,7 +34,7 @@ if (config.getBoolean('persistConfig')) {
|
||||
// first see if the mode was set as an attribute on <html>
|
||||
// which could have been set by the user, or by prerendering
|
||||
// otherwise get the mode via config settings, and fallback to md
|
||||
const documentElement = document.documentElement;
|
||||
const documentElement = document.documentElement!;
|
||||
const mode = config.get('mode', documentElement.getAttribute('mode') || (isPlatform(win, 'ios') ? 'ios' : 'md'));
|
||||
Ionic.mode = Context.mode = mode;
|
||||
config.set('mode', mode);
|
||||
|
||||
2
core/src/interface.d.ts
vendored
2
core/src/interface.d.ts
vendored
@@ -18,7 +18,7 @@ export * from './components/content/content-interface';
|
||||
export * from './components/select/select-interface';
|
||||
export * from './components/select-popover/select-popover-interface';
|
||||
export * from './components/spinner/spinner-interface';
|
||||
export * from './components/tabbar/tabbar-interface';
|
||||
export * from './components/tab-bar/tab-bar-interface';
|
||||
export * from './components/toast/toast-interface';
|
||||
export * from './components/virtual-scroll/virtual-scroll-interface';
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export function renderHiddenInput(container: HTMLElement, name: string, value: s
|
||||
if (hasShadowDom(container)) {
|
||||
let input = container.querySelector('input.aux-input') as HTMLInputElement | null;
|
||||
if (!input) {
|
||||
input = container.ownerDocument.createElement('input');
|
||||
input = container.ownerDocument!.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.classList.add('aux-input');
|
||||
container.appendChild(input);
|
||||
|
||||
@@ -21,7 +21,7 @@ export function relocateInput(
|
||||
// before it receives the actual focus event
|
||||
// We hide the focused input (with the visible caret) invisiable by making it scale(0),
|
||||
cloneInputComponent(componentEl, inputEl);
|
||||
const doc = componentEl.ownerDocument;
|
||||
const doc = componentEl.ownerDocument!;
|
||||
const tx = doc.dir === 'rtl' ? 9999 : -9999;
|
||||
inputEl.style.transform = `translate3d(${tx}px,${inputRelativeY}px,0)`;
|
||||
// TODO
|
||||
@@ -33,7 +33,7 @@ export function relocateInput(
|
||||
}
|
||||
|
||||
export function isFocused(input: HTMLInputElement): boolean {
|
||||
return input === input.ownerDocument.activeElement;
|
||||
return input === input.ownerDocument!.activeElement;
|
||||
}
|
||||
|
||||
function removeClone(componentEl: HTMLElement, inputEl: HTMLElement) {
|
||||
@@ -55,7 +55,7 @@ function cloneInputComponent(componentEl: HTMLElement, inputEl: HTMLInputElement
|
||||
// find its parent wrapping component like <ion-input> or <ion-textarea>
|
||||
// then clone the entire component
|
||||
const parentElement = componentEl.parentElement;
|
||||
const doc = componentEl.ownerDocument;
|
||||
const doc = componentEl.ownerDocument!;
|
||||
if (componentEl && parentElement) {
|
||||
// DOM READ
|
||||
const srcTop = componentEl.offsetTop;
|
||||
|
||||
@@ -42,7 +42,7 @@ export const config: Config = {
|
||||
{ components: ['ion-slides', 'ion-slide'] },
|
||||
{ components: ['ion-spinner'] },
|
||||
{ components: ['ion-split-pane'] },
|
||||
{ components: ['ion-tabs', 'ion-tab', 'ion-tabbar'] },
|
||||
{ components: ['ion-tabs', 'ion-tab', 'ion-tab-bar', 'ion-tab-button'] },
|
||||
{ components: ['ion-text'] },
|
||||
{ components: ['ion-toast', 'ion-toast-controller'] },
|
||||
{ components: ['ion-toggle'] },
|
||||
|
||||
Reference in New Issue
Block a user