mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 04:14:21 +08:00
feat(item): initial checkin of item sliding
This commit is contained in:
69
packages/core/src/components/item-sliding/item-options.tsx
Normal file
69
packages/core/src/components/item-sliding/item-options.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { Component, h, Ionic, Prop } from '@stencil/core';
|
||||||
|
|
||||||
|
import { isRightSide, Side } from '../../utils/util';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ItemOptions
|
||||||
|
* @description
|
||||||
|
* The option buttons for an `ion-item-sliding`. These buttons can be placed either on the left or right side.
|
||||||
|
* You can combine the `(ionSwipe)` event plus the `expandable` directive to create a full swipe action for the item.
|
||||||
|
*
|
||||||
|
* @usage
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <ion-item-sliding>
|
||||||
|
* <ion-item>
|
||||||
|
* Item 1
|
||||||
|
* </ion-item>
|
||||||
|
* <ion-item-options side="right" (ionSwipe)="saveItem(item)">
|
||||||
|
* <ion-button expandable (click)="saveItem(item)">
|
||||||
|
* <ion-icon name="star"></ion-icon>
|
||||||
|
* </ion-button>
|
||||||
|
* </ion-item-options>
|
||||||
|
* </ion-item-sliding>
|
||||||
|
*```
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
tag: 'ion-item-options'
|
||||||
|
})
|
||||||
|
export class ItemOptions {
|
||||||
|
$el: HTMLElement;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @input {string} The side the option button should be on. Defaults to `"right"`.
|
||||||
|
* If you have multiple `ion-item-options`, a side must be provided for each.
|
||||||
|
*/
|
||||||
|
@Prop() side: Side = 'right';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @output {event} Emitted when the item has been fully swiped.
|
||||||
|
*/
|
||||||
|
// @Output() ionSwipe: EventEmitter<ItemSliding> = new EventEmitter<ItemSliding>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
isRightSide(): boolean {
|
||||||
|
const isRTL = document.dir === 'rtl';
|
||||||
|
return isRightSide(this.side, isRTL, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @output {event} Emitted when the item has been fully swiped.
|
||||||
|
*/
|
||||||
|
ionSwipe(itemSliding: any) {
|
||||||
|
Ionic.emit(itemSliding, 'ionSwipe');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
width(): number {
|
||||||
|
return this.$el.offsetWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <slot></slot>;
|
||||||
|
}
|
||||||
|
}
|
171
packages/core/src/components/item-sliding/item-sliding.scss
Normal file
171
packages/core/src/components/item-sliding/item-sliding.scss
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
@import "../../themes/ionic.globals";
|
||||||
|
|
||||||
|
// Item Sliding
|
||||||
|
// --------------------------------------------------
|
||||||
|
// The hidden right-side buttons that can be exposed under a list item with dragging.
|
||||||
|
|
||||||
|
ion-item-sliding {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-sliding .item {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-options {
|
||||||
|
position: absolute;
|
||||||
|
z-index: $z-index-item-options;
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
font-size: 14px;
|
||||||
|
visibility: hidden;
|
||||||
|
|
||||||
|
@include multi-dir() {
|
||||||
|
// scss-lint:disable PropertySpelling
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include ltr() {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include rtl() {
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
&:not([side=right]) {
|
||||||
|
justify-content: flex-end;
|
||||||
|
|
||||||
|
// scss-lint:disable PropertySpelling
|
||||||
|
right: auto;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-options[side=left] {
|
||||||
|
@include multi-dir() {
|
||||||
|
// scss-lint:disable PropertySpelling
|
||||||
|
right: auto;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include ltr() {
|
||||||
|
justify-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include rtl() {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-options .button {
|
||||||
|
@include margin(0);
|
||||||
|
@include padding(0, .7em);
|
||||||
|
@include border-radius(0);
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
box-sizing: content-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-options:not([icon-left]) .button:not([icon-only]), // deprecated
|
||||||
|
ion-item-options:not([icon-start]) .button:not([icon-only]) {
|
||||||
|
.button-inner {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-icon {
|
||||||
|
@include padding(null, 0, .3em, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-sliding.active-slide {
|
||||||
|
@include rtl() {
|
||||||
|
&.active-options-left ion-item-options:not([side=right]) {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.item,
|
||||||
|
.item.activated {
|
||||||
|
position: relative;
|
||||||
|
z-index: $z-index-item-options + 1;
|
||||||
|
|
||||||
|
opacity: 1;
|
||||||
|
transition: transform 500ms cubic-bezier(.36, .66, .04, 1);
|
||||||
|
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-options {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active-options-left ion-item-options[side=left],
|
||||||
|
&.active-options-right ion-item-options:not([side=left]) {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Item Expandable Animation
|
||||||
|
// --------------------------------------------------
|
||||||
|
|
||||||
|
button[expandable] {
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
transition-duration: 0;
|
||||||
|
transition-property: none;
|
||||||
|
transition-timing-function: cubic-bezier(.65, .05, .36, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-sliding.active-swipe-right button[expandable] {
|
||||||
|
transition-duration: .6s;
|
||||||
|
transition-property: padding-left;
|
||||||
|
|
||||||
|
@include multi-dir() {
|
||||||
|
// scss-lint:disable PropertySpelling
|
||||||
|
padding-left: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include ltr() {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include rtl() {
|
||||||
|
order: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ion-item-sliding.active-swipe-left button[expandable] {
|
||||||
|
transition-duration: .6s;
|
||||||
|
transition-property: padding-right;
|
||||||
|
|
||||||
|
@include multi-dir() {
|
||||||
|
// scss-lint:disable PropertySpelling
|
||||||
|
padding-right: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include ltr() {
|
||||||
|
order: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include rtl() {
|
||||||
|
order: 1;
|
||||||
|
}
|
||||||
|
}
|
521
packages/core/src/components/item-sliding/item-sliding.tsx
Normal file
521
packages/core/src/components/item-sliding/item-sliding.tsx
Normal file
@ -0,0 +1,521 @@
|
|||||||
|
import { Component, h, Ionic, State } from '@stencil/core';
|
||||||
|
|
||||||
|
import { GestureDetail, HostElement } from '../../utils/interfaces';
|
||||||
|
import { swipeShouldReset } from '../../utils/util';
|
||||||
|
|
||||||
|
// import { ItemOptions } from './item-options';
|
||||||
|
|
||||||
|
const SWIPE_MARGIN = 30;
|
||||||
|
const ELASTIC_FACTOR = 0.55;
|
||||||
|
|
||||||
|
const ITEM_SIDE_FLAG_NONE = 0;
|
||||||
|
const ITEM_SIDE_FLAG_LEFT = 1 << 0;
|
||||||
|
const ITEM_SIDE_FLAG_RIGHT = 1 << 1;
|
||||||
|
const ITEM_SIDE_FLAG_BOTH = ITEM_SIDE_FLAG_LEFT | ITEM_SIDE_FLAG_RIGHT;
|
||||||
|
|
||||||
|
|
||||||
|
const enum SlidingState {
|
||||||
|
Disabled = 1 << 1,
|
||||||
|
Enabled = 1 << 2,
|
||||||
|
Right = 1 << 3,
|
||||||
|
Left = 1 << 4,
|
||||||
|
|
||||||
|
SwipeRight = 1 << 5,
|
||||||
|
SwipeLeft = 1 << 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name ItemSliding
|
||||||
|
* @description
|
||||||
|
* A sliding item is a list item that can be swiped to reveal buttons. It requires
|
||||||
|
* an [Item](../Item) component as a child and a [List](../../list/List) component as
|
||||||
|
* a parent. All buttons to reveal can be placed in the `<ion-item-options>` element.
|
||||||
|
*
|
||||||
|
* @usage
|
||||||
|
* ```html
|
||||||
|
* <ion-list>
|
||||||
|
* <ion-item-sliding #item>
|
||||||
|
* <ion-item>
|
||||||
|
* Item
|
||||||
|
* </ion-item>
|
||||||
|
* <ion-item-options side="left">
|
||||||
|
* <ion-button (click)="favorite(item)">Favorite</ion-button>
|
||||||
|
* <ion-button color="danger" (click)="share(item)">Share</ion-button>
|
||||||
|
* </ion-item-options>
|
||||||
|
*
|
||||||
|
* <ion-item-options side="right">
|
||||||
|
* <ion-button (click)="unread(item)">Unread</ion-button>
|
||||||
|
* </ion-item-options>
|
||||||
|
* </ion-item-sliding>
|
||||||
|
* </ion-list>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ### Swipe Direction
|
||||||
|
* By default, the buttons are revealed when the sliding item is swiped from right to left,
|
||||||
|
* so the buttons are placed in the right side. But it's also possible to reveal them
|
||||||
|
* in the right side (sliding from left to right) by setting the `side` attribute
|
||||||
|
* on the `ion-item-options` element. Up to 2 `ion-item-options` can used at the same time
|
||||||
|
* in order to reveal two different sets of buttons depending the swipping direction.
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <ion-item-options side="right">
|
||||||
|
* <ion-button (click)="archive(item)">
|
||||||
|
* <ion-icon name="archive"></ion-icon>
|
||||||
|
* Archive
|
||||||
|
* </ion-button>
|
||||||
|
* </ion-item-options>
|
||||||
|
*
|
||||||
|
* <ion-item-options side="left">
|
||||||
|
* <ion-button (click)="archive(item)">
|
||||||
|
* <ion-icon name="archive"></ion-icon>
|
||||||
|
* Archive
|
||||||
|
* </ion-button>
|
||||||
|
* </ion-item-options>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ### Listening for events (ionDrag) and (ionSwipe)
|
||||||
|
* It's possible to know the current relative position of the sliding item by subscribing
|
||||||
|
* to the (ionDrag)` event.
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <ion-item-sliding (ionDrag)="logDrag($event)">
|
||||||
|
* <ion-item>Item</ion-item>
|
||||||
|
* <ion-item-options>
|
||||||
|
* <ion-button>Favorite</ion-button>
|
||||||
|
* </ion-item-options>
|
||||||
|
* </ion-item-sliding>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ### Button Layout
|
||||||
|
* If an icon is placed with text in the option button, by default it will
|
||||||
|
* display the icon on top of the text. This can be changed to display the icon
|
||||||
|
* to the left of the text by setting `icon-start` as an attribute on the
|
||||||
|
* `<ion-item-options>` element.
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <ion-item-options icon-start>
|
||||||
|
* <ion-button (click)="archive(item)">
|
||||||
|
* <ion-icon name="archive"></ion-icon>
|
||||||
|
* Archive
|
||||||
|
* </ion-button>
|
||||||
|
* </ion-item-options>
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ### Expandable Options
|
||||||
|
*
|
||||||
|
* Options can be expanded to take up the full width of the item if you swipe past
|
||||||
|
* a certain point. This can be combined with the `ionSwipe` event to call methods
|
||||||
|
* on the class.
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
*
|
||||||
|
* <ion-item-sliding (ionSwipe)="delete(item)">
|
||||||
|
* <ion-item>Item</ion-item>
|
||||||
|
* <ion-item-options>
|
||||||
|
* <ion-button expandable (click)="delete(item)">Delete</ion-button>
|
||||||
|
* </ion-item-options>
|
||||||
|
* </ion-item-sliding>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* We can call `delete` by either clicking the button, or by doing a full swipe on the item.
|
||||||
|
*
|
||||||
|
* @demo /docs/demos/src/item-sliding/
|
||||||
|
* @see {@link /docs/components#lists List Component Docs}
|
||||||
|
* @see {@link ../Item Item API Docs}
|
||||||
|
* @see {@link ../../list/List List API Docs}
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
tag: 'ion-item-sliding',
|
||||||
|
styleUrl: 'item-sliding.scss',
|
||||||
|
// TODO REMOVE
|
||||||
|
styleUrls: {
|
||||||
|
ios: 'item-sliding.scss',
|
||||||
|
md: 'item-sliding.scss',
|
||||||
|
wp: 'item-sliding.scss'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
export class ItemSliding {
|
||||||
|
$el: HTMLElement;
|
||||||
|
item: HostElement;
|
||||||
|
|
||||||
|
openAmount: number = 0;
|
||||||
|
startX: number = 0;
|
||||||
|
optsWidthRightSide: number = 0;
|
||||||
|
optsWidthLeftSide: number = 0;
|
||||||
|
sides: number;
|
||||||
|
tmr: number = null;
|
||||||
|
|
||||||
|
// TODO file with item sliding interfaces & item options implement
|
||||||
|
// leftOptions: ItemOptions;
|
||||||
|
// rightOptions: ItemOptions;
|
||||||
|
leftOptions: any;
|
||||||
|
rightOptions: any;
|
||||||
|
|
||||||
|
optsDirty: boolean = true;
|
||||||
|
|
||||||
|
@State() state: SlidingState = SlidingState.Disabled;
|
||||||
|
|
||||||
|
preSelectedContainer: ItemSliding = null;
|
||||||
|
selectedContainer: ItemSliding = null;
|
||||||
|
openContainer: ItemSliding = null;
|
||||||
|
firstCoordX: number;
|
||||||
|
firstTimestamp: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @output {event} Emitted when the sliding position changes.
|
||||||
|
* It reports the relative position.
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* onDrag(slidingItem) {
|
||||||
|
* let percent = slidingItem.getSlidingPercent();
|
||||||
|
* if (percent > 0) {
|
||||||
|
* // positive
|
||||||
|
* console.log('right side');
|
||||||
|
* } else {
|
||||||
|
* // negative
|
||||||
|
* console.log('left side');
|
||||||
|
* }
|
||||||
|
* if (Math.abs(percent) > 1) {
|
||||||
|
* console.log('overscroll');
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ionDrag() {
|
||||||
|
Ionic.emit(this, 'ionDrag');
|
||||||
|
}
|
||||||
|
|
||||||
|
ionViewDidLoad() {
|
||||||
|
const options = this.$el.querySelectorAll('ion-item-options') as NodeListOf<HostElement>;
|
||||||
|
|
||||||
|
let sides = 0;
|
||||||
|
|
||||||
|
// Reset left and right options in case they were removed
|
||||||
|
this.leftOptions = this.rightOptions = null;
|
||||||
|
|
||||||
|
for (var i = 0; i < options.length; i++) {
|
||||||
|
let option = options[i].$instance;
|
||||||
|
|
||||||
|
if (option.isRightSide()) {
|
||||||
|
this.rightOptions = option;
|
||||||
|
sides |= ITEM_SIDE_FLAG_RIGHT;
|
||||||
|
} else {
|
||||||
|
this.leftOptions = option;
|
||||||
|
sides |= ITEM_SIDE_FLAG_LEFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.optsDirty = true;
|
||||||
|
this.sides = sides;
|
||||||
|
|
||||||
|
this.item = this.$el.querySelector('ion-item') as HostElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
canStart(gesture: GestureDetail): boolean {
|
||||||
|
if (this.selectedContainer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Get swiped sliding container
|
||||||
|
let container = this;
|
||||||
|
|
||||||
|
// Close open container if it is not the selected one.
|
||||||
|
if (container !== this.openContainer) {
|
||||||
|
this.closeOpened();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.preSelectedContainer = container;
|
||||||
|
this.firstCoordX = gesture.currentX;
|
||||||
|
this.firstTimestamp = Date.now();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragStart(gesture: GestureDetail) {
|
||||||
|
this.selectedContainer = this.openContainer = this.preSelectedContainer;
|
||||||
|
this.selectedContainer.startSliding(gesture.currentX);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragMove(gesture: GestureDetail) {
|
||||||
|
this.selectedContainer && this.selectedContainer.moveSliding(gesture.currentX);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDragEnd(gesture: GestureDetail) {
|
||||||
|
this.selectedContainer.endSliding(gesture.velocityX);
|
||||||
|
this.selectedContainer = null;
|
||||||
|
this.preSelectedContainer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeOpened(): boolean {
|
||||||
|
this.selectedContainer = null;
|
||||||
|
|
||||||
|
if (this.openContainer) {
|
||||||
|
this.openContainer.close();
|
||||||
|
this.openContainer = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
getOpenAmount(): number {
|
||||||
|
return this.openAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
getSlidingPercent(): number {
|
||||||
|
const openAmount = this.openAmount;
|
||||||
|
if (openAmount > 0) {
|
||||||
|
return openAmount / this.optsWidthRightSide;
|
||||||
|
} else if (openAmount < 0) {
|
||||||
|
return openAmount / this.optsWidthLeftSide;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
startSliding(startX: number) {
|
||||||
|
if (this.tmr) {
|
||||||
|
clearTimeout(this.tmr);
|
||||||
|
this.tmr = null;
|
||||||
|
}
|
||||||
|
if (this.openAmount === 0) {
|
||||||
|
this.optsDirty = true;
|
||||||
|
this.setState(SlidingState.Enabled);
|
||||||
|
}
|
||||||
|
this.startX = startX + this.openAmount;
|
||||||
|
this.item.style.transition = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
moveSliding(x: number): number {
|
||||||
|
if (this.optsDirty) {
|
||||||
|
this.calculateOptsWidth();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let openAmount = (this.startX - x);
|
||||||
|
|
||||||
|
switch (this.sides) {
|
||||||
|
case ITEM_SIDE_FLAG_RIGHT: openAmount = Math.max(0, openAmount); break;
|
||||||
|
case ITEM_SIDE_FLAG_LEFT: openAmount = Math.min(0, openAmount); break;
|
||||||
|
case ITEM_SIDE_FLAG_BOTH: break;
|
||||||
|
case ITEM_SIDE_FLAG_NONE: return 0;
|
||||||
|
default: console.warn('invalid ItemSideFlags value', this.sides); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (openAmount > this.optsWidthRightSide) {
|
||||||
|
var optsWidth = this.optsWidthRightSide;
|
||||||
|
openAmount = optsWidth + (openAmount - optsWidth) * ELASTIC_FACTOR;
|
||||||
|
|
||||||
|
} else if (openAmount < -this.optsWidthLeftSide) {
|
||||||
|
var optsWidth = -this.optsWidthLeftSide;
|
||||||
|
openAmount = optsWidth + (openAmount - optsWidth) * ELASTIC_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setOpenAmount(openAmount, false);
|
||||||
|
return openAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
endSliding(velocity: number): number {
|
||||||
|
let restingPoint = (this.openAmount > 0)
|
||||||
|
? this.optsWidthRightSide
|
||||||
|
: -this.optsWidthLeftSide;
|
||||||
|
|
||||||
|
// Check if the drag didn't clear the buttons mid-point
|
||||||
|
// and we aren't moving fast enough to swipe open
|
||||||
|
const isResetDirection = (this.openAmount > 0) === !(velocity < 0);
|
||||||
|
const isMovingFast = Math.abs(velocity) > 0.3;
|
||||||
|
const isOnCloseZone = Math.abs(this.openAmount) < Math.abs(restingPoint / 2);
|
||||||
|
if (swipeShouldReset(isResetDirection, isMovingFast, isOnCloseZone)) {
|
||||||
|
restingPoint = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setOpenAmount(restingPoint, true);
|
||||||
|
this.fireSwipeEvent();
|
||||||
|
return restingPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
* Emit the ionSwipe event on the child options
|
||||||
|
*/
|
||||||
|
fireSwipeEvent() {
|
||||||
|
if (this.state & SlidingState.SwipeRight) {
|
||||||
|
this.rightOptions.ionSwipe(this);
|
||||||
|
} else if (this.state & SlidingState.SwipeLeft) {
|
||||||
|
this.leftOptions.ionSwipe(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hidden
|
||||||
|
*/
|
||||||
|
calculateOptsWidth() {
|
||||||
|
if (!this.optsDirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.optsWidthRightSide = 0;
|
||||||
|
if (this.rightOptions) {
|
||||||
|
this.optsWidthRightSide = this.rightOptions.width();
|
||||||
|
this.optsWidthRightSide == 0 && console.warn('optsWidthRightSide should not be zero');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.optsWidthLeftSide = 0;
|
||||||
|
if (this.leftOptions) {
|
||||||
|
this.optsWidthLeftSide = this.leftOptions.width();
|
||||||
|
this.optsWidthLeftSide == 0 && console.warn('optsWidthLeftSide should not be zero');
|
||||||
|
}
|
||||||
|
this.optsDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpenAmount(openAmount: number, isFinal: boolean) {
|
||||||
|
if (this.tmr) {
|
||||||
|
clearTimeout(this.tmr);
|
||||||
|
this.tmr = null;
|
||||||
|
}
|
||||||
|
this.openAmount = openAmount;
|
||||||
|
|
||||||
|
if (isFinal) {
|
||||||
|
this.item.style.transition = '';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (openAmount > 0) {
|
||||||
|
var state = (openAmount >= (this.optsWidthRightSide + SWIPE_MARGIN))
|
||||||
|
? SlidingState.Right | SlidingState.SwipeRight
|
||||||
|
: SlidingState.Right;
|
||||||
|
|
||||||
|
this.setState(state);
|
||||||
|
|
||||||
|
} else if (openAmount < 0) {
|
||||||
|
var state = (openAmount <= (-this.optsWidthLeftSide - SWIPE_MARGIN))
|
||||||
|
? SlidingState.Left | SlidingState.SwipeLeft
|
||||||
|
: SlidingState.Left;
|
||||||
|
|
||||||
|
this.setState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (openAmount === 0) {
|
||||||
|
this.setState(SlidingState.Disabled);
|
||||||
|
this.tmr = setTimeout(() => {
|
||||||
|
this.tmr = null;
|
||||||
|
this.setState(SlidingState.Disabled);
|
||||||
|
}, 600);
|
||||||
|
this.item.style.transform = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.item.style.transform = `translate3d(${-openAmount}px,0,0)`;
|
||||||
|
this.ionDrag();
|
||||||
|
}
|
||||||
|
|
||||||
|
private setState(state: SlidingState) {
|
||||||
|
console.log('setState',
|
||||||
|
this.state + '\n',
|
||||||
|
'active-slide', (this.state !== SlidingState.Disabled),
|
||||||
|
'active-options-right', !!(this.state & SlidingState.Right),
|
||||||
|
'active-options-left', !!(this.state & SlidingState.Left),
|
||||||
|
'active-swipe-right', !!(this.state & SlidingState.SwipeRight),
|
||||||
|
'active-swipe-left', !!(this.state & SlidingState.SwipeLeft)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (state === this.state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the sliding item. Items can also be closed from the [List](../../list/List).
|
||||||
|
*
|
||||||
|
* The sliding item can be closed by grabbing a reference to `ItemSliding`. In the
|
||||||
|
* below example, the template reference variable `slidingItem` is placed on the element
|
||||||
|
* and passed to the `share` method.
|
||||||
|
*
|
||||||
|
* ```html
|
||||||
|
* <ion-list>
|
||||||
|
* <ion-item-sliding #slidingItem>
|
||||||
|
* <ion-item>
|
||||||
|
* Item
|
||||||
|
* </ion-item>
|
||||||
|
* <ion-item-options>
|
||||||
|
* <ion-button (click)="share(slidingItem)">Share</ion-button>
|
||||||
|
* </ion-item-options>
|
||||||
|
* </ion-item-sliding>
|
||||||
|
* </ion-list>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* import { Component } from '@angular/core';
|
||||||
|
* import { ItemSliding } from 'ionic-angular';
|
||||||
|
*
|
||||||
|
* @Component({...})
|
||||||
|
* export class MyClass {
|
||||||
|
* constructor() { }
|
||||||
|
*
|
||||||
|
* share(slidingItem: ItemSliding) {
|
||||||
|
* slidingItem.close();
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
close() {
|
||||||
|
this.setOpenAmount(0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
hostData() {
|
||||||
|
console.log('hostData',
|
||||||
|
this.state + '\n',
|
||||||
|
'active-slide', (this.state !== SlidingState.Disabled),
|
||||||
|
'active-options-right', !!(this.state & SlidingState.Right),
|
||||||
|
'active-options-left', !!(this.state & SlidingState.Left),
|
||||||
|
'active-swipe-right', !!(this.state & SlidingState.SwipeRight),
|
||||||
|
'active-swipe-left', !!(this.state & SlidingState.SwipeLeft)
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
class: {
|
||||||
|
'item-wrapper': true,
|
||||||
|
'active-slide': (this.state !== SlidingState.Disabled),
|
||||||
|
'active-options-right': !!(this.state & SlidingState.Right),
|
||||||
|
'active-options-left': !!(this.state & SlidingState.Left),
|
||||||
|
'active-swipe-right': !!(this.state & SlidingState.SwipeRight),
|
||||||
|
'active-swipe-left': !!(this.state & SlidingState.SwipeLeft)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
|
||||||
|
<ion-gesture props={{
|
||||||
|
'canStart': this.canStart.bind(this),
|
||||||
|
'onStart': this.onDragStart.bind(this),
|
||||||
|
'onMove': this.onDragMove.bind(this),
|
||||||
|
'onEnd': this.onDragEnd.bind(this),
|
||||||
|
'gestureName': 'item-swipe',
|
||||||
|
'gesturePriority': -10,
|
||||||
|
'type': 'pan',
|
||||||
|
'direction': 'x',
|
||||||
|
'maxAngle': 20,
|
||||||
|
'threshold': 5,
|
||||||
|
'attachTo': 'parent'
|
||||||
|
}}>
|
||||||
|
<slot></slot>
|
||||||
|
</ion-gesture>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
309
packages/core/src/components/item-sliding/test/basic.html
Normal file
309
packages/core/src/components/item-sliding/test/basic.html
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html dir="ltr">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Ionic Item Sliding</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||||
|
<script src="/dist/ionic.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<ion-app>
|
||||||
|
<ion-content>
|
||||||
|
|
||||||
|
<div padding>
|
||||||
|
<ion-button block onclick="toggleSliding()">Toggle sliding</ion-button>
|
||||||
|
<ion-button block onclick="changeDynamic()">Change Dynamic Options</ion-button>
|
||||||
|
<ion-button block onclick="closeOpened()">Close Opened Items</ion-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ion-list #myList>
|
||||||
|
|
||||||
|
<ion-item-sliding>
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>
|
||||||
|
<h2>No Options</h2>
|
||||||
|
<p>Should not error or swipe without options</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding id="item6">
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>
|
||||||
|
One Line, dynamic option and text
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options *ngIf="showOptions">
|
||||||
|
<ion-button color="primary">
|
||||||
|
<ion-icon name="more"></ion-icon>
|
||||||
|
{{ moreText }}
|
||||||
|
</ion-button>
|
||||||
|
<ion-button color="secondary" onclick="archive('item6')">
|
||||||
|
<ion-icon name="archive"></ion-icon>
|
||||||
|
{{ archiveText }}
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding id="item6">
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>
|
||||||
|
Two options, one dynamic option and text
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options side="left">
|
||||||
|
<ion-button color="primary">
|
||||||
|
<ion-icon slot="icon-only" name="more"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
<ion-item-options side="right" *ngIf="showOptions">
|
||||||
|
<ion-button color="primary">
|
||||||
|
<ion-icon name="more"></ion-icon>
|
||||||
|
{{ moreText }}
|
||||||
|
</ion-button>
|
||||||
|
<ion-button color="secondary" onclick="archive('item6')">
|
||||||
|
<ion-icon name="archive"></ion-icon>
|
||||||
|
{{ archiveText }}
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding id="item1"00>
|
||||||
|
<ion-item href="#">
|
||||||
|
<ion-label>
|
||||||
|
<h2>HubStruck Notifications</h2>
|
||||||
|
<p>A new message from a repo in your network</p>
|
||||||
|
<p>Oceanic Next has joined your network</p>
|
||||||
|
</ion-label>
|
||||||
|
<ion-note slot="end">
|
||||||
|
10:45 AM
|
||||||
|
</ion-note>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item-options side="left">
|
||||||
|
<ion-button onclick="noclose(item100)">
|
||||||
|
No close
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
<ion-item-options side="right">
|
||||||
|
<ion-button color="danger" onclick="unread('item100')">
|
||||||
|
<ion-icon slot="icon-only" name="trash"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
<ion-button onclick="unread('item100')">
|
||||||
|
<ion-icon slot="icon-only" name="star"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding id="item0">
|
||||||
|
<ion-item text-wrap onclick="didClick(item0)">
|
||||||
|
<ion-label>
|
||||||
|
<h2>RIGHT side - no icons</h2>
|
||||||
|
<p>Hey do you want to go to the game tonight?</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options *ngIf="slidingEnabled">
|
||||||
|
<ion-button color="primary" onclick="archive('item0')">Archive</ion-button>
|
||||||
|
<ion-button color="danger" onclick="del('item0')">Delete</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding id="item1">
|
||||||
|
<ion-item text-wrap detail-push href="#" class="activated">
|
||||||
|
<ion-label>
|
||||||
|
<h2>LEFT side - no icons</h2>
|
||||||
|
<p>I think I figured out how to get more Mountain Dew</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options side="left" *ngIf="slidingEnabled">
|
||||||
|
<ion-button color="primary" onclick="archive('item1')">Archive</ion-button>
|
||||||
|
<ion-button color="danger" onclick="del('item1')">Delete</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
|
||||||
|
<ion-item-sliding id="item2">
|
||||||
|
<ion-item text-wrap detail-push>
|
||||||
|
<ion-label>
|
||||||
|
<h2>RIGHT/LEFT side - icons</h2>
|
||||||
|
<p>I think I figured out how to get more Mountain Dew</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options side="left" (ionSwipe)="unread($event)" *ngIf="slidingEnabled">
|
||||||
|
<ion-button color="secondary" expandable onclick="unread('item2')">
|
||||||
|
<ion-icon name="ios-checkmark"></ion-icon>Unread
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
|
||||||
|
<ion-item-options side="right" (ionSwipe)="del('item2')" *ngIf="slidingEnabled">
|
||||||
|
<ion-button color="primary" onclick="archive('item2')">
|
||||||
|
<ion-icon name="mail"></ion-icon>Archive
|
||||||
|
</ion-button>
|
||||||
|
<ion-button color="danger" onclick="del('item2')" expandable>
|
||||||
|
<ion-icon name="trash"></ion-icon>Delete
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding id="item3">
|
||||||
|
<ion-item text-wrap detail-push>
|
||||||
|
<ion-label>
|
||||||
|
<h2>RIGHT/LEFT side - icons (slot="start")</h2>
|
||||||
|
<p>I think I figured out how to get more Mountain Dew</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options side="left" icon-start (ionSwipe)="unread($event)" *ngIf="slidingEnabled">
|
||||||
|
<ion-button color="secondary" expandable onclick="unread('item3')">
|
||||||
|
<ion-icon name="ios-checkmark"></ion-icon>Unread
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
|
||||||
|
<ion-item-options icon-start (ionSwipe)="del('item3')">
|
||||||
|
<ion-button color="primary" onclick="archive('item3')">
|
||||||
|
<ion-icon name="mail"></ion-icon>Archive
|
||||||
|
</ion-button>
|
||||||
|
<ion-button color="danger" onclick="del('item3')" expandable *ngIf="slidingEnabled">
|
||||||
|
<ion-icon name="trash"></ion-icon>Delete
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
|
||||||
|
<ion-item-sliding id="item4">
|
||||||
|
<ion-item>
|
||||||
|
<ion-icon name="mail" slot="start"></ion-icon>
|
||||||
|
<ion-label>
|
||||||
|
One Line w/ Icon, div only text
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options icon-start (ionSwipe)="archive($event)">
|
||||||
|
<ion-button color="primary" onclick="archive('item4')" expandable *ngIf="slidingEnabled">
|
||||||
|
<ion-icon name="archive"></ion-icon>Archive
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
|
||||||
|
<ion-item-sliding id="item5" *ngIf="slidingEnabled">
|
||||||
|
<ion-item>
|
||||||
|
<ion-avatar slot="start">
|
||||||
|
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==">
|
||||||
|
</ion-avatar>
|
||||||
|
<ion-label>
|
||||||
|
One Line w/ Avatar, div only text
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options>
|
||||||
|
<ion-button color="primary" expandable>
|
||||||
|
<ion-icon name="more"></ion-icon>More
|
||||||
|
</ion-button>
|
||||||
|
<ion-button color="secondary" onclick="archive('item5')">
|
||||||
|
<ion-icon name="archive"></ion-icon>Archive
|
||||||
|
</ion-button>
|
||||||
|
<ion-button color="danger" onclick="del('item5')">
|
||||||
|
<ion-icon name="trash"></ion-icon>Delete
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
|
||||||
|
<ion-item-sliding id="item7">
|
||||||
|
<ion-item>
|
||||||
|
<ion-label>
|
||||||
|
One Line, dynamic icon-start option
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options icon-start>
|
||||||
|
<ion-button color="primary">
|
||||||
|
<ion-icon name="more"></ion-icon>
|
||||||
|
{{ moreText }}
|
||||||
|
</ion-button>
|
||||||
|
<ion-button color="secondary" onclick="archive('item7')">
|
||||||
|
<ion-icon name="archive"></ion-icon>
|
||||||
|
{{ archiveText }}
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding id="item8">
|
||||||
|
<ion-item>
|
||||||
|
<ion-thumbnail slot="start">
|
||||||
|
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==">
|
||||||
|
</ion-thumbnail>
|
||||||
|
<ion-label>
|
||||||
|
<h2>DOWNLOAD</h2>
|
||||||
|
<p>Paragraph text.</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item-options (ionSwipe)="download($event)">
|
||||||
|
<ion-button color="primary" onclick="archive('item8')">
|
||||||
|
<ion-icon name="archive"></ion-icon>Archive
|
||||||
|
</ion-button>
|
||||||
|
<ion-button color="secondary" expandable onclick="download(item8)">
|
||||||
|
<ion-icon name="download" class="download-hide"></ion-icon>
|
||||||
|
<div class="download-hide">Download</div>
|
||||||
|
<ion-spinner id="download-spinner"></ion-spinner>
|
||||||
|
</ion-button>
|
||||||
|
</ion-item-options>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item-sliding id="item9">
|
||||||
|
<ion-item>
|
||||||
|
<ion-thumbnail slot="start">
|
||||||
|
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==">
|
||||||
|
</ion-thumbnail>
|
||||||
|
<ion-label>
|
||||||
|
<h2>ion-item-sliding without options (no sliding)</h2>
|
||||||
|
<p>Paragraph text.</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-item-sliding>
|
||||||
|
|
||||||
|
<ion-item text-wrap>
|
||||||
|
<ion-label>
|
||||||
|
<h2>Normal ion-item (no sliding)</h2>
|
||||||
|
<p>Paragraph text.</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item text-wrap onclick="didClick(item9)">
|
||||||
|
<ion-label>
|
||||||
|
<h2>Normal button (no sliding)</h2>
|
||||||
|
<p>Hey do you want to go to the game tonight?</p>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
</ion-list>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var dynamicColor = document.getElementById('dynamicColor');
|
||||||
|
|
||||||
|
function unread(item) {
|
||||||
|
console.log('unread');
|
||||||
|
}
|
||||||
|
|
||||||
|
function archive(item) {
|
||||||
|
console.log('archive');
|
||||||
|
}
|
||||||
|
|
||||||
|
function del(item) {
|
||||||
|
console.log('del');
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSliding() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDynamic() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeOpened() {
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</ion-content>
|
||||||
|
</ion-app>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -17,6 +17,7 @@ export class Item {
|
|||||||
|
|
||||||
@Prop() mode: string;
|
@Prop() mode: string;
|
||||||
@Prop() color: string;
|
@Prop() color: string;
|
||||||
|
@Prop() href: string;
|
||||||
|
|
||||||
@Listen('ionStyle')
|
@Listen('ionStyle')
|
||||||
itemStyle(ev: UIEvent) {
|
itemStyle(ev: UIEvent) {
|
||||||
@ -51,8 +52,11 @@ export class Item {
|
|||||||
'item-block': true
|
'item-block': true
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO add support for button items
|
||||||
|
const TagType = this.href ? 'a' : 'div';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class={themedClasses}>
|
<TagType class={themedClasses}>
|
||||||
<slot name='start'></slot>
|
<slot name='start'></slot>
|
||||||
<div class='item-inner'>
|
<div class='item-inner'>
|
||||||
<div class='input-wrapper'>
|
<div class='input-wrapper'>
|
||||||
@ -60,7 +64,7 @@ export class Item {
|
|||||||
</div>
|
</div>
|
||||||
<slot name='end'></slot>
|
<slot name='end'></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</TagType>
|
||||||
);
|
);
|
||||||
|
|
||||||
// template:
|
// template:
|
||||||
|
@ -10,7 +10,7 @@ exports.config = {
|
|||||||
{ components: ['ion-card', 'ion-card-content', 'ion-card-header', 'ion-card-title'] },
|
{ components: ['ion-card', 'ion-card-content', 'ion-card-header', 'ion-card-title'] },
|
||||||
{ components: ['ion-fab', 'ion-fab-button', 'ion-fab-list'] },
|
{ components: ['ion-fab', 'ion-fab-button', 'ion-fab-list'] },
|
||||||
{ components: ['ion-gesture', 'ion-scroll'], priority: 'low' },
|
{ components: ['ion-gesture', 'ion-scroll'], priority: 'low' },
|
||||||
{ components: ['ion-item', 'ion-item-divider', 'ion-label', 'ion-list', 'ion-list-header', 'ion-skeleton-text'] },
|
{ components: ['ion-item', 'ion-item-divider', 'ion-item-sliding', 'ion-item-options', 'ion-label', 'ion-list', 'ion-list-header', 'ion-skeleton-text'] },
|
||||||
{ components: ['ion-loading', 'ion-loading-controller'] },
|
{ components: ['ion-loading', 'ion-loading-controller'] },
|
||||||
{ components: ['ion-menu'], priority: 'low' },
|
{ components: ['ion-menu'], priority: 'low' },
|
||||||
{ components: ['ion-modal', 'ion-modal-controller'] },
|
{ components: ['ion-modal', 'ion-modal-controller'] },
|
||||||
|
Reference in New Issue
Block a user