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 {
|
namespace JSXElements {
|
||||||
export interface IonMenuToggleAttributes extends HTMLAttributes {
|
export interface IonMenuToggleAttributes extends HTMLAttributes {
|
||||||
|
autoHide?: boolean;
|
||||||
menu?: string;
|
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({
|
@Component({
|
||||||
tag: 'ion-menu-toggle',
|
tag: 'ion-menu-toggle',
|
||||||
styleUrls: {
|
styleUrl: 'menu-toggle.scss'
|
||||||
ios: 'menu-toggle.ios.scss',
|
|
||||||
md: 'menu-toggle.md.scss'
|
|
||||||
},
|
|
||||||
host: {
|
|
||||||
theme: 'menu-toggle'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
export class MenuToggle {
|
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
|
* 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() menu: string;
|
||||||
|
|
||||||
|
@Prop() autoHide = true;
|
||||||
|
|
||||||
|
componentDidLoad() {
|
||||||
|
this.updateVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
@Listen('child:click')
|
@Listen('child:click')
|
||||||
onClick() {
|
onClick() {
|
||||||
const menuControllerElement = document.querySelector('ion-menu-controller');
|
getMenuController().then(menuCtrl => {
|
||||||
if (!menuControllerElement) {
|
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;
|
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() {
|
render() {
|
||||||
return <slot></slot>;
|
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
|
## Properties
|
||||||
|
|
||||||
|
#### autoHide
|
||||||
|
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
#### menu
|
#### menu
|
||||||
|
|
||||||
string
|
string
|
||||||
@ -16,6 +21,11 @@ Optional property that maps to a Menu's `menuId` prop. Can also be `left` or `ri
|
|||||||
|
|
||||||
## Attributes
|
## Attributes
|
||||||
|
|
||||||
|
#### auto-hide
|
||||||
|
|
||||||
|
boolean
|
||||||
|
|
||||||
|
|
||||||
#### menu
|
#### menu
|
||||||
|
|
||||||
string
|
string
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Component, Element, Event, EventEmitter, EventListenerEnable, Listen, Method, Prop, State, Watch } from '@stencil/core';
|
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';
|
import { Side, assert, checkEdgeSide, isRightSide } from '../../utils/helpers';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -76,8 +76,9 @@ export class Menu {
|
|||||||
@Prop({ mutable: true }) disabled = false;
|
@Prop({ mutable: true }) disabled = false;
|
||||||
|
|
||||||
@Watch('disabled')
|
@Watch('disabled')
|
||||||
protected enabledChanged() {
|
protected disabledChanged(disabled: boolean) {
|
||||||
this.updateState();
|
this.updateState();
|
||||||
|
this.ionMenuDisable.emit({disabled});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,6 +124,9 @@ export class Menu {
|
|||||||
*/
|
*/
|
||||||
@Event() ionClose: EventEmitter;
|
@Event() ionClose: EventEmitter;
|
||||||
|
|
||||||
|
|
||||||
|
@Event() protected ionMenuDisable: EventEmitter;
|
||||||
|
|
||||||
componentWillLoad() {
|
componentWillLoad() {
|
||||||
return this.lazyMenuCtrl.componentOnReady().then(menu => {
|
return this.lazyMenuCtrl.componentOnReady().then(menu => {
|
||||||
this.menuCtrl = menu as HTMLIonMenuControllerElement;
|
this.menuCtrl = menu as HTMLIonMenuControllerElement;
|
||||||
@ -170,9 +174,9 @@ export class Menu {
|
|||||||
this.contentEl = this.backdropEl = this.menuInnerEl = null;
|
this.contentEl = this.backdropEl = this.menuInnerEl = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listen('body:ionSplitPaneDidChange')
|
@Listen('body:ionSplitPaneVisible')
|
||||||
splitPaneChanged(ev: SplitPaneAlert) {
|
splitPaneChanged(ev: CustomEvent) {
|
||||||
this.isPane = ev.detail.splitPane.isPane(this.el);
|
this.isPane = (ev.target as any).isPane(this.el);
|
||||||
this.updateState();
|
this.updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +134,9 @@ Emitted when the sliding position changes.
|
|||||||
It reports the relative position.
|
It reports the relative position.
|
||||||
|
|
||||||
|
|
||||||
|
#### ionMenuDisable
|
||||||
|
|
||||||
|
|
||||||
#### ionOpen
|
#### ionOpen
|
||||||
|
|
||||||
Emitted when the menu is open.
|
Emitted when the menu is open.
|
||||||
|
@ -156,13 +156,16 @@ Can also be a boolean expression.
|
|||||||
Emitted when the split pane is visible.
|
Emitted when the split pane is visible.
|
||||||
|
|
||||||
|
|
||||||
#### ionSplitPaneDidChange
|
#### ionSplitPaneVisible
|
||||||
|
|
||||||
Expression to be called when the split-pane visibility has changed
|
Expression to be called when the split-pane visibility has changed
|
||||||
|
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
|
#### isPane()
|
||||||
|
|
||||||
|
|
||||||
#### isVisible()
|
#### isVisible()
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ export class SplitPane {
|
|||||||
private rmL: any;
|
private rmL: any;
|
||||||
|
|
||||||
@Element() private el: HTMLElement;
|
@Element() private el: HTMLElement;
|
||||||
@State() private visible = false;
|
@State() visible = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If true, the split pane will be hidden. Defaults to `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'];
|
@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.
|
* Emitted when the split pane is visible.
|
||||||
*/
|
*/
|
||||||
@Event() ionChange: EventEmitter;
|
@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() {
|
componentDidLoad() {
|
||||||
this._styleChildren();
|
this._styleChildren();
|
||||||
this.whenChanged();
|
this.whenChanged();
|
||||||
@ -61,6 +68,58 @@ export class SplitPane {
|
|||||||
this.rmL = null;
|
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() {
|
private _styleChildren() {
|
||||||
const children = this.el.children;
|
const children = this.el.children;
|
||||||
const nu = this.el.childElementCount;
|
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() {
|
hostData() {
|
||||||
return {
|
return {
|
||||||
class: {
|
class: {
|
||||||
@ -153,14 +152,8 @@ export class SplitPane {
|
|||||||
render() {
|
render() {
|
||||||
return <slot></slot>;
|
return <slot></slot>;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SplitPaneAlert {
|
|
||||||
detail: {
|
|
||||||
splitPane: SplitPane
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function setPaneClass(el: HTMLElement, isMain: boolean) {
|
function setPaneClass(el: HTMLElement, isMain: boolean) {
|
||||||
let toAdd;
|
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 { Slides } from './components/slides/slides';
|
||||||
export * from './components/spinner/spinner-configs';
|
export * from './components/spinner/spinner-configs';
|
||||||
export { Spinner } from './components/spinner/spinner';
|
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 { Tab } from './components/tab/tab';
|
||||||
export { TabButton } from './components/tab-button/tab-button';
|
export { TabButton } from './components/tab-button/tab-button';
|
||||||
export { Tabs } from './components/tabs/tabs';
|
export { Tabs } from './components/tabs/tabs';
|
||||||
|
Reference in New Issue
Block a user