mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-22 05:21:52 +08:00
fix(item-sliding): fix the item options visibility and wrap the button
- updates documentation - renames `getSlidingPercent` to `getSlidingRatio ` - adds expandable as a property to option - renames classes and updates styles - fixes a bug where active class wasn’t being removed on drag end references #13993
This commit is contained in:
10
BREAKING.md
10
BREAKING.md
@ -14,6 +14,7 @@ A list of the breaking changes introduced in Ionic Angular v4.
|
|||||||
- [Input](#Input)
|
- [Input](#Input)
|
||||||
- [Item](#item)
|
- [Item](#item)
|
||||||
- [Item Divider](#item-divider)
|
- [Item Divider](#item-divider)
|
||||||
|
- [Item Sliding](#item-sliding)
|
||||||
- [List Header](#list-header)
|
- [List Header](#list-header)
|
||||||
- [Menu Toggle](#menu-toggle)
|
- [Menu Toggle](#menu-toggle)
|
||||||
- [Nav](#nav)
|
- [Nav](#nav)
|
||||||
@ -467,7 +468,14 @@ The `menuToggle` attribute should not be added to an element anymore. Elements t
|
|||||||
</ion-menu-toggle>
|
</ion-menu-toggle>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Toolbar
|
## Item Sliding
|
||||||
|
|
||||||
|
### Method Renamed
|
||||||
|
|
||||||
|
The `getSlidingPercent` method has been renamed to `getSlidingRatio` since the function is returning a ratio of the open amount of the item compared to the width of the options.
|
||||||
|
|
||||||
|
|
||||||
|
## Toolbar
|
||||||
|
|
||||||
Previously if a `menuToggle` directive was added to an Ionic `button` in a toolbar, it would be positioned outside of the `ion-buttons` element. Since menu toggle is simply a wrapper to a button now, it should be placed inside of the `ion-buttons` element.
|
Previously if a `menuToggle` directive was added to an Ionic `button` in a toolbar, it would be positioned outside of the `ion-buttons` element. Since menu toggle is simply a wrapper to a button now, it should be placed inside of the `ion-buttons` element.
|
||||||
|
|
||||||
|
1
packages/core/src/components.d.ts
vendored
1
packages/core/src/components.d.ts
vendored
@ -1314,6 +1314,7 @@ declare global {
|
|||||||
export interface IonItemOptionAttributes extends HTMLAttributes {
|
export interface IonItemOptionAttributes extends HTMLAttributes {
|
||||||
color?: string;
|
color?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
expandable?: boolean;
|
||||||
href?: string;
|
href?: string;
|
||||||
mode?: 'ios' | 'md';
|
mode?: 'ios' | 'md';
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
.card-ios > .item:last-child,
|
.card-ios > .item:last-child,
|
||||||
.card-ios > .item:last-child .item-inner,
|
.card-ios > .item:last-child .item-inner,
|
||||||
.card-ios > .item-wrapper:last-child .item {
|
.card-ios > .item-sliding:last-child .item {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
.card-md > .item:last-child,
|
.card-md > .item:last-child,
|
||||||
.card-md > .item:last-child .item-inner,
|
.card-md > .item:last-child .item-inner,
|
||||||
.card-md > .item-wrapper:last-child .item {
|
.card-md > .item-sliding:last-child .item {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item-group-ios ion-item:last-child .item-inner,
|
.item-group-ios ion-item:last-child .item-inner,
|
||||||
.item-group-ios .item-wrapper:last-child .item .item-inner {
|
.item-group-ios .item-sliding:last-child .item .item-inner {
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item-group-md ion-item:last-child .item-inner,
|
.item-group-md ion-item:last-child .item-inner,
|
||||||
.item-group-md .item-wrapper:last-child .item .item-inner {
|
.item-group-md .item-sliding:last-child .item .item-inner {
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
@ -10,10 +10,6 @@
|
|||||||
background-color: $item-option-button-ios-background-color;
|
background-color: $item-option-button-ios-background-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-option-ios .icon {
|
|
||||||
fill: $item-option-button-ios-icon-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-ios .item-options-right ion-item-option:last-child {
|
.list-ios .item-options-right ion-item-option:last-child {
|
||||||
@include safe-area-padding-horizontal(null, .7em);
|
@include safe-area-padding-horizontal(null, .7em);
|
||||||
}
|
}
|
||||||
@ -35,8 +31,4 @@
|
|||||||
color: $color-contrast;
|
color: $color-contrast;
|
||||||
background-color: $color-base;
|
background-color: $color-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-option-ios-#{$color-name} .icon {
|
|
||||||
fill: $color-contrast;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,9 @@
|
|||||||
background-color: $item-option-button-md-background-color;
|
background-color: $item-option-button-md-background-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-option-md .icon {
|
.item-option-md .item-option-button {
|
||||||
fill: $item-option-button-md-icon-color;
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -27,8 +28,4 @@
|
|||||||
color: $color-contrast;
|
color: $color-contrast;
|
||||||
background-color: $color-base;
|
background-color: $color-base;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-option-md-#{$color-name} .icon {
|
|
||||||
fill: $color-contrast;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -3,34 +3,22 @@
|
|||||||
// Item Option
|
// Item Option
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
ion-item-option {
|
|
||||||
@include padding(0, .7em);
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
min-width: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.item-option-button {
|
.item-option-button {
|
||||||
@include position(0, 0, 0, 0);
|
@include padding(0, .7em);
|
||||||
@include margin(0);
|
|
||||||
@include padding(0);
|
|
||||||
@include border-radius(0);
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
border: 0;
|
border: 0;
|
||||||
background: none;
|
background: none;
|
||||||
|
color: inherit;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
font-size: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-options:not([icon-start]) ion-item-option:not([icon-only]) {
|
ion-item-options .item-option-button-inner {
|
||||||
.item-option-button-inner {
|
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.item-option-button-inner {
|
.item-option-button-inner {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -44,11 +32,18 @@ ion-item-options:not([icon-start]) ion-item-option:not([icon-only]) {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-option-button [slot="icon-only"] {
|
||||||
|
padding: 0;
|
||||||
|
min-width: .9em;
|
||||||
|
|
||||||
|
font-size: 1.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Item Expandable Animation
|
// Item Expandable Animation
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
|
||||||
ion-item-option[expandable] {
|
.item-option-expandable {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
transition-duration: 0;
|
transition-duration: 0;
|
||||||
@ -56,7 +51,7 @@ ion-item-option[expandable] {
|
|||||||
transition-timing-function: cubic-bezier(.65, .05, .36, 1);
|
transition-timing-function: cubic-bezier(.65, .05, .36, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding.active-swipe-right ion-item-option[expandable] {
|
.item-sliding-active-swipe-right .item-options-right .item-option-expandable {
|
||||||
transition-duration: .6s;
|
transition-duration: .6s;
|
||||||
transition-property: padding-left;
|
transition-property: padding-left;
|
||||||
|
|
||||||
@ -74,7 +69,7 @@ ion-item-sliding.active-swipe-right ion-item-option[expandable] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding.active-swipe-left ion-item-option[expandable] {
|
.item-sliding-active-swipe-left .item-options-left .item-option-expandable {
|
||||||
transition-duration: .6s;
|
transition-duration: .6s;
|
||||||
transition-property: padding-right;
|
transition-property: padding-right;
|
||||||
|
|
||||||
|
@ -26,17 +26,22 @@ export class ItemOption {
|
|||||||
*/
|
*/
|
||||||
@Prop() mode: 'ios' | 'md';
|
@Prop() mode: 'ios' | 'md';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, the user cannot interact with the item option. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
@Prop() disabled = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, the option will expand to take up the available width and cover any other options. Defaults to `false`.
|
||||||
|
*/
|
||||||
|
@Prop() expandable = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains a URL or a URL fragment that the hyperlink points to.
|
* Contains a URL or a URL fragment that the hyperlink points to.
|
||||||
* If this property is set, an anchor tag will be rendered.
|
* If this property is set, an anchor tag will be rendered.
|
||||||
*/
|
*/
|
||||||
@Prop() href: string;
|
@Prop() href: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* If true, the user cannot interact with the item option. Defaults to `false`.
|
|
||||||
*/
|
|
||||||
@Prop() disabled = false;
|
|
||||||
|
|
||||||
notCaptured() {
|
notCaptured() {
|
||||||
// if (!clickedOptionButton(ev)) {
|
// if (!clickedOptionButton(ev)) {
|
||||||
// this.closeOpened();
|
// this.closeOpened();
|
||||||
@ -48,21 +53,33 @@ export class ItemOption {
|
|||||||
return !!el;
|
return !!el;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
hostData() {
|
||||||
|
return {
|
||||||
|
class: {
|
||||||
|
'item-option-expandable': this.expandable
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
const TagType = this.href ? 'a' : 'button';
|
const TagType = this.href ? 'a' : 'button';
|
||||||
|
|
||||||
// TODO TagType should wrap button-inner
|
return (
|
||||||
return [
|
|
||||||
<TagType
|
<TagType
|
||||||
class='item-option-button'
|
class='item-option-button'
|
||||||
disabled={this.disabled}
|
disabled={this.disabled}
|
||||||
href={this.href}
|
href={this.href}
|
||||||
onClick={this.clickedOptionButton.bind(this)}></TagType>,
|
onClick={this.clickedOptionButton.bind(this)}>
|
||||||
<span class='item-option-button-inner'>
|
<span class='item-option-button-inner'>
|
||||||
|
<slot name='start'></slot>
|
||||||
|
<slot name='top'></slot>
|
||||||
|
<slot name='icon-only'></slot>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
<slot name='bottom'></slot>
|
||||||
|
<slot name='end'></slot>
|
||||||
</span>
|
</span>
|
||||||
];
|
</TagType>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,13 @@ boolean
|
|||||||
If true, the user cannot interact with the item option. Defaults to `false`.
|
If true, the user cannot interact with the item option. Defaults to `false`.
|
||||||
|
|
||||||
|
|
||||||
|
#### expandable
|
||||||
|
|
||||||
|
boolean
|
||||||
|
|
||||||
|
If true, the option will expand to take up the available width and cover any other options. Defaults to `false`.
|
||||||
|
|
||||||
|
|
||||||
#### href
|
#### href
|
||||||
|
|
||||||
string
|
string
|
||||||
@ -61,6 +68,13 @@ boolean
|
|||||||
If true, the user cannot interact with the item option. Defaults to `false`.
|
If true, the user cannot interact with the item option. Defaults to `false`.
|
||||||
|
|
||||||
|
|
||||||
|
#### expandable
|
||||||
|
|
||||||
|
boolean
|
||||||
|
|
||||||
|
If true, the option will expand to take up the available width and cover any other options. Defaults to `false`.
|
||||||
|
|
||||||
|
|
||||||
#### href
|
#### href
|
||||||
|
|
||||||
string
|
string
|
||||||
|
@ -11,7 +11,10 @@ ion-item-options {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
|
||||||
|
&.hydrated {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
@include multi-dir() {
|
@include multi-dir() {
|
||||||
// scss-lint:disable PropertySpelling
|
// scss-lint:disable PropertySpelling
|
||||||
@ -53,9 +56,9 @@ ion-item-options[side=left] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding.active-slide {
|
.item-sliding-active-slide {
|
||||||
@include rtl() {
|
@include rtl() {
|
||||||
&.active-options-left ion-item-options:not([side=right]) {
|
&.item-sliding-active-options-left ion-item-options:not([side=right]) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
@ -66,8 +69,8 @@ ion-item-sliding.active-slide {
|
|||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active-options-left ion-item-options[side=left],
|
&.item-sliding-active-options-left ion-item-options[side=left],
|
||||||
&.active-options-right ion-item-options:not([side=left]) {
|
&.item-sliding-active-options-right ion-item-options:not([side=left]) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
|
@ -11,7 +11,7 @@ ion-item-sliding {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
ion-item-sliding.active-slide {
|
.item-sliding-active-slide {
|
||||||
ion-item,
|
ion-item,
|
||||||
ion-item.activated {
|
ion-item.activated {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -34,7 +34,6 @@ export const enum SlidingState {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
export class ItemSliding {
|
export class ItemSliding {
|
||||||
|
|
||||||
private item: HTMLIonItemElement;
|
private item: HTMLIonItemElement;
|
||||||
private list: HTMLIonListElement;
|
private list: HTMLIonListElement;
|
||||||
private openAmount = 0;
|
private openAmount = 0;
|
||||||
@ -42,55 +41,20 @@ export class ItemSliding {
|
|||||||
private optsWidthRightSide = 0;
|
private optsWidthRightSide = 0;
|
||||||
private optsWidthLeftSide = 0;
|
private optsWidthLeftSide = 0;
|
||||||
private sides: ItemSide;
|
private sides: ItemSide;
|
||||||
private tmr: any = null;
|
private tmr: number;
|
||||||
private leftOptions: ItemOptions;
|
private leftOptions: ItemOptions;
|
||||||
private rightOptions: ItemOptions;
|
private rightOptions: ItemOptions;
|
||||||
private optsDirty = true;
|
private optsDirty = true;
|
||||||
private gestureOptions: any;
|
|
||||||
|
|
||||||
@Element() private el: HTMLElement;
|
@Element() private el: HTMLElement;
|
||||||
@State() state: SlidingState = SlidingState.Disabled;
|
|
||||||
|
|
||||||
|
@State() state: SlidingState = SlidingState.Disabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emitted when the sliding position changes.
|
* 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');
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@Event() ionDrag: EventEmitter;
|
@Event() ionDrag: EventEmitter;
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.gestureOptions = {
|
|
||||||
'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'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidLoad() {
|
componentDidLoad() {
|
||||||
this.item = this.el.querySelector('ion-item');
|
this.item = this.el.querySelector('ion-item');
|
||||||
this.list = this.el.closest('ion-list') as HTMLIonListElement;
|
this.list = this.el.closest('ion-list') as HTMLIonListElement;
|
||||||
@ -102,18 +66,27 @@ export class ItemSliding {
|
|||||||
this.item = this.list = this.leftOptions = this.rightOptions = null;
|
this.item = this.list = this.leftOptions = this.rightOptions = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the amount the item is open in pixels.
|
||||||
|
*/
|
||||||
@Method()
|
@Method()
|
||||||
getOpenAmount(): number {
|
getOpenAmount(): number {
|
||||||
return this.openAmount;
|
return this.openAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the ratio of the open amount of the item compared to the width of the options.
|
||||||
|
* If the number returned is positive, then the options on the right side are open.
|
||||||
|
* If the number returned is negative, then the options on the left side are open.
|
||||||
|
* If the absolute value of the number is greater than 1, the item is open more than
|
||||||
|
* the width of the options.
|
||||||
|
*/
|
||||||
@Method()
|
@Method()
|
||||||
getSlidingPercent(): number {
|
getSlidingRatio(): number {
|
||||||
const openAmount = this.openAmount;
|
if (this.openAmount > 0) {
|
||||||
if (openAmount > 0) {
|
return this.openAmount / this.optsWidthRightSide;
|
||||||
return openAmount / this.optsWidthRightSide;
|
} else if (this.openAmount < 0) {
|
||||||
} else if (openAmount < 0) {
|
return this.openAmount / this.optsWidthLeftSide;
|
||||||
return openAmount / this.optsWidthLeftSide;
|
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -122,43 +95,15 @@ export class ItemSliding {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the sliding item. Items can also be closed from the [List](../../list/List).
|
* 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();
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
*/
|
||||||
@Method()
|
@Method()
|
||||||
close() {
|
close() {
|
||||||
this.setOpenAmount(0, true);
|
this.setOpenAmount(0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close all of the sliding items in the list. Items can also be closed from the [List](../../list/List).
|
||||||
|
*/
|
||||||
@Method()
|
@Method()
|
||||||
closeOpened(): boolean {
|
closeOpened(): boolean {
|
||||||
return this.list && this.list.closeSlidingItems();
|
return this.list && this.list.closeSlidingItems();
|
||||||
@ -286,20 +231,18 @@ export class ItemSliding {
|
|||||||
|
|
||||||
if (isFinal) {
|
if (isFinal) {
|
||||||
style.transition = '';
|
style.transition = '';
|
||||||
|
}
|
||||||
|
|
||||||
} else if (openAmount > 0) {
|
if (openAmount > 0) {
|
||||||
this.state = (openAmount >= (this.optsWidthRightSide + SWIPE_MARGIN))
|
this.state = (openAmount >= (this.optsWidthRightSide + SWIPE_MARGIN))
|
||||||
? SlidingState.Right | SlidingState.SwipeRight
|
? SlidingState.Right | SlidingState.SwipeRight
|
||||||
: SlidingState.Right;
|
: SlidingState.Right;
|
||||||
|
|
||||||
} else if (openAmount < 0) {
|
} else if (openAmount < 0) {
|
||||||
this.state = (openAmount <= (-this.optsWidthLeftSide - SWIPE_MARGIN))
|
this.state = (openAmount <= (-this.optsWidthLeftSide - SWIPE_MARGIN))
|
||||||
? SlidingState.Left | SlidingState.SwipeLeft
|
? SlidingState.Left | SlidingState.SwipeLeft
|
||||||
: SlidingState.Left;
|
: SlidingState.Left;
|
||||||
}
|
} else {
|
||||||
|
this.tmr = window.setTimeout(() => {
|
||||||
if (openAmount === 0) {
|
|
||||||
this.tmr = setTimeout(() => {
|
|
||||||
this.state = SlidingState.Disabled;
|
this.state = SlidingState.Disabled;
|
||||||
this.tmr = null;
|
this.tmr = null;
|
||||||
}, 600);
|
}, 600);
|
||||||
@ -315,19 +258,31 @@ export class ItemSliding {
|
|||||||
hostData() {
|
hostData() {
|
||||||
return {
|
return {
|
||||||
class: {
|
class: {
|
||||||
'item-wrapper': true,
|
'item-sliding': true,
|
||||||
'active-slide': (this.state !== SlidingState.Disabled),
|
'item-sliding-active-slide': (this.state !== SlidingState.Disabled),
|
||||||
'active-options-right': !!(this.state & SlidingState.Right),
|
'item-sliding-active-options-right': !!(this.state & SlidingState.Right),
|
||||||
'active-options-left': !!(this.state & SlidingState.Left),
|
'item-sliding-active-options-left': !!(this.state & SlidingState.Left),
|
||||||
'active-swipe-right': !!(this.state & SlidingState.SwipeRight),
|
'item-sliding-active-swipe-right': !!(this.state & SlidingState.SwipeRight),
|
||||||
'active-swipe-left': !!(this.state & SlidingState.SwipeLeft)
|
'item-sliding-active-swipe-left': !!(this.state & SlidingState.SwipeLeft)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ion-gesture {...this.gestureOptions}>
|
<ion-gesture {...{
|
||||||
|
'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>
|
<slot></slot>
|
||||||
</ion-gesture>
|
</ion-gesture>
|
||||||
);
|
);
|
||||||
|
@ -1,79 +1,72 @@
|
|||||||
# ion-item-sliding
|
# ion-item-sliding
|
||||||
|
|
||||||
A sliding item is a list item that can be swiped to reveal buttons. It requires
|
A Sliding item is a component that contains an item that can be dragged to reveal buttons. It requires an [Item](../Item) component as a child. All options to reveal should be placed in the item options element.
|
||||||
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.
|
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<ion-list>
|
<ion-list>
|
||||||
<ion-item-sliding #item>
|
<ion-item-sliding>
|
||||||
<ion-item>
|
<ion-item>
|
||||||
Item
|
<ion-label>Item</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item-options side="left">
|
<ion-item-options side="left">
|
||||||
<ion-button (click)="favorite(item)">Favorite</ion-button>
|
<ion-item-option onClick="favorite(item)">Favorite</ion-item-option>
|
||||||
<ion-button color="danger" (click)="share(item)">Share</ion-button>
|
<ion-item-option color="danger" onClick="share(item)">Share</ion-item-option>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
|
|
||||||
<ion-item-options side="right">
|
<ion-item-options side="right">
|
||||||
<ion-button (click)="unread(item)">Unread</ion-button>
|
<ion-item-option onClick="unread(item)">Unread</ion-item-option>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
</ion-list>
|
</ion-list>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Swipe Direction
|
### Direction
|
||||||
|
|
||||||
By default, the buttons are revealed when the sliding item is swiped from right to left,
|
By default, the options are revealed when the sliding item is swiped from right to left, so the buttons are placed on the right side. It's also possible to reveal them from the right side by setting the `side` attribute on the `ion-item-options` element. Up to two `ion-item-options` can be used at the same time in order to reveal two different sets of options depending on the swiping direction.
|
||||||
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
|
```html
|
||||||
<ion-item-options side="right">
|
<ion-item-options side="right">
|
||||||
<ion-button (click)="archive(item)">
|
<ion-item-option onClick="archive(item)">
|
||||||
<ion-icon name="archive"></ion-icon>
|
<ion-icon name="archive"></ion-icon>
|
||||||
Archive
|
Archive
|
||||||
</ion-button>
|
</ion-item-option>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
|
|
||||||
<ion-item-options side="left">
|
<ion-item-options side="left">
|
||||||
<ion-button (click)="archive(item)">
|
<ion-item-option onClick="archive(item)">
|
||||||
<ion-icon name="archive"></ion-icon>
|
<ion-icon name="archive"></ion-icon>
|
||||||
Archive
|
Archive
|
||||||
</ion-button>
|
</ion-item-option>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Listening for events (ionDrag) and (ionSwipe)
|
### Events
|
||||||
It's possible to know the current relative position of the sliding item by subscribing
|
|
||||||
to the (ionDrag)` event.
|
It's possible to know the current relative position of the sliding item by subscribing to the ionDrag` event.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<ion-item-sliding (ionDrag)="logDrag($event)">
|
<ion-item-sliding>
|
||||||
<ion-item>Item</ion-item>
|
<ion-item>
|
||||||
|
<ion-label>Item</ion-label>
|
||||||
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<ion-button>Favorite</ion-button>
|
<ion-item-option>Favorite</ion-item-option>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Button Layout
|
### Layout
|
||||||
If an icon is placed with text in the option button, by default it will
|
By default if an icon is placed with text in the option button, 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.
|
||||||
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
|
```html
|
||||||
<ion-item-options icon-start>
|
<ion-item-options icon-start>
|
||||||
<ion-button (click)="archive(item)">
|
<ion-item-option onClick="archive(item)">
|
||||||
<ion-icon name="archive"></ion-icon>
|
<ion-icon name="archive"></ion-icon>
|
||||||
Archive
|
Archive
|
||||||
</ion-button>
|
</ion-item-option>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -81,22 +74,20 @@ to the left of the text by setting `icon-start` as an attribute on the
|
|||||||
|
|
||||||
### Expandable Options
|
### Expandable Options
|
||||||
|
|
||||||
Options can be expanded to take up the full width of the item if you swipe past
|
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.
|
||||||
a certain point. This can be combined with the `ionSwipe` event to call methods
|
|
||||||
on the class.
|
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
<ion-item-sliding>
|
||||||
<ion-item-sliding (ionSwipe)="delete(item)">
|
<ion-item>
|
||||||
<ion-item>Item</ion-item>
|
<ion-label>Item</ion-label>
|
||||||
|
</ion-item>
|
||||||
<ion-item-options>
|
<ion-item-options>
|
||||||
<ion-button expandable (click)="delete(item)">Delete</ion-button>
|
<ion-item-option expandable onClick="delete(item)">Delete</ion-item-option>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
</ion-item-sliding>
|
</ion-item-sliding>
|
||||||
```
|
```
|
||||||
|
|
||||||
We can call `delete` by either clicking the button, or by doing a full swipe on the item.
|
We can call `delete` by either clicking the option, or by doing a full swipe on the item.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Auto Generated Below -->
|
<!-- Auto Generated Below -->
|
||||||
@ -107,23 +98,6 @@ We can call `delete` by either clicking the button, or by doing a full swipe on
|
|||||||
#### ionDrag
|
#### ionDrag
|
||||||
|
|
||||||
Emitted when the sliding position changes.
|
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');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
@ -132,35 +106,24 @@ onDrag(slidingItem) {
|
|||||||
|
|
||||||
Close the sliding item. Items can also be closed from the [List](../../list/List).
|
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';
|
|
||||||
|
|
||||||
|
|
||||||
#### closeOpened()
|
#### closeOpened()
|
||||||
|
|
||||||
|
Close all of the sliding items in the list. Items can also be closed from the [List](../../list/List).
|
||||||
|
|
||||||
|
|
||||||
#### getOpenAmount()
|
#### getOpenAmount()
|
||||||
|
|
||||||
|
Get the amount the item is open in pixels.
|
||||||
|
|
||||||
#### getSlidingPercent()
|
|
||||||
|
#### getSlidingRatio()
|
||||||
|
|
||||||
|
Get the ratio of the open amount of the item compared to the width of the options.
|
||||||
|
If the number returned is positive, then the options on the right side are open.
|
||||||
|
If the number returned is negative, then the options on the left side are open.
|
||||||
|
If the absolute value of the number is greater than 1, the item is open more than
|
||||||
|
the width of the options.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@
|
|||||||
</ion-item-option>
|
</ion-item-option>
|
||||||
</ion-item-options>
|
</ion-item-options>
|
||||||
<ion-item-options side="right">
|
<ion-item-options side="right">
|
||||||
<ion-item-option color="light" onclick="unread('item100')">
|
<ion-item-option color="danger" onclick="unread('item100')">
|
||||||
<ion-icon slot="icon-only" name="trash"></ion-icon>
|
<ion-icon slot="icon-only" name="trash"></ion-icon>
|
||||||
</ion-item-option>
|
</ion-item-option>
|
||||||
<ion-item-option onclick="unread('item100')">
|
<ion-item-option onclick="unread('item100')">
|
||||||
@ -380,7 +380,24 @@
|
|||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
document.addEventListener('ionSwipe', (ev)=> console.log('SWIPE!!', ev.detail));
|
document.addEventListener('ionSwipe', (ev)=> console.log('SWIPE!!', ev.detail));
|
||||||
document.addEventListener('ionDrag', (ev)=> console.log('DRAG!!', ev.detail.getOpenAmount()));
|
document.addEventListener('ionDrag', (ev) => {
|
||||||
|
// console.log('DRAG!!', ev.detail);
|
||||||
|
|
||||||
|
let slidingRatio = ev.target.getSlidingRatio();
|
||||||
|
console.log('sliding', slidingRatio);
|
||||||
|
|
||||||
|
if (slidingRatio > 0) {
|
||||||
|
// positive
|
||||||
|
console.log('right side');
|
||||||
|
} else {
|
||||||
|
// negative
|
||||||
|
console.log('left side');
|
||||||
|
}
|
||||||
|
if (Math.abs(slidingRatio) > 1) {
|
||||||
|
console.log('overscroll');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
|
@ -13,12 +13,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list-ios > .item-block:last-child,
|
.list-ios > .item-block:last-child,
|
||||||
.list-ios > .item-wrapper:last-child .item-block {
|
.list-ios > .item-sliding:last-child .item-block {
|
||||||
border-bottom: $hairlines-width solid $item-ios-border-color;
|
border-bottom: $hairlines-width solid $item-ios-border-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-ios > .item-block:last-child .item-inner,
|
.list-ios > .item-block:last-child .item-inner,
|
||||||
.list-ios > .item-wrapper:last-child .item-block .item-inner {
|
.list-ios > .item-sliding:last-child .item-block .item-inner {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,12 +61,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list-ios[inset] > .item:first-child,
|
.list-ios[inset] > .item:first-child,
|
||||||
.list-ios[inset] > .item-wrapper:first-child .item {
|
.list-ios[inset] > .item-sliding:first-child .item {
|
||||||
border-top: 0;
|
border-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.list-ios[inset] > .item:last-child,
|
.list-ios[inset] > .item:last-child,
|
||||||
.list-ios[inset] > .item-wrapper:last-child .item {
|
.list-ios[inset] > .item-sliding:last-child .item {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.list-md > .item-block:last-child,
|
.list-md > .item-block:last-child,
|
||||||
.list-md > .item-wrapper:last-child {
|
.list-md > .item-sliding:last-child {
|
||||||
ion-label,
|
ion-label,
|
||||||
.item-inner {
|
.item-inner {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
|
@ -26,6 +26,9 @@ export class List {
|
|||||||
this.openedItem = itemSliding;
|
this.openedItem = itemSliding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the sliding items. Items can also be closed from the [Item Sliding](../../item-sliding/ItemSliding).
|
||||||
|
*/
|
||||||
@Method()
|
@Method()
|
||||||
closeSlidingItems(): boolean {
|
closeSlidingItems(): boolean {
|
||||||
if (this.openedItem) {
|
if (this.openedItem) {
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#### closeSlidingItems()
|
#### closeSlidingItems()
|
||||||
|
|
||||||
|
Close the sliding items. Items can also be closed from the [Item Sliding](../../item-sliding/ItemSliding).
|
||||||
|
|
||||||
|
|
||||||
#### getOpenedItem()
|
#### getOpenedItem()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user