UNPKG

ionic-angular

Version:

A powerful framework for building mobile and progressive web apps with JavaScript and Angular

334 lines 9.54 kB
import { ContentChildren, Directive, ElementRef, EventEmitter, Input, NgZone, Output, Renderer, forwardRef } from '@angular/core'; import { Ion } from '../ion'; import { isTrueProperty } from '../../util/util'; import { Config } from '../../config/config'; import { Platform } from '../../platform/platform'; const QUERY = { xs: '(min-width: 0px)', sm: '(min-width: 576px)', md: '(min-width: 768px)', lg: '(min-width: 992px)', xl: '(min-width: 1200px)', never: '' }; /** * @hidden */ export class RootNode { } /** * @name SplitPane * * @description * SplitPane is a component that makes it possible to create multi-view layout. * Similar to iPad apps, SplitPane allows UI elements, like Menus, to be * displayed as the viewport increases. * * If the devices screen size is below a certain size, the SplitPane will * collapse and the menu will become hidden again. This is especially useful when * creating an app that will be served over a browser or deployed through the app * store to phones and tablets. * * @usage * To use SplitPane, simply add the component around your root component. * In this example, we'll be using a sidemenu layout, similar to what is * provided from the sidemenu starter template. * * ```html * <ion-split-pane> * <!-- our side menu --> * <ion-menu [content]="content"> * <ion-header> * <ion-toolbar> * <ion-title>Menu</ion-title> * </ion-toolbar> * </ion-header> * </ion-menu> * * <!-- the main content --> * <ion-nav [root]="root" main #content></ion-nav> * </ion-split-pane> * ``` * * Here, SplitPane will look for the element with the `main` attribute and make * that the central component on larger screens. The `main` component can be any * Ionic component (`ion-nav` or `ion-tabs`) except `ion-menu`. * * ### Setting breakpoints * * By default, SplitPane will expand when the screen is larger than 768px. * If you want to customize this, use the `when` input. The `when` input can * accept any valid media query, as it uses `matchMedia()` underneath. * * ``` * <ion-split-pane when="(min-width: 475px)"> * * <!-- our side menu --> * <ion-menu [content]="content"> * .... * </ion-menu> * * <!-- the main content --> * <ion-nav [root]="root" main #content></ion-nav> * </ion-split-pane> * ``` * * SplitPane also provides some predefined media queries that can be used. * * ```html * <!-- could be "xs", "sm", "md", "lg", or "xl" --> * <ion-split-pane when="lg"> * ... * </ion-split-pane> * ``` * * * | Size | Value | Description | * |------|-----------------------|-----------------------------------------------------------------------| * | `xs` | `(min-width: 0px)` | Show the split-pane when the min-width is 0px (meaning, always) | * | `sm` | `(min-width: 576px)` | Show the split-pane when the min-width is 576px | * | `md` | `(min-width: 768px)` | Show the split-pane when the min-width is 768px (default break point) | * | `lg` | `(min-width: 992px)` | Show the split-pane when the min-width is 992px | * | `xl` | `(min-width: 1200px)` | Show the split-pane when the min-width is 1200px | * * You can also pass in boolean values that will trigger SplitPane when the value * or expression evaluates to true. * * * ```html * <ion-split-pane [when]="isLarge"> * ... * </ion-split-pane> * ``` * * ```ts * class MyClass { * public isLarge = false; * constructor(){} * } * ``` * * Or * * ```html * <ion-split-pane [when]="shouldShow()"> * ... * </ion-split-pane> * ``` * * ```ts * class MyClass { * constructor(){} * shouldShow(){ * if(conditionA){ * return true * } else { * return false * } * } * } * ``` * */ export class SplitPane extends Ion { constructor(_zone, _plt, config, elementRef, renderer) { super(config, elementRef, renderer, 'split-pane'); this._zone = _zone; this._plt = _plt; this._init = false; this._visible = false; this._isEnabled = true; this._mediaQuery = QUERY['md']; /** * @hidden */ this.sideContent = null; /** * @hidden */ this.mainContent = null; /** * @output {any} Expression to be called when the split-pane visibility has changed */ this.ionChange = new EventEmitter(); } /** * @hidden */ set _setchildren(query) { const children = this._children = query.filter((child => child !== this)); children.forEach(child => { var isMain = child.initPane(); this._setPaneCSSClass(child.getElementRef(), isMain); }); } /** * @input {string | boolean} When the split-pane should be shown. * Can be a CSS media query expression, or a shortcut expression. * Can also be a boolean expression. */ set when(query) { if (typeof query === 'boolean') { this._mediaQuery = query; } else { const defaultQuery = QUERY[query]; this._mediaQuery = (defaultQuery) ? defaultQuery : query; } this._update(); } get when() { return this._mediaQuery; } /** * @input {boolean} If `false`, the split-pane is disabled, ie. the side pane will * never be displayed. Default `true`. */ set enabled(val) { this._isEnabled = isTrueProperty(val); this._update(); } get enabled() { return this._isEnabled; } /** * @hidden */ _register(node, isMain, callback) { if (this.getElementRef().nativeElement !== node.getElementRef().nativeElement.parentNode) { return false; } this._setPaneCSSClass(node.getElementRef(), isMain); if (callback) { this.ionChange.subscribe(callback); } if (isMain) { if (this.mainContent) { console.error('split pane: main content was already set'); } this.mainContent = node; } return true; } /** * @hidden */ ngAfterViewInit() { this._init = true; this._update(); } /** * @hidden */ _update() { if (!this._init) { return; } // Unlisten this._rmListener && this._rmListener(); this._rmListener = null; // Check if the split-pane is disabled if (!this._isEnabled) { this._setVisible(false); return; } const query = this._mediaQuery; if (typeof query === 'boolean') { this._setVisible(query); return; } if (query && query.length > 0) { // Listen const callback = (query) => this._setVisible(query.matches); const mediaList = this._plt.win().matchMedia(query); mediaList.addListener(callback); this._setVisible(mediaList.matches); this._rmListener = function () { mediaList.removeListener(callback); }; } else { this._setVisible(false); } } /** * @hidden */ _updateChildren() { this.mainContent = null; this.sideContent = null; const visible = this._visible; this._children.forEach(child => child.paneChanged && child.paneChanged(visible)); } /** * @hidden */ _setVisible(visible) { if (this._visible === visible) { return; } this._visible = visible; this.setElementClass('split-pane-visible', visible); this._updateChildren(); this._zone.run(() => { this.ionChange.emit(this); }); } /** * @hidden */ isVisible() { return this._visible; } /** * @hidden */ setElementClass(className, add) { this._renderer.setElementClass(this._elementRef.nativeElement, className, add); } /** * @hidden */ _setPaneCSSClass(elementRef, isMain) { const ele = elementRef.nativeElement; this._renderer.setElementClass(ele, 'split-pane-main', isMain); this._renderer.setElementClass(ele, 'split-pane-side', !isMain); } /** * @hidden */ ngOnDestroy() { (void 0) /* assert */; this._rmListener && this._rmListener(); this._rmListener = null; } /** * @hidden */ initPane() { return true; } } SplitPane.decorators = [ { type: Directive, args: [{ selector: 'ion-split-pane', providers: [{ provide: RootNode, useExisting: forwardRef(() => SplitPane) }] },] }, ]; /** @nocollapse */ SplitPane.ctorParameters = () => [ { type: NgZone, }, { type: Platform, }, { type: Config, }, { type: ElementRef, }, { type: Renderer, }, ]; SplitPane.propDecorators = { '_setchildren': [{ type: ContentChildren, args: [RootNode, { descendants: false },] },], 'when': [{ type: Input },], 'enabled': [{ type: Input },], 'ionChange': [{ type: Output },], }; //# sourceMappingURL=split-pane.js.map