mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-23 05:58:26 +08:00
fix(menu-button): hide menu button when auto hide or split pane (#18702)
- updates menu-button to use the host element - moves menu-toggle logic to a utils file for menu button to share - removes the dependency on menu-toggle - adds an e2e test for an auto-hidden menu button fixes #18666
This commit is contained in:
@ -77,6 +77,13 @@ ion-icon {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Menu Button: Hidden
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
:host(.menu-button-hidden) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
// Menu Button: Disabled
|
// Menu Button: Disabled
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { Component, ComponentInterface, Prop, h } from '@stencil/core';
|
import { Component, ComponentInterface, Host, Listen, Prop, State, h } from '@stencil/core';
|
||||||
|
|
||||||
import { config } from '../../global/config';
|
import { config } from '../../global/config';
|
||||||
import { getIonMode } from '../../global/ionic-global';
|
import { getIonMode } from '../../global/ionic-global';
|
||||||
import { Color } from '../../interface';
|
import { Color } from '../../interface';
|
||||||
import { ButtonInterface } from '../../utils/element-interface';
|
import { ButtonInterface } from '../../utils/element-interface';
|
||||||
import { createColorClasses } from '../../utils/theme';
|
import { createColorClasses } from '../../utils/theme';
|
||||||
|
import { toggleMenu, updateVisibility } from '../menu-toggle/menu-toggle-util';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-menu-button',
|
tag: 'ion-menu-button',
|
||||||
@ -16,6 +17,8 @@ import { createColorClasses } from '../../utils/theme';
|
|||||||
})
|
})
|
||||||
export class MenuButton implements ComponentInterface, ButtonInterface {
|
export class MenuButton implements ComponentInterface, ButtonInterface {
|
||||||
|
|
||||||
|
@State() visible = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The color to use from your application's color palette.
|
* The color to use from your application's color palette.
|
||||||
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
|
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
|
||||||
@ -43,35 +46,51 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
|
|||||||
*/
|
*/
|
||||||
@Prop() type: 'submit' | 'reset' | 'button' = 'button';
|
@Prop() type: 'submit' | 'reset' | 'button' = 'button';
|
||||||
|
|
||||||
hostData() {
|
async componentDidLoad() {
|
||||||
const mode = getIonMode(this);
|
await this.setVisibility();
|
||||||
const { color, disabled } = this;
|
}
|
||||||
|
|
||||||
return {
|
@Listen('ionMenuChange', { target: 'body' })
|
||||||
'aria-disabled': disabled ? 'true' : null,
|
@Listen('ionSplitPaneVisible', { target: 'body' })
|
||||||
class: {
|
async visibilityChanged() {
|
||||||
...createColorClasses(color),
|
await this.setVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
[mode]: true,
|
private setVisibility = async () => {
|
||||||
|
this.visible = await updateVisibility(this.menu);
|
||||||
|
}
|
||||||
|
|
||||||
'button': true, // ion-buttons target .button
|
private onClick = async () => {
|
||||||
'menu-button-disabled': disabled,
|
await toggleMenu(this.menu);
|
||||||
'ion-activatable': true,
|
|
||||||
'ion-focusable': true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
const { color, disabled } = this;
|
||||||
const mode = getIonMode(this);
|
const mode = getIonMode(this);
|
||||||
const menuIcon = config.get('menuIcon', 'menu');
|
const menuIcon = config.get('menuIcon', 'menu');
|
||||||
|
const hidden = this.autoHide && !this.visible;
|
||||||
|
|
||||||
const attrs = {
|
const attrs = {
|
||||||
type: this.type
|
type: this.type
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ion-menu-toggle menu={this.menu} autoHide={this.autoHide}>
|
<Host
|
||||||
|
onClick={this.onClick}
|
||||||
|
aria-disabled={disabled ? 'true' : null}
|
||||||
|
aria-hidden={hidden ? 'true' : null}
|
||||||
|
class={{
|
||||||
|
[mode]: true,
|
||||||
|
|
||||||
|
...createColorClasses(color),
|
||||||
|
|
||||||
|
'button': true, // ion-buttons target .button
|
||||||
|
'menu-button-hidden': hidden,
|
||||||
|
'menu-button-disabled': disabled,
|
||||||
|
'ion-activatable': true,
|
||||||
|
'ion-focusable': true
|
||||||
|
}}
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
{...attrs}
|
{...attrs}
|
||||||
disabled={this.disabled}
|
disabled={this.disabled}
|
||||||
@ -82,7 +101,7 @@ export class MenuButton implements ComponentInterface, ButtonInterface {
|
|||||||
</slot>
|
</slot>
|
||||||
{mode === 'md' && <ion-ripple-effect type="unbounded"></ion-ripple-effect>}
|
{mode === 'md' && <ion-ripple-effect type="unbounded"></ion-ripple-effect>}
|
||||||
</button>
|
</button>
|
||||||
</ion-menu-toggle>
|
</Host>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,14 +38,12 @@ Menu Button is component that automatically creates the icon and functionality t
|
|||||||
|
|
||||||
### Depends on
|
### Depends on
|
||||||
|
|
||||||
- [ion-menu-toggle](../menu-toggle)
|
|
||||||
- ion-icon
|
- ion-icon
|
||||||
- [ion-ripple-effect](../ripple-effect)
|
- [ion-ripple-effect](../ripple-effect)
|
||||||
|
|
||||||
### Graph
|
### Graph
|
||||||
```mermaid
|
```mermaid
|
||||||
graph TD;
|
graph TD;
|
||||||
ion-menu-button --> ion-menu-toggle
|
|
||||||
ion-menu-button --> ion-icon
|
ion-menu-button --> ion-icon
|
||||||
ion-menu-button --> ion-ripple-effect
|
ion-menu-button --> ion-ripple-effect
|
||||||
style ion-menu-button fill:#f9f,stroke:#333,stroke-width:4px
|
style ion-menu-button fill:#f9f,stroke:#333,stroke-width:4px
|
||||||
|
@ -84,6 +84,13 @@
|
|||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
<ion-title>Success</ion-title>
|
<ion-title>Success</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
|
|
||||||
|
<ion-toolbar color="dark">
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-menu-button></ion-menu-button>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>Hidden</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
</ion-app>
|
</ion-app>
|
||||||
|
|
||||||
@ -92,7 +99,7 @@
|
|||||||
padding-left: 16px;
|
padding-left: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-menu-button {
|
ion-menu-button[auto-hide="false"] {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
core/src/components/menu-toggle/menu-toggle-util.ts
Normal file
32
core/src/components/menu-toggle/menu-toggle-util.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
// Get the menu controller element
|
||||||
|
export const getMenuController = (doc: Document): Promise<HTMLIonMenuControllerElement | undefined> => {
|
||||||
|
const menuControllerElement = doc.querySelector('ion-menu-controller');
|
||||||
|
if (!menuControllerElement) {
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
return menuControllerElement.componentOnReady();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Given a menu, toggle it
|
||||||
|
export const toggleMenu = async (menu: string | undefined) => {
|
||||||
|
const menuCtrl = await getMenuController(document);
|
||||||
|
if (menuCtrl) {
|
||||||
|
const menuEl = await menuCtrl.get(menu);
|
||||||
|
if (menuEl) {
|
||||||
|
menuCtrl.toggle(menu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Given a menu, return whether or not the menu toggle should be visible
|
||||||
|
export const updateVisibility = async (menu: string | undefined) => {
|
||||||
|
const menuCtrl = await getMenuController(document);
|
||||||
|
if (menuCtrl) {
|
||||||
|
const menuEl = await menuCtrl.get(menu);
|
||||||
|
if (menuEl && await menuEl.isActive()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
@ -2,6 +2,8 @@ import { Component, ComponentInterface, Host, Listen, Prop, State, h } from '@st
|
|||||||
|
|
||||||
import { getIonMode } from '../../global/ionic-global';
|
import { getIonMode } from '../../global/ionic-global';
|
||||||
|
|
||||||
|
import { toggleMenu, updateVisibility } from './menu-toggle-util';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
tag: 'ion-menu-toggle',
|
tag: 'ion-menu-toggle',
|
||||||
styleUrl: 'menu-toggle.scss',
|
styleUrl: 'menu-toggle.scss',
|
||||||
@ -29,33 +31,24 @@ export class MenuToggle implements ComponentInterface {
|
|||||||
*/
|
*/
|
||||||
@Prop() autoHide = true;
|
@Prop() autoHide = true;
|
||||||
|
|
||||||
componentDidLoad() {
|
async componentDidLoad() {
|
||||||
return this.updateVisibility();
|
await this.setVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listen('ionMenuChange', { target: 'body' })
|
@Listen('ionMenuChange', { target: 'body' })
|
||||||
@Listen('ionSplitPaneVisible', { target: 'body' })
|
@Listen('ionSplitPaneVisible', { target: 'body' })
|
||||||
async updateVisibility() {
|
async visibilityChanged() {
|
||||||
const menuCtrl = await getMenuController(document);
|
await this.setVisibility();
|
||||||
if (menuCtrl) {
|
}
|
||||||
const menu = await menuCtrl.get(this.menu);
|
|
||||||
if (menu && await menu.isActive()) {
|
private setVisibility = async () => {
|
||||||
this.visible = true;
|
this.visible = await updateVisibility(this.menu);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.visible = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onClick = async () => {
|
private onClick = async () => {
|
||||||
const menuCtrl = await getMenuController(document);
|
await toggleMenu(this.menu);
|
||||||
if (menuCtrl) {
|
|
||||||
const menu = await menuCtrl.get(this.menu);
|
|
||||||
if (menu) {
|
|
||||||
menuCtrl.toggle(this.menu);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const mode = getIonMode(this);
|
const mode = getIonMode(this);
|
||||||
const hidden = this.autoHide && !this.visible;
|
const hidden = this.autoHide && !this.visible;
|
||||||
@ -74,11 +67,3 @@ export class MenuToggle implements ComponentInterface {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMenuController(doc: Document): Promise<HTMLIonMenuControllerElement | undefined> {
|
|
||||||
const menuControllerElement = doc.querySelector('ion-menu-controller');
|
|
||||||
if (!menuControllerElement) {
|
|
||||||
return Promise.resolve(undefined);
|
|
||||||
}
|
|
||||||
return menuControllerElement.componentOnReady();
|
|
||||||
}
|
|
||||||
|
@ -17,19 +17,6 @@ In case it's desired to keep `ion-menu-toggle` always visible, the `autoHide` pr
|
|||||||
| `menu` | `menu` | Optional property that maps to a Menu's `menuId` prop. Can also be `start` or `end` for the menu side. This is used to find the correct menu to toggle. If this property is not used, `ion-menu-toggle` will toggle the first menu that is active. | `string \| undefined` | `undefined` |
|
| `menu` | `menu` | Optional property that maps to a Menu's `menuId` prop. Can also be `start` or `end` for the menu side. This is used to find the correct menu to toggle. If this property is not used, `ion-menu-toggle` will toggle the first menu that is active. | `string \| undefined` | `undefined` |
|
||||||
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
### Used by
|
|
||||||
|
|
||||||
- [ion-menu-button](../menu-button)
|
|
||||||
|
|
||||||
### Graph
|
|
||||||
```mermaid
|
|
||||||
graph TD;
|
|
||||||
ion-menu-button --> ion-menu-toggle
|
|
||||||
style ion-menu-toggle fill:#f9f,stroke:#333,stroke-width:4px
|
|
||||||
```
|
|
||||||
|
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
*Built with [StencilJS](https://stenciljs.com/)*
|
*Built with [StencilJS](https://stenciljs.com/)*
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
|
|
||||||
<ion-buttons slot="start">
|
<ion-buttons slot="start">
|
||||||
<ion-menu-button></ion-menu-button>
|
<ion-menu-button></ion-menu-button>
|
||||||
|
<ion-menu-button auto-hide="false"></ion-menu-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
|
|
||||||
<ion-title>Navigation</ion-title>
|
<ion-title>Navigation</ion-title>
|
||||||
|
Reference in New Issue
Block a user