mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 11:41:20 +08:00
docs(): update examples
This commit is contained in:
@ -28,7 +28,7 @@ export class ModalController implements OverlayController {
|
||||
removeLastOverlay(this.modals);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Create a modal overlay with modal options.
|
||||
*/
|
||||
@Method()
|
||||
@ -36,7 +36,7 @@ export class ModalController implements OverlayController {
|
||||
return createOverlay(this.doc.createElement('ion-modal'), opts);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Dismiss the open modal overlay.
|
||||
*/
|
||||
@Method()
|
||||
@ -44,7 +44,7 @@ export class ModalController implements OverlayController {
|
||||
return dismissOverlay(data, role, this.modals, modalId);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Get the most recently opened modal overlay.
|
||||
*/
|
||||
@Method()
|
||||
|
@ -3,41 +3,6 @@
|
||||
Modal controllers programmatically control the modal component. Modals can be created and dismissed from the modal controller. View the [Modal](../../modal/Modal) documentation for a full list of options to pass upon creation.
|
||||
|
||||
|
||||
```javascript
|
||||
async function presentModal() {
|
||||
// initialize controller
|
||||
const modalController = document.querySelector('ion-modal-controller');
|
||||
await modalController.componentOnReady();
|
||||
|
||||
// create component to open
|
||||
const element = document.createElement('div');
|
||||
element.innerHTML = `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Super Modal</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<h1>Content of doom</h1>
|
||||
<div>Here's some more content</div>
|
||||
<ion-button class="dismiss">Dismiss Modal</ion-button>
|
||||
</ion-content>
|
||||
`;
|
||||
|
||||
// listen for close event
|
||||
const button = element.querySelector('ion-button');
|
||||
button.addEventListener('click', () => {
|
||||
modalController.dismiss();
|
||||
});
|
||||
|
||||
// present the modal
|
||||
const modalElement = await modalController.create({
|
||||
component: element
|
||||
});
|
||||
modalElement.present();
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
||||
|
@ -7,16 +7,16 @@ async function presentModal() {
|
||||
// create component to open
|
||||
const element = document.createElement('div');
|
||||
element.innerHTML = `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Super Modal</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<h1>Content of doom</h1>
|
||||
<div>Here's some more content</div>
|
||||
<ion-button class="dismiss">Dismiss Modal</ion-button>
|
||||
</ion-content>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Super Modal</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
<ion-content>
|
||||
<h1>Content of doom</h1>
|
||||
<div>Here's some more content</div>
|
||||
<ion-button class="dismiss">Dismiss Modal</ion-button>
|
||||
</ion-content>
|
||||
`;
|
||||
|
||||
// listen for close event
|
||||
|
@ -1,5 +1,6 @@
|
||||
# ion-nav-pop
|
||||
|
||||
`NavPop` is a component used the automatically go back in navigation. It is the element from of `NavController.pop()`
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
@ -2,13 +2,19 @@ import { Component, Element, Listen, Prop } from '@stencil/core';
|
||||
import { ComponentProps, NavComponent } from '../../interface';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-nav-push',
|
||||
tag: 'ion-nav-push'
|
||||
})
|
||||
export class NavPush {
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
/**
|
||||
* Component to navigate to
|
||||
*/
|
||||
@Prop() component?: NavComponent;
|
||||
|
||||
/**
|
||||
* Data you want to pass to the component as props
|
||||
*/
|
||||
@Prop() componentProps?: ComponentProps;
|
||||
|
||||
@Listen('child:click')
|
||||
@ -20,5 +26,4 @@ export class NavPush {
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
# ion-nav-push
|
||||
|
||||
`NavPush` is a component used to navigate to the specified component.
|
||||
It is the element from of `NavController.push()`
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
@ -2,12 +2,20 @@ import { Component, Element, Listen, Prop } from '@stencil/core';
|
||||
import { ComponentProps, NavComponent } from '../../interface';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-nav-set-root',
|
||||
tag: 'ion-nav-set-root'
|
||||
})
|
||||
export class NavSetRoot {
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
/**
|
||||
* Component you want to make root for the navigation stack
|
||||
*
|
||||
*/
|
||||
@Prop() component?: NavComponent;
|
||||
|
||||
/**
|
||||
* Data you want to pass to the component as props
|
||||
*/
|
||||
@Prop() componentProps?: ComponentProps;
|
||||
|
||||
@Listen('child:click')
|
||||
@ -19,5 +27,4 @@ export class NavSetRoot {
|
||||
}
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
# ion-nav-set-root
|
||||
|
||||
`NavSetRoot` is an element that allows you to set the root of the current navigation stack.
|
||||
It is the element form a calling `NavController.setRoot()`
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
@ -1,19 +1,49 @@
|
||||
import { Build, Component, Element, Event, EventEmitter, Method, Prop, Watch } from '@stencil/core';
|
||||
import {
|
||||
Build,
|
||||
Component,
|
||||
Element,
|
||||
Event,
|
||||
EventEmitter,
|
||||
Method,
|
||||
Prop,
|
||||
Watch
|
||||
} from '@stencil/core';
|
||||
import { ViewLifecycle } from '../..';
|
||||
import {
|
||||
Animation, ComponentProps, Config, FrameworkDelegate, GestureDetail, Mode,
|
||||
NavComponent, NavOptions, NavOutlet, NavResult, QueueController, RouteID,
|
||||
RouteWrite, TransitionDoneFn, TransitionInstruction } from '../../interface';
|
||||
Animation,
|
||||
ComponentProps,
|
||||
Config,
|
||||
FrameworkDelegate,
|
||||
GestureDetail,
|
||||
Mode,
|
||||
NavComponent,
|
||||
NavOptions,
|
||||
NavOutlet,
|
||||
NavResult,
|
||||
QueueController,
|
||||
RouteID,
|
||||
RouteWrite,
|
||||
TransitionDoneFn,
|
||||
TransitionInstruction
|
||||
} from '../../interface';
|
||||
import { assert } from '../../utils/helpers';
|
||||
import { TransitionOptions, lifecycle, transition } from '../../utils/transition';
|
||||
import {
|
||||
TransitionOptions,
|
||||
lifecycle,
|
||||
transition
|
||||
} from '../../utils/transition';
|
||||
import { RouterIntent } from '../router/utils/constants';
|
||||
import { ViewController, ViewState, convertToViews, matches } from './view-controller';
|
||||
import {
|
||||
ViewController,
|
||||
ViewState,
|
||||
convertToViews,
|
||||
matches
|
||||
} from './view-controller';
|
||||
|
||||
@Component({
|
||||
tag: 'ion-nav',
|
||||
tag: 'ion-nav'
|
||||
})
|
||||
export class Nav implements NavOutlet {
|
||||
|
||||
private transInstr: TransitionInstruction[] = [];
|
||||
private sbTrns?: Animation;
|
||||
private useRouter = false;
|
||||
@ -25,16 +55,41 @@ export class Nav implements NavOutlet {
|
||||
|
||||
@Element() el!: HTMLElement;
|
||||
|
||||
@Prop({ context: 'queue' }) queue!: QueueController;
|
||||
@Prop({ context: 'config' }) config!: Config;
|
||||
@Prop({ context: 'window' }) win!: Window;
|
||||
@Prop({ context: 'queue' })
|
||||
queue!: QueueController;
|
||||
|
||||
@Prop({ connect: 'ion-animation-controller' }) animationCtrl!: HTMLIonAnimationControllerElement;
|
||||
@Prop({ mutable: true }) swipeBackEnabled?: boolean;
|
||||
@Prop({ mutable: true }) animated?: boolean;
|
||||
@Prop({ context: 'config' })
|
||||
config!: Config;
|
||||
|
||||
@Prop({ context: 'window' })
|
||||
win!: Window;
|
||||
|
||||
@Prop({ connect: 'ion-animation-controller' })
|
||||
animationCtrl!: HTMLIonAnimationControllerElement;
|
||||
/**
|
||||
* If the nav component should allow for swipe-to-go-back
|
||||
*/
|
||||
@Prop({ mutable: true })
|
||||
swipeBackEnabled?: boolean;
|
||||
/**
|
||||
* If the nav should animate the components or not
|
||||
*/
|
||||
@Prop({ mutable: true })
|
||||
animated?: boolean;
|
||||
|
||||
/** @hidden */
|
||||
@Prop() delegate?: FrameworkDelegate;
|
||||
|
||||
/**
|
||||
* Any parameters for the root component
|
||||
*/
|
||||
@Prop() rootParams?: ComponentProps;
|
||||
|
||||
/**
|
||||
* Root NavComponent to load
|
||||
*/
|
||||
@Prop() root?: NavComponent;
|
||||
|
||||
@Watch('root')
|
||||
rootChanged() {
|
||||
const isDev = Build.isDev;
|
||||
@ -42,19 +97,35 @@ export class Nav implements NavOutlet {
|
||||
if (!this.useRouter) {
|
||||
this.setRoot(this.root, this.rootParams);
|
||||
} else if (isDev) {
|
||||
console.warn('<ion-nav> does not support a root attribute when using ion-router.');
|
||||
console.warn(
|
||||
'<ion-nav> does not support a root attribute when using ion-router.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event fired when Nav will load a component
|
||||
*/
|
||||
@Event() ionNavWillLoad!: EventEmitter<void>;
|
||||
/**
|
||||
* Event fired when the nav will components
|
||||
*/
|
||||
@Event() ionNavWillChange!: EventEmitter<void>;
|
||||
/**
|
||||
* Event fired when the nav has changed components
|
||||
*/
|
||||
@Event() ionNavDidChange!: EventEmitter<void>;
|
||||
|
||||
componentWillLoad() {
|
||||
this.useRouter = !!this.win.document.querySelector('ion-router') && !this.el.closest('[no-router]');
|
||||
this.useRouter =
|
||||
!!this.win.document.querySelector('ion-router') &&
|
||||
!this.el.closest('[no-router]');
|
||||
if (this.swipeBackEnabled === undefined) {
|
||||
this.swipeBackEnabled = this.config.getBoolean('swipeBackEnabled', this.mode === 'ios');
|
||||
this.swipeBackEnabled = this.config.getBoolean(
|
||||
'swipeBackEnabled',
|
||||
this.mode === 'ios'
|
||||
);
|
||||
}
|
||||
if (this.animated === undefined) {
|
||||
this.animated = this.config.getBoolean('animate', true);
|
||||
@ -79,44 +150,91 @@ export class Nav implements NavOutlet {
|
||||
this.destroyed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a new component onto the current navigation stack. Pass any aditional information along as an object. This additional information is accessible through NavParams
|
||||
*/
|
||||
@Method()
|
||||
push(component: NavComponent, componentProps?: ComponentProps|null, opts?: NavOptions|null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
return this.queueTrns({
|
||||
insertStart: -1,
|
||||
insertViews: [{ page: component, params: componentProps }],
|
||||
opts: opts,
|
||||
}, done);
|
||||
push(
|
||||
component: NavComponent,
|
||||
componentProps?: ComponentProps | null,
|
||||
opts?: NavOptions | null,
|
||||
done?: TransitionDoneFn
|
||||
): Promise<boolean> {
|
||||
return this.queueTrns(
|
||||
{
|
||||
insertStart: -1,
|
||||
insertViews: [{ page: component, params: componentProps }],
|
||||
opts: opts
|
||||
},
|
||||
done
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a component into the nav stack at the specified index. This is useful if you need to add a component at any point in your navigation stack.
|
||||
*/
|
||||
@Method()
|
||||
insert(insertIndex: number, component: NavComponent, componentProps?: ComponentProps|null, opts?: NavOptions|null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
return this.queueTrns({
|
||||
insertStart: insertIndex,
|
||||
insertViews: [{ page: component, params: componentProps }],
|
||||
opts: opts,
|
||||
}, done);
|
||||
insert(
|
||||
insertIndex: number,
|
||||
component: NavComponent,
|
||||
componentProps?: ComponentProps | null,
|
||||
opts?: NavOptions | null,
|
||||
done?: TransitionDoneFn
|
||||
): Promise<boolean> {
|
||||
return this.queueTrns(
|
||||
{
|
||||
insertStart: insertIndex,
|
||||
insertViews: [{ page: component, params: componentProps }],
|
||||
opts: opts
|
||||
},
|
||||
done
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an array of components into the nav stack at the specified index. The last component in the array will become instantiated as a view, and animate in to become the active view.
|
||||
*/
|
||||
@Method()
|
||||
insertPages(insertIndex: number, insertComponents: NavComponent[], opts?: NavOptions|null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
return this.queueTrns({
|
||||
insertStart: insertIndex,
|
||||
insertViews: insertComponents,
|
||||
opts: opts,
|
||||
}, done);
|
||||
insertPages(
|
||||
insertIndex: number,
|
||||
insertComponents: NavComponent[],
|
||||
opts?: NavOptions | null,
|
||||
done?: TransitionDoneFn
|
||||
): Promise<boolean> {
|
||||
return this.queueTrns(
|
||||
{
|
||||
insertStart: insertIndex,
|
||||
insertViews: insertComponents,
|
||||
opts: opts
|
||||
},
|
||||
done
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call to navigate back from a current component. Similar to push(), you can also pass navigation options.
|
||||
*/
|
||||
@Method()
|
||||
pop(opts?: NavOptions|null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
return this.queueTrns({
|
||||
removeStart: -1,
|
||||
removeCount: 1,
|
||||
opts: opts,
|
||||
}, done);
|
||||
pop(opts?: NavOptions | null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
return this.queueTrns(
|
||||
{
|
||||
removeStart: -1,
|
||||
removeCount: 1,
|
||||
opts: opts
|
||||
},
|
||||
done
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop to a specific index in the navigation stack
|
||||
*/
|
||||
@Method()
|
||||
popTo(indexOrViewCtrl: number | ViewController, opts?: NavOptions|null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
popTo(
|
||||
indexOrViewCtrl: number | ViewController,
|
||||
opts?: NavOptions | null,
|
||||
done?: TransitionDoneFn
|
||||
): Promise<boolean> {
|
||||
const config: TransitionInstruction = {
|
||||
removeStart: -1,
|
||||
removeCount: -1,
|
||||
@ -131,31 +249,70 @@ export class Nav implements NavOutlet {
|
||||
return this.queueTrns(config, done);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate back to the root of the stack, no matter how far back that is.
|
||||
*/
|
||||
@Method()
|
||||
popToRoot(opts?: NavOptions|null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
return this.queueTrns({
|
||||
removeStart: 1,
|
||||
removeCount: -1,
|
||||
opts: opts,
|
||||
}, done);
|
||||
popToRoot(
|
||||
opts?: NavOptions | null,
|
||||
done?: TransitionDoneFn
|
||||
): Promise<boolean> {
|
||||
return this.queueTrns(
|
||||
{
|
||||
removeStart: 1,
|
||||
removeCount: -1,
|
||||
opts: opts
|
||||
},
|
||||
done
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a page from the nav stack at the specified index.
|
||||
*/
|
||||
@Method()
|
||||
removeIndex(startIndex: number, removeCount = 1, opts?: NavOptions|null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
return this.queueTrns({
|
||||
removeStart: startIndex,
|
||||
removeCount: removeCount,
|
||||
opts: opts,
|
||||
}, done);
|
||||
removeIndex(
|
||||
startIndex: number,
|
||||
removeCount = 1,
|
||||
opts?: NavOptions | null,
|
||||
done?: TransitionDoneFn
|
||||
): Promise<boolean> {
|
||||
return this.queueTrns(
|
||||
{
|
||||
removeStart: startIndex,
|
||||
removeCount: removeCount,
|
||||
opts: opts
|
||||
},
|
||||
done
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the root for the current navigation stack.
|
||||
*/
|
||||
@Method()
|
||||
setRoot(component: NavComponent, componentProps?: ComponentProps|null, opts?: NavOptions|null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
return this.setPages([{ page: component, params: componentProps }], opts, done);
|
||||
setRoot(
|
||||
component: NavComponent,
|
||||
componentProps?: ComponentProps | null,
|
||||
opts?: NavOptions | null,
|
||||
done?: TransitionDoneFn
|
||||
): Promise<boolean> {
|
||||
return this.setPages(
|
||||
[{ page: component, params: componentProps }],
|
||||
opts,
|
||||
done
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the views of the current navigation stack and navigate to the last view. By default animations are disabled, but they can be enabled by passing options to the navigation controller.You can also pass any navigation params to the individual pages in the array.
|
||||
*/
|
||||
@Method()
|
||||
setPages(views: any[], opts?: NavOptions|null, done?: TransitionDoneFn): Promise<boolean> {
|
||||
setPages(
|
||||
views: any[],
|
||||
opts?: NavOptions | null,
|
||||
done?: TransitionDoneFn
|
||||
): Promise<boolean> {
|
||||
if (!opts) {
|
||||
opts = {};
|
||||
}
|
||||
@ -163,17 +320,25 @@ export class Nav implements NavOutlet {
|
||||
if (opts.animated !== true) {
|
||||
opts.animated = false;
|
||||
}
|
||||
return this.queueTrns({
|
||||
insertStart: 0,
|
||||
insertViews: views,
|
||||
removeStart: 0,
|
||||
removeCount: -1,
|
||||
opts: opts
|
||||
}, done);
|
||||
return this.queueTrns(
|
||||
{
|
||||
insertStart: 0,
|
||||
insertViews: views,
|
||||
removeStart: 0,
|
||||
removeCount: -1,
|
||||
opts: opts
|
||||
},
|
||||
done
|
||||
);
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Method()
|
||||
setRouteId(id: string, params: any, direction: RouterIntent): Promise<RouteWrite> {
|
||||
setRouteId(
|
||||
id: string,
|
||||
params: any,
|
||||
direction: RouterIntent
|
||||
): Promise<RouteWrite> {
|
||||
const active = this.getActive();
|
||||
if (matches(active, id, params)) {
|
||||
return Promise.resolve({
|
||||
@ -183,13 +348,13 @@ export class Nav implements NavOutlet {
|
||||
}
|
||||
|
||||
let resolve: (result: RouteWrite) => void;
|
||||
const promise = new Promise<RouteWrite>((r) => resolve = r);
|
||||
const promise = new Promise<RouteWrite>(r => (resolve = r));
|
||||
let finish: Promise<boolean>;
|
||||
const commonOpts: NavOptions = {
|
||||
updateURL: false,
|
||||
viewIsReady: (enteringEl) => {
|
||||
viewIsReady: enteringEl => {
|
||||
let mark: Function;
|
||||
const p = new Promise(r => mark = r);
|
||||
const p = new Promise(r => (mark = r));
|
||||
resolve({
|
||||
changed: true,
|
||||
element: enteringEl,
|
||||
@ -208,51 +373,76 @@ export class Nav implements NavOutlet {
|
||||
const viewController = this.views.find(v => matches(v, id, params));
|
||||
|
||||
if (viewController) {
|
||||
finish = this.popTo(viewController, {...commonOpts, direction: 'back'});
|
||||
finish = this.popTo(viewController, {
|
||||
...commonOpts,
|
||||
direction: 'back'
|
||||
});
|
||||
} else if (direction === 1) {
|
||||
finish = this.push(id, params, commonOpts);
|
||||
} else if (direction === -1) {
|
||||
finish = this.setRoot(id, params, {...commonOpts, direction: 'back', animated: true});
|
||||
finish = this.setRoot(id, params, {
|
||||
...commonOpts,
|
||||
direction: 'back',
|
||||
animated: true
|
||||
});
|
||||
}
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
@Method()
|
||||
getRouteId(): RouteID|undefined {
|
||||
getRouteId(): RouteID | undefined {
|
||||
const active = this.getActive();
|
||||
return active ? {
|
||||
id: active.element!.tagName,
|
||||
params: active.params,
|
||||
element: active.element
|
||||
} : undefined;
|
||||
return active
|
||||
? {
|
||||
id: active.element!.tagName,
|
||||
params: active.params,
|
||||
element: active.element
|
||||
}
|
||||
: undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true or false if the current view can go back
|
||||
*/
|
||||
@Method()
|
||||
canGoBack(view = this.getActive()): boolean {
|
||||
return !!(view && this.getPrevious(view));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the active view
|
||||
*/
|
||||
@Method()
|
||||
getActive(): ViewController|undefined {
|
||||
getActive(): ViewController | undefined {
|
||||
return this.views[this.views.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the view at the index
|
||||
*/
|
||||
@Method()
|
||||
getByIndex(index: number): ViewController|undefined {
|
||||
getByIndex(index: number): ViewController | undefined {
|
||||
return this.views[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the previous view
|
||||
*/
|
||||
@Method()
|
||||
getPrevious(view = this.getActive()): ViewController|undefined {
|
||||
getPrevious(view = this.getActive()): ViewController | undefined {
|
||||
if (!view) {
|
||||
return undefined;
|
||||
}
|
||||
const views = this.views;
|
||||
const index = views.indexOf(view);
|
||||
return (index > 0) ? views[index - 1] : undefined;
|
||||
return index > 0 ? views[index - 1] : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of navigation stack
|
||||
*/
|
||||
@Method()
|
||||
length() {
|
||||
return this.views.length;
|
||||
@ -268,7 +458,10 @@ export class Nav implements NavOutlet {
|
||||
// 7. _transitionStart(): called once the transition actually starts, it initializes the Animation underneath.
|
||||
// 8. _transitionFinish(): called once the transition finishes
|
||||
// 9. _cleanup(): syncs the navigation internal state with the DOM. For example it removes the pages from the DOM or hides/show them.
|
||||
private queueTrns(ti: TransitionInstruction, done: TransitionDoneFn|undefined): Promise<boolean> {
|
||||
private queueTrns(
|
||||
ti: TransitionInstruction,
|
||||
done: TransitionDoneFn | undefined
|
||||
): Promise<boolean> {
|
||||
const promise = new Promise<boolean>((resolve, reject) => {
|
||||
ti.resolve = resolve;
|
||||
ti.reject = reject;
|
||||
@ -310,9 +503,7 @@ export class Nav implements NavOutlet {
|
||||
if (ti.opts!.updateURL !== false && this.useRouter) {
|
||||
const router = this.win.document.querySelector('ion-router');
|
||||
if (router) {
|
||||
const direction = (result.direction === 'back')
|
||||
? -1
|
||||
: 1;
|
||||
const direction = result.direction === 'back' ? -1 : 1;
|
||||
|
||||
router.navChanged(direction);
|
||||
}
|
||||
@ -377,17 +568,19 @@ export class Nav implements NavOutlet {
|
||||
this.postViewInit(enteringView, leavingView, ti);
|
||||
|
||||
// Needs transition?
|
||||
const requiresTransition = (ti.enteringRequiresTransition || ti.leavingRequiresTransition) && enteringView !== leavingView;
|
||||
const requiresTransition =
|
||||
(ti.enteringRequiresTransition || ti.leavingRequiresTransition) &&
|
||||
enteringView !== leavingView;
|
||||
const result = requiresTransition
|
||||
? await this.transition(enteringView!, leavingView, ti)
|
||||
: {
|
||||
// transition is not required, so we are already done!
|
||||
// they're inserting/removing the views somewhere in the middle or
|
||||
// beginning, so visually nothing needs to animate/transition
|
||||
// resolve immediately because there's no animation that's happening
|
||||
hasCompleted: true,
|
||||
requiresTransition: false
|
||||
};
|
||||
// transition is not required, so we are already done!
|
||||
// they're inserting/removing the views somewhere in the middle or
|
||||
// beginning, so visually nothing needs to animate/transition
|
||||
// resolve immediately because there's no animation that's happening
|
||||
hasCompleted: true,
|
||||
requiresTransition: false
|
||||
};
|
||||
|
||||
this.success(result, ti);
|
||||
this.ionNavDidChange.emit();
|
||||
@ -418,12 +611,13 @@ export class Nav implements NavOutlet {
|
||||
}
|
||||
if (ti.removeStart != null) {
|
||||
if (ti.removeStart < 0) {
|
||||
ti.removeStart = (viewsLength - 1);
|
||||
ti.removeStart = viewsLength - 1;
|
||||
}
|
||||
if (ti.removeCount! < 0) {
|
||||
ti.removeCount = (viewsLength - ti.removeStart);
|
||||
ti.removeCount = viewsLength - ti.removeStart;
|
||||
}
|
||||
ti.leavingRequiresTransition = (ti.removeCount! > 0) && ((ti.removeStart + ti.removeCount!) === viewsLength);
|
||||
ti.leavingRequiresTransition =
|
||||
ti.removeCount! > 0 && ti.removeStart + ti.removeCount! === viewsLength;
|
||||
}
|
||||
|
||||
if (ti.insertViews) {
|
||||
@ -432,7 +626,7 @@ export class Nav implements NavOutlet {
|
||||
if (ti.insertStart! < 0 || ti.insertStart! > viewsLength) {
|
||||
ti.insertStart = viewsLength;
|
||||
}
|
||||
ti.enteringRequiresTransition = (ti.insertStart === viewsLength);
|
||||
ti.enteringRequiresTransition = ti.insertStart === viewsLength;
|
||||
}
|
||||
|
||||
const insertViews = ti.insertViews;
|
||||
@ -460,7 +654,10 @@ export class Nav implements NavOutlet {
|
||||
ti.insertViews = viewControllers;
|
||||
}
|
||||
|
||||
private getEnteringView(ti: TransitionInstruction, leavingView: ViewController|undefined): ViewController|undefined {
|
||||
private getEnteringView(
|
||||
ti: TransitionInstruction,
|
||||
leavingView: ViewController | undefined
|
||||
): ViewController | undefined {
|
||||
const insertViews = ti.insertViews;
|
||||
if (insertViews) {
|
||||
// grab the very last view of the views to be inserted
|
||||
@ -482,8 +679,15 @@ export class Nav implements NavOutlet {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private postViewInit(enteringView: ViewController|undefined, leavingView: ViewController|undefined, ti: TransitionInstruction) {
|
||||
assert(leavingView || enteringView, 'Both leavingView and enteringView are null');
|
||||
private postViewInit(
|
||||
enteringView: ViewController | undefined,
|
||||
leavingView: ViewController | undefined,
|
||||
ti: TransitionInstruction
|
||||
) {
|
||||
assert(
|
||||
leavingView || enteringView,
|
||||
'Both leavingView and enteringView are null'
|
||||
);
|
||||
assert(ti.resolve, 'resolve must be valid');
|
||||
assert(ti.reject, 'reject must be valid');
|
||||
|
||||
@ -491,7 +695,7 @@ export class Nav implements NavOutlet {
|
||||
const insertViews = ti.insertViews;
|
||||
const removeStart = ti.removeStart;
|
||||
const removeCount = ti.removeCount;
|
||||
let destroyQueue: ViewController[]|undefined = undefined;
|
||||
let destroyQueue: ViewController[] | undefined = undefined;
|
||||
|
||||
// there are views to remove
|
||||
if (removeStart != null && removeCount != null) {
|
||||
@ -509,11 +713,17 @@ export class Nav implements NavOutlet {
|
||||
opts.direction = opts.direction || 'back';
|
||||
}
|
||||
|
||||
const finalBalance = this.views.length + (insertViews ? insertViews.length : 0) - (removeCount ? removeCount : 0);
|
||||
const finalBalance =
|
||||
this.views.length +
|
||||
(insertViews ? insertViews.length : 0) -
|
||||
(removeCount ? removeCount : 0);
|
||||
assert(finalBalance >= 0, 'final balance can not be negative');
|
||||
if (finalBalance === 0) {
|
||||
console.warn(`You can't remove all the pages in the navigation stack. nav.pop() is probably called too many times.`,
|
||||
this, this.el);
|
||||
console.warn(
|
||||
`You can't remove all the pages in the navigation stack. nav.pop() is probably called too many times.`,
|
||||
this,
|
||||
this.el
|
||||
);
|
||||
|
||||
throw new Error('navigation stack needs at least one root page');
|
||||
}
|
||||
@ -553,7 +763,11 @@ export class Nav implements NavOutlet {
|
||||
}
|
||||
}
|
||||
|
||||
private async transition(enteringView: ViewController, leavingView: ViewController|undefined, ti: TransitionInstruction): Promise<NavResult> {
|
||||
private async transition(
|
||||
enteringView: ViewController,
|
||||
leavingView: ViewController | undefined,
|
||||
ti: TransitionInstruction
|
||||
): Promise<NavResult> {
|
||||
if (this.sbTrns) {
|
||||
this.sbTrns.destroy();
|
||||
this.sbTrns = undefined;
|
||||
@ -564,7 +778,9 @@ export class Nav implements NavOutlet {
|
||||
const opts = ti.opts!;
|
||||
|
||||
const progressCallback = opts.progressAnimation
|
||||
? (animation: Animation) => { this.sbTrns = animation; }
|
||||
? (animation: Animation) => {
|
||||
this.sbTrns = animation;
|
||||
}
|
||||
: undefined;
|
||||
|
||||
const enteringEl = enteringView.element!;
|
||||
@ -586,7 +802,12 @@ export class Nav implements NavOutlet {
|
||||
return this.transitionFinish(trns, enteringView, leavingView, opts);
|
||||
}
|
||||
|
||||
private transitionFinish(transition: Animation|null, enteringView: ViewController, leavingView: ViewController | undefined, opts: NavOptions): NavResult {
|
||||
private transitionFinish(
|
||||
transition: Animation | null,
|
||||
enteringView: ViewController,
|
||||
leavingView: ViewController | undefined,
|
||||
opts: NavOptions
|
||||
): NavResult {
|
||||
const hasCompleted = transition ? transition.hasCompleted : true;
|
||||
|
||||
const cleanupView = hasCompleted ? enteringView : leavingView;
|
||||
@ -627,7 +848,10 @@ export class Nav implements NavOutlet {
|
||||
}
|
||||
|
||||
private removeView(view: ViewController) {
|
||||
assert(view.state === ViewState.Attached || view.state === ViewState.Destroyed, 'view state should be loaded or destroyed');
|
||||
assert(
|
||||
view.state === ViewState.Attached || view.state === ViewState.Destroyed,
|
||||
'view state should be loaded or destroyed'
|
||||
);
|
||||
|
||||
const views = this.views;
|
||||
const index = views.indexOf(view);
|
||||
@ -662,7 +886,6 @@ export class Nav implements NavOutlet {
|
||||
// let's unload it
|
||||
lifecycle(this.win, view.element, ViewLifecycle.WillUnload);
|
||||
this.destroyView(view);
|
||||
|
||||
} else if (i < activeViewIndex) {
|
||||
// this view comes before the active view
|
||||
// and it is not a portal then ensure it is hidden
|
||||
@ -682,11 +905,14 @@ export class Nav implements NavOutlet {
|
||||
progressAnimation: true
|
||||
};
|
||||
|
||||
this.queueTrns({
|
||||
removeStart: -1,
|
||||
removeCount: 1,
|
||||
opts: opts,
|
||||
}, undefined);
|
||||
this.queueTrns(
|
||||
{
|
||||
removeStart: -1,
|
||||
removeCount: 1,
|
||||
opts: opts
|
||||
},
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
private swipeBackProgress(detail: GestureDetail) {
|
||||
@ -710,8 +936,8 @@ export class Nav implements NavOutlet {
|
||||
const stepValue = delta / width;
|
||||
const velocity = detail.velocityX;
|
||||
const z = width / 2.0;
|
||||
const shouldComplete = (velocity >= 0)
|
||||
&& (velocity > 0.2 || detail.deltaX > z);
|
||||
const shouldComplete =
|
||||
velocity >= 0 && (velocity > 0.2 || detail.deltaX > z);
|
||||
|
||||
const missing = shouldComplete ? 1 - stepValue : stepValue;
|
||||
const missingDistance = missing * width;
|
||||
@ -726,16 +952,12 @@ export class Nav implements NavOutlet {
|
||||
}
|
||||
|
||||
private canSwipeBack(): boolean {
|
||||
return (
|
||||
!!this.swipeBackEnabled &&
|
||||
!this.isTransitioning &&
|
||||
this.canGoBack()
|
||||
);
|
||||
return !!this.swipeBackEnabled && !this.isTransitioning && this.canGoBack();
|
||||
}
|
||||
|
||||
render() {
|
||||
return [
|
||||
this.swipeBackEnabled &&
|
||||
this.swipeBackEnabled && (
|
||||
<ion-gesture
|
||||
canStart={this.canSwipeBack.bind(this)}
|
||||
onStart={this.swipeBackStart.bind(this)}
|
||||
@ -745,9 +967,11 @@ export class Nav implements NavOutlet {
|
||||
gesturePriority={10}
|
||||
direction="x"
|
||||
threshold={10}
|
||||
attachTo="body"/>,
|
||||
this.mode === 'ios' && <div class="nav-decor"/>,
|
||||
<slot></slot>
|
||||
attachTo="body"
|
||||
/>
|
||||
),
|
||||
this.mode === 'ios' && <div class="nav-decor" />,
|
||||
<slot />
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { Component, Prop } from '@stencil/core';
|
||||
import { Color, Mode } from '../../interface';
|
||||
|
||||
|
||||
@Component({
|
||||
tag: 'ion-note',
|
||||
styleUrls: {
|
||||
@ -13,19 +12,15 @@ import { Color, Mode } from '../../interface';
|
||||
}
|
||||
})
|
||||
export class Note {
|
||||
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
@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;
|
||||
|
||||
}
|
||||
|
@ -2,31 +2,6 @@
|
||||
|
||||
Notes are text elements generally used as subtitles that provide more information. Notes are styled to appear grey by default.
|
||||
|
||||
```html
|
||||
<!-- Default Note -->
|
||||
<ion-note>Default Note</ion-note>
|
||||
|
||||
<!-- Note Colors -->
|
||||
<ion-note color="primary">Primary Note</ion-note>
|
||||
<ion-note color="secondary">Secondary Note</ion-note>
|
||||
<ion-note color="danger">Danger Note</ion-note>
|
||||
<ion-note color="light">Light Note</ion-note>
|
||||
<ion-note color="dark">Dark Note</ion-note>
|
||||
|
||||
<!-- Notes in a List -->
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label>Note (End)</ion-label>
|
||||
<ion-note slot="end">On</ion-note>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-note slot="start">Off</ion-note>
|
||||
<ion-label>Note (Start)</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
```
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
24
core/src/components/note/usage/javascript.md
Normal file
24
core/src/components/note/usage/javascript.md
Normal file
@ -0,0 +1,24 @@
|
||||
```html
|
||||
<!-- Default Note -->
|
||||
<ion-note>Default Note</ion-note>
|
||||
|
||||
<!-- Note Colors -->
|
||||
<ion-note color="primary">Primary Note</ion-note>
|
||||
<ion-note color="secondary">Secondary Note</ion-note>
|
||||
<ion-note color="danger">Danger Note</ion-note>
|
||||
<ion-note color="light">Light Note</ion-note>
|
||||
<ion-note color="dark">Dark Note</ion-note>
|
||||
|
||||
<!-- Notes in a List -->
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-label>Note (End)</ion-label>
|
||||
<ion-note slot="end">On</ion-note>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-note slot="start">Off</ion-note>
|
||||
<ion-label>Note (Start)</ion-label>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
```
|
@ -1,7 +1,30 @@
|
||||
import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core';
|
||||
import { Animation, AnimationBuilder, Config, CssClassMap, Mode, PickerButton, PickerColumn } from '../../interface';
|
||||
import {
|
||||
Component,
|
||||
Element,
|
||||
Event,
|
||||
EventEmitter,
|
||||
Listen,
|
||||
Method,
|
||||
Prop,
|
||||
State
|
||||
} from '@stencil/core';
|
||||
import {
|
||||
Animation,
|
||||
AnimationBuilder,
|
||||
Config,
|
||||
CssClassMap,
|
||||
Mode,
|
||||
PickerButton,
|
||||
PickerColumn
|
||||
} from '../../interface';
|
||||
|
||||
import { OverlayEventDetail, OverlayInterface, dismiss, eventMethod, present } from '../../utils/overlays';
|
||||
import {
|
||||
OverlayEventDetail,
|
||||
OverlayInterface,
|
||||
dismiss,
|
||||
eventMethod,
|
||||
present
|
||||
} from '../../utils/overlays';
|
||||
import { getClassMap } from '../../utils/theme';
|
||||
|
||||
import { iosEnterAnimation } from './animations/ios.enter';
|
||||
@ -18,7 +41,6 @@ import { iosLeaveAnimation } from './animations/ios.leave';
|
||||
}
|
||||
})
|
||||
export class Picker implements OverlayInterface {
|
||||
|
||||
private durationTimeout: any;
|
||||
|
||||
mode!: Mode;
|
||||
@ -30,9 +52,18 @@ export class Picker implements OverlayInterface {
|
||||
@State() private showSpinner!: boolean;
|
||||
@State() private spinner!: string;
|
||||
|
||||
@Prop({ connect: 'ion-animation-controller' }) animationCtrl!: HTMLIonAnimationControllerElement;
|
||||
@Prop({ context: 'config' }) config!: Config;
|
||||
@Prop({ connect: 'ion-animation-controller' })
|
||||
animationCtrl!: HTMLIonAnimationControllerElement;
|
||||
|
||||
@Prop({ context: 'config' })
|
||||
config!: Config;
|
||||
|
||||
/** @hidden */
|
||||
@Prop() overlayId!: number;
|
||||
|
||||
/**
|
||||
* If the keyboard should be able to close the picker. Defaults to true.
|
||||
*/
|
||||
@Prop() keyboardClose = true;
|
||||
|
||||
/**
|
||||
@ -89,32 +120,35 @@ export class Picker implements OverlayInterface {
|
||||
/**
|
||||
* Emitted after the picker has presented.
|
||||
*/
|
||||
@Event({eventName: 'ionPickerDidPresent'}) didPresent!: EventEmitter<void>;
|
||||
@Event({ eventName: 'ionPickerDidPresent' })
|
||||
didPresent!: EventEmitter<void>;
|
||||
|
||||
/**
|
||||
* Emitted before the picker has presented.
|
||||
*/
|
||||
@Event({eventName: 'ionPickerWillPresent'}) willPresent!: EventEmitter<void>;
|
||||
@Event({ eventName: 'ionPickerWillPresent' })
|
||||
willPresent!: EventEmitter<void>;
|
||||
|
||||
/**
|
||||
* Emitted before the picker has dismissed.
|
||||
*/
|
||||
@Event({eventName: 'ionPickerWillDismiss'}) willDismiss!: EventEmitter<OverlayEventDetail>;
|
||||
@Event({ eventName: 'ionPickerWillDismiss' })
|
||||
willDismiss!: EventEmitter<OverlayEventDetail>;
|
||||
|
||||
/**
|
||||
* Emitted after the picker has dismissed.
|
||||
*/
|
||||
@Event({eventName: 'ionPickerDidDismiss'}) didDismiss!: EventEmitter<OverlayEventDetail>;
|
||||
@Event({ eventName: 'ionPickerDidDismiss' })
|
||||
didDismiss!: EventEmitter<OverlayEventDetail>;
|
||||
|
||||
/**
|
||||
* Emitted after the picker has unloaded.
|
||||
*/
|
||||
@Event() ionPickerDidUnload!: EventEmitter<void>;
|
||||
|
||||
|
||||
componentWillLoad() {
|
||||
if (!this.spinner) {
|
||||
const defaultSpinner = (this.mode === 'ios') ? 'lines' : 'crescent';
|
||||
const defaultSpinner = this.mode === 'ios' ? 'lines' : 'crescent';
|
||||
this.spinner = this.config.get('pickerSpinner', defaultSpinner);
|
||||
}
|
||||
if (this.showSpinner === undefined) {
|
||||
@ -145,7 +179,13 @@ export class Picker implements OverlayInterface {
|
||||
*/
|
||||
@Method()
|
||||
async present(): Promise<void> {
|
||||
await present(this, 'pickerEnter', iosEnterAnimation, iosEnterAnimation, undefined);
|
||||
await present(
|
||||
this,
|
||||
'pickerEnter',
|
||||
iosEnterAnimation,
|
||||
iosEnterAnimation,
|
||||
undefined
|
||||
);
|
||||
|
||||
if (this.duration) {
|
||||
this.durationTimeout = setTimeout(() => this.dismiss(), this.duration);
|
||||
@ -160,7 +200,14 @@ export class Picker implements OverlayInterface {
|
||||
if (this.durationTimeout) {
|
||||
clearTimeout(this.durationTimeout);
|
||||
}
|
||||
return dismiss(this, data, role, 'pickerLeave', iosLeaveAnimation, iosLeaveAnimation);
|
||||
return dismiss(
|
||||
this,
|
||||
data,
|
||||
role,
|
||||
'pickerLeave',
|
||||
iosLeaveAnimation,
|
||||
iosLeaveAnimation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,7 +216,9 @@ export class Picker implements OverlayInterface {
|
||||
*
|
||||
*/
|
||||
@Method()
|
||||
onDidDismiss(callback?: (detail: OverlayEventDetail) => void): Promise<OverlayEventDetail> {
|
||||
onDidDismiss(
|
||||
callback?: (detail: OverlayEventDetail) => void
|
||||
): Promise<OverlayEventDetail> {
|
||||
return eventMethod(this.el, 'ionPickerDidDismiss', callback);
|
||||
}
|
||||
|
||||
@ -179,25 +228,39 @@ export class Picker implements OverlayInterface {
|
||||
*
|
||||
*/
|
||||
@Method()
|
||||
onWillDismiss(callback?: (detail: OverlayEventDetail) => void): Promise<OverlayEventDetail> {
|
||||
onWillDismiss(
|
||||
callback?: (detail: OverlayEventDetail) => void
|
||||
): Promise<OverlayEventDetail> {
|
||||
return eventMethod(this.el, 'ionPickerWillDismiss', callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new PickerButton to the picker
|
||||
*/
|
||||
@Method()
|
||||
addButton(button: PickerButton) {
|
||||
this.buttons.push(button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new PickerColumn to the picker
|
||||
*/
|
||||
@Method()
|
||||
addColumn(column: PickerColumn) {
|
||||
this.columns.push(column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column the matches the specified name
|
||||
*/
|
||||
@Method()
|
||||
getColumn(name: string): PickerColumn|undefined {
|
||||
getColumn(name: string): PickerColumn | undefined {
|
||||
return this.columns.find(column => column.name === name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the PickerColumns
|
||||
*/
|
||||
@Method()
|
||||
getColumns(): PickerColumn[] {
|
||||
return this.columns;
|
||||
@ -226,13 +289,15 @@ export class Picker implements OverlayInterface {
|
||||
}
|
||||
|
||||
private getSelected() {
|
||||
const selected: {[k: string]: any} = {};
|
||||
const selected: { [k: string]: any } = {};
|
||||
this.columns.forEach((col, index) => {
|
||||
const selectedColumn = col.selectedIndex ? col.options[col.selectedIndex] : null;
|
||||
const selectedColumn = col.selectedIndex
|
||||
? col.options[col.selectedIndex]
|
||||
: null;
|
||||
selected[col.name] = {
|
||||
text: selectedColumn ? selectedColumn.text : null,
|
||||
value: selectedColumn ? selectedColumn.value : null,
|
||||
columnIndex: index,
|
||||
columnIndex: index
|
||||
};
|
||||
});
|
||||
return selected;
|
||||
@ -241,7 +306,7 @@ export class Picker implements OverlayInterface {
|
||||
hostData() {
|
||||
return {
|
||||
style: {
|
||||
zIndex: 20000 + this.overlayId,
|
||||
zIndex: 20000 + this.overlayId
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -249,16 +314,17 @@ export class Picker implements OverlayInterface {
|
||||
render() {
|
||||
// TODO: cssClass
|
||||
|
||||
const buttons = this.buttons.map(b => {
|
||||
if (typeof b === 'string') {
|
||||
b = { text: b };
|
||||
}
|
||||
if (!b.cssClass) {
|
||||
b.cssClass = '';
|
||||
}
|
||||
return b;
|
||||
})
|
||||
.filter(b => b !== null);
|
||||
const buttons = this.buttons
|
||||
.map(b => {
|
||||
if (typeof b === 'string') {
|
||||
b = { text: b };
|
||||
}
|
||||
if (!b.cssClass) {
|
||||
b.cssClass = '';
|
||||
}
|
||||
return b;
|
||||
})
|
||||
.filter(b => b !== null);
|
||||
|
||||
const columns = this.columns;
|
||||
|
||||
@ -292,23 +358,27 @@ export class Picker implements OverlayInterface {
|
||||
// });
|
||||
|
||||
return [
|
||||
<ion-backdrop visible={this.showBackdrop} tappable={this.enableBackdropDismiss}/>,
|
||||
<ion-backdrop
|
||||
visible={this.showBackdrop}
|
||||
tappable={this.enableBackdropDismiss}
|
||||
/>,
|
||||
<div class="picker-wrapper" role="dialog">
|
||||
<div class="picker-toolbar">
|
||||
{buttons.map(b =>
|
||||
{buttons.map(b => (
|
||||
<div class={buttonWrapperClass(b)}>
|
||||
<button onClick={() => this.buttonClick(b)} class={buttonClass(b)}>
|
||||
<button
|
||||
onClick={() => this.buttonClick(b)}
|
||||
class={buttonClass(b)}
|
||||
>
|
||||
{b.text}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
))}
|
||||
</div>
|
||||
<div class="picker-columns">
|
||||
<div class="picker-above-highlight"></div>
|
||||
{columns.map(c =>
|
||||
<ion-picker-column col={c}></ion-picker-column>
|
||||
)}
|
||||
<div class="picker-below-highlight"></div>
|
||||
<div class="picker-above-highlight" />
|
||||
{columns.map(c => <ion-picker-column col={c} />)}
|
||||
<div class="picker-below-highlight" />
|
||||
</div>
|
||||
</div>
|
||||
];
|
||||
@ -317,7 +387,7 @@ export class Picker implements OverlayInterface {
|
||||
|
||||
function buttonWrapperClass(button: PickerButton): CssClassMap {
|
||||
const buttonClass: CssClassMap = {
|
||||
'picker-toolbar-button': true,
|
||||
'picker-toolbar-button': true
|
||||
};
|
||||
if (button.role) {
|
||||
buttonClass[`picker-toolbar-${button.role}`] = true;
|
||||
|
@ -6,44 +6,6 @@ button that belongs to a radio group unchecks any previous checked
|
||||
radio button within the same group.
|
||||
|
||||
|
||||
```html
|
||||
<ion-list>
|
||||
|
||||
<ion-radio-group>
|
||||
|
||||
<ion-list-header>
|
||||
Auto Manufacturers
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Cord</ion-label>
|
||||
<ion-radio value="cord"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Duesenberg</ion-label>
|
||||
<ion-radio value="duesenberg"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Hudson</ion-label>
|
||||
<ion-radio value="hudson"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Packard</ion-label>
|
||||
<ion-radio value="packard"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Studebaker</ion-label>
|
||||
<ion-radio value="studebaker"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
</ion-radio-group>
|
||||
|
||||
</ion-list>
|
||||
```
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
38
core/src/components/radio-group/usage/javascript.md
Normal file
38
core/src/components/radio-group/usage/javascript.md
Normal file
@ -0,0 +1,38 @@
|
||||
```html
|
||||
<ion-list>
|
||||
|
||||
<ion-radio-group>
|
||||
|
||||
<ion-list-header>
|
||||
Auto Manufacturers
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Cord</ion-label>
|
||||
<ion-radio value="cord"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Duesenberg</ion-label>
|
||||
<ion-radio value="duesenberg"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Hudson</ion-label>
|
||||
<ion-radio value="hudson"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Packard</ion-label>
|
||||
<ion-radio value="packard"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Studebaker</ion-label>
|
||||
<ion-radio value="studebaker"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
</ion-radio-group>
|
||||
|
||||
</ion-list>
|
||||
```
|
@ -24,14 +24,12 @@ export class Radio implements RadioButtonInput {
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
@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;
|
||||
|
||||
|
@ -5,30 +5,6 @@ Radios are generally used as a set of related options inside of a group, but the
|
||||
An `ion-radio-group` can be used to group a set of radios. When radios are inside of a [radio group](../radio-group), only one radio in the group will be checked at any time. Pressing a radio will check it and uncheck the previously selected radio, if there is one. If a radio is not in a group with another radio, then both radios will have the ability to be checked at the same time.
|
||||
|
||||
|
||||
```html
|
||||
<ion-list>
|
||||
<ion-radio-group>
|
||||
<ion-list-header>
|
||||
<ion-label>Name</ion-label>
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Biff</ion-label>
|
||||
<ion-radio slot="start" value="biff" checked></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Griff</ion-label>
|
||||
<ion-radio slot="start" value="griff"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Buford</ion-label>
|
||||
<ion-radio slot="start" value="buford"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
</ion-list>
|
||||
```
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
24
core/src/components/radio/usage/javascript.md
Normal file
24
core/src/components/radio/usage/javascript.md
Normal file
@ -0,0 +1,24 @@
|
||||
```html
|
||||
<ion-list>
|
||||
<ion-radio-group>
|
||||
<ion-list-header>
|
||||
<ion-label>Name</ion-label>
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Biff</ion-label>
|
||||
<ion-radio slot="start" value="biff" checked></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Griff</ion-label>
|
||||
<ion-radio slot="start" value="griff"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Buford</ion-label>
|
||||
<ion-radio slot="start" value="buford"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
</ion-list>
|
||||
```
|
@ -1,5 +1,6 @@
|
||||
# ion-range-knob
|
||||
|
||||
RangeKnob is an internal component of Range.
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
@ -1,5 +1,21 @@
|
||||
import { Component, Element, Event, EventEmitter, Listen, Prop, State, Watch } from '@stencil/core';
|
||||
import { BaseInput, Color, GestureDetail, Mode, RangeInputChangeEvent, StyleEvent } from '../../interface';
|
||||
import {
|
||||
Component,
|
||||
Element,
|
||||
Event,
|
||||
EventEmitter,
|
||||
Listen,
|
||||
Prop,
|
||||
State,
|
||||
Watch
|
||||
} from '@stencil/core';
|
||||
import {
|
||||
BaseInput,
|
||||
Color,
|
||||
GestureDetail,
|
||||
Mode,
|
||||
RangeInputChangeEvent,
|
||||
StyleEvent
|
||||
} from '../../interface';
|
||||
import { clamp, debounceEvent, deferEvent } from '../../utils/helpers';
|
||||
import { Knob, RangeEventDetail, RangeValue } from './range-interface';
|
||||
|
||||
@ -14,7 +30,6 @@ import { Knob, RangeEventDetail, RangeValue } from './range-interface';
|
||||
}
|
||||
})
|
||||
export class Range implements BaseInput {
|
||||
|
||||
private noUpdate = false;
|
||||
private rect!: ClientRect;
|
||||
private hasFocus = false;
|
||||
@ -28,14 +43,12 @@ export class Range implements BaseInput {
|
||||
/**
|
||||
* 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).
|
||||
*/
|
||||
@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;
|
||||
|
||||
@ -99,16 +112,16 @@ export class Range implements BaseInput {
|
||||
/**
|
||||
* the value of the range.
|
||||
*/
|
||||
@Prop({ mutable: true }) value: any = 0;
|
||||
@Prop({ mutable: true })
|
||||
value: any = 0;
|
||||
@Watch('value')
|
||||
protected valueChanged(value: RangeValue) {
|
||||
if (!this.noUpdate) {
|
||||
this.updateRatio();
|
||||
}
|
||||
this.ionChange.emit({value});
|
||||
this.ionChange.emit({ value });
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emitted when the value property has changed.
|
||||
*/
|
||||
@ -129,7 +142,6 @@ export class Range implements BaseInput {
|
||||
*/
|
||||
@Event() ionBlur!: EventEmitter<void>;
|
||||
|
||||
|
||||
componentWillLoad() {
|
||||
this.ionStyle = deferEvent(this.ionStyle);
|
||||
|
||||
@ -162,7 +174,7 @@ export class Range implements BaseInput {
|
||||
}
|
||||
return {
|
||||
lower: 0,
|
||||
upper: value,
|
||||
upper: value
|
||||
};
|
||||
} else {
|
||||
if (typeof value === 'object') {
|
||||
@ -198,14 +210,16 @@ export class Range implements BaseInput {
|
||||
this.fireFocus();
|
||||
|
||||
const el = this.el.querySelector('.range-slider')!;
|
||||
const rect = this.rect = el.getBoundingClientRect() as any;
|
||||
const rect = (this.rect = el.getBoundingClientRect() as any);
|
||||
const currentX = detail.currentX;
|
||||
|
||||
// figure out which knob they started closer to
|
||||
const ratio = clamp(0, (currentX - rect.left) / rect.width, 1);
|
||||
this.pressedKnob = (!this.dualKnobs || (Math.abs(this.ratioA - ratio) < Math.abs(this.ratioB - ratio)))
|
||||
? Knob.A
|
||||
: Knob.B;
|
||||
this.pressedKnob =
|
||||
!this.dualKnobs ||
|
||||
Math.abs(this.ratioA - ratio) < Math.abs(this.ratioB - ratio)
|
||||
? Knob.A
|
||||
: Knob.B;
|
||||
|
||||
// update the active knob's position
|
||||
this.update(currentX);
|
||||
@ -267,7 +281,7 @@ export class Range implements BaseInput {
|
||||
|
||||
private updateRatio() {
|
||||
const value = this.getValue() as any;
|
||||
const {min, max} = this;
|
||||
const { min, max } = this;
|
||||
if (this.dualKnobs) {
|
||||
this.ratioA = valueToRatio(value.lower, min, max);
|
||||
this.ratioB = valueToRatio(value.upper, min, max);
|
||||
@ -279,13 +293,13 @@ export class Range implements BaseInput {
|
||||
private updateValue() {
|
||||
this.noUpdate = true;
|
||||
|
||||
const {valA, valB} = this;
|
||||
this.value = (!this.dualKnobs)
|
||||
const { valA, valB } = this;
|
||||
this.value = !this.dualKnobs
|
||||
? valA
|
||||
: {
|
||||
lower: Math.min(valA, valB),
|
||||
upper: Math.max(valA, valB)
|
||||
};
|
||||
lower: Math.min(valA, valB),
|
||||
upper: Math.max(valA, valB)
|
||||
};
|
||||
|
||||
this.noUpdate = false;
|
||||
}
|
||||
@ -301,7 +315,7 @@ export class Range implements BaseInput {
|
||||
}
|
||||
|
||||
render() {
|
||||
const {min, max, step, ratioLower, ratioUpper} = this;
|
||||
const { min, max, step, ratioLower, ratioUpper } = this;
|
||||
|
||||
const barL = `${ratioLower * 100}%`;
|
||||
const barR = `${100 - ratioUpper * 100}%`;
|
||||
@ -319,7 +333,7 @@ export class Range implements BaseInput {
|
||||
}
|
||||
|
||||
return [
|
||||
<slot name="start"></slot>,
|
||||
<slot name="start" />,
|
||||
<ion-gesture
|
||||
disableScroll={true}
|
||||
onStart={this.onDragStart.bind(this)}
|
||||
@ -329,18 +343,19 @@ export class Range implements BaseInput {
|
||||
gestureName="range"
|
||||
gesturePriority={30}
|
||||
direction="x"
|
||||
threshold={0}>
|
||||
|
||||
threshold={0}
|
||||
>
|
||||
<div class="range-slider">
|
||||
{ticks.map(t =>
|
||||
{ticks.map(t => (
|
||||
<div
|
||||
style={{ left: t.left }}
|
||||
role="presentation"
|
||||
class={{
|
||||
'range-tick': true,
|
||||
'range-tick-active': t.active
|
||||
}}/>
|
||||
)}
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
<div class="range-bar" role="presentation" />
|
||||
<div
|
||||
@ -358,9 +373,10 @@ export class Range implements BaseInput {
|
||||
ratio={this.ratioA}
|
||||
pin={this.pin}
|
||||
min={min}
|
||||
max={max}/>
|
||||
max={max}
|
||||
/>
|
||||
|
||||
{ this.dualKnobs &&
|
||||
{this.dualKnobs && (
|
||||
<ion-range-knob
|
||||
knob={Knob.B}
|
||||
pressed={this.pressedKnob === Knob.B}
|
||||
@ -368,17 +384,23 @@ export class Range implements BaseInput {
|
||||
ratio={this.ratioB}
|
||||
pin={this.pin}
|
||||
min={min}
|
||||
max={max} /> }
|
||||
max={max}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</ion-gesture>,
|
||||
<slot name="end"></slot>
|
||||
<slot name="end" />
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function ratioToValue(ratio: number, min: number, max: number, step: number): number {
|
||||
let value = ((max - min) * ratio);
|
||||
export function ratioToValue(
|
||||
ratio: number,
|
||||
min: number,
|
||||
max: number,
|
||||
step: number
|
||||
): number {
|
||||
let value = (max - min) * ratio;
|
||||
if (step > 0) {
|
||||
value = Math.round(value / step) * step + min;
|
||||
}
|
||||
|
@ -9,39 +9,8 @@ controls the value of the range.
|
||||
Labels can be placed on either side of the range by adding the
|
||||
`slot="start"` or `slot="end"` to the element. The element doesn't have to
|
||||
be an `ion-label`, it can be added to any element to place it to the
|
||||
left or right of the range. See [usage](#usage) below for examples.
|
||||
left or right of the range.
|
||||
|
||||
### Usage
|
||||
|
||||
```html
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-range color="danger" pin="true"></ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range min="-200" max="200" color="secondary">
|
||||
<ion-label slot="start">-200</ion-label>
|
||||
<ion-label slot="end">200</ion-label>
|
||||
</ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range min="20" max="80" step="2" >
|
||||
<ion-icon small slot="start" name="sunny"></ion-icon>
|
||||
<ion-icon slot="end" name="sunny"></ion-icon>
|
||||
</ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range min="1000" max="2000" step="100" snaps="true" color="secondary" ></ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range dualKnobs="true" min="21" max="72" step="3" snaps="true"></ion-range>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
```
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
||||
|
31
core/src/components/range/usage/angular.md
Normal file
31
core/src/components/range/usage/angular.md
Normal file
@ -0,0 +1,31 @@
|
||||
```html
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-range color="danger" pin="true"></ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range min="-200" max="200" color="secondary">
|
||||
<ion-label slot="start">-200</ion-label>
|
||||
<ion-label slot="end">200</ion-label>
|
||||
</ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range min="20" max="80" step="2" >
|
||||
<ion-icon small slot="start" name="sunny"></ion-icon>
|
||||
<ion-icon slot="end" name="sunny"></ion-icon>
|
||||
</ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range min="1000" max="2000" step="100" snaps="true" color="secondary" ></ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range dualKnobs="true" min="21" max="72" step="3" snaps="true"></ion-range>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
```
|
||||
|
||||
|
29
core/src/components/range/usage/javascript.md
Normal file
29
core/src/components/range/usage/javascript.md
Normal file
@ -0,0 +1,29 @@
|
||||
```html
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
<ion-range color="danger" pin="true"></ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range min="-200" max="200" color="secondary">
|
||||
<ion-label slot="start">-200</ion-label>
|
||||
<ion-label slot="end">200</ion-label>
|
||||
</ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range min="20" max="80" step="2" >
|
||||
<ion-icon small slot="start" name="sunny"></ion-icon>
|
||||
<ion-icon slot="end" name="sunny"></ion-icon>
|
||||
</ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range min="1000" max="2000" step="100" snaps="true" color="secondary" ></ion-range>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-range dual-knobs="true" min="21" max="72" step="3" snaps="true"></ion-range>
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
```
|
@ -2,18 +2,6 @@
|
||||
|
||||
The refresher content contains the text, icon and spinner to display during a pull-to-refresh. Ionic provides the pulling icon and refreshing spinner based on the platform. However, the default icon, spinner, and text can be customized based on the state of the refresher.
|
||||
|
||||
```html
|
||||
<ion-content>
|
||||
<ion-refresher slot="fixed">
|
||||
<ion-refresher-content
|
||||
pulling-icon="arrow-dropdown"
|
||||
pulling-text="Pull to refresh"
|
||||
refreshing-spinner="circles"
|
||||
refreshing-text="Refreshing...">
|
||||
</ion-refresher-content>
|
||||
</ion-refresher>
|
||||
</ion-content>
|
||||
```
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
@ -10,12 +10,6 @@ refresher.
|
||||
|
||||
|
||||
```html
|
||||
<ion-content>
|
||||
<ion-refresher slot="fixed">
|
||||
<ion-refresher-content>
|
||||
</ion-refresher-content>
|
||||
</ion-refresher>
|
||||
</ion-content>
|
||||
```
|
||||
|
||||
|
||||
|
23
core/src/components/refresher/usage/angular.md
Normal file
23
core/src/components/refresher/usage/angular.md
Normal file
@ -0,0 +1,23 @@
|
||||
```html
|
||||
<ion-content>
|
||||
<ion-refresher (ionRefresh)="doRefresh($event)">
|
||||
<ion-refresher-content></ion-refresher-content>
|
||||
</ion-refresher>
|
||||
</ion-content>
|
||||
```
|
||||
|
||||
```typescript
|
||||
@Component({...})
|
||||
export class NewsFeedPage {
|
||||
|
||||
doRefresh(event) {
|
||||
console.log('Begin async operation', refresher);
|
||||
|
||||
setTimeout(() => {
|
||||
console.log('Async operation has ended');
|
||||
event.target.complete();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
21
core/src/components/refresher/usage/javascript.md
Normal file
21
core/src/components/refresher/usage/javascript.md
Normal file
@ -0,0 +1,21 @@
|
||||
```html
|
||||
<ion-content>
|
||||
<ion-refresher slot="fixed">
|
||||
<ion-refresher-content>
|
||||
</ion-refresher-content>
|
||||
</ion-refresher>
|
||||
</ion-content>
|
||||
|
||||
<!-- or for custom content -->
|
||||
|
||||
<ion-content>
|
||||
<ion-refresher slot="fixed">
|
||||
<ion-refresher-content
|
||||
pulling-icon="arrow-dropdown"
|
||||
pulling-text="Pull to refresh"
|
||||
refreshing-spinner="circles"
|
||||
refreshing-text="Refreshing...">
|
||||
</ion-refresher-content>
|
||||
</ion-refresher>
|
||||
</ion-content>
|
||||
```
|
@ -1,8 +1,7 @@
|
||||
# ion-reorder-group
|
||||
|
||||
Item reorder adds the ability to change an item's order in a group.
|
||||
It can be used within an `ion-list` or `ion-item-group` to provide a
|
||||
visual drag and drop interface.
|
||||
ReorderGroup is a wrapper component for items with the Reorder element.
|
||||
|
||||
|
||||
|
||||
## Grouping Items
|
||||
|
@ -1,5 +1,6 @@
|
||||
# ion-reorder
|
||||
|
||||
Reorder adds the ability to change an item's order in a group. It can be used within an ion-list or ion-reorder-group to provide a visual drag and drop interface.
|
||||
|
||||
|
||||
<!-- Auto Generated Below -->
|
||||
|
Reference in New Issue
Block a user