docs(): update examples and usage

This commit is contained in:
mhartington
2018-05-31 10:56:02 -04:00
parent 89a7d169e9
commit 5ad35ccc00
25 changed files with 370 additions and 225 deletions

View File

@ -2980,7 +2980,7 @@ declare global {
*/
'button': boolean;
/**
* The color to use from your Sass `$colors` map. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information, see [Theming your App](/docs/theming/theming-your-app).
* The color to use for the background of the item.
*/
'color': Color;
/**
@ -3000,7 +3000,7 @@ declare global {
*/
'lines': 'full' | 'inset' | 'none';
/**
* The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`. For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
* The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`.
*/
'mode': Mode;
/**
@ -3034,7 +3034,7 @@ declare global {
*/
'button'?: boolean;
/**
* The color to use from your Sass `$colors` map. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information, see [Theming your App](/docs/theming/theming-your-app).
* The color to use for the background of the item.
*/
'color'?: Color;
/**
@ -3054,7 +3054,7 @@ declare global {
*/
'lines'?: 'full' | 'inset' | 'none';
/**
* The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`. For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
* The mode determines which platform styles to use. Possible values are: `"ios"` or `"md"`.
*/
'mode'?: Mode;
/**

View File

@ -1,7 +1,10 @@
import { Component, Element, Listen, Prop } from '@stencil/core';
import { Color, CssClassMap, Mode, RouterDirection } from '../../interface';
import { createThemedClasses, getElementClassMap, openURL } from '../../utils/theme';
import {
createThemedClasses,
getElementClassMap,
openURL
} from '../../utils/theme';
@Component({
tag: 'ion-item',
@ -11,24 +14,21 @@ import { createThemedClasses, getElementClassMap, openURL } from '../../utils/th
}
})
export class Item {
private itemStyles: { [key: string]: CssClassMap } = {};
@Element() el!: HTMLStencilElement;
@Prop({ context: 'window' }) win!: Window;
@Prop({ context: 'window' })
win!: Window;
/**
* The color to use from your Sass `$colors` map.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information, see [Theming your App](/docs/theming/theming-your-app).
* The color to use for the background of the item.
*/
@Prop() color?: Color;
/**
* The mode determines which platform styles to use.
* Possible values are: `"ios"` or `"md"`.
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
*/
@Prop() mode!: Mode;
@ -65,7 +65,6 @@ export class Item {
*/
@Prop() routerDirection?: RouterDirection;
@Listen('ionStyle')
itemStyle(ev: UIEvent) {
ev.stopPropagation();
@ -110,15 +109,13 @@ export class Item {
const clickable = !!(this.href || this.el.onclick || this.button);
const TagType = clickable
? this.href ? 'a' : 'button'
: 'div';
const TagType = clickable ? (this.href ? 'a' : 'button') : 'div';
const attrs = (TagType === 'button')
? { type: 'button' }
: { href: this.href };
const attrs =
TagType === 'button' ? { type: 'button' } : { href: this.href };
const showDetail = this.detail != null ? this.detail : (this.mode === 'ios' && clickable);
const showDetail =
this.detail != null ? this.detail : this.mode === 'ios' && clickable;
const themedClasses = {
...childStyles,
@ -134,17 +131,18 @@ export class Item {
<TagType
{...attrs}
class={themedClasses}
onClick={(ev) => openURL(this.win, this.href, ev, this.routerDirection)}>
<slot name="start"></slot>
onClick={ev => openURL(this.win, this.href, ev, this.routerDirection)}
>
<slot name="start" />
<div class="item-inner">
<div class="input-wrapper">
<slot></slot>
<slot />
</div>
<slot name="end"></slot>
<slot name="end" />
</div>
{ clickable && this.mode === 'md' && <ion-ripple-effect tapClick={true}/> }
{clickable &&
this.mode === 'md' && <ion-ripple-effect tapClick={true} />}
</TagType>
);
}
}

View File

@ -7,20 +7,20 @@ Items are elements that can contain text, icons, avatars, images, inputs, and an
By default, clickable items will display a right arrow icon on `ios` mode. To hide the right arrow icon on clickable elements, set the `detail` property to `false`. To show the right arrow icon on an item that doesn't display it naturally, add the `detail` attribute to the item.
This feature is not enabled by default on clickable items for the `md` mode, but it can be enabled by setting the following Sass variable:
<!-- This feature is not enabled by default on clickable items for the `md` mode, but it can be enabled by setting the following Sass variable: -->
<!-- -->
<!-- ```scss -->
<!-- $item-md-detail-push-show: true; -->
<!-- ``` -->
```scss
$item-md-detail-push-show: true;
```
It can also be turned off by default on clickable items for ios by setting the following Sass variable:
```scss
$item-ios-detail-push-show: false;
```
See the [theming documentation](http://ionicframework.com/docs/theming/overriding-ionic-variables/) for more information on overriding Sass variables.
<!-- It can also be turned off by default on clickable items for ios by setting the following Sass variable: -->
<!-- -->
<!-- ```scss -->
<!-- $item-ios-detail-push-show: false; -->
<!-- ``` -->
<!-- See the [theming documentation](http://ionicframework.com/docs/theming/overriding-ionic-variables/) for more information on overriding Sass variables. -->
<!-- -->
## Item Placement
@ -28,11 +28,11 @@ Item uses named [slots](https://developer.mozilla.org/en-US/docs/Web/HTML/Elemen
The below chart details the item slots and where it will place the element inside of the item:
| Slot | Description |
|---------|-----------------------------------------------------------------------------------|
| `start` | Placed to the left of all other content in LTR, and to the `right` in RTL. |
| `end` | Placed to the right of all other content in LTR, and to the `right` in RTL. |
| none | Placed inside of the input wrapper. |
| Slot | Description |
|---------|-----------------------------------------------------------------------------|
| `start` | Placed to the left of all other content in LTR, and to the `right` in RTL. |
| `end` | Placed to the right of all other content in LTR, and to the `right` in RTL. |
| none | Placed inside of the input wrapper. |
### Text Alignment
@ -56,9 +56,7 @@ If true, a button tag will be rendered and the item will be tappable. Defaults t
string
The color to use from your Sass `$colors` map.
Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
For more information, see [Theming your App](/docs/theming/theming-your-app).
The color to use for the background of the item.
#### detail
@ -97,7 +95,6 @@ string
The mode determines which platform styles to use.
Possible values are: `"ios"` or `"md"`.
For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
#### routerDirection
@ -121,9 +118,7 @@ If true, a button tag will be rendered and the item will be tappable. Defaults t
string
The color to use from your Sass `$colors` map.
Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
For more information, see [Theming your App](/docs/theming/theming-your-app).
The color to use for the background of the item.
#### detail
@ -162,7 +157,6 @@ string
The mode determines which platform styles to use.
Possible values are: `"ios"` or `"md"`.
For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
#### router-direction

View File

@ -1,7 +1,14 @@
import { Component, Element, Event, EventEmitter, Method, Prop, Watch } from '@stencil/core';
import {
Component,
Element,
Event,
EventEmitter,
Method,
Prop,
Watch
} from '@stencil/core';
import { Color, Mode, StyleEvent } from '../../interface';
@Component({
tag: 'ion-label',
styleUrls: {
@ -13,20 +20,16 @@ import { Color, Mode, StyleEvent } from '../../interface';
}
})
export class Label {
@Element() el!: HTMLElement;
/**
* The color to use from your Sass `$colors` map.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information, see [Theming your App](/docs/theming/theming-your-app).
* The color to use for the label's text
*/
@Prop() color?: Color;
/**
* The mode determines which platform styles to use.
* Possible values are: `"ios"` or `"md"`.
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
*/
@Prop() mode!: Mode;
@ -54,7 +57,7 @@ export class Label {
positionChanged() {
const position = this.position;
return this.ionStyle.emit({
[`label-${position}`]: !!position,
[`label-${position}`]: !!position
});
}

View File

@ -1,5 +1,5 @@
# ion-label
Label is a wrapper element that can be used in combination with `ion-item`.
<!-- Auto Generated Below -->

View File

@ -0,0 +1,24 @@
```html
<ion-list>
<ion-item>
<ion-label>Default</ion-label>
<ion-input></ion-input>
</ion-item>
<ion-item text-wrap>
<ion-label>Wrap label this label just goes on and on and on</ion-label>
<ion-input></ion-input>
</ion-item>
<ion-item>
<ion-label position="fixed">Fixed</ion-label>
<ion-input></ion-input>
</ion-item>
<ion-item>
<ion-label position="floating">Floating</ion-label>
<ion-input></ion-input>
</ion-item>
<ion-item>
<ion-label position="stacked">Stacked</ion-label>
<ion-input></ion-input>
</ion-item>
</ion-list>
```

View File

@ -1,7 +1,6 @@
import { Component, Prop } from '@stencil/core';
import { Color, Mode } from '../../interface';
@Component({
tag: 'ion-list-header',
styleUrls: {
@ -13,19 +12,14 @@ import { Color, Mode } from '../../interface';
}
})
export class ListHeader {
/**
* The color to use from your Sass `$colors` map.
* Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`.
* For more information, see [Theming your App](/docs/theming/theming-your-app).
* The color to use for the background.
*/
@Prop() color?: Color;
/**
* The mode determines which platform styles to use.
* Possible values are: `"ios"` or `"md"`.
* For more information, see [Platform Styles](/docs/theming/platform-specific-styles).
*/
@Prop() mode!: Mode;
}

View File

@ -1,5 +1,5 @@
# ion-list-header
List header a header component for a list.
<!-- Auto Generated Below -->

View File

@ -0,0 +1,12 @@
```html
<ion-list>
<ion-list-header>
<ion-label>Items</ion-label>
</ion-list-header>
<ion-item>Item 1</ion-item>
<ion-item>Item 2</ion-item>
<ion-item>Item 3</ion-item>
<ion-item>Item 4</ion-item>
<ion-item>Item 5</ion-item>
</ion-list>
```

View File

@ -58,5 +58,4 @@ export class List {
}
};
}
}

View File

@ -28,7 +28,7 @@ export class LoadingController implements OverlayController {
removeLastOverlay(this.loadings);
}
/*
/**
* Create a loading overlay with loading options.
*/
@Method()
@ -36,7 +36,7 @@ export class LoadingController implements OverlayController {
return createOverlay(this.doc.createElement('ion-loading'), opts);
}
/*
/**
* Dismiss the open loading overlay.
*/
@Method()
@ -44,7 +44,7 @@ export class LoadingController implements OverlayController {
return dismissOverlay(data, role, this.loadings, loadingId);
}
/*
/**
* Get the most recently opened loading overlay.
*/
@Method()

View File

@ -3,19 +3,6 @@
Loading controllers programmatically control the loading component. Loadings can be created and dismissed from the loading controller. View the [Loading](../../loading/Loading) documentation for a full list of options to pass upon creation.
```javascript
async function presentLoading() {
const loadingController = document.querySelector('ion-loading-controller');
await loadingController.componentOnReady();
const loadingElement = await loadingController.create({
content: 'Please wait...',
spinner: 'crescent',
duration: 2000
});
return await loadingElement.present();
}
```
<!-- Auto Generated Below -->

View File

@ -0,0 +1,13 @@
```javascript
async function presentLoading() {
const loadingController = document.querySelector('ion-loading-controller');
await loadingController.componentOnReady();
const loadingElement = await loadingController.create({
content: 'Please wait...',
spinner: 'crescent',
duration: 2000
});
return await loadingElement.present();
}
```

View File

@ -1,6 +1,27 @@
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
import { Animation, AnimationBuilder, Color, Config, Mode } from '../../interface';
import { BACKDROP, OverlayEventDetail, OverlayInterface, dismiss, eventMethod, present } from '../../utils/overlays';
import {
Component,
Element,
Event,
EventEmitter,
Listen,
Method,
Prop
} from '@stencil/core';
import {
Animation,
AnimationBuilder,
Color,
Config,
Mode
} from '../../interface';
import {
BACKDROP,
OverlayEventDetail,
OverlayInterface,
dismiss,
eventMethod,
present
} from '../../utils/overlays';
import { createThemedClasses, getClassMap } from '../../utils/theme';
import { iosEnterAnimation } from './animations/ios.enter';
@ -20,7 +41,6 @@ import { mdLeaveAnimation } from './animations/md.leave';
}
})
export class Loading implements OverlayInterface {
private durationTimeout: any;
presented = false;
@ -30,8 +50,10 @@ export class Loading implements OverlayInterface {
@Element() el!: HTMLElement;
@Prop({ connect: 'ion-animation-controller' }) animationCtrl!: HTMLIonAnimationControllerElement;
@Prop({ context: 'config' }) config!: Config;
@Prop({ connect: 'ion-animation-controller' })
animationCtrl!: HTMLIonAnimationControllerElement;
@Prop({ context: 'config' })
config!: Config;
@Prop() overlayId!: number;
@Prop() keyboardClose = true;
@ -105,28 +127,36 @@ export class Loading implements OverlayInterface {
/**
* Emitted after the loading has presented.
*/
@Event({eventName: 'ionLoadingDidPresent'}) didPresent!: EventEmitter<void>;
@Event({ eventName: 'ionLoadingDidPresent' })
didPresent!: EventEmitter<void>;
/**
* Emitted before the loading has presented.
*/
@Event({eventName: 'ionLoadingWillPresent'}) willPresent!: EventEmitter<void>;
@Event({ eventName: 'ionLoadingWillPresent' })
willPresent!: EventEmitter<void>;
/**
* Emitted before the loading has dismissed.
*/
@Event({eventName: 'ionLoadingWillDismiss'}) willDismiss!: EventEmitter<OverlayEventDetail>;
@Event({ eventName: 'ionLoadingWillDismiss' })
willDismiss!: EventEmitter<OverlayEventDetail>;
/**
* Emitted after the loading has dismissed.
*/
@Event({eventName: 'ionLoadingDidDismiss'}) didDismiss!: EventEmitter<OverlayEventDetail>;
@Event({ eventName: 'ionLoadingDidDismiss' })
didDismiss!: EventEmitter<OverlayEventDetail>;
componentWillLoad() {
if (!this.spinner) {
this.spinner = this.config.get('loadingSpinner', this.mode === 'ios' ? 'lines' : 'crescent');
this.spinner = this.config.get(
'loadingSpinner',
this.mode === 'ios' ? 'lines' : 'crescent'
);
}
}
componentDidLoad() {
this.ionLoadingDidLoad.emit();
}
@ -145,10 +175,19 @@ export class Loading implements OverlayInterface {
*/
@Method()
async present(): Promise<void> {
await present(this, 'loadingEnter', iosEnterAnimation, mdEnterAnimation, undefined);
await present(
this,
'loadingEnter',
iosEnterAnimation,
mdEnterAnimation,
undefined
);
if (this.duration) {
this.durationTimeout = setTimeout(() => this.dismiss(), this.duration + 10);
this.durationTimeout = setTimeout(
() => this.dismiss(),
this.duration + 10
);
}
}
@ -160,19 +199,25 @@ export class Loading implements OverlayInterface {
if (this.durationTimeout) {
clearTimeout(this.durationTimeout);
}
return dismiss(this, data, role, 'loadingLeave', iosLeaveAnimation, mdLeaveAnimation);
return dismiss(
this,
data,
role,
'loadingLeave',
iosLeaveAnimation,
mdLeaveAnimation
);
}
/**
* Returns a promise that resolves when the loading did dismiss. It also accepts a callback
* that is called in the same circustances.
*
* ```
* const {data, role} = await loading.onDidDismiss();
* ```
*/
@Method()
onDidDismiss(callback?: (detail: OverlayEventDetail) => void): Promise<OverlayEventDetail> {
onDidDismiss(
callback?: (detail: OverlayEventDetail) => void
): Promise<OverlayEventDetail> {
return eventMethod(this.el, 'ionLoadingDidDismiss', callback);
}
@ -185,16 +230,20 @@ export class Loading implements OverlayInterface {
* ```
*/
@Method()
onWillDismiss(callback?: (detail: OverlayEventDetail) => void): Promise<OverlayEventDetail> {
onWillDismiss(
callback?: (detail: OverlayEventDetail) => void
): Promise<OverlayEventDetail> {
return eventMethod(this.el, 'ionLoadingWillDismiss', callback);
}
hostData() {
const themedClasses = this.translucent ? createThemedClasses(this.mode, this.color, 'loading-translucent') : {};
const themedClasses = this.translucent
? createThemedClasses(this.mode, this.color, 'loading-translucent')
: {};
return {
style: {
zIndex: 20000 + this.overlayId,
zIndex: 20000 + this.overlayId
},
class: {
...themedClasses,
@ -207,13 +256,13 @@ export class Loading implements OverlayInterface {
return [
<ion-backdrop visible={this.showBackdrop} tappable={false} />,
<div class="loading-wrapper" role="dialog">
{this.spinner !== 'hide' && (
<div class="loading-spinner">
<ion-spinner name={this.spinner} />
</div>
)}
{ this.spinner !== 'hide' &&
<div class="loading-spinner">
<ion-spinner name={this.spinner}></ion-spinner>
</div>}
{ this.content && <div class="loading-content">{this.content}</div>}
{this.content && <div class="loading-content">{this.content}</div>}
</div>
];
}

View File

@ -18,7 +18,7 @@ export class LoadingExample {
return await loading.present();
}
presentLoadingWithOptions() {
async presentLoadingWithOptions() {
const loading = await this.loadingController.create({
spinner: 'hide',
duration: 5000,

View File

@ -12,8 +12,8 @@ import { Config } from '../../interface';
}
})
export class MenuButton {
@Prop({ context: 'config' }) config!: Config;
@Prop({ context: 'config' })
config!: Config;
/**
* 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

View File

@ -1,5 +1,6 @@
# ion-menu-button
Menu Button is component that automatically creates the icon and functionality to open a menu on a page.
<!-- Auto Generated Below -->

View File

@ -9,11 +9,11 @@ import { menuRevealAnimation } from './animations/reveal';
tag: 'ion-menu-controller'
})
export class MenuController {
private menus: Menu[] = [];
private menuAnimations = new Map<string, AnimationBuilder>();
@Prop({ connect: 'ion-animation-controller' }) animationCtrl!: HTMLIonAnimationControllerElement;
@Prop({ connect: 'ion-animation-controller' })
animationCtrl!: HTMLIonAnimationControllerElement;
constructor() {
this.registerAnimation('reveal', menuRevealAnimation);
@ -22,9 +22,7 @@ export class MenuController {
}
/**
* Programatically open the Menu.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {Promise} returns a promise when the menu is fully opened
* Open the Menu.
*/
@Method()
open(menuId?: string): Promise<boolean> {
@ -36,17 +34,13 @@ export class MenuController {
}
/**
* Programatically close the Menu. If no `menuId` is given as the first
* Close the Menu. If no `menuId` is given as the first
* argument then it'll close any menu which is open. If a `menuId`
* is given then it'll close that exact menu.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {Promise} returns a promise when the menu is fully closed
*/
@Method()
close(menuId?: string): Promise<boolean> {
const menu = (menuId)
? this.get(menuId)
: this.getOpen();
const menu = menuId ? this.get(menuId) : this.getOpen();
if (menu) {
return menu.close();
@ -57,8 +51,6 @@ export class MenuController {
/**
* Toggle the menu. If it's closed, it will open, and if opened, it
* will close.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {Promise} returns a promise when the menu has been toggled
*/
@Method()
toggle(menuId?: string): Promise<boolean> {
@ -74,11 +66,9 @@ export class MenuController {
* left menus, but only one of them should be able to be opened at the same
* time. If there are multiple menus on the same side, then enabling one menu
* will also automatically disable all the others that are on the same side.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {HTMLIonMenuElement} Returns the instance of the menu, which is useful for chaining.
*/
@Method()
enable(shouldEnable: boolean, menuId?: string): HTMLIonMenuElement|null {
enable(shouldEnable: boolean, menuId?: string): HTMLIonMenuElement | null {
const menu = this.get(menuId);
if (menu) {
menu.disabled = !shouldEnable;
@ -88,12 +78,12 @@ export class MenuController {
/**
* Used to enable or disable the ability to swipe open the menu.
* @param {boolean} shouldEnable True if it should be swipe-able, false if not.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {HTMLIonMenuElement} Returns the instance of the menu, which is useful for chaining.
*/
@Method()
swipeEnable(shouldEnable: boolean, menuId?: string): HTMLIonMenuElement|null {
swipeEnable(
shouldEnable: boolean,
menuId?: string
): HTMLIonMenuElement | null {
const menu = this.get(menuId);
if (menu) {
menu.swipeEnabled = shouldEnable;
@ -102,22 +92,19 @@ export class MenuController {
}
/**
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {boolean} Returns true if the specified menu is currently open, otherwise false.
* If the menuId is not specified, it returns true if ANY menu is currenly open.
*/
@Method()
isOpen(menuId?: string): boolean {
if (menuId) {
const menu = this.get(menuId);
return menu && menu.isOpen() || false;
return (menu && menu.isOpen()) || false;
}
return !!this.getOpen();
}
/**
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {boolean} Returns true if the menu is currently enabled, otherwise false.
* Returns true or false if the menuId is enabled or not
*/
@Method()
isEnabled(menuId?: string): boolean {
@ -134,8 +121,6 @@ export class MenuController {
* it'll return the enabled menu on that side. Otherwise, if a `menuId` is
* provided, then it'll try to find the menu using the menu's `id`
* property. If a menu is not found then it'll return `null`.
* @param {string} [menuId] Optionally get the menu by its id, or side.
* @return {HTMLIonMenuElement} Returns the instance of the menu if found, otherwise `null`.
*/
@Method()
get(menuId?: string): HTMLIonMenuElement | null {
@ -147,7 +132,7 @@ export class MenuController {
console.error('menu.side=right is deprecated, use "end" instead');
return null;
}
if (menuId === 'start' || menuId === 'end' ) {
if (menuId === 'start' || menuId === 'end') {
// there could be more than one menu on the same side
// so first try to get the enabled one
const menu = this.find(m => m.side === menuId && !m.disabled);
@ -158,7 +143,6 @@ export class MenuController {
// didn't find a menu side that is enabled
// so try to get the first menu side found
return this.find(m => m.side === menuId) || null;
} else if (menuId) {
// the menuId was not left or right
// so try to get the menu by its "id"
@ -172,19 +156,19 @@ export class MenuController {
}
// get the first menu in the array, if one exists
return (this.menus.length > 0 ? this.menus[0].el : null);
return this.menus.length > 0 ? this.menus[0].el : null;
}
/**
* @return {Menu} Returns the instance of the menu already opened, otherwise `null`.
* Returns the instance of the menu already opened, otherwise `null`.
*/
@Method()
getOpen(): HTMLIonMenuElement|null {
getOpen(): HTMLIonMenuElement | null {
return this.find(m => m.isOpen());
}
/**
* @return {Array<HTMLIonMenuElement>} Returns an array of all menu instances.
* Returns an array of all menu instances.
*/
@Method()
getMenus(): HTMLIonMenuElement[] {
@ -192,17 +176,13 @@ export class MenuController {
}
/**
* @hidden
* @return {boolean} if any menu is currently animating
* If any menu is currently animating
*/
@Method()
isAnimating(): boolean {
return this.menus.some(menu => menu.isAnimating);
}
/**
* @hidden
*/
@Method()
_register(menu: Menu) {
if (this.menus.indexOf(menu) < 0) {
@ -210,9 +190,6 @@ export class MenuController {
}
}
/**
* @hidden
*/
@Method()
_unregister(menu: Menu) {
const index = this.menus.indexOf(menu);
@ -221,9 +198,6 @@ export class MenuController {
}
}
/**
* @hidden
*/
@Method()
_setActiveMenu(menu: Menu) {
// if this menu should be enabled
@ -232,14 +206,15 @@ export class MenuController {
const side = menu.side;
this.menus
.filter(m => m.side === side && m !== menu)
.forEach(m => m.disabled = true);
.forEach(m => (m.disabled = true));
}
/**
* @hidden
*/
@Method()
_setOpen(menu: Menu, shouldOpen: boolean, animated: boolean): Promise<boolean> {
_setOpen(
menu: Menu,
shouldOpen: boolean,
animated: boolean
): Promise<boolean> {
if (this.isAnimating()) {
return Promise.resolve(false);
}
@ -252,9 +227,6 @@ export class MenuController {
return menu._setOpen(shouldOpen, animated);
}
/**
* @hidden
*/
@Method()
createAnimation(type: string, menuCmp: Menu): Promise<Animation> {
const animationBuilder = this.menuAnimations.get(type);
@ -269,14 +241,13 @@ export class MenuController {
this.menuAnimations.set(name, animation);
}
private find(predicate: (menu: Menu) => boolean): HTMLIonMenuElement|null {
private find(predicate: (menu: Menu) => boolean): HTMLIonMenuElement | null {
const instance = this.menus.find(predicate);
if (instance) {
return instance.el;
}
return null;
}
}
export { menuOverlayAnimation, menuPushAnimation, menuRevealAnimation };

View File

@ -1,5 +1,6 @@
# ion-menu-controller
The MenuController makes it easy to control a Menu. Its methods can be used to display the menu, enable the menu, toggle the menu, and more. The controller will grab a reference to the menu by the side, id, or, if neither of these are passed to it, it will grab the first menu it finds.
<!-- Auto Generated Below -->

View File

@ -5,19 +5,20 @@ import { Component, Listen, Prop, State } from '@stencil/core';
styleUrl: 'menu-toggle.scss'
})
export class MenuToggle {
@Prop({ context: 'document' }) doc!: Document;
@Prop({ context: 'document' })
doc!: Document;
@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;
/**
* Automatically hides the content when the corresponding menu is not
* active
* Automatically hides the content when the corresponding menu is not active
*/
@Prop() autoHide = true;
@ -54,15 +55,16 @@ export class MenuToggle {
hostData() {
const hidden = this.autoHide && !this.visible;
return {
class: {
class: {
'menu-toggle-hidden': hidden
}
};
}
}
function getMenuController(doc: Document): Promise<HTMLIonMenuControllerElement|null> {
function getMenuController(
doc: Document
): Promise<HTMLIonMenuControllerElement | null> {
const menuControllerElement = doc.querySelector('ion-menu-controller');
if (!menuControllerElement) {
return Promise.resolve(null);

View File

@ -1,5 +1,5 @@
# ion-menu-toggle
The MenuToggle component can be used to toggle a menu open or closed.
<!-- Auto Generated Below -->

View File

@ -1,5 +1,23 @@
import { Component, Element, Event, EventEmitter, EventListenerEnable, Listen, Method, Prop, State, Watch } from '@stencil/core';
import { Animation, Color, Config, GestureDetail, MenuChangeEventDetail, Mode } from '../../interface';
import {
Component,
Element,
Event,
EventEmitter,
EventListenerEnable,
Listen,
Method,
Prop,
State,
Watch
} from '@stencil/core';
import {
Animation,
Color,
Config,
GestureDetail,
MenuChangeEventDetail,
Mode
} from '../../interface';
import { Side, assert, isEndSide } from '../../utils/helpers';
@Component({
@ -13,7 +31,6 @@ import { Side, assert, isEndSide } from '../../utils/helpers';
}
})
export class Menu {
private animation?: Animation;
private isPane = false;
private _isOpen = false;
@ -33,11 +50,20 @@ export class Menu {
@State() isEndSide = false;
@Prop({ context: 'config' }) config!: Config;
@Prop({ context: 'isServer' }) isServer!: boolean;
@Prop({ connect: 'ion-menu-controller' }) lazyMenuCtrl!: HTMLIonMenuControllerElement;
@Prop({ context: 'enableListener' }) enableListener!: EventListenerEnable;
@Prop({ context: 'window' }) win!: Window;
@Prop({ context: 'config' })
config!: Config;
@Prop({ context: 'isServer' })
isServer!: boolean;
@Prop({ connect: 'ion-menu-controller' })
lazyMenuCtrl!: HTMLIonMenuControllerElement;
@Prop({ context: 'enableListener' })
enableListener!: EventListenerEnable;
@Prop({ context: 'window' })
win!: Window;
/**
* The content's id the menu should use.
@ -50,11 +76,11 @@ export class Menu {
@Prop() menuId?: string;
/**
* The display type of the menu. Default varies based on the mode,
* see the `menuType` in the [config](../../config/Config). Available options:
* `"overlay"`, `"reveal"`, `"push"`.
* The display type of the menu.
* Available options: `"overlay"`, `"reveal"`, `"push"`.
*/
@Prop({ mutable: true }) type!: string;
@Prop({ mutable: true })
type!: string;
@Watch('type')
typeChanged(type: string, oldType: string | null) {
@ -74,12 +100,13 @@ export class Menu {
/**
* If true, the menu is disabled. Default `false`.
*/
@Prop({ mutable: true }) disabled = false;
@Prop({ mutable: true })
disabled = false;
@Watch('disabled')
protected disabledChanged(disabled: boolean) {
this.updateState();
this.ionMenuChange.emit({ disabled: disabled, open: this._isOpen});
this.ionMenuChange.emit({ disabled: disabled, open: this._isOpen });
}
/**
@ -107,6 +134,10 @@ export class Menu {
*/
@Prop() persistent = false;
/**
* The edge threshold for dragging the menu open.
* If a drag/swipe happens over this value, the menu is not triggered.
*/
@Prop() maxEdgeStart = 50;
/**
@ -119,7 +150,6 @@ export class Menu {
*/
@Event() ionClose!: EventEmitter<void>;
@Event() protected ionMenuChange!: EventEmitter<MenuChangeEventDetail>;
async componentWillLoad() {
@ -139,13 +169,15 @@ export class Menu {
}
const el = this.el;
const parent = el.parentNode as any;
const content = (this.contentId)
const content = this.contentId
? document.getElementById(this.contentId)
: parent && parent.querySelector && parent.querySelector('[main]');
if (!content || !content.tagName) {
// requires content element
console.error('Menu: must have a "content" element to listen for drag events on.');
console.error(
'Menu: must have a "content" element to listen for drag events on.'
);
return;
}
this.contentEl = content as HTMLElement;
@ -165,7 +197,7 @@ export class Menu {
}
// register this menu with the app's menu controller
this.menuCtrl!._register(this);
this.ionMenuChange.emit({ disabled: !isEnabled, open: this._isOpen});
this.ionMenuChange.emit({ disabled: !isEnabled, open: this._isOpen });
// mask it as enabled / disabled
this.disabled = !isEnabled;
@ -188,7 +220,7 @@ export class Menu {
@Listen('body:click', { enabled: false, capture: true })
onBackdropClick(ev: UIEvent) {
const el = ev.target as HTMLElement;
if (!el.closest('.menu-inner') && this.lastOnEnd < (ev.timeStamp - 100)) {
if (!el.closest('.menu-inner') && this.lastOnEnd < ev.timeStamp - 100) {
ev.preventDefault();
ev.stopPropagation();
this.close();
@ -222,7 +254,7 @@ export class Menu {
async _setOpen(shouldOpen: boolean, animated = true): Promise<boolean> {
// If the menu is disabled or it is currenly being animated, let's do nothing
if (!this.isActive() || this.isAnimating || (shouldOpen === this._isOpen)) {
if (!this.isActive() || this.isAnimating || shouldOpen === this._isOpen) {
return this._isOpen;
}
@ -257,7 +289,10 @@ export class Menu {
this.animation = await this.menuCtrl!.createAnimation(this.type, this);
}
private async startAnimation(shouldOpen: boolean, animated: boolean): Promise<void> {
private async startAnimation(
shouldOpen: boolean,
animated: boolean
): Promise<void> {
const ani = this.animation!.reverse(!shouldOpen);
if (animated) {
await ani.playAsync();
@ -267,9 +302,7 @@ export class Menu {
}
private canSwipe(): boolean {
return this.swipeEnabled &&
!this.isAnimating &&
this.isActive();
return this.swipeEnabled && !this.isAnimating && this.isActive();
}
private canStart(detail: GestureDetail): boolean {
@ -281,7 +314,12 @@ export class Menu {
} else if (this.menuCtrl!.getOpen()) {
return false;
}
return checkEdgeSide(this.win, detail.currentX, this.isEndSide, this.maxEdgeStart);
return checkEdgeSide(
this.win,
detail.currentX,
this.isEndSide,
this.maxEdgeStart
);
}
private onWillStart(): Promise<void> {
@ -296,9 +334,7 @@ export class Menu {
}
// the cloned animation should not use an easing curve during seek
this.animation
.reverse(this._isOpen)
.progressStart();
this.animation.reverse(this._isOpen).progressStart();
}
private onDragMove(detail: GestureDetail) {
@ -324,17 +360,17 @@ export class Menu {
const stepValue = delta / width;
const velocity = detail.velocityX;
const z = width / 2.0;
const shouldCompleteRight = (velocity >= 0)
&& (velocity > 0.2 || detail.deltaX > z);
const shouldCompleteRight =
velocity >= 0 && (velocity > 0.2 || detail.deltaX > z);
const shouldCompleteLeft = (velocity <= 0)
&& (velocity < -0.2 || detail.deltaX < -z);
const shouldCompleteLeft =
velocity <= 0 && (velocity < -0.2 || detail.deltaX < -z);
const shouldComplete = (isOpen)
const shouldComplete = isOpen
? isEndSide ? shouldCompleteRight : shouldCompleteLeft
: isEndSide ? shouldCompleteLeft : shouldCompleteRight;
let shouldOpen = (!isOpen && shouldComplete);
let shouldOpen = !isOpen && shouldComplete;
if (isOpen && !shouldComplete) {
shouldOpen = true;
}
@ -349,7 +385,9 @@ export class Menu {
this.lastOnEnd = detail.timeStamp;
this.animation
.onFinish(() => this.afterAnimation(shouldOpen), { clearExistingCallacks: true })
.onFinish(() => this.afterAnimation(shouldOpen), {
clearExistingCallacks: true
})
.progressEnd(shouldComplete, stepValue, realDur);
}
@ -382,7 +420,6 @@ export class Menu {
// emit open event
this.ionOpen.emit();
} else {
// remove css classes
this.el.classList.remove(SHOW_MENU);
@ -425,22 +462,23 @@ export class Menu {
[`menu-type-${this.type}`]: true,
'menu-enabled': !this.disabled,
'menu-side-right': isEndSide,
'menu-side-left': !isEndSide,
'menu-side-left': !isEndSide
}
};
}
render() {
return ([
<div class="menu-inner" ref={el => this.menuInnerEl = el}>
<slot></slot>
return [
<div class="menu-inner" ref={el => (this.menuInnerEl = el)}>
<slot />
</div>,
<ion-backdrop
ref={el => this.backdropEl = el}
ref={el => (this.backdropEl = el)}
class="menu-backdrop"
tappable={false}
stopPropagation={false}/>,
stopPropagation={false}
/>,
<ion-gesture
canStart={this.canStart.bind(this)}
@ -454,16 +492,26 @@ export class Menu {
direction="x"
threshold={10}
attachTo="window"
disableScroll={true} />
]);
disableScroll={true}
/>
];
}
}
function computeDelta(deltaX: number, isOpen: boolean, isEndSide: boolean): number {
return Math.max(0, (isOpen !== isEndSide) ? -deltaX : deltaX);
function computeDelta(
deltaX: number,
isOpen: boolean,
isEndSide: boolean
): number {
return Math.max(0, isOpen !== isEndSide ? -deltaX : deltaX);
}
function checkEdgeSide(win: Window, posX: number, isEndSide: boolean, maxEdgeStart: number): boolean {
function checkEdgeSide(
win: Window,
posX: number,
isEndSide: boolean,
maxEdgeStart: number
): boolean {
if (isEndSide) {
return posX >= win.innerWidth - maxEdgeStart;
} else {

View File

@ -1,5 +1,11 @@
# ion-menu
The Menu component is a navigation drawer that slides in from the side of the current view.
By default, it slides in from the left, but the side can be overridden.
The menu will be displayed differently based on the mode, however the display type can be changed to any of the available menu types.
The menu element should be a sibling to the root content element.
There can be any number of menus attached to the content.
These can be controlled from the templates, or programmatically using the MenuController.
<!-- Auto Generated Below -->

View File

@ -0,0 +1,10 @@
```html
<ion-menu>
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
</ion-menu>
<ion-router-outlet main></ion-router-outlet>
```

View File

@ -0,0 +1,33 @@
```html
<ion-app>
<ion-menu side="start">
<ion-header>
<ion-toolbar color="secondary">
<ion-title>Left Menu</ion-title>
</ion-toolbar>
</ion-header>
</ion-menu>
<ion-menu side="end">
<ion-header>
<ion-toolbar>
<ion-title>Hola</ion-title>
</ion-toolbar>
</ion-header>
<ion-content padding>
hola macho
</ion-content>
</ion-menu>
<div class="ion-page" main>
<ion-header>
<ion-toolbar>
<ion-title>Menu - Basic</ion-title>
</ion-toolbar>
</ion-header>
</div>
</ion-app>
<ion-menu-controller></ion-menu-controller>
```