diff --git a/packages/core/package-lock.json b/packages/core/package-lock.json
index 6aa05215c5..b2bab1566d 100644
--- a/packages/core/package-lock.json
+++ b/packages/core/package-lock.json
@@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"@stencil/core": {
- "version": "0.0.6-2",
- "resolved": "https://registry.npmjs.org/@stencil/core/-/core-0.0.6-2.tgz",
- "integrity": "sha512-sr6U3Hbdsk8WLn5ZKckATRWkHmCbZqsJFr8R7wFj0SCLLUtdpOKh6+p+C+taJguFx+sm0n14JnybFFrpmB0mvg==",
+ "version": "0.0.6-4",
+ "resolved": "https://registry.npmjs.org/@stencil/core/-/core-0.0.6-4.tgz",
+ "integrity": "sha512-QWuC6K07Y1Iv+uit040QFrpMa5dBRhDQhg3qRZ88fWMZQ1vpHnUggfavzfjNNDdfu5AhvG9BcT5jMYgG2rPTfg==",
"dev": true,
"requires": {
"chokidar": "1.7.0",
@@ -58,9 +58,9 @@
"dev": true
},
"abbrev": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
- "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true
},
"acorn": {
@@ -2282,14 +2282,6 @@
}
}
},
- "string_decoder": {
- "version": "1.0.1",
- "bundled": true,
- "dev": true,
- "requires": {
- "safe-buffer": "5.0.1"
- }
- },
"string-width": {
"version": "1.0.2",
"bundled": true,
@@ -2300,6 +2292,14 @@
"strip-ansi": "3.0.1"
}
},
+ "string_decoder": {
+ "version": "1.0.1",
+ "bundled": true,
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.0.1"
+ }
+ },
"stringstream": {
"version": "0.0.5",
"bundled": true,
@@ -4526,7 +4526,7 @@
"integrity": "sha512-kxBL06p6iO2qPBHsqGK2b3cRwiRGpnmSuVWNhwHcMX7qJOUr1HvricYP1LZOCdkQBUp0jiWg2d6WJwR3vYgByw==",
"dev": true,
"requires": {
- "vlq": "0.2.2"
+ "vlq": "0.2.3"
}
},
"makeerror": {
@@ -4760,7 +4760,7 @@
"integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
"dev": true,
"requires": {
- "abbrev": "1.1.0"
+ "abbrev": "1.1.1"
}
},
"normalize-package-data": {
@@ -5745,15 +5745,6 @@
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
"dev": true
},
- "string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "dev": true,
- "requires": {
- "safe-buffer": "5.1.1"
- }
- },
"string-length": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz",
@@ -5798,6 +5789,15 @@
"strip-ansi": "3.0.1"
}
},
+ "string_decoder": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+ "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "5.1.1"
+ }
+ },
"stringstream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
@@ -6233,9 +6233,9 @@
}
},
"vlq": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.2.tgz",
- "integrity": "sha1-4xbVJXtAuGu0PLjV/qXX9U1rDKE=",
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
+ "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==",
"dev": true
},
"walker": {
diff --git a/packages/core/package.json b/packages/core/package.json
index c55a13ea74..3fd6e4b096 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -10,7 +10,7 @@
"dist/"
],
"devDependencies": {
- "@stencil/core": "0.0.6-2",
+ "@stencil/core": "0.0.6-4",
"@stencil/dev-server": "latest",
"@stencil/utils": "latest",
"@types/jest": "^21.1.0",
@@ -26,7 +26,7 @@
"test": "jest --no-cache",
"test.watch": "jest --watch --no-cache",
"clean": "rm -rf dist",
- "lint": "npm run tslint",
+ "lint": "npm run tslint & npm run sass-lint",
"sass-lint": "sass-lint -v -q",
"tslint": "tslint --project .",
"tslint-fix": "tslint --project . --fix",
diff --git a/packages/core/src/components/button/test/button.spec.ts b/packages/core/src/components/button/test/button.spec.ts
index aebefad187..0dd4cf839f 100644
--- a/packages/core/src/components/button/test/button.spec.ts
+++ b/packages/core/src/components/button/test/button.spec.ts
@@ -1,4 +1,4 @@
-import { render, flush } from '@stencil/core/testing';
+import { flush, render } from '@stencil/core/testing';
import { Button } from '../button';
diff --git a/packages/core/src/components/gesture/gesture.tsx b/packages/core/src/components/gesture/gesture.tsx
index 8d98ce94ec..aafd72d296 100644
--- a/packages/core/src/components/gesture/gesture.tsx
+++ b/packages/core/src/components/gesture/gesture.tsx
@@ -167,6 +167,9 @@ export class Gesture {
this.positions.push(detail.currentX, detail.currentY, timeStamp);
if (this.pan) {
this.hasStartedPan = true;
+ if (this.threshold === 0) {
+ return this.tryToCapturePan();
+ }
this.pan.start(detail.startX, detail.startY);
}
return true;
diff --git a/packages/core/src/components/item/item.scss b/packages/core/src/components/item/item.scss
index cc7cdd18fb..702ee852cb 100644
--- a/packages/core/src/components/item/item.scss
+++ b/packages/core/src/components/item/item.scss
@@ -97,10 +97,3 @@ ion-input.item {
background: transparent;
cursor: pointer;
}
-
-[reorderAnchor] {
- display: none;
-
- pointer-events: all !important;
- touch-action: manipulation;
-}
diff --git a/packages/core/src/components/reorder/reorder-group.tsx b/packages/core/src/components/reorder/reorder-group.tsx
index f97c689036..24795099bb 100644
--- a/packages/core/src/components/reorder/reorder-group.tsx
+++ b/packages/core/src/components/reorder/reorder-group.tsx
@@ -1,11 +1,11 @@
import { Component, Element, Prop, PropDidChange, State } from '@stencil/core';
import { GestureDetail } from '../../index';
-import { reorderArray } from '../../utils/helpers';
+import { clamp, reorderArray } from '../../utils/helpers';
import { CSS_PROP } from '../animation-controller/constants';
-// const AUTO_SCROLL_MARGIN = 60;
-// const SCROLL_JUMP = 10;
-const ITEM_REORDER_ACTIVE = 'reorder-active';
+const AUTO_SCROLL_MARGIN = 60;
+const SCROLL_JUMP = 10;
+const ITEM_REORDER_SELECTED = 'reorder-selected';
export class ReorderIndexes {
@@ -147,10 +147,16 @@ export class ReorderGroup {
private selectedItemEle: HTMLElement = null;
private selectedItemHeight: number;
private lastToIndex: number;
- private lastYcoord: number;
- private topOfList: number;
private cachedHeights: number[] = [];
private containerEle: HTMLElement;
+ private scrollEle: HTMLElement;
+
+ private scrollTop: number;
+ private scrollBottom: number;
+ private scrollInitial: number;
+
+ private containerTop: number;
+ private containerBottom: number;
@State() _enabled: boolean = false;
@State() _iconVisible: boolean = false;
@@ -178,6 +184,7 @@ export class ReorderGroup {
ionViewDidLoad() {
this.containerEle = this.ele.querySelector('ion-gesture') as HTMLElement;
+ this.scrollEle = this.ele.closest('ion-scroll') as HTMLElement;
}
ionViewDidUnload() {
@@ -189,7 +196,7 @@ export class ReorderGroup {
return false;
}
const target = ev.event.target as HTMLElement;
- const reorderEle = target.closest('[reorderAnchor]') as HTMLElement;
+ const reorderEle = target.closest('ion-reorder') as HTMLElement;
if (!reorderEle) {
return false;
}
@@ -213,20 +220,33 @@ export class ReorderGroup {
}
let sum = 0;
- for (let i = 0, ilen = children.length; i < ilen; i++) {
+ for (var i = 0, ilen = children.length; i < ilen; i++) {
var child = children[i];
sum += child.offsetHeight;
heights.push(sum);
child.$ionIndex = i;
}
- this.topOfList = item.getBoundingClientRect().top;
- this._actived = true;
- this.lastYcoord = -100;
+ const box = this.containerEle.getBoundingClientRect();
+ this.containerTop = box.top;
+ this.containerBottom = box.bottom;
+
+ if (this.scrollEle) {
+ var scrollBox = this.scrollEle.getBoundingClientRect();
+ this.scrollInitial = this.scrollEle.scrollTop;
+ this.scrollTop = scrollBox.top + AUTO_SCROLL_MARGIN;
+ this.scrollBottom = scrollBox.bottom - AUTO_SCROLL_MARGIN;
+ } else {
+ this.scrollInitial = 0;
+ this.scrollTop = 0;
+ this.scrollBottom = 0;
+ }
+
this.lastToIndex = indexForItem(item);
this.selectedItemHeight = item.offsetHeight;
+ this._actived = true;
- item.classList.add(ITEM_REORDER_ACTIVE);
+ item.classList.add(ITEM_REORDER_SELECTED);
}
private onDragMove(ev: GestureDetail) {
@@ -234,26 +254,24 @@ export class ReorderGroup {
if (!selectedItem) {
return;
}
- // ev.event.preventDefault();
+ // Scroll if we reach the scroll margins
+ const scroll = this.autoscroll(ev.currentY);
// // Get coordinate
- const posY = ev.deltaY;
-
- // Scroll if we reach the scroll margins
- // const scrollPosition = this.scroll(posY);
- // Only perform hit test if we moved at least 30px from previous position
- if (Math.abs(posY - this.lastYcoord) > 30) {
- let toIndex = this.itemIndexForDelta(posY);
- if (toIndex !== undefined && (toIndex !== this.lastToIndex)) {
- let fromIndex = indexForItem(selectedItem);
- this.lastToIndex = toIndex;
- this.lastYcoord = posY;
- this._reorderMove(fromIndex, toIndex, this.selectedItemHeight);
- }
+ const top = this.containerTop - scroll;
+ const bottom = this.containerBottom - scroll;
+ const currentY = clamp(top, ev.currentY, bottom);
+ const deltaY = scroll + currentY - ev.startY;
+ const normalizedY = currentY - top;
+ const toIndex = this.itemIndexForTop(normalizedY);
+ if (toIndex !== undefined && (toIndex !== this.lastToIndex)) {
+ let fromIndex = indexForItem(selectedItem);
+ this.lastToIndex = toIndex;
+ this._reorderMove(fromIndex, toIndex);
}
// Update selected item position
- (selectedItem.style as any)[CSS_PROP.transformProp] = `translateY(${posY}px)`;
+ (selectedItem.style as any)[CSS_PROP.transformProp] = `translateY(${deltaY}px)`;
}
private onDragEnd() {
@@ -285,7 +303,7 @@ export class ReorderGroup {
const reorderInactive = () => {
this.selectedItemEle.style.transition = '';
- this.selectedItemEle.classList.remove(ITEM_REORDER_ACTIVE);
+ this.selectedItemEle.classList.remove(ITEM_REORDER_SELECTED);
this.selectedItemEle = null;
};
if (toIndex === fromIndex) {
@@ -296,24 +314,29 @@ export class ReorderGroup {
}
}
- private itemIndexForDelta(deltaY: number): number {
+ private itemIndexForTop(deltaY: number): number {
const heights = this.cachedHeights;
- let sum = deltaY + this.topOfList - (this.selectedItemHeight / 2);
- for (var i = 0; i < heights.length; i++) {
- if (heights[i] > sum) {
- return i;
+ let i = 0;
+
+ // TODO: since heights is a sorted array of integers, we can do
+ // speed up the search using binary search. Remember that linear-search is still
+ // faster than binary-search for small arrays (<64) due CPU branch misprediction.
+ for (i = 0; i < heights.length; i++) {
+ if (heights[i] > deltaY) {
+ break;
}
}
- return null;
+ return i;
}
- private _reorderMove(fromIndex: number, toIndex: number, itemHeight: number) {
- /********* DOM WRITE ********* */
+ /********* DOM WRITE ********* */
+ private _reorderMove(fromIndex: number, toIndex: number) {
+ const itemHeight = this.selectedItemHeight;
const children = this.containerEle.children;
const transform = CSS_PROP.transformProp;
for (var i = 0; i < children.length; i++) {
- const style = (children[i] as any).style;
- let value = '';
+ var style = (children[i] as any).style;
+ var value = '';
if (i > fromIndex && i <= toIndex) {
value = `translateY(${-itemHeight}px)`;
} else if (i < fromIndex && i >= toIndex) {
@@ -323,6 +346,23 @@ export class ReorderGroup {
}
}
+ private autoscroll(posY: number): number {
+ if (!this.scrollEle) {
+ return 0;
+ }
+
+ let amount = 0;
+ if (posY < this.scrollTop) {
+ amount = -SCROLL_JUMP;
+ } else if (posY > this.scrollBottom) {
+ amount = SCROLL_JUMP;
+ }
+ if (amount !== 0) {
+ this.scrollEle.scrollBy(0, amount);
+ }
+ return this.scrollEle.scrollTop - this.scrollInitial;
+ }
+
hostData() {
return {
class: {
diff --git a/packages/core/src/components/reorder/reorder.scss b/packages/core/src/components/reorder/reorder.scss
index a16b01f215..8b1bfb3deb 100644
--- a/packages/core/src/components/reorder/reorder.scss
+++ b/packages/core/src/components/reorder/reorder.scss
@@ -4,8 +4,7 @@ $reorder-initial-transform: 160% !default;
// Reorder group general
// --------------------------------------------------
-
-.reorder-enabled [reorderAnchor] {
+ion-reorder-group > ion-gesture {
display: block;
}
@@ -15,50 +14,68 @@ $reorder-initial-transform: 160% !default;
will-change: transform;
}
-.reorder-list-active ion-gesture *:not([reorderAnchor]) {
- pointer-events: none;
-}
-
-.reorder-active {
+.reorder-selected {
position: relative;
z-index: 100;
box-shadow: 0 0 10px rgba(0, 0, 0, .4);
opacity: .8;
transition: none !important;
-
- pointer-events: none;
}
// Reorder icon
// --------------------------------------------------
-ion-reorder {
- @include transform(translate3d($reorder-initial-transform, 0, 0));
+ion-reorder.no-hide {
+ display: block;
+ visibility: normal;
+}
+
+ion-reorder:not(.no-hide) {
+ display: none;
+
+ pointer-events: all !important;
+ touch-action: manipulation;
+}
+
+.reorder-enabled ion-reorder {
+ display: block;
+
+ cursor: grab;
+ cursor: -webkit-grab;
+}
+
+.reorder-selected,
+.reorder-selected ion-reorder {
+ cursor: grabbing;
+ cursor: -webkit-grabbing;
+}
+
+ion-reorder[slot] {
+ line-height: 0;
margin-top: auto !important;
margin-bottom: auto !important;
+}
- font-size: 1.7em;
+ion-reorder[slot="start"] {
+ order: -1;
+}
+
+.reorder-icon {
+ @include transform(translate3d($reorder-initial-transform, 0, 0));
+
+ font-size: 1.3em;
opacity: .25;
- line-height: 0;
-
transition: transform 140ms ease-in;
}
-ion-reorder ion-icon {
- pointer-events: none;
-}
-
-ion-reorder[slot="start"] {
+ion-reorder[slot="start"] .reorder-icon {
@include transform(translate3d(-$reorder-initial-transform, 0, 0));
-
- order: -1;
}
-.reorder-visible ion-reorder {
+.reorder-visible ion-reorder .reorder-icon {
@include transform(translate3d(0, 0, 0));
}
-
diff --git a/packages/core/src/components/reorder/reorder.tsx b/packages/core/src/components/reorder/reorder.tsx
index 8100af5c98..44aba5d37c 100644
--- a/packages/core/src/components/reorder/reorder.tsx
+++ b/packages/core/src/components/reorder/reorder.tsx
@@ -1,20 +1,26 @@
-import { Component } from '@stencil/core';
+import { Component, Element, State } from '@stencil/core';
@Component({
tag: 'ion-reorder',
})
export class ItemReorder {
- hostData() {
- return {
- attrs: {
- 'reorderAnchor': '',
- }
- };
+ @State() hasContent: boolean = null;
+ @Element() ele: HTMLElement;
+
+ ionViewDidLoad() {
+ this.hasContent = this.ele.childElementCount > 0;
}
render() {
- return ;
+ // TODO: https://github.com/ionic-team/stencil/issues/171
+ if (this.hasContent === true) {
+ return ;
+ } else if (this.hasContent === false) {
+ return ;
+ } else {
+ return undefined;
+ }
}
-}
+}
diff --git a/packages/core/src/components/reorder/test/basic.html b/packages/core/src/components/reorder/test/basic.html
index 4d5aaf5178..5ee421291b 100644
--- a/packages/core/src/components/reorder/test/basic.html
+++ b/packages/core/src/components/reorder/test/basic.html
@@ -22,54 +22,49 @@
+
- Item 1
+ Item 1 (default ion-reorder)
- Item 2
-
-
- Item 3
-
-
- Item 4
-
+
+ Item 2 (default ion-reorder)
+
- Item 5
-
+
+ Item 3 (default ion-reorder slot="start")
+
- Item 6
-
+
+ Item 4 (custom ion-reorder)
+
- Item 7
-
+
+ Item 5 (custom ion-reorder)
+
- Item 8
-
+
+ Item 6 (custom ion-reorder slot="start")
+
- Item 9
-
-
- Item 10
-
+
+ Item 7 (the whole item can be dragged)
+
-
- Item 11
-
+
+ Item 8 (the whole item can be dragged)
+
+
+
+ Item 9 (the whole item can be dragged)
+
-
- Item 12
-
-
- Item 13
-
-