mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-22 21:48:42 +08:00
fix(menu-toggle): autohides
This commit is contained in:
1
packages/core/src/components.d.ts
vendored
1
packages/core/src/components.d.ts
vendored
@ -1664,6 +1664,7 @@ declare global {
|
||||
}
|
||||
namespace JSXElements {
|
||||
export interface IonMenuToggleAttributes extends HTMLAttributes {
|
||||
autoHide?: boolean;
|
||||
menu?: string;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,4 @@
|
||||
|
||||
ion-menu-toggle.menu-toggle-hidden {
|
||||
display: none;
|
||||
}
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
menuControllerElement.componentOnReady().then(() => {
|
||||
const menu = menuControllerElement.get(this.menu);
|
||||
if (menu) {
|
||||
menu.toggle();
|
||||
}
|
||||
this.visible = false;
|
||||
});
|
||||
}
|
||||
|
||||
hostData() {
|
||||
const hidden = this.autoHide && !this.visible;
|
||||
return {
|
||||
class: {
|
||||
'menu-toggle-hidden': hidden
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return <slot></slot>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function getMenuController(): Promise<HTMLIonMenuControllerElement> {
|
||||
const menuControllerElement = document.querySelector('ion-menu-controller');
|
||||
if (!menuControllerElement) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
return menuControllerElement.componentOnReady();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -134,6 +134,9 @@ Emitted when the sliding position changes.
|
||||
It reports the relative position.
|
||||
|
||||
|
||||
#### ionMenuDisable
|
||||
|
||||
|
||||
#### ionOpen
|
||||
|
||||
Emitted when the menu is open.
|
||||
|
@ -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()
|
||||
|
||||
|
||||
|
@ -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 <slot></slot>;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface SplitPaneAlert {
|
||||
detail: {
|
||||
splitPane: SplitPane
|
||||
};
|
||||
}
|
||||
|
||||
function setPaneClass(el: HTMLElement, isMain: boolean) {
|
||||
let toAdd;
|
||||
|
2
packages/core/src/index.d.ts
vendored
2
packages/core/src/index.d.ts
vendored
@ -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';
|
||||
|
Reference in New Issue
Block a user