diff --git a/packages/core/src/components.d.ts b/packages/core/src/components.d.ts index ac5efab705..917f392a74 100644 --- a/packages/core/src/components.d.ts +++ b/packages/core/src/components.d.ts @@ -1664,6 +1664,7 @@ declare global { } namespace JSXElements { export interface IonMenuToggleAttributes extends HTMLAttributes { + autoHide?: boolean; menu?: string; } } diff --git a/packages/core/src/components/menu-toggle/menu-toggle.ios.scss b/packages/core/src/components/menu-toggle/menu-toggle.ios.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/core/src/components/menu-toggle/menu-toggle.md.scss b/packages/core/src/components/menu-toggle/menu-toggle.md.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/packages/core/src/components/menu-toggle/menu-toggle.scss b/packages/core/src/components/menu-toggle/menu-toggle.scss new file mode 100644 index 0000000000..c4526a0534 --- /dev/null +++ b/packages/core/src/components/menu-toggle/menu-toggle.scss @@ -0,0 +1,4 @@ + +ion-menu-toggle.menu-toggle-hidden { + display: none; +} diff --git a/packages/core/src/components/menu-toggle/menu-toggle.tsx b/packages/core/src/components/menu-toggle/menu-toggle.tsx index a642c62f66..0f8d806fa7 100644 --- a/packages/core/src/components/menu-toggle/menu-toggle.tsx +++ b/packages/core/src/components/menu-toggle/menu-toggle.tsx @@ -1,38 +1,66 @@ -import { Component, Listen, Prop } from '@stencil/core'; +import { Component, Listen, Prop, State } from '@stencil/core'; @Component({ tag: 'ion-menu-toggle', - styleUrls: { - ios: 'menu-toggle.ios.scss', - md: 'menu-toggle.md.scss' - }, - host: { - theme: 'menu-toggle' - } + styleUrl: 'menu-toggle.scss' }) export class MenuToggle { + @State() visible = false; /** * Optional property that maps to a Menu's `menuId` prop. Can also be `left` or `right` for the menu side. This is used to find the correct menu to toggle */ @Prop() menu: string; + @Prop() autoHide = true; + + componentDidLoad() { + this.updateVisibility(); + } + @Listen('child:click') onClick() { - const menuControllerElement = document.querySelector('ion-menu-controller'); - if (!menuControllerElement) { - return; - } - menuControllerElement.componentOnReady().then(() => { - const menu = menuControllerElement.get(this.menu); - if (menu) { - menu.toggle(); + getMenuController().then(menuCtrl => { + if (menuCtrl) { + return menuCtrl.toggle(this.menu); } + return false; }); } + @Listen('body:ionMenuDisable') + @Listen('body:ionSplitPaneVisible') + updateVisibility() { + getMenuController().then(menuCtrl => { + if (menuCtrl) { + const menu = menuCtrl.get(this.menu); + if (menu && menu.isActive()) { + this.visible = true; + return; + } + } + this.visible = false; + }); + } + + hostData() { + const hidden = this.autoHide && !this.visible; + return { + class: { + 'menu-toggle-hidden': hidden + } + }; + } + render() { return ; } - +} + +function getMenuController(): Promise { + const menuControllerElement = document.querySelector('ion-menu-controller'); + if (!menuControllerElement) { + return Promise.resolve(null); + } + return menuControllerElement.componentOnReady(); } diff --git a/packages/core/src/components/menu-toggle/readme.md b/packages/core/src/components/menu-toggle/readme.md index 64ca295adb..17064e2eba 100644 --- a/packages/core/src/components/menu-toggle/readme.md +++ b/packages/core/src/components/menu-toggle/readme.md @@ -7,6 +7,11 @@ ## Properties +#### autoHide + +boolean + + #### menu string @@ -16,6 +21,11 @@ Optional property that maps to a Menu's `menuId` prop. Can also be `left` or `ri ## Attributes +#### auto-hide + +boolean + + #### menu string diff --git a/packages/core/src/components/menu/menu.tsx b/packages/core/src/components/menu/menu.tsx index cf8e327d76..c0d9e9603d 100644 --- a/packages/core/src/components/menu/menu.tsx +++ b/packages/core/src/components/menu/menu.tsx @@ -1,5 +1,5 @@ import { Component, Element, Event, EventEmitter, EventListenerEnable, Listen, Method, Prop, State, Watch } from '@stencil/core'; -import { Animation, Config, GestureDetail, SplitPaneAlert } from '../../index'; +import { Animation, Config, GestureDetail } from '../../index'; import { Side, assert, checkEdgeSide, isRightSide } from '../../utils/helpers'; @Component({ @@ -76,8 +76,9 @@ export class Menu { @Prop({ mutable: true }) disabled = false; @Watch('disabled') - protected enabledChanged() { + protected disabledChanged(disabled: boolean) { this.updateState(); + this.ionMenuDisable.emit({disabled}); } /** @@ -123,6 +124,9 @@ export class Menu { */ @Event() ionClose: EventEmitter; + + @Event() protected ionMenuDisable: EventEmitter; + componentWillLoad() { return this.lazyMenuCtrl.componentOnReady().then(menu => { this.menuCtrl = menu as HTMLIonMenuControllerElement; @@ -170,9 +174,9 @@ export class Menu { this.contentEl = this.backdropEl = this.menuInnerEl = null; } - @Listen('body:ionSplitPaneDidChange') - splitPaneChanged(ev: SplitPaneAlert) { - this.isPane = ev.detail.splitPane.isPane(this.el); + @Listen('body:ionSplitPaneVisible') + splitPaneChanged(ev: CustomEvent) { + this.isPane = (ev.target as any).isPane(this.el); this.updateState(); } diff --git a/packages/core/src/components/menu/readme.md b/packages/core/src/components/menu/readme.md index 1343d07813..87eb6c7ad4 100644 --- a/packages/core/src/components/menu/readme.md +++ b/packages/core/src/components/menu/readme.md @@ -134,6 +134,9 @@ Emitted when the sliding position changes. It reports the relative position. +#### ionMenuDisable + + #### ionOpen Emitted when the menu is open. diff --git a/packages/core/src/components/split-pane/readme.md b/packages/core/src/components/split-pane/readme.md index 11b903cc74..dfa8545010 100644 --- a/packages/core/src/components/split-pane/readme.md +++ b/packages/core/src/components/split-pane/readme.md @@ -156,13 +156,16 @@ Can also be a boolean expression. Emitted when the split pane is visible. -#### ionSplitPaneDidChange +#### ionSplitPaneVisible Expression to be called when the split-pane visibility has changed ## Methods +#### isPane() + + #### isVisible() diff --git a/packages/core/src/components/split-pane/split-pane.tsx b/packages/core/src/components/split-pane/split-pane.tsx index 21172ee23e..87a8fa3165 100644 --- a/packages/core/src/components/split-pane/split-pane.tsx +++ b/packages/core/src/components/split-pane/split-pane.tsx @@ -27,7 +27,7 @@ export class SplitPane { private rmL: any; @Element() private el: HTMLElement; - @State() private visible = false; + @State() visible = false; /** * If true, the split pane will be hidden. Defaults to `false`. @@ -41,16 +41,23 @@ export class SplitPane { */ @Prop() when: string | boolean = QUERY['md']; - /** - * Expression to be called when the split-pane visibility has changed - */ - @Event() ionSplitPaneDidChange: EventEmitter; - /** * Emitted when the split pane is visible. */ @Event() ionChange: EventEmitter; + /** + * Expression to be called when the split-pane visibility has changed + */ + @Event() protected ionSplitPaneVisible: EventEmitter; + + @Watch('visible') + visibleChanged(visible: boolean) { + const detail = { visible }; + this.ionChange.emit(detail); + this.ionSplitPaneVisible.emit(detail); + } + componentDidLoad() { this._styleChildren(); this.whenChanged(); @@ -61,6 +68,58 @@ export class SplitPane { this.rmL = null; } + @Watch('when') + protected whenChanged() { + this.rmL && this.rmL(); + this.rmL = null; + + // Check if the split-pane is disabled + if (this.disabled) { + this.visible = false; + return; + } + + // When query is a boolean + const query = this.when; + if (typeof query === 'boolean') { + this.visible = query; + return; + } + + // When query is a string, let's find first if it is a shortcut + const defaultQuery = QUERY[query]; + const mediaQuery = (defaultQuery) + ? defaultQuery + : query; + + // Media query is empty or null, we hide it + if (!mediaQuery || mediaQuery.length === 0) { + this.visible = false; + return; + } + + // Listen on media query + const callback = (q: MediaQueryList) => this.visible = q.matches; + const mediaList = window.matchMedia(mediaQuery); + mediaList.addListener(callback); + this.rmL = () => mediaList.removeListener(callback); + this.visible = mediaList.matches; + } + + @Method() + isVisible(): boolean { + return this.visible; + } + + @Method() + isPane(element: HTMLElement): boolean { + if (!this.visible) { + return false; + } + return element.parentElement === this.el + && element.classList.contains(SPLIT_PANE_SIDE); + } + private _styleChildren() { const children = this.el.children; const nu = this.el.childElementCount; @@ -82,66 +141,6 @@ export class SplitPane { } } - @Watch('when') - protected whenChanged() { - this.rmL && this.rmL(); - this.rmL = null; - - // Check if the split-pane is disabled - if (this.disabled) { - this._setVisible(false); - return; - } - - // When query is a boolean - const query = this.when; - if (typeof query === 'boolean') { - this._setVisible(query); - return; - } - - // When query is a string, let's find first if it is a shortcut - const defaultQuery = QUERY[query]; - const mediaQuery = (defaultQuery) - ? defaultQuery - : query; - - // Media query is empty or null, we hide it - if (!mediaQuery || mediaQuery.length === 0) { - this._setVisible(false); - return; - } - - // Listen on media query - const callback = (q: MediaQueryList) => this._setVisible(q.matches); - const mediaList = window.matchMedia(mediaQuery); - mediaList.addListener(callback); - this.rmL = () => mediaList.removeListener(callback); - this._setVisible(mediaList.matches); - } - - private _setVisible(visible: boolean) { - if (this.visible !== visible) { - this.visible = visible; - const detail = { splitPane: this }; - this.ionChange.emit(detail); - this.ionSplitPaneDidChange.emit(detail); - } - } - - @Method() - isVisible(): boolean { - return this.visible; - } - - isPane(element: HTMLElement): boolean { - if (!this.visible) { - return false; - } - return element.parentElement === this.el - && element.classList.contains(SPLIT_PANE_SIDE); - } - hostData() { return { class: { @@ -153,14 +152,8 @@ export class SplitPane { render() { return ; } - } -export interface SplitPaneAlert { - detail: { - splitPane: SplitPane - }; -} function setPaneClass(el: HTMLElement, isMain: boolean) { let toAdd; diff --git a/packages/core/src/index.d.ts b/packages/core/src/index.d.ts index 0de39303d5..3a188265fd 100644 --- a/packages/core/src/index.d.ts +++ b/packages/core/src/index.d.ts @@ -99,7 +99,7 @@ export { Slide } from './components/slide/slide'; export { Slides } from './components/slides/slides'; export * from './components/spinner/spinner-configs'; export { Spinner } from './components/spinner/spinner'; -export { SplitPane, SplitPaneAlert } from './components/split-pane/split-pane'; +export { SplitPane } from './components/split-pane/split-pane'; export { Tab } from './components/tab/tab'; export { TabButton } from './components/tab-button/tab-button'; export { Tabs } from './components/tabs/tabs';