From 61bfaa0fefe8fc92b5d597f2b3f9d8f46bdeb8b9 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:41:40 +0100 Subject: [PATCH 001/292] Add node versions --- .nvmrc | 1 + package.json | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..ca063943 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +6.2.2 diff --git a/package.json b/package.json index f8bab769..57eb88d9 100644 --- a/package.json +++ b/package.json @@ -38,5 +38,8 @@ "react": ">=0.14.7", "react-dom": ">=0.14.7", "watchify": "=3.6.1" + }, + "engines": { + "node": "6.2.2" } } From 3f402442ace8c49dac52fe702cfe04426fa6c19a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:45:49 +0100 Subject: [PATCH 002/292] Add babelify --- examples/.babelrc | 3 +++ package.json | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 examples/.babelrc diff --git a/examples/.babelrc b/examples/.babelrc new file mode 100644 index 00000000..12d195e5 --- /dev/null +++ b/examples/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["react"] +} diff --git a/package.json b/package.json index 57eb88d9..bf164cb8 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "scripts": { "start": "http-server examples/ -c-1 -o", "build-less": "lessc examples/src/less/index.less examples/build/css/index.css && echo 'Less compiled'", - "build-js": "browserify examples/src/js/index.js -o examples/build/js/index.js", - "watch-js": "watchify examples/src/js/index.js -o examples/build/js/index.js -v", + "build-js": "browserify -t babelify examples/src/js/index.js -o examples/build/js/index.js", + "watch-js": "watchify -t babelify examples/src/js/index.js -o examples/build/js/index.js -v", "build-dirs": "mkdir -p examples/build/css/ && mkdir -p examples/build/js/", "build": "npm run build-dirs && npm run build-less && npm run build-js", "watch": "npm run watch-js" @@ -32,6 +32,8 @@ ], "dependencies": {}, "devDependencies": { + "babel-preset-react": "=6.11.1", + "babelify": "=7.3.0", "browserify": "=12.0.1", "http-server": "=0.8.5", "less": "=2.5.3", From 768dd2adc5d4544f9f65cbeeda0191dc47c45217 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:46:00 +0100 Subject: [PATCH 003/292] Add linting --- package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index bf164cb8..ea2af32f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,10 @@ "watch-js": "watchify -t babelify examples/src/js/index.js -o examples/build/js/index.js -v", "build-dirs": "mkdir -p examples/build/css/ && mkdir -p examples/build/js/", "build": "npm run build-dirs && npm run build-less && npm run build-js", - "watch": "npm run watch-js" + "watch": "npm run watch-js", + "lint-lib": "eslint -c node_modules/eslintrc/.eslintrc-es5 lib/index.js", + "lint-examples": "eslint -c node_modules/eslintrc/.eslintrc-es5-react lib/index.js", + "test": "npm run lint-lib && npm run lint-examples" }, "bugs": "https://github.com/JakeSidSmith/react-reorder/issues", "repository": { @@ -35,6 +38,7 @@ "babel-preset-react": "=6.11.1", "babelify": "=7.3.0", "browserify": "=12.0.1", + "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", "less": "=2.5.3", "react": ">=0.14.7", From 212e05bb9b81fe259dd1e72b371fde961e57aa0c Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:46:06 +0100 Subject: [PATCH 004/292] Update React --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ea2af32f..4125bdee 100644 --- a/package.json +++ b/package.json @@ -41,8 +41,8 @@ "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", "less": "=2.5.3", - "react": ">=0.14.7", - "react-dom": ">=0.14.7", + "react": "=15.3.1", + "react-dom": "=15.3.1", "watchify": "=3.6.1" }, "engines": { From 9d55242c4c9257f50c487a4df82f9e374f9db6ed Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:49:45 +0100 Subject: [PATCH 005/292] Move main index.js --- examples/src/js/index.js | 2 +- index.js => lib/index.js | 0 package.json | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename index.js => lib/index.js (100%) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index d65ece74..105d35d2 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -2,7 +2,7 @@ var React = require('react'); var ReactDOM = require('react-dom'); -var Reorder = require('../../../index'); +var Reorder = require('../../../lib/index'); var ListItem = React.createClass({ render: function () { diff --git a/index.js b/lib/index.js similarity index 100% rename from index.js rename to lib/index.js diff --git a/package.json b/package.json index 4125bdee..7815624f 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", - "main": "index.js", + "main": "lib/index.js", "scripts": { "start": "http-server examples/ -c-1 -o", "build-less": "lessc examples/src/less/index.less examples/build/css/index.css && echo 'Less compiled'", From 25d56e8c986570d1321b58888c4ef2dfb5617185 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:52:43 +0100 Subject: [PATCH 006/292] Fix a few linting issues --- lib/index.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/index.js b/lib/index.js index b3d4813a..22f0c768 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,6 @@ -(function () { - 'use strict'; +'use strict'; +(function () { var getReorderComponent = function (React, ReactDOM) { return React.createClass({ @@ -67,7 +67,7 @@ }; // Timeout if holdTime is defined - var holdTime = Math.abs(parseInt(this.props.holdTime)); + var holdTime = Math.abs(parseInt(this.props.holdTime, 10)); if (holdTime) { this.holdTimeout = setTimeout(function () { @@ -279,8 +279,8 @@ } return rect.height - - parseInt(computedStyle.getPropertyValue('border-top-width') || computedStyle.borderTopWidth) - - parseInt(computedStyle.getPropertyValue('border-bottom-width') || computedStyle.borderBottomWidth); + parseInt(computedStyle.getPropertyValue('border-top-width') || computedStyle.borderTopWidth, 10) - + parseInt(computedStyle.getPropertyValue('border-bottom-width') || computedStyle.borderBottomWidth, 10); }, elementWidthMinusBorders: function (element) { var rect = element.getBoundingClientRect(); @@ -293,8 +293,8 @@ } return rect.width - - parseInt(computedStyle.getPropertyValue('border-left-width') || computedStyle.borderLeftWidth) - - parseInt(computedStyle.getPropertyValue('border-right-width') || computedStyle.borderRightWidth); + parseInt(computedStyle.getPropertyValue('border-left-width') || computedStyle.borderLeftWidth, 10) - + parseInt(computedStyle.getPropertyValue('border-right-width') || computedStyle.borderRightWidth, 10); }, setDraggedPosition: function (event) { var draggedStyle = { From f258dc922582dd6d11db4ec156aa1a359d5a8bfd Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:54:16 +0100 Subject: [PATCH 007/292] Fix line lengths --- lib/index.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/lib/index.js b/lib/index.js index 22f0c768..f0ce43bd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -118,7 +118,12 @@ } // Item clicked - if (typeof this.props.itemClicked === 'function' && !this.state.held && !this.state.moved && this.state.dragged) { + if ( + typeof this.props.itemClicked === 'function' && + !this.state.held && + !this.state.moved && + this.state.dragged + ) { this.props.itemClicked(event, this.state.dragged.item, this.state.dragged.index); } @@ -196,7 +201,10 @@ this.scrollIntervalY = setInterval(this.dragScrollY, this.constants.SCROLL_RATE); } } else { - if (event.clientY <= rect.bottom - this.constants.SCROLL_AREA && event.clientY >= rect.top + this.constants.SCROLL_AREA) { + if ( + event.clientY <= rect.bottom - this.constants.SCROLL_AREA && + event.clientY >= rect.top + this.constants.SCROLL_AREA + ) { clearInterval(this.scrollIntervalY); this.scrollIntervalY = undefined; } @@ -212,7 +220,10 @@ this.scrollIntervalX = setInterval(this.dragScrollX, this.constants.SCROLL_RATE); } } else { - if (event.clientX <= rect.right - this.constants.SCROLL_AREA && event.clientX >= rect.left + this.constants.SCROLL_AREA) { + if ( + event.clientX <= rect.right - this.constants.SCROLL_AREA && + event.clientX >= rect.left + this.constants.SCROLL_AREA + ) { clearInterval(this.scrollIntervalX); this.scrollIntervalX = undefined; } @@ -380,7 +391,8 @@ getSelectedClass: function (item) { if (typeof this.props.selected !== 'undefined') { if (typeof this.props.selectedKey !== 'undefined') { - return this.props.selected[this.props.selectedKey] === item[this.props.selectedKey] ? 'selected' : undefined; + return this.props.selected[this.props.selectedKey] === item[this.props.selectedKey] ? + 'selected' : undefined; } return this.props.selected === item ? 'selected' : undefined; } @@ -435,7 +447,11 @@ var targetClone = function () { if (self.state.held && self.state.dragged) { var itemKey = self.state.dragged.item[self.props.itemKey] || self.state.dragged.item; - var itemClass = [self.props.itemClass, self.getDraggedClass(self.state.dragged.item), self.getSelectedClass(self.state.dragged.item)].join(' '); + var itemClass = [ + self.props.itemClass, + self.getDraggedClass(self.state.dragged.item), + self.getSelectedClass(self.state.dragged.item) + ].join(' '); return React.createElement('div', { key: itemKey, className: itemClass, From c2105338b3570a3afc828dd5b5329488d6c7168f Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:57:10 +0100 Subject: [PATCH 008/292] Fix no lonely if --- lib/index.js | 48 ++++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/lib/index.js b/lib/index.js index f0ce43bd..612cc9e9 100644 --- a/lib/index.js +++ b/lib/index.js @@ -200,14 +200,12 @@ } else if (event.clientY > rect.bottom - this.constants.SCROLL_AREA) { this.scrollIntervalY = setInterval(this.dragScrollY, this.constants.SCROLL_RATE); } - } else { - if ( - event.clientY <= rect.bottom - this.constants.SCROLL_AREA && - event.clientY >= rect.top + this.constants.SCROLL_AREA - ) { - clearInterval(this.scrollIntervalY); - this.scrollIntervalY = undefined; - } + } else if ( + event.clientY <= rect.bottom - this.constants.SCROLL_AREA && + event.clientY >= rect.top + this.constants.SCROLL_AREA + ) { + clearInterval(this.scrollIntervalY); + this.scrollIntervalY = undefined; } }, handleDragScrollX: function (event) { @@ -219,14 +217,12 @@ } else if (event.clientX > rect.right - this.constants.SCROLL_AREA) { this.scrollIntervalX = setInterval(this.dragScrollX, this.constants.SCROLL_RATE); } - } else { - if ( - event.clientX <= rect.right - this.constants.SCROLL_AREA && - event.clientX >= rect.left + this.constants.SCROLL_AREA - ) { - clearInterval(this.scrollIntervalX); - this.scrollIntervalX = undefined; - } + } else if ( + event.clientX <= rect.right - this.constants.SCROLL_AREA && + event.clientX >= rect.left + this.constants.SCROLL_AREA + ) { + clearInterval(this.scrollIntervalX); + this.scrollIntervalX = undefined; } }, onMouseMove: function (event) { @@ -263,13 +259,11 @@ this.handleDragScrollY(event); this.handleDragScrollX(event); - } else { - if (this.state.downPos) { - // Cancel hold if mouse has moved - if (this.xHasMoved(event) || this.yHasMoved(event)) { - clearTimeout(this.holdTimeout); - this.setState({moved: true}); - } + } else if (this.state.downPos) { + // Cancel hold if mouse has moved + if (this.xHasMoved(event) || this.yHasMoved(event)) { + clearTimeout(this.holdTimeout); + this.setState({moved: true}); } } }, @@ -354,11 +348,9 @@ if (this.xCollision(rect, event)) { return listElements[i]; } - } else { - if (this.yCollision(rect, event)) { - if (this.xCollision(rect, event)) { - return listElements[i]; - } + } else if (this.yCollision(rect, event)) { + if (this.xCollision(rect, event)) { + return listElements[i]; } } From 8f21a2c5774cc78595587c7b8a33c8e11180e80a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:58:43 +0100 Subject: [PATCH 009/292] Fix AMD definitions --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index 612cc9e9..8b4f5f6c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -470,8 +470,8 @@ module.exports = getReorderComponent(React, ReactDOM); // Export for amd / require } else if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef - define(['react', 'react-dom'], function (React, ReactDOM) { // eslint-disable-line no-undef - return getReorderComponent(React, ReactDOM); + define(['react', 'react-dom'], function (ReactAMD, ReactDOMAMD) { // eslint-disable-line no-undef + return getReorderComponent(ReactAMD, ReactDOMAMD); }); // Export globally } else { From 8a3201c97d6c95c0adfe869e57d5ebbed149fa76 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 02:59:53 +0100 Subject: [PATCH 010/292] Move babelrc to (correct) root directory --- examples/.babelrc => .babelrc | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename examples/.babelrc => .babelrc (100%) diff --git a/examples/.babelrc b/.babelrc similarity index 100% rename from examples/.babelrc rename to .babelrc From 4a6b4a3764b801aa98c747aa851c900556c31327 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 03:08:35 +0100 Subject: [PATCH 011/292] Fix examples linting --- examples/src/js/index.js | 47 +++++++++++++++++++++++++++++++++++++--- package.json | 2 +- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 105d35d2..79340ccb 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -41,7 +41,10 @@ var Main = React.createClass({ var list = []; for (var i = 0; i < 10; i += 1) { - list.push({name: ['Thing', i].join(' '), color: ['rgb(',(i + 1) * 25, ',', 250 - ((i + 1) * 25),',0)'].join('')}); + list.push({ + name: ['Thing', i].join(' '), + color: ['rgb(', (i + 1) * 25, ',', 250 - ((i + 1) * 25), ',0)'].join('') + }); } return { @@ -50,12 +53,50 @@ var Main = React.createClass({ }; }, render: function () { + // return ( + //
+ //

+ // + // Lock horizontal + // + //

+ // + // This example has a hold time of 500 milliseconds before dragging begins, + // allowing for other events like clicking / tapping to be attached + // + //

+ // Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined} + //

+ //

+ // Prefix (shared props): + //

+ // + //
+ // ); + return React.createElement('div', {className: 'app'}, React.createElement('p', null, React.createElement('strong', null, 'Lock horizontal')), - React.createElement('small', null, 'This example has a hold time of 500 milliseconds before dragging begins, allowing for other events like clicking / tapping to be attached'), + React.createElement('small', null, 'This example has a hold time of 500 milliseconds before dragging begins,' + + 'allowing for other events like clicking / tapping to be attached'), - React.createElement('p', null, 'Selected item: ', this.state.clickedItem ? this.state.clickedItem.name : undefined), + React.createElement('p', null, + 'Selected item: ', this.state.clickedItem ? this.state.clickedItem.name : undefined), React.createElement('p', null, 'Prefix (shared props): ', diff --git a/package.json b/package.json index 7815624f..627a33f9 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "build": "npm run build-dirs && npm run build-less && npm run build-js", "watch": "npm run watch-js", "lint-lib": "eslint -c node_modules/eslintrc/.eslintrc-es5 lib/index.js", - "lint-examples": "eslint -c node_modules/eslintrc/.eslintrc-es5-react lib/index.js", + "lint-examples": "eslint -c node_modules/eslintrc/.eslintrc-es5-react examples/src/js/", "test": "npm run lint-lib && npm run lint-examples" }, "bugs": "https://github.com/JakeSidSmith/react-reorder/issues", From 65ba4ce7545e64dd9d46a33c96780710f813f76a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 03:10:08 +0100 Subject: [PATCH 012/292] Begin moving toward using JSX in examples --- examples/src/js/index.js | 72 ++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 79340ccb..c421b85f 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -30,7 +30,7 @@ var Main = React.createClass({ disableToggled: function () { this.setState({disableReorder: !this.state.disableReorder}); }, - prefixChanged: function (event) { + onPrefixChange: function (event) { var target = event.currentTarget; this.setState({prefix: target.value}); }, @@ -53,41 +53,41 @@ var Main = React.createClass({ }; }, render: function () { - // return ( - //
- //

- // - // Lock horizontal - // - //

- // - // This example has a hold time of 500 milliseconds before dragging begins, - // allowing for other events like clicking / tapping to be attached - // - //

- // Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined} - //

- //

- // Prefix (shared props): - //

- // - //
- // ); + return ( +
+

+ + Lock horizontal + +

+ + This example has a hold time of 500 milliseconds before dragging begins, + allowing for other events like clicking / tapping to be attached + +

+ Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined} +

+

+ Prefix (shared props): +

+ +
+ ); return React.createElement('div', {className: 'app'}, From 8ed79044ac18d39add533ab99904f2fbde5c465f Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 03:16:30 +0100 Subject: [PATCH 013/292] Move remaining examples to JSX --- examples/src/js/index.js | 121 ++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 72 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index c421b85f..4c526bb1 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -27,7 +27,7 @@ var Main = React.createClass({ itemClicked2: function (event, item) { this.setState({clickedItem2: item}); }, - disableToggled: function () { + onDisableToggle: function () { this.setState({disableReorder: !this.state.disableReorder}); }, onPrefixChange: function (event) { @@ -70,6 +70,7 @@ var Main = React.createClass({

Prefix (shared props):

+ - - ); - - return React.createElement('div', {className: 'app'}, - - React.createElement('p', null, React.createElement('strong', null, 'Lock horizontal')), - React.createElement('small', null, 'This example has a hold time of 500 milliseconds before dragging begins,' + - 'allowing for other events like clicking / tapping to be attached'), - - React.createElement('p', null, - 'Selected item: ', this.state.clickedItem ? this.state.clickedItem.name : undefined), - - React.createElement('p', null, - 'Prefix (shared props): ', - React.createElement('input', { - type: 'text', - onChange: this.prefixChanged, - value: this.state.prefix - }) - ), - - React.createElement(Reorder, { - itemKey: 'name', - lock: 'horizontal', - holdTime: '500', - list: this.state.arr, - template: ListItem, - callback: this.callback, - listClass: 'my-list', - itemClass: 'list-item', - itemClicked: this.itemClicked, - selected: this.state.clickedItem, - selectedKey: 'name', - sharedProps: { - prefix: [this.state.prefix, ': '].join('') - }}), - - React.createElement('p', null, React.createElement('strong', null, 'Lock vertical')), - React.createElement('small', null, 'This example has a hold time of 250 milliseconds'), - - React.createElement('p', null, - 'Reorder disabled: ', - React.createElement('input', { - type: 'checkbox', - onChange: this.disableToggled, - value: this.state.disableReorder || false - }), - 'Last item clicked: ', - this.state.clickedItem2 ? this.state.clickedItem2.name : undefined - ), - React.createElement(Reorder, { - itemKey: 'name', - lock: 'vertical', - holdTime: '250', - list: this.state.arr, - template: ListItem, - callback: this.callback, - listClass: 'my-list-2', - itemClass: 'list-item', - itemClicked: this.itemClicked2, - disableReorder: this.state.disableReorder}), +

+ + Lock vertical + +

+ + This example has a hold time of 250 milliseconds + +

+ {'Reorder disabled: '} + + Last item clicked: {this.state.clickedItem2 ? this.state.clickedItem2.name : undefined} +

- React.createElement('p', null, React.createElement('strong', null, 'No lock (grid)')), - React.createElement('small', null, 'This example has a hold time of 0 milliseconds'), + - React.createElement(Reorder, { - itemKey: 'name', - holdTime: '0', - list: this.state.arr, - template: ListItem, - callback: this.callback, - listClass: 'my-list-3', - itemClass: 'list-item'}) +

+ + No lock (grid) + +

+ + This example has a hold time of 0 milliseconds + + + ); } }); From 5c28d40f5398aafd9d8e8fda0a576a8c8c202643 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 03:20:53 +0100 Subject: [PATCH 014/292] Fix React 15 error message --- lib/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/index.js b/lib/index.js index 8b4f5f6c..17d53367 100644 --- a/lib/index.js +++ b/lib/index.js @@ -18,6 +18,10 @@ }, handleTouchEvents: function (event) { if (event.touches && event.touches.length) { + if (typeof event.persist === 'function') { + event.persist(); + } + event.clientX = event.touches[0].clientX; event.clientY = event.touches[0].clientY; } From b47f7b8950ce011bc4b9a2f55c9dea1d8757d970 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 03:24:37 +0100 Subject: [PATCH 015/292] Setup CircleCI --- circle.yml | 15 +++++++++++++++ scripts/deploy.sh | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 circle.yml create mode 100755 scripts/deploy.sh diff --git a/circle.yml b/circle.yml new file mode 100644 index 00000000..3ba2f375 --- /dev/null +++ b/circle.yml @@ -0,0 +1,15 @@ +machine: + node: + version: 6.2.2 + +general: + branches: + ignore: + - gh-pages + +deployment: + master: + branch: master + commands: + - npm run build + - scripts/deploy.sh diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100755 index 00000000..65fe0e7b --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +BRANCH=gh-pages # Branch to deploy to, probably gh-pages +DIST_DIR=examples # Location of build static files to deploy +DEPLOY_DIR=site_deploy # Temp directory to clone to during deployment +USERNAME=JakeSidSmith # Repo account username +REPO=react-reorder # repo name + + +if [[ -z "$GH_TOKEN" ]]; then + echo "> No Github token found!" + exit 1 +fi + +if [ ! -d "$DIST_DIR" ]; then + echo "> Can't find dist directory, aborting..." + exit +fi + +set -e + +echo "> Starting deployment to Github Pages" + +# Setup Details for deploy commit + +# Clone existing deployment branch into temp directory +mkdir $DEPLOY_DIR +git clone --depth=1 --quiet --branch=$BRANCH --single-branch https://${GH_TOKEN}@github.com/${USERNAME}/${REPO}.git $DEPLOY_DIR + +# Copy new static build into temp directory +rsync -rv $DIST_DIR/* circle.yml --exclude=src/* $DEPLOY_DIR + +# Commit changes +cd $DEPLOY_DIR +git config user.email "jake@dabapps.com" +git config user.name "Automated Docs Deployer" +git add -f . +git commit -m "Deployment - build $CIRCLE_BUILD_NUM" + +# Deploy to branch +git push -fq origin $BRANCH + +echo "> Deployment completed." + +# Cleanup +rm -rf $DEPLOY_DIR From 867910fb05869f5614a413a69cc7d413c365d5a3 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 03:26:38 +0100 Subject: [PATCH 016/292] Update version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 627a33f9..a2ba371f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-reorder", - "version": "2.1.0", + "version": "3.0.0", "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", From ed69361f157e7db33b7ffb44312da701c5c0e943 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 03:29:50 +0100 Subject: [PATCH 017/292] Add status badge to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39b7d602..c8c97712 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# React Reorder +# React Reorder [![CircleCI](https://circleci.com/gh/JakeSidSmith/react-reorder.svg?style=svg)](https://circleci.com/gh/JakeSidSmith/react-reorder) __Drag & drop, touch enabled, reorder / sortable list, React component__ From 763d473739ecfac846960c5493dcc41e3b6ada45 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 12:47:47 +0100 Subject: [PATCH 018/292] Update less --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a2ba371f..c661d1df 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "browserify": "=12.0.1", "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", - "less": "=2.5.3", + "less": "=2.7.1", "react": "=15.3.1", "react-dom": "=15.3.1", "watchify": "=3.6.1" From 2d721ee3adbd4b1bbeb98668eea1963689cdc365 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 12:47:54 +0100 Subject: [PATCH 019/292] Adjust some styles --- examples/src/less/index.less | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/src/less/index.less b/examples/src/less/index.less index dd886d39..0771b851 100644 --- a/examples/src/less/index.less +++ b/examples/src/less/index.less @@ -6,7 +6,8 @@ box-sizing: border-box; } -html, body { +html, +body { padding: 0; margin: 0; font-family: arial, helvetica, sans-serif; @@ -21,11 +22,11 @@ html, body { -webkit-tap-highlight-color: transparent; } -p, small { - float: left; +p, +small { + display: block; width: 100%; - padding: 12px; - margin: 0; + margin: 10px auto; } small { From 3b9f749a4c1036120bbdafebd21299eef3cd3328 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 11 Sep 2016 12:49:26 +0100 Subject: [PATCH 020/292] Change examples markup --- examples/src/js/index.js | 75 +++++++++++++++++++++------------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 4c526bb1..da874dc0 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -17,7 +17,7 @@ var ListItem = React.createClass({ var Main = React.createClass({ callback: function (event, item, index, newIndex, list) { - this.setState({arr: list}); + this.setState({list: list}); }, itemClicked: function (event, item) { this.setState({ @@ -48,22 +48,26 @@ var Main = React.createClass({ } return { - arr: list, + list: list, prefix: 'Prefix' }; }, render: function () { return (
+

+ React Reorder +

+

+ Examples +

+

+ Lock horizontal +

- - Lock horizontal - -

- This example has a hold time of 500 milliseconds before dragging begins, allowing for other events like clicking / tapping to be attached - +

Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined}

@@ -72,30 +76,33 @@ var Main = React.createClass({

+ > + { + this.state.list.map(function (item) { + return ( +
  • + {this.state.prefix} {item.name} +
  • + ); + }.bind(this)) + } +
    +

    + Lock vertical +

    - - Lock vertical - -

    - This example has a hold time of 250 milliseconds - +

    {'Reorder disabled: '} +

    + No lock (grid) +

    - - No lock (grid) - -

    - This example has a hold time of 0 milliseconds - +

    Date: Mon, 12 Sep 2016 09:47:54 +0100 Subject: [PATCH 021/292] Store a ton of change I don't want to loose --- examples/src/js/index.js | 1 + examples/src/less/index.less | 1 + lib/index.js | 964 +++++++++++++++++++++-------------- 3 files changed, 570 insertions(+), 396 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index da874dc0..045d209c 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -91,6 +91,7 @@ var Main = React.createClass({ style={{color: item.color}} > {this.state.prefix} {item.name} + ); }.bind(this)) diff --git a/examples/src/less/index.less b/examples/src/less/index.less index 0771b851..a3d33a89 100644 --- a/examples/src/less/index.less +++ b/examples/src/less/index.less @@ -71,6 +71,7 @@ small { height: auto; border: 1px solid grey; padding: 8px; + list-style: none; } .my-list { diff --git a/lib/index.js b/lib/index.js index 17d53367..b6ccfc12 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,21 +3,406 @@ (function () { var getReorderComponent = function (React, ReactDOM) { + function extend (obj1, obj2, obj3) { + for (var key in obj2) { + obj1[key] = obj2[key]; + } + + for (var key in obj3) { + obj1[key] = obj3[key]; + } + + return obj1; + } + + var CONSTANTS = { + HOLD_THRESHOLD: 8, + SCROLL_RATE: 1000 / 60, + SCROLL_AREA: 50, + SCROLL_MULTIPLIER: 5 + }; + return React.createClass({ displayName: 'Reorder', - nonCollisionElement: new RegExp('(^|\\s)(placeholder|dragged)($|\\s)', ''), - constants: { - HOLD_THRESHOLD: 8, - SCROLL_RATE: 1000 / 60, - SCROLL_DISTANCE: 1, - SCROLL_AREA: 50, - SCROLL_MULTIPLIER: 5 + // nonCollisionElement: new RegExp('(^|\\s)(placeholder|dragged)($|\\s)', ''), + // startDrag: function (dragOffset, draggedStyle) { + // if (!this.props.disableReorder) { + // this.setState({ + // dragOffset: dragOffset, + // draggedStyle: draggedStyle, + // originalPosition: draggedStyle, + // held: true, + // moved: false + // }); + // } + // }, + // itemDown: function (item, index, event) { + // this.handleTouchEvents(event); + // + // var self = this; + // var target = event.currentTarget; + // var rect = target.getBoundingClientRect(); + // + // this.setState({ + // held: false, + // moved: false + // }); + // + // var dragOffset = { + // top: event.clientY - rect.top, + // left: event.clientX - rect.left + // }; + // + // this.setState({ + // dragged: { + // target: target, + // item: item, + // index: index + // } + // }); + // + // var draggedStyle = { + // position: 'fixed', + // top: rect.top, + // left: rect.left, + // width: rect.width, + // height: rect.height + // }; + // + // // Timeout if holdTime is defined + // var holdTime = Math.abs(parseInt(this.props.holdTime, 10)); + // + // if (holdTime) { + // this.holdTimeout = setTimeout(function () { + // self.startDrag(dragOffset, draggedStyle); + // }, holdTime); + // } else { + // self.startDrag(dragOffset, draggedStyle); + // } + // }, + // listDown: function (event) { + // this.handleTouchEvents(event); + // + // var self = this; + // + // var downPos = { + // clientY: event.clientY, + // clientX: event.clientX, + // scrollTop: ReactDOM.findDOMNode(self).scrollTop, + // scrollLeft: ReactDOM.findDOMNode(self).scrollLeft + // }; + // + // this.setState({ + // downPos: downPos, + // pointer: { + // clientY: downPos.clientY, + // clientX: downPos.clientX + // }, + // velocity: { + // y: 0, + // x: 0 + // }, + // movedALittle: false + // }); + // + // // Mouse events + // window.addEventListener('mouseup', this.onMouseUp); // Mouse up + // window.addEventListener('mousemove', this.onMouseMove); // Mouse move + // + // // Touch events + // window.addEventListener('touchend', this.onMouseUp); // Touch up + // window.addEventListener('touchmove', this.onMouseMove); // Touch move + // + // window.addEventListener('contextmenu', this.preventDefault); + // }, + // onMouseUp: function (event) { + // if (event.type.indexOf('touch') >= 0 && !this.state.movedALittle) { + // event.preventDefault(); + // } + // + // // Item clicked + // if ( + // typeof this.props.itemClicked === 'function' && + // !this.state.held && + // !this.state.moved && + // this.state.dragged + // ) { + // this.props.itemClicked(event, this.state.dragged.item, this.state.dragged.index); + // } + // + // // Reorder callback + // if (this.state.held && this.state.dragged && typeof this.props.callback === 'function') { + // var listElements = this.nodesToArray(ReactDOM.findDOMNode(this).childNodes); + // var newIndex = listElements.indexOf(this.state.dragged.target); + // + // this.props.callback(event, this.state.dragged.item, this.state.dragged.index, newIndex, this.state.list); + // } + // + // this.setState({ + // dragged: undefined, + // draggedStyle: undefined, + // dragOffset: undefined, + // originalPosition: undefined, + // downPos: undefined, + // held: false, + // moved: false + // }); + // + // clearTimeout(this.holdTimeout); + // clearInterval(this.scrollIntervalY); + // this.scrollIntervalY = undefined; + // clearInterval(this.scrollIntervalX); + // this.scrollIntervalX = undefined; + // + // // Mouse events + // window.removeEventListener('mouseup', this.onMouseUp); // Mouse up + // window.removeEventListener('mousemove', this.onMouseMove); // Mouse move + // // Touch events + // window.removeEventListener('touchend', this.onMouseUp); // Touch up + // window.removeEventListener('touchmove', this.onMouseMove); // Touch move + // + // window.removeEventListener('contextmenu', this.preventDefault); + // }, + // getScrollArea: function (value) { + // return Math.max(Math.min(value / 4, this.constants.SCROLL_AREA), this.constants.SCROLL_AREA / 5); + // }, + // dragScrollY: function () { + // var element = ReactDOM.findDOMNode(this); + // var rect = element.getBoundingClientRect(); + // var scrollArea = this.getScrollArea(rect.height); + // + // var distanceInArea; + // if (this.state.pointer.clientY < rect.top + scrollArea) { + // distanceInArea = Math.min((rect.top + scrollArea) - this.state.pointer.clientY, scrollArea * 2); + // element.scrollTop -= distanceInArea / this.constants.SCROLL_MULTIPLIER; + // } else if (this.state.pointer.clientY > rect.bottom - scrollArea) { + // distanceInArea = Math.min(this.state.pointer.clientY - (rect.bottom - scrollArea), scrollArea * 2); + // element.scrollTop += distanceInArea / this.constants.SCROLL_MULTIPLIER; + // } + // }, + // dragScrollX: function () { + // var element = ReactDOM.findDOMNode(this); + // var rect = element.getBoundingClientRect(); + // var scrollArea = this.getScrollArea(rect.width); + // + // var distanceInArea; + // if (this.state.pointer.clientX < rect.left + scrollArea) { + // distanceInArea = Math.min((rect.left + scrollArea) - this.state.pointer.clientX, scrollArea * 2); + // element.scrollLeft -= distanceInArea / this.constants.SCROLL_MULTIPLIER; + // } else if (this.state.pointer.clientX > rect.right - scrollArea) { + // distanceInArea = Math.min(this.state.pointer.clientX - (rect.right - scrollArea), scrollArea * 2); + // element.scrollLeft += distanceInArea / this.constants.SCROLL_MULTIPLIER; + // } + // }, + // handleDragScrollY: function (event) { + // var rect = ReactDOM.findDOMNode(this).getBoundingClientRect(); + // + // if (!this.scrollIntervalY && this.props.lock !== 'vertical') { + // if (event.clientY < rect.top + this.constants.SCROLL_AREA) { + // this.scrollIntervalY = setInterval(this.dragScrollY, this.constants.SCROLL_RATE); + // } else if (event.clientY > rect.bottom - this.constants.SCROLL_AREA) { + // this.scrollIntervalY = setInterval(this.dragScrollY, this.constants.SCROLL_RATE); + // } + // } else if ( + // event.clientY <= rect.bottom - this.constants.SCROLL_AREA && + // event.clientY >= rect.top + this.constants.SCROLL_AREA + // ) { + // clearInterval(this.scrollIntervalY); + // this.scrollIntervalY = undefined; + // } + // }, + // handleDragScrollX: function (event) { + // var rect = ReactDOM.findDOMNode(this).getBoundingClientRect(); + // + // if (!this.scrollIntervalX && this.props.lock !== 'horizontal') { + // if (event.clientX < rect.left + this.constants.SCROLL_AREA) { + // this.scrollIntervalX = setInterval(this.dragScrollX, this.constants.SCROLL_RATE); + // } else if (event.clientX > rect.right - this.constants.SCROLL_AREA) { + // this.scrollIntervalX = setInterval(this.dragScrollX, this.constants.SCROLL_RATE); + // } + // } else if ( + // event.clientX <= rect.right - this.constants.SCROLL_AREA && + // event.clientX >= rect.left + this.constants.SCROLL_AREA + // ) { + // clearInterval(this.scrollIntervalX); + // this.scrollIntervalX = undefined; + // } + // }, + // onMouseMove: function (event) { + // this.handleTouchEvents(event); + // + // var pointer = { + // clientY: event.clientY, + // clientX: event.clientX + // }; + // + // this.setState({ + // pointer: pointer, + // velocity: { + // y: pointer.clientY - event.clientY, + // x: pointer.clientX - event.clientX + // }, + // movedALittle: true + // }); + // + // if (this.state.held && this.state.dragged) { + // event.preventDefault(); + // this.setDraggedPosition(event); + // + // var listElements = this.nodesToArray(ReactDOM.findDOMNode(this).childNodes); + // var collision = this.findCollision(listElements, event); + // + // if (collision) { + // var previousIndex = listElements.indexOf(this.state.dragged.target); + // var newIndex = listElements.indexOf(collision); + // + // this.state.list.splice(newIndex, 0, this.state.list.splice(previousIndex, 1)[0]); + // this.setState({list: this.state.list}); + // } + // + // this.handleDragScrollY(event); + // this.handleDragScrollX(event); + // } else if (this.state.downPos) { + // // Cancel hold if mouse has moved + // if (this.xHasMoved(event) || this.yHasMoved(event)) { + // clearTimeout(this.holdTimeout); + // this.setState({moved: true}); + // } + // } + // }, + // xHasMoved: function (event) { + // return Math.abs(this.state.downPos.clientX - event.clientX) > this.constants.HOLD_THRESHOLD; + // }, + // yHasMoved: function (event) { + // return Math.abs(this.state.downPos.clientY - event.clientY) > this.constants.HOLD_THRESHOLD; + // }, + // elementHeightMinusBorders: function (element) { + // var rect = element.getBoundingClientRect(); + // var computedStyle; + // + // if (getComputedStyle) { + // computedStyle = getComputedStyle(element); + // } else { + // computedStyle = element.currentStyle; + // } + // + // return rect.height - + // parseInt(computedStyle.getPropertyValue('border-top-width') || computedStyle.borderTopWidth, 10) - + // parseInt(computedStyle.getPropertyValue('border-bottom-width') || computedStyle.borderBottomWidth, 10); + // }, + // elementWidthMinusBorders: function (element) { + // var rect = element.getBoundingClientRect(); + // var computedStyle; + // + // if (getComputedStyle) { + // computedStyle = getComputedStyle(element); + // } else { + // computedStyle = element.currentStyle; + // } + // + // return rect.width - + // parseInt(computedStyle.getPropertyValue('border-left-width') || computedStyle.borderLeftWidth, 10) - + // parseInt(computedStyle.getPropertyValue('border-right-width') || computedStyle.borderRightWidth, 10); + // }, + // setDraggedPosition: function (event) { + // var draggedStyle = { + // position: this.state.draggedStyle.position, + // top: this.state.draggedStyle.top, + // left: this.state.draggedStyle.left, + // width: this.state.draggedStyle.width, + // height: this.state.draggedStyle.height + // }; + // + // if (this.props.lock === 'horizontal') { + // draggedStyle.top = event.clientY - this.state.dragOffset.top; + // draggedStyle.left = this.state.originalPosition.left; + // } else if (this.props.lock === 'vertical') { + // draggedStyle.top = this.state.originalPosition.top; + // draggedStyle.left = event.clientX - this.state.dragOffset.left; + // } else { + // draggedStyle.top = event.clientY - this.state.dragOffset.top; + // draggedStyle.left = event.clientX - this.state.dragOffset.left; + // } + // + // this.setState({draggedStyle: draggedStyle}); + // }, + // + // // Collision methods + // + // nodesToArray: function (nodes) { + // return Array.prototype.slice.call(nodes, 0); + // }, + // xCollision: function (rect, event) { + // return event.clientX >= rect.left && event.clientX <= rect.right; + // }, + // yCollision: function (rect, event) { + // return event.clientY >= rect.top && event.clientY <= rect.bottom; + // }, + // findCollision: function (listElements, event) { + // for (var i = 0; i < listElements.length; i += 1) { + // if (!this.nonCollisionElement.exec(listElements[i].className)) { + // var rect = listElements[i].getBoundingClientRect(); + // + // if (this.props.lock === 'horizontal') { + // if (this.yCollision(rect, event)) { + // return listElements[i]; + // } + // } else if (this.props.lock === 'vertical') { + // if (this.xCollision(rect, event)) { + // return listElements[i]; + // } + // } else if (this.yCollision(rect, event)) { + // if (this.xCollision(rect, event)) { + // return listElements[i]; + // } + // } + // + // } + // } + // + // return undefined; + // }, + // + // // ---- Default methods + // + // componentWillUnmount: function () { + // clearTimeout(this.holdTimeout); + // + // clearInterval(this.scrollIntervalY); + // this.scrollIntervalY = undefined; + // clearInterval(this.scrollIntervalX); + // this.scrollIntervalX = undefined; + // }, + // componentWillReceiveProps: function (props) { + // // Updates list when props changed + // this.setState({ + // list: props.list + // }); + // }, + // getInitialState: function () { + // return { + // list: this.props.list || [] + // }; + // }, + getInitialState: function() { + return { + draggedIndex: -1, + draggedStyle: null + }; }, + preventDefault: function (event) { event.preventDefault(); }, - handleTouchEvents: function (event) { - if (event.touches && event.touches.length) { + + preventDefaultIfDragging: function (event) { + if (this.state.draggedIndex >= 0) { + event.preventDefault(); + } + }, + + copyTouchKeys: function (event) { + if (event.touches && event.touches[0]) { if (typeof event.persist === 'function') { event.persist(); } @@ -26,442 +411,229 @@ event.clientY = event.touches[0].clientY; } }, - startDrag: function (dragOffset, draggedStyle) { - if (!this.props.disableReorder) { - this.setState({ - dragOffset: dragOffset, - draggedStyle: draggedStyle, - originalPosition: draggedStyle, - held: true, - moved: false - }); + + onItemDown: function (callback, index, event) { + if (event.button === 2) { + return; } - }, - itemDown: function (item, index, event) { - this.handleTouchEvents(event); + this.copyTouchKeys(event); + console.log('Item down'); var self = this; - var target = event.currentTarget; - var rect = target.getBoundingClientRect(); - - this.setState({ - held: false, - moved: false - }); - - var dragOffset = { - top: event.clientY - rect.top, - left: event.clientX - rect.left - }; - - this.setState({ - dragged: { - target: target, - item: item, - index: index + var rect = event.target.getBoundingClientRect(); + + self.setState({ + draggedIndex: index, + placedIndex: index, + draggedStyle: { + position: 'absolute', + top: rect.top, + left: rect.left, + width: rect.width, + height: rect.height + }, + downOffset: { + clientX: event.clientX - rect.left, + clientY: event.clientY - rect.top } }); - var draggedStyle = { - position: 'fixed', - top: rect.top, - left: rect.left, - width: rect.width, - height: rect.height - }; - - // Timeout if holdTime is defined - var holdTime = Math.abs(parseInt(this.props.holdTime, 10)); - - if (holdTime) { - this.holdTimeout = setTimeout(function () { - self.startDrag(dragOffset, draggedStyle); - }, holdTime); - } else { - self.startDrag(dragOffset, draggedStyle); + if (typeof callback === 'function') { + callback(event); } }, - listDown: function (event) { - this.handleTouchEvents(event); - var self = this; + onListDown: function (callback, event) { + if (event.button === 2) { + return; + } - var downPos = { - clientY: event.clientY, - clientX: event.clientX, - scrollTop: ReactDOM.findDOMNode(self).scrollTop, - scrollLeft: ReactDOM.findDOMNode(self).scrollLeft - }; + this.copyTouchKeys(event); + console.log('List down'); this.setState({ - downPos: downPos, - pointer: { - clientY: downPos.clientY, - clientX: downPos.clientX - }, - velocity: { - y: 0, - x: 0 - }, - movedALittle: false + downPos: { + clientX: event.clientX, + clientY: event.clientY + } }); - // Mouse events - window.addEventListener('mouseup', this.onMouseUp); // Mouse up - window.addEventListener('mousemove', this.onMouseMove); // Mouse move - - // Touch events - window.addEventListener('touchend', this.onMouseUp); // Touch up - window.addEventListener('touchmove', this.onMouseMove); // Touch move - - window.addEventListener('contextmenu', this.preventDefault); - }, - onMouseUp: function (event) { - if (event.type.indexOf('touch') >= 0 && !this.state.movedALittle) { - event.preventDefault(); + if (typeof callback === 'function') { + callback(event); } + }, - // Item clicked - if ( - typeof this.props.itemClicked === 'function' && - !this.state.held && - !this.state.moved && - this.state.dragged - ) { - this.props.itemClicked(event, this.state.dragged.item, this.state.dragged.index); + onListMove: function (callback, event) { + if (event.button === 2) { + return; } - // Reorder callback - if (this.state.held && this.state.dragged && typeof this.props.callback === 'function') { - var listElements = this.nodesToArray(ReactDOM.findDOMNode(this).childNodes); - var newIndex = listElements.indexOf(this.state.dragged.target); + this.copyTouchKeys(event); + console.log('List move'); - this.props.callback(event, this.state.dragged.item, this.state.dragged.index, newIndex, this.state.list); + if (typeof callback === 'function') { + callback(event); } + }, - this.setState({ - dragged: undefined, - draggedStyle: undefined, - dragOffset: undefined, - originalPosition: undefined, - downPos: undefined, - held: false, - moved: false - }); - - clearTimeout(this.holdTimeout); - clearInterval(this.scrollIntervalY); - this.scrollIntervalY = undefined; - clearInterval(this.scrollIntervalX); - this.scrollIntervalX = undefined; + onListUp: function (callback, event) { + if (event.button === 2) { + return; + } - // Mouse events - window.removeEventListener('mouseup', this.onMouseUp); // Mouse up - window.removeEventListener('mousemove', this.onMouseMove); // Mouse move - // Touch events - window.removeEventListener('touchend', this.onMouseUp); // Touch up - window.removeEventListener('touchmove', this.onMouseMove); // Touch move + this.copyTouchKeys(event); + console.log('List up'); - window.removeEventListener('contextmenu', this.preventDefault); - }, - getScrollArea: function (value) { - return Math.max(Math.min(value / 4, this.constants.SCROLL_AREA), this.constants.SCROLL_AREA / 5); - }, - dragScrollY: function () { - var element = ReactDOM.findDOMNode(this); - var rect = element.getBoundingClientRect(); - var scrollArea = this.getScrollArea(rect.height); - - var distanceInArea; - if (this.state.pointer.clientY < rect.top + scrollArea) { - distanceInArea = Math.min((rect.top + scrollArea) - this.state.pointer.clientY, scrollArea * 2); - element.scrollTop -= distanceInArea / this.constants.SCROLL_MULTIPLIER; - } else if (this.state.pointer.clientY > rect.bottom - scrollArea) { - distanceInArea = Math.min(this.state.pointer.clientY - (rect.bottom - scrollArea), scrollArea * 2); - element.scrollTop += distanceInArea / this.constants.SCROLL_MULTIPLIER; - } - }, - dragScrollX: function () { - var element = ReactDOM.findDOMNode(this); - var rect = element.getBoundingClientRect(); - var scrollArea = this.getScrollArea(rect.width); - - var distanceInArea; - if (this.state.pointer.clientX < rect.left + scrollArea) { - distanceInArea = Math.min((rect.left + scrollArea) - this.state.pointer.clientX, scrollArea * 2); - element.scrollLeft -= distanceInArea / this.constants.SCROLL_MULTIPLIER; - } else if (this.state.pointer.clientX > rect.right - scrollArea) { - distanceInArea = Math.min(this.state.pointer.clientX - (rect.right - scrollArea), scrollArea * 2); - element.scrollLeft += distanceInArea / this.constants.SCROLL_MULTIPLIER; - } - }, - handleDragScrollY: function (event) { - var rect = ReactDOM.findDOMNode(this).getBoundingClientRect(); - - if (!this.scrollIntervalY && this.props.lock !== 'vertical') { - if (event.clientY < rect.top + this.constants.SCROLL_AREA) { - this.scrollIntervalY = setInterval(this.dragScrollY, this.constants.SCROLL_RATE); - } else if (event.clientY > rect.bottom - this.constants.SCROLL_AREA) { - this.scrollIntervalY = setInterval(this.dragScrollY, this.constants.SCROLL_RATE); - } - } else if ( - event.clientY <= rect.bottom - this.constants.SCROLL_AREA && - event.clientY >= rect.top + this.constants.SCROLL_AREA - ) { - clearInterval(this.scrollIntervalY); - this.scrollIntervalY = undefined; - } - }, - handleDragScrollX: function (event) { - var rect = ReactDOM.findDOMNode(this).getBoundingClientRect(); - - if (!this.scrollIntervalX && this.props.lock !== 'horizontal') { - if (event.clientX < rect.left + this.constants.SCROLL_AREA) { - this.scrollIntervalX = setInterval(this.dragScrollX, this.constants.SCROLL_RATE); - } else if (event.clientX > rect.right - this.constants.SCROLL_AREA) { - this.scrollIntervalX = setInterval(this.dragScrollX, this.constants.SCROLL_RATE); - } - } else if ( - event.clientX <= rect.right - this.constants.SCROLL_AREA && - event.clientX >= rect.left + this.constants.SCROLL_AREA - ) { - clearInterval(this.scrollIntervalX); - this.scrollIntervalX = undefined; + if (typeof callback === 'function') { + callback(event); } }, - onMouseMove: function (event) { - this.handleTouchEvents(event); - - var pointer = { - clientY: event.clientY, - clientX: event.clientX - }; + onWindowUp: function () { this.setState({ - pointer: pointer, - velocity: { - y: this.state.pointer.clientY - event.clientY, - x: this.state.pointer.clientX - event.clientX - }, - movedALittle: true + draggedIndex: -1, + draggedStyle: null }); + }, - if (this.state.held && this.state.dragged) { - event.preventDefault(); - this.setDraggedPosition(event); - - var listElements = this.nodesToArray(ReactDOM.findDOMNode(this).childNodes); - var collision = this.findCollision(listElements, event); + onWindowMove: function (event) { + if (this.state.draggedIndex >= 0) { + this.copyTouchKeys(event); - if (collision) { - var previousIndex = listElements.indexOf(this.state.dragged.target); - var newIndex = listElements.indexOf(collision); + var draggedStyle = { + position: this.state.draggedStyle.position, + top: this.state.draggedStyle.top, + left: this.state.draggedStyle.left, + width: this.state.draggedStyle.width, + height: this.state.draggedStyle.height + }; - this.state.list.splice(newIndex, 0, this.state.list.splice(previousIndex, 1)[0]); - this.setState({list: this.state.list}); + if (!this.props.lock || this.props.lock === 'horizontal') { + draggedStyle.top = event.clientY - this.state.downOffset.clientY; } - this.handleDragScrollY(event); - this.handleDragScrollX(event); - } else if (this.state.downPos) { - // Cancel hold if mouse has moved - if (this.xHasMoved(event) || this.yHasMoved(event)) { - clearTimeout(this.holdTimeout); - this.setState({moved: true}); + if (!this.props.lock || this.props.lock === 'vertical') { + draggedStyle.left = event.clientX - this.state.downOffset.clientX; } + + this.setState({ + draggedStyle: draggedStyle + }); } }, - xHasMoved: function (event) { - return Math.abs(this.state.downPos.clientX - event.clientX) > this.constants.HOLD_THRESHOLD; - }, - yHasMoved: function (event) { - return Math.abs(this.state.downPos.clientY - event.clientY) > this.constants.HOLD_THRESHOLD; - }, - elementHeightMinusBorders: function (element) { - var rect = element.getBoundingClientRect(); - var computedStyle; - - if (getComputedStyle) { - computedStyle = getComputedStyle(element); - } else { - computedStyle = element.currentStyle; - } - return rect.height - - parseInt(computedStyle.getPropertyValue('border-top-width') || computedStyle.borderTopWidth, 10) - - parseInt(computedStyle.getPropertyValue('border-bottom-width') || computedStyle.borderBottomWidth, 10); + componentWillMount: function() { + window.addEventListener('mouseup', this.onWindowUp); + window.addEventListener('touchend', this.onWindowUp); + window.addEventListener('mousemove', this.onWindowMove); + window.addEventListener('touchmove', this.onWindowMove); + window.addEventListener('contextmenu', this.preventDefaultIfDragging); }, - elementWidthMinusBorders: function (element) { - var rect = element.getBoundingClientRect(); - var computedStyle; - - if (getComputedStyle) { - computedStyle = getComputedStyle(element); - } else { - computedStyle = element.currentStyle; - } - return rect.width - - parseInt(computedStyle.getPropertyValue('border-left-width') || computedStyle.borderLeftWidth, 10) - - parseInt(computedStyle.getPropertyValue('border-right-width') || computedStyle.borderRightWidth, 10); + componentWillUnmount: function() { + window.removeEventListener('mouseup', this.onWindowUp); + window.removeEventListener('touchend', this.onWindowUp); + window.removeEventListener('mousemove', this.onWindowMove); + window.removeEventListener('touchmove', this.onWindowMove); + window.removeEventListener('contextmenu', this.preventDefaultIfDragging); }, - setDraggedPosition: function (event) { - var draggedStyle = { - position: this.state.draggedStyle.position, - top: this.state.draggedStyle.top, - left: this.state.draggedStyle.left, - width: this.state.draggedStyle.width, - height: this.state.draggedStyle.height - }; - if (this.props.lock === 'horizontal') { - draggedStyle.top = event.clientY - this.state.dragOffset.top; - draggedStyle.left = this.state.originalPosition.left; - } else if (this.props.lock === 'vertical') { - draggedStyle.top = this.state.originalPosition.top; - draggedStyle.left = event.clientX - this.state.dragOffset.left; - } else { - draggedStyle.top = event.clientY - this.state.dragOffset.top; - draggedStyle.left = event.clientX - this.state.dragOffset.left; - } + render: function () { + var self = this; - this.setState({draggedStyle: draggedStyle}); - }, + var children = this.props.children && this.props.children.map(function (child, index) { + var isDragged = index === self.state.draggedIndex; + var className = child.props.className; - // Collision methods + var draggedStyle = isDragged ? extend({}, child.props.style, self.state.draggedStyle) : child.props.style; + var draggedClass = isDragged ? (className ? className + ' dragged' : 'dragged') : className; - nodesToArray: function (nodes) { - return Array.prototype.slice.call(nodes, 0); - }, - xCollision: function (rect, event) { - return event.clientX >= rect.left && event.clientX <= rect.right; - }, - yCollision: function (rect, event) { - return event.clientY >= rect.top && event.clientY <= rect.bottom; - }, - findCollision: function (listElements, event) { - for (var i = 0; i < listElements.length; i += 1) { - if (!this.nonCollisionElement.exec(listElements[i].className)) { - var rect = listElements[i].getBoundingClientRect(); - - if (this.props.lock === 'horizontal') { - if (this.yCollision(rect, event)) { - return listElements[i]; - } - } else if (this.props.lock === 'vertical') { - if (this.xCollision(rect, event)) { - return listElements[i]; - } - } else if (this.yCollision(rect, event)) { - if (this.xCollision(rect, event)) { - return listElements[i]; - } + return React.cloneElement( + child, + { + style: draggedStyle, + className: draggedClass, + onMouseDown: self.onItemDown.bind(self, child.props.onMouseDown, index), + onTouchStart: self.onItemDown.bind(self, child.props.onTouchStart, index) } + ); + }.bind(this)); - } - } - - return undefined; - }, + var draggedElement = this.props.children && this.props.children[this.state.draggedIndex]; - // ---- View methods - - getDraggedStyle: function (item) { - if (this.state.held && this.state.dragged && this.state.dragged.item === item) { - return this.state.draggedStyle; - } - return undefined; - }, - getDraggedClass: function (item) { - if (this.state.held && this.state.dragged && this.state.dragged.item === item) { - return 'dragged'; - } - return undefined; - }, - getPlaceholderClass: function (item) { - if (this.state.held && this.state.dragged && this.state.dragged.item === item) { - return 'placeholder'; - } - return undefined; - }, - getSelectedClass: function (item) { - if (typeof this.props.selected !== 'undefined') { - if (typeof this.props.selectedKey !== 'undefined') { - return this.props.selected[this.props.selectedKey] === item[this.props.selectedKey] ? - 'selected' : undefined; - } - return this.props.selected === item ? 'selected' : undefined; + if (this.state.placedIndex >= 0 && draggedElement) { + var placeholder = React.cloneElement( + draggedElement, + { + key: 'react-reorder-placeholder', + className: draggedElement.props.className ? draggedElement.props.className + ' placeholder' : 'placeholder' + } + ); + children.splice(this.state.placedIndex, 0, placeholder); } - return undefined; - }, - - // ---- Default methods - - componentWillUnmount: function () { - clearTimeout(this.holdTimeout); - - clearInterval(this.scrollIntervalY); - this.scrollIntervalY = undefined; - clearInterval(this.scrollIntervalX); - this.scrollIntervalX = undefined; - }, - componentWillReceiveProps: function (props) { - // Updates list when props changed - this.setState({ - list: props.list - }); - }, - getInitialState: function () { - return { - list: this.props.list || [] - }; - }, - render: function () { - var self = this; - - var getPropsTemplate = function (item) { - if (self.props.template) { - return React.createElement(self.props.template, { - item: item, - sharedProps: self.props.sharedProps - }); - } - return item; - }; - - var list = this.state.list.map(function (item, index) { - var itemKey = item[self.props.itemKey] || item; - var itemClass = [self.props.itemClass, self.getPlaceholderClass(item), self.getSelectedClass(item)].join(' '); - return React.createElement('div', { - key: itemKey, - className: itemClass, - onMouseDown: self.itemDown.bind(self, item, index), - onTouchStart: self.itemDown.bind(self, item, index), - }, getPropsTemplate(item)); - }); - var targetClone = function () { - if (self.state.held && self.state.dragged) { - var itemKey = self.state.dragged.item[self.props.itemKey] || self.state.dragged.item; - var itemClass = [ - self.props.itemClass, - self.getDraggedClass(self.state.dragged.item), - self.getSelectedClass(self.state.dragged.item) - ].join(' '); - return React.createElement('div', { - key: itemKey, - className: itemClass, - style: self.getDraggedStyle(self.state.dragged.item) - }, getPropsTemplate(self.state.dragged.item)); - } - return undefined; - }; - - return React.createElement('div', { - className: this.props.listClass, - onMouseDown: self.listDown, - onTouchStart: self.listDown - }, list, targetClone()); + return React.createElement( + self.props.component || 'div', + { + className: this.props.className, + id: this.props.id, + style: this.props.style, + onClick: this.props.onClick, + onMouseDown: this.onListDown.bind(this, this.props.onMouseDown), + onTouchStart: this.onListDown.bind(this, this.props.onTouchStart), + onMouseMove: this.onListMove.bind(this, this.props.onMouseMove), + onTouchMove: this.onListMove.bind(this, this.props.onTouchMove), + onMouseUp: this.onListUp.bind(this, this.props.onMouseUp), + onTouchEnd: this.onListUp.bind(this, this.props.onTouchEnd) + }, + children + ); + + // var self = this; + // + // var getPropsTemplate = function (item) { + // if (self.props.template) { + // return React.createElement(self.props.template, { + // item: item, + // sharedProps: self.props.sharedProps + // }); + // } + // return item; + // }; + // + // var list = this.state.list.map(function (item, index) { + // var itemKey = item[self.props.itemKey] || item; + // var itemClass = [self.props.itemClass, self.getPlaceholderClass(item), self.getSelectedClass(item)].join(' '); + // return React.createElement('div', { + // key: itemKey, + // className: itemClass, + // onMouseDown: self.itemDown.bind(self, item, index), + // onTouchStart: self.itemDown.bind(self, item, index), + // }, getPropsTemplate(item)); + // }); + // + // var targetClone = function () { + // if (self.state.held && self.state.dragged) { + // var itemKey = self.state.dragged.item[self.props.itemKey] || self.state.dragged.item; + // var itemClass = [ + // self.props.itemClass, + // self.getDraggedClass(self.state.dragged.item), + // self.getSelectedClass(self.state.dragged.item) + // ].join(' '); + // return React.createElement('div', { + // key: itemKey, + // className: itemClass, + // style: self.getDraggedStyle(self.state.dragged.item) + // }, getPropsTemplate(self.state.dragged.item)); + // } + // return undefined; + // }; + // + // return React.createElement('div', { + // className: this.props.listClass, + // onMouseDown: self.listDown, + // onTouchStart: self.listDown + // }, list, targetClone()); } }); From c27bb643b0dcdc5e178c7f9342ad8a4b16705ad5 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 12 Sep 2016 20:27:27 +0100 Subject: [PATCH 022/292] Begin using React Style Sheets for styling --- examples/src/js/index.js | 277 ++++++++++++++++++----------------- examples/src/js/styles.js | 35 +++++ examples/src/less/index.less | 36 ----- package.json | 1 + 4 files changed, 177 insertions(+), 172 deletions(-) create mode 100644 examples/src/js/styles.js diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 045d209c..0979b023 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -1,151 +1,156 @@ 'use strict'; -var React = require('react'); -var ReactDOM = require('react-dom'); -var Reorder = require('../../../lib/index'); +(function () { -var ListItem = React.createClass({ - render: function () { - return React.createElement('div', { - className: 'inner', - style: { - color: this.props.item.color - } - }, this.props.sharedProps ? this.props.sharedProps.prefix : undefined, this.props.item.name); - } -}); + require('./styles'); + var React = require('react'); + var ReactDOM = require('react-dom'); + var Reorder = require('../../../lib/index'); -var Main = React.createClass({ - callback: function (event, item, index, newIndex, list) { - this.setState({list: list}); - }, - itemClicked: function (event, item) { - this.setState({ - clickedItem: item === this.state.clickedItem ? undefined : item - }); - }, - itemClicked2: function (event, item) { - this.setState({clickedItem2: item}); - }, - onDisableToggle: function () { - this.setState({disableReorder: !this.state.disableReorder}); - }, - onPrefixChange: function (event) { - var target = event.currentTarget; - this.setState({prefix: target.value}); - }, + var ListItem = React.createClass({ + render: function () { + return React.createElement('div', { + className: 'inner', + style: { + color: this.props.item.color + } + }, this.props.sharedProps ? this.props.sharedProps.prefix : undefined, this.props.item.name); + } + }); - // ---- + var Main = React.createClass({ + callback: function (event, item, index, newIndex, list) { + this.setState({list: list}); + }, + itemClicked: function (event, item) { + this.setState({ + clickedItem: item === this.state.clickedItem ? undefined : item + }); + }, + itemClicked2: function (event, item) { + this.setState({clickedItem2: item}); + }, + onDisableToggle: function () { + this.setState({disableReorder: !this.state.disableReorder}); + }, + onPrefixChange: function (event) { + var target = event.currentTarget; + this.setState({prefix: target.value}); + }, - getInitialState: function () { - var list = []; + // ---- - for (var i = 0; i < 10; i += 1) { - list.push({ - name: ['Thing', i].join(' '), - color: ['rgb(', (i + 1) * 25, ',', 250 - ((i + 1) * 25), ',0)'].join('') - }); - } + getInitialState: function () { + var list = []; - return { - list: list, - prefix: 'Prefix' - }; - }, - render: function () { - return ( -
    -

    - React Reorder -

    -

    - Examples -

    -

    - Lock horizontal -

    -

    - This example has a hold time of 500 milliseconds before dragging begins, - allowing for other events like clicking / tapping to be attached -

    -

    - Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined} -

    -

    - Prefix (shared props): -

    + for (var i = 0; i < 10; i += 1) { + list.push({ + name: ['Thing', i].join(' '), + color: ['rgb(', (i + 1) * 25, ',', 250 - ((i + 1) * 25), ',0)'].join('') + }); + } + + return { + list: list, + prefix: 'Prefix' + }; + }, + render: function () { + return ( +
    +

    + React Reorder +

    +

    + Examples +

    +

    + Lock horizontal +

    +

    + This example has a hold time of 500 milliseconds before dragging begins, + allowing for other events like clicking / tapping to be attached +

    +

    + Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined} +

    +

    + Prefix (shared props): +

    + + + { + this.state.list.map(function (item) { + return ( +
  • + {this.state.prefix} {item.name} + +
  • + ); + }.bind(this)) + } +
    - - { - this.state.list.map(function (item) { - return ( -
  • - {this.state.prefix} {item.name} - -
  • - ); - }.bind(this)) - } -
    +

    + Lock vertical +

    +

    + This example has a hold time of 250 milliseconds +

    +

    + {'Reorder disabled: '} + + Last item clicked: {this.state.clickedItem2 ? this.state.clickedItem2.name : undefined} +

    -

    - Lock vertical -

    -

    - This example has a hold time of 250 milliseconds -

    -

    - {'Reorder disabled: '} - - Last item clicked: {this.state.clickedItem2 ? this.state.clickedItem2.name : undefined} -

    - +

    + No lock (grid) +

    +

    + This example has a hold time of 0 milliseconds +

    -

    - No lock (grid) -

    -

    - This example has a hold time of 0 milliseconds -

    + +
    + ); + } + }); - -
    - ); - } -}); + ReactDOM.render(React.createElement(Main), document.getElementById('app')); -ReactDOM.render(React.createElement(Main), document.getElementById('app')); +})(); diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js new file mode 100644 index 00000000..3d873829 --- /dev/null +++ b/examples/src/js/styles.js @@ -0,0 +1,35 @@ +'use strict'; + +(function () { + + var ReactStyleSheets = require('react-style-sheets'); + + ReactStyleSheets.setOptions({ + vendorPrefixes: { + userSelect: ['webkit', 'khtml', 'moz', 'ms', 'o'] + } + }); + + var htmlBody = { + padding: 0, + margin: 0, + fontFamily: ['arial', 'helvetica', 'sans-serif'], + fontSize: 14, + color: '#333', + WebkitTouchCallout: 'none', + userSelect: 'none', + WebkitTapHighlightColor: 'transparent' + }; + + ReactStyleSheets.createGlobalTagStyles({ + '*': { + boxSizing: 'border-box' + }, + html: htmlBody, + body: htmlBody, + p: { + margin: [10, 'auto'] + } + }); + +})(); diff --git a/examples/src/less/index.less b/examples/src/less/index.less index a3d33a89..32f50b22 100644 --- a/examples/src/less/index.less +++ b/examples/src/less/index.less @@ -1,39 +1,3 @@ -@BaseFontColor: #333; - -@BaseFontSize: 14px; - -* { - box-sizing: border-box; -} - -html, -body { - padding: 0; - margin: 0; - font-family: arial, helvetica, sans-serif; - font-size: @BaseFontSize; - color: @BaseFontColor; - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-tap-highlight-color: transparent; -} - -p, -small { - display: block; - width: 100%; - margin: 10px auto; -} - -small { - padding-top: 0; - font-size: @BaseFontSize - 2px; -} - .app { position: relative; width: 100%; diff --git a/package.json b/package.json index c661d1df..d296fbec 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "less": "=2.7.1", "react": "=15.3.1", "react-dom": "=15.3.1", + "react-style-sheets": "=0.1.0", "watchify": "=3.6.1" }, "engines": { From 92f31b046e93ea317279f2558ffe917426d79028 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 12 Sep 2016 20:34:07 +0100 Subject: [PATCH 023/292] Move some more styles out of the less --- examples/index.html | 22 +++++++++++++++++++++- examples/src/js/index.js | 14 +++++++++++++- examples/src/less/index.less | 29 ----------------------------- 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/examples/index.html b/examples/index.html index d052dada..8c24a844 100644 --- a/examples/index.html +++ b/examples/index.html @@ -4,7 +4,27 @@ React Reorder - + diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 0979b023..2bba72ea 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -5,8 +5,20 @@ require('./styles'); var React = require('react'); var ReactDOM = require('react-dom'); + var ReactStyleSheets = require('react-style-sheets'); var Reorder = require('../../../lib/index'); + var classNames = ReactStyleSheets.createUniqueClassStyles({ + app: { + position: 'relative', + width: '100%', + maxWidth: 768, + overflow: 'hidden', + margin: 'auto', + padding: 8 + } + }); + var ListItem = React.createClass({ render: function () { return React.createElement('div', { @@ -57,7 +69,7 @@ }, render: function () { return ( -
    +

    React Reorder

    diff --git a/examples/src/less/index.less b/examples/src/less/index.less index 32f50b22..7aace172 100644 --- a/examples/src/less/index.less +++ b/examples/src/less/index.less @@ -1,32 +1,3 @@ -.app { - position: relative; - width: 100%; - max-width: 768px; - overflow: hidden; - margin: auto; - padding: 8px; -} - -.loading { - position: relative; - width: 100%; - margin: 100px auto auto auto; - text-align: center; - padding: 8px; - - p { - float: left; - width: 100%; - font-size: 18px; - margin: 0; - padding: 0; - - small { - font-size: 14px; - } - } -} - .my-list, .my-list-2, .my-list-3 { From e29285c2e4c1a10b6cc38d46afa7674f04836c42 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 12 Sep 2016 20:35:17 +0100 Subject: [PATCH 024/292] Remove less dependencies / build steps --- package.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index d296fbec..705d704c 100644 --- a/package.json +++ b/package.json @@ -7,11 +7,10 @@ "main": "lib/index.js", "scripts": { "start": "http-server examples/ -c-1 -o", - "build-less": "lessc examples/src/less/index.less examples/build/css/index.css && echo 'Less compiled'", "build-js": "browserify -t babelify examples/src/js/index.js -o examples/build/js/index.js", "watch-js": "watchify -t babelify examples/src/js/index.js -o examples/build/js/index.js -v", - "build-dirs": "mkdir -p examples/build/css/ && mkdir -p examples/build/js/", - "build": "npm run build-dirs && npm run build-less && npm run build-js", + "build-dirs": "mkdir -p examples/build/js/", + "build": "npm run build-dirs && npm run build-js", "watch": "npm run watch-js", "lint-lib": "eslint -c node_modules/eslintrc/.eslintrc-es5 lib/index.js", "lint-examples": "eslint -c node_modules/eslintrc/.eslintrc-es5-react examples/src/js/", @@ -40,7 +39,6 @@ "browserify": "=12.0.1", "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", - "less": "=2.7.1", "react": "=15.3.1", "react-dom": "=15.3.1", "react-style-sheets": "=0.1.0", From 4a81980721038cfa7d62897b88a6a6fd094d263b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 13 Sep 2016 10:06:09 +0100 Subject: [PATCH 025/292] Move all styles to React Style Sheets --- examples/src/js/index.js | 61 ++++++++++++++++++++++++++++++-- examples/src/js/styles.js | 5 ++- examples/src/less/index.less | 68 ------------------------------------ lib/index.js | 4 +-- 4 files changed, 65 insertions(+), 73 deletions(-) delete mode 100644 examples/src/less/index.less diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 2bba72ea..0838ac6f 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -16,6 +16,59 @@ overflow: 'hidden', margin: 'auto', padding: 8 + }, + placeholder: { + backgroundColor: '#CCC', + border: [2, 'solid', '#CCC'] + }, + dragged: { + backgroundColor: '#EEE', + transform: 'scale(0.98, 0.98)', + opacity: 0.7 + }, + selected: { + border: [2, 'solid', 'red'] + }, + myList: { + float: 'left', + width: '100%', + height: 'auto', + border: [1, 'solid', 'grey'], + padding: 8, + listStyle: 'none' + }, + myList1: { + height: 200, + overflow: 'auto', + paddingBottom: 0 + }, + myList2: { + overflowX: 'auto', + overflowY: 'hidden', + height: 62, + whiteSpace: 'nowrap' + }, + mylist3: {}, + listItem: { + float: 'left', + width: '100%', + height: 'auto', + padding: 12, + border: [2, 'solid', 'lightblue'], + marginBottom: 8, + transformOrigin: '50% 50%' + }, + listItem2: { + float: 'none', + width: 80, + marginBottom: 0, + whiteSpace: 'nowrap', + overflow: 'hidden', + display: 'inline-block' + }, + listItem3: { + float: 'left', + width: '50%' } }); @@ -92,17 +145,19 @@ { this.state.list.map(function (item) { return (
  • {this.state.prefix} {item.name} @@ -130,6 +185,7 @@

    Date: Wed, 14 Sep 2016 17:59:35 +0100 Subject: [PATCH 026/292] Adjust style & code spacing --- examples/src/js/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 0838ac6f..d4581210 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -19,7 +19,7 @@ }, placeholder: { backgroundColor: '#CCC', - border: [2, 'solid', '#CCC'] + border: [1, 'solid', '#CCC'] }, dragged: { backgroundColor: '#EEE', @@ -87,17 +87,21 @@ callback: function (event, item, index, newIndex, list) { this.setState({list: list}); }, + itemClicked: function (event, item) { this.setState({ clickedItem: item === this.state.clickedItem ? undefined : item }); }, + itemClicked2: function (event, item) { this.setState({clickedItem2: item}); }, + onDisableToggle: function () { this.setState({disableReorder: !this.state.disableReorder}); }, + onPrefixChange: function (event) { var target = event.currentTarget; this.setState({prefix: target.value}); @@ -120,6 +124,7 @@ prefix: 'Prefix' }; }, + render: function () { return (
    From a5c7d976e8d184f2331e3a9072b35f9829599484 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 14 Sep 2016 17:59:44 +0100 Subject: [PATCH 027/292] Fix dragged style --- lib/index.js | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/lib/index.js b/lib/index.js index df9e2fd2..3db34a1e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -426,7 +426,7 @@ draggedIndex: index, placedIndex: index, draggedStyle: { - position: 'absolute', + position: 'fixed', top: rect.top, left: rect.left, width: rect.width, @@ -500,21 +500,12 @@ if (this.state.draggedIndex >= 0) { this.copyTouchKeys(event); - var draggedStyle = { - position: this.state.draggedStyle.position, - top: this.state.draggedStyle.top, - left: this.state.draggedStyle.left, - width: this.state.draggedStyle.width, - height: this.state.draggedStyle.height - }; - - if (!this.props.lock || this.props.lock === 'horizontal') { - draggedStyle.top = event.clientY - this.state.downOffset.clientY; - } - - if (!this.props.lock || this.props.lock === 'vertical') { - draggedStyle.left = event.clientX - this.state.downOffset.clientX; - } + var draggedStyle = extend({}, this.state.draggedStyle, { + top: (!this.props.lock || this.props.lock === 'horizontal') ? + event.clientY - this.state.downOffset.clientY : this.state.draggedStyl.top, + left: (!this.props.lock || this.props.lock === 'vertical') ? + event.clientX - this.state.downOffset.clientX : this.state.draggedStyle.left + }); this.setState({ draggedStyle: draggedStyle @@ -546,7 +537,7 @@ var className = child.props.className; var draggedStyle = isDragged ? extend({}, child.props.style, self.state.draggedStyle) : child.props.style; - var draggedClass = [child.props.className || '', self.props.draggedClassName || ''].join(' '); + var draggedClass = [child.props.className || '', (isDragged ? self.props.draggedClassName : '') || ''].join(' '); return React.cloneElement( child, From f237c1de1b18551698719bc48f625acfaa2d988b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 14 Sep 2016 18:07:53 +0100 Subject: [PATCH 028/292] Add some comments and rename mouse offset --- lib/index.js | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/index.js b/lib/index.js index 3db34a1e..82e73106 100644 --- a/lib/index.js +++ b/lib/index.js @@ -412,6 +412,7 @@ } }, + // Begin dragging index, set initial drag style, set placeholder position, calculate mouse offset onItemDown: function (callback, index, event) { if (event.button === 2) { return; @@ -423,6 +424,10 @@ var rect = event.target.getBoundingClientRect(); self.setState({ + downPos: { + clientX: event.clientX, + clientY: event.clientY + }, draggedIndex: index, placedIndex: index, draggedStyle: { @@ -432,7 +437,7 @@ width: rect.width, height: rect.height }, - downOffset: { + mouseOffset: { clientX: event.clientX - rect.left, clientY: event.clientY - rect.top } @@ -443,6 +448,14 @@ } }, + onItemMove: function (callback, index, event) { + + + if (typeof callback === 'function') { + callback(event); + } + }, + onListDown: function (callback, event) { if (event.button === 2) { return; @@ -451,13 +464,6 @@ this.copyTouchKeys(event); console.log('List down'); - this.setState({ - downPos: { - clientX: event.clientX, - clientY: event.clientY - } - }); - if (typeof callback === 'function') { callback(event); } @@ -489,6 +495,7 @@ } }, + // Stop dragging - reset style & draggedIndex onWindowUp: function () { this.setState({ draggedIndex: -1, @@ -496,15 +503,16 @@ }); }, + // Update dragged position if dragging onWindowMove: function (event) { if (this.state.draggedIndex >= 0) { this.copyTouchKeys(event); var draggedStyle = extend({}, this.state.draggedStyle, { top: (!this.props.lock || this.props.lock === 'horizontal') ? - event.clientY - this.state.downOffset.clientY : this.state.draggedStyl.top, + event.clientY - this.state.mouseOffset.clientY : this.state.draggedStyle.top, left: (!this.props.lock || this.props.lock === 'vertical') ? - event.clientX - this.state.downOffset.clientX : this.state.draggedStyle.left + event.clientX - this.state.mouseOffset.clientX : this.state.draggedStyle.left }); this.setState({ @@ -513,6 +521,7 @@ } }, + // Add listeners componentWillMount: function() { window.addEventListener('mouseup', this.onWindowUp); window.addEventListener('touchend', this.onWindowUp); @@ -521,6 +530,7 @@ window.addEventListener('contextmenu', this.preventDefaultIfDragging); }, + // Remove listeners componentWillUnmount: function() { window.removeEventListener('mouseup', this.onWindowUp); window.removeEventListener('touchend', this.onWindowUp); @@ -545,7 +555,9 @@ style: draggedStyle, className: draggedClass, onMouseDown: self.onItemDown.bind(self, child.props.onMouseDown, index), - onTouchStart: self.onItemDown.bind(self, child.props.onTouchStart, index) + onTouchStart: self.onItemDown.bind(self, child.props.onTouchStart, index), + onMouseMove: self.onItemMove.bind(self, child.props.onMouseMove, index), + onTouchMove: self.onItemMove.bind(self, child.props.onTouchMove, index) } ); }.bind(this)); From 9bdae94fb1fa0d9b52de3f83ed8a49c7ea884984 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 14 Sep 2016 19:00:29 +0100 Subject: [PATCH 029/292] Basic collision detection --- lib/index.js | 74 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/lib/index.js b/lib/index.js index 82e73106..059431b1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -412,6 +412,45 @@ } }, + xCollision: function (rect, event) { + return event.clientX >= rect.left && event.clientX <= rect.right; + }, + + yCollision: function (rect, event) { + return event.clientY >= rect.top && event.clientY <= rect.bottom; + }, + + findCollisionIndex: function (listElements, event) { + for (var i = 0; i < listElements.length; i += 1) { + if (!listElements[i].getAttribute('data-placeholder') && !listElements[i].getAttribute('data-dragged')) { + + var rect = listElements[i].getBoundingClientRect(); + + switch (this.props.lock) { + case 'horizontal': + if (this.yCollision(rect, event)) { + return i; + } + break; + case 'vertical': + if (this.xCollision(rect, event)) { + return i; + } + break; + default: + if (this.yCollision(rect, event) && this.xCollision(rect, event)) { + return i; + } + break; + } + + } + + } + + return -1; + }, + // Begin dragging index, set initial drag style, set placeholder position, calculate mouse offset onItemDown: function (callback, index, event) { if (event.button === 2) { @@ -419,7 +458,6 @@ } this.copyTouchKeys(event); - console.log('Item down'); var self = this; var rect = event.target.getBoundingClientRect(); @@ -449,7 +487,13 @@ }, onItemMove: function (callback, index, event) { + if (event.button === 2) { + return; + } + this.copyTouchKeys(event); + + console.log('Move', index); if (typeof callback === 'function') { callback(event); @@ -462,40 +506,39 @@ } this.copyTouchKeys(event); - console.log('List down'); if (typeof callback === 'function') { callback(event); } }, + // Handle moving from one list to another onListMove: function (callback, event) { if (event.button === 2) { return; } this.copyTouchKeys(event); - console.log('List move'); if (typeof callback === 'function') { callback(event); } }, + // Handle same as list move onListUp: function (callback, event) { if (event.button === 2) { return; } this.copyTouchKeys(event); - console.log('List up'); if (typeof callback === 'function') { callback(event); } }, - // Stop dragging - reset style & draggedIndex + // Stop dragging - reset style & draggedIndex handle reorder onWindowUp: function () { this.setState({ draggedIndex: -1, @@ -503,7 +546,7 @@ }); }, - // Update dragged position if dragging + // Update dragged position onWindowMove: function (event) { if (this.state.draggedIndex >= 0) { this.copyTouchKeys(event); @@ -515,6 +558,19 @@ event.clientX - this.state.mouseOffset.clientX : this.state.draggedStyle.left }); + var children = ReactDOM.findDOMNode(this).childNodes; + var collisionIndex = this.findCollisionIndex(children, event); + + if ( + collisionIndex !== this.state.placedIndex && + collisionIndex <= this.props.children.length && + collisionIndex >= 0 + ) { + this.setState({ + placedIndex: collisionIndex + }); + } + this.setState({ draggedStyle: draggedStyle }); @@ -556,8 +612,7 @@ className: draggedClass, onMouseDown: self.onItemDown.bind(self, child.props.onMouseDown, index), onTouchStart: self.onItemDown.bind(self, child.props.onTouchStart, index), - onMouseMove: self.onItemMove.bind(self, child.props.onMouseMove, index), - onTouchMove: self.onItemMove.bind(self, child.props.onTouchMove, index) + 'data-dragged': isDragged ? true : null } ); }.bind(this)); @@ -569,7 +624,8 @@ draggedElement, { key: 'react-reorder-placeholder', - className: [draggedElement.props.className || '', self.props.placeholderClassName || ''].join(' ') + className: [draggedElement.props.className || '', self.props.placeholderClassName || ''].join(' '), + 'data-placeholder': true } ); children.splice(this.state.placedIndex, 0, placeholder); From 09f641e82e33a4b1f7e1af1a5082f441922d2766 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 14 Sep 2016 19:31:15 +0100 Subject: [PATCH 030/292] onReorder callback --- examples/src/js/index.js | 55 ++++++++++++++++++++++------------------ lib/index.js | 9 ++++++- 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index d4581210..a3e59d85 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -84,31 +84,6 @@ }); var Main = React.createClass({ - callback: function (event, item, index, newIndex, list) { - this.setState({list: list}); - }, - - itemClicked: function (event, item) { - this.setState({ - clickedItem: item === this.state.clickedItem ? undefined : item - }); - }, - - itemClicked2: function (event, item) { - this.setState({clickedItem2: item}); - }, - - onDisableToggle: function () { - this.setState({disableReorder: !this.state.disableReorder}); - }, - - onPrefixChange: function (event) { - var target = event.currentTarget; - this.setState({prefix: target.value}); - }, - - // ---- - getInitialState: function () { var list = []; @@ -125,6 +100,35 @@ }; }, + onReorder: function (event, previousIndex, nextIndex) { + console.log(previousIndex, nextIndex); + + var list = [].concat(this.state.list); + list.splice(nextIndex, 0, list.splice(previousIndex, 1)[0]); + + console.log(list); + + this.setState({ + list: list + }); + }, + + onDisableToggle: function () { + this.setState({ + disableReorder: !this.state.disableReorder + }); + }, + + onPrefixChange: function (event) { + var target = event.currentTarget; + + this.setState({ + prefix: target.value + }); + }, + + // ---- + render: function () { return (
    @@ -156,6 +160,7 @@ callback={this.callback} placeholderClassName={classNames.placeholder} draggedClassName={classNames.dragged} + onReorder={this.onReorder} > { this.state.list.map(function (item) { diff --git a/lib/index.js b/lib/index.js index 059431b1..bc1f341a 100644 --- a/lib/index.js +++ b/lib/index.js @@ -539,7 +539,14 @@ }, // Stop dragging - reset style & draggedIndex handle reorder - onWindowUp: function () { + onWindowUp: function (event) { + var fromIndex = this.state.draggedIndex; + var toIndex = this.state.placedIndex; + + if (typeof this.props.onReorder === 'function' && fromIndex !== toIndex) { + this.props.onReorder(event, fromIndex, toIndex - (fromIndex < toIndex ? 1 : 0)); + } + this.setState({ draggedIndex: -1, draggedStyle: null From 50b0dd8b3430658e73876c350976171ece092252 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 14 Sep 2016 19:31:47 +0100 Subject: [PATCH 031/292] Remove logs --- examples/src/js/index.js | 4 ---- lib/index.js | 2 -- 2 files changed, 6 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index a3e59d85..1110a1d0 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -101,13 +101,9 @@ }, onReorder: function (event, previousIndex, nextIndex) { - console.log(previousIndex, nextIndex); - var list = [].concat(this.state.list); list.splice(nextIndex, 0, list.splice(previousIndex, 1)[0]); - console.log(list); - this.setState({ list: list }); diff --git a/lib/index.js b/lib/index.js index bc1f341a..3b6ad0bb 100644 --- a/lib/index.js +++ b/lib/index.js @@ -493,8 +493,6 @@ this.copyTouchKeys(event); - console.log('Move', index); - if (typeof callback === 'function') { callback(event); } From b1d1f8de29c5c7c4c0c0aa6656904052cdb7318a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 14 Sep 2016 19:32:28 +0100 Subject: [PATCH 032/292] Update comments --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index 3b6ad0bb..8b4b6a80 100644 --- a/lib/index.js +++ b/lib/index.js @@ -536,7 +536,7 @@ } }, - // Stop dragging - reset style & draggedIndex handle reorder + // Stop dragging - reset style & draggedIndex, handle reorder onWindowUp: function (event) { var fromIndex = this.state.draggedIndex; var toIndex = this.state.placedIndex; @@ -551,7 +551,7 @@ }); }, - // Update dragged position + // Update dragged position & placeholder index onWindowMove: function (event) { if (this.state.draggedIndex >= 0) { this.copyTouchKeys(event); From 19f852d4128911734db0478e2ce1135ed41256d9 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 14 Sep 2016 19:45:17 +0100 Subject: [PATCH 033/292] Remove unused downPos --- lib/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/index.js b/lib/index.js index 8b4b6a80..db5beb1e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -462,10 +462,6 @@ var rect = event.target.getBoundingClientRect(); self.setState({ - downPos: { - clientX: event.clientX, - clientY: event.clientY - }, draggedIndex: index, placedIndex: index, draggedStyle: { From 69cfee5f8228d0f1cabfefe1321329c292ef50ad Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 14 Sep 2016 19:45:23 +0100 Subject: [PATCH 034/292] Prevent touch scrolling --- lib/index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/index.js b/lib/index.js index db5beb1e..e36452ed 100644 --- a/lib/index.js +++ b/lib/index.js @@ -401,6 +401,12 @@ } }, + preventTouchScrolling: function (event) { + if (event.touches) { + event.preventDefault(); + } + }, + copyTouchKeys: function (event) { if (event.touches && event.touches[0]) { if (typeof event.persist === 'function') { @@ -551,6 +557,7 @@ onWindowMove: function (event) { if (this.state.draggedIndex >= 0) { this.copyTouchKeys(event); + this.preventTouchScrolling(event); var draggedStyle = extend({}, this.state.draggedStyle, { top: (!this.props.lock || this.props.lock === 'horizontal') ? From b8b827894a84c898252da243dea80774e24787b2 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 14 Sep 2016 20:00:03 +0100 Subject: [PATCH 035/292] Remove old callback --- examples/src/js/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 1110a1d0..61575e9e 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -153,7 +153,6 @@ className={[classNames.myList, classNames.myList1].join(' ')} lock="horizontal" holdTime={500} - callback={this.callback} placeholderClassName={classNames.placeholder} draggedClassName={classNames.dragged} onReorder={this.onReorder} From f133c1e400efe6aa2c17915e52c00c551c449247 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 19 Sep 2016 23:09:21 +0100 Subject: [PATCH 036/292] Delay dragging --- lib/index.js | 82 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 25 deletions(-) diff --git a/lib/index.js b/lib/index.js index e36452ed..92b93fe3 100644 --- a/lib/index.js +++ b/lib/index.js @@ -407,11 +407,15 @@ } }, + persistEvent: function (event) { + if (typeof event.persist === 'function') { + event.persist(); + } + }, + copyTouchKeys: function (event) { if (event.touches && event.touches[0]) { - if (typeof event.persist === 'function') { - event.persist(); - } + this.persistEvent(event); event.clientX = event.touches[0].clientX; event.clientY = event.touches[0].clientY; @@ -457,17 +461,22 @@ return -1; }, - // Begin dragging index, set initial drag style, set placeholder position, calculate mouse offset - onItemDown: function (callback, index, event) { - if (event.button === 2) { - return; + getHoldTime: function (event) { + var holdTime = 0; + + if (event.touches && this.props.touchHoldTime || this.props.touchHoldTime === 0) { + holdTime = parseInt(this.props.touchHoldTime, 10); + } else if (this.props.mouseHoldTime || this.props.mouseHoldTime === 0) { + holdTime = parseInt(this.props.mouseHoldTime, 10); } - this.copyTouchKeys(event); - var self = this; - var rect = event.target.getBoundingClientRect(); + return holdTime || parseInt(this.props.holdTime, 10) || 0; + }, + + startDrag: function (event, target, index) { + var rect = target.getBoundingClientRect(); - self.setState({ + this.setState({ draggedIndex: index, placedIndex: index, draggedStyle: { @@ -482,64 +491,85 @@ clientY: event.clientY - rect.top } }); + }, + // Begin dragging index, set initial drag style, set placeholder position, calculate mouse offset + onItemDown: function (callback, index, event) { if (typeof callback === 'function') { callback(event); } - }, - onItemMove: function (callback, index, event) { - if (event.button === 2) { + if (event.button === 2 || this.props.disabled) { return; } this.copyTouchKeys(event); + var holdTime = this.getHoldTime(event); + var target = event.currentTarget; + + if (holdTime) { + this.persistEvent(event); + this.holdTimeout = setTimeout(this.startDrag.bind(this, event, target, index), holdTime); + } else { + this.startDrag(event, target, index); + } + }, + + onItemMove: function (callback, index, event) { if (typeof callback === 'function') { callback(event); } - }, - onListDown: function (callback, event) { - if (event.button === 2) { + if (event.button === 2 || this.props.disabled) { return; } this.copyTouchKeys(event); + }, + onListDown: function (callback, event) { if (typeof callback === 'function') { callback(event); } - }, - // Handle moving from one list to another - onListMove: function (callback, event) { - if (event.button === 2) { + if (event.button === 2 || this.props.disabled) { return; } this.copyTouchKeys(event); + }, + // Handle moving from one list to another + onListMove: function (callback, event) { if (typeof callback === 'function') { callback(event); } - }, - // Handle same as list move - onListUp: function (callback, event) { - if (event.button === 2) { + if (event.button === 2 || this.props.disabled) { return; } this.copyTouchKeys(event); + }, + // Handle same as list move + onListUp: function (callback, event) { if (typeof callback === 'function') { callback(event); } + + if (event.button === 2 || this.props.disabled) { + return; + } + + this.copyTouchKeys(event); }, // Stop dragging - reset style & draggedIndex, handle reorder onWindowUp: function (event) { + clearTimeout(this.holdTimeout); + var fromIndex = this.state.draggedIndex; var toIndex = this.state.placedIndex; @@ -596,6 +626,8 @@ // Remove listeners componentWillUnmount: function() { + clearTimeout(this.holdTimeout); + window.removeEventListener('mouseup', this.onWindowUp); window.removeEventListener('touchend', this.onWindowUp); window.removeEventListener('mousemove', this.onWindowMove); From 63a73b3c0d56418659ad57415e76c3ac3e4b704b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 19 Sep 2016 23:11:03 +0100 Subject: [PATCH 037/292] Only reorder if dragging --- lib/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/index.js b/lib/index.js index 92b93fe3..c16a3b32 100644 --- a/lib/index.js +++ b/lib/index.js @@ -573,7 +573,11 @@ var fromIndex = this.state.draggedIndex; var toIndex = this.state.placedIndex; - if (typeof this.props.onReorder === 'function' && fromIndex !== toIndex) { + if ( + typeof this.props.onReorder === 'function' && + fromIndex !== toIndex && + fromIndex >= 0 + ) { this.props.onReorder(event, fromIndex, toIndex - (fromIndex < toIndex ? 1 : 0)); } From 7406658cf7f665b7ca1f1f315eaffca7f45cfda3 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 19 Sep 2016 23:21:37 +0100 Subject: [PATCH 038/292] Fix getHoldTime --- lib/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/index.js b/lib/index.js index c16a3b32..af32bff1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -462,15 +462,13 @@ }, getHoldTime: function (event) { - var holdTime = 0; - if (event.touches && this.props.touchHoldTime || this.props.touchHoldTime === 0) { - holdTime = parseInt(this.props.touchHoldTime, 10); + return parseInt(this.props.touchHoldTime, 10) || 0; } else if (this.props.mouseHoldTime || this.props.mouseHoldTime === 0) { - holdTime = parseInt(this.props.mouseHoldTime, 10); + return parseInt(this.props.mouseHoldTime, 10) || 0; } - return holdTime || parseInt(this.props.holdTime, 10) || 0; + return parseInt(this.props.holdTime, 10) || 0; }, startDrag: function (event, target, index) { From eedc7f4a68aa7533671a24d0b013b1eb3c41bc69 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 19 Sep 2016 23:29:40 +0100 Subject: [PATCH 039/292] Do not allow drag if moved --- lib/index.js | 54 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/lib/index.js b/lib/index.js index af32bff1..ab368f3b 100644 --- a/lib/index.js +++ b/lib/index.js @@ -472,23 +472,25 @@ }, startDrag: function (event, target, index) { - var rect = target.getBoundingClientRect(); + if (!this.moved) { + var rect = target.getBoundingClientRect(); - this.setState({ - draggedIndex: index, - placedIndex: index, - draggedStyle: { - position: 'fixed', - top: rect.top, - left: rect.left, - width: rect.width, - height: rect.height - }, - mouseOffset: { - clientX: event.clientX - rect.left, - clientY: event.clientY - rect.top - } - }); + this.setState({ + draggedIndex: index, + placedIndex: index, + draggedStyle: { + position: 'fixed', + top: rect.top, + left: rect.left, + width: rect.width, + height: rect.height + }, + mouseOffset: { + clientX: event.clientX - rect.left, + clientY: event.clientY - rect.top + } + }); + } }, // Begin dragging index, set initial drag style, set placeholder position, calculate mouse offset @@ -503,6 +505,12 @@ this.copyTouchKeys(event); + this.moved = false; + this.downPos = { + clientX: event.clientX, + clientY: event.clientY + }; + var holdTime = this.getHoldTime(event); var target = event.currentTarget; @@ -585,10 +593,20 @@ }); }, - // Update dragged position & placeholder index + // Update dragged position & placeholder index, invalidate drag if moved onWindowMove: function (event) { + this.copyTouchKeys(event); + + if ( + this.downPos && ( + Math.abs(event.clientX - this.downPos.clientX) >= CONSTANTS.HOLD_THRESHOLD || + Math.abs(event.clientY - this.downPos.clientY) >= CONSTANTS.HOLD_THRESHOLD + ) + ) { + this.moved = true; + } + if (this.state.draggedIndex >= 0) { - this.copyTouchKeys(event); this.preventTouchScrolling(event); var draggedStyle = extend({}, this.state.draggedStyle, { From e6c6057802adaf598143ad07964ac16107e98c47 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 19 Sep 2016 23:36:22 +0100 Subject: [PATCH 040/292] Setup second demo --- examples/src/js/index.js | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 61575e9e..e4e32dc1 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -151,10 +151,10 @@ { @@ -190,18 +190,29 @@

    + holdTime={250} + onReorder={this.onReorder} + disabled={this.state.disableReorder} + > + { + this.state.list.map(function (item) { + return ( +
  • + {item.name} +
  • + ); + }.bind(this)) + } +

    No lock (grid) From 5b14294d11613aaba8cfe73827e608d0f8eafcc6 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 19 Sep 2016 23:37:55 +0100 Subject: [PATCH 041/292] Setup third demo --- examples/src/js/index.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index e4e32dc1..17e08e38 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -223,14 +223,24 @@ + placeholderClassName={classNames.placeholder} + draggedClassName={classNames.dragged} + onReorder={this.onReorder} + > + { + this.state.list.map(function (item) { + return ( +
  • + {item.name} +
  • + ); + }.bind(this)) + } +

    ); } From f5cfacc1d75e14d94c26729f1996aad0c81683f9 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 19 Sep 2016 23:46:00 +0100 Subject: [PATCH 042/292] Custom placeholder element --- examples/src/js/index.js | 3 ++- lib/index.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 17e08e38..5da815cc 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -52,7 +52,7 @@ listItem: { float: 'left', width: '100%', - height: 'auto', + height: 46, padding: 12, border: [2, 'solid', 'lightblue'], marginBottom: 8, @@ -156,6 +156,7 @@ lock="horizontal" holdTime={500} onReorder={this.onReorder} + placeholder={
    } > { this.state.list.map(function (item) { diff --git a/lib/index.js b/lib/index.js index ab368f3b..cce17977 100644 --- a/lib/index.js +++ b/lib/index.js @@ -681,7 +681,7 @@ if (this.state.placedIndex >= 0 && draggedElement) { var placeholder = React.cloneElement( - draggedElement, + this.props.placeholder || draggedElement, { key: 'react-reorder-placeholder', className: [draggedElement.props.className || '', self.props.placeholderClassName || ''].join(' '), From 181f67a47fa4bc72166840bb07f777c97985dbe9 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 19 Sep 2016 23:55:50 +0100 Subject: [PATCH 043/292] Fix custom placeholder --- examples/src/js/index.js | 5 ++++- lib/index.js | 8 +++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 5da815cc..fec87bce 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -21,6 +21,9 @@ backgroundColor: '#CCC', border: [1, 'solid', '#CCC'] }, + customPlaceholder: { + height: 0 + }, dragged: { backgroundColor: '#EEE', transform: 'scale(0.98, 0.98)', @@ -156,7 +159,7 @@ lock="horizontal" holdTime={500} onReorder={this.onReorder} - placeholder={
    } + placeholder={
    } > { this.state.list.map(function (item) { diff --git a/lib/index.js b/lib/index.js index cce17977..9ab99a34 100644 --- a/lib/index.js +++ b/lib/index.js @@ -588,6 +588,7 @@ } this.setState({ + placedIndex: -1, draggedIndex: -1, draggedStyle: null }); @@ -678,13 +679,14 @@ }.bind(this)); var draggedElement = this.props.children && this.props.children[this.state.draggedIndex]; + var placeholderElement = this.props.placeholder || draggedElement; - if (this.state.placedIndex >= 0 && draggedElement) { + if (this.state.placedIndex >= 0 && placeholderElement) { var placeholder = React.cloneElement( - this.props.placeholder || draggedElement, + placeholderElement, { key: 'react-reorder-placeholder', - className: [draggedElement.props.className || '', self.props.placeholderClassName || ''].join(' '), + className: [placeholderElement.props.className || '', self.props.placeholderClassName || ''].join(' '), 'data-placeholder': true } ); From 6a4d964292610247fbfb6753349f8f9f708f3cbf Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 19 Sep 2016 23:59:45 +0100 Subject: [PATCH 044/292] Adjust styles --- examples/src/js/index.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index fec87bce..51f261e2 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -17,21 +17,6 @@ margin: 'auto', padding: 8 }, - placeholder: { - backgroundColor: '#CCC', - border: [1, 'solid', '#CCC'] - }, - customPlaceholder: { - height: 0 - }, - dragged: { - backgroundColor: '#EEE', - transform: 'scale(0.98, 0.98)', - opacity: 0.7 - }, - selected: { - border: [2, 'solid', 'red'] - }, myList: { float: 'left', width: '100%', @@ -72,6 +57,21 @@ listItem3: { float: 'left', width: '50%' + }, + placeholder: { + backgroundColor: '#CCC', + border: [1, 'solid', '#CCC'] + }, + customPlaceholder: { + opacity: 0.2 + }, + dragged: { + backgroundColor: '#EEE', + transform: 'scale(0.98, 0.98)', + opacity: 0.8 + }, + selected: { + border: [2, 'solid', 'red'] } }); From 28e8cf63f55e95e4592948d17c4101af9297bd75 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 20 Sep 2016 00:02:21 +0100 Subject: [PATCH 045/292] Fix linting --- examples/src/js/index.js | 11 ----------- lib/index.js | 20 +++++++++++--------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 51f261e2..c54072db 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -75,17 +75,6 @@ } }); - var ListItem = React.createClass({ - render: function () { - return React.createElement('div', { - className: 'inner', - style: { - color: this.props.item.color - } - }, this.props.sharedProps ? this.props.sharedProps.prefix : undefined, this.props.item.name); - } - }); - var Main = React.createClass({ getInitialState: function () { var list = []; diff --git a/lib/index.js b/lib/index.js index 9ab99a34..0a2c94fd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,12 +4,12 @@ var getReorderComponent = function (React, ReactDOM) { function extend (obj1, obj2, obj3) { - for (var key in obj2) { - obj1[key] = obj2[key]; + for (var key2 in obj2) { + obj1[key2] = obj2[key2]; } - for (var key in obj3) { - obj1[key] = obj3[key]; + for (var key3 in obj3) { + obj1[key3] = obj3[key3]; } return obj1; @@ -384,7 +384,7 @@ // list: this.props.list || [] // }; // }, - getInitialState: function() { + getInitialState: function () { return { draggedIndex: -1, draggedStyle: null @@ -637,7 +637,7 @@ }, // Add listeners - componentWillMount: function() { + componentWillMount: function () { window.addEventListener('mouseup', this.onWindowUp); window.addEventListener('touchend', this.onWindowUp); window.addEventListener('mousemove', this.onWindowMove); @@ -646,7 +646,7 @@ }, // Remove listeners - componentWillUnmount: function() { + componentWillUnmount: function () { clearTimeout(this.holdTimeout); window.removeEventListener('mouseup', this.onWindowUp); @@ -661,10 +661,12 @@ var children = this.props.children && this.props.children.map(function (child, index) { var isDragged = index === self.state.draggedIndex; - var className = child.props.className; var draggedStyle = isDragged ? extend({}, child.props.style, self.state.draggedStyle) : child.props.style; - var draggedClass = [child.props.className || '', (isDragged ? self.props.draggedClassName : '') || ''].join(' '); + var draggedClass = [ + child.props.className || '', + (isDragged ? self.props.draggedClassName : '') || '' + ].join(' '); return React.cloneElement( child, From 32e0ec5ac019b5d3ef7f1cdb8f5afb741399b214 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 30 Oct 2016 20:00:41 +0000 Subject: [PATCH 046/292] Test with immutable --- examples/src/js/index.js | 27 ++++++++++++--------------- package.json | 1 + 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index c54072db..a286bb61 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -6,6 +6,7 @@ var React = require('react'); var ReactDOM = require('react-dom'); var ReactStyleSheets = require('react-style-sheets'); + var Immutable = require('immutable'); var Reorder = require('../../../lib/index'); var classNames = ReactStyleSheets.createUniqueClassStyles({ @@ -77,24 +78,20 @@ var Main = React.createClass({ getInitialState: function () { - var list = []; - - for (var i = 0; i < 10; i += 1) { - list.push({ - name: ['Thing', i].join(' '), - color: ['rgb(', (i + 1) * 25, ',', 250 - ((i + 1) * 25), ',0)'].join('') - }); - } - return { - list: list, + list: Immutable.List(Immutable.Range(0, 10).map(function (value) { + return { + name: ['Thing', value].join(' '), + color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') + } + })), prefix: 'Prefix' }; }, onReorder: function (event, previousIndex, nextIndex) { - var list = [].concat(this.state.list); - list.splice(nextIndex, 0, list.splice(previousIndex, 1)[0]); + // list.splice(nextIndex, 0, list.splice(previousIndex, 1)[0]); + var list = this.state.list.delete(previousIndex).splice(nextIndex, 0, this.state.list.get(previousIndex)); this.setState({ list: list @@ -162,7 +159,7 @@ ); - }.bind(this)) + }.bind(this)).toArray() } @@ -203,7 +200,7 @@ {item.name} ); - }.bind(this)) + }.bind(this)).toArray() } @@ -231,7 +228,7 @@ {item.name} ); - }.bind(this)) + }.bind(this)).toArray() }
    diff --git a/package.json b/package.json index 705d704c..d73f58c8 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "browserify": "=12.0.1", "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", + "immutable": "=3.8.1", "react": "=15.3.1", "react-dom": "=15.3.1", "react-style-sheets": "=0.1.0", From 3aaefc27a0110c1a75ad93b805f9d747915a66a1 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 30 Oct 2016 20:01:13 +0000 Subject: [PATCH 047/292] Semi --- examples/src/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index a286bb61..dc8c4ff1 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -83,7 +83,7 @@ return { name: ['Thing', value].join(' '), color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') - } + }; })), prefix: 'Prefix' }; From 69473c9de1d61ead2b5c7d4c573a593cb675fd41 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 30 Oct 2016 20:26:16 +0000 Subject: [PATCH 048/292] Add reorder helper methods --- examples/src/js/index.js | 3 +-- lib/index.js | 53 ++++++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index dc8c4ff1..963986d2 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -90,8 +90,7 @@ }, onReorder: function (event, previousIndex, nextIndex) { - // list.splice(nextIndex, 0, list.splice(previousIndex, 1)[0]); - var list = this.state.list.delete(previousIndex).splice(nextIndex, 0, this.state.list.get(previousIndex)); + var list = Immutable.List(Reorder.reorderImmutable(this.state.list, previousIndex, nextIndex)); this.setState({ list: list diff --git a/lib/index.js b/lib/index.js index 0a2c94fd..5fe8f29d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,27 +1,42 @@ 'use strict'; (function () { - var getReorderComponent = function (React, ReactDOM) { - function extend (obj1, obj2, obj3) { - for (var key2 in obj2) { - obj1[key2] = obj2[key2]; - } + var CONSTANTS = { + HOLD_THRESHOLD: 8, + SCROLL_RATE: 1000 / 60, + SCROLL_AREA: 50, + SCROLL_MULTIPLIER: 5 + }; - for (var key3 in obj3) { - obj1[key3] = obj3[key3]; - } + function extend (obj1, obj2, obj3) { + for (var key2 in obj2) { + obj1[key2] = obj2[key2]; + } - return obj1; + for (var key3 in obj3) { + obj1[key3] = obj3[key3]; } - var CONSTANTS = { - HOLD_THRESHOLD: 8, - SCROLL_RATE: 1000 / 60, - SCROLL_AREA: 50, - SCROLL_MULTIPLIER: 5 - }; + return obj1; + } + + function reorder (list, previousIndex, nextIndex, mutate) { + list = mutate ? list : [].concat(list); + return list.splice(nextIndex, 0, list.splice(previousIndex, 1)[0]); + } + function reorderImmutable (list, previousIndex, nextIndex) { + return list.delete(previousIndex).splice(nextIndex, 0, list.get(previousIndex)); + } + + function withReorderMethods (Reorder) { + Reorder.reorder = reorder; + Reorder.reorderImmutable = reorderImmutable; + return Reorder; + } + + function getReorderComponent (React, ReactDOM) { return React.createClass({ displayName: 'Reorder', // nonCollisionElement: new RegExp('(^|\\s)(placeholder|dragged)($|\\s)', ''), @@ -760,17 +775,17 @@ } }); - }; + } // Export for commonjs / browserify if (typeof exports === 'object' && typeof module !== 'undefined') { var React = require('react'); var ReactDOM = require('react-dom'); - module.exports = getReorderComponent(React, ReactDOM); + module.exports = withReorderMethods(getReorderComponent(React, ReactDOM)); // Export for amd / require } else if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef define(['react', 'react-dom'], function (ReactAMD, ReactDOMAMD) { // eslint-disable-line no-undef - return getReorderComponent(ReactAMD, ReactDOMAMD); + return withReorderMethods(getReorderComponent(ReactAMD, ReactDOMAMD)); }); // Export globally } else { @@ -786,7 +801,7 @@ root = this; } - root.Reorder = getReorderComponent(root.React, root.ReactDOM); + root.Reorder = withReorderMethods(getReorderComponent(root.React, root.ReactDOM)); } })(); From b04642224bd5b9d2149aacddb29ac38b8da8962a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 30 Oct 2016 21:18:33 +0000 Subject: [PATCH 049/292] Do not allow mutation --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index 5fe8f29d..8a0c7317 100644 --- a/lib/index.js +++ b/lib/index.js @@ -21,8 +21,8 @@ return obj1; } - function reorder (list, previousIndex, nextIndex, mutate) { - list = mutate ? list : [].concat(list); + function reorder (list, previousIndex, nextIndex) { + list = [].concat(list); return list.splice(nextIndex, 0, list.splice(previousIndex, 1)[0]); } From 25bddfc73896600e087ea8b8d222eea277998a40 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 17:52:26 +0000 Subject: [PATCH 050/292] Prevent native scrolling always --- lib/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/index.js b/lib/index.js index 8a0c7317..a187dba0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -416,10 +416,8 @@ } }, - preventTouchScrolling: function (event) { - if (event.touches) { - event.preventDefault(); - } + preventNativeScrolling: function (event) { + event.preventDefault(); }, persistEvent: function (event) { @@ -623,7 +621,7 @@ } if (this.state.draggedIndex >= 0) { - this.preventTouchScrolling(event); + this.preventNativeScrolling(event); var draggedStyle = extend({}, this.state.draggedStyle, { top: (!this.props.lock || this.props.lock === 'horizontal') ? From 4e447bfb9bdea014554bbb5902d143e0bfef221b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 17:54:27 +0000 Subject: [PATCH 051/292] Method to check if dragging --- lib/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index a187dba0..362cb499 100644 --- a/lib/index.js +++ b/lib/index.js @@ -406,12 +406,16 @@ }; }, + isDragging: function () { + return this.state.draggedIndex >= 0; + }, + preventDefault: function (event) { event.preventDefault(); }, preventDefaultIfDragging: function (event) { - if (this.state.draggedIndex >= 0) { + if (this.isDragging()) { event.preventDefault(); } }, @@ -620,7 +624,7 @@ this.moved = true; } - if (this.state.draggedIndex >= 0) { + if (this.isDragging()) { this.preventNativeScrolling(event); var draggedStyle = extend({}, this.state.draggedStyle, { From 1c1d3595cf6568b79ceeb96ef32ac5212855c630 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 17:57:00 +0000 Subject: [PATCH 052/292] Remove commented out old code --- lib/index.js | 361 +-------------------------------------------------- 1 file changed, 1 insertion(+), 360 deletions(-) diff --git a/lib/index.js b/lib/index.js index 362cb499..03808770 100644 --- a/lib/index.js +++ b/lib/index.js @@ -39,366 +39,7 @@ function getReorderComponent (React, ReactDOM) { return React.createClass({ displayName: 'Reorder', - // nonCollisionElement: new RegExp('(^|\\s)(placeholder|dragged)($|\\s)', ''), - // startDrag: function (dragOffset, draggedStyle) { - // if (!this.props.disableReorder) { - // this.setState({ - // dragOffset: dragOffset, - // draggedStyle: draggedStyle, - // originalPosition: draggedStyle, - // held: true, - // moved: false - // }); - // } - // }, - // itemDown: function (item, index, event) { - // this.handleTouchEvents(event); - // - // var self = this; - // var target = event.currentTarget; - // var rect = target.getBoundingClientRect(); - // - // this.setState({ - // held: false, - // moved: false - // }); - // - // var dragOffset = { - // top: event.clientY - rect.top, - // left: event.clientX - rect.left - // }; - // - // this.setState({ - // dragged: { - // target: target, - // item: item, - // index: index - // } - // }); - // - // var draggedStyle = { - // position: 'fixed', - // top: rect.top, - // left: rect.left, - // width: rect.width, - // height: rect.height - // }; - // - // // Timeout if holdTime is defined - // var holdTime = Math.abs(parseInt(this.props.holdTime, 10)); - // - // if (holdTime) { - // this.holdTimeout = setTimeout(function () { - // self.startDrag(dragOffset, draggedStyle); - // }, holdTime); - // } else { - // self.startDrag(dragOffset, draggedStyle); - // } - // }, - // listDown: function (event) { - // this.handleTouchEvents(event); - // - // var self = this; - // - // var downPos = { - // clientY: event.clientY, - // clientX: event.clientX, - // scrollTop: ReactDOM.findDOMNode(self).scrollTop, - // scrollLeft: ReactDOM.findDOMNode(self).scrollLeft - // }; - // - // this.setState({ - // downPos: downPos, - // pointer: { - // clientY: downPos.clientY, - // clientX: downPos.clientX - // }, - // velocity: { - // y: 0, - // x: 0 - // }, - // movedALittle: false - // }); - // - // // Mouse events - // window.addEventListener('mouseup', this.onMouseUp); // Mouse up - // window.addEventListener('mousemove', this.onMouseMove); // Mouse move - // - // // Touch events - // window.addEventListener('touchend', this.onMouseUp); // Touch up - // window.addEventListener('touchmove', this.onMouseMove); // Touch move - // - // window.addEventListener('contextmenu', this.preventDefault); - // }, - // onMouseUp: function (event) { - // if (event.type.indexOf('touch') >= 0 && !this.state.movedALittle) { - // event.preventDefault(); - // } - // - // // Item clicked - // if ( - // typeof this.props.itemClicked === 'function' && - // !this.state.held && - // !this.state.moved && - // this.state.dragged - // ) { - // this.props.itemClicked(event, this.state.dragged.item, this.state.dragged.index); - // } - // - // // Reorder callback - // if (this.state.held && this.state.dragged && typeof this.props.callback === 'function') { - // var listElements = this.nodesToArray(ReactDOM.findDOMNode(this).childNodes); - // var newIndex = listElements.indexOf(this.state.dragged.target); - // - // this.props.callback(event, this.state.dragged.item, this.state.dragged.index, newIndex, this.state.list); - // } - // - // this.setState({ - // dragged: undefined, - // draggedStyle: undefined, - // dragOffset: undefined, - // originalPosition: undefined, - // downPos: undefined, - // held: false, - // moved: false - // }); - // - // clearTimeout(this.holdTimeout); - // clearInterval(this.scrollIntervalY); - // this.scrollIntervalY = undefined; - // clearInterval(this.scrollIntervalX); - // this.scrollIntervalX = undefined; - // - // // Mouse events - // window.removeEventListener('mouseup', this.onMouseUp); // Mouse up - // window.removeEventListener('mousemove', this.onMouseMove); // Mouse move - // // Touch events - // window.removeEventListener('touchend', this.onMouseUp); // Touch up - // window.removeEventListener('touchmove', this.onMouseMove); // Touch move - // - // window.removeEventListener('contextmenu', this.preventDefault); - // }, - // getScrollArea: function (value) { - // return Math.max(Math.min(value / 4, this.constants.SCROLL_AREA), this.constants.SCROLL_AREA / 5); - // }, - // dragScrollY: function () { - // var element = ReactDOM.findDOMNode(this); - // var rect = element.getBoundingClientRect(); - // var scrollArea = this.getScrollArea(rect.height); - // - // var distanceInArea; - // if (this.state.pointer.clientY < rect.top + scrollArea) { - // distanceInArea = Math.min((rect.top + scrollArea) - this.state.pointer.clientY, scrollArea * 2); - // element.scrollTop -= distanceInArea / this.constants.SCROLL_MULTIPLIER; - // } else if (this.state.pointer.clientY > rect.bottom - scrollArea) { - // distanceInArea = Math.min(this.state.pointer.clientY - (rect.bottom - scrollArea), scrollArea * 2); - // element.scrollTop += distanceInArea / this.constants.SCROLL_MULTIPLIER; - // } - // }, - // dragScrollX: function () { - // var element = ReactDOM.findDOMNode(this); - // var rect = element.getBoundingClientRect(); - // var scrollArea = this.getScrollArea(rect.width); - // - // var distanceInArea; - // if (this.state.pointer.clientX < rect.left + scrollArea) { - // distanceInArea = Math.min((rect.left + scrollArea) - this.state.pointer.clientX, scrollArea * 2); - // element.scrollLeft -= distanceInArea / this.constants.SCROLL_MULTIPLIER; - // } else if (this.state.pointer.clientX > rect.right - scrollArea) { - // distanceInArea = Math.min(this.state.pointer.clientX - (rect.right - scrollArea), scrollArea * 2); - // element.scrollLeft += distanceInArea / this.constants.SCROLL_MULTIPLIER; - // } - // }, - // handleDragScrollY: function (event) { - // var rect = ReactDOM.findDOMNode(this).getBoundingClientRect(); - // - // if (!this.scrollIntervalY && this.props.lock !== 'vertical') { - // if (event.clientY < rect.top + this.constants.SCROLL_AREA) { - // this.scrollIntervalY = setInterval(this.dragScrollY, this.constants.SCROLL_RATE); - // } else if (event.clientY > rect.bottom - this.constants.SCROLL_AREA) { - // this.scrollIntervalY = setInterval(this.dragScrollY, this.constants.SCROLL_RATE); - // } - // } else if ( - // event.clientY <= rect.bottom - this.constants.SCROLL_AREA && - // event.clientY >= rect.top + this.constants.SCROLL_AREA - // ) { - // clearInterval(this.scrollIntervalY); - // this.scrollIntervalY = undefined; - // } - // }, - // handleDragScrollX: function (event) { - // var rect = ReactDOM.findDOMNode(this).getBoundingClientRect(); - // - // if (!this.scrollIntervalX && this.props.lock !== 'horizontal') { - // if (event.clientX < rect.left + this.constants.SCROLL_AREA) { - // this.scrollIntervalX = setInterval(this.dragScrollX, this.constants.SCROLL_RATE); - // } else if (event.clientX > rect.right - this.constants.SCROLL_AREA) { - // this.scrollIntervalX = setInterval(this.dragScrollX, this.constants.SCROLL_RATE); - // } - // } else if ( - // event.clientX <= rect.right - this.constants.SCROLL_AREA && - // event.clientX >= rect.left + this.constants.SCROLL_AREA - // ) { - // clearInterval(this.scrollIntervalX); - // this.scrollIntervalX = undefined; - // } - // }, - // onMouseMove: function (event) { - // this.handleTouchEvents(event); - // - // var pointer = { - // clientY: event.clientY, - // clientX: event.clientX - // }; - // - // this.setState({ - // pointer: pointer, - // velocity: { - // y: pointer.clientY - event.clientY, - // x: pointer.clientX - event.clientX - // }, - // movedALittle: true - // }); - // - // if (this.state.held && this.state.dragged) { - // event.preventDefault(); - // this.setDraggedPosition(event); - // - // var listElements = this.nodesToArray(ReactDOM.findDOMNode(this).childNodes); - // var collision = this.findCollision(listElements, event); - // - // if (collision) { - // var previousIndex = listElements.indexOf(this.state.dragged.target); - // var newIndex = listElements.indexOf(collision); - // - // this.state.list.splice(newIndex, 0, this.state.list.splice(previousIndex, 1)[0]); - // this.setState({list: this.state.list}); - // } - // - // this.handleDragScrollY(event); - // this.handleDragScrollX(event); - // } else if (this.state.downPos) { - // // Cancel hold if mouse has moved - // if (this.xHasMoved(event) || this.yHasMoved(event)) { - // clearTimeout(this.holdTimeout); - // this.setState({moved: true}); - // } - // } - // }, - // xHasMoved: function (event) { - // return Math.abs(this.state.downPos.clientX - event.clientX) > this.constants.HOLD_THRESHOLD; - // }, - // yHasMoved: function (event) { - // return Math.abs(this.state.downPos.clientY - event.clientY) > this.constants.HOLD_THRESHOLD; - // }, - // elementHeightMinusBorders: function (element) { - // var rect = element.getBoundingClientRect(); - // var computedStyle; - // - // if (getComputedStyle) { - // computedStyle = getComputedStyle(element); - // } else { - // computedStyle = element.currentStyle; - // } - // - // return rect.height - - // parseInt(computedStyle.getPropertyValue('border-top-width') || computedStyle.borderTopWidth, 10) - - // parseInt(computedStyle.getPropertyValue('border-bottom-width') || computedStyle.borderBottomWidth, 10); - // }, - // elementWidthMinusBorders: function (element) { - // var rect = element.getBoundingClientRect(); - // var computedStyle; - // - // if (getComputedStyle) { - // computedStyle = getComputedStyle(element); - // } else { - // computedStyle = element.currentStyle; - // } - // - // return rect.width - - // parseInt(computedStyle.getPropertyValue('border-left-width') || computedStyle.borderLeftWidth, 10) - - // parseInt(computedStyle.getPropertyValue('border-right-width') || computedStyle.borderRightWidth, 10); - // }, - // setDraggedPosition: function (event) { - // var draggedStyle = { - // position: this.state.draggedStyle.position, - // top: this.state.draggedStyle.top, - // left: this.state.draggedStyle.left, - // width: this.state.draggedStyle.width, - // height: this.state.draggedStyle.height - // }; - // - // if (this.props.lock === 'horizontal') { - // draggedStyle.top = event.clientY - this.state.dragOffset.top; - // draggedStyle.left = this.state.originalPosition.left; - // } else if (this.props.lock === 'vertical') { - // draggedStyle.top = this.state.originalPosition.top; - // draggedStyle.left = event.clientX - this.state.dragOffset.left; - // } else { - // draggedStyle.top = event.clientY - this.state.dragOffset.top; - // draggedStyle.left = event.clientX - this.state.dragOffset.left; - // } - // - // this.setState({draggedStyle: draggedStyle}); - // }, - // - // // Collision methods - // - // nodesToArray: function (nodes) { - // return Array.prototype.slice.call(nodes, 0); - // }, - // xCollision: function (rect, event) { - // return event.clientX >= rect.left && event.clientX <= rect.right; - // }, - // yCollision: function (rect, event) { - // return event.clientY >= rect.top && event.clientY <= rect.bottom; - // }, - // findCollision: function (listElements, event) { - // for (var i = 0; i < listElements.length; i += 1) { - // if (!this.nonCollisionElement.exec(listElements[i].className)) { - // var rect = listElements[i].getBoundingClientRect(); - // - // if (this.props.lock === 'horizontal') { - // if (this.yCollision(rect, event)) { - // return listElements[i]; - // } - // } else if (this.props.lock === 'vertical') { - // if (this.xCollision(rect, event)) { - // return listElements[i]; - // } - // } else if (this.yCollision(rect, event)) { - // if (this.xCollision(rect, event)) { - // return listElements[i]; - // } - // } - // - // } - // } - // - // return undefined; - // }, - // - // // ---- Default methods - // - // componentWillUnmount: function () { - // clearTimeout(this.holdTimeout); - // - // clearInterval(this.scrollIntervalY); - // this.scrollIntervalY = undefined; - // clearInterval(this.scrollIntervalX); - // this.scrollIntervalX = undefined; - // }, - // componentWillReceiveProps: function (props) { - // // Updates list when props changed - // this.setState({ - // list: props.list - // }); - // }, - // getInitialState: function () { - // return { - // list: this.props.list || [] - // }; - // }, + getInitialState: function () { return { draggedIndex: -1, From c32c17671aa05ea97ab47d63fa3e7300d1e95e43 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 17:57:43 +0000 Subject: [PATCH 053/292] Remove commented old render code --- lib/index.js | 47 +---------------------------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/lib/index.js b/lib/index.js index 03808770..d44f3b49 100644 --- a/lib/index.js +++ b/lib/index.js @@ -369,53 +369,8 @@ }, children ); - - // var self = this; - // - // var getPropsTemplate = function (item) { - // if (self.props.template) { - // return React.createElement(self.props.template, { - // item: item, - // sharedProps: self.props.sharedProps - // }); - // } - // return item; - // }; - // - // var list = this.state.list.map(function (item, index) { - // var itemKey = item[self.props.itemKey] || item; - // var itemClass = [self.props.itemClass, self.getPlaceholderClass(item), self.getSelectedClass(item)].join(' '); - // return React.createElement('div', { - // key: itemKey, - // className: itemClass, - // onMouseDown: self.itemDown.bind(self, item, index), - // onTouchStart: self.itemDown.bind(self, item, index), - // }, getPropsTemplate(item)); - // }); - // - // var targetClone = function () { - // if (self.state.held && self.state.dragged) { - // var itemKey = self.state.dragged.item[self.props.itemKey] || self.state.dragged.item; - // var itemClass = [ - // self.props.itemClass, - // self.getDraggedClass(self.state.dragged.item), - // self.getSelectedClass(self.state.dragged.item) - // ].join(' '); - // return React.createElement('div', { - // key: itemKey, - // className: itemClass, - // style: self.getDraggedStyle(self.state.dragged.item) - // }, getPropsTemplate(self.state.dragged.item)); - // } - // return undefined; - // }; - // - // return React.createElement('div', { - // className: this.props.listClass, - // onMouseDown: self.listDown, - // onTouchStart: self.listDown - // }, list, targetClone()); } + }); } From 3d658a796ccca6b084f0184a3dabb8637c7a39ea Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 18:12:00 +0000 Subject: [PATCH 054/292] Update example with retained state --- examples/src/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 963986d2..75f15cf2 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -155,7 +155,7 @@ style={{color: item.color}} > {this.state.prefix} {item.name} - + ); }.bind(this)).toArray() From 6675fc30be8288d9cd9a5a1edbf3e4ace9627ab5 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 18:17:01 +0000 Subject: [PATCH 055/292] Check if hold times are undefined --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index d44f3b49..b5be6322 100644 --- a/lib/index.js +++ b/lib/index.js @@ -120,9 +120,9 @@ }, getHoldTime: function (event) { - if (event.touches && this.props.touchHoldTime || this.props.touchHoldTime === 0) { + if (event.touches && typeof this.props.touchHoldTime !== 'undefined') { return parseInt(this.props.touchHoldTime, 10) || 0; - } else if (this.props.mouseHoldTime || this.props.mouseHoldTime === 0) { + } else if (typeof this.props.mouseHoldTime !== 'undefined') { return parseInt(this.props.mouseHoldTime, 10) || 0; } From 6e85ab3ff1cf2c12c463cdb7df9784fa69b45bf6 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 18:21:42 +0000 Subject: [PATCH 056/292] Style input content --- examples/src/js/index.js | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 75f15cf2..73c91859 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -73,6 +73,17 @@ }, selected: { border: [2, 'solid', 'red'] + }, + contentHolder: { + display: 'table', + width: '100%' + }, + itemName: { + display: 'table-cell' + }, + input: { + display: 'table-cell', + width: '100%' } }); @@ -154,8 +165,12 @@ className={classNames.listItem} style={{color: item.color}} > - {this.state.prefix} {item.name} - +
    + + {this.state.prefix} {item.name} + + +
    ); }.bind(this)).toArray() From cfe10071b26b3249352bbb7dbe7ddaaad3833272 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 19:25:30 +0000 Subject: [PATCH 057/292] Root node ref --- lib/index.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/index.js b/lib/index.js index b5be6322..0c6a66bf 100644 --- a/lib/index.js +++ b/lib/index.js @@ -314,6 +314,14 @@ window.removeEventListener('contextmenu', this.preventDefaultIfDragging); }, + storeRootNode: function (element) { + this.rootNode = element; + + if (typeof this.props.ref === 'function') { + this.props.ref(element); + } + }, + render: function () { var self = this; @@ -360,6 +368,7 @@ id: this.props.id, style: this.props.style, onClick: this.props.onClick, + ref: this.storeRootNode, onMouseDown: this.onListDown.bind(this, this.props.onMouseDown), onTouchStart: this.onListDown.bind(this, this.props.onTouchStart), onMouseMove: this.onListMove.bind(this, this.props.onMouseMove), From 61539ed2575ab97faec4e248adf9433f0d914529 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 19:25:41 +0000 Subject: [PATCH 058/292] Adjust scroll constants --- lib/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index 0c6a66bf..26f1c541 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,8 +5,7 @@ var CONSTANTS = { HOLD_THRESHOLD: 8, SCROLL_RATE: 1000 / 60, - SCROLL_AREA: 50, - SCROLL_MULTIPLIER: 5 + SCROLL_AREA_MAX: 50 }; function extend (obj1, obj2, obj3) { From e497802e047a2c9a80a15f92606e0745252b83dd Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 19:26:14 +0000 Subject: [PATCH 059/292] Do not store mouse coords in state --- lib/index.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/index.js b/lib/index.js index 26f1c541..6e8feb72 100644 --- a/lib/index.js +++ b/lib/index.js @@ -141,12 +141,13 @@ left: rect.left, width: rect.width, height: rect.height - }, - mouseOffset: { - clientX: event.clientX - rect.left, - clientY: event.clientY - rect.top } }); + + this.mouseDownOffset = { + clientX: event.clientX - rect.left, + clientY: event.clientY - rect.top + }; } }, @@ -269,9 +270,9 @@ var draggedStyle = extend({}, this.state.draggedStyle, { top: (!this.props.lock || this.props.lock === 'horizontal') ? - event.clientY - this.state.mouseOffset.clientY : this.state.draggedStyle.top, + event.clientY - this.mouseDownOffset.clientY : this.state.draggedStyle.top, left: (!this.props.lock || this.props.lock === 'vertical') ? - event.clientX - this.state.mouseOffset.clientX : this.state.draggedStyle.left + event.clientX - this.mouseDownOffset.clientX : this.state.draggedStyle.left }); var children = ReactDOM.findDOMNode(this).childNodes; From 23d823a4b0229b5fd7714a7e54146a6df12aa6a3 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 19:26:30 +0000 Subject: [PATCH 060/292] Store mouse offset on down & move --- lib/index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/index.js b/lib/index.js index 6e8feb72..e8e4ed16 100644 --- a/lib/index.js +++ b/lib/index.js @@ -144,6 +144,11 @@ } }); + this.mouseOffset = { + clientX: event.clientX, + clientY: event.clientY + }; + this.mouseDownOffset = { clientX: event.clientX - rect.left, clientY: event.clientY - rect.top @@ -291,6 +296,11 @@ this.setState({ draggedStyle: draggedStyle }); + + this.mouseOffset = { + clientX: event.clientX, + clientY: event.clientY + }; } }, From a235b4e0ba3c760445cd4e7b3dd21ef283e0a6c3 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 19:26:41 +0000 Subject: [PATCH 061/292] Setup auto scroll interval --- lib/index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/index.js b/lib/index.js index e8e4ed16..71301037 100644 --- a/lib/index.js +++ b/lib/index.js @@ -128,8 +128,13 @@ return parseInt(this.props.holdTime, 10) || 0; }, + autoScroll: function () { + + }, + startDrag: function (event, target, index) { if (!this.moved) { + this.scrollInterval = setInterval(this.autoScroll, CONSTANTS.SCROLL_RATE); var rect = target.getBoundingClientRect(); this.setState({ @@ -238,6 +243,7 @@ // Stop dragging - reset style & draggedIndex, handle reorder onWindowUp: function (event) { clearTimeout(this.holdTimeout); + clearInterval(this.scrollInterval); var fromIndex = this.state.draggedIndex; var toIndex = this.state.placedIndex; @@ -316,6 +322,7 @@ // Remove listeners componentWillUnmount: function () { clearTimeout(this.holdTimeout); + clearInterval(this.scrollInterval); window.removeEventListener('mouseup', this.onWindowUp); window.removeEventListener('touchend', this.onWindowUp); From bc5d08153195016807e3da8c61eda3af9010db9b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 19:51:00 +0000 Subject: [PATCH 062/292] Implement auto scrolling --- lib/index.js | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 71301037..b6f5950f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,8 +4,9 @@ var CONSTANTS = { HOLD_THRESHOLD: 8, - SCROLL_RATE: 1000 / 60, - SCROLL_AREA_MAX: 50 + SCROLL_INTERVAL: 1000 / 60, + SCROLL_AREA_MAX: 50, + SCROLL_SPEED: 20 }; function extend (obj1, obj2, obj3) { @@ -129,12 +130,48 @@ }, autoScroll: function () { + var rect = this.rootNode.getBoundingClientRect(); + var scrollTop = this.rootNode.scrollTop; + var scrollLeft = this.rootNode.scrollLeft; + + var scrollHeight = this.rootNode.scrollHeight; + var scrollWidth = this.rootNode.scrollWidth; + + var scrollArea = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); + + if (this.props.lock !== 'horizontal') { + if (this.mouseOffset.clientX <= rect.left + scrollArea) { + var scrollMultiplier = Math.min(Math.abs(rect.left + scrollArea - this.mouseOffset.clientX), scrollArea) / scrollArea; + + this.rootNode.scrollLeft = this.rootNode.scrollLeft - scrollMultiplier * CONSTANTS.SCROLL_SPEED; + } + + if (this.mouseOffset.clientX >= rect.right - scrollArea) { + var scrollMultiplier = Math.min(Math.abs(rect.right - scrollArea - this.mouseOffset.clientX), scrollArea) / scrollArea; + + this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollMultiplier * CONSTANTS.SCROLL_SPEED; + } + } + + if (this.props.lock !== 'vertical') { + if (scrollTop > 0 && this.mouseOffset.clientY <= rect.top + scrollArea) { + var scrollMultiplier = Math.min(Math.abs(rect.top + scrollArea - this.mouseOffset.clientY), scrollArea) / scrollArea; + + this.rootNode.scrollTop = this.rootNode.scrollTop - scrollMultiplier * CONSTANTS.SCROLL_SPEED; + } + + if (scrollTop < scrollHeight - rect.height && this.mouseOffset.clientY >= rect.bottom - scrollArea) { + var scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollArea - this.mouseOffset.clientY), scrollArea) / scrollArea; + + this.rootNode.scrollTop = this.rootNode.scrollTop + scrollMultiplier * CONSTANTS.SCROLL_SPEED; + } + } }, startDrag: function (event, target, index) { if (!this.moved) { - this.scrollInterval = setInterval(this.autoScroll, CONSTANTS.SCROLL_RATE); + this.scrollInterval = setInterval(this.autoScroll, CONSTANTS.SCROLL_INTERVAL); var rect = target.getBoundingClientRect(); this.setState({ From 8789266695809db1e93a9cc72b425a0c9009bf1d Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 20:03:06 +0000 Subject: [PATCH 063/292] Different scroll area for horizontal and vertical dragging --- lib/index.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/index.js b/lib/index.js index b6f5950f..d65128d4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -138,31 +138,32 @@ var scrollHeight = this.rootNode.scrollHeight; var scrollWidth = this.rootNode.scrollWidth; - var scrollArea = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); + var scrollAreaX = Math.min(rect.width / 3, CONSTANTS.SCROLL_AREA_MAX); + var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); if (this.props.lock !== 'horizontal') { - if (this.mouseOffset.clientX <= rect.left + scrollArea) { - var scrollMultiplier = Math.min(Math.abs(rect.left + scrollArea - this.mouseOffset.clientX), scrollArea) / scrollArea; + if (this.mouseOffset.clientX <= rect.left + scrollAreaX) { + var scrollMultiplier = Math.min(Math.abs(rect.left + scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; this.rootNode.scrollLeft = this.rootNode.scrollLeft - scrollMultiplier * CONSTANTS.SCROLL_SPEED; } - if (this.mouseOffset.clientX >= rect.right - scrollArea) { - var scrollMultiplier = Math.min(Math.abs(rect.right - scrollArea - this.mouseOffset.clientX), scrollArea) / scrollArea; + if (this.mouseOffset.clientX >= rect.right - scrollAreaX) { + var scrollMultiplier = Math.min(Math.abs(rect.right - scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollMultiplier * CONSTANTS.SCROLL_SPEED; } } if (this.props.lock !== 'vertical') { - if (scrollTop > 0 && this.mouseOffset.clientY <= rect.top + scrollArea) { - var scrollMultiplier = Math.min(Math.abs(rect.top + scrollArea - this.mouseOffset.clientY), scrollArea) / scrollArea; + if (scrollTop > 0 && this.mouseOffset.clientY <= rect.top + scrollAreaY) { + var scrollMultiplier = Math.min(Math.abs(rect.top + scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / scrollAreaY; this.rootNode.scrollTop = this.rootNode.scrollTop - scrollMultiplier * CONSTANTS.SCROLL_SPEED; } - if (scrollTop < scrollHeight - rect.height && this.mouseOffset.clientY >= rect.bottom - scrollArea) { - var scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollArea - this.mouseOffset.clientY), scrollArea) / scrollArea; + if (scrollTop < scrollHeight - rect.height && this.mouseOffset.clientY >= rect.bottom - scrollAreaY) { + var scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / scrollAreaY; this.rootNode.scrollTop = this.rootNode.scrollTop + scrollMultiplier * CONSTANTS.SCROLL_SPEED; } From 8b95e015ff73cee6506d8741a78e4db20d42fa47 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 20:11:32 +0000 Subject: [PATCH 064/292] Missed horizontal checks --- lib/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/index.js b/lib/index.js index d65128d4..840d2011 100644 --- a/lib/index.js +++ b/lib/index.js @@ -142,14 +142,14 @@ var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); if (this.props.lock !== 'horizontal') { - if (this.mouseOffset.clientX <= rect.left + scrollAreaX) { var scrollMultiplier = Math.min(Math.abs(rect.left + scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; + if (scrollLeft > 0 && this.mouseOffset.clientX <= rect.left + scrollAreaX) { this.rootNode.scrollLeft = this.rootNode.scrollLeft - scrollMultiplier * CONSTANTS.SCROLL_SPEED; } - if (this.mouseOffset.clientX >= rect.right - scrollAreaX) { var scrollMultiplier = Math.min(Math.abs(rect.right - scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; + if (scrollLeft < scrollWidth - rect.width && this.mouseOffset.clientX >= rect.right - scrollAreaX) { this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollMultiplier * CONSTANTS.SCROLL_SPEED; } From 68bcdcf298a67d5053df3bc1ea01757deea7d7ab Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 20:11:47 +0000 Subject: [PATCH 065/292] Fix scrollMultiplier used outside scope --- lib/index.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/index.js b/lib/index.js index 840d2011..7c6021e4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -141,15 +141,17 @@ var scrollAreaX = Math.min(rect.width / 3, CONSTANTS.SCROLL_AREA_MAX); var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); + var scrollMultiplier; + if (this.props.lock !== 'horizontal') { - var scrollMultiplier = Math.min(Math.abs(rect.left + scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; if (scrollLeft > 0 && this.mouseOffset.clientX <= rect.left + scrollAreaX) { + scrollMultiplier = Math.min(Math.abs(rect.left + scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; this.rootNode.scrollLeft = this.rootNode.scrollLeft - scrollMultiplier * CONSTANTS.SCROLL_SPEED; } - var scrollMultiplier = Math.min(Math.abs(rect.right - scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; if (scrollLeft < scrollWidth - rect.width && this.mouseOffset.clientX >= rect.right - scrollAreaX) { + scrollMultiplier = Math.min(Math.abs(rect.right - scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollMultiplier * CONSTANTS.SCROLL_SPEED; } @@ -157,13 +159,13 @@ if (this.props.lock !== 'vertical') { if (scrollTop > 0 && this.mouseOffset.clientY <= rect.top + scrollAreaY) { - var scrollMultiplier = Math.min(Math.abs(rect.top + scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / scrollAreaY; + scrollMultiplier = Math.min(Math.abs(rect.top + scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / scrollAreaY; this.rootNode.scrollTop = this.rootNode.scrollTop - scrollMultiplier * CONSTANTS.SCROLL_SPEED; } if (scrollTop < scrollHeight - rect.height && this.mouseOffset.clientY >= rect.bottom - scrollAreaY) { - var scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / scrollAreaY; + scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / scrollAreaY; this.rootNode.scrollTop = this.rootNode.scrollTop + scrollMultiplier * CONSTANTS.SCROLL_SPEED; } From fb325feb1d4a61f3f265ed6f3bf645a87c8b56c4 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 20:12:26 +0000 Subject: [PATCH 066/292] Fix linting --- lib/index.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/index.js b/lib/index.js index 7c6021e4..88d45c53 100644 --- a/lib/index.js +++ b/lib/index.js @@ -145,13 +145,15 @@ if (this.props.lock !== 'horizontal') { if (scrollLeft > 0 && this.mouseOffset.clientX <= rect.left + scrollAreaX) { - scrollMultiplier = Math.min(Math.abs(rect.left + scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; + scrollMultiplier = Math.min(Math.abs(rect.left + scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / + scrollAreaX; this.rootNode.scrollLeft = this.rootNode.scrollLeft - scrollMultiplier * CONSTANTS.SCROLL_SPEED; } if (scrollLeft < scrollWidth - rect.width && this.mouseOffset.clientX >= rect.right - scrollAreaX) { - scrollMultiplier = Math.min(Math.abs(rect.right - scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / scrollAreaX; + scrollMultiplier = Math.min(Math.abs(rect.right - scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / + scrollAreaX; this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollMultiplier * CONSTANTS.SCROLL_SPEED; } @@ -159,13 +161,15 @@ if (this.props.lock !== 'vertical') { if (scrollTop > 0 && this.mouseOffset.clientY <= rect.top + scrollAreaY) { - scrollMultiplier = Math.min(Math.abs(rect.top + scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / scrollAreaY; + scrollMultiplier = Math.min(Math.abs(rect.top + scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / + scrollAreaY; this.rootNode.scrollTop = this.rootNode.scrollTop - scrollMultiplier * CONSTANTS.SCROLL_SPEED; } if (scrollTop < scrollHeight - rect.height && this.mouseOffset.clientY >= rect.bottom - scrollAreaY) { - scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / scrollAreaY; + scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / + scrollAreaY; this.rootNode.scrollTop = this.rootNode.scrollTop + scrollMultiplier * CONSTANTS.SCROLL_SPEED; } From 070440608fb37a24da57b623a6fe04841360446d Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 20:29:51 +0000 Subject: [PATCH 067/292] Update readme --- README.md | 123 ++++++++++++++---------------------------------------- 1 file changed, 32 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index c8c97712..a7da0fef 100644 --- a/README.md +++ b/README.md @@ -55,92 +55,40 @@ __[Demo](http://jakesidsmith.github.io/react-reorder/)__ 3. Configuration - **Note: If your array is an array of primitives (e.g. strings) then `itemKey` is not required as the string itself will be used as the key, however item keys must be unique in any case** - - 1. Using JSX - - ```javascript - - ``` - - 2. Using standard Javascript - - ```javascript - React.createElement(Reorder, { - // The key of each object in your list to use as the element key - itemKey: 'name', - // Lock horizontal to have a vertical list - lock: 'horizontal', - // The milliseconds to hold an item for before dragging begins - holdTime: '500', - // The list to display - list: [ - {name: 'Item 1'}, - {name: 'Item 2'}, - {name: 'Item 3'} - ], - // A template to display for each list item - template: ListItem, - // Function that is called once a reorder has been performed - callback: this.callback, - // Class to be applied to the outer list element - listClass: 'my-list', - // Class to be applied to each list item's wrapper element - itemClass: 'list-item', - // A function to be called if a list item is clicked (before hold time is up) - itemClicked: this.itemClicked, - // The item to be selected (adds 'selected' class) - selected: this.state.selected, - // The key to compare from the selected item object with each item object - selectedKey: 'uuid', - // Allows reordering to be disabled - disableReorder: false - }) - ``` +```javascript + // Custom placeholder element (optional, defaults to child element) + } +> + { + this.state.list.map(function (item) { + return ( +
  • {item.name}
  • + ); + }).toArray() // Note this example is an ImmutableJS List so we must turn it into an array + } +
    +``` 5. Callback functions - 1. The `callback` function that is called once a reorder has been performed + 1. The `onReorder` function that is called once a reorder has been performed ```javascript - function callback(event, itemThatHasBeenMoved, itemsPreviousIndex, itemsNewIndex, reorderedArray) { - // ... - } - ``` - - 2. The `itemClicked` function that is called when an item is clicked before any dragging begins - - ```javascript - function itemClicked(event, itemThatHasBeenClicked, itemsIndex) { - // ... + function onReorder(event, fromIndex, toIndex) { + // You can use our helper functions for reordering your arrays (reorderImmutable is also available) + this.setState({ + myList: Reorder.reorder(this.state.myList, fromIndex, toIndex); + }); } ``` @@ -148,6 +96,8 @@ __[Demo](http://jakesidsmith.github.io/react-reorder/)__ ## Compatibility / Requirements +* Version `3.x` tested and working with React `0.15` + * Version `2.x` tested and working with React `0.14` * Versions `1.x` tested and working with React `0.12` - `0.13` @@ -160,7 +110,7 @@ __[Demo](http://jakesidsmith.github.io/react-reorder/)__ ### Desktop -* Internet Explorer 9+ (may support IE8**) +* Internet Explorer 9+ (dropped support for IE 8) * Google Chrome (tested in version 39.0.2171.95(64-bit)) @@ -170,17 +120,8 @@ __[Demo](http://jakesidsmith.github.io/react-reorder/)__ * Safari (tested in version 7.1.2 (9537.85.11.5)) -\** Have not had a chance to test in IE8, but IE8 is supported by React - - ### Mobile * Chrome (tested in version 40.0.2214.89) * Safari (tested on iOS 8) - -## Untested Browsers - -* Internet Explorer 8*** (the lowest version that React supports) - -\*** If anyone could confirm that this works in IE8, that'd be awesome From 7182b29ac1011027dfccdbe410cb064d7b557351 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 10 Dec 2016 20:32:31 +0000 Subject: [PATCH 068/292] More readme updates --- README.md | 54 +++++++++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index a7da0fef..0d34a767 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,10 @@ __Drag & drop, touch enabled, reorder / sortable list, React component__ React Reorder is a React component that allows the user to drag-and-drop items in a list (horizontal / vertical) or a grid. -It fully supports touch devices and auto-scrolls when a component is being dragged (check out the demo, link below). +It fully supports touch devices and auto-scrolls when a component is being dragged (check out the [demo](http://jakesidsmith.github.io/react-reorder/)). It also allows the user to set a hold time (duration before drag begins) allowing additional events like clicking / tapping to be applied. -Although this project is very new, it has been thoroughly tested in all modern browsers (see supported browsers). - -__[Demo](http://jakesidsmith.github.io/react-reorder/)__ - ## Installation * Using npm @@ -55,33 +51,33 @@ __[Demo](http://jakesidsmith.github.io/react-reorder/)__ 3. Configuration -```javascript - // Custom placeholder element (optional, defaults to child element) - } -> - { - this.state.list.map(function (item) { - return ( -
  • {item.name}
  • - ); - }).toArray() // Note this example is an ImmutableJS List so we must turn it into an array - } -
    -``` + ```javascript + // Custom placeholder element (optional, defaults to child element) + } + > + { + this.state.list.map(function (item) { + return ( +
  • {item.name}
  • + ); + }).toArray() // Note this example is an ImmutableJS List so we must turn it into an array + } +
    + ``` 5. Callback functions - 1. The `onReorder` function that is called once a reorder has been performed + * The `onReorder` function that is called once a reorder has been performed ```javascript function onReorder(event, fromIndex, toIndex) { From 544a4b286fa6145aa9e89996935b4dcc01478e24 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:35:23 +0000 Subject: [PATCH 069/292] Change to alpha version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d73f58c8..dc2658b7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-reorder", - "version": "3.0.0", + "version": "3.0.0-alpha.0", "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", From 0cc5fee441e2ae1561c247bdd36bcd5a5322cdfd Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:37:39 +0000 Subject: [PATCH 070/292] Update node version --- .nvmrc | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.nvmrc b/.nvmrc index ca063943..dc3829f5 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -6.2.2 +6.9.1 diff --git a/package.json b/package.json index dc2658b7..d0bc9bca 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,6 @@ "watchify": "=3.6.1" }, "engines": { - "node": "6.2.2" + "node": "6.9.1" } } From d00fedb4048ce70a49430c117175215d873913e1 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:39:13 +0000 Subject: [PATCH 071/292] Set npm version --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index d0bc9bca..946538da 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "watchify": "=3.6.1" }, "engines": { - "node": "6.9.1" + "node": "6.9.1", + "npm": "3.10.8" } } From c8a7540e7ee9ffdcfa9f98e597f5ed0e61d9e50b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:39:53 +0000 Subject: [PATCH 072/292] Add test dependencies --- package.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/package.json b/package.json index 946538da..da7fe74c 100644 --- a/package.json +++ b/package.json @@ -37,12 +37,17 @@ "babel-preset-react": "=6.11.1", "babelify": "=7.3.0", "browserify": "=12.0.1", + "chai": "=3.5.0", "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", "immutable": "=3.8.1", + "mocha": "=3.2.0", + "nyc": "=10.0.0", "react": "=15.3.1", "react-dom": "=15.3.1", "react-style-sheets": "=0.1.0", + "sinon": "=1.17.6", + "sinon-chai": "=2.8.0", "watchify": "=3.6.1" }, "engines": { From cc0097abe184b18277fdd72254b31ed786738746 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:42:22 +0000 Subject: [PATCH 073/292] Add babel preset es2015 for example code --- .babelrc | 5 ++++- package.json | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.babelrc b/.babelrc index 12d195e5..bd20dc17 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,6 @@ { - "presets": ["react"] + "presets": [ + "es2015", + "react" + ] } diff --git a/package.json b/package.json index da7fe74c..1771a2e5 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ ], "dependencies": {}, "devDependencies": { + "babel-preset-es2015": "=6.18.0", "babel-preset-react": "=6.11.1", "babelify": "=7.3.0", "browserify": "=12.0.1", From 65522f9f3877f104418cf7b5709d12195a562d74 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:42:46 +0000 Subject: [PATCH 074/292] Update gitignore --- .gitignore | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c5f77b67..669cc36d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ -node_modules/ -examples/build/ +node_modules/** +examples/build/** + +npm-debug.log* .DS_Store From d6d1a47ec9ec0c09fea7031dea5b77625b2af4fc Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:44:13 +0000 Subject: [PATCH 075/292] Update example linting to use es6 --- examples/src/js/index.js | 504 +++++++++++++++++++------------------- examples/src/js/styles.js | 64 +++-- package.json | 2 +- 3 files changed, 279 insertions(+), 291 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 73c91859..4339a106 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -1,255 +1,249 @@ -'use strict'; - -(function () { - - require('./styles'); - var React = require('react'); - var ReactDOM = require('react-dom'); - var ReactStyleSheets = require('react-style-sheets'); - var Immutable = require('immutable'); - var Reorder = require('../../../lib/index'); - - var classNames = ReactStyleSheets.createUniqueClassStyles({ - app: { - position: 'relative', - width: '100%', - maxWidth: 768, - overflow: 'hidden', - margin: 'auto', - padding: 8 - }, - myList: { - float: 'left', - width: '100%', - height: 'auto', - border: [1, 'solid', 'grey'], - padding: 8, - listStyle: 'none' - }, - myList1: { - height: 200, - overflow: 'auto', - paddingBottom: 0 - }, - myList2: { - overflowX: 'auto', - overflowY: 'hidden', - height: 62, - whiteSpace: 'nowrap' - }, - mylist3: {}, - listItem: { - float: 'left', - width: '100%', - height: 46, - padding: 12, - border: [2, 'solid', 'lightblue'], - marginBottom: 8, - transformOrigin: '50% 50%' - }, - listItem2: { - float: 'none', - width: 80, - marginBottom: 0, - whiteSpace: 'nowrap', - overflow: 'hidden', - display: 'inline-block' - }, - listItem3: { - float: 'left', - width: '50%' - }, - placeholder: { - backgroundColor: '#CCC', - border: [1, 'solid', '#CCC'] - }, - customPlaceholder: { - opacity: 0.2 - }, - dragged: { - backgroundColor: '#EEE', - transform: 'scale(0.98, 0.98)', - opacity: 0.8 - }, - selected: { - border: [2, 'solid', 'red'] - }, - contentHolder: { - display: 'table', - width: '100%' - }, - itemName: { - display: 'table-cell' - }, - input: { - display: 'table-cell', - width: '100%' - } - }); - - var Main = React.createClass({ - getInitialState: function () { - return { - list: Immutable.List(Immutable.Range(0, 10).map(function (value) { - return { - name: ['Thing', value].join(' '), - color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') - }; - })), - prefix: 'Prefix' - }; - }, - - onReorder: function (event, previousIndex, nextIndex) { - var list = Immutable.List(Reorder.reorderImmutable(this.state.list, previousIndex, nextIndex)); - - this.setState({ - list: list - }); - }, - - onDisableToggle: function () { - this.setState({ - disableReorder: !this.state.disableReorder - }); - }, - - onPrefixChange: function (event) { - var target = event.currentTarget; - - this.setState({ - prefix: target.value - }); - }, - - // ---- - - render: function () { - return ( -
    -

    - React Reorder -

    -

    - Examples -

    -

    - Lock horizontal -

    -

    - This example has a hold time of 500 milliseconds before dragging begins, - allowing for other events like clicking / tapping to be attached -

    -

    - Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined} -

    -

    - Prefix (shared props): -

    - - } - > - { - this.state.list.map(function (item) { - return ( -
  • -
    - - {this.state.prefix} {item.name} - - -
    -
  • - ); - }.bind(this)).toArray() - } -
    - -

    - Lock vertical -

    -

    - This example has a hold time of 250 milliseconds -

    -

    - {'Reorder disabled: '} - - Last item clicked: {this.state.clickedItem2 ? this.state.clickedItem2.name : undefined} -

    - - - { - this.state.list.map(function (item) { - return ( -
  • - {item.name} -
  • - ); - }.bind(this)).toArray() - } -
    - -

    - No lock (grid) -

    -

    - This example has a hold time of 0 milliseconds -

    - - - { - this.state.list.map(function (item) { - return ( -
  • - {item.name} -
  • - ); - }.bind(this)).toArray() - } -
    -
    - ); - } - }); - - ReactDOM.render(React.createElement(Main), document.getElementById('app')); - -})(); +require('./styles'); +var React = require('react'); +var ReactDOM = require('react-dom'); +var ReactStyleSheets = require('react-style-sheets'); +var Immutable = require('immutable'); +var Reorder = require('../../../lib/index'); + +var classNames = ReactStyleSheets.createUniqueClassStyles({ + app: { + position: 'relative', + width: '100%', + maxWidth: 768, + overflow: 'hidden', + margin: 'auto', + padding: 8 + }, + myList: { + float: 'left', + width: '100%', + height: 'auto', + border: [1, 'solid', 'grey'], + padding: 8, + listStyle: 'none' + }, + myList1: { + height: 200, + overflow: 'auto', + paddingBottom: 0 + }, + myList2: { + overflowX: 'auto', + overflowY: 'hidden', + height: 62, + whiteSpace: 'nowrap' + }, + mylist3: {}, + listItem: { + float: 'left', + width: '100%', + height: 46, + padding: 12, + border: [2, 'solid', 'lightblue'], + marginBottom: 8, + transformOrigin: '50% 50%' + }, + listItem2: { + float: 'none', + width: 80, + marginBottom: 0, + whiteSpace: 'nowrap', + overflow: 'hidden', + display: 'inline-block' + }, + listItem3: { + float: 'left', + width: '50%' + }, + placeholder: { + backgroundColor: '#CCC', + border: [1, 'solid', '#CCC'] + }, + customPlaceholder: { + opacity: 0.2 + }, + dragged: { + backgroundColor: '#EEE', + transform: 'scale(0.98, 0.98)', + opacity: 0.8 + }, + selected: { + border: [2, 'solid', 'red'] + }, + contentHolder: { + display: 'table', + width: '100%' + }, + itemName: { + display: 'table-cell' + }, + input: { + display: 'table-cell', + width: '100%' + } +}); + +var Main = React.createClass({ + getInitialState: function () { + return { + list: Immutable.List(Immutable.Range(0, 10).map(function (value) { + return { + name: ['Thing', value].join(' '), + color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') + }; + })), + prefix: 'Prefix' + }; + }, + + onReorder: function (event, previousIndex, nextIndex) { + var list = Immutable.List(Reorder.reorderImmutable(this.state.list, previousIndex, nextIndex)); + + this.setState({ + list: list + }); + }, + + onDisableToggle: function () { + this.setState({ + disableReorder: !this.state.disableReorder + }); + }, + + onPrefixChange: function (event) { + var target = event.currentTarget; + + this.setState({ + prefix: target.value + }); + }, + + // ---- + + render: function () { + return ( +
    +

    + React Reorder +

    +

    + Examples +

    +

    + Lock horizontal +

    +

    + This example has a hold time of 500 milliseconds before dragging begins, + allowing for other events like clicking / tapping to be attached +

    +

    + Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined} +

    +

    + Prefix (shared props): +

    + + } + > + { + this.state.list.map(function (item) { + return ( +
  • +
    + + {this.state.prefix} {item.name} + + +
    +
  • + ); + }.bind(this)).toArray() + } +
    + +

    + Lock vertical +

    +

    + This example has a hold time of 250 milliseconds +

    +

    + {'Reorder disabled: '} + + Last item clicked: {this.state.clickedItem2 ? this.state.clickedItem2.name : undefined} +

    + + + { + this.state.list.map(function (item) { + return ( +
  • + {item.name} +
  • + ); + }.bind(this)).toArray() + } +
    + +

    + No lock (grid) +

    +

    + This example has a hold time of 0 milliseconds +

    + + + { + this.state.list.map(function (item) { + return ( +
  • + {item.name} +
  • + ); + }.bind(this)).toArray() + } +
    +
    + ); + } +}); + +ReactDOM.render(React.createElement(Main), document.getElementById('app')); diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index b85f3428..c97bbe93 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -1,38 +1,32 @@ -'use strict'; +var ReactStyleSheets = require('react-style-sheets'); -(function () { +ReactStyleSheets.setOptions({ + vendorPrefixes: { + userSelect: ['webkit', 'khtml', 'moz', 'ms', 'o'], + transform: ['webkit', 'moz', 'ms', 'o'], + transition: ['webkit', 'moz', 'ms', 'o'], + transformOrigin: ['webkit', 'moz', 'ms', 'o'] + } +}); - var ReactStyleSheets = require('react-style-sheets'); +var htmlBody = { + padding: 0, + margin: 0, + fontFamily: ['arial', 'helvetica', 'sans-serif'], + fontSize: 14, + color: '#333', + WebkitTouchCallout: 'none', + userSelect: 'none', + WebkitTapHighlightColor: 'transparent' +}; - ReactStyleSheets.setOptions({ - vendorPrefixes: { - userSelect: ['webkit', 'khtml', 'moz', 'ms', 'o'], - transform: ['webkit', 'moz', 'ms', 'o'], - transition: ['webkit', 'moz', 'ms', 'o'], - transformOrigin: ['webkit', 'moz', 'ms', 'o'] - } - }); - - var htmlBody = { - padding: 0, - margin: 0, - fontFamily: ['arial', 'helvetica', 'sans-serif'], - fontSize: 14, - color: '#333', - WebkitTouchCallout: 'none', - userSelect: 'none', - WebkitTapHighlightColor: 'transparent' - }; - - ReactStyleSheets.createGlobalTagStyles({ - '*': { - boxSizing: 'border-box' - }, - html: htmlBody, - body: htmlBody, - p: { - margin: [10, 'auto'] - } - }); - -})(); +ReactStyleSheets.createGlobalTagStyles({ + '*': { + boxSizing: 'border-box' + }, + html: htmlBody, + body: htmlBody, + p: { + margin: [10, 'auto'] + } +}); diff --git a/package.json b/package.json index 1771a2e5..07d69148 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "build": "npm run build-dirs && npm run build-js", "watch": "npm run watch-js", "lint-lib": "eslint -c node_modules/eslintrc/.eslintrc-es5 lib/index.js", - "lint-examples": "eslint -c node_modules/eslintrc/.eslintrc-es5-react examples/src/js/", + "lint-examples": "eslint -c node_modules/eslintrc/.eslintrc-es6-react examples/src/js/", "test": "npm run lint-lib && npm run lint-examples" }, "bugs": "https://github.com/JakeSidSmith/react-reorder/issues", From aec9d6554ce68fa78e7097eab663fea5c4635abc Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:46:18 +0000 Subject: [PATCH 076/292] Make examples more es6y --- examples/src/js/index.js | 20 ++++++++++---------- examples/src/js/styles.js | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 4339a106..687063f0 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -1,11 +1,11 @@ -require('./styles'); -var React = require('react'); -var ReactDOM = require('react-dom'); -var ReactStyleSheets = require('react-style-sheets'); -var Immutable = require('immutable'); -var Reorder = require('../../../lib/index'); +import './styles'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import ReactStyleSheets from 'react-style-sheets'; +import Immutable from 'immutable'; +import Reorder from '../../../lib/index'; -var classNames = ReactStyleSheets.createUniqueClassStyles({ +const classNames = ReactStyleSheets.createUniqueClassStyles({ app: { position: 'relative', width: '100%', @@ -83,7 +83,7 @@ var classNames = ReactStyleSheets.createUniqueClassStyles({ } }); -var Main = React.createClass({ +const Main = React.createClass({ getInitialState: function () { return { list: Immutable.List(Immutable.Range(0, 10).map(function (value) { @@ -97,7 +97,7 @@ var Main = React.createClass({ }, onReorder: function (event, previousIndex, nextIndex) { - var list = Immutable.List(Reorder.reorderImmutable(this.state.list, previousIndex, nextIndex)); + const list = Immutable.List(Reorder.reorderImmutable(this.state.list, previousIndex, nextIndex)); this.setState({ list: list @@ -111,7 +111,7 @@ var Main = React.createClass({ }, onPrefixChange: function (event) { - var target = event.currentTarget; + const target = event.currentTarget; this.setState({ prefix: target.value diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index c97bbe93..da18430a 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -1,4 +1,4 @@ -var ReactStyleSheets = require('react-style-sheets'); +import ReactStyleSheets from 'react-style-sheets'; ReactStyleSheets.setOptions({ vendorPrefixes: { @@ -9,7 +9,7 @@ ReactStyleSheets.setOptions({ } }); -var htmlBody = { +const htmlBody = { padding: 0, margin: 0, fontFamily: ['arial', 'helvetica', 'sans-serif'], From 5d542349985c8d2f49c718d532ba0d24f4183d74 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:49:52 +0000 Subject: [PATCH 077/292] ES6 class in examples --- examples/src/js/index.js | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 687063f0..2a94a2d5 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -1,5 +1,5 @@ import './styles'; -import React from 'react'; +import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import ReactStyleSheets from 'react-style-sheets'; import Immutable from 'immutable'; @@ -83,9 +83,11 @@ const classNames = ReactStyleSheets.createUniqueClassStyles({ } }); -const Main = React.createClass({ - getInitialState: function () { - return { +class Main extends Component { + constructor () { + super(); + + this.state = { list: Immutable.List(Immutable.Range(0, 10).map(function (value) { return { name: ['Thing', value].join(' '), @@ -94,33 +96,33 @@ const Main = React.createClass({ })), prefix: 'Prefix' }; - }, + } - onReorder: function (event, previousIndex, nextIndex) { + onReorder (event, previousIndex, nextIndex) { const list = Immutable.List(Reorder.reorderImmutable(this.state.list, previousIndex, nextIndex)); this.setState({ list: list }); - }, + } - onDisableToggle: function () { + onDisableToggle () { this.setState({ disableReorder: !this.state.disableReorder }); - }, + } - onPrefixChange: function (event) { + onPrefixChange (event) { const target = event.currentTarget; this.setState({ prefix: target.value }); - }, + } // ---- - render: function () { + render () { return (

    @@ -140,7 +142,7 @@ const Main = React.createClass({ Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined}

    - Prefix (shared props): + Prefix (shared props):

    } > { @@ -184,7 +186,7 @@ const Main = React.createClass({ Last item clicked: {this.state.clickedItem2 ? this.state.clickedItem2.name : undefined}

    @@ -196,7 +198,7 @@ const Main = React.createClass({ draggedClassName={classNames.dragged} lock="vertical" holdTime={250} - onReorder={this.onReorder} + onReorder={this.onReorder.bind(this)} disabled={this.state.disableReorder} > { @@ -225,7 +227,7 @@ const Main = React.createClass({ className={[classNames.myList, classNames.myList3].join(' ')} placeholderClassName={classNames.placeholder} draggedClassName={classNames.dragged} - onReorder={this.onReorder} + onReorder={this.onReorder.bind(this)} > { this.state.list.map(function (item) { @@ -244,6 +246,6 @@ const Main = React.createClass({

    ); } -}); +} ReactDOM.render(React.createElement(Main), document.getElementById('app')); From 762ab4cea68a561e0b2da3787125218e304a7581 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:53:43 +0000 Subject: [PATCH 078/292] Update readme --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 0d34a767..2af02cc4 100644 --- a/README.md +++ b/README.md @@ -39,14 +39,12 @@ It also allows the user to set a hold time (duration before drag begins) allowin ```javascript var Reorder = require('react-reorder'); - ``` + var reorder = Reorder.reorder; + var reorderImmutable = Reorder.reorderImmutable; - If using requirejs you'll probably want to wrap your module e.g. + // Or ES6 - ```javascript - define(function (require) { - // Require react-reorder here - }); + import Reorder, { reorder, reorderImmutable } from 'react-reorder'; ``` 3. Configuration @@ -60,7 +58,7 @@ It also allows the user to set a hold time (duration before drag begins) allowin holdTime={500} // Default hold time before dragging begins (mouse & touch) (optional) defaults to 0 touchHoldTime={500} // Hold time before dragging begins on touch devices (optional) defaults to holdTime mouseHoldTime={200} // Hold time before dragging begins with mouse (optional) defaults to holdTime - onReorder={this.onReorder} // Callback when an item is dropped (you will need this to update your state) + onReorder={this.onReorder.bind(this)} // Callback when an item is dropped (you will need this to update your state) placeholder={
    // Custom placeholder element (optional, defaults to child element) } @@ -83,7 +81,7 @@ It also allows the user to set a hold time (duration before drag begins) allowin function onReorder(event, fromIndex, toIndex) { // You can use our helper functions for reordering your arrays (reorderImmutable is also available) this.setState({ - myList: Reorder.reorder(this.state.myList, fromIndex, toIndex); + myList: reorder(this.state.myList, fromIndex, toIndex); }); } ``` From 1f096971aaf838aa7cb2e1b920a0fdf486752abc Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:54:44 +0000 Subject: [PATCH 079/292] Adjust example import --- examples/src/js/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 2a94a2d5..75d05b81 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -3,7 +3,7 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import ReactStyleSheets from 'react-style-sheets'; import Immutable from 'immutable'; -import Reorder from '../../../lib/index'; +import Reorder, { reorderImmutable } from '../../../lib/index'; const classNames = ReactStyleSheets.createUniqueClassStyles({ app: { @@ -99,7 +99,7 @@ class Main extends Component { } onReorder (event, previousIndex, nextIndex) { - const list = Immutable.List(Reorder.reorderImmutable(this.state.list, previousIndex, nextIndex)); + const list = Immutable.List(reorderImmutable(this.state.list, previousIndex, nextIndex)); this.setState({ list: list From 82dbef1a67af228c3e0a3f5038b13c6302b6ddc2 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 16:56:40 +0000 Subject: [PATCH 080/292] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2af02cc4..f8b86682 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ It also allows the user to set a hold time (duration before drag begins) allowin mouseHoldTime={200} // Hold time before dragging begins with mouse (optional) defaults to holdTime onReorder={this.onReorder.bind(this)} // Callback when an item is dropped (you will need this to update your state) placeholder={ -
    // Custom placeholder element (optional, defaults to child element) +
    // Custom placeholder element (optional, defaults to clone of dragged element) } > { From 0c5fef62063dd7d07e24d73f3b3a0b495fa3ab4b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 17:07:31 +0000 Subject: [PATCH 081/292] Fix example linting --- examples/src/js/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 75d05b81..51586214 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -142,7 +142,8 @@ class Main extends Component { Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined}

    - Prefix (shared props): + {'Prefix (shared props): '} +

    Date: Thu, 15 Dec 2016 17:07:46 +0000 Subject: [PATCH 082/292] Rename src folder (from lib) --- {lib => src}/index.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {lib => src}/index.js (100%) diff --git a/lib/index.js b/src/index.js similarity index 100% rename from lib/index.js rename to src/index.js From 1081a303b6e487675d20b992c856f90c0aa7f3df Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 17:12:58 +0000 Subject: [PATCH 083/292] Setup tests --- .gitignore | 2 ++ .nycrc | 27 +++++++++++++++++++++++++++ package.json | 5 ++++- tests/helpers/test-setup.js | 21 +++++++++++++++++++++ tests/index.test.js | 13 +++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 .nycrc create mode 100644 tests/helpers/test-setup.js create mode 100644 tests/index.test.js diff --git a/.gitignore b/.gitignore index 669cc36d..5d0feb77 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ node_modules/** examples/build/** +coverage/** +.nyc_output/** npm-debug.log* .DS_Store diff --git a/.nycrc b/.nycrc new file mode 100644 index 00000000..3b0fbd60 --- /dev/null +++ b/.nycrc @@ -0,0 +1,27 @@ +{ + "lines": 100, + "statements": 100, + "functions": 100, + "branches": 100, + "require": [ + "babel-core/register", + "./tests/helpers/test-setup.js" + ], + "include": [ + "src/**/*.js" + ], + "exclude": [], + "extension": [ + ".js" + ], + "reporter": [ + "lcov", + "text-summary" + ], + "cache": true, + "all": true, + "check-coverage": true, + "sourceMap": true, + "instrument": true, + "report-dir": "./coverage" +} diff --git a/package.json b/package.json index 07d69148..c145fe94 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,9 @@ "watch": "npm run watch-js", "lint-lib": "eslint -c node_modules/eslintrc/.eslintrc-es5 lib/index.js", "lint-examples": "eslint -c node_modules/eslintrc/.eslintrc-es6-react examples/src/js/", - "test": "npm run lint-lib && npm run lint-examples" + "lint-tests": "eslint -c node_modules/eslintrc/.eslintrc-es6-react-mocha tests/", + "mocha": "nyc mocha --bail --recursive 'tests/**/*.test.js'", + "test": "npm run lint-lib && npm run lint-examples && npm run lint-tests && npm run mocha" }, "bugs": "https://github.com/JakeSidSmith/react-reorder/issues", "repository": { @@ -42,6 +44,7 @@ "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", "immutable": "=3.8.1", + "jsdom": "=9.8.3", "mocha": "=3.2.0", "nyc": "=10.0.0", "react": "=15.3.1", diff --git a/tests/helpers/test-setup.js b/tests/helpers/test-setup.js new file mode 100644 index 00000000..c6ad85af --- /dev/null +++ b/tests/helpers/test-setup.js @@ -0,0 +1,21 @@ +import chai from 'chai'; +import sinonChai from 'sinon-chai'; +import jsdom from 'jsdom'; + +// Jsdom document & window +const doc = jsdom.jsdom(''); +const win = doc.defaultView; + +// Add to global +global.document = doc; // eslint-disable-line no-undef +global.window = win; // eslint-disable-line no-undef + +// Add window keys to global window +Object.keys(window).forEach((key) => { + if (!(key in global)) { // eslint-disable-line no-undef + global[key] = window[key]; // eslint-disable-line no-undef + } +}); + +chai.expect(); +chai.use(sinonChai); diff --git a/tests/index.test.js b/tests/index.test.js new file mode 100644 index 00000000..295cddd8 --- /dev/null +++ b/tests/index.test.js @@ -0,0 +1,13 @@ +import { expect } from 'chai'; + +describe('An example test', function () { + + it('should pass', function () { + expect(true).to.be.true; + }); + + it('should fail', function () { + expect(true).not.to.be.true; + }); + +}); From 6b701e13ba24b95a24edf715b42fe31b10df57c5 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 17:21:22 +0000 Subject: [PATCH 084/292] Fix examples --- examples/src/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 51586214..db9d8de1 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -3,7 +3,7 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import ReactStyleSheets from 'react-style-sheets'; import Immutable from 'immutable'; -import Reorder, { reorderImmutable } from '../../../lib/index'; +import Reorder, { reorderImmutable } from '../../../src/index'; const classNames = ReactStyleSheets.createUniqueClassStyles({ app: { From cdbe97e28c3cae4e755f62d22e50c86a8b15481e Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 17:21:30 +0000 Subject: [PATCH 085/292] Remove mention of shared props --- examples/src/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index db9d8de1..2ba17d49 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -142,7 +142,7 @@ class Main extends Component { Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined}

    - {'Prefix (shared props): '} + {'Prefix: '}

    From 92dac8055eada7fe677b64ccae8a4b0b7f40d85a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 20:06:27 +0000 Subject: [PATCH 086/292] Update main in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c145fe94..c5cbbfa1 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", - "main": "lib/index.js", + "main": "src/index.js", "scripts": { "start": "http-server examples/ -c-1 -o", "build-js": "browserify -t babelify examples/src/js/index.js -o examples/build/js/index.js", From ecbc0417388b42ac866e5986e6947bec41032b8b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 20:06:35 +0000 Subject: [PATCH 087/292] Add React peer dependency --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index c5cbbfa1..0e15be76 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,9 @@ "sinon-chai": "=2.8.0", "watchify": "=3.6.1" }, + "peerDependencies": { + "react": ">=0.14" + }, "engines": { "node": "6.9.1", "npm": "3.10.8" From 589f2ff324a810da8d1fd079a1d13d1634af401d Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 20:06:46 +0000 Subject: [PATCH 088/292] Add enzyme dependency --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 0e15be76..decaef2e 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "babelify": "=7.3.0", "browserify": "=12.0.1", "chai": "=3.5.0", + "enzyme": "=2.6.0", "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", "immutable": "=3.8.1", From 819e14a5937019c93e84594962d9b2b8b4767259 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 20:17:27 +0000 Subject: [PATCH 089/292] Update dependencies for enzyme --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index decaef2e..b9d16108 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,9 @@ "jsdom": "=9.8.3", "mocha": "=3.2.0", "nyc": "=10.0.0", - "react": "=15.3.1", - "react-dom": "=15.3.1", + "react": "=15.4.1", + "react-addons-test-utils": "=15.4.1", + "react-dom": "=15.4.1", "react-style-sheets": "=0.1.0", "sinon": "=1.17.6", "sinon-chai": "=2.8.0", From 48a51859ec6e5355e254a6c954126b78909231fa Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 20:36:04 +0000 Subject: [PATCH 090/292] Update readme --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f8b86682..f5fb920b 100644 --- a/README.md +++ b/README.md @@ -51,16 +51,16 @@ It also allows the user to set a hold time (duration before drag begins) allowin ```javascript // Custom placeholder element (optional, defaults to clone of dragged element) +
    // Custom placeholder element (optional), defaults to clone of dragged element } > { From cf4e4bb8a2495306c6b6d1ebe0cdd0a4b8a2a907 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 20:38:42 +0000 Subject: [PATCH 091/292] Add prop types & default props --- src/index.js | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 88d45c53..bc2cf93f 100644 --- a/src/index.js +++ b/src/index.js @@ -37,7 +37,8 @@ } function getReorderComponent (React, ReactDOM) { - return React.createClass({ + + var Reorder = React.createClass({ displayName: 'Reorder', getInitialState: function () { @@ -392,7 +393,7 @@ var draggedStyle = isDragged ? extend({}, child.props.style, self.state.draggedStyle) : child.props.style; var draggedClass = [ child.props.className || '', - (isDragged ? self.props.draggedClassName : '') || '' + (isDragged ? self.props.draggedClassName : '') ].join(' '); return React.cloneElement( @@ -415,7 +416,7 @@ placeholderElement, { key: 'react-reorder-placeholder', - className: [placeholderElement.props.className || '', self.props.placeholderClassName || ''].join(' '), + className: [placeholderElement.props.className || '', self.props.placeholderClassName].join(' '), 'data-placeholder': true } ); @@ -423,7 +424,7 @@ } return React.createElement( - self.props.component || 'div', + self.props.component, { className: this.props.className, id: this.props.id, @@ -443,6 +444,34 @@ }); + var PropTypes = React.PropTypes; + + Reorder.propTypes = { + component: PropTypes.node, + placeholderClassName: PropTypes.string, + draggedClassName: PropTypes.string, + lock: PropTypes.string, + holdTime: PropTypes.number, + touchHoldTime: PropTypes.number, + mouseHoldTime: PropTypes.number, + onReorder: PropTypes.func, + placeholder: PropTypes.element + }; + + Reorder.defaultProps = { + component: 'div', + placeholderClassName: 'placeholder', + draggedClassName: 'dragged', + // lock: direction, + holdTime: 0 + // touchHoldTime: 0, + // mouseHoldTime: 0, + // onReorder: function, + // placeholder: react element + }; + + return Reorder; + } // Export for commonjs / browserify From 90a5fa50166c33135dbc1d5d780e7a390d07fea8 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 21:26:05 +0000 Subject: [PATCH 092/292] First 2 simple tests --- tests/index.test.js | 70 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/tests/index.test.js b/tests/index.test.js index 295cddd8..9fccaa53 100644 --- a/tests/index.test.js +++ b/tests/index.test.js @@ -1,13 +1,73 @@ import { expect } from 'chai'; +import { shallow, mount } from 'enzyme'; +import React from 'react'; +import Reorder from '../src/index'; -describe('An example test', function () { +describe('Reorder', function () { - it('should pass', function () { - expect(true).to.be.true; + const items = [ + { + name: 'Foo', + id: 'foo' + }, + { + name: 'Bar', + id: 'bar' + }, + { + name: 'Fizz', + id: 'fizz' + }, + { + name: 'Buzz', + id: 'buzz' + } + ]; + + it('should render itself & its children', function () { + const wrapper = shallow( + + { + items.map((item) => ( + + {item.name} + + )) + } + + ); + + const children = wrapper.children(); + + expect(wrapper.type()).to.equal('div'); + expect(children.length).to.equal(4); + + children.forEach(function (child) { + expect(child.type()).to.equal('span'); + }); }); - it('should fail', function () { - expect(true).not.to.be.true; + it('shoudl have a name & default props', function () { + const wrapper = mount( + + { + items.map((item) => ( + + {item.name} + + )) + } + + ); + + expect(wrapper.name()).to.equal('Reorder'); + + const props = wrapper.props(); + + expect(props.component).to.equal('div'); + expect(props.placeholderClassName).to.equal('placeholder'); + expect(props.draggedClassName).to.equal('dragged'); + expect(props.holdTime).to.equal(0); }); }); From 7f69c51404308fdd8df8ad3fcf2fbc309b57f383 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 21:26:43 +0000 Subject: [PATCH 093/292] Test name typo --- tests/index.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/index.test.js b/tests/index.test.js index 9fccaa53..74f13b95 100644 --- a/tests/index.test.js +++ b/tests/index.test.js @@ -47,7 +47,7 @@ describe('Reorder', function () { }); }); - it('shoudl have a name & default props', function () { + it('should have a name & default props', function () { const wrapper = mount( { From 9dd31b41d3233997b7b19165086ec57ad50a5240 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 21:29:42 +0000 Subject: [PATCH 094/292] Describe basic rendering --- tests/index.test.js | 76 ++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/tests/index.test.js b/tests/index.test.js index 74f13b95..989882f3 100644 --- a/tests/index.test.js +++ b/tests/index.test.js @@ -24,50 +24,54 @@ describe('Reorder', function () { } ]; - it('should render itself & its children', function () { - const wrapper = shallow( - - { - items.map((item) => ( - - {item.name} - - )) - } - - ); + describe('basic rendering', function () { - const children = wrapper.children(); + it('should render itself & its children', function () { + const wrapper = shallow( + + { + items.map((item) => ( + + {item.name} + + )) + } + + ); - expect(wrapper.type()).to.equal('div'); - expect(children.length).to.equal(4); + const children = wrapper.children(); - children.forEach(function (child) { - expect(child.type()).to.equal('span'); + expect(wrapper.type()).to.equal('div'); + expect(children.length).to.equal(4); + + children.forEach(function (child) { + expect(child.type()).to.equal('span'); + }); }); - }); - it('should have a name & default props', function () { - const wrapper = mount( - - { - items.map((item) => ( - - {item.name} - - )) - } - - ); + it('should have a name & default props', function () { + const wrapper = mount( + + { + items.map((item) => ( + + {item.name} + + )) + } + + ); - expect(wrapper.name()).to.equal('Reorder'); + expect(wrapper.name()).to.equal('Reorder'); - const props = wrapper.props(); + const props = wrapper.props(); + + expect(props.component).to.equal('div'); + expect(props.placeholderClassName).to.equal('placeholder'); + expect(props.draggedClassName).to.equal('dragged'); + expect(props.holdTime).to.equal(0); + }); - expect(props.component).to.equal('div'); - expect(props.placeholderClassName).to.equal('placeholder'); - expect(props.draggedClassName).to.equal('dragged'); - expect(props.holdTime).to.equal(0); }); }); From e5e18f6e7aa7b02f3c77f9e00f5fe2644f84518c Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 21:29:49 +0000 Subject: [PATCH 095/292] Test changing the component --- tests/index.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/index.test.js b/tests/index.test.js index 989882f3..5a2218a6 100644 --- a/tests/index.test.js +++ b/tests/index.test.js @@ -72,6 +72,12 @@ describe('Reorder', function () { expect(props.holdTime).to.equal(0); }); + it('should allow defining the root component', function () { + const wrapper = shallow(); + + expect(wrapper.type()).to.equal('ul'); + }); + }); }); From 5f53f39d85b96f17a48b8ecea1952c22666e1283 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 21:55:25 +0000 Subject: [PATCH 096/292] Allow function as component --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index bc2cf93f..e3ff0a19 100644 --- a/src/index.js +++ b/src/index.js @@ -447,7 +447,7 @@ var PropTypes = React.PropTypes; Reorder.propTypes = { - component: PropTypes.node, + component: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), placeholderClassName: PropTypes.string, draggedClassName: PropTypes.string, lock: PropTypes.string, From 518eef628e157b073d36a5a5e0b3f44e05be8b76 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 21:55:34 +0000 Subject: [PATCH 097/292] Test functional component --- tests/index.test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/index.test.js b/tests/index.test.js index 5a2218a6..b4acb349 100644 --- a/tests/index.test.js +++ b/tests/index.test.js @@ -78,6 +78,16 @@ describe('Reorder', function () { expect(wrapper.type()).to.equal('ul'); }); + it('should allow defining the root component', function () { + function MyComponent () { + return
    ; + } + + const wrapper = shallow(); + + expect(wrapper.name()).to.equal('MyComponent'); + }); + }); }); From 41b9d3b774201ada7fd6344111b6d350bbee21fd Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 22:20:14 +0000 Subject: [PATCH 098/292] Test React class as component --- tests/index.test.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/tests/index.test.js b/tests/index.test.js index b4acb349..b0c2b780 100644 --- a/tests/index.test.js +++ b/tests/index.test.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { shallow, mount } from 'enzyme'; -import React from 'react'; +import React, { Component } from 'react'; import Reorder from '../src/index'; describe('Reorder', function () { @@ -72,13 +72,13 @@ describe('Reorder', function () { expect(props.holdTime).to.equal(0); }); - it('should allow defining the root component', function () { + it('should allow defining the root component (string)', function () { const wrapper = shallow(); expect(wrapper.type()).to.equal('ul'); }); - it('should allow defining the root component', function () { + it('should allow defining the root component (function)', function () { function MyComponent () { return
    ; } @@ -88,6 +88,18 @@ describe('Reorder', function () { expect(wrapper.name()).to.equal('MyComponent'); }); + it('should allow defining the root component (component)', function () { + class MyComponent extends Component { + render () { + return
    ; + } + } + + const wrapper = shallow(); + + expect(wrapper.name()).to.equal('MyComponent'); + }); + }); }); From 6ae3701ccb9b5571e87d7b65ebd0e693fafe9949 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 23:08:40 +0000 Subject: [PATCH 099/292] Rename basic test file --- tests/{index.test.js => basic.test.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{index.test.js => basic.test.js} (100%) diff --git a/tests/index.test.js b/tests/basic.test.js similarity index 100% rename from tests/index.test.js rename to tests/basic.test.js From 34a45af1d15a820babc69942ff82ee4421f80247 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 23:33:19 +0000 Subject: [PATCH 100/292] Istanbul ignore exports --- src/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.js b/src/index.js index e3ff0a19..78b82d3d 100644 --- a/src/index.js +++ b/src/index.js @@ -474,6 +474,8 @@ } + /* istanbul ignore next */ + // Export for commonjs / browserify if (typeof exports === 'object' && typeof module !== 'undefined') { var React = require('react'); From 43dd1e849d9ebc6caca5c821a6fd1fafada2b9bd Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 23:34:25 +0000 Subject: [PATCH 101/292] Add test for ref function --- tests/basic.test.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index b0c2b780..4be304ea 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -1,4 +1,5 @@ import { expect } from 'chai'; +import { spy } from 'sinon'; import { shallow, mount } from 'enzyme'; import React, { Component } from 'react'; import Reorder from '../src/index'; @@ -100,6 +101,14 @@ describe('Reorder', function () { expect(wrapper.name()).to.equal('MyComponent'); }); + it('should call a ref function (if provided) with the root element', function () { + const refSpy = spy(); + + mount(); + + expect(refSpy).to.have.been.called; + }); + }); }); From bc3f218fa5bc1275ecaf737e1191fe0d8245b853 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 15 Dec 2016 23:35:59 +0000 Subject: [PATCH 102/292] Update CircleCI node version --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 3ba2f375..d6d2ba9f 100644 --- a/circle.yml +++ b/circle.yml @@ -1,6 +1,6 @@ machine: node: - version: 6.2.2 + version: 6.9.1 general: branches: From d8eb251261b382a28fbc999c4a391e081f840643 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:06:55 +0000 Subject: [PATCH 103/292] Begin creating custom mount utility --- package.json | 1 + tests/helpers/mount.js | 44 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/helpers/mount.js diff --git a/package.json b/package.json index b9d16108..7ded0177 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", "immutable": "=3.8.1", + "jquery": "=3.1.1", "jsdom": "=9.8.3", "mocha": "=3.2.0", "nyc": "=10.0.0", diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js new file mode 100644 index 00000000..cc1021da --- /dev/null +++ b/tests/helpers/mount.js @@ -0,0 +1,44 @@ +import $ from 'jquery'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import TestUtils from 'react-addons-test-utils'; + +// Override trigger method with one from TestUtils +$.fn.trigger = function (type, data) { + TestUtils.Simulate[type](this[0], data); +}; + +function defineProperty (obj, prop, value) { + Object.defineProperty(obj, prop, {value, enumerable: false}); +} + +export default function mount (component) { + const element = document.createElement('div'); + + let instance = ReactDOM.render(component, element); + let wrapper = $(ReactDOM.findDOMNode(instance)); + + defineProperty(wrapper, 'getInstance', function () { + return instance; + }); + + defineProperty(wrapper, 'setProps', function (props) { + const clone = React.cloneElement(component, props); + + instance = ReactDOM.render(clone, element); + wrapper = $(ReactDOM.findDOMNode(instance)); + + // instance.forceUpdate(); + + return wrapper; + }); + + defineProperty(wrapper, 'setState', function (state) { + instance.setState(state); + + return wrapper; + }); + + return wrapper; + +} From 987a13cd309bfd557a43b9a57c7cd0b29102a66c Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:18:04 +0000 Subject: [PATCH 104/292] Refactor mount util --- tests/helpers/mount.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index cc1021da..c57d6255 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -12,7 +12,7 @@ function defineProperty (obj, prop, value) { Object.defineProperty(obj, prop, {value, enumerable: false}); } -export default function mount (component) { +function internalMount (component) { const element = document.createElement('div'); let instance = ReactDOM.render(component, element); @@ -29,16 +29,15 @@ export default function mount (component) { wrapper = $(ReactDOM.findDOMNode(instance)); // instance.forceUpdate(); - - return wrapper; }); defineProperty(wrapper, 'setState', function (state) { instance.setState(state); - - return wrapper; }); return wrapper; +} +export default function mount (component) { + return internalMount(component); } From 4d88cfc4c0c80afb5128c72767bdd01df0845128 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:25:45 +0000 Subject: [PATCH 105/292] Add tag and forEach methods to mount util --- tests/helpers/mount.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index c57d6255..b646d041 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -8,6 +8,18 @@ $.fn.trigger = function (type, data) { TestUtils.Simulate[type](this[0], data); }; +$.fn.tag = function () { + return (this[0].tagName || '').toLowerCase(); +}; + +$.fn.forEach = function (fn) { + return this.each(function () { + if (typeof fn === 'function') { + fn($(this)); + } + }); +}; + function defineProperty (obj, prop, value) { Object.defineProperty(obj, prop, {value, enumerable: false}); } From 22511297af1ac9986fe69f57ed5e8eac32788f27 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:33:49 +0000 Subject: [PATCH 106/292] Add methods to get name, props & state to mount util --- tests/helpers/mount.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index b646d041..2347ef05 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -34,6 +34,18 @@ function internalMount (component) { return instance; }); + defineProperty(wrapper, 'getName', function () { + return instance.constructor.displayName; + }); + + defineProperty(wrapper, 'getProps', function () { + return instance.props; + }); + + defineProperty(wrapper, 'getState', function () { + return instance.state; + }); + defineProperty(wrapper, 'setProps', function (props) { const clone = React.cloneElement(component, props); From 25ae1ae36d986c60060a0254d9d2161568d22c58 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:37:55 +0000 Subject: [PATCH 107/292] Rename mount util methods --- tests/helpers/mount.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index 2347ef05..0305f88b 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -8,7 +8,7 @@ $.fn.trigger = function (type, data) { TestUtils.Simulate[type](this[0], data); }; -$.fn.tag = function () { +$.fn.tagName = function () { return (this[0].tagName || '').toLowerCase(); }; @@ -30,19 +30,19 @@ function internalMount (component) { let instance = ReactDOM.render(component, element); let wrapper = $(ReactDOM.findDOMNode(instance)); - defineProperty(wrapper, 'getInstance', function () { + defineProperty(wrapper, 'instance', function () { return instance; }); - defineProperty(wrapper, 'getName', function () { + defineProperty(wrapper, 'name', function () { return instance.constructor.displayName; }); - defineProperty(wrapper, 'getProps', function () { + defineProperty(wrapper, 'props', function () { return instance.props; }); - defineProperty(wrapper, 'getState', function () { + defineProperty(wrapper, 'state', function () { return instance.state; }); From c584343dedd7c5facd848b055fd9aa9b0e1be1c7 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:38:59 +0000 Subject: [PATCH 108/292] Remove enzyme dependency --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 7ded0177..ba38ab97 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "babelify": "=7.3.0", "browserify": "=12.0.1", "chai": "=3.5.0", - "enzyme": "=2.6.0", "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", "immutable": "=3.8.1", From 6cb677192c7377e4c88cdbca126c65d49a2e2d3e Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:39:09 +0000 Subject: [PATCH 109/292] Fix tests --- tests/basic.test.js | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index 4be304ea..1159a278 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { spy } from 'sinon'; -import { shallow, mount } from 'enzyme'; +import mount from './helpers/mount'; import React, { Component } from 'react'; import Reorder from '../src/index'; @@ -28,7 +28,7 @@ describe('Reorder', function () { describe('basic rendering', function () { it('should render itself & its children', function () { - const wrapper = shallow( + const wrapper = mount( { items.map((item) => ( @@ -42,11 +42,11 @@ describe('Reorder', function () { const children = wrapper.children(); - expect(wrapper.type()).to.equal('div'); + expect(wrapper.tagName()).to.equal('div'); expect(children.length).to.equal(4); children.forEach(function (child) { - expect(child.type()).to.equal('span'); + expect(child.tagName()).to.equal('span'); }); }); @@ -74,31 +74,33 @@ describe('Reorder', function () { }); it('should allow defining the root component (string)', function () { - const wrapper = shallow(); + const wrapper = mount(); - expect(wrapper.type()).to.equal('ul'); + expect(wrapper.tagName()).to.equal('ul'); }); it('should allow defining the root component (function)', function () { function MyComponent () { - return
    ; + return

    ; } - const wrapper = shallow(); + const wrapper = mount(); - expect(wrapper.name()).to.equal('MyComponent'); + expect(wrapper.name()).to.equal('Reorder'); + expect(wrapper.tagName()).to.equal('h1'); }); it('should allow defining the root component (component)', function () { class MyComponent extends Component { render () { - return
    ; + return

    ; } } - const wrapper = shallow(); + const wrapper = mount(); - expect(wrapper.name()).to.equal('MyComponent'); + expect(wrapper.name()).to.equal('Reorder'); + expect(wrapper.tagName()).to.equal('h2'); }); it('should call a ref function (if provided) with the root element', function () { From 8bab8b27ac81b42b958c8858fe9dcaf6a0008d40 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:40:35 +0000 Subject: [PATCH 110/292] Update mount util setProps & setState methods --- tests/helpers/mount.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index 0305f88b..9c215628 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -47,16 +47,16 @@ function internalMount (component) { }); defineProperty(wrapper, 'setProps', function (props) { - const clone = React.cloneElement(component, props); + $.extend(instance.props, props); + instance.forceUpdate(); - instance = ReactDOM.render(clone, element); - wrapper = $(ReactDOM.findDOMNode(instance)); - - // instance.forceUpdate(); + return wrapper; }); defineProperty(wrapper, 'setState', function (state) { instance.setState(state); + + return wrapper; }); return wrapper; From 6d3b8174c45fbb5003e206c07618bac1b03836af Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:43:10 +0000 Subject: [PATCH 111/292] Custom getRef prop (and update readme) --- README.md | 1 + src/index.js | 4 ++-- tests/basic.test.js | 2 +- tests/helpers/mount.js | 1 - 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f5fb920b..d2f920d4 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ It also allows the user to set a hold time (duration before drag begins) allowin ```javascript ); + mount(); expect(refSpy).to.have.been.called; }); diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index 9c215628..939bfe33 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -1,5 +1,4 @@ import $ from 'jquery'; -import React from 'react'; import ReactDOM from 'react-dom'; import TestUtils from 'react-addons-test-utils'; From a35f9e0d9f4cdd5b6c4bbd56b3148a8ba5c50168 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:47:37 +0000 Subject: [PATCH 112/292] Clone component & re-render to update props --- tests/helpers/mount.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index 939bfe33..64b1b5e9 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -1,4 +1,5 @@ import $ from 'jquery'; +import React from 'react'; import ReactDOM from 'react-dom'; import TestUtils from 'react-addons-test-utils'; @@ -46,8 +47,9 @@ function internalMount (component) { }); defineProperty(wrapper, 'setProps', function (props) { - $.extend(instance.props, props); - instance.forceUpdate(); + const clone = React.cloneElement(component, props); + instance = ReactDOM.render(clone, element); + wrapper = $(ReactDOM.findDOMNode(instance)); return wrapper; }); From 14fcf42bc130b2b0c18ff2648499a7c105a35366 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:47:49 +0000 Subject: [PATCH 113/292] Add unmount method to mount util --- tests/helpers/mount.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index 64b1b5e9..d1bf6585 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -60,6 +60,10 @@ function internalMount (component) { return wrapper; }); + defineProperty(wrapper, 'unmount', function () { + ReactDOM.unmountComponentAtNode(element); + }); + return wrapper; } From ebf6cccf4ae89ae60336a1f45aed28d28312e058 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:55:02 +0000 Subject: [PATCH 114/292] Add test for event listeners --- tests/basic.test.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index c497d87c..41285ba7 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -111,6 +111,27 @@ describe('Reorder', function () { expect(refSpy).to.have.been.called; }); + it('should add and remove event listeners on mount and unmount', function () { + const addEventListenerSpy = spy(window, 'addEventListener'); + const removeEventListenerSpy = spy(window, 'removeEventListener'); + + const wrapper = mount(); + + expect(addEventListenerSpy).to.have.been.called; + expect(removeEventListenerSpy).not.to.have.been.called; + + addEventListenerSpy.reset(); + removeEventListenerSpy.reset(); + + wrapper.unmount(); + + expect(addEventListenerSpy).not.to.have.been.called; + expect(removeEventListenerSpy).to.have.been.called; + + addEventListenerSpy.restore(); + removeEventListenerSpy.restore(); + }); + }); }); From 910c1f3e79df8a9c7d44297243c1976ddc8a3425 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 00:59:20 +0000 Subject: [PATCH 115/292] More thorough event listener tests --- tests/basic.test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index 41285ba7..b848adc8 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -117,6 +117,8 @@ describe('Reorder', function () { const wrapper = mount(); + const eventCount = addEventListenerSpy.callCount; + expect(addEventListenerSpy).to.have.been.called; expect(removeEventListenerSpy).not.to.have.been.called; @@ -128,6 +130,9 @@ describe('Reorder', function () { expect(addEventListenerSpy).not.to.have.been.called; expect(removeEventListenerSpy).to.have.been.called; + expect(removeEventListenerSpy.callCount).to.be.above(0); + expect(removeEventListenerSpy.callCount).to.equal(eventCount); + addEventListenerSpy.restore(); removeEventListenerSpy.restore(); }); From cb8558c0f0543c14d6a2c9521d4e31aec48f1332 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 01:02:30 +0000 Subject: [PATCH 116/292] Even more thorough event listener tests --- tests/basic.test.js | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index b848adc8..f84b2115 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -112,15 +112,26 @@ describe('Reorder', function () { }); it('should add and remove event listeners on mount and unmount', function () { + const events = [ + 'mouseup', + 'touchend', + 'mousemove', + 'touchmove', + 'contextmenu' + ]; + const addEventListenerSpy = spy(window, 'addEventListener'); const removeEventListenerSpy = spy(window, 'removeEventListener'); const wrapper = mount(); - const eventCount = addEventListenerSpy.callCount; - expect(addEventListenerSpy).to.have.been.called; expect(removeEventListenerSpy).not.to.have.been.called; + expect(addEventListenerSpy.callCount).to.equal(events.length); + + events.forEach(function (event) { + expect(addEventListenerSpy).to.have.been.calledWith(event); + }); addEventListenerSpy.reset(); removeEventListenerSpy.reset(); @@ -129,9 +140,11 @@ describe('Reorder', function () { expect(addEventListenerSpy).not.to.have.been.called; expect(removeEventListenerSpy).to.have.been.called; + expect(removeEventListenerSpy.callCount).to.equal(events.length); - expect(removeEventListenerSpy.callCount).to.be.above(0); - expect(removeEventListenerSpy.callCount).to.equal(eventCount); + events.forEach(function (event) { + expect(removeEventListenerSpy).to.have.been.calledWith(event); + }); addEventListenerSpy.restore(); removeEventListenerSpy.restore(); From 78f830cd41383348920b9dc59cb440e4d6f70fb4 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 01:08:47 +0000 Subject: [PATCH 117/292] Test clearing timeouts & intervals on unmount --- tests/basic.test.js | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index f84b2115..28a26549 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -112,6 +112,9 @@ describe('Reorder', function () { }); it('should add and remove event listeners on mount and unmount', function () { + const addEventListenerSpy = spy(window, 'addEventListener'); + const removeEventListenerSpy = spy(window, 'removeEventListener'); + const events = [ 'mouseup', 'touchend', @@ -120,9 +123,6 @@ describe('Reorder', function () { 'contextmenu' ]; - const addEventListenerSpy = spy(window, 'addEventListener'); - const removeEventListenerSpy = spy(window, 'removeEventListener'); - const wrapper = mount(); expect(addEventListenerSpy).to.have.been.called; @@ -150,6 +150,32 @@ describe('Reorder', function () { removeEventListenerSpy.restore(); }); + it('should clear timeouts & intervals on unmount', function () { + const clearTimeoutSpy = spy(global, 'clearTimeout'); + const clearIntervalSpy = spy(global, 'clearInterval'); + + const wrapper = mount(); + const instance = wrapper.instance(); + + instance.holdTimeout = { + foo: 'bar' + }; + instance.scrollInterval = { + bar: 'foo' + }; + + wrapper.unmount(); + + expect(clearTimeoutSpy).to.have.been.called; + expect(clearIntervalSpy).to.have.been.called; + + expect(clearTimeoutSpy).to.have.been.calledWith(instance.holdTimeout); + expect(clearIntervalSpy).to.have.been.calledWith(instance.scrollInterval); + + clearTimeoutSpy.restore(); + clearIntervalSpy.restore(); + }); + }); }); From a0ca7638ad8ad3c06bcf6ce141eb6d832037d5aa Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 01:15:03 +0000 Subject: [PATCH 118/292] Return new mount instance on setProps --- tests/helpers/mount.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index d1bf6585..d9aa4059 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -24,8 +24,8 @@ function defineProperty (obj, prop, value) { Object.defineProperty(obj, prop, {value, enumerable: false}); } -function internalMount (component) { - const element = document.createElement('div'); +function internalMount (component, element) { + element = typeof element !== 'undefined' ? element : document.createElement('div'); let instance = ReactDOM.render(component, element); let wrapper = $(ReactDOM.findDOMNode(instance)); @@ -48,10 +48,8 @@ function internalMount (component) { defineProperty(wrapper, 'setProps', function (props) { const clone = React.cloneElement(component, props); - instance = ReactDOM.render(clone, element); - wrapper = $(ReactDOM.findDOMNode(instance)); - return wrapper; + return internalMount(clone, element); }); defineProperty(wrapper, 'setState', function (state) { From c28be21442900afb6b748b7484ad1182d61d8815 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 01:16:03 +0000 Subject: [PATCH 119/292] Create test file for mount util --- tests/mount.test.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/mount.test.js diff --git a/tests/mount.test.js b/tests/mount.test.js new file mode 100644 index 00000000..70ee9b2e --- /dev/null +++ b/tests/mount.test.js @@ -0,0 +1 @@ +// Test mount util From 1ead6a7b1e8146a5a847ac111a364a31cd0f6115 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 18:51:39 +0000 Subject: [PATCH 120/292] Begin testing mount util --- tests/mount.test.js | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/mount.test.js b/tests/mount.test.js index 70ee9b2e..a180cbb6 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -1 +1,27 @@ -// Test mount util +import { expect } from 'chai'; +import { spy } from 'sinon'; +import mount from './helpers/mount'; +import React, { Component } from 'react'; + +describe('mount', function () { + + // let wrapper; + + class MyComponent extends Component { + render () { + return
    ; + } + } + + const renderSpy = spy(MyComponent.prototype, 'render'); + + it('should render a component', function () { + // wrapper = + mount(); + + expect(renderSpy).to.have.been.called; + + renderSpy.reset(); + }); + +}); From 2843ba3a3b1c0f057398100c5f79f0df15917cf8 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 18:55:17 +0000 Subject: [PATCH 121/292] Test lifecycle methods --- tests/mount.test.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tests/mount.test.js b/tests/mount.test.js index a180cbb6..90b5fa83 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -8,20 +8,38 @@ describe('mount', function () { // let wrapper; class MyComponent extends Component { + componentWillMount () { + + } + + componentDidMount () { + + } + render () { return
    ; } } const renderSpy = spy(MyComponent.prototype, 'render'); + const componentWillMountSpy = spy(MyComponent.prototype, 'componentWillMount'); + const componentDidMountSpy = spy(MyComponent.prototype, 'componentDidMount'); + + it('should render a component & call its lifecycle methods', function () { + expect(renderSpy).not.to.have.been.called; + expect(componentWillMountSpy).not.to.have.been.called; + expect(componentDidMountSpy).not.to.have.been.called; - it('should render a component', function () { // wrapper = mount(); expect(renderSpy).to.have.been.called; + expect(componentWillMountSpy).to.have.been.called; + expect(componentDidMountSpy).to.have.been.called; renderSpy.reset(); + componentWillMountSpy.reset(); + componentDidMountSpy.reset(); }); }); From a825f4ccbf4a8a70f8a01524d38cd238e396f6e6 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 18:57:32 +0000 Subject: [PATCH 122/292] Test unmounting component --- tests/mount.test.js | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/mount.test.js b/tests/mount.test.js index 90b5fa83..d5799d1d 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -5,16 +5,14 @@ import React, { Component } from 'react'; describe('mount', function () { - // let wrapper; + let wrapper; class MyComponent extends Component { - componentWillMount () { + componentWillMount () {} - } - - componentDidMount () { + componentDidMount () {} - } + componentWillUnmount () {} render () { return
    ; @@ -24,14 +22,14 @@ describe('mount', function () { const renderSpy = spy(MyComponent.prototype, 'render'); const componentWillMountSpy = spy(MyComponent.prototype, 'componentWillMount'); const componentDidMountSpy = spy(MyComponent.prototype, 'componentDidMount'); + const componentWillUnmountSpy = spy(MyComponent.prototype, 'componentWillUnmount'); it('should render a component & call its lifecycle methods', function () { expect(renderSpy).not.to.have.been.called; expect(componentWillMountSpy).not.to.have.been.called; expect(componentDidMountSpy).not.to.have.been.called; - // wrapper = - mount(); + wrapper = mount(); expect(renderSpy).to.have.been.called; expect(componentWillMountSpy).to.have.been.called; @@ -42,4 +40,12 @@ describe('mount', function () { componentDidMountSpy.reset(); }); + it('should unmount a component', function () { + expect(componentWillUnmountSpy).not.to.have.been.called; + + wrapper.unmount(); + + expect(componentWillUnmountSpy).to.have.been.called; + }); + }); From e0d6592648283f353c971a74614a98194aaa40eb Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:03:44 +0000 Subject: [PATCH 123/292] Test updating components props --- tests/mount.test.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/mount.test.js b/tests/mount.test.js index d5799d1d..e76d06ce 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -8,6 +8,12 @@ describe('mount', function () { let wrapper; class MyComponent extends Component { + shouldComponentUpdate () { + return true; + } + + componentDidUpdate () {} + componentWillMount () {} componentDidMount () {} @@ -20,6 +26,8 @@ describe('mount', function () { } const renderSpy = spy(MyComponent.prototype, 'render'); + const shouldComponentUpdateSpy = spy(MyComponent.prototype, 'shouldComponentUpdate'); + const componentDidUpdateSpy = spy(MyComponent.prototype, 'componentDidUpdate'); const componentWillMountSpy = spy(MyComponent.prototype, 'componentWillMount'); const componentDidMountSpy = spy(MyComponent.prototype, 'componentDidMount'); const componentWillUnmountSpy = spy(MyComponent.prototype, 'componentWillUnmount'); @@ -40,6 +48,25 @@ describe('mount', function () { componentDidMountSpy.reset(); }); + it('should return and update the component\'s props', function () { + const originalProps = wrapper.props(); + + expect(originalProps).to.eql({}); + expect(shouldComponentUpdateSpy).not.to.have.been.called; + expect(componentDidUpdateSpy).not.to.have.been.called; + + wrapper.setProps({foo: 'bar'}); + + expect(shouldComponentUpdateSpy).to.have.been.called; + expect(componentDidUpdateSpy).to.have.been.called; + + const updatedProps = wrapper.props(); + + expect(updatedProps).to.eql({foo: 'bar'}); + + expect(originalProps).not.to.eql(updatedProps); + }); + it('should unmount a component', function () { expect(componentWillUnmountSpy).not.to.have.been.called; From deac107ff9d13a6dfae88135d5911a4572274167 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:08:52 +0000 Subject: [PATCH 124/292] Reset spies after test --- tests/mount.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/mount.test.js b/tests/mount.test.js index e76d06ce..8020e737 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -65,6 +65,9 @@ describe('mount', function () { expect(updatedProps).to.eql({foo: 'bar'}); expect(originalProps).not.to.eql(updatedProps); + + shouldComponentUpdateSpy.reset(); + componentDidUpdateSpy.reset(); }); it('should unmount a component', function () { From 3ff9b0ff0a78a8c551cbeea1f878d32930b6ae04 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:09:58 +0000 Subject: [PATCH 125/292] Ensure component is not remounted --- tests/mount.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/mount.test.js b/tests/mount.test.js index 8020e737..c194473f 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -55,6 +55,9 @@ describe('mount', function () { expect(shouldComponentUpdateSpy).not.to.have.been.called; expect(componentDidUpdateSpy).not.to.have.been.called; + expect(componentWillMountSpy).not.to.have.been.called; + expect(componentDidMountSpy).not.to.have.been.called; + wrapper.setProps({foo: 'bar'}); expect(shouldComponentUpdateSpy).to.have.been.called; From 59a81a8ebba921c2d70aca5b61812a2bb7f26dd1 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:10:54 +0000 Subject: [PATCH 126/292] Include mount in test coverage --- .nycrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.nycrc b/.nycrc index 3b0fbd60..0eb9fbfe 100644 --- a/.nycrc +++ b/.nycrc @@ -8,7 +8,8 @@ "./tests/helpers/test-setup.js" ], "include": [ - "src/**/*.js" + "src/**/*.js", + "tests/helpers/mount.js" ], "exclude": [], "extension": [ From bfee84bfecf9f9592a6d37d8458b8baa8d2a1d1d Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:16:22 +0000 Subject: [PATCH 127/292] Update test component --- tests/mount.test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/mount.test.js b/tests/mount.test.js index c194473f..7249b4db 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -21,7 +21,12 @@ describe('mount', function () { componentWillUnmount () {} render () { - return
    ; + return ( +
    + Foo + Bar +
    + ); } } From 697588af4a56b10550639f0cf2a0ac6e22d244d8 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:16:28 +0000 Subject: [PATCH 128/292] Test tag name --- tests/mount.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/mount.test.js b/tests/mount.test.js index 7249b4db..15440d0f 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -53,6 +53,10 @@ describe('mount', function () { componentDidMountSpy.reset(); }); + it('should return the components tag name', function () { + expect(wrapper.tagName()).to.equal('div'); + }); + it('should return and update the component\'s props', function () { const originalProps = wrapper.props(); From 2222a32e561667d3245ff33408e2888fd6ec5ea6 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:16:41 +0000 Subject: [PATCH 129/292] Test children and forEach --- tests/helpers/mount.js | 4 ++-- tests/mount.test.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index d9aa4059..7c12b386 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -13,9 +13,9 @@ $.fn.tagName = function () { }; $.fn.forEach = function (fn) { - return this.each(function () { + return this.each(function (index) { if (typeof fn === 'function') { - fn($(this)); + fn($(this), index); } }); }; diff --git a/tests/mount.test.js b/tests/mount.test.js index 15440d0f..b86cc4ee 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -57,6 +57,19 @@ describe('mount', function () { expect(wrapper.tagName()).to.equal('div'); }); + it('should return the components children & loop over a jquery collection', function () { + let childCount = 0; + const childText = ['Foo', 'Bar']; + const children = wrapper.children(); + + children.forEach(function (child, index) { + childCount += 1; + expect(child.text()).to.equal(childText[index]); + }); + + expect(childCount).to.equal(2); + }); + it('should return and update the component\'s props', function () { const originalProps = wrapper.props(); From f670af1a95889902f471469eeecc618de7d19267 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:18:07 +0000 Subject: [PATCH 130/292] Update tagName jquery plugin --- tests/helpers/mount.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index 7c12b386..e8be7c56 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -9,7 +9,7 @@ $.fn.trigger = function (type, data) { }; $.fn.tagName = function () { - return (this[0].tagName || '').toLowerCase(); + return this[0].tagName.toLowerCase(); }; $.fn.forEach = function (fn) { From c1ee53369e09d090e2a59cee4e1f9e40b80db007 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:22:10 +0000 Subject: [PATCH 131/292] Test getting components name --- tests/helpers/mount.js | 2 +- tests/mount.test.js | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index e8be7c56..c35ce0c2 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -35,7 +35,7 @@ function internalMount (component, element) { }); defineProperty(wrapper, 'name', function () { - return instance.constructor.displayName; + return instance.constructor.displayName || instance.displayName; }); defineProperty(wrapper, 'props', function () { diff --git a/tests/mount.test.js b/tests/mount.test.js index b86cc4ee..9c322195 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -8,6 +8,12 @@ describe('mount', function () { let wrapper; class MyComponent extends Component { + constructor () { + super(); + + this.displayName = 'MyComponent'; + } + shouldComponentUpdate () { return true; } @@ -53,7 +59,8 @@ describe('mount', function () { componentDidMountSpy.reset(); }); - it('should return the components tag name', function () { + it('should return the components name & tag name', function () { + expect(wrapper.name()).to.equal('MyComponent'); expect(wrapper.tagName()).to.equal('div'); }); From d623e9bfd3abe7d026a4f0c72fdbf6c6c0a7400d Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:24:46 +0000 Subject: [PATCH 132/292] Further test component name --- tests/mount.test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/mount.test.js b/tests/mount.test.js index 9c322195..d03eab93 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -36,6 +36,12 @@ describe('mount', function () { } } + const AnotherComponent = React.createClass({ + render: function () { + return
    ; + } + }); + const renderSpy = spy(MyComponent.prototype, 'render'); const shouldComponentUpdateSpy = spy(MyComponent.prototype, 'shouldComponentUpdate'); const componentDidUpdateSpy = spy(MyComponent.prototype, 'componentDidUpdate'); @@ -62,6 +68,10 @@ describe('mount', function () { it('should return the components name & tag name', function () { expect(wrapper.name()).to.equal('MyComponent'); expect(wrapper.tagName()).to.equal('div'); + + const anotherComponent = mount(); + + expect(anotherComponent.name()).to.equal('AnotherComponent'); }); it('should return the components children & loop over a jquery collection', function () { From 16641ca1e81fd0a91683d238d22285c645232efe Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:29:08 +0000 Subject: [PATCH 133/292] Test getting and setting component state --- tests/mount.test.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/mount.test.js b/tests/mount.test.js index d03eab93..92292503 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -12,6 +12,9 @@ describe('mount', function () { super(); this.displayName = 'MyComponent'; + this.state = { + foo: 'bar' + }; } shouldComponentUpdate () { @@ -112,6 +115,31 @@ describe('mount', function () { componentDidUpdateSpy.reset(); }); + it('should return and update the component\'s state', function () { + const originalState = wrapper.state(); + + expect(originalState).to.eql({foo: 'bar'}); + expect(shouldComponentUpdateSpy).not.to.have.been.called; + expect(componentDidUpdateSpy).not.to.have.been.called; + + expect(componentWillMountSpy).not.to.have.been.called; + expect(componentDidMountSpy).not.to.have.been.called; + + wrapper.setState({foo: 'foo', bar: 'foo'}); + + expect(shouldComponentUpdateSpy).to.have.been.called; + expect(componentDidUpdateSpy).to.have.been.called; + + const updatedState = wrapper.state(); + + expect(updatedState).to.eql({foo: 'foo', bar: 'foo'}); + + expect(originalState).not.to.eql(updatedState); + + shouldComponentUpdateSpy.reset(); + componentDidUpdateSpy.reset(); + }); + it('should unmount a component', function () { expect(componentWillUnmountSpy).not.to.have.been.called; From cf15d06a8fa0b499095708410876e629ad626e91 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:34:52 +0000 Subject: [PATCH 134/292] Test triggering events --- tests/mount.test.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/mount.test.js b/tests/mount.test.js index 92292503..1022ea43 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -29,9 +29,13 @@ describe('mount', function () { componentWillUnmount () {} + onClick (event) { + expect(event.foo).to.equal('bar'); + } + render () { return ( -
    +
    Foo Bar
    @@ -51,6 +55,7 @@ describe('mount', function () { const componentWillMountSpy = spy(MyComponent.prototype, 'componentWillMount'); const componentDidMountSpy = spy(MyComponent.prototype, 'componentDidMount'); const componentWillUnmountSpy = spy(MyComponent.prototype, 'componentWillUnmount'); + const onClickSpy = spy(MyComponent.prototype, 'onClick'); it('should render a component & call its lifecycle methods', function () { expect(renderSpy).not.to.have.been.called; @@ -140,6 +145,13 @@ describe('mount', function () { componentDidUpdateSpy.reset(); }); + it('should trigger event listeners', function () { + const event = {foo: 'bar'}; + wrapper.trigger('click', event); + + expect(onClickSpy).to.have.been.called; + }); + it('should unmount a component', function () { expect(componentWillUnmountSpy).not.to.have.been.called; From 66c201bc9dde90a2fcbb67965affe1f08e9f03bd Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:36:52 +0000 Subject: [PATCH 135/292] Do not return wrappers from set props / state --- tests/helpers/mount.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index c35ce0c2..85856b3a 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -49,13 +49,11 @@ function internalMount (component, element) { defineProperty(wrapper, 'setProps', function (props) { const clone = React.cloneElement(component, props); - return internalMount(clone, element); + internalMount(clone, element); }); defineProperty(wrapper, 'setState', function (state) { instance.setState(state); - - return wrapper; }); defineProperty(wrapper, 'unmount', function () { From 0d723317b8db158b90b4c08725d8b21c91de44ea Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 16 Dec 2016 19:37:57 +0000 Subject: [PATCH 136/292] Test forEach without callback --- tests/mount.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/mount.test.js b/tests/mount.test.js index 1022ea43..4dd1f285 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -87,6 +87,8 @@ describe('mount', function () { const childText = ['Foo', 'Bar']; const children = wrapper.children(); + children.forEach(); + children.forEach(function (child, index) { childCount += 1; expect(child.text()).to.equal(childText[index]); From a9b3a10f254b1a75dcb9d60b5598b34d9ec7db81 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 15:46:19 +0000 Subject: [PATCH 137/292] Use lodash assign instead of custom extend --- package.json | 5 ++++- src/index.js | 27 ++++++++------------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index ba38ab97..2496f78e 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,9 @@ "mobile", "touch" ], - "dependencies": {}, + "dependencies": { + "lodash.assign": "*" + }, "devDependencies": { "babel-preset-es2015": "=6.18.0", "babel-preset-react": "=6.11.1", @@ -46,6 +48,7 @@ "immutable": "=3.8.1", "jquery": "=3.1.1", "jsdom": "=9.8.3", + "lodash.assign": "=4.2.0", "mocha": "=3.2.0", "nyc": "=10.0.0", "react": "=15.4.1", diff --git a/src/index.js b/src/index.js index 2f664383..65405e3e 100644 --- a/src/index.js +++ b/src/index.js @@ -9,18 +9,6 @@ SCROLL_SPEED: 20 }; - function extend (obj1, obj2, obj3) { - for (var key2 in obj2) { - obj1[key2] = obj2[key2]; - } - - for (var key3 in obj3) { - obj1[key3] = obj3[key3]; - } - - return obj1; - } - function reorder (list, previousIndex, nextIndex) { list = [].concat(list); return list.splice(nextIndex, 0, list.splice(previousIndex, 1)[0]); @@ -36,7 +24,7 @@ return Reorder; } - function getReorderComponent (React, ReactDOM) { + function getReorderComponent (React, ReactDOM, assign) { var Reorder = React.createClass({ displayName: 'Reorder', @@ -324,7 +312,7 @@ if (this.isDragging()) { this.preventNativeScrolling(event); - var draggedStyle = extend({}, this.state.draggedStyle, { + var draggedStyle = assign({}, this.state.draggedStyle, { top: (!this.props.lock || this.props.lock === 'horizontal') ? event.clientY - this.mouseDownOffset.clientY : this.state.draggedStyle.top, left: (!this.props.lock || this.props.lock === 'vertical') ? @@ -390,7 +378,7 @@ var children = this.props.children && this.props.children.map(function (child, index) { var isDragged = index === self.state.draggedIndex; - var draggedStyle = isDragged ? extend({}, child.props.style, self.state.draggedStyle) : child.props.style; + var draggedStyle = isDragged ? assign({}, child.props.style, self.state.draggedStyle) : child.props.style; var draggedClass = [ child.props.className || '', (isDragged ? self.props.draggedClassName : '') @@ -480,11 +468,12 @@ if (typeof exports === 'object' && typeof module !== 'undefined') { var React = require('react'); var ReactDOM = require('react-dom'); - module.exports = withReorderMethods(getReorderComponent(React, ReactDOM)); + var assign = require('lodash.assign'); + module.exports = withReorderMethods(getReorderComponent(React, ReactDOM, assign)); // Export for amd / require } else if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef - define(['react', 'react-dom'], function (ReactAMD, ReactDOMAMD) { // eslint-disable-line no-undef - return withReorderMethods(getReorderComponent(ReactAMD, ReactDOMAMD)); + define(['react', 'react-dom', 'lodash.assign'], function (ReactAMD, ReactDOMAMD, assignAMD) { // eslint-disable-line no-undef + return withReorderMethods(getReorderComponent(ReactAMD, ReactDOMAMD, assignAMD)); }); // Export globally } else { @@ -500,7 +489,7 @@ root = this; } - root.Reorder = withReorderMethods(getReorderComponent(root.React, root.ReactDOM)); + root.Reorder = withReorderMethods(getReorderComponent(root.React, root.ReactDOM, root.assign)); } })(); From 5ffca321ec64e8521f660ce90078353ba69ef6fa Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 15:47:08 +0000 Subject: [PATCH 138/292] No restriction on React version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2496f78e..106bca83 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "watchify": "=3.6.1" }, "peerDependencies": { - "react": ">=0.14" + "react": "*" }, "engines": { "node": "6.9.1", From dd5c761512070e3a34c3166746bfa796ac3dab9b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 15:52:46 +0000 Subject: [PATCH 139/292] Test module exports --- tests/basic.test.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index 28a26549..a7c98ff5 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { spy } from 'sinon'; import mount from './helpers/mount'; import React, { Component } from 'react'; -import Reorder from '../src/index'; +import Reorder, { reorder, reorderImmutable } from '../src/index'; describe('Reorder', function () { @@ -25,6 +25,22 @@ describe('Reorder', function () { } ]; + describe('exports', function () { + + it('should provide a react component and some helpful functions', function () { + expect(typeof Reorder).to.equal('function'); + expect(typeof reorder).to.equal('function'); + expect(typeof reorderImmutable).to.equal('function'); + + const requiredReorder = require('../src/index'); + + expect(typeof requiredReorder).to.equal('function'); + expect(typeof requiredReorder.reorder).to.equal('function'); + expect(typeof requiredReorder.reorderImmutable).to.equal('function'); + }); + + }); + describe('basic rendering', function () { it('should render itself & its children', function () { From b9af2ceeb1ce29155f07c49ffe7d91453099d11a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 15:56:12 +0000 Subject: [PATCH 140/292] Break up basic tests --- tests/basic.test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index a7c98ff5..21312aef 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -89,6 +89,10 @@ describe('Reorder', function () { expect(props.holdTime).to.equal(0); }); + }); + + describe('props', function () { + it('should allow defining the root component (string)', function () { const wrapper = mount(); @@ -127,6 +131,10 @@ describe('Reorder', function () { expect(refSpy).to.have.been.called; }); + }); + + describe('mounting & unmounting', function () { + it('should add and remove event listeners on mount and unmount', function () { const addEventListenerSpy = spy(window, 'addEventListener'); const removeEventListenerSpy = spy(window, 'removeEventListener'); From e5c4bb96f782f0bc5702865285a916eeb1c3d3eb Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 18:01:59 +0000 Subject: [PATCH 141/292] Test reorder function and small refactor --- src/index.js | 8 ++++++-- tests/basic.test.js | 13 +++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 65405e3e..6a4e5f8b 100644 --- a/src/index.js +++ b/src/index.js @@ -10,8 +10,12 @@ }; function reorder (list, previousIndex, nextIndex) { - list = [].concat(list); - return list.splice(nextIndex, 0, list.splice(previousIndex, 1)[0]); + const copy = [].concat(list); + const removed = copy.splice(previousIndex, 1)[0]; + + copy.splice(nextIndex, 0, removed); + + return copy; } function reorderImmutable (list, previousIndex, nextIndex) { diff --git a/tests/basic.test.js b/tests/basic.test.js index 21312aef..dde7eda7 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -202,4 +202,17 @@ describe('Reorder', function () { }); + describe('helper functions', function () { + + it('should reorder an array', function () { + const arr = [1, 2, 3, 4, 5]; + + const reordered = reorder(arr, 1, 3); + + expect(reordered).not.to.equal(arr); + expect(reordered).to.eql([1, 3, 4, 2, 5]); + }); + + }); + }); From 356800e543eaef0cff9cab6446d7f979b53c6a55 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 18:05:11 +0000 Subject: [PATCH 142/292] Test reorderImmutable and small refactor --- src/index.js | 3 ++- tests/basic.test.js | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 6a4e5f8b..e18a8f51 100644 --- a/src/index.js +++ b/src/index.js @@ -19,7 +19,8 @@ } function reorderImmutable (list, previousIndex, nextIndex) { - return list.delete(previousIndex).splice(nextIndex, 0, list.get(previousIndex)); + const removed = list.get(previousIndex); + return list.delete(previousIndex).splice(nextIndex, 0, removed); } function withReorderMethods (Reorder) { diff --git a/tests/basic.test.js b/tests/basic.test.js index dde7eda7..8b4eb0e0 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -1,7 +1,9 @@ import { expect } from 'chai'; import { spy } from 'sinon'; import mount from './helpers/mount'; + import React, { Component } from 'react'; +import { List } from 'immutable'; import Reorder, { reorder, reorderImmutable } from '../src/index'; describe('Reorder', function () { @@ -213,6 +215,15 @@ describe('Reorder', function () { expect(reordered).to.eql([1, 3, 4, 2, 5]); }); + it('should reorder an immutable list', function () { + const list = List([1, 2, 3, 4, 5]); + + const reordered = reorderImmutable(list, 4, 0); + + expect(reordered).not.to.equal(list); + expect(reordered.toJS()).to.eql([5, 1, 2, 3, 4]); + }); + }); }); From 51eb982f020b56344e0d6c7ae2c949f60ac7f358 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 20:09:06 +0000 Subject: [PATCH 143/292] Always prevent default for context menus --- src/index.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index e18a8f51..7d18a015 100644 --- a/src/index.js +++ b/src/index.js @@ -49,12 +49,6 @@ event.preventDefault(); }, - preventDefaultIfDragging: function (event) { - if (this.isDragging()) { - event.preventDefault(); - } - }, - preventNativeScrolling: function (event) { event.preventDefault(); }, @@ -354,7 +348,7 @@ window.addEventListener('touchend', this.onWindowUp); window.addEventListener('mousemove', this.onWindowMove); window.addEventListener('touchmove', this.onWindowMove); - window.addEventListener('contextmenu', this.preventDefaultIfDragging); + window.addEventListener('contextmenu', this.preventDefault); }, // Remove listeners @@ -366,7 +360,7 @@ window.removeEventListener('touchend', this.onWindowUp); window.removeEventListener('mousemove', this.onWindowMove); window.removeEventListener('touchmove', this.onWindowMove); - window.removeEventListener('contextmenu', this.preventDefaultIfDragging); + window.removeEventListener('contextmenu', this.preventDefault); }, storeRootNode: function (element) { From 775f4eb48135c9e4025ad7fab38260d8e2985873 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 20:17:39 +0000 Subject: [PATCH 144/292] Test isDragging --- tests/basic.test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index 8b4eb0e0..57e65a57 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -204,6 +204,25 @@ describe('Reorder', function () { }); + describe('methods', function () { + + it('should return true if the draggedIndex is greater than or equal to zero', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + expect(instance.isDragging()).to.be.false; + + wrapper.setState({draggedIndex: 0}); + + expect(instance.isDragging()).to.be.true; + + wrapper.setState({draggedIndex: 10}); + + expect(instance.isDragging()).to.be.true; + }); + + }); + describe('helper functions', function () { it('should reorder an array', function () { From 2405370e81408afddc5fefe04f3e75056b658c31 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 20:19:17 +0000 Subject: [PATCH 145/292] Test preventDefault --- tests/basic.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index 57e65a57..a35db9f3 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -221,6 +221,21 @@ describe('Reorder', function () { expect(instance.isDragging()).to.be.true; }); + it('should preventDefault on events', function () { + const event = { + preventDefault: spy() + }; + + const wrapper = mount(); + const instance = wrapper.instance(); + + expect(event.preventDefault).not.to.have.been.called; + + instance.preventDefault(event); + + expect(event.preventDefault).to.have.been.called; + }); + }); describe('helper functions', function () { From d2bf86fd742ccd9ee010b3ea59525e505ffa92b1 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 20:21:09 +0000 Subject: [PATCH 146/292] Test preventNativeScrolling --- tests/basic.test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index a35db9f3..b71d7895 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -230,9 +230,13 @@ describe('Reorder', function () { const instance = wrapper.instance(); expect(event.preventDefault).not.to.have.been.called; - instance.preventDefault(event); + expect(event.preventDefault).to.have.been.called; + event.preventDefault.reset(); + + expect(event.preventDefault).not.to.have.been.called; + instance.preventNativeScrolling(event); expect(event.preventDefault).to.have.been.called; }); From 35656943590eb5a1b0f9492aa19389a78a027417 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 20:23:18 +0000 Subject: [PATCH 147/292] Test persistEvent --- tests/basic.test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index b71d7895..0a93aad7 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -240,6 +240,21 @@ describe('Reorder', function () { expect(event.preventDefault).to.have.been.called; }); + it('should persist an event if available', function () { + const event = {}; + + const wrapper = mount(); + const instance = wrapper.instance(); + + instance.persistEvent(event); + + event.persist = spy(); + + instance.persistEvent(event); + + expect(event.persist).to.have.been.calledOnce; + }); + }); describe('helper functions', function () { From 902ba96d99d02e185ff5ffa5a274c45138ac46a0 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 20:27:40 +0000 Subject: [PATCH 148/292] Test copyTouchKeys --- tests/basic.test.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index 0a93aad7..27beae09 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -250,11 +250,36 @@ describe('Reorder', function () { event.persist = spy(); + expect(event.persist).not.to.have.been.called; + instance.persistEvent(event); expect(event.persist).to.have.been.calledOnce; }); + it('should copy clientX and clientY from touches & persist event', function () { + const event = { + touches: [ + { + clientX: 123, + clientY: 456 + } + ], + persist: spy() + }; + + const wrapper = mount(); + const instance = wrapper.instance(); + + expect(event.persist).not.to.have.been.called; + + instance.copyTouchKeys(event); + + expect(event.persist).to.have.been.calledOnce; + expect(event.clientX).to.equal(123); + expect(event.clientY).to.equal(456); + }); + }); describe('helper functions', function () { From 7cef3020fe17a9a37341aa4eb16c1a76c1eec264 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sat, 17 Dec 2016 20:29:34 +0000 Subject: [PATCH 149/292] More specific call tests --- tests/basic.test.js | 10 +++++----- tests/mount.test.js | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index 27beae09..1b957f83 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -130,7 +130,7 @@ describe('Reorder', function () { mount(); - expect(refSpy).to.have.been.called; + expect(refSpy).to.have.been.calledOnce; }); }); @@ -192,8 +192,8 @@ describe('Reorder', function () { wrapper.unmount(); - expect(clearTimeoutSpy).to.have.been.called; - expect(clearIntervalSpy).to.have.been.called; + expect(clearTimeoutSpy).to.have.been.calledOnce; + expect(clearIntervalSpy).to.have.been.calledOnce; expect(clearTimeoutSpy).to.have.been.calledWith(instance.holdTimeout); expect(clearIntervalSpy).to.have.been.calledWith(instance.scrollInterval); @@ -231,13 +231,13 @@ describe('Reorder', function () { expect(event.preventDefault).not.to.have.been.called; instance.preventDefault(event); - expect(event.preventDefault).to.have.been.called; + expect(event.preventDefault).to.have.been.calledOnce; event.preventDefault.reset(); expect(event.preventDefault).not.to.have.been.called; instance.preventNativeScrolling(event); - expect(event.preventDefault).to.have.been.called; + expect(event.preventDefault).to.have.been.calledOnce; }); it('should persist an event if available', function () { diff --git a/tests/mount.test.js b/tests/mount.test.js index 4dd1f285..7b0435c0 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -64,9 +64,9 @@ describe('mount', function () { wrapper = mount(); - expect(renderSpy).to.have.been.called; - expect(componentWillMountSpy).to.have.been.called; - expect(componentDidMountSpy).to.have.been.called; + expect(renderSpy).to.have.been.calledOnce; + expect(componentWillMountSpy).to.have.been.calledOnce; + expect(componentDidMountSpy).to.have.been.calledOnce; renderSpy.reset(); componentWillMountSpy.reset(); @@ -109,8 +109,8 @@ describe('mount', function () { wrapper.setProps({foo: 'bar'}); - expect(shouldComponentUpdateSpy).to.have.been.called; - expect(componentDidUpdateSpy).to.have.been.called; + expect(shouldComponentUpdateSpy).to.have.been.calledOnce; + expect(componentDidUpdateSpy).to.have.been.calledOnce; const updatedProps = wrapper.props(); @@ -134,8 +134,8 @@ describe('mount', function () { wrapper.setState({foo: 'foo', bar: 'foo'}); - expect(shouldComponentUpdateSpy).to.have.been.called; - expect(componentDidUpdateSpy).to.have.been.called; + expect(shouldComponentUpdateSpy).to.have.been.calledOnce; + expect(componentDidUpdateSpy).to.have.been.calledOnce; const updatedState = wrapper.state(); @@ -151,7 +151,7 @@ describe('mount', function () { const event = {foo: 'bar'}; wrapper.trigger('click', event); - expect(onClickSpy).to.have.been.called; + expect(onClickSpy).to.have.been.calledOnce; }); it('should unmount a component', function () { @@ -159,7 +159,7 @@ describe('mount', function () { wrapper.unmount(); - expect(componentWillUnmountSpy).to.have.been.called; + expect(componentWillUnmountSpy).to.have.been.calledOnce; }); }); From 2c63b7e753ff82bf7c05e35ae9a3a8b11ecd4f12 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 00:25:42 +0000 Subject: [PATCH 150/292] Test copyTouchKeys with no touches --- tests/basic.test.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index 1b957f83..0e249ea9 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -259,12 +259,6 @@ describe('Reorder', function () { it('should copy clientX and clientY from touches & persist event', function () { const event = { - touches: [ - { - clientX: 123, - clientY: 456 - } - ], persist: spy() }; @@ -275,6 +269,20 @@ describe('Reorder', function () { instance.copyTouchKeys(event); + expect(event.clientX).not.to.be.ok; + expect(event.clientY).not.to.be.ok; + + expect(event.persist).not.to.have.been.called; + + event.touches = [ + { + clientX: 123, + clientY: 456 + } + ]; + + instance.copyTouchKeys(event); + expect(event.persist).to.have.been.calledOnce; expect(event.clientX).to.equal(123); expect(event.clientY).to.equal(456); From e42edbde76c6fb45d3ad3794cb5ac1f38d032b0b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 15:46:01 +0000 Subject: [PATCH 151/292] Move expect --- tests/basic.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index 0e249ea9..a0ff2527 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -269,11 +269,10 @@ describe('Reorder', function () { instance.copyTouchKeys(event); + expect(event.persist).not.to.have.been.called; expect(event.clientX).not.to.be.ok; expect(event.clientY).not.to.be.ok; - expect(event.persist).not.to.have.been.called; - event.touches = [ { clientX: 123, From 6db85ad49167c472447235b04c4b7aa277427231 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 15:50:51 +0000 Subject: [PATCH 152/292] Tests for collision x and y --- tests/basic.test.js | 56 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index a0ff2527..8162badc 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -287,6 +287,62 @@ describe('Reorder', function () { expect(event.clientY).to.equal(456); }); + it('should check a collision on the x-axis', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + const rect = { + left: 50, + right: 100 + }; + + const event = { + clientX: 20 + }; + + expect(instance.xCollision(rect, event)).to.be.false; + + event.clientX = 120; + + expect(instance.xCollision(rect, event)).to.be.false; + + event.clientX = 80; + + expect(instance.xCollision(rect, event)).to.be.true; + + event.clientX = 100; + + expect(instance.xCollision(rect, event)).to.be.true; + }); + + it('should check a collision on the y-axis', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + const rect = { + top: 20, + bottom: 80 + }; + + const event = { + clientY: 10 + }; + + expect(instance.yCollision(rect, event)).to.be.false; + + event.clientY = 100; + + expect(instance.yCollision(rect, event)).to.be.false; + + event.clientY = 50; + + expect(instance.yCollision(rect, event)).to.be.true; + + event.clientY = 80; + + expect(instance.yCollision(rect, event)).to.be.true; + }); + }); describe('helper functions', function () { From ba1a775aa95c39a4b0e8938ecac3e3a62a236689 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 16:03:52 +0000 Subject: [PATCH 153/292] Create mock children --- tests/basic.test.js | 63 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index 8162badc..4bdae2ee 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -343,6 +343,69 @@ describe('Reorder', function () { expect(instance.yCollision(rect, event)).to.be.true; }); + const children = []; // [item, placeholder, dragged, item, item] + + it('should create some mock children', function () { + const itemSize = { + width: 100, + height: 20, + left: 10, + top: 20 + }; + + for (var i = 0; i < 5; i += 1) { + const index = i; + + children.push({ + getAttribute: function (attr) { + if (attr === 'data-placeholder' && index === 1) { + return true; + } + + if (attr === 'data-dragged' && index === 2) { + return true; + } + + return false; + }, + getBoundingClientRect: function () { + return { + top: itemSize.top + (itemSize.height * index), + bottom: itemSize.top + (itemSize.height * index) + itemSize.height, + left: itemSize.left, + right: itemSize.left + itemSize.width, + width: itemSize.width, + height: itemSize.height + }; + } + }); + } + + expect(children.length).to.equal(5); + expect(children[0].getAttribute('data-placeholder')).to.be.false; + expect(children[1].getAttribute('data-placeholder')).to.be.true; + expect(children[1].getAttribute('data-dragged')).to.be.false; + expect(children[2].getAttribute('data-dragged')).to.be.true; + + expect(children[0].getBoundingClientRect()).to.eql({ + top: 20, + left: 10, + bottom: 40, + right: 110, + width: 100, + height: 20 + }); + + expect(children[3].getBoundingClientRect()).to.eql({ + top: 20 + 20 * 3, + left: 10, + bottom: 40 + 20 * 3, + right: 110, + width: 100, + height: 20 + }); + }); + }); describe('helper functions', function () { From 4079ad56aa28cdbb73c44fd30890058954e954df Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 16:05:33 +0000 Subject: [PATCH 154/292] Move mock children into own describe --- tests/basic.test.js | 130 +++++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 63 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index 4bdae2ee..aedf0b56 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -204,6 +204,73 @@ describe('Reorder', function () { }); + const children = []; // [item, placeholder, dragged, item, item] + + describe('mock children', function () { + + it('should create some mock children', function () { + const itemSize = { + width: 100, + height: 20, + left: 10, + top: 20 + }; + + for (var i = 0; i < 5; i += 1) { + const index = i; + + children.push({ + getAttribute: function (attr) { + if (attr === 'data-placeholder' && index === 1) { + return true; + } + + if (attr === 'data-dragged' && index === 2) { + return true; + } + + return false; + }, + getBoundingClientRect: function () { + return { + top: itemSize.top + (itemSize.height * index), + bottom: itemSize.top + (itemSize.height * index) + itemSize.height, + left: itemSize.left, + right: itemSize.left + itemSize.width, + width: itemSize.width, + height: itemSize.height + }; + } + }); + } + + expect(children.length).to.equal(5); + expect(children[0].getAttribute('data-placeholder')).to.be.false; + expect(children[1].getAttribute('data-placeholder')).to.be.true; + expect(children[1].getAttribute('data-dragged')).to.be.false; + expect(children[2].getAttribute('data-dragged')).to.be.true; + + expect(children[0].getBoundingClientRect()).to.eql({ + top: 20, + left: 10, + bottom: 40, + right: 110, + width: 100, + height: 20 + }); + + expect(children[3].getBoundingClientRect()).to.eql({ + top: 20 + 20 * 3, + left: 10, + bottom: 40 + 20 * 3, + right: 110, + width: 100, + height: 20 + }); + }); + + }); + describe('methods', function () { it('should return true if the draggedIndex is greater than or equal to zero', function () { @@ -343,69 +410,6 @@ describe('Reorder', function () { expect(instance.yCollision(rect, event)).to.be.true; }); - const children = []; // [item, placeholder, dragged, item, item] - - it('should create some mock children', function () { - const itemSize = { - width: 100, - height: 20, - left: 10, - top: 20 - }; - - for (var i = 0; i < 5; i += 1) { - const index = i; - - children.push({ - getAttribute: function (attr) { - if (attr === 'data-placeholder' && index === 1) { - return true; - } - - if (attr === 'data-dragged' && index === 2) { - return true; - } - - return false; - }, - getBoundingClientRect: function () { - return { - top: itemSize.top + (itemSize.height * index), - bottom: itemSize.top + (itemSize.height * index) + itemSize.height, - left: itemSize.left, - right: itemSize.left + itemSize.width, - width: itemSize.width, - height: itemSize.height - }; - } - }); - } - - expect(children.length).to.equal(5); - expect(children[0].getAttribute('data-placeholder')).to.be.false; - expect(children[1].getAttribute('data-placeholder')).to.be.true; - expect(children[1].getAttribute('data-dragged')).to.be.false; - expect(children[2].getAttribute('data-dragged')).to.be.true; - - expect(children[0].getBoundingClientRect()).to.eql({ - top: 20, - left: 10, - bottom: 40, - right: 110, - width: 100, - height: 20 - }); - - expect(children[3].getBoundingClientRect()).to.eql({ - top: 20 + 20 * 3, - left: 10, - bottom: 40 + 20 * 3, - right: 110, - width: 100, - height: 20 - }); - }); - }); describe('helper functions', function () { From bfdfa3860f637e34acd6b197145e3bf313dafbb3 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 16:09:49 +0000 Subject: [PATCH 155/292] Test findCollisionIndex with no lock --- tests/basic.test.js | 47 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index aedf0b56..f6d75fe5 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -410,6 +410,53 @@ describe('Reorder', function () { expect(instance.yCollision(rect, event)).to.be.true; }); + it('should find the first collision of the pointer & Reorder children (no lock)', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + const event = { + clientX: 0, + clientY: 0 + }; + + expect(instance.findCollisionIndex(children, event)).to.equal(-1); + + event.clientX = 30; + + expect(instance.findCollisionIndex(children, event)).to.equal(-1); + + event.clientY = 30; + + expect(instance.findCollisionIndex(children, event)).to.equal(0); + + event.clientY = 50; + + expect(instance.findCollisionIndex(children, event)).to.equal(-1); + + event.clientY = 70; + + expect(instance.findCollisionIndex(children, event)).to.equal(-1); + + event.clientY = 90; + + expect(instance.findCollisionIndex(children, event)).to.equal(3); + + event.clientX = 200; + event.clientY = 110; + + expect(instance.findCollisionIndex(children, event)).to.equal(-1); + + event.clientX = 50; + event.clientY = 110; + + expect(instance.findCollisionIndex(children, event)).to.equal(4); + + event.clientX = 50; + event.clientY = 130; + + expect(instance.findCollisionIndex(children, event)).to.equal(-1); + }); + }); describe('helper functions', function () { From 00087cbd8c9e9473fb3d67fb350dd5e214cb3670 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 16:14:50 +0000 Subject: [PATCH 156/292] Test storing reference to root node --- tests/basic.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/basic.test.js b/tests/basic.test.js index f6d75fe5..654b108b 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -91,6 +91,13 @@ describe('Reorder', function () { expect(props.holdTime).to.equal(0); }); + it('should store a reference to its root node', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + expect(instance.rootNode).to.be.ok; + }); + }); describe('props', function () { From 1f4759c667367416762c410a67ca29b43e09af7f Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 16:24:37 +0000 Subject: [PATCH 157/292] Move methods & children stub into own files --- .nycrc | 3 +- tests/basic.test.js | 257 +-------------------------------- tests/children-stub.test.js | 32 ++++ tests/helpers/children-stub.js | 36 +++++ tests/methods.test.js | 195 +++++++++++++++++++++++++ 5 files changed, 266 insertions(+), 257 deletions(-) create mode 100644 tests/children-stub.test.js create mode 100644 tests/helpers/children-stub.js create mode 100644 tests/methods.test.js diff --git a/.nycrc b/.nycrc index 0eb9fbfe..f8b6f612 100644 --- a/.nycrc +++ b/.nycrc @@ -9,7 +9,8 @@ ], "include": [ "src/**/*.js", - "tests/helpers/mount.js" + "tests/helpers/mount.js", + "tests/helpers/children-stub.js" ], "exclude": [], "extension": [ diff --git a/tests/basic.test.js b/tests/basic.test.js index 654b108b..51c305fe 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -6,7 +6,7 @@ import React, { Component } from 'react'; import { List } from 'immutable'; import Reorder, { reorder, reorderImmutable } from '../src/index'; -describe('Reorder', function () { +describe('basic', function () { const items = [ { @@ -211,261 +211,6 @@ describe('Reorder', function () { }); - const children = []; // [item, placeholder, dragged, item, item] - - describe('mock children', function () { - - it('should create some mock children', function () { - const itemSize = { - width: 100, - height: 20, - left: 10, - top: 20 - }; - - for (var i = 0; i < 5; i += 1) { - const index = i; - - children.push({ - getAttribute: function (attr) { - if (attr === 'data-placeholder' && index === 1) { - return true; - } - - if (attr === 'data-dragged' && index === 2) { - return true; - } - - return false; - }, - getBoundingClientRect: function () { - return { - top: itemSize.top + (itemSize.height * index), - bottom: itemSize.top + (itemSize.height * index) + itemSize.height, - left: itemSize.left, - right: itemSize.left + itemSize.width, - width: itemSize.width, - height: itemSize.height - }; - } - }); - } - - expect(children.length).to.equal(5); - expect(children[0].getAttribute('data-placeholder')).to.be.false; - expect(children[1].getAttribute('data-placeholder')).to.be.true; - expect(children[1].getAttribute('data-dragged')).to.be.false; - expect(children[2].getAttribute('data-dragged')).to.be.true; - - expect(children[0].getBoundingClientRect()).to.eql({ - top: 20, - left: 10, - bottom: 40, - right: 110, - width: 100, - height: 20 - }); - - expect(children[3].getBoundingClientRect()).to.eql({ - top: 20 + 20 * 3, - left: 10, - bottom: 40 + 20 * 3, - right: 110, - width: 100, - height: 20 - }); - }); - - }); - - describe('methods', function () { - - it('should return true if the draggedIndex is greater than or equal to zero', function () { - const wrapper = mount(); - const instance = wrapper.instance(); - - expect(instance.isDragging()).to.be.false; - - wrapper.setState({draggedIndex: 0}); - - expect(instance.isDragging()).to.be.true; - - wrapper.setState({draggedIndex: 10}); - - expect(instance.isDragging()).to.be.true; - }); - - it('should preventDefault on events', function () { - const event = { - preventDefault: spy() - }; - - const wrapper = mount(); - const instance = wrapper.instance(); - - expect(event.preventDefault).not.to.have.been.called; - instance.preventDefault(event); - expect(event.preventDefault).to.have.been.calledOnce; - - event.preventDefault.reset(); - - expect(event.preventDefault).not.to.have.been.called; - instance.preventNativeScrolling(event); - expect(event.preventDefault).to.have.been.calledOnce; - }); - - it('should persist an event if available', function () { - const event = {}; - - const wrapper = mount(); - const instance = wrapper.instance(); - - instance.persistEvent(event); - - event.persist = spy(); - - expect(event.persist).not.to.have.been.called; - - instance.persistEvent(event); - - expect(event.persist).to.have.been.calledOnce; - }); - - it('should copy clientX and clientY from touches & persist event', function () { - const event = { - persist: spy() - }; - - const wrapper = mount(); - const instance = wrapper.instance(); - - expect(event.persist).not.to.have.been.called; - - instance.copyTouchKeys(event); - - expect(event.persist).not.to.have.been.called; - expect(event.clientX).not.to.be.ok; - expect(event.clientY).not.to.be.ok; - - event.touches = [ - { - clientX: 123, - clientY: 456 - } - ]; - - instance.copyTouchKeys(event); - - expect(event.persist).to.have.been.calledOnce; - expect(event.clientX).to.equal(123); - expect(event.clientY).to.equal(456); - }); - - it('should check a collision on the x-axis', function () { - const wrapper = mount(); - const instance = wrapper.instance(); - - const rect = { - left: 50, - right: 100 - }; - - const event = { - clientX: 20 - }; - - expect(instance.xCollision(rect, event)).to.be.false; - - event.clientX = 120; - - expect(instance.xCollision(rect, event)).to.be.false; - - event.clientX = 80; - - expect(instance.xCollision(rect, event)).to.be.true; - - event.clientX = 100; - - expect(instance.xCollision(rect, event)).to.be.true; - }); - - it('should check a collision on the y-axis', function () { - const wrapper = mount(); - const instance = wrapper.instance(); - - const rect = { - top: 20, - bottom: 80 - }; - - const event = { - clientY: 10 - }; - - expect(instance.yCollision(rect, event)).to.be.false; - - event.clientY = 100; - - expect(instance.yCollision(rect, event)).to.be.false; - - event.clientY = 50; - - expect(instance.yCollision(rect, event)).to.be.true; - - event.clientY = 80; - - expect(instance.yCollision(rect, event)).to.be.true; - }); - - it('should find the first collision of the pointer & Reorder children (no lock)', function () { - const wrapper = mount(); - const instance = wrapper.instance(); - - const event = { - clientX: 0, - clientY: 0 - }; - - expect(instance.findCollisionIndex(children, event)).to.equal(-1); - - event.clientX = 30; - - expect(instance.findCollisionIndex(children, event)).to.equal(-1); - - event.clientY = 30; - - expect(instance.findCollisionIndex(children, event)).to.equal(0); - - event.clientY = 50; - - expect(instance.findCollisionIndex(children, event)).to.equal(-1); - - event.clientY = 70; - - expect(instance.findCollisionIndex(children, event)).to.equal(-1); - - event.clientY = 90; - - expect(instance.findCollisionIndex(children, event)).to.equal(3); - - event.clientX = 200; - event.clientY = 110; - - expect(instance.findCollisionIndex(children, event)).to.equal(-1); - - event.clientX = 50; - event.clientY = 110; - - expect(instance.findCollisionIndex(children, event)).to.equal(4); - - event.clientX = 50; - event.clientY = 130; - - expect(instance.findCollisionIndex(children, event)).to.equal(-1); - }); - - }); - describe('helper functions', function () { it('should reorder an array', function () { diff --git a/tests/children-stub.test.js b/tests/children-stub.test.js new file mode 100644 index 00000000..bd13c6b7 --- /dev/null +++ b/tests/children-stub.test.js @@ -0,0 +1,32 @@ +import { expect } from 'chai'; +import { verticalChildren } from './helpers/children-stub'; + +describe('children stub', function () { + + it('should create some mock children', function () { + expect(verticalChildren.length).to.equal(5); + expect(verticalChildren[0].getAttribute('data-placeholder')).to.be.false; + expect(verticalChildren[1].getAttribute('data-placeholder')).to.be.true; + expect(verticalChildren[1].getAttribute('data-dragged')).to.be.false; + expect(verticalChildren[2].getAttribute('data-dragged')).to.be.true; + + expect(verticalChildren[0].getBoundingClientRect()).to.eql({ + top: 20, + left: 10, + bottom: 40, + right: 110, + width: 100, + height: 20 + }); + + expect(verticalChildren[3].getBoundingClientRect()).to.eql({ + top: 20 + 20 * 3, + left: 10, + bottom: 40 + 20 * 3, + right: 110, + width: 100, + height: 20 + }); + }); + +}); diff --git a/tests/helpers/children-stub.js b/tests/helpers/children-stub.js new file mode 100644 index 00000000..e5692a7d --- /dev/null +++ b/tests/helpers/children-stub.js @@ -0,0 +1,36 @@ +export const verticalChildren = []; // [item, placeholder, dragged, item, item] + +const itemSize = { + width: 100, + height: 20, + left: 10, + top: 20 +}; + +for (var i = 0; i < 5; i += 1) { + const index = i; + + verticalChildren.push({ + getAttribute: function (attr) { + if (attr === 'data-placeholder' && index === 1) { + return true; + } + + if (attr === 'data-dragged' && index === 2) { + return true; + } + + return false; + }, + getBoundingClientRect: function () { + return { + top: itemSize.top + (itemSize.height * index), + bottom: itemSize.top + (itemSize.height * index) + itemSize.height, + left: itemSize.left, + right: itemSize.left + itemSize.width, + width: itemSize.width, + height: itemSize.height + }; + } + }); +} diff --git a/tests/methods.test.js b/tests/methods.test.js new file mode 100644 index 00000000..b6552f15 --- /dev/null +++ b/tests/methods.test.js @@ -0,0 +1,195 @@ +import { expect } from 'chai'; +import { spy } from 'sinon'; +import mount from './helpers/mount'; + +import React from 'react'; +import Reorder from '../src/index'; +import { verticalChildren } from './helpers/children-stub'; + +describe('methods', function () { + + it('should return true if the draggedIndex is greater than or equal to zero', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + expect(instance.isDragging()).to.be.false; + + wrapper.setState({draggedIndex: 0}); + + expect(instance.isDragging()).to.be.true; + + wrapper.setState({draggedIndex: 10}); + + expect(instance.isDragging()).to.be.true; + }); + + it('should preventDefault on events', function () { + const event = { + preventDefault: spy() + }; + + const wrapper = mount(); + const instance = wrapper.instance(); + + expect(event.preventDefault).not.to.have.been.called; + instance.preventDefault(event); + expect(event.preventDefault).to.have.been.calledOnce; + + event.preventDefault.reset(); + + expect(event.preventDefault).not.to.have.been.called; + instance.preventNativeScrolling(event); + expect(event.preventDefault).to.have.been.calledOnce; + }); + + it('should persist an event if available', function () { + const event = {}; + + const wrapper = mount(); + const instance = wrapper.instance(); + + instance.persistEvent(event); + + event.persist = spy(); + + expect(event.persist).not.to.have.been.called; + + instance.persistEvent(event); + + expect(event.persist).to.have.been.calledOnce; + }); + + it('should copy clientX and clientY from touches & persist event', function () { + const event = { + persist: spy() + }; + + const wrapper = mount(); + const instance = wrapper.instance(); + + expect(event.persist).not.to.have.been.called; + + instance.copyTouchKeys(event); + + expect(event.persist).not.to.have.been.called; + expect(event.clientX).not.to.be.ok; + expect(event.clientY).not.to.be.ok; + + event.touches = [ + { + clientX: 123, + clientY: 456 + } + ]; + + instance.copyTouchKeys(event); + + expect(event.persist).to.have.been.calledOnce; + expect(event.clientX).to.equal(123); + expect(event.clientY).to.equal(456); + }); + + it('should check a collision on the x-axis', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + const rect = { + left: 50, + right: 100 + }; + + const event = { + clientX: 20 + }; + + expect(instance.xCollision(rect, event)).to.be.false; + + event.clientX = 120; + + expect(instance.xCollision(rect, event)).to.be.false; + + event.clientX = 80; + + expect(instance.xCollision(rect, event)).to.be.true; + + event.clientX = 100; + + expect(instance.xCollision(rect, event)).to.be.true; + }); + + it('should check a collision on the y-axis', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + const rect = { + top: 20, + bottom: 80 + }; + + const event = { + clientY: 10 + }; + + expect(instance.yCollision(rect, event)).to.be.false; + + event.clientY = 100; + + expect(instance.yCollision(rect, event)).to.be.false; + + event.clientY = 50; + + expect(instance.yCollision(rect, event)).to.be.true; + + event.clientY = 80; + + expect(instance.yCollision(rect, event)).to.be.true; + }); + + it('should find the first collision of the pointer & Reorder children (no lock)', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + const event = { + clientX: 0, + clientY: 0 + }; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + event.clientX = 30; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + event.clientY = 30; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(0); + + event.clientY = 50; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + event.clientY = 70; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + event.clientY = 90; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(3); + + event.clientX = 200; + event.clientY = 110; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + event.clientX = 50; + event.clientY = 110; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(4); + + event.clientX = 50; + event.clientY = 130; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + }); + +}); From ccb9d6bc3f350789da169328875e732b27201929 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 16:29:42 +0000 Subject: [PATCH 158/292] Create horizontal children stub --- tests/helpers/children-stub.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/helpers/children-stub.js b/tests/helpers/children-stub.js index e5692a7d..32545047 100644 --- a/tests/helpers/children-stub.js +++ b/tests/helpers/children-stub.js @@ -1,4 +1,7 @@ -export const verticalChildren = []; // [item, placeholder, dragged, item, item] +// [item, placeholder, dragged, item, item] + +export const verticalChildren = []; +export const horizontalChildren = []; const itemSize = { width: 100, @@ -33,4 +36,28 @@ for (var i = 0; i < 5; i += 1) { }; } }); + + horizontalChildren.push({ + getAttribute: function (attr) { + if (attr === 'data-placeholder' && index === 1) { + return true; + } + + if (attr === 'data-dragged' && index === 2) { + return true; + } + + return false; + }, + getBoundingClientRect: function () { + return { + top: itemSize.top, + bottom: itemSize.top, + left: itemSize.left + (itemSize.width * index), + right: itemSize.left + (itemSize.width * index) + itemSize.width, + width: itemSize.width, + height: itemSize.height + }; + } + }); } From 8e53c0edee6b17b3c54de4106ffc7a106e629a92 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 16:32:31 +0000 Subject: [PATCH 159/292] Test (& fix) horizontal children stub --- tests/children-stub.test.js | 30 ++++++++++++++++++++++++++++-- tests/helpers/children-stub.js | 2 +- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/tests/children-stub.test.js b/tests/children-stub.test.js index bd13c6b7..6e343b9e 100644 --- a/tests/children-stub.test.js +++ b/tests/children-stub.test.js @@ -1,9 +1,9 @@ import { expect } from 'chai'; -import { verticalChildren } from './helpers/children-stub'; +import { verticalChildren, horizontalChildren } from './helpers/children-stub'; describe('children stub', function () { - it('should create some mock children', function () { + it('should create some stub children (vertical)', function () { expect(verticalChildren.length).to.equal(5); expect(verticalChildren[0].getAttribute('data-placeholder')).to.be.false; expect(verticalChildren[1].getAttribute('data-placeholder')).to.be.true; @@ -29,4 +29,30 @@ describe('children stub', function () { }); }); + it('should create some stub children (horizontal)', function () { + expect(horizontalChildren.length).to.equal(5); + expect(horizontalChildren[0].getAttribute('data-placeholder')).to.be.false; + expect(horizontalChildren[1].getAttribute('data-placeholder')).to.be.true; + expect(horizontalChildren[1].getAttribute('data-dragged')).to.be.false; + expect(horizontalChildren[2].getAttribute('data-dragged')).to.be.true; + + expect(horizontalChildren[0].getBoundingClientRect()).to.eql({ + top: 20, + left: 10, + bottom: 40, + right: 110, + width: 100, + height: 20 + }); + + expect(horizontalChildren[3].getBoundingClientRect()).to.eql({ + top: 20, + left: 10 + 100 * 3, + bottom: 40, + right: 110 + 100 * 3, + width: 100, + height: 20 + }); + }); + }); diff --git a/tests/helpers/children-stub.js b/tests/helpers/children-stub.js index 32545047..082acb05 100644 --- a/tests/helpers/children-stub.js +++ b/tests/helpers/children-stub.js @@ -52,7 +52,7 @@ for (var i = 0; i < 5; i += 1) { getBoundingClientRect: function () { return { top: itemSize.top, - bottom: itemSize.top, + bottom: itemSize.top + itemSize.height, left: itemSize.left + (itemSize.width * index), right: itemSize.left + (itemSize.width * index) + itemSize.width, width: itemSize.width, From 4c9a2a93452e104ed435173a81f31bff18307dd6 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 16:47:36 +0000 Subject: [PATCH 160/292] Test collision horizontal and vertical --- tests/methods.test.js | 98 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 2 deletions(-) diff --git a/tests/methods.test.js b/tests/methods.test.js index b6552f15..916ded90 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -4,7 +4,7 @@ import mount from './helpers/mount'; import React from 'react'; import Reorder from '../src/index'; -import { verticalChildren } from './helpers/children-stub'; +import { verticalChildren, horizontalChildren } from './helpers/children-stub'; describe('methods', function () { @@ -145,7 +145,7 @@ describe('methods', function () { expect(instance.yCollision(rect, event)).to.be.true; }); - it('should find the first collision of the pointer & Reorder children (no lock)', function () { + it('should find the first collision of the pointer & children (no lock)', function () { const wrapper = mount(); const instance = wrapper.instance(); @@ -192,4 +192,98 @@ describe('methods', function () { expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); }); + it('should find the first collision of the pointer & children (horizontal)', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + const event = { + clientX: 0, + clientY: 0 + }; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + event.clientY = 30; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(0); + + event.clientX = 30; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(0); + + event.clientY = 50; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + event.clientY = 70; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + event.clientY = 90; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(3); + + event.clientX = 200; + event.clientY = 110; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(4); + + event.clientX = 50; + event.clientY = 110; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(4); + + event.clientX = 50; + event.clientY = 130; + + expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + }); + + it('should find the first collision of the pointer & children (vertical)', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + const event = { + clientX: 0, + clientY: 0 + }; + + expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); + + event.clientX = 30; + + expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(0); + + event.clientY = 30; + + expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(0); + + event.clientX = 150; + + expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); + + event.clientX = 250; + + expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); + + event.clientX = 350; + + expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(3); + + event.clientX = 450; + event.clientY = 110; + + expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(4); + + event.clientX = 450; + event.clientY = 0; + + expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(4); + + event.clientX = 550; + event.clientY = 130; + + expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); + }); + }); From c5a6dbb1604a9c20f4e62257def79d5f38c674c1 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 16:54:02 +0000 Subject: [PATCH 161/292] Test getHoldTime --- tests/methods.test.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/methods.test.js b/tests/methods.test.js index 916ded90..eb20f45f 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -286,4 +286,37 @@ describe('methods', function () { expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); }); + it('should return the relevant holdTime', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + expect(instance.getHoldTime({})).to.equal(0); + expect(instance.getHoldTime({touches: []})).to.equal(0); + + wrapper.setProps({holdTime: 50}); + + expect(instance.getHoldTime({})).to.equal(50); + expect(instance.getHoldTime({touches: []})).to.equal(50); + + wrapper.setProps({holdTime: 50, touchHoldTime: 500}); + + expect(instance.getHoldTime({})).to.equal(50); + expect(instance.getHoldTime({touches: []})).to.equal(500); + + wrapper.setProps({holdTime: 50, mouseHoldTime: 250, touchHoldTime: 500}); + + expect(instance.getHoldTime({})).to.equal(250); + expect(instance.getHoldTime({touches: []})).to.equal(500); + + wrapper.setProps({holdTime: NaN}); + + expect(instance.getHoldTime({})).to.equal(0); + expect(instance.getHoldTime({touches: []})).to.equal(0); + + wrapper.setProps({holdTime: NaN, mouseHoldTime: NaN, touchHoldTime: NaN}); + + expect(instance.getHoldTime({})).to.equal(0); + expect(instance.getHoldTime({touches: []})).to.equal(0); + }); + }); From c68410d8dd092ee65467323d8303a5125ac3a352 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 17:05:25 +0000 Subject: [PATCH 162/292] Update readme (more ES6) --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d2f920d4..d02351e8 100644 --- a/README.md +++ b/README.md @@ -65,11 +65,11 @@ It also allows the user to set a hold time (duration before drag begins) allowin } > { - this.state.list.map(function (item) { - return ( -
  • {item.name}
  • - ); - }).toArray() // Note this example is an ImmutableJS List so we must turn it into an array + this.state.list.map((item) => ( +
  • + {item.name} +
  • + )).toArray() // Note this example is an ImmutableJS List so we must convert it to an array }
    ``` From 207604934201b03e7f31e08e2c7c7de137954534 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 17:25:36 +0000 Subject: [PATCH 163/292] autoScroll prop --- README.md | 1 + src/index.js | 66 ++++++++++++++++++++++++++++------------------------ 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index d02351e8..af196469 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,7 @@ It also allows the user to set a hold time (duration before drag begins) allowin touchHoldTime={500} // Hold time before dragging begins on touch devices (optional), defaults to holdTime mouseHoldTime={200} // Hold time before dragging begins with mouse (optional), defaults to holdTime onReorder={this.onReorder.bind(this)} // Callback when an item is dropped (you will need this to update your state) + autoScroll={true} // Enable auto-scrolling when the pointer is close to the edge of the Reorder component, defaults to true placeholder={
    // Custom placeholder element (optional), defaults to clone of dragged element } diff --git a/src/index.js b/src/index.js index 7d18a015..ae2eac59 100644 --- a/src/index.js +++ b/src/index.js @@ -118,48 +118,50 @@ }, autoScroll: function () { - var rect = this.rootNode.getBoundingClientRect(); + if (this.props.autoScroll) { + var rect = this.rootNode.getBoundingClientRect(); - var scrollTop = this.rootNode.scrollTop; - var scrollLeft = this.rootNode.scrollLeft; + var scrollTop = this.rootNode.scrollTop; + var scrollLeft = this.rootNode.scrollLeft; - var scrollHeight = this.rootNode.scrollHeight; - var scrollWidth = this.rootNode.scrollWidth; + var scrollHeight = this.rootNode.scrollHeight; + var scrollWidth = this.rootNode.scrollWidth; - var scrollAreaX = Math.min(rect.width / 3, CONSTANTS.SCROLL_AREA_MAX); - var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); + var scrollAreaX = Math.min(rect.width / 3, CONSTANTS.SCROLL_AREA_MAX); + var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); - var scrollMultiplier; + var scrollMultiplier; - if (this.props.lock !== 'horizontal') { - if (scrollLeft > 0 && this.mouseOffset.clientX <= rect.left + scrollAreaX) { - scrollMultiplier = Math.min(Math.abs(rect.left + scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / - scrollAreaX; + if (this.props.lock !== 'horizontal') { + if (scrollLeft > 0 && this.mouseOffset.clientX <= rect.left + scrollAreaX) { + scrollMultiplier = Math.min(Math.abs(rect.left + scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / + scrollAreaX; - this.rootNode.scrollLeft = this.rootNode.scrollLeft - scrollMultiplier * CONSTANTS.SCROLL_SPEED; - } + this.rootNode.scrollLeft = this.rootNode.scrollLeft - scrollMultiplier * CONSTANTS.SCROLL_SPEED; + } - if (scrollLeft < scrollWidth - rect.width && this.mouseOffset.clientX >= rect.right - scrollAreaX) { - scrollMultiplier = Math.min(Math.abs(rect.right - scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / - scrollAreaX; + if (scrollLeft < scrollWidth - rect.width && this.mouseOffset.clientX >= rect.right - scrollAreaX) { + scrollMultiplier = Math.min(Math.abs(rect.right - scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / + scrollAreaX; - this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollMultiplier * CONSTANTS.SCROLL_SPEED; + this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollMultiplier * CONSTANTS.SCROLL_SPEED; + } } - } - if (this.props.lock !== 'vertical') { - if (scrollTop > 0 && this.mouseOffset.clientY <= rect.top + scrollAreaY) { - scrollMultiplier = Math.min(Math.abs(rect.top + scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / - scrollAreaY; + if (this.props.lock !== 'vertical') { + if (scrollTop > 0 && this.mouseOffset.clientY <= rect.top + scrollAreaY) { + scrollMultiplier = Math.min(Math.abs(rect.top + scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / + scrollAreaY; - this.rootNode.scrollTop = this.rootNode.scrollTop - scrollMultiplier * CONSTANTS.SCROLL_SPEED; - } + this.rootNode.scrollTop = this.rootNode.scrollTop - scrollMultiplier * CONSTANTS.SCROLL_SPEED; + } - if (scrollTop < scrollHeight - rect.height && this.mouseOffset.clientY >= rect.bottom - scrollAreaY) { - scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / - scrollAreaY; + if (scrollTop < scrollHeight - rect.height && this.mouseOffset.clientY >= rect.bottom - scrollAreaY) { + scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / + scrollAreaY; - this.rootNode.scrollTop = this.rootNode.scrollTop + scrollMultiplier * CONSTANTS.SCROLL_SPEED; + this.rootNode.scrollTop = this.rootNode.scrollTop + scrollMultiplier * CONSTANTS.SCROLL_SPEED; + } } } }, @@ -442,7 +444,8 @@ touchHoldTime: PropTypes.number, mouseHoldTime: PropTypes.number, onReorder: PropTypes.func, - placeholder: PropTypes.element + placeholder: PropTypes.element, + autoScroll: PropTypes.bool }; Reorder.defaultProps = { @@ -450,11 +453,12 @@ placeholderClassName: 'placeholder', draggedClassName: 'dragged', // lock: direction, - holdTime: 0 + holdTime: 0, // touchHoldTime: 0, // mouseHoldTime: 0, // onReorder: function, // placeholder: react element + autoScroll: true }; return Reorder; From 11790e734a22242d9cdc95bca2b69f64b642788c Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 17:41:13 +0000 Subject: [PATCH 164/292] Abstract methods to return scroll offsets --- src/index.js | 73 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/src/index.js b/src/index.js index ae2eac59..4d9602bf 100644 --- a/src/index.js +++ b/src/index.js @@ -117,50 +117,61 @@ return parseInt(this.props.holdTime, 10) || 0; }, - autoScroll: function () { - if (this.props.autoScroll) { - var rect = this.rootNode.getBoundingClientRect(); + getScrollOffsetX: function (rect, node, mouseOffset) { + var scrollLeft = node.scrollLeft; + var scrollWidth = node.scrollWidth; - var scrollTop = this.rootNode.scrollTop; - var scrollLeft = this.rootNode.scrollLeft; + var scrollAreaX = Math.min(rect.width / 3, CONSTANTS.SCROLL_AREA_MAX); - var scrollHeight = this.rootNode.scrollHeight; - var scrollWidth = this.rootNode.scrollWidth; + if (scrollLeft > 0 && mouseOffset.clientX <= rect.left + scrollAreaX) { + return -Math.min(Math.abs(rect.left + scrollAreaX - mouseOffset.clientX), scrollAreaX) / + scrollAreaX * CONSTANTS.SCROLL_SPEED; + } - var scrollAreaX = Math.min(rect.width / 3, CONSTANTS.SCROLL_AREA_MAX); - var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); + if (scrollLeft < scrollWidth - rect.width && mouseOffset.clientX >= rect.right - scrollAreaX) { + return Math.min(Math.abs(rect.right - scrollAreaX - mouseOffset.clientX), scrollAreaX) / + scrollAreaX * CONSTANTS.SCROLL_SPEED; + } - var scrollMultiplier; + return 0; + }, - if (this.props.lock !== 'horizontal') { - if (scrollLeft > 0 && this.mouseOffset.clientX <= rect.left + scrollAreaX) { - scrollMultiplier = Math.min(Math.abs(rect.left + scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / - scrollAreaX; + getScrollOffsetY: function (rect, node, mouseOffset) { + var scrollTop = node.scrollTop; + var scrollHeight = node.scrollHeight; - this.rootNode.scrollLeft = this.rootNode.scrollLeft - scrollMultiplier * CONSTANTS.SCROLL_SPEED; - } + var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); - if (scrollLeft < scrollWidth - rect.width && this.mouseOffset.clientX >= rect.right - scrollAreaX) { - scrollMultiplier = Math.min(Math.abs(rect.right - scrollAreaX - this.mouseOffset.clientX), scrollAreaX) / - scrollAreaX; + if (scrollTop > 0 && mouseOffset.clientY <= rect.top + scrollAreaY) { + return -Math.min(Math.abs(rect.top + scrollAreaY - mouseOffset.clientY), scrollAreaY) / + scrollAreaY * CONSTANTS.SCROLL_SPEED; + } - this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollMultiplier * CONSTANTS.SCROLL_SPEED; - } - } + if (scrollTop < scrollHeight - rect.height && mouseOffset.clientY >= rect.bottom - scrollAreaY) { + return Math.min(Math.abs(rect.bottom - scrollAreaY - mouseOffset.clientY), scrollAreaY) / + scrollAreaY * CONSTANTS.SCROLL_SPEED; + } - if (this.props.lock !== 'vertical') { - if (scrollTop > 0 && this.mouseOffset.clientY <= rect.top + scrollAreaY) { - scrollMultiplier = Math.min(Math.abs(rect.top + scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / - scrollAreaY; + return 0; + }, - this.rootNode.scrollTop = this.rootNode.scrollTop - scrollMultiplier * CONSTANTS.SCROLL_SPEED; + autoScroll: function () { + if (this.props.autoScroll) { + var rect = this.rootNode.getBoundingClientRect(); + + if (this.props.lock !== 'horizontal') { + var scrollOffsetX = this.getScrollOffsetX(rect, this.rootNode, this.mouseOffset); + + if (scrollOffsetX) { + this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollOffsetX; } + } - if (scrollTop < scrollHeight - rect.height && this.mouseOffset.clientY >= rect.bottom - scrollAreaY) { - scrollMultiplier = Math.min(Math.abs(rect.bottom - scrollAreaY - this.mouseOffset.clientY), scrollAreaY) / - scrollAreaY; + if (this.props.lock !== 'vertical') { + var scrollOffsetY = this.getScrollOffsetY(rect, this.rootNode, this.mouseOffset); - this.rootNode.scrollTop = this.rootNode.scrollTop + scrollMultiplier * CONSTANTS.SCROLL_SPEED; + if (scrollOffsetY) { + this.rootNode.scrollTop = this.rootNode.scrollTop + scrollOffsetY; } } } From b8cf63a7823203f2e454e56140991dbc288cf7c7 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 17:43:49 +0000 Subject: [PATCH 165/292] Disabled prop types & default --- README.md | 1 + src/index.js | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index af196469..68727825 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ It also allows the user to set a hold time (duration before drag begins) allowin mouseHoldTime={200} // Hold time before dragging begins with mouse (optional), defaults to holdTime onReorder={this.onReorder.bind(this)} // Callback when an item is dropped (you will need this to update your state) autoScroll={true} // Enable auto-scrolling when the pointer is close to the edge of the Reorder component, defaults to true + disabled={false} // Disable reordering, defaults to false placeholder={
    // Custom placeholder element (optional), defaults to clone of dragged element } diff --git a/src/index.js b/src/index.js index 4d9602bf..e6b7f450 100644 --- a/src/index.js +++ b/src/index.js @@ -456,7 +456,8 @@ mouseHoldTime: PropTypes.number, onReorder: PropTypes.func, placeholder: PropTypes.element, - autoScroll: PropTypes.bool + autoScroll: PropTypes.bool, + disabled: PropTypes.bool }; Reorder.defaultProps = { @@ -469,7 +470,8 @@ // mouseHoldTime: 0, // onReorder: function, // placeholder: react element - autoScroll: true + autoScroll: true, + disabled: false }; return Reorder; From e0ce0ed8935bcc69fba6147b8b679c13f404300e Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 18:54:22 +0000 Subject: [PATCH 166/292] Begin testing scroll offsets --- tests/methods.test.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/methods.test.js b/tests/methods.test.js index eb20f45f..cef7ba6d 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -319,4 +319,40 @@ describe('methods', function () { expect(instance.getHoldTime({touches: []})).to.equal(0); }); + it('should return the scroll offset x for autoscrolling', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + const rect = { + top: 10, + left: 10, + right: 110, + bottom: 110, + width: 100, + height: 100 + }; + + const node = { + scrollTop: 50, + scrollLeft: 50, + scrollHeight: 200, + scrollWidth: 200 + }; + + const mouseOffset = { + clientX: 50, + clientY: 50 + }; + + expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(0); + + mouseOffset.clientX = 0; + + expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(-20); + + mouseOffset.clientX = 120; + + expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(20); + }); + }); From 77064a8faa8d82ae81bddb66bb11c7f4486dcc81 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 18:56:32 +0000 Subject: [PATCH 167/292] Improve scroll offset test --- tests/methods.test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/methods.test.js b/tests/methods.test.js index cef7ba6d..847ace8c 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -326,8 +326,8 @@ describe('methods', function () { const rect = { top: 10, left: 10, - right: 110, - bottom: 110, + right: 120, + bottom: 120, width: 100, height: 100 }; @@ -347,11 +347,15 @@ describe('methods', function () { expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(0); mouseOffset.clientX = 0; + expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(-20); + mouseOffset.clientX = rect.left; expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(-20); mouseOffset.clientX = 120; + expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(20); + mouseOffset.clientX = rect.right; expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(20); }); From 4c764ffb5e96e6b83d85a9b04d80e928e24003c7 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 23:28:10 +0000 Subject: [PATCH 168/292] More thorough tests for scroll offsets x & y --- tests/methods.test.js | 72 ++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/tests/methods.test.js b/tests/methods.test.js index 847ace8c..d3c3cd75 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -319,44 +319,68 @@ describe('methods', function () { expect(instance.getHoldTime({touches: []})).to.equal(0); }); - it('should return the scroll offset x for autoscrolling', function () { + it('should return the scroll offset x for auto-scrolling (max scroll area)', function () { + const maxScrollArea = 50; + const scrollSpeed = 20; const wrapper = mount(); const instance = wrapper.instance(); const rect = { - top: 10, - left: 10, - right: 120, - bottom: 120, - width: 100, - height: 100 + top: 200, + left: maxScrollArea, + height: 50, // Larger than maxScrollArea * 3 (as scroll area is divided by 3) + width: maxScrollArea * 4, // Larger than maxScrollArea * 3 (as scroll area is divided by 3) + bottom: 250, + right: maxScrollArea * 5 }; const node = { - scrollTop: 50, - scrollLeft: 50, - scrollHeight: 200, - scrollWidth: 200 + scrollTop: 1000, // More than zero, less than scrollHeight + scrollLeft: 1, // More than zero, less than scrollWidth + scrollHeight: 2000, // Larger than width & height + scrollWidth: maxScrollArea * 5 // Larger than width & height }; - const mouseOffset = { - clientX: 50, - clientY: 50 - }; + const expectedScrollOffsets = [-scrollSpeed, -scrollSpeed, 0, 0, 0, scrollSpeed, scrollSpeed]; + + for (var i = 0; i < expectedScrollOffsets.length; i += 1) { + const expectedScrollOffset = expectedScrollOffsets[i]; + const mouseOffset = {clientX: maxScrollArea * i}; + + expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(expectedScrollOffset); + } + }); - expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(0); + it('should return the scroll offset y for auto-scrolling (max scroll area)', function () { + const maxScrollArea = 50; + const scrollSpeed = 20; + const wrapper = mount(); + const instance = wrapper.instance(); - mouseOffset.clientX = 0; - expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(-20); + const rect = { + top: maxScrollArea, + left: 200, + height: maxScrollArea * 4, // Larger than maxScrollArea * 3 (as scroll area is divided by 3) + width: 50, // Larger than maxScrollArea * 3 (as scroll area is divided by 3) + bottom: maxScrollArea * 5, + right: 250 + }; + + const node = { + scrollTop: 1, // More than zero, less than scrollHeight + scrollLeft: 1000, // More than zero, less than scrollWidth + scrollHeight: maxScrollArea * 5, // Larger than width & height + scrollWidth: 2000 // Larger than width & height + }; - mouseOffset.clientX = rect.left; - expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(-20); + const expectedScrollOffsets = [-scrollSpeed, -scrollSpeed, 0, 0, 0, scrollSpeed, scrollSpeed]; - mouseOffset.clientX = 120; - expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(20); + for (var i = 0; i < expectedScrollOffsets.length; i += 1) { + const expectedScrollOffset = expectedScrollOffsets[i]; + const mouseOffset = {clientY: maxScrollArea * i}; - mouseOffset.clientX = rect.right; - expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(20); + expect(instance.getScrollOffsetY(rect, node, mouseOffset)).to.equal(expectedScrollOffset); + } }); }); From e02933c3c380e9470b0cefc71f4582f984d2ae0f Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 23:31:07 +0000 Subject: [PATCH 169/292] Test half scroll speeds --- tests/methods.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/methods.test.js b/tests/methods.test.js index d3c3cd75..e214df59 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -349,6 +349,9 @@ describe('methods', function () { expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(expectedScrollOffset); } + + expect(instance.getScrollOffsetX(rect, node, {clientX: maxScrollArea * 1.5})).to.equal(-scrollSpeed / 2); + expect(instance.getScrollOffsetX(rect, node, {clientX: maxScrollArea * 4.5})).to.equal(scrollSpeed / 2); }); it('should return the scroll offset y for auto-scrolling (max scroll area)', function () { @@ -381,6 +384,9 @@ describe('methods', function () { expect(instance.getScrollOffsetY(rect, node, mouseOffset)).to.equal(expectedScrollOffset); } + + expect(instance.getScrollOffsetY(rect, node, {clientY: maxScrollArea * 1.5})).to.equal(-scrollSpeed / 2); + expect(instance.getScrollOffsetY(rect, node, {clientY: maxScrollArea * 4.5})).to.equal(scrollSpeed / 2); }); }); From b331651b804af40d4c4be0e312d6fe7f868e5eff Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 23:53:06 +0000 Subject: [PATCH 170/292] Test autoScroll --- tests/methods.test.js | 57 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/tests/methods.test.js b/tests/methods.test.js index e214df59..c5a3fce3 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spy } from 'sinon'; +import { spy, stub } from 'sinon'; import mount from './helpers/mount'; import React from 'react'; @@ -389,4 +389,59 @@ describe('methods', function () { expect(instance.getScrollOffsetY(rect, node, {clientY: maxScrollArea * 4.5})).to.equal(scrollSpeed / 2); }); + it('should scroll the root node if auto-scroll enabled & pointer is in the right location', function () { + const wrapper = mount(); + const instance = wrapper.instance(); + + expect(instance.rootNode).to.be.ok; + + stub(instance.rootNode, 'getBoundingClientRect', function () { + return { + top: 0, + left: 0, + height: 100, + width: 100, + bottom: 100, + right: 100 + }; + }); + + instance.rootNode.scrollTop = 50; + instance.rootNode.scrollLeft = 50; + instance.rootNode.scrollHeight = 200; + instance.rootNode.scrollWidth = 200; + + instance.mouseOffset = { + clientY: 50, + clientX: 50 + }; + + instance.autoScroll(); + expect(instance.rootNode.scrollTop).to.equal(50); + expect(instance.rootNode.scrollLeft).to.equal(50); + + instance.mouseOffset.clientY = 100; + instance.autoScroll(); + expect(instance.rootNode.scrollTop).to.equal(70); + expect(instance.rootNode.scrollLeft).to.equal(50); + + wrapper.setProps({lock: 'vertical'}); + instance.mouseOffset.clientX = 100; + instance.autoScroll(); + expect(instance.rootNode.scrollTop).to.equal(70); + expect(instance.rootNode.scrollLeft).to.equal(70); + + wrapper.setProps({lock: 'horizontal'}); + instance.autoScroll(); + expect(instance.rootNode.scrollTop).to.equal(90); + expect(instance.rootNode.scrollLeft).to.equal(70); + + wrapper.setProps({autoScroll: false}); + instance.autoScroll(); + expect(instance.rootNode.scrollTop).to.equal(90); + expect(instance.rootNode.scrollLeft).to.equal(70); + + instance.rootNode.getBoundingClientRect.restore(); + }); + }); From cdce22f99f285360de24eb3440e4f94d36571d09 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 18 Dec 2016 23:54:45 +0000 Subject: [PATCH 171/292] Add placedIndex default state --- src/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.js b/src/index.js index e6b7f450..f6ccff7a 100644 --- a/src/index.js +++ b/src/index.js @@ -36,6 +36,7 @@ getInitialState: function () { return { + placedIndex: -1, draggedIndex: -1, draggedStyle: null }; From 4ee71af1f4bf475d4eb114488a5d5cb29dd35df4 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 22 Dec 2016 14:26:06 +0000 Subject: [PATCH 172/292] Update readme --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 68727825..cc2ca078 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,13 @@ It also allows the user to set a hold time (duration before drag begins) allowin
  • {item.name}
  • - )).toArray() // Note this example is an ImmutableJS List so we must convert it to an array + )).toArray() + /* + Note this example is an ImmutableJS List so we must convert it to an array. + I've left this up to you to covert to an array, as react-reorder updates a lot, + and if I called this internally it could get rather slow, + whereas you have greater control over your component updates. + */ }
    ``` From 8309c03f1e39ec54d9c386e2b56d94554bfed30b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 19 Feb 2017 20:02:51 +0000 Subject: [PATCH 173/292] Add multi-list example (for testing) --- examples/src/js/index.js | 72 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 2ba17d49..7fb2efae 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -34,6 +34,13 @@ const classNames = ReactStyleSheets.createUniqueClassStyles({ whiteSpace: 'nowrap' }, mylist3: {}, + multiList: { + width: '50%', + minHeight: 100, + maxHeight: 400, + overflowX: 'hidden', + overflowY: 'auto' + }, listItem: { float: 'left', width: '100%', @@ -55,6 +62,7 @@ const classNames = ReactStyleSheets.createUniqueClassStyles({ float: 'left', width: '50%' }, + multiListItem: {}, placeholder: { backgroundColor: '#CCC', border: [1, 'solid', '#CCC'] @@ -94,6 +102,18 @@ class Main extends Component { color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') }; })), + multiList1: Immutable.List(Immutable.Range(0, 5).map(function (value) { + return { + name: ['List A - Item', value].join(' '), + color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') + }; + })), + multiList2: Immutable.List(Immutable.Range(0, 5).map(function (value) { + return { + name: ['List B - Item', value].join(' '), + color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') + }; + })), prefix: 'Prefix' }; } @@ -225,6 +245,7 @@ class Main extends Component {

    + +

    + Drag between lists +

    +

    + This example has a group of lists that you can drag items between +

    + + + { + this.state.multiList1.map(function (item) { + return ( +
  • + {item.name} +
  • + ); + }.bind(this)).toArray() + } +
    + + + { + this.state.multiList2.map(function (item) { + return ( +
  • + {item.name} +
  • + ); + }.bind(this)).toArray() + } +
    ); } From c12be3396695b8f0166c8c6379d558e1cf5af557 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 19 Feb 2017 20:05:27 +0000 Subject: [PATCH 174/292] Prevent passive listeners --- src/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index f6ccff7a..1cc75659 100644 --- a/src/index.js +++ b/src/index.js @@ -358,11 +358,11 @@ // Add listeners componentWillMount: function () { - window.addEventListener('mouseup', this.onWindowUp); - window.addEventListener('touchend', this.onWindowUp); - window.addEventListener('mousemove', this.onWindowMove); - window.addEventListener('touchmove', this.onWindowMove); - window.addEventListener('contextmenu', this.preventDefault); + window.addEventListener('mouseup', this.onWindowUp, {passive: false}); + window.addEventListener('touchend', this.onWindowUp, {passive: false}); + window.addEventListener('mousemove', this.onWindowMove, {passive: false}); + window.addEventListener('touchmove', this.onWindowMove, {passive: false}); + window.addEventListener('contextmenu', this.preventDefault, {passive: false}); }, // Remove listeners From c27a57af7428d129b703c82e72d0acc219a17533 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 19 Feb 2017 20:22:50 +0000 Subject: [PATCH 175/292] Allow / disable content menus --- src/index.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 1cc75659..f9650ac5 100644 --- a/src/index.js +++ b/src/index.js @@ -46,8 +46,10 @@ return this.state.draggedIndex >= 0; }, - preventDefault: function (event) { - event.preventDefault(); + preventContextMenu: function (event) { + if (this.downPos && this.props.disableContentMenus) { + event.preventDefault(); + } }, preventNativeScrolling: function (event) { @@ -307,6 +309,8 @@ draggedIndex: -1, draggedStyle: null }); + + this.downPos = null; }, // Update dragged position & placeholder index, invalidate drag if moved @@ -362,7 +366,7 @@ window.addEventListener('touchend', this.onWindowUp, {passive: false}); window.addEventListener('mousemove', this.onWindowMove, {passive: false}); window.addEventListener('touchmove', this.onWindowMove, {passive: false}); - window.addEventListener('contextmenu', this.preventDefault, {passive: false}); + window.addEventListener('contextmenu', this.preventContextMenu, {passive: false}); }, // Remove listeners @@ -374,7 +378,7 @@ window.removeEventListener('touchend', this.onWindowUp); window.removeEventListener('mousemove', this.onWindowMove); window.removeEventListener('touchmove', this.onWindowMove); - window.removeEventListener('contextmenu', this.preventDefault); + window.removeEventListener('contextmenu', this.preventContextMenu); }, storeRootNode: function (element) { @@ -458,7 +462,8 @@ onReorder: PropTypes.func, placeholder: PropTypes.element, autoScroll: PropTypes.bool, - disabled: PropTypes.bool + disabled: PropTypes.bool, + disableContentMenus: PropTypes.bool }; Reorder.defaultProps = { @@ -472,7 +477,8 @@ // onReorder: function, // placeholder: react element autoScroll: true, - disabled: false + disabled: false, + disableContentMenus: true }; return Reorder; From 8719350a8c8e9d6b942e98f0a58aab07a8812dd2 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 19 Feb 2017 20:39:12 +0000 Subject: [PATCH 176/292] Reorder Id & Group PropTypes --- src/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/index.js b/src/index.js index f9650ac5..05670be8 100644 --- a/src/index.js +++ b/src/index.js @@ -453,6 +453,8 @@ Reorder.propTypes = { component: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), + reorderId: PropTypes.string.isRequired, + reorderGroup: PropTypes.string, placeholderClassName: PropTypes.string, draggedClassName: PropTypes.string, lock: PropTypes.string, @@ -468,6 +470,8 @@ Reorder.defaultProps = { component: 'div', + // reorderId: id, + // reorderGroup: group, placeholderClassName: 'placeholder', draggedClassName: 'dragged', // lock: direction, From a19541ed80276b52952701f9a7821953655ab565 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 19 Feb 2017 21:37:56 +0000 Subject: [PATCH 177/292] Begin validating reorder Id and Group --- examples/src/js/index.js | 7 ++++++ src/index.js | 53 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 7fb2efae..9e68ee7f 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -167,6 +167,7 @@ class Main extends Component {

    Date: Sun, 19 Feb 2017 21:46:46 +0000 Subject: [PATCH 178/292] Update eslint config dep --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 106bca83..ccc181e1 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "babelify": "=7.3.0", "browserify": "=12.0.1", "chai": "=3.5.0", - "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v0.0.2", "http-server": "=0.8.5", "immutable": "=3.8.1", "jquery": "=3.1.1", @@ -58,6 +57,7 @@ "sinon": "=1.17.6", "sinon-chai": "=2.8.0", "watchify": "=3.6.1" + "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v2.1.0", }, "peerDependencies": { "react": "*" From 4f669279fe7778a5953a184cbda7b437765db8d8 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 19 Feb 2017 21:47:00 +0000 Subject: [PATCH 179/292] Remove equals from deps --- package.json | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index ccc181e1..edd29fd5 100644 --- a/package.json +++ b/package.json @@ -38,26 +38,26 @@ "lodash.assign": "*" }, "devDependencies": { - "babel-preset-es2015": "=6.18.0", - "babel-preset-react": "=6.11.1", - "babelify": "=7.3.0", - "browserify": "=12.0.1", - "chai": "=3.5.0", - "http-server": "=0.8.5", - "immutable": "=3.8.1", - "jquery": "=3.1.1", - "jsdom": "=9.8.3", - "lodash.assign": "=4.2.0", - "mocha": "=3.2.0", - "nyc": "=10.0.0", - "react": "=15.4.1", - "react-addons-test-utils": "=15.4.1", - "react-dom": "=15.4.1", - "react-style-sheets": "=0.1.0", - "sinon": "=1.17.6", - "sinon-chai": "=2.8.0", - "watchify": "=3.6.1" + "babel-preset-es2015": "6.18.0", + "babel-preset-react": "6.11.1", + "babelify": "7.3.0", + "browserify": "12.0.1", + "chai": "3.5.0", "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v2.1.0", + "http-server": "0.8.5", + "immutable": "3.8.1", + "jquery": "3.1.1", + "jsdom": "9.8.3", + "lodash.assign": "4.2.0", + "mocha": "3.2.0", + "nyc": "10.0.0", + "react": "15.4.1", + "react-addons-test-utils": "15.4.1", + "react-dom": "15.4.1", + "react-style-sheets": "0.1.0", + "sinon": "1.17.6", + "sinon-chai": "2.8.0", + "watchify": "3.6.1" }, "peerDependencies": { "react": "*" From 8a96c5077f6e409092b082ea3fb9df21f3f0b187 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 19 Feb 2017 21:48:30 +0000 Subject: [PATCH 180/292] Update lint scripts & config --- .eslintrc-examples.json | 5 +++++ .eslintrc-src.json | 6 ++++++ .eslintrc-tests.json | 6 ++++++ package.json | 8 ++++---- 4 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 .eslintrc-examples.json create mode 100644 .eslintrc-src.json create mode 100644 .eslintrc-tests.json diff --git a/.eslintrc-examples.json b/.eslintrc-examples.json new file mode 100644 index 00000000..d1cfbb39 --- /dev/null +++ b/.eslintrc-examples.json @@ -0,0 +1,5 @@ +{ + "extends":[ + "jakesidsmith/default" + ] +} diff --git a/.eslintrc-src.json b/.eslintrc-src.json new file mode 100644 index 00000000..fc876f04 --- /dev/null +++ b/.eslintrc-src.json @@ -0,0 +1,6 @@ +{ + "extends":[ + "jakesidsmith/base", + "jakesidsmith/browser" + ] +} diff --git a/.eslintrc-tests.json b/.eslintrc-tests.json new file mode 100644 index 00000000..baee7ffb --- /dev/null +++ b/.eslintrc-tests.json @@ -0,0 +1,6 @@ +{ + "extends":[ + "jakesidsmith/default", + "jakesidsmith/mocha" + ] +} diff --git a/package.json b/package.json index edd29fd5..b8442d36 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,11 @@ "build-dirs": "mkdir -p examples/build/js/", "build": "npm run build-dirs && npm run build-js", "watch": "npm run watch-js", - "lint-lib": "eslint -c node_modules/eslintrc/.eslintrc-es5 lib/index.js", - "lint-examples": "eslint -c node_modules/eslintrc/.eslintrc-es6-react examples/src/js/", - "lint-tests": "eslint -c node_modules/eslintrc/.eslintrc-es6-react-mocha tests/", + "lint-src": "eslint -c .eslintrc-src.json src/", + "lint-examples": "eslint -c .eslintrc-examples.json examples/src/js/", + "lint-tests": "eslint -c .eslintrc-tests.json tests/", "mocha": "nyc mocha --bail --recursive 'tests/**/*.test.js'", - "test": "npm run lint-lib && npm run lint-examples && npm run lint-tests && npm run mocha" + "test": "npm run lint-src && npm run lint-examples && npm run lint-tests && npm run mocha" }, "bugs": "https://github.com/JakeSidSmith/react-reorder/issues", "repository": { From 542c17df9c30c25a6a1dc17ddac5af32c71104c7 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 19 Feb 2017 21:48:38 +0000 Subject: [PATCH 181/292] Fix linting errors in src --- src/index.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/index.js b/src/index.js index a6daa59f..c20476db 100644 --- a/src/index.js +++ b/src/index.js @@ -55,8 +55,8 @@ } function reorder (list, previousIndex, nextIndex) { - const copy = [].concat(list); - const removed = copy.splice(previousIndex, 1)[0]; + var copy = [].concat(list); + var removed = copy.splice(previousIndex, 1)[0]; copy.splice(nextIndex, 0, removed); @@ -64,7 +64,7 @@ } function reorderImmutable (list, previousIndex, nextIndex) { - const removed = list.get(previousIndex); + var removed = list.get(previousIndex); return list.delete(previousIndex).splice(nextIndex, 0, removed); } @@ -544,10 +544,10 @@ // Export for commonjs / browserify if (typeof exports === 'object' && typeof module !== 'undefined') { - var React = require('react'); - var ReactDOM = require('react-dom'); - var assign = require('lodash.assign'); - module.exports = withReorderMethods(getReorderComponent(React, ReactDOM, assign)); + var React = require('react'); // eslint-disable-line no-undef + var ReactDOM = require('react-dom'); // eslint-disable-line no-undef + var assign = require('lodash.assign'); // eslint-disable-line no-undef + module.exports = withReorderMethods(getReorderComponent(React, ReactDOM, assign)); // eslint-disable-line no-undef // Export for amd / require } else if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef define(['react', 'react-dom', 'lodash.assign'], function (ReactAMD, ReactDOMAMD, assignAMD) { // eslint-disable-line no-undef @@ -560,9 +560,9 @@ if (typeof window !== 'undefined') { root = window; } else if (typeof global !== 'undefined') { - root = global; + root = global; // eslint-disable-line no-undef } else if (typeof self !== 'undefined') { - root = self; + root = self; // eslint-disable-line no-undef } else { root = this; } From f2fc388113619ba8610170cffc8151b580465598 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 09:22:33 +0000 Subject: [PATCH 182/292] Some variables --- src/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/index.js b/src/index.js index c20476db..6ffd55a4 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,11 @@ (function () { + var activeGroup, draggedId, placedId; + + var draggedIndex = -1; + var placedIndex = -1; + var reorderComponents = {}; var reorderGroups = {}; From 81b281caa365e120ebcefa820b9ccd9548947933 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 19:37:02 +0000 Subject: [PATCH 183/292] Create store & register listeners for single lists --- src/index.js | 166 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 121 insertions(+), 45 deletions(-) diff --git a/src/index.js b/src/index.js index 6ffd55a4..e4c488df 100644 --- a/src/index.js +++ b/src/index.js @@ -2,14 +2,6 @@ (function () { - var activeGroup, draggedId, placedId; - - var draggedIndex = -1; - var placedIndex = -1; - - var reorderComponents = {}; - var reorderGroups = {}; - var CONSTANTS = { HOLD_THRESHOLD: 8, SCROLL_INTERVAL: 1000 / 60, @@ -17,48 +9,129 @@ SCROLL_SPEED: 20 }; - function validateComponentIdAndGroup (reorderId, reorderGroup) { - if (typeof reorderId !== 'string') { - throw new Error('Expected reorderId to be a string. Instead got ' + (typeof reorderId)); - } + function Store () { + var activeGroup, draggedId, placedId; - if (typeof reorderGroup !== 'undefined' && typeof reorderGroup !== 'string') { - throw new Error('Expected reorderGroup to be a string. Instead got ' + (typeof reorderGroup)); + var draggedIndex = -1; + var placedIndex = -1; + + var reorderComponents = {}; + var reorderGroups = {}; + + function trigger () { + reorderComponents[draggedId](draggedIndex, placedIndex); } - } - function registerComponent (reorderId, reorderGroup, callback) { - validateComponentIdAndGroup(reorderId, reorderGroup); + function triggerGroup () { - if (reorderId in reorderComponents) { - throw new Error('Duplicate reorderId: ' + reorderId); } - if (typeof reorderGroup !== 'undefined') { - if ((reorderGroup in reorderGroups) && (reorderId in reorderGroups[reorderGroup])) { - throw new Error('Duplicate reorderId: ' + reorderId + ' in reorderGroup: ' + reorderGroup); + function validateComponentIdAndGroup (reorderId, reorderGroup) { + if (typeof reorderId !== 'string') { + throw new Error('Expected reorderId to be a string. Instead got ' + (typeof reorderId)); + } + + if (typeof reorderGroup !== 'undefined' && typeof reorderGroup !== 'string') { + throw new Error('Expected reorderGroup to be a string. Instead got ' + (typeof reorderGroup)); } } - } - function unregisterComponent (reorderId, reorderGroup, callback) { - validateComponentIdAndGroup(reorderId, reorderGroup); + this.registerReorderComponent = function registerReorderComponent (reorderId, reorderGroup, callback) { + validateComponentIdAndGroup(reorderId, reorderGroup); - if (!(reorderId in reorderComponents)) { - throw new Error('Unknown reorderId: ' + reorderId); - } + if (reorderId in reorderComponents) { + throw new Error('Duplicate reorderId: ' + reorderId); + } - if (typeof reorderGroup !== 'undefined') { - if (!(reorderGroup in reorderGroups)) { - throw new Error('Unknown reorderGroup: ' + reorderGroup); + if (typeof reorderGroup !== 'undefined') { + if ((reorderGroup in reorderGroups) && (reorderId in reorderGroups[reorderGroup])) { + throw new Error('Duplicate reorderId: ' + reorderId + ' in reorderGroup: ' + reorderGroup); + } + + reorderGroups[reorderGroup] = reorderGroups[reorderGroup] || {}; + reorderGroups[reorderGroup][reorderId] = callback; + } else { + reorderComponents[reorderId] = callback; } + }; + + this.unregisterReorderComponent = function unregisterReorderComponent (reorderId, reorderGroup) { + validateComponentIdAndGroup(reorderId, reorderGroup); - if ((reorderGroup in reorderGroups) && !(reorderId in reorderGroups[reorderGroup])) { - throw new Error('Unknown reorderId: ' + reorderId + ' in reorderGroup: ' + reorderGroup); + if (!(reorderId in reorderComponents)) { + throw new Error('Unknown reorderId: ' + reorderId); } - } + + if (typeof reorderGroup !== 'undefined') { + if (!(reorderGroup in reorderGroups)) { + throw new Error('Unknown reorderGroup: ' + reorderGroup); + } + + if ((reorderGroup in reorderGroups) && !(reorderId in reorderGroups[reorderGroup])) { + throw new Error('Unknown reorderId: ' + reorderId + ' in reorderGroup: ' + reorderGroup); + } + + delete reorderGroups[reorderGroup][reorderId]; + } else { + delete reorderComponents[reorderId]; + } + }; + + this.startDrag = function startDrag (reorderId, reorderGroup, index) { + validateComponentIdAndGroup(reorderId, reorderGroup); + + draggedId = reorderId; + draggedIndex = index; + placedIndex = index; + + if (typeof reorderGroup !== 'undefined') { + activeGroup = reorderGroup; + + triggerGroup(); + } else { + trigger(); + } + }; + + this.stopDrag = function stopDrag (reorderId, reorderGroup) { + validateComponentIdAndGroup(reorderId, reorderGroup); + + if (typeof activeGroup !== 'undefined' && reorderGroup === activeGroup) { + draggedIndex = -1; + placedIndex = -1; + + triggerGroup(); + } else if (reorderId === draggedId) { + draggedIndex = -1; + placedIndex = -1; + + trigger(); + } + + draggedId = undefined; + placedId = undefined; + activeGroup = undefined; + }; + + this.setPlacedIndex = function setPlacedIndex (reorderId, reorderGroup, index) { + validateComponentIdAndGroup(reorderId, reorderGroup); + + if (typeof reorderGroup !== 'undefined' && reorderGroup === activeGroup) { + placedId = reorderId; + placedIndex = index; + + triggerGroup(); + } else if (reorderId === draggedId) { + placedId = reorderId; + placedIndex = index; + + trigger(); + } + }; } + var store = new Store(); + function reorder (list, previousIndex, nextIndex) { var copy = [].concat(list); var removed = copy.splice(previousIndex, 1)[0]; @@ -235,9 +308,9 @@ this.scrollInterval = setInterval(this.autoScroll, CONSTANTS.SCROLL_INTERVAL); var rect = target.getBoundingClientRect(); + store.startDrag(this.props.reorderId, this.props.reorderGroup, index); + this.setState({ - draggedIndex: index, - placedIndex: index, draggedStyle: { position: 'fixed', top: rect.top, @@ -354,9 +427,9 @@ this.props.onReorder(event, fromIndex, toIndex - (fromIndex < toIndex ? 1 : 0)); } + store.stopDrag(this.props.reorderId, this.props.reorderGroup); + this.setState({ - placedIndex: -1, - draggedIndex: -1, draggedStyle: null }); @@ -394,9 +467,7 @@ collisionIndex <= this.props.children.length && collisionIndex >= 0 ) { - this.setState({ - placedIndex: collisionIndex - }); + store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, collisionIndex); } this.setState({ @@ -410,13 +481,18 @@ } }, - updateState: function () { - console.log('Update'); + updateState: function (draggedIndex, placedIndex) { + console.log('Update', this.props.reorderId, this.props.reorderGroup); + + this.setState({ + draggedIndex: draggedIndex, + placedIndex: placedIndex + }) }, // Add listeners componentWillMount: function () { - registerComponent(this.props.reorderId, this.props.reorderGroup, this.updateState); + store.registerReorderComponent(this.props.reorderId, this.props.reorderGroup, this.updateState); window.addEventListener('mouseup', this.onWindowUp, {passive: false}); window.addEventListener('touchend', this.onWindowUp, {passive: false}); window.addEventListener('mousemove', this.onWindowMove, {passive: false}); @@ -426,7 +502,7 @@ // Remove listeners componentWillUnmount: function () { - unregisterComponent(this.props.reorderId, this.props.reorderGroup, this.updateState); + store.unregisterReorderComponent(this.props.reorderId, this.props.reorderGroup); clearTimeout(this.holdTimeout); clearInterval(this.scrollInterval); From 449ce844be13d62cb25e93bc2298e4194d0471d9 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 19:37:30 +0000 Subject: [PATCH 184/292] Missing semi --- src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index e4c488df..2228bf36 100644 --- a/src/index.js +++ b/src/index.js @@ -487,7 +487,7 @@ this.setState({ draggedIndex: draggedIndex, placedIndex: placedIndex - }) + }); }, // Add listeners From c432aa4a9532b48793ce297dec9f46559adea1ba Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 19:41:38 +0000 Subject: [PATCH 185/292] Fix typo in examples --- examples/src/js/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 9e68ee7f..d4716d65 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -278,7 +278,7 @@ class Main extends Component { Date: Mon, 20 Feb 2017 19:41:50 +0000 Subject: [PATCH 186/292] Fix linting in tests --- tests/helpers/children-stub.js | 2 +- tests/methods.test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/helpers/children-stub.js b/tests/helpers/children-stub.js index 082acb05..d523b9e7 100644 --- a/tests/helpers/children-stub.js +++ b/tests/helpers/children-stub.js @@ -10,7 +10,7 @@ const itemSize = { top: 20 }; -for (var i = 0; i < 5; i += 1) { +for (let i = 0; i < 5; i += 1) { const index = i; verticalChildren.push({ diff --git a/tests/methods.test.js b/tests/methods.test.js index c5a3fce3..52e2e8a1 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -343,7 +343,7 @@ describe('methods', function () { const expectedScrollOffsets = [-scrollSpeed, -scrollSpeed, 0, 0, 0, scrollSpeed, scrollSpeed]; - for (var i = 0; i < expectedScrollOffsets.length; i += 1) { + for (let i = 0; i < expectedScrollOffsets.length; i += 1) { const expectedScrollOffset = expectedScrollOffsets[i]; const mouseOffset = {clientX: maxScrollArea * i}; @@ -378,7 +378,7 @@ describe('methods', function () { const expectedScrollOffsets = [-scrollSpeed, -scrollSpeed, 0, 0, 0, scrollSpeed, scrollSpeed]; - for (var i = 0; i < expectedScrollOffsets.length; i += 1) { + for (let i = 0; i < expectedScrollOffsets.length; i += 1) { const expectedScrollOffset = expectedScrollOffsets[i]; const mouseOffset = {clientY: maxScrollArea * i}; From a81676fca2a2ddd4af2f7ded19869a1133168d4d Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 19:51:35 +0000 Subject: [PATCH 187/292] Fix stop drag & group events --- src/index.js | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/src/index.js b/src/index.js index 2228bf36..16835b02 100644 --- a/src/index.js +++ b/src/index.js @@ -96,33 +96,40 @@ this.stopDrag = function stopDrag (reorderId, reorderGroup) { validateComponentIdAndGroup(reorderId, reorderGroup); - if (typeof activeGroup !== 'undefined' && reorderGroup === activeGroup) { - draggedIndex = -1; - placedIndex = -1; + if (typeof activeGroup !== 'undefined') { + if (reorderGroup === activeGroup) { + draggedIndex = -1; + placedIndex = -1; - triggerGroup(); + triggerGroup(); + + draggedId = undefined; + placedId = undefined; + activeGroup = undefined; + } } else if (reorderId === draggedId) { draggedIndex = -1; placedIndex = -1; trigger(); - } - draggedId = undefined; - placedId = undefined; - activeGroup = undefined; + draggedId = undefined; + placedId = undefined; + activeGroup = undefined; + } }; this.setPlacedIndex = function setPlacedIndex (reorderId, reorderGroup, index) { validateComponentIdAndGroup(reorderId, reorderGroup); - if (typeof reorderGroup !== 'undefined' && reorderGroup === activeGroup) { - placedId = reorderId; - placedIndex = index; + if (typeof reorderGroup !== 'undefined') { + if (reorderGroup === activeGroup) { + placedId = reorderId; + placedIndex = index; - triggerGroup(); + triggerGroup(); + } } else if (reorderId === draggedId) { - placedId = reorderId; placedIndex = index; trigger(); From d294ddb1d1bcfdae3eac702adc6d9667c5323a23 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 19:51:43 +0000 Subject: [PATCH 188/292] Remove log --- src/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/index.js b/src/index.js index 16835b02..60d9265c 100644 --- a/src/index.js +++ b/src/index.js @@ -489,8 +489,6 @@ }, updateState: function (draggedIndex, placedIndex) { - console.log('Update', this.props.reorderId, this.props.reorderGroup); - this.setState({ draggedIndex: draggedIndex, placedIndex: placedIndex From 4eb0fd95a62b2141dbb53311a9f44c71d21ccc78 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 19:57:13 +0000 Subject: [PATCH 189/292] Set placedId when beginning drag --- src/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.js b/src/index.js index 60d9265c..412596a8 100644 --- a/src/index.js +++ b/src/index.js @@ -81,6 +81,7 @@ validateComponentIdAndGroup(reorderId, reorderGroup); draggedId = reorderId; + placedId = reorderId; draggedIndex = index; placedIndex = index; From b77c24272f3b7211bcb7f18f5abacac4204e54c7 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 20:11:30 +0000 Subject: [PATCH 190/292] Update setDragState method & add activeGroup to state --- src/index.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 412596a8..bde24362 100644 --- a/src/index.js +++ b/src/index.js @@ -23,7 +23,13 @@ } function triggerGroup () { - + for (var reorderId in reorderGroups[activeGroup]) { + reorderGroups[activeGroup][reorderId]( + reorderId === draggedId ? draggedIndex : -1, + reorderId === placedId ? placedIndex : -1, + activeGroup + ); + } } function validateComponentIdAndGroup (reorderId, reorderGroup) { @@ -489,16 +495,17 @@ } }, - updateState: function (draggedIndex, placedIndex) { + setDragState: function (draggedIndex, placedIndex, activeGroup) { this.setState({ draggedIndex: draggedIndex, - placedIndex: placedIndex + placedIndex: placedIndex, + activeGroup: activeGroup }); }, // Add listeners componentWillMount: function () { - store.registerReorderComponent(this.props.reorderId, this.props.reorderGroup, this.updateState); + store.registerReorderComponent(this.props.reorderId, this.props.reorderGroup, this.setDragState); window.addEventListener('mouseup', this.onWindowUp, {passive: false}); window.addEventListener('touchend', this.onWindowUp, {passive: false}); window.addEventListener('mousemove', this.onWindowMove, {passive: false}); From c5cdd5d9c8dde1cff1ca109f9dbabe6a10a20fbe Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 20:11:42 +0000 Subject: [PATCH 191/292] Remove unused methods --- src/index.js | 58 +--------------------------------------------------- 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/src/index.js b/src/index.js index bde24362..b3cba5e9 100644 --- a/src/index.js +++ b/src/index.js @@ -375,56 +375,6 @@ } }, - onItemMove: function (callback, index, event) { - if (typeof callback === 'function') { - callback(event); - } - - if (event.button === 2 || this.props.disabled) { - return; - } - - this.copyTouchKeys(event); - }, - - onListDown: function (callback, event) { - if (typeof callback === 'function') { - callback(event); - } - - if (event.button === 2 || this.props.disabled) { - return; - } - - this.copyTouchKeys(event); - }, - - // Handle moving from one list to another - onListMove: function (callback, event) { - if (typeof callback === 'function') { - callback(event); - } - - if (event.button === 2 || this.props.disabled) { - return; - } - - this.copyTouchKeys(event); - }, - - // Handle same as list move - onListUp: function (callback, event) { - if (typeof callback === 'function') { - callback(event); - } - - if (event.button === 2 || this.props.disabled) { - return; - } - - this.copyTouchKeys(event); - }, - // Stop dragging - reset style & draggedIndex, handle reorder onWindowUp: function (event) { clearTimeout(this.holdTimeout); @@ -580,13 +530,7 @@ id: this.props.id, style: this.props.style, onClick: this.props.onClick, - ref: this.storeRootNode, - onMouseDown: this.onListDown.bind(this, this.props.onMouseDown), - onTouchStart: this.onListDown.bind(this, this.props.onTouchStart), - onMouseMove: this.onListMove.bind(this, this.props.onMouseMove), - onTouchMove: this.onListMove.bind(this, this.props.onTouchMove), - onMouseUp: this.onListUp.bind(this, this.props.onMouseUp), - onTouchEnd: this.onListUp.bind(this, this.props.onTouchEnd) + ref: this.storeRootNode }, children ); From 5c6fdd2df35cc6162862068895d9bbbe22038eee Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 20:31:44 +0000 Subject: [PATCH 192/292] Replace mutli-list examples callback --- examples/src/js/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index d4716d65..40a97a40 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -126,6 +126,10 @@ class Main extends Component { }); } + onReorderGroup () { + console.log('Reorder group'); + } + onDisableToggle () { this.setState({ disableReorder: !this.state.disableReorder @@ -283,7 +287,7 @@ class Main extends Component { className={[classNames.myList, classNames.multiList].join(' ')} placeholderClassName={classNames.placeholder} draggedClassName={classNames.dragged} - onReorder={this.onReorder.bind(this)} + onReorder={this.onReorderGroup.bind(this)} > { this.state.multiList1.map(function (item) { @@ -307,7 +311,7 @@ class Main extends Component { className={[classNames.myList, classNames.multiList].join(' ')} placeholderClassName={classNames.placeholder} draggedClassName={classNames.dragged} - onReorder={this.onReorder.bind(this)} + onReorder={this.onReorderGroup.bind(this)} > { this.state.multiList2.map(function (item) { From 46747fe040f6d38fbb3dd7b1da20b2a443c0367b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 20:32:38 +0000 Subject: [PATCH 193/292] Store draggedStyle --- src/index.js | 54 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/src/index.js b/src/index.js index b3cba5e9..d7726cc4 100644 --- a/src/index.js +++ b/src/index.js @@ -20,6 +20,7 @@ function trigger () { reorderComponents[draggedId](draggedIndex, placedIndex); + reorderComponents[draggedId](draggedIndex, placedIndex, activeGroup, draggedStyle); } function triggerGroup () { @@ -27,7 +28,8 @@ reorderGroups[activeGroup][reorderId]( reorderId === draggedId ? draggedIndex : -1, reorderId === placedId ? placedIndex : -1, - activeGroup + activeGroup, + draggedStyle ); } } @@ -107,6 +109,7 @@ if (reorderGroup === activeGroup) { draggedIndex = -1; placedIndex = -1; + draggedStyle = null; triggerGroup(); @@ -117,6 +120,7 @@ } else if (reorderId === draggedId) { draggedIndex = -1; placedIndex = -1; + draggedStyle = null; trigger(); @@ -142,6 +146,22 @@ trigger(); } }; + + this.setDraggedStyle = function setDraggedStyle (reorderId, reorderGroup, style) { + validateComponentIdAndGroup(reorderId, reorderGroup); + + if (typeof reorderGroup !== 'undefined') { + if (reorderGroup === activeGroup) { + draggedStyle = style; + + triggerGroup(); + } + } else if (reorderId === draggedId) { + draggedStyle = style; + + trigger(); + } + }; } var store = new Store(); @@ -322,17 +342,16 @@ this.scrollInterval = setInterval(this.autoScroll, CONSTANTS.SCROLL_INTERVAL); var rect = target.getBoundingClientRect(); - store.startDrag(this.props.reorderId, this.props.reorderGroup, index); + var draggedStyle = { + position: 'fixed', + top: rect.top, + left: rect.left, + width: rect.width, + height: rect.height + }; - this.setState({ - draggedStyle: { - position: 'fixed', - top: rect.top, - left: rect.left, - width: rect.width, - height: rect.height - } - }); + store.startDrag(this.props.reorderId, this.props.reorderGroup, index); + store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); this.mouseOffset = { clientX: event.clientX, @@ -393,10 +412,6 @@ store.stopDrag(this.props.reorderId, this.props.reorderGroup); - this.setState({ - draggedStyle: null - }); - this.downPos = null; }, @@ -434,9 +449,7 @@ store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, collisionIndex); } - this.setState({ - draggedStyle: draggedStyle - }); + store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); this.mouseOffset = { clientX: event.clientX, @@ -445,11 +458,12 @@ } }, - setDragState: function (draggedIndex, placedIndex, activeGroup) { + setDragState: function (draggedIndex, placedIndex, activeGroup, draggedStyle) { this.setState({ draggedIndex: draggedIndex, placedIndex: placedIndex, - activeGroup: activeGroup + activeGroup: activeGroup, + draggedStyle: draggedStyle }); }, From 38be72bc3c06a0c867f09f47fd1abc7381ab7f44 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 20:32:52 +0000 Subject: [PATCH 194/292] Default store draggedStyle --- src/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.js b/src/index.js index d7726cc4..1f688a2e 100644 --- a/src/index.js +++ b/src/index.js @@ -12,6 +12,7 @@ function Store () { var activeGroup, draggedId, placedId; + var draggedStyle = null; var draggedIndex = -1; var placedIndex = -1; From 8a94faf7689e2d1ff72932245fc1a4b5615e1011 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 20:33:08 +0000 Subject: [PATCH 195/292] Fix weird commit --- src/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.js b/src/index.js index 1f688a2e..5e3b0229 100644 --- a/src/index.js +++ b/src/index.js @@ -20,7 +20,6 @@ var reorderGroups = {}; function trigger () { - reorderComponents[draggedId](draggedIndex, placedIndex); reorderComponents[draggedId](draggedIndex, placedIndex, activeGroup, draggedStyle); } From 7eadf0ca40d263cd51d66b52f4cda77453df2f9b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 20:37:04 +0000 Subject: [PATCH 196/292] Store downPos in global state --- src/index.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 5e3b0229..40a2ed5f 100644 --- a/src/index.js +++ b/src/index.js @@ -9,6 +9,8 @@ SCROLL_SPEED: 20 }; + var downPos = null; + function Store () { var activeGroup, draggedId, placedId; @@ -204,7 +206,7 @@ }, preventContextMenu: function (event) { - if (this.downPos && this.props.disableContentMenus) { + if (downPos && this.props.disableContentMenus) { event.preventDefault(); } }, @@ -378,7 +380,7 @@ this.copyTouchKeys(event); this.moved = false; - this.downPos = { + downPos = { clientX: event.clientX, clientY: event.clientY }; @@ -412,7 +414,7 @@ store.stopDrag(this.props.reorderId, this.props.reorderGroup); - this.downPos = null; + downPos = null; }, // Update dragged position & placeholder index, invalidate drag if moved @@ -420,9 +422,9 @@ this.copyTouchKeys(event); if ( - this.downPos && ( - Math.abs(event.clientX - this.downPos.clientX) >= CONSTANTS.HOLD_THRESHOLD || - Math.abs(event.clientY - this.downPos.clientY) >= CONSTANTS.HOLD_THRESHOLD + downPos && ( + Math.abs(event.clientX - downPos.clientX) >= CONSTANTS.HOLD_THRESHOLD || + Math.abs(event.clientY - downPos.clientY) >= CONSTANTS.HOLD_THRESHOLD ) ) { this.moved = true; From 128e400cccaf1343ef91bb8c6200820e53fe872c Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 20:42:16 +0000 Subject: [PATCH 197/292] Store mouseOffset in global scope --- src/index.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 40a2ed5f..b9b1fb3f 100644 --- a/src/index.js +++ b/src/index.js @@ -10,6 +10,7 @@ }; var downPos = null; + var mouseOffset = null; function Store () { var activeGroup, draggedId, placedId; @@ -279,7 +280,7 @@ return parseInt(this.props.holdTime, 10) || 0; }, - getScrollOffsetX: function (rect, node, mouseOffset) { + getScrollOffsetX: function (rect, node) { var scrollLeft = node.scrollLeft; var scrollWidth = node.scrollWidth; @@ -298,7 +299,7 @@ return 0; }, - getScrollOffsetY: function (rect, node, mouseOffset) { + getScrollOffsetY: function (rect, node) { var scrollTop = node.scrollTop; var scrollHeight = node.scrollHeight; @@ -322,7 +323,7 @@ var rect = this.rootNode.getBoundingClientRect(); if (this.props.lock !== 'horizontal') { - var scrollOffsetX = this.getScrollOffsetX(rect, this.rootNode, this.mouseOffset); + var scrollOffsetX = this.getScrollOffsetX(rect, this.rootNode); if (scrollOffsetX) { this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollOffsetX; @@ -330,7 +331,7 @@ } if (this.props.lock !== 'vertical') { - var scrollOffsetY = this.getScrollOffsetY(rect, this.rootNode, this.mouseOffset); + var scrollOffsetY = this.getScrollOffsetY(rect, this.rootNode); if (scrollOffsetY) { this.rootNode.scrollTop = this.rootNode.scrollTop + scrollOffsetY; @@ -355,7 +356,7 @@ store.startDrag(this.props.reorderId, this.props.reorderGroup, index); store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); - this.mouseOffset = { + mouseOffset = { clientX: event.clientX, clientY: event.clientY }; @@ -415,6 +416,7 @@ store.stopDrag(this.props.reorderId, this.props.reorderGroup); downPos = null; + mouseOffset = null; }, // Update dragged position & placeholder index, invalidate drag if moved @@ -453,7 +455,7 @@ store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); - this.mouseOffset = { + mouseOffset = { clientX: event.clientX, clientY: event.clientY }; From d5b5b07e0bc6e7a1eb7eb78ffbd58a0b34d3d33f Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 20 Feb 2017 20:44:18 +0000 Subject: [PATCH 198/292] Store mouseDownOffset in global scope --- src/index.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index b9b1fb3f..35f4f3e6 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,7 @@ var downPos = null; var mouseOffset = null; + var mouseDownOffset = null; function Store () { var activeGroup, draggedId, placedId; @@ -361,7 +362,7 @@ clientY: event.clientY }; - this.mouseDownOffset = { + mouseDownOffset = { clientX: event.clientX - rect.left, clientY: event.clientY - rect.top }; @@ -416,7 +417,8 @@ store.stopDrag(this.props.reorderId, this.props.reorderGroup); downPos = null; - mouseOffset = null; + // mouseOffset = null; + // mouseDownOffset = null; }, // Update dragged position & placeholder index, invalidate drag if moved @@ -437,9 +439,9 @@ var draggedStyle = assign({}, this.state.draggedStyle, { top: (!this.props.lock || this.props.lock === 'horizontal') ? - event.clientY - this.mouseDownOffset.clientY : this.state.draggedStyle.top, + event.clientY - mouseDownOffset.clientY : this.state.draggedStyle.top, left: (!this.props.lock || this.props.lock === 'vertical') ? - event.clientX - this.mouseDownOffset.clientX : this.state.draggedStyle.left + event.clientX - mouseDownOffset.clientX : this.state.draggedStyle.left }); var children = ReactDOM.findDOMNode(this).childNodes; From 3990716180d8cc4e861154b4b8c9654237354725 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:01:14 +0000 Subject: [PATCH 199/292] Add inputs to group example --- examples/src/js/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 40a97a40..d7aaa78d 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -298,6 +298,7 @@ class Main extends Component { style={{color: item.color}} > {item.name} + ); }.bind(this)).toArray() @@ -322,6 +323,7 @@ class Main extends Component { style={{color: item.color}} > {item.name} + ); }.bind(this)).toArray() From fbfbed7894bdd7b95b41329f580f2acffcd6bb85 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:01:40 +0000 Subject: [PATCH 200/292] Store draggedElement & handle dragging & placing to different lists --- src/index.js | 154 +++++++++++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 65 deletions(-) diff --git a/src/index.js b/src/index.js index 35f4f3e6..e28e6226 100644 --- a/src/index.js +++ b/src/index.js @@ -14,7 +14,7 @@ var mouseDownOffset = null; function Store () { - var activeGroup, draggedId, placedId; + var activeGroup, draggedId, placedId, draggedElement; var draggedStyle = null; var draggedIndex = -1; @@ -23,18 +23,25 @@ var reorderComponents = {}; var reorderGroups = {}; + function getState () { + return { + draggedId: draggedId, + placedId: placedId, + activeGroup: activeGroup, + draggedStyle: draggedStyle, + draggedIndex: draggedIndex, + placedIndex: placedIndex, + draggedElement: draggedElement + }; + } + function trigger () { - reorderComponents[draggedId](draggedIndex, placedIndex, activeGroup, draggedStyle); + reorderComponents[draggedId](getState()); } function triggerGroup () { for (var reorderId in reorderGroups[activeGroup]) { - reorderGroups[activeGroup][reorderId]( - reorderId === draggedId ? draggedIndex : -1, - reorderId === placedId ? placedIndex : -1, - activeGroup, - draggedStyle - ); + reorderGroups[activeGroup][reorderId](getState()); } } @@ -48,7 +55,7 @@ } } - this.registerReorderComponent = function registerReorderComponent (reorderId, reorderGroup, callback) { + function registerReorderComponent (reorderId, reorderGroup, callback) { validateComponentIdAndGroup(reorderId, reorderGroup); if (reorderId in reorderComponents) { @@ -67,7 +74,7 @@ } }; - this.unregisterReorderComponent = function unregisterReorderComponent (reorderId, reorderGroup) { + function unregisterReorderComponent (reorderId, reorderGroup) { validateComponentIdAndGroup(reorderId, reorderGroup); if (!(reorderId in reorderComponents)) { @@ -89,24 +96,25 @@ } }; - this.startDrag = function startDrag (reorderId, reorderGroup, index) { + function startDrag (reorderId, reorderGroup, index, element) { validateComponentIdAndGroup(reorderId, reorderGroup); draggedId = reorderId; placedId = reorderId; draggedIndex = index; placedIndex = index; + draggedElement = element; if (typeof reorderGroup !== 'undefined') { activeGroup = reorderGroup; triggerGroup(); - } else { + } else if (typeof draggedId !== 'undefined' && reorderId === draggedId) { trigger(); } }; - this.stopDrag = function stopDrag (reorderId, reorderGroup) { + function stopDrag (reorderId, reorderGroup) { validateComponentIdAndGroup(reorderId, reorderGroup); if (typeof activeGroup !== 'undefined') { @@ -114,6 +122,7 @@ draggedIndex = -1; placedIndex = -1; draggedStyle = null; + draggedElement = undefined; triggerGroup(); @@ -121,10 +130,11 @@ placedId = undefined; activeGroup = undefined; } - } else if (reorderId === draggedId) { + } else if (typeof draggedId !== 'undefined' && reorderId === draggedId) { draggedIndex = -1; placedIndex = -1; draggedStyle = null; + draggedElement = undefined; trigger(); @@ -134,7 +144,7 @@ } }; - this.setPlacedIndex = function setPlacedIndex (reorderId, reorderGroup, index) { + function setPlacedIndex (reorderId, reorderGroup, index) { validateComponentIdAndGroup(reorderId, reorderGroup); if (typeof reorderGroup !== 'undefined') { @@ -144,14 +154,14 @@ triggerGroup(); } - } else if (reorderId === draggedId) { + } else if (typeof draggedId !== 'undefined' && reorderId === draggedId) { placedIndex = index; trigger(); } }; - this.setDraggedStyle = function setDraggedStyle (reorderId, reorderGroup, style) { + function setDraggedStyle (reorderId, reorderGroup, style) { validateComponentIdAndGroup(reorderId, reorderGroup); if (typeof reorderGroup !== 'undefined') { @@ -160,12 +170,20 @@ triggerGroup(); } - } else if (reorderId === draggedId) { + } else if (typeof draggedId !== 'undefined' && reorderId === draggedId) { draggedStyle = style; trigger(); } }; + + this.getState = getState; + this.registerReorderComponent = registerReorderComponent; + this.unregisterReorderComponent = unregisterReorderComponent; + this.startDrag = startDrag; + this.stopDrag = stopDrag; + this.setPlacedIndex = setPlacedIndex; + this.setDraggedStyle = setDraggedStyle; } var store = new Store(); @@ -196,17 +214,29 @@ displayName: 'Reorder', getInitialState: function () { - return { - placedIndex: -1, - draggedIndex: -1, - draggedStyle: null - }; + return store.getState(); }, isDragging: function () { return this.state.draggedIndex >= 0; }, + isPlacing: function () { + return this.state.placedIndex >= 0; + }, + + isDraggingFrom: function () { + return this.props.reorderId === this.state.draggedId; + }, + + isPlacingTo: function () { + return this.props.reorderId === this.state.placedId; + }, + + isInvolvedInDragging: function () { + return this.props.reorderId === this.state.draggedId || this.props.reorderGroup === this.state.activeGroup; + }, + preventContextMenu: function (event) { if (downPos && this.props.disableContentMenus) { event.preventDefault(); @@ -354,7 +384,7 @@ height: rect.height }; - store.startDrag(this.props.reorderId, this.props.reorderGroup, index); + store.startDrag(this.props.reorderId, this.props.reorderGroup, index, this.props.children[index]); store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); mouseOffset = { @@ -403,38 +433,38 @@ clearTimeout(this.holdTimeout); clearInterval(this.scrollInterval); - var fromIndex = this.state.draggedIndex; - var toIndex = this.state.placedIndex; + if (this.isDraggingFrom() && this.isDragging()) { + var fromIndex = this.state.draggedIndex; + var toIndex = this.state.placedIndex; - if ( - typeof this.props.onReorder === 'function' && - fromIndex !== toIndex && - fromIndex >= 0 - ) { - this.props.onReorder(event, fromIndex, toIndex - (fromIndex < toIndex ? 1 : 0)); - } + store.stopDrag(this.props.reorderId, this.props.reorderGroup); - store.stopDrag(this.props.reorderId, this.props.reorderGroup); + if (fromIndex !== toIndex && fromIndex >= 0) { + if (typeof this.props.onReorder === 'function') { + this.props.onReorder(event, fromIndex, toIndex - (fromIndex < toIndex ? 1 : 0)); + } + } + } downPos = null; - // mouseOffset = null; - // mouseDownOffset = null; + mouseOffset = null; + mouseDownOffset = null; }, // Update dragged position & placeholder index, invalidate drag if moved onWindowMove: function (event) { this.copyTouchKeys(event); - if ( - downPos && ( - Math.abs(event.clientX - downPos.clientX) >= CONSTANTS.HOLD_THRESHOLD || - Math.abs(event.clientY - downPos.clientY) >= CONSTANTS.HOLD_THRESHOLD - ) - ) { - this.moved = true; - } + if (this.isDragging() && this.isDraggingFrom()) { + if ( + downPos && ( + Math.abs(event.clientX - downPos.clientX) >= CONSTANTS.HOLD_THRESHOLD || + Math.abs(event.clientY - downPos.clientY) >= CONSTANTS.HOLD_THRESHOLD + ) + ) { + this.moved = true; + } - if (this.isDragging()) { this.preventNativeScrolling(event); var draggedStyle = assign({}, this.state.draggedStyle, { @@ -464,13 +494,8 @@ } }, - setDragState: function (draggedIndex, placedIndex, activeGroup, draggedStyle) { - this.setState({ - draggedIndex: draggedIndex, - placedIndex: placedIndex, - activeGroup: activeGroup, - draggedStyle: draggedStyle - }); + setDragState: function (state) { + this.setState(state); }, // Add listeners @@ -505,46 +530,45 @@ }, render: function () { - var self = this; - var children = this.props.children && this.props.children.map(function (child, index) { - var isDragged = index === self.state.draggedIndex; + var isDragged = this.isDragging() && this.isDraggingFrom() && index === this.state.draggedIndex; + + var draggedStyle = isDragged ? assign({}, child.props.style, this.state.draggedStyle) : child.props.style; - var draggedStyle = isDragged ? assign({}, child.props.style, self.state.draggedStyle) : child.props.style; var draggedClass = [ child.props.className || '', - (isDragged ? self.props.draggedClassName : '') + (isDragged ? this.props.draggedClassName : '') ].join(' '); return React.cloneElement( - child, + isDragged ? this.state.draggedElement : child, { style: draggedStyle, className: draggedClass, - onMouseDown: self.onItemDown.bind(self, child.props.onMouseDown, index), - onTouchStart: self.onItemDown.bind(self, child.props.onTouchStart, index), + onMouseDown: this.onItemDown.bind(this, child.props.onMouseDown, index), + onTouchStart: this.onItemDown.bind(this, child.props.onTouchStart, index), 'data-dragged': isDragged ? true : null } ); }.bind(this)); - var draggedElement = this.props.children && this.props.children[this.state.draggedIndex]; - var placeholderElement = this.props.placeholder || draggedElement; + var placeholderElement = this.props.placeholder || this.state.draggedElement; - if (this.state.placedIndex >= 0 && placeholderElement) { + if (this.isPlacing() && this.isPlacingTo() && placeholderElement) { var placeholder = React.cloneElement( placeholderElement, { key: 'react-reorder-placeholder', - className: [placeholderElement.props.className || '', self.props.placeholderClassName].join(' '), + className: [placeholderElement.props.className || '', this.props.placeholderClassName].join(' '), 'data-placeholder': true } ); + children.splice(this.state.placedIndex, 0, placeholder); } return React.createElement( - self.props.component, + this.props.component, { className: this.props.className, id: this.props.id, From b13fb3c7eda17390ea9dc3dfd3d4a1307cd63a82 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:02:22 +0000 Subject: [PATCH 201/292] Remove unnecessary semis --- src/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index e28e6226..81524156 100644 --- a/src/index.js +++ b/src/index.js @@ -72,7 +72,7 @@ } else { reorderComponents[reorderId] = callback; } - }; + } function unregisterReorderComponent (reorderId, reorderGroup) { validateComponentIdAndGroup(reorderId, reorderGroup); @@ -94,7 +94,7 @@ } else { delete reorderComponents[reorderId]; } - }; + } function startDrag (reorderId, reorderGroup, index, element) { validateComponentIdAndGroup(reorderId, reorderGroup); @@ -112,7 +112,7 @@ } else if (typeof draggedId !== 'undefined' && reorderId === draggedId) { trigger(); } - }; + } function stopDrag (reorderId, reorderGroup) { validateComponentIdAndGroup(reorderId, reorderGroup); @@ -142,7 +142,7 @@ placedId = undefined; activeGroup = undefined; } - }; + } function setPlacedIndex (reorderId, reorderGroup, index) { validateComponentIdAndGroup(reorderId, reorderGroup); @@ -159,7 +159,7 @@ trigger(); } - }; + } function setDraggedStyle (reorderId, reorderGroup, style) { validateComponentIdAndGroup(reorderId, reorderGroup); @@ -175,7 +175,7 @@ trigger(); } - }; + } this.getState = getState; this.registerReorderComponent = registerReorderComponent; From fd59fe03ce6d52114b07773b83b8edd67a6f13df Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:06:15 +0000 Subject: [PATCH 202/292] Allow placeholder in other lists --- src/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 81524156..f89b36a9 100644 --- a/src/index.js +++ b/src/index.js @@ -455,7 +455,7 @@ onWindowMove: function (event) { this.copyTouchKeys(event); - if (this.isDragging() && this.isDraggingFrom()) { + if (this.isDragging() && this.isInvolvedInDragging()) { if ( downPos && ( Math.abs(event.clientX - downPos.clientX) >= CONSTANTS.HOLD_THRESHOLD || @@ -478,7 +478,7 @@ var collisionIndex = this.findCollisionIndex(children, event); if ( - collisionIndex !== this.state.placedIndex && + (collisionIndex !== this.state.placedIndex || !this.isDraggingFrom()) && collisionIndex <= this.props.children.length && collisionIndex >= 0 ) { From 4c1248ca455d5d55b0411d06d0a627bc17ef4b79 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:09:01 +0000 Subject: [PATCH 203/292] Reduce ifs --- src/index.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index f89b36a9..b316267e 100644 --- a/src/index.js +++ b/src/index.js @@ -439,10 +439,8 @@ store.stopDrag(this.props.reorderId, this.props.reorderGroup); - if (fromIndex !== toIndex && fromIndex >= 0) { - if (typeof this.props.onReorder === 'function') { - this.props.onReorder(event, fromIndex, toIndex - (fromIndex < toIndex ? 1 : 0)); - } + if (fromIndex !== toIndex && fromIndex >= 0 && typeof this.props.onReorder === 'function') { + this.props.onReorder(event, fromIndex, toIndex - (fromIndex < toIndex ? 1 : 0)); } } From 0baa8ab1da7a696458ee2b729b42bf7088cf17fa Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:10:49 +0000 Subject: [PATCH 204/292] Comments about store state --- src/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.js b/src/index.js index b316267e..b5cb6297 100644 --- a/src/index.js +++ b/src/index.js @@ -126,6 +126,7 @@ triggerGroup(); + // These need to be cleared after trigger to allow state updates to these components draggedId = undefined; placedId = undefined; activeGroup = undefined; @@ -138,6 +139,7 @@ trigger(); + // These need to be cleared after trigger to allow state updates to these components draggedId = undefined; placedId = undefined; activeGroup = undefined; From 9cbce4918aed631df075b117ea9752c18de359a6 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:26:26 +0000 Subject: [PATCH 205/292] Clear store values on startDrag --- src/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index b5cb6297..2c26649f 100644 --- a/src/index.js +++ b/src/index.js @@ -99,12 +99,15 @@ function startDrag (reorderId, reorderGroup, index, element) { validateComponentIdAndGroup(reorderId, reorderGroup); - draggedId = reorderId; - placedId = reorderId; draggedIndex = index; placedIndex = index; + draggedStyle = null; draggedElement = element; + draggedId = reorderId; + placedId = reorderId; + activeGroup = undefined; + if (typeof reorderGroup !== 'undefined') { activeGroup = reorderGroup; From 12a0d682ff8a6a1a5694c969ffce83b8df9da548 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:26:54 +0000 Subject: [PATCH 206/292] Always allow setting placed index if involved --- src/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.js b/src/index.js index 2c26649f..03cfddfc 100644 --- a/src/index.js +++ b/src/index.js @@ -481,7 +481,6 @@ var collisionIndex = this.findCollisionIndex(children, event); if ( - (collisionIndex !== this.state.placedIndex || !this.isDraggingFrom()) && collisionIndex <= this.props.children.length && collisionIndex >= 0 ) { From 1d4ecf20f0488756d736c72950570fd25fe25fbd Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:33:07 +0000 Subject: [PATCH 207/292] Reorder from to methods --- src/index.js | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 03cfddfc..0794c429 100644 --- a/src/index.js +++ b/src/index.js @@ -195,21 +195,45 @@ function reorder (list, previousIndex, nextIndex) { var copy = [].concat(list); - var removed = copy.splice(previousIndex, 1)[0]; + var item = copy.splice(previousIndex, 1)[0]; - copy.splice(nextIndex, 0, removed); + copy.splice(nextIndex, 0, item); return copy; } function reorderImmutable (list, previousIndex, nextIndex) { - var removed = list.get(previousIndex); - return list.delete(previousIndex).splice(nextIndex, 0, removed); + var item = list.get(previousIndex); + return list.delete(previousIndex).splice(nextIndex, 0, item); + } + + function reorderFromTo (lists, previousIndex, nextIndex) { + var previousList = [].concat(lists.from); + var nextList = [].concat(lists.to); + + var item = previousList.splice(previousIndex, 1); + nextList.splice(nextList, 0, item); + + return { + from: previousList, + to: nextList + }; + } + + function reorderFromToImmutable (lists, previousIndex, nextIndex) { + var item = lists.from.get(previousIndex); + + return { + from: lists.from.delete(previousIndex), + to: lists.to.splice(nextIndex, 0, item); + }; } function withReorderMethods (Reorder) { Reorder.reorder = reorder; Reorder.reorderImmutable = reorderImmutable; + Reorder.reorderFromTo = reorderFromTo; + Reorder.reorderFromToImmutable = reorderFromToImmutable; return Reorder; } From c51e9ce53c896cffedec5763b1dd3eeaaefd240f Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:41:44 +0000 Subject: [PATCH 208/292] Call onReorder with IDs --- src/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 0794c429..8176f574 100644 --- a/src/index.js +++ b/src/index.js @@ -225,7 +225,7 @@ return { from: lists.from.delete(previousIndex), - to: lists.to.splice(nextIndex, 0, item); + to: lists.to.splice(nextIndex, 0, item) }; } @@ -469,7 +469,13 @@ store.stopDrag(this.props.reorderId, this.props.reorderGroup); if (fromIndex !== toIndex && fromIndex >= 0 && typeof this.props.onReorder === 'function') { - this.props.onReorder(event, fromIndex, toIndex - (fromIndex < toIndex ? 1 : 0)); + this.props.onReorder( + event, + fromIndex, + toIndex - (fromIndex < toIndex ? 1 : 0), + this.state.draggedId, + this.state.placedId + ); } } From ddabe52630fd371ebdb44dbb0e943ef759de94ae Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:44:44 +0000 Subject: [PATCH 209/292] Fix reorder multiple indices --- src/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 8176f574..9cb4d1e9 100644 --- a/src/index.js +++ b/src/index.js @@ -468,11 +468,15 @@ store.stopDrag(this.props.reorderId, this.props.reorderGroup); - if (fromIndex !== toIndex && fromIndex >= 0 && typeof this.props.onReorder === 'function') { + if ( + fromIndex >= 0 && + (fromIndex !== toIndex || this.state.draggedId !== this.state.placedId) && + typeof this.props.onReorder === 'function' + ) { this.props.onReorder( event, fromIndex, - toIndex - (fromIndex < toIndex ? 1 : 0), + toIndex - (this.state.draggedId === this.state.placedId && fromIndex < toIndex ? 1 : 0), this.state.draggedId, this.state.placedId ); From 18610002b5717c29a840237734820e94d2cc2c71 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:45:24 +0000 Subject: [PATCH 210/292] Update examples to reorder multiple lists --- examples/src/js/index.js | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index d7aaa78d..01347230 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -3,7 +3,7 @@ import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import ReactStyleSheets from 'react-style-sheets'; import Immutable from 'immutable'; -import Reorder, { reorderImmutable } from '../../../src/index'; +import Reorder, { reorderImmutable, reorderFromToImmutable } from '../../../src/index'; const classNames = ReactStyleSheets.createUniqueClassStyles({ app: { @@ -102,13 +102,13 @@ class Main extends Component { color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') }; })), - multiList1: Immutable.List(Immutable.Range(0, 5).map(function (value) { + listA: Immutable.List(Immutable.Range(0, 5).map(function (value) { return { name: ['List A - Item', value].join(' '), color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') }; })), - multiList2: Immutable.List(Immutable.Range(0, 5).map(function (value) { + listB: Immutable.List(Immutable.Range(0, 5).map(function (value) { return { name: ['List B - Item', value].join(' '), color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') @@ -126,8 +126,28 @@ class Main extends Component { }); } - onReorderGroup () { - console.log('Reorder group'); + onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { + console.log(fromId, toId); + + if (fromId === toId) { + const list = Immutable.List(reorderImmutable(this.state[fromId], previousIndex, nextIndex)); + + var state = {}; + + state[fromId] = list; + + this.setState(state); + } else { + var lists = reorderFromToImmutable({ + from: this.state[fromId], + to: this.state[toId], + }, previousIndex, nextIndex); + + this.setState({ + listA: fromId === 'listA' ? lists.from : lists.to, + listB: fromId === 'listB' ? lists.from : lists.to + }); + } } onDisableToggle () { @@ -290,7 +310,7 @@ class Main extends Component { onReorder={this.onReorderGroup.bind(this)} > { - this.state.multiList1.map(function (item) { + this.state.listA.map(function (item) { return (
  • { - this.state.multiList2.map(function (item) { + this.state.listB.map(function (item) { return (
  • Date: Wed, 22 Feb 2017 20:56:22 +0000 Subject: [PATCH 211/292] Allow multi list to be dropped on empty list --- src/index.js | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index 9cb4d1e9..ae90ab67 100644 --- a/src/index.js +++ b/src/index.js @@ -291,15 +291,15 @@ } }, - xCollision: function (rect, event) { + xCollision: function (event, rect) { return event.clientX >= rect.left && event.clientX <= rect.right; }, - yCollision: function (rect, event) { + yCollision: function (event, rect) { return event.clientY >= rect.top && event.clientY <= rect.bottom; }, - findCollisionIndex: function (listElements, event) { + findCollisionIndex: function (event, listElements) { for (var i = 0; i < listElements.length; i += 1) { if (!listElements[i].getAttribute('data-placeholder') && !listElements[i].getAttribute('data-dragged')) { @@ -307,17 +307,17 @@ switch (this.props.lock) { case 'horizontal': - if (this.yCollision(rect, event)) { + if (this.yCollision(event, rect)) { return i; } break; case 'vertical': - if (this.xCollision(rect, event)) { + if (this.xCollision(event, rect)) { return i; } break; default: - if (this.yCollision(rect, event) && this.xCollision(rect, event)) { + if (this.yCollision(event, rect) && this.xCollision(event, rect)) { return i; } break; @@ -330,6 +330,11 @@ return -1; }, + collidesWithElement: function (event, element) { + var rect = element.getBoundingClientRect(); + return this.yCollision(event, rect) && this.xCollision(event, rect); + }, + getHoldTime: function (event) { if (event.touches && typeof this.props.touchHoldTime !== 'undefined') { return parseInt(this.props.touchHoldTime, 10) || 0; @@ -511,14 +516,21 @@ event.clientX - mouseDownOffset.clientX : this.state.draggedStyle.left }); - var children = ReactDOM.findDOMNode(this).childNodes; - var collisionIndex = this.findCollisionIndex(children, event); + var element = ReactDOM.findDOMNode(this); + var children = element.childNodes; + var collisionIndex = this.findCollisionIndex(event, children); if ( collisionIndex <= this.props.children.length && collisionIndex >= 0 ) { store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, collisionIndex); + } else if ( + typeof this.props.reorderGroup !== 'undefined' && + (!this.props.children || !this.props.children.length) && + this.collidesWithElement(event, element) + ) { + store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, 0); } store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); From afc5c01e96dabf6e586e290adc26133a77666086 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 20:56:56 +0000 Subject: [PATCH 212/292] Remove log from examples --- examples/src/js/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 01347230..ad7dc4db 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -127,8 +127,6 @@ class Main extends Component { } onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { - console.log(fromId, toId); - if (fromId === toId) { const list = Immutable.List(reorderImmutable(this.state[fromId], previousIndex, nextIndex)); From 40121dcb4150c29e528efec3a4dc2034a55d6158 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 21:01:32 +0000 Subject: [PATCH 213/292] Allow dragging mutli list back to now empty list --- src/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index ae90ab67..56071f6a 100644 --- a/src/index.js +++ b/src/index.js @@ -526,8 +526,11 @@ ) { store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, collisionIndex); } else if ( - typeof this.props.reorderGroup !== 'undefined' && - (!this.props.children || !this.props.children.length) && + typeof this.props.reorderGroup !== 'undefined' && // Is part of a group + ( + (!this.props.children || !this.props.children.length) || // If all items removed + (this.isDraggingFrom() && this.props.children.length === 1) // If dragging back to a now empty list + ) && this.collidesWithElement(event, element) ) { store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, 0); From 011f60c68caa8abf50dd36485f0b05118781d909 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 21:03:14 +0000 Subject: [PATCH 214/292] Fix linting --- examples/src/js/index.js | 6 +++--- src/index.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index ad7dc4db..cecddc80 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -130,15 +130,15 @@ class Main extends Component { if (fromId === toId) { const list = Immutable.List(reorderImmutable(this.state[fromId], previousIndex, nextIndex)); - var state = {}; + const state = {}; state[fromId] = list; this.setState(state); } else { - var lists = reorderFromToImmutable({ + const lists = reorderFromToImmutable({ from: this.state[fromId], - to: this.state[toId], + to: this.state[toId] }, previousIndex, nextIndex); this.setState({ diff --git a/src/index.js b/src/index.js index 56071f6a..62bc029e 100644 --- a/src/index.js +++ b/src/index.js @@ -212,7 +212,7 @@ var nextList = [].concat(lists.to); var item = previousList.splice(previousIndex, 1); - nextList.splice(nextList, 0, item); + nextList.splice(nextIndex, 0, item); return { from: previousList, From 4b4984970b905198f99c035eaafa38829b6c40aa Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 21:08:02 +0000 Subject: [PATCH 215/292] Prevent dragging if moved --- src/index.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/index.js b/src/index.js index 62bc029e..2843e3ec 100644 --- a/src/index.js +++ b/src/index.js @@ -497,16 +497,16 @@ onWindowMove: function (event) { this.copyTouchKeys(event); - if (this.isDragging() && this.isInvolvedInDragging()) { - if ( - downPos && ( - Math.abs(event.clientX - downPos.clientX) >= CONSTANTS.HOLD_THRESHOLD || - Math.abs(event.clientY - downPos.clientY) >= CONSTANTS.HOLD_THRESHOLD - ) - ) { - this.moved = true; - } + if ( + downPos && ( + Math.abs(event.clientX - downPos.clientX) >= CONSTANTS.HOLD_THRESHOLD || + Math.abs(event.clientY - downPos.clientY) >= CONSTANTS.HOLD_THRESHOLD + ) + ) { + this.moved = true; + } + if (this.isDragging() && this.isInvolvedInDragging()) { this.preventNativeScrolling(event); var draggedStyle = assign({}, this.state.draggedStyle, { From 78543c744cbfc102bfbe562185ea44e9726bd8e0 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 22 Feb 2017 21:12:38 +0000 Subject: [PATCH 216/292] Update multi list input styling & default value --- examples/src/js/index.js | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index cecddc80..fb1145a6 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -211,7 +211,11 @@ class Main extends Component { {this.state.prefix} {item.name} - +
  • ); @@ -315,8 +319,16 @@ class Main extends Component { className={[classNames.listItem, classNames.multiListItem].join(' ')} style={{color: item.color}} > - {item.name} - +
    + + {item.name} + + +
    ); }.bind(this)).toArray() @@ -340,8 +352,16 @@ class Main extends Component { className={[classNames.listItem, classNames.multiListItem].join(' ')} style={{color: item.color}} > - {item.name} - +
    + + {item.name} + + +
    ); }.bind(this)).toArray() From 47e208ef03e01f096bfddeaa007f8937932501a7 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 14:41:39 +0000 Subject: [PATCH 217/292] No need to create new Immutable Lists --- examples/src/js/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index fb1145a6..24a50a9e 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -119,7 +119,7 @@ class Main extends Component { } onReorder (event, previousIndex, nextIndex) { - const list = Immutable.List(reorderImmutable(this.state.list, previousIndex, nextIndex)); + const list = reorderImmutable(this.state.list, previousIndex, nextIndex); this.setState({ list: list @@ -128,7 +128,7 @@ class Main extends Component { onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { if (fromId === toId) { - const list = Immutable.List(reorderImmutable(this.state[fromId], previousIndex, nextIndex)); + const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); const state = {}; From 25327ff0056afe0596cfbea735ff8c8dd57c4cb4 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 14:41:51 +0000 Subject: [PATCH 218/292] Update readme with new API --- README.md | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index cc2ca078..c96847fd 100644 --- a/README.md +++ b/README.md @@ -51,17 +51,19 @@ It also allows the user to set a hold time (duration before drag begins) allowin ```javascript // Custom placeholder element (optional), defaults to clone of dragged element } @@ -84,18 +86,40 @@ It also allows the user to set a hold time (duration before drag begins) allowin 5. Callback functions - * The `onReorder` function that is called once a reorder has been performed + * The `onReorder` function that is called once a reorder has been performed. + You can use our helper functions for reordering your arrays. ```javascript - function onReorder(event, fromIndex, toIndex) { - // You can use our helper functions for reordering your arrays (reorderImmutable is also available) + import { reorder, reorderImmutable, reorderFromTo, reorderFromToImmutable } from 'react-reorder'; + + onReorder (event, previousIndex, nextIndex, fromId, toId) { this.setState({ myList: reorder(this.state.myList, fromIndex, toIndex); }); } - ``` - **Note: `event` will be the synthetic React event for either `mouseup` or `touchend`, and both contain `clientX` & `clientY` values (for ease of use)** + onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { + if (fromId === toId) { + const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); + + const state = {}; + + state[fromId] = list; + + this.setState(state); + } else { + const lists = reorderFromToImmutable({ + from: this.state[fromId], + to: this.state[toId] + }, previousIndex, nextIndex); + + this.setState({ + listA: fromId === 'listA' ? lists.from : lists.to, + listB: fromId === 'listB' ? lists.from : lists.to + }); + } + } + ``` ## Compatibility / Requirements From d21fa30394969175824ad43694235b31bbe332a8 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 14:45:20 +0000 Subject: [PATCH 219/292] Improve example reordering --- README.md | 12 +++++------- examples/src/js/index.js | 12 +++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index c96847fd..72739181 100644 --- a/README.md +++ b/README.md @@ -102,11 +102,9 @@ It also allows the user to set a hold time (duration before drag begins) allowin if (fromId === toId) { const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); - const state = {}; - - state[fromId] = list; - - this.setState(state); + this.setState({ + [fromId]: list + }); } else { const lists = reorderFromToImmutable({ from: this.state[fromId], @@ -114,8 +112,8 @@ It also allows the user to set a hold time (duration before drag begins) allowin }, previousIndex, nextIndex); this.setState({ - listA: fromId === 'listA' ? lists.from : lists.to, - listB: fromId === 'listB' ? lists.from : lists.to + [fromId]: lists.from, + [toId]: lists.to }); } } diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 24a50a9e..802dcd61 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -130,11 +130,9 @@ class Main extends Component { if (fromId === toId) { const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); - const state = {}; - - state[fromId] = list; - - this.setState(state); + this.setState({ + [fromId]: list + }); } else { const lists = reorderFromToImmutable({ from: this.state[fromId], @@ -142,8 +140,8 @@ class Main extends Component { }, previousIndex, nextIndex); this.setState({ - listA: fromId === 'listA' ? lists.from : lists.to, - listB: fromId === 'listB' ? lists.from : lists.to + [fromId]: lists.from, + [toId]: lists.to }); } } From 6692ea1aa6a2f8fa255c4b8969d2f20cc39a0073 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 14:54:45 +0000 Subject: [PATCH 220/292] Update test setup --- .babelrc | 9 ++++++++- .mocharc | 4 ++++ .nycrc | 11 ++++------- package.json | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 .mocharc diff --git a/.babelrc b/.babelrc index bd20dc17..737c9944 100644 --- a/.babelrc +++ b/.babelrc @@ -2,5 +2,12 @@ "presets": [ "es2015", "react" - ] + ], + "env": { + "mocha": { + "plugins": [ + "istanbul" + ] + } + } } diff --git a/.mocharc b/.mocharc new file mode 100644 index 00000000..4a66a5eb --- /dev/null +++ b/.mocharc @@ -0,0 +1,4 @@ +--require babel-core/register +--require tests/helpers/test-setup.js +--bail +--recursive diff --git a/.nycrc b/.nycrc index f8b6f612..4f58f05e 100644 --- a/.nycrc +++ b/.nycrc @@ -3,10 +3,7 @@ "statements": 100, "functions": 100, "branches": 100, - "require": [ - "babel-core/register", - "./tests/helpers/test-setup.js" - ], + "require": [], "include": [ "src/**/*.js", "tests/helpers/mount.js", @@ -23,7 +20,7 @@ "cache": true, "all": true, "check-coverage": true, - "sourceMap": true, - "instrument": true, - "report-dir": "./coverage" + "sourceMap": false, + "instrument": false, + "report-dir": "coverage" } diff --git a/package.json b/package.json index b8442d36..1bf36d05 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "lint-src": "eslint -c .eslintrc-src.json src/", "lint-examples": "eslint -c .eslintrc-examples.json examples/src/js/", "lint-tests": "eslint -c .eslintrc-tests.json tests/", - "mocha": "nyc mocha --bail --recursive 'tests/**/*.test.js'", + "mocha": "BABEL_ENV=mocha nyc mocha --opts .mocharc 'tests/**/*.test.js'", "test": "npm run lint-src && npm run lint-examples && npm run lint-tests && npm run mocha" }, "bugs": "https://github.com/JakeSidSmith/react-reorder/issues", From eeecda9ba55e04a9d4cb0ddc6896256b331bd9b1 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 15:02:51 +0000 Subject: [PATCH 221/292] Add reorderIds and unmount in tests --- tests/basic.test.js | 36 ++++++++++++++++++++++-------- tests/methods.test.js | 52 ++++++++++++++++++++++++++++++++----------- 2 files changed, 66 insertions(+), 22 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index 51c305fe..7f14dfaa 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -47,7 +47,7 @@ describe('basic', function () { it('should render itself & its children', function () { const wrapper = mount( - + { items.map((item) => ( @@ -66,11 +66,13 @@ describe('basic', function () { children.forEach(function (child) { expect(child.tagName()).to.equal('span'); }); + + wrapper.unmount(); }); it('should have a name & default props', function () { const wrapper = mount( - + { items.map((item) => ( @@ -89,13 +91,17 @@ describe('basic', function () { expect(props.placeholderClassName).to.equal('placeholder'); expect(props.draggedClassName).to.equal('dragged'); expect(props.holdTime).to.equal(0); + + wrapper.unmount(); }); it('should store a reference to its root node', function () { - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); expect(instance.rootNode).to.be.ok; + + wrapper.unmount(); }); }); @@ -103,9 +109,11 @@ describe('basic', function () { describe('props', function () { it('should allow defining the root component (string)', function () { - const wrapper = mount(); + const wrapper = mount(); expect(wrapper.tagName()).to.equal('ul'); + + wrapper.unmount(); }); it('should allow defining the root component (function)', function () { @@ -113,10 +121,12 @@ describe('basic', function () { return

    ; } - const wrapper = mount(); + const wrapper = mount(); expect(wrapper.name()).to.equal('Reorder'); expect(wrapper.tagName()).to.equal('h1'); + + wrapper.unmount(); }); it('should allow defining the root component (component)', function () { @@ -126,18 +136,22 @@ describe('basic', function () { } } - const wrapper = mount(); + const wrapper = mount(); expect(wrapper.name()).to.equal('Reorder'); expect(wrapper.tagName()).to.equal('h2'); + + wrapper.unmount(); }); it('should call a ref function (if provided) with the root element', function () { const refSpy = spy(); - mount(); + const wrapper = mount(); expect(refSpy).to.have.been.calledOnce; + + wrapper.unmount(); }); }); @@ -156,7 +170,7 @@ describe('basic', function () { 'contextmenu' ]; - const wrapper = mount(); + const wrapper = mount(); expect(addEventListenerSpy).to.have.been.called; expect(removeEventListenerSpy).not.to.have.been.called; @@ -181,13 +195,15 @@ describe('basic', function () { addEventListenerSpy.restore(); removeEventListenerSpy.restore(); + + wrapper.unmount(); }); it('should clear timeouts & intervals on unmount', function () { const clearTimeoutSpy = spy(global, 'clearTimeout'); const clearIntervalSpy = spy(global, 'clearInterval'); - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); instance.holdTimeout = { @@ -207,6 +223,8 @@ describe('basic', function () { clearTimeoutSpy.restore(); clearIntervalSpy.restore(); + + wrapper.unmount(); }); }); diff --git a/tests/methods.test.js b/tests/methods.test.js index 52e2e8a1..532084b8 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -9,7 +9,7 @@ import { verticalChildren, horizontalChildren } from './helpers/children-stub'; describe('methods', function () { it('should return true if the draggedIndex is greater than or equal to zero', function () { - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); expect(instance.isDragging()).to.be.false; @@ -21,6 +21,8 @@ describe('methods', function () { wrapper.setState({draggedIndex: 10}); expect(instance.isDragging()).to.be.true; + + wrapper.unmount(); }); it('should preventDefault on events', function () { @@ -28,7 +30,7 @@ describe('methods', function () { preventDefault: spy() }; - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); expect(event.preventDefault).not.to.have.been.called; @@ -40,12 +42,14 @@ describe('methods', function () { expect(event.preventDefault).not.to.have.been.called; instance.preventNativeScrolling(event); expect(event.preventDefault).to.have.been.calledOnce; + + wrapper.unmount(); }); it('should persist an event if available', function () { const event = {}; - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); instance.persistEvent(event); @@ -57,6 +61,8 @@ describe('methods', function () { instance.persistEvent(event); expect(event.persist).to.have.been.calledOnce; + + wrapper.unmount(); }); it('should copy clientX and clientY from touches & persist event', function () { @@ -64,7 +70,7 @@ describe('methods', function () { persist: spy() }; - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); expect(event.persist).not.to.have.been.called; @@ -87,10 +93,12 @@ describe('methods', function () { expect(event.persist).to.have.been.calledOnce; expect(event.clientX).to.equal(123); expect(event.clientY).to.equal(456); + + wrapper.unmount(); }); it('should check a collision on the x-axis', function () { - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); const rect = { @@ -115,10 +123,12 @@ describe('methods', function () { event.clientX = 100; expect(instance.xCollision(rect, event)).to.be.true; + + wrapper.unmount(); }); it('should check a collision on the y-axis', function () { - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); const rect = { @@ -143,10 +153,12 @@ describe('methods', function () { event.clientY = 80; expect(instance.yCollision(rect, event)).to.be.true; + + wrapper.unmount(); }); it('should find the first collision of the pointer & children (no lock)', function () { - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); const event = { @@ -190,10 +202,12 @@ describe('methods', function () { event.clientY = 130; expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + wrapper.unmount(); }); it('should find the first collision of the pointer & children (horizontal)', function () { - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); const event = { @@ -237,10 +251,12 @@ describe('methods', function () { event.clientY = 130; expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + + wrapper.unmount(); }); it('should find the first collision of the pointer & children (vertical)', function () { - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); const event = { @@ -284,10 +300,12 @@ describe('methods', function () { event.clientY = 130; expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); + + wrapper.unmount(); }); it('should return the relevant holdTime', function () { - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); expect(instance.getHoldTime({})).to.equal(0); @@ -317,12 +335,14 @@ describe('methods', function () { expect(instance.getHoldTime({})).to.equal(0); expect(instance.getHoldTime({touches: []})).to.equal(0); + + wrapper.unmount(); }); it('should return the scroll offset x for auto-scrolling (max scroll area)', function () { const maxScrollArea = 50; const scrollSpeed = 20; - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); const rect = { @@ -352,12 +372,14 @@ describe('methods', function () { expect(instance.getScrollOffsetX(rect, node, {clientX: maxScrollArea * 1.5})).to.equal(-scrollSpeed / 2); expect(instance.getScrollOffsetX(rect, node, {clientX: maxScrollArea * 4.5})).to.equal(scrollSpeed / 2); + + wrapper.unmount(); }); it('should return the scroll offset y for auto-scrolling (max scroll area)', function () { const maxScrollArea = 50; const scrollSpeed = 20; - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); const rect = { @@ -387,10 +409,12 @@ describe('methods', function () { expect(instance.getScrollOffsetY(rect, node, {clientY: maxScrollArea * 1.5})).to.equal(-scrollSpeed / 2); expect(instance.getScrollOffsetY(rect, node, {clientY: maxScrollArea * 4.5})).to.equal(scrollSpeed / 2); + + wrapper.unmount(); }); it('should scroll the root node if auto-scroll enabled & pointer is in the right location', function () { - const wrapper = mount(); + const wrapper = mount(); const instance = wrapper.instance(); expect(instance.rootNode).to.be.ok; @@ -442,6 +466,8 @@ describe('methods', function () { expect(instance.rootNode.scrollLeft).to.equal(70); instance.rootNode.getBoundingClientRect.restore(); + + wrapper.unmount(); }); }); From 0426eab23e5734b595d572f2f764c396ffdae485 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 15:06:33 +0000 Subject: [PATCH 222/292] Context menu typo --- src/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 2843e3ec..b0665704 100644 --- a/src/index.js +++ b/src/index.js @@ -267,7 +267,7 @@ }, preventContextMenu: function (event) { - if (downPos && this.props.disableContentMenus) { + if (downPos && this.props.disableContextMenus) { event.preventDefault(); } }, @@ -649,7 +649,7 @@ placeholder: PropTypes.element, autoScroll: PropTypes.bool, disabled: PropTypes.bool, - disableContentMenus: PropTypes.bool + disableContextMenus: PropTypes.bool }; Reorder.defaultProps = { @@ -666,7 +666,7 @@ // placeholder: react element autoScroll: true, disabled: false, - disableContentMenus: true + disableContextMenus: true }; return Reorder; From 8cc871eee1768ef1f3d3707c8cd435ee84fd4986 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 15:06:46 +0000 Subject: [PATCH 223/292] Add info about disableContextMenu to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 72739181..f5cc0729 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ It also allows the user to set a hold time (duration before drag begins) allowin onReorder={this.onReorder.bind(this)} // Callback when an item is dropped (you will need this to update your state) autoScroll={true} // Enable auto-scrolling when the pointer is close to the edge of the Reorder component (optional), defaults to true disabled={false} // Disable reordering (optional), defaults to false + disableContextMenus={true} // Disable context menus when holding on touch devices (optional), defaults to true placeholder={
    // Custom placeholder element (optional), defaults to clone of dragged element } From 3866835b12136ffbe9d6c63201ae2ee6bbfcf4b1 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 15:07:30 +0000 Subject: [PATCH 224/292] Update preventDefault tests --- tests/methods.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/methods.test.js b/tests/methods.test.js index 532084b8..e1cd76b3 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -34,14 +34,14 @@ describe('methods', function () { const instance = wrapper.instance(); expect(event.preventDefault).not.to.have.been.called; - instance.preventDefault(event); + instance.preventNativeScrolling(event); expect(event.preventDefault).to.have.been.calledOnce; event.preventDefault.reset(); expect(event.preventDefault).not.to.have.been.called; - instance.preventNativeScrolling(event); - expect(event.preventDefault).to.have.been.calledOnce; + instance.preventContextMenu(event); + expect(event.preventDefault).not.to.have.been.called; wrapper.unmount(); }); From 6aa581547022dbc67b9018ef110581337135adeb Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 15:13:09 +0000 Subject: [PATCH 225/292] Update collision tests --- tests/methods.test.js | 70 +++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/methods.test.js b/tests/methods.test.js index e1cd76b3..41061df9 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -110,19 +110,19 @@ describe('methods', function () { clientX: 20 }; - expect(instance.xCollision(rect, event)).to.be.false; + expect(instance.xCollision(event, rect)).to.be.false; event.clientX = 120; - expect(instance.xCollision(rect, event)).to.be.false; + expect(instance.xCollision(event, rect)).to.be.false; event.clientX = 80; - expect(instance.xCollision(rect, event)).to.be.true; + expect(instance.xCollision(event, rect)).to.be.true; event.clientX = 100; - expect(instance.xCollision(rect, event)).to.be.true; + expect(instance.xCollision(event, rect)).to.be.true; wrapper.unmount(); }); @@ -140,19 +140,19 @@ describe('methods', function () { clientY: 10 }; - expect(instance.yCollision(rect, event)).to.be.false; + expect(instance.yCollision(event, rect)).to.be.false; event.clientY = 100; - expect(instance.yCollision(rect, event)).to.be.false; + expect(instance.yCollision(event, rect)).to.be.false; event.clientY = 50; - expect(instance.yCollision(rect, event)).to.be.true; + expect(instance.yCollision(event, rect)).to.be.true; event.clientY = 80; - expect(instance.yCollision(rect, event)).to.be.true; + expect(instance.yCollision(event, rect)).to.be.true; wrapper.unmount(); }); @@ -166,42 +166,42 @@ describe('methods', function () { clientY: 0 }; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); event.clientX = 30; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); event.clientY = 30; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(0); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(0); event.clientY = 50; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); event.clientY = 70; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); event.clientY = 90; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(3); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(3); event.clientX = 200; event.clientY = 110; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); event.clientX = 50; event.clientY = 110; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(4); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(4); event.clientX = 50; event.clientY = 130; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); wrapper.unmount(); }); @@ -215,42 +215,42 @@ describe('methods', function () { clientY: 0 }; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); event.clientY = 30; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(0); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(0); event.clientX = 30; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(0); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(0); event.clientY = 50; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); event.clientY = 70; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); event.clientY = 90; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(3); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(3); event.clientX = 200; event.clientY = 110; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(4); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(4); event.clientX = 50; event.clientY = 110; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(4); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(4); event.clientX = 50; event.clientY = 130; - expect(instance.findCollisionIndex(verticalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, verticalChildren)).to.equal(-1); wrapper.unmount(); }); @@ -264,42 +264,42 @@ describe('methods', function () { clientY: 0 }; - expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, horizontalChildren)).to.equal(-1); event.clientX = 30; - expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(0); + expect(instance.findCollisionIndex(event, horizontalChildren)).to.equal(0); event.clientY = 30; - expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(0); + expect(instance.findCollisionIndex(event, horizontalChildren)).to.equal(0); event.clientX = 150; - expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, horizontalChildren)).to.equal(-1); event.clientX = 250; - expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, horizontalChildren)).to.equal(-1); event.clientX = 350; - expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(3); + expect(instance.findCollisionIndex(event, horizontalChildren)).to.equal(3); event.clientX = 450; event.clientY = 110; - expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(4); + expect(instance.findCollisionIndex(event, horizontalChildren)).to.equal(4); event.clientX = 450; event.clientY = 0; - expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(4); + expect(instance.findCollisionIndex(event, horizontalChildren)).to.equal(4); event.clientX = 550; event.clientY = 130; - expect(instance.findCollisionIndex(horizontalChildren, event)).to.equal(-1); + expect(instance.findCollisionIndex(event, horizontalChildren)).to.equal(-1); wrapper.unmount(); }); From 9baa8bb57dbdfe4a2a4139da56c7d90676683e1a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:01:21 +0000 Subject: [PATCH 226/292] Fix scroll offset tests --- src/index.js | 18 ++++++++++-------- tests/methods.test.js | 44 +++++++++++++++++++++++++++---------------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/index.js b/src/index.js index b0665704..0d39754f 100644 --- a/src/index.js +++ b/src/index.js @@ -346,38 +346,40 @@ }, getScrollOffsetX: function (rect, node) { + var positionInScrollArea; var scrollLeft = node.scrollLeft; var scrollWidth = node.scrollWidth; var scrollAreaX = Math.min(rect.width / 3, CONSTANTS.SCROLL_AREA_MAX); if (scrollLeft > 0 && mouseOffset.clientX <= rect.left + scrollAreaX) { - return -Math.min(Math.abs(rect.left + scrollAreaX - mouseOffset.clientX), scrollAreaX) / - scrollAreaX * CONSTANTS.SCROLL_SPEED; + positionInScrollArea = Math.min(Math.abs(rect.left + scrollAreaX - mouseOffset.clientX), scrollAreaX); + return -positionInScrollArea / scrollAreaX * CONSTANTS.SCROLL_SPEED; } if (scrollLeft < scrollWidth - rect.width && mouseOffset.clientX >= rect.right - scrollAreaX) { - return Math.min(Math.abs(rect.right - scrollAreaX - mouseOffset.clientX), scrollAreaX) / - scrollAreaX * CONSTANTS.SCROLL_SPEED; + positionInScrollArea = Math.min(Math.abs(rect.right - scrollAreaX - mouseOffset.clientX), scrollAreaX); + return positionInScrollArea / scrollAreaX * CONSTANTS.SCROLL_SPEED; } return 0; }, getScrollOffsetY: function (rect, node) { + var positionInScrollArea; var scrollTop = node.scrollTop; var scrollHeight = node.scrollHeight; var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); if (scrollTop > 0 && mouseOffset.clientY <= rect.top + scrollAreaY) { - return -Math.min(Math.abs(rect.top + scrollAreaY - mouseOffset.clientY), scrollAreaY) / - scrollAreaY * CONSTANTS.SCROLL_SPEED; + positionInScrollArea = Math.min(Math.abs(rect.top + scrollAreaY - mouseOffset.clientY), scrollAreaY); + return -positionInScrollArea / scrollAreaY * CONSTANTS.SCROLL_SPEED; } if (scrollTop < scrollHeight - rect.height && mouseOffset.clientY >= rect.bottom - scrollAreaY) { - return Math.min(Math.abs(rect.bottom - scrollAreaY - mouseOffset.clientY), scrollAreaY) / - scrollAreaY * CONSTANTS.SCROLL_SPEED; + positionInScrollArea = Math.min(Math.abs(rect.bottom - scrollAreaY - mouseOffset.clientY), scrollAreaY); + return positionInScrollArea / scrollAreaY * CONSTANTS.SCROLL_SPEED; } return 0; diff --git a/tests/methods.test.js b/tests/methods.test.js index 41061df9..0c268b32 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -342,7 +342,7 @@ describe('methods', function () { it('should return the scroll offset x for auto-scrolling (max scroll area)', function () { const maxScrollArea = 50; const scrollSpeed = 20; - const wrapper = mount(); + const wrapper = mount({[
  • Item
  • ]}
    ); const instance = wrapper.instance(); const rect = { @@ -363,23 +363,29 @@ describe('methods', function () { const expectedScrollOffsets = [-scrollSpeed, -scrollSpeed, 0, 0, 0, scrollSpeed, scrollSpeed]; - for (let i = 0; i < expectedScrollOffsets.length; i += 1) { - const expectedScrollOffset = expectedScrollOffsets[i]; - const mouseOffset = {clientX: maxScrollArea * i}; + const listItem = wrapper.find('li'); + + expectedScrollOffsets.forEach(function (expectedScrollOffset, index) { + const event = {clientX: maxScrollArea * index}; - expect(instance.getScrollOffsetX(rect, node, mouseOffset)).to.equal(expectedScrollOffset); - } + listItem.trigger('mouseDown', event); + + expect(instance.getScrollOffsetX(rect, node)).to.equal(expectedScrollOffset); + }); - expect(instance.getScrollOffsetX(rect, node, {clientX: maxScrollArea * 1.5})).to.equal(-scrollSpeed / 2); - expect(instance.getScrollOffsetX(rect, node, {clientX: maxScrollArea * 4.5})).to.equal(scrollSpeed / 2); + listItem.trigger('mouseDown', {clientX: maxScrollArea * 1.5}); + expect(instance.getScrollOffsetX(rect, node)).to.equal(-scrollSpeed / 2); + listItem.trigger('mouseDown', {clientX: maxScrollArea * 4.5}); + expect(instance.getScrollOffsetX(rect, node)).to.equal(scrollSpeed / 2); + instance.onWindowUp(); // Stop drag wrapper.unmount(); }); it('should return the scroll offset y for auto-scrolling (max scroll area)', function () { const maxScrollArea = 50; const scrollSpeed = 20; - const wrapper = mount(); + const wrapper = mount({[
  • Item
  • ]}
    ); const instance = wrapper.instance(); const rect = { @@ -400,16 +406,22 @@ describe('methods', function () { const expectedScrollOffsets = [-scrollSpeed, -scrollSpeed, 0, 0, 0, scrollSpeed, scrollSpeed]; - for (let i = 0; i < expectedScrollOffsets.length; i += 1) { - const expectedScrollOffset = expectedScrollOffsets[i]; - const mouseOffset = {clientY: maxScrollArea * i}; + const listItem = wrapper.find('li'); + + expectedScrollOffsets.forEach(function (expectedScrollOffset, index) { + const event = {clientY: maxScrollArea * index}; - expect(instance.getScrollOffsetY(rect, node, mouseOffset)).to.equal(expectedScrollOffset); - } + listItem.trigger('mouseDown', event); + + expect(instance.getScrollOffsetY(rect, node)).to.equal(expectedScrollOffset); + }); - expect(instance.getScrollOffsetY(rect, node, {clientY: maxScrollArea * 1.5})).to.equal(-scrollSpeed / 2); - expect(instance.getScrollOffsetY(rect, node, {clientY: maxScrollArea * 4.5})).to.equal(scrollSpeed / 2); + listItem.trigger('mouseDown', {clientY: maxScrollArea * 1.5}); + expect(instance.getScrollOffsetY(rect, node)).to.equal(-scrollSpeed / 2); + listItem.trigger('mouseDown', {clientY: maxScrollArea * 4.5}); + expect(instance.getScrollOffsetY(rect, node)).to.equal(scrollSpeed / 2); + instance.onWindowUp(); // Stop drag wrapper.unmount(); }); From 075e8c7263d8c037f987412f1f9b6a7a76be1af0 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:04:59 +0000 Subject: [PATCH 227/292] Fix auto-scroll tests --- tests/methods.test.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/tests/methods.test.js b/tests/methods.test.js index 0c268b32..36e5a7f3 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -426,8 +426,9 @@ describe('methods', function () { }); it('should scroll the root node if auto-scroll enabled & pointer is in the right location', function () { - const wrapper = mount(); + const wrapper = mount({[
  • Item
  • ]}
    ); const instance = wrapper.instance(); + const listItem = wrapper.find('li'); expect(instance.rootNode).to.be.ok; @@ -447,22 +448,31 @@ describe('methods', function () { instance.rootNode.scrollHeight = 200; instance.rootNode.scrollWidth = 200; - instance.mouseOffset = { + listItem.trigger('mouseDown', { clientY: 50, clientX: 50 - }; + }); instance.autoScroll(); expect(instance.rootNode.scrollTop).to.equal(50); expect(instance.rootNode.scrollLeft).to.equal(50); - instance.mouseOffset.clientY = 100; + listItem.trigger('mouseDown', { + clientY: 100, + clientX: 50 + }); + instance.autoScroll(); expect(instance.rootNode.scrollTop).to.equal(70); expect(instance.rootNode.scrollLeft).to.equal(50); wrapper.setProps({lock: 'vertical'}); - instance.mouseOffset.clientX = 100; + + listItem.trigger('mouseDown', { + clientY: 100, + clientX: 100 + }); + instance.autoScroll(); expect(instance.rootNode.scrollTop).to.equal(70); expect(instance.rootNode.scrollLeft).to.equal(70); @@ -479,6 +489,7 @@ describe('methods', function () { instance.rootNode.getBoundingClientRect.restore(); + instance.onWindowUp(); // Stop drag wrapper.unmount(); }); From bf45364a1e40470071ef79338d66fd520eebc3d0 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:11:26 +0000 Subject: [PATCH 228/292] Test reorderFromTo helpers & fix array function --- src/index.js | 2 +- tests/basic.test.js | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 0d39754f..df348f3b 100644 --- a/src/index.js +++ b/src/index.js @@ -211,7 +211,7 @@ var previousList = [].concat(lists.from); var nextList = [].concat(lists.to); - var item = previousList.splice(previousIndex, 1); + var item = previousList.splice(previousIndex, 1)[0]; nextList.splice(nextIndex, 0, item); return { diff --git a/tests/basic.test.js b/tests/basic.test.js index 7f14dfaa..ebc8cb0a 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -4,7 +4,7 @@ import mount from './helpers/mount'; import React, { Component } from 'react'; import { List } from 'immutable'; -import Reorder, { reorder, reorderImmutable } from '../src/index'; +import Reorder, { reorder, reorderImmutable, reorderFromTo, reorderFromToImmutable } from '../src/index'; describe('basic', function () { @@ -249,6 +249,26 @@ describe('basic', function () { expect(reordered.toJS()).to.eql([5, 1, 2, 3, 4]); }); + it('should reorder an item from one array to another', function () { + const from = [1, 2, 3, 4, 5]; + const to = [1, 2, 3, 4, 5]; + + const reordered = reorderFromTo({from, to}, 0, 2); + + expect(reordered.from).to.eql([2, 3, 4, 5]); + expect(reordered.to).to.eql([1, 2, 1, 3, 4, 5]); + }); + + it('should reorder an item from one array to another', function () { + const from = List([1, 2, 3, 4, 5]); + const to = List([1, 2, 3, 4, 5]); + + const reordered = reorderFromToImmutable({from, to}, 4, 1); + + expect(reordered.from.toJS()).to.eql([1, 2, 3, 4]); + expect(reordered.to.toJS()).to.eql([1, 5, 2, 3, 4, 5]); + }); + }); }); From d8a14d544e1f9471043c79b2c85e1034dff3ee09 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:13:28 +0000 Subject: [PATCH 229/292] Do not enforce coverage --- .nycrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nycrc b/.nycrc index 4f58f05e..3b31fc89 100644 --- a/.nycrc +++ b/.nycrc @@ -19,7 +19,7 @@ ], "cache": true, "all": true, - "check-coverage": true, + "check-coverage": false, "sourceMap": false, "instrument": false, "report-dir": "coverage" From e1658da70e04711bd1295a382c3da3c493a9bf47 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:16:39 +0000 Subject: [PATCH 230/292] Add getRef prop type --- src/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/index.js b/src/index.js index df348f3b..ab4dfb96 100644 --- a/src/index.js +++ b/src/index.js @@ -639,6 +639,7 @@ Reorder.propTypes = { component: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), + getRef: PropTypes.func, reorderId: PropTypes.string, reorderGroup: PropTypes.string, placeholderClassName: PropTypes.string, @@ -656,6 +657,7 @@ Reorder.defaultProps = { component: 'div', + // getRef: function, // reorderId: id, // reorderGroup: group, placeholderClassName: 'placeholder', From 452252d1483f32774a7f9b87afb247dd37b92284 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:28:48 +0000 Subject: [PATCH 231/292] Tidy up readme --- README.md | 212 +++++++++++++++++++++++------------------------------- 1 file changed, 90 insertions(+), 122 deletions(-) diff --git a/README.md b/README.md index f5cc0729..4038d455 100644 --- a/README.md +++ b/README.md @@ -12,142 +12,110 @@ It also allows the user to set a hold time (duration before drag begins) allowin ## Installation -* Using npm - ``` - npm install react-reorder - ``` - Add `--save` or `-S` to update your package.json - -* Using bower - ``` - bower install react-reorder - ``` - Add `--save` or `-S` to update your bower.json +Using npm -## Example - -1. If using requirejs: add `react-reorder` to your `require.config` +Add `--save` or `-S` to update your package.json - ```javascript - paths: - // : - 'react-reorder': 'react-reorder/reorder' - } - ``` - -2. If using a module loader (requirejs / browserfiy / commonjs): require `react-reorder` where it will be used in your project - - ```javascript - var Reorder = require('react-reorder'); - var reorder = Reorder.reorder; - var reorderImmutable = Reorder.reorderImmutable; - - // Or ES6 - - import Reorder, { reorder, reorderImmutable } from 'react-reorder'; - ``` - -3. Configuration - - ```javascript - // Custom placeholder element (optional), defaults to clone of dragged element - } - > - { - this.state.list.map((item) => ( -
  • - {item.name} -
  • - )).toArray() - /* - Note this example is an ImmutableJS List so we must convert it to an array. - I've left this up to you to covert to an array, as react-reorder updates a lot, - and if I called this internally it could get rather slow, - whereas you have greater control over your component updates. - */ - } -
    - ``` - -5. Callback functions - - * The `onReorder` function that is called once a reorder has been performed. - You can use our helper functions for reordering your arrays. - - ```javascript - import { reorder, reorderImmutable, reorderFromTo, reorderFromToImmutable } from 'react-reorder'; - - onReorder (event, previousIndex, nextIndex, fromId, toId) { - this.setState({ - myList: reorder(this.state.myList, fromIndex, toIndex); - }); - } - - onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { - if (fromId === toId) { - const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); - - this.setState({ - [fromId]: list - }); - } else { - const lists = reorderFromToImmutable({ - from: this.state[fromId], - to: this.state[toId] - }, previousIndex, nextIndex); - - this.setState({ - [fromId]: lists.from, - [toId]: lists.to - }); - } - } - ``` - -## Compatibility / Requirements +``` +npm install react-reorder +``` -* Version `3.x` tested and working with React `0.15` +Using bower -* Version `2.x` tested and working with React `0.14` +Add `--save` or `-S` to update your bower.json -* Versions `1.x` tested and working with React `0.12` - `0.13` +``` +bower install react-reorder +``` -* requirejs / commonjs / browserify (__Optional, but recommended*__) +## Example -\* Has only been tested with requirejs & browserify +If using a module loader (requirejs / browserfiy / commonjs): require `react-reorder` where it will be used in your project + +```javascript +var Reorder = require('react-reorder'); +var reorder = Reorder.reorder; +var reorderImmutable = Reorder.reorderImmutable; + +// Or ES6 + +import Reorder, { reorder, reorderImmutable } from 'react-reorder'; +``` + +### Configuration + +```javascript + // Custom placeholder element (optional), defaults to clone of dragged element + } +> + { + this.state.list.map((item) => ( +
  • + {item.name} +
  • + )).toArray() + /* + Note this example is an ImmutableJS List so we must convert it to an array. + I've left this up to you to covert to an array, as react-reorder updates a lot, + and if I called this internally it could get rather slow, + whereas you have greater control over your component updates. + */ + } +
    +``` -## Supported Browsers +### Callback functions -### Desktop +The `onReorder` function that is called once a reorder has been performed. -* Internet Explorer 9+ (dropped support for IE 8) +You can use our helper functions for reordering your arrays. -* Google Chrome (tested in version 39.0.2171.95(64-bit)) +```javascript +import { reorder, reorderImmutable, reorderFromTo, reorderFromToImmutable } from 'react-reorder'; -* Mozilla Firefox (tested in version 33.0) +onReorder (event, previousIndex, nextIndex, fromId, toId) { + this.setState({ + myList: reorder(this.state.myList, fromIndex, toIndex); + }); +} -* Opera (tested in version 26.0.1656.60) +onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { + if (fromId === toId) { + const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); -* Safari (tested in version 7.1.2 (9537.85.11.5)) + this.setState({ + [fromId]: list + }); + } else { + const lists = reorderFromToImmutable({ + from: this.state[fromId], + to: this.state[toId] + }, previousIndex, nextIndex); -### Mobile + this.setState({ + [fromId]: lists.from, + [toId]: lists.to + }); + } +} +``` -* Chrome (tested in version 40.0.2214.89) +## Compatibility / Requirements -* Safari (tested on iOS 8) +* Version `3.x` tested and working with React `15`, but should be backward compatible at least a couple of versions. From dafcca1f3a0d8e31fdcad934767955bd454d3249 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:29:35 +0000 Subject: [PATCH 232/292] Note about multi-list dragging --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4038d455..0338f50f 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ It fully supports touch devices and auto-scrolls when a component is being dragg It also allows the user to set a hold time (duration before drag begins) allowing additional events like clicking / tapping to be applied. +Version 3 adds the ability to drag items between multiple lists. + ## Installation Using npm From 6dfeb005666efc71ebbacc5ca56135e2e519b208 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:33:51 +0000 Subject: [PATCH 233/292] Update readme --- README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0338f50f..4c19b585 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,12 @@ __Drag & drop, touch enabled, reorder / sortable list, React component__ ## About -React Reorder is a React component that allows the user to drag-and-drop items in a list (horizontal / vertical) or a grid. +React Reorder is a React component that allows the user to drag-and-drop items in a list (horizontal / vertical), or a grid. You can also allow dragging items from one list to another. It fully supports touch devices and auto-scrolls when a component is being dragged (check out the [demo](http://jakesidsmith.github.io/react-reorder/)). It also allows the user to set a hold time (duration before drag begins) allowing additional events like clicking / tapping to be applied. -Version 3 adds the ability to drag items between multiple lists. - ## Installation Using npm @@ -38,10 +36,17 @@ If using a module loader (requirejs / browserfiy / commonjs): require `react-reo var Reorder = require('react-reorder'); var reorder = Reorder.reorder; var reorderImmutable = Reorder.reorderImmutable; +var reorderFromTo = Reorder.reorderFromTo; +var reorderFromToImmutable = Reorder.reorderFromToImmutable; // Or ES6 -import Reorder, { reorder, reorderImmutable } from 'react-reorder'; +import Reorder, { + reorder, + reorderImmutable, + reorderFromTo, + reorderFromToImmutable +} from 'react-reorder'; ``` ### Configuration From 231cb78d6904fc2df48c3368e00cbdf55662c809 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:47:27 +0000 Subject: [PATCH 234/292] Update deployer name --- scripts/deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 65fe0e7b..72fcf059 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -33,7 +33,7 @@ rsync -rv $DIST_DIR/* circle.yml --exclude=src/* $DEPLOY_DIR # Commit changes cd $DEPLOY_DIR git config user.email "jake@dabapps.com" -git config user.name "Automated Docs Deployer" +git config user.name "Automated Example Deployer" git add -f . git commit -m "Deployment - build $CIRCLE_BUILD_NUM" From e8b42d6c29f3db12fdee82b0c7c6350e2646b394 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:48:20 +0000 Subject: [PATCH 235/292] Remove engines from package (yarn hates them) --- package.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/package.json b/package.json index 1bf36d05..803a004e 100644 --- a/package.json +++ b/package.json @@ -61,9 +61,5 @@ }, "peerDependencies": { "react": "*" - }, - "engines": { - "node": "6.9.1", - "npm": "3.10.8" } } From c8b67e4e642812788152a9e5baa90c84fc9f4740 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 12 Mar 2017 16:49:33 +0000 Subject: [PATCH 236/292] Add babel plugin istanbul to package --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 803a004e..6181cf99 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "lodash.assign": "*" }, "devDependencies": { + "babel-plugin-istanbul": "4.0.0", "babel-preset-es2015": "6.18.0", "babel-preset-react": "6.11.1", "babelify": "7.3.0", From 916d6dd8e353f8df88c82dfe7d79c3e6a32e0091 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Mon, 10 Apr 2017 14:10:23 +0100 Subject: [PATCH 237/292] New alpha version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6181cf99..00552a6d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-reorder", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.1", "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", From 53da42b4f595bdf592646c8ca4cec8801ab8c58e Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 11:37:11 +0100 Subject: [PATCH 238/292] Update node version --- .nvmrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.nvmrc b/.nvmrc index dc3829f5..3c024323 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -6.9.1 +6.10.3 From 53e96accbe487427007bd451e0912383f3507829 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 11:37:26 +0100 Subject: [PATCH 239/292] Install concurrently --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 00552a6d..df3a7efa 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "babelify": "7.3.0", "browserify": "12.0.1", "chai": "3.5.0", + "concurrently": "3.5.0", "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v2.1.0", "http-server": "0.8.5", "immutable": "3.8.1", From 4b767cb65133031c45d885feab2fa19b0fc885ff Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 11:37:34 +0100 Subject: [PATCH 240/292] Create start script --- package.json | 2 +- scripts/start | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100755 scripts/start diff --git a/package.json b/package.json index df3a7efa..1da8dcec 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "license": "MIT", "main": "src/index.js", "scripts": { - "start": "http-server examples/ -c-1 -o", + "start": "./scripts/start", "build-js": "browserify -t babelify examples/src/js/index.js -o examples/build/js/index.js", "watch-js": "watchify -t babelify examples/src/js/index.js -o examples/build/js/index.js -v", "build-dirs": "mkdir -p examples/build/js/", diff --git a/scripts/start b/scripts/start new file mode 100755 index 00000000..1a7e0237 --- /dev/null +++ b/scripts/start @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -e + +mkdir -p examples/build/js/ +mkdir -p examples/build/css/ + +concurrently --kill-others \ + --prefix='name' \ + --names='watch-js ,http-server' \ + --prefix-colors='red,green' \ + 'watchify -d -t babelify examples/src/js/index.js -o examples/build/js/index.js -v' \ + 'http-server -c-0 examples/ -o' From 1a229b0091e4cd224e8f25f1f87e6c7d71f6f9fb Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 11:39:31 +0100 Subject: [PATCH 241/292] Update eslint configs --- .eslintrc-examples.json | 5 ----- .eslintrc-tests.json | 6 ------ .eslintrc-src.json => .eslintrc.json | 0 examples/.eslintrc.json | 8 ++++++++ package.json | 6 ++---- tests/.eslintrc.json | 9 +++++++++ 6 files changed, 19 insertions(+), 15 deletions(-) delete mode 100644 .eslintrc-examples.json delete mode 100644 .eslintrc-tests.json rename .eslintrc-src.json => .eslintrc.json (100%) create mode 100644 examples/.eslintrc.json create mode 100644 tests/.eslintrc.json diff --git a/.eslintrc-examples.json b/.eslintrc-examples.json deleted file mode 100644 index d1cfbb39..00000000 --- a/.eslintrc-examples.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends":[ - "jakesidsmith/default" - ] -} diff --git a/.eslintrc-tests.json b/.eslintrc-tests.json deleted file mode 100644 index baee7ffb..00000000 --- a/.eslintrc-tests.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends":[ - "jakesidsmith/default", - "jakesidsmith/mocha" - ] -} diff --git a/.eslintrc-src.json b/.eslintrc.json similarity index 100% rename from .eslintrc-src.json rename to .eslintrc.json diff --git a/examples/.eslintrc.json b/examples/.eslintrc.json new file mode 100644 index 00000000..0a53a4e7 --- /dev/null +++ b/examples/.eslintrc.json @@ -0,0 +1,8 @@ +{ + "extends":[ + "jakesidsmith/commonjs", + "jakesidsmith/es6", + "jakesidsmith/react", + "jakesidsmith/browser" + ] +} diff --git a/package.json b/package.json index 1da8dcec..99f2dce1 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,9 @@ "build-dirs": "mkdir -p examples/build/js/", "build": "npm run build-dirs && npm run build-js", "watch": "npm run watch-js", - "lint-src": "eslint -c .eslintrc-src.json src/", - "lint-examples": "eslint -c .eslintrc-examples.json examples/src/js/", - "lint-tests": "eslint -c .eslintrc-tests.json tests/", + "lint": "eslint src/ tests/ examples/js/", "mocha": "BABEL_ENV=mocha nyc mocha --opts .mocharc 'tests/**/*.test.js'", - "test": "npm run lint-src && npm run lint-examples && npm run lint-tests && npm run mocha" + "test": "npm run lint && npm run mocha" }, "bugs": "https://github.com/JakeSidSmith/react-reorder/issues", "repository": { diff --git a/tests/.eslintrc.json b/tests/.eslintrc.json new file mode 100644 index 00000000..5a58739b --- /dev/null +++ b/tests/.eslintrc.json @@ -0,0 +1,9 @@ +{ + "extends":[ + "jakesidsmith/commonjs", + "jakesidsmith/es6", + "jakesidsmith/react", + "jakesidsmith/browser", + "jakesidsmith/mocha" + ] +} From 3aa1d3e62bfe5e622d86cc595c8ef7deb3184e97 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 11:39:44 +0100 Subject: [PATCH 242/292] Update babel configs --- .babelrc | 1 - examples/.babelrc | 6 ++++++ tests/.babelrc | 6 ++++++ 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 examples/.babelrc create mode 100644 tests/.babelrc diff --git a/.babelrc b/.babelrc index 737c9944..66ec89e3 100644 --- a/.babelrc +++ b/.babelrc @@ -1,6 +1,5 @@ { "presets": [ - "es2015", "react" ], "env": { diff --git a/examples/.babelrc b/examples/.babelrc new file mode 100644 index 00000000..bd20dc17 --- /dev/null +++ b/examples/.babelrc @@ -0,0 +1,6 @@ +{ + "presets": [ + "es2015", + "react" + ] +} diff --git a/tests/.babelrc b/tests/.babelrc new file mode 100644 index 00000000..bd20dc17 --- /dev/null +++ b/tests/.babelrc @@ -0,0 +1,6 @@ +{ + "presets": [ + "es2015", + "react" + ] +} From fc4bb3ff33c752a4146c3af18bf3c8e7cde5e18f Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 11:59:08 +0100 Subject: [PATCH 243/292] Reorganize examples --- examples/src/js/grid.js | 64 +++++ examples/src/js/index.js | 361 +---------------------------- examples/src/js/lock-horizontal.js | 93 ++++++++ examples/src/js/lock-vertical.js | 91 ++++++++ examples/src/js/multi-list.js | 127 ++++++++++ examples/src/js/styles.js | 86 +++++++ 6 files changed, 471 insertions(+), 351 deletions(-) create mode 100644 examples/src/js/grid.js create mode 100644 examples/src/js/lock-horizontal.js create mode 100644 examples/src/js/lock-vertical.js create mode 100644 examples/src/js/multi-list.js diff --git a/examples/src/js/grid.js b/examples/src/js/grid.js new file mode 100644 index 00000000..fa18eff7 --- /dev/null +++ b/examples/src/js/grid.js @@ -0,0 +1,64 @@ +import Immutable from 'immutable'; +import React, { Component } from 'react'; +import Reorder, { reorderImmutable } from '../../../src/index'; + +import { classNames } from './styles'; + +export class Grid extends Component { + constructor () { + super(); + + this.state = { + list: Immutable.List(Immutable.Range(0, 10).map(function (value) { + return { + name: ['Thing', value].join(' '), + color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') + }; + })) + }; + } + + onReorder (event, previousIndex, nextIndex) { + const list = reorderImmutable(this.state.list, previousIndex, nextIndex); + + this.setState({ + list: list + }); + } + + render () { + return ( +
    +

    + No lock (grid) +

    +

    + This example has a hold time of 0 milliseconds +

    + + + { + this.state.list.map(function (item) { + return ( +
  • + {item.name} +
  • + ); + }.bind(this)).toArray() + } +
    +
    + ); + } +} diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 802dcd61..b09eee6a 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -1,167 +1,14 @@ -import './styles'; +import { classNames } from './styles'; + import React, { Component } from 'react'; import ReactDOM from 'react-dom'; -import ReactStyleSheets from 'react-style-sheets'; -import Immutable from 'immutable'; -import Reorder, { reorderImmutable, reorderFromToImmutable } from '../../../src/index'; -const classNames = ReactStyleSheets.createUniqueClassStyles({ - app: { - position: 'relative', - width: '100%', - maxWidth: 768, - overflow: 'hidden', - margin: 'auto', - padding: 8 - }, - myList: { - float: 'left', - width: '100%', - height: 'auto', - border: [1, 'solid', 'grey'], - padding: 8, - listStyle: 'none' - }, - myList1: { - height: 200, - overflow: 'auto', - paddingBottom: 0 - }, - myList2: { - overflowX: 'auto', - overflowY: 'hidden', - height: 62, - whiteSpace: 'nowrap' - }, - mylist3: {}, - multiList: { - width: '50%', - minHeight: 100, - maxHeight: 400, - overflowX: 'hidden', - overflowY: 'auto' - }, - listItem: { - float: 'left', - width: '100%', - height: 46, - padding: 12, - border: [2, 'solid', 'lightblue'], - marginBottom: 8, - transformOrigin: '50% 50%' - }, - listItem2: { - float: 'none', - width: 80, - marginBottom: 0, - whiteSpace: 'nowrap', - overflow: 'hidden', - display: 'inline-block' - }, - listItem3: { - float: 'left', - width: '50%' - }, - multiListItem: {}, - placeholder: { - backgroundColor: '#CCC', - border: [1, 'solid', '#CCC'] - }, - customPlaceholder: { - opacity: 0.2 - }, - dragged: { - backgroundColor: '#EEE', - transform: 'scale(0.98, 0.98)', - opacity: 0.8 - }, - selected: { - border: [2, 'solid', 'red'] - }, - contentHolder: { - display: 'table', - width: '100%' - }, - itemName: { - display: 'table-cell' - }, - input: { - display: 'table-cell', - width: '100%' - } -}); +import { LockHorizontal } from './lock-horizontal'; +import { LockVertical } from './lock-vertical'; +import { Grid } from './grid'; +import { MultiList } from './multi-list'; class Main extends Component { - constructor () { - super(); - - this.state = { - list: Immutable.List(Immutable.Range(0, 10).map(function (value) { - return { - name: ['Thing', value].join(' '), - color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') - }; - })), - listA: Immutable.List(Immutable.Range(0, 5).map(function (value) { - return { - name: ['List A - Item', value].join(' '), - color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') - }; - })), - listB: Immutable.List(Immutable.Range(0, 5).map(function (value) { - return { - name: ['List B - Item', value].join(' '), - color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') - }; - })), - prefix: 'Prefix' - }; - } - - onReorder (event, previousIndex, nextIndex) { - const list = reorderImmutable(this.state.list, previousIndex, nextIndex); - - this.setState({ - list: list - }); - } - - onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { - if (fromId === toId) { - const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); - - this.setState({ - [fromId]: list - }); - } else { - const lists = reorderFromToImmutable({ - from: this.state[fromId], - to: this.state[toId] - }, previousIndex, nextIndex); - - this.setState({ - [fromId]: lists.from, - [toId]: lists.to - }); - } - } - - onDisableToggle () { - this.setState({ - disableReorder: !this.state.disableReorder - }); - } - - onPrefixChange (event) { - const target = event.currentTarget; - - this.setState({ - prefix: target.value - }); - } - - // ---- - render () { return (
    @@ -171,200 +18,12 @@ class Main extends Component {

    Examples

    -

    - Lock horizontal -

    -

    - This example has a hold time of 500 milliseconds before dragging begins, - allowing for other events like clicking / tapping to be attached -

    -

    - Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined} -

    -

    - {'Prefix: '} - -

    - - } - > - { - this.state.list.map(function (item) { - return ( -
  • -
    - - {this.state.prefix} {item.name} - - -
    -
  • - ); - }.bind(this)).toArray() - } -
    - -

    - Lock vertical -

    -

    - This example has a hold time of 250 milliseconds -

    -

    - {'Reorder disabled: '} - - Last item clicked: {this.state.clickedItem2 ? this.state.clickedItem2.name : undefined} -

    - - - { - this.state.list.map(function (item) { - return ( -
  • - {item.name} -
  • - ); - }.bind(this)).toArray() - } -
    - -

    - No lock (grid) -

    -

    - This example has a hold time of 0 milliseconds -

    - - - { - this.state.list.map(function (item) { - return ( -
  • - {item.name} -
  • - ); - }.bind(this)).toArray() - } -
    - -

    - Drag between lists -

    -

    - This example has a group of lists that you can drag items between -

    - - { - this.state.listA.map(function (item) { - return ( -
  • -
    - - {item.name} - - -
    -
  • - ); - }.bind(this)).toArray() - } -
    + + + + - - { - this.state.listB.map(function (item) { - return ( -
  • -
    - - {item.name} - - -
    -
  • - ); - }.bind(this)).toArray() - } -
    ); } diff --git a/examples/src/js/lock-horizontal.js b/examples/src/js/lock-horizontal.js new file mode 100644 index 00000000..8ddbff36 --- /dev/null +++ b/examples/src/js/lock-horizontal.js @@ -0,0 +1,93 @@ +import Immutable from 'immutable'; +import React, { Component } from 'react'; +import Reorder, { reorderImmutable } from '../../../src/index'; + +import { classNames } from './styles'; + +export class LockHorizontal extends Component { + constructor () { + super(); + + this.state = { + list: Immutable.List(Immutable.Range(0, 10).map(function (value) { + return { + name: ['Thing', value].join(' '), + color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') + }; + })), + prefix: 'Prefix' + }; + } + + onPrefixChange (event) { + const target = event.currentTarget; + + this.setState({ + prefix: target.value + }); + } + + onReorder (event, previousIndex, nextIndex) { + const list = reorderImmutable(this.state.list, previousIndex, nextIndex); + + this.setState({ + list: list + }); + } + + render () { + return ( +
    +

    + Lock horizontal +

    +

    + This example has a hold time of 500 milliseconds before dragging begins, + allowing for other events like clicking / tapping to be attached +

    +

    + Selected item: {this.state.clickedItem ? this.state.clickedItem.name : undefined} +

    +

    + {'Prefix: '} + +

    + + } + > + { + this.state.list.map(function (item) { + return ( +
  • +
    + + {this.state.prefix} {item.name} + + +
    +
  • + ); + }.bind(this)).toArray() + } +
    +
    + ); + } +} diff --git a/examples/src/js/lock-vertical.js b/examples/src/js/lock-vertical.js new file mode 100644 index 00000000..18c6ad36 --- /dev/null +++ b/examples/src/js/lock-vertical.js @@ -0,0 +1,91 @@ +import Immutable from 'immutable'; +import React, { Component } from 'react'; +import Reorder, { reorderImmutable } from '../../../src/index'; + +import { classNames } from './styles'; + +export class LockVertical extends Component { + constructor () { + super(); + + this.state = { + list: Immutable.List(Immutable.Range(0, 10).map(function (value) { + return { + name: ['Thing', value].join(' '), + color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') + }; + })), + prefix: 'Prefix' + }; + } + + onPrefixChange (event) { + const target = event.currentTarget; + + this.setState({ + prefix: target.value + }); + } + + onDisableToggle () { + this.setState({ + disableReorder: !this.state.disableReorder + }); + } + + onReorder (event, previousIndex, nextIndex) { + const list = reorderImmutable(this.state.list, previousIndex, nextIndex); + + this.setState({ + list: list + }); + } + + render () { + return ( +
    +

    + Lock vertical +

    +

    + This example has a hold time of 250 milliseconds +

    +

    + {'Reorder disabled: '} + + Last item clicked: {this.state.clickedItem2 ? this.state.clickedItem2.name : undefined} +

    + + + { + this.state.list.map(function (item) { + return ( +
  • + {item.name} +
  • + ); + }.bind(this)).toArray() + } +
    +
    + ); + } +} diff --git a/examples/src/js/multi-list.js b/examples/src/js/multi-list.js new file mode 100644 index 00000000..e7c4ee26 --- /dev/null +++ b/examples/src/js/multi-list.js @@ -0,0 +1,127 @@ +import Immutable from 'immutable'; +import React, { Component } from 'react'; +import Reorder, { reorderImmutable, reorderFromToImmutable } from '../../../src/index'; + +import { classNames } from './styles'; + +export class MultiList extends Component { + constructor () { + super(); + + this.state = { + listA: Immutable.List(Immutable.Range(0, 5).map(function (value) { + return { + name: ['List A - Item', value].join(' '), + color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') + }; + })), + listB: Immutable.List(Immutable.Range(0, 5).map(function (value) { + return { + name: ['List B - Item', value].join(' '), + color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') + }; + })) + }; + } + + onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { + if (fromId === toId) { + const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); + + this.setState({ + [fromId]: list + }); + } else { + const lists = reorderFromToImmutable({ + from: this.state[fromId], + to: this.state[toId] + }, previousIndex, nextIndex); + + this.setState({ + [fromId]: lists.from, + [toId]: lists.to + }); + } + } + + render () { + return ( +
    +

    + Drag between lists +

    +

    + This example has a group of lists that you can drag items between +

    + + + { + this.state.listA.map(function (item) { + return ( +
  • +
    + + {item.name} + + +
    +
  • + ); + }.bind(this)).toArray() + } +
    + + + { + this.state.listB.map(function (item) { + return ( +
  • +
    + + {item.name} + + +
    +
  • + ); + }.bind(this)).toArray() + } +
    +
    + ); + } +} + + diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index da18430a..5f260c91 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -30,3 +30,89 @@ ReactStyleSheets.createGlobalTagStyles({ margin: [10, 'auto'] } }); + +export const classNames = ReactStyleSheets.createUniqueClassStyles({ + app: { + position: 'relative', + width: '100%', + maxWidth: 768, + overflow: 'hidden', + margin: 'auto', + padding: 8 + }, + myList: { + float: 'left', + width: '100%', + height: 'auto', + border: [1, 'solid', 'grey'], + padding: 8, + listStyle: 'none' + }, + myList1: { + height: 200, + overflow: 'auto', + paddingBottom: 0 + }, + myList2: { + overflowX: 'auto', + overflowY: 'hidden', + height: 62, + whiteSpace: 'nowrap' + }, + mylist3: {}, + multiList: { + width: '50%', + minHeight: 100, + maxHeight: 400, + overflowX: 'hidden', + overflowY: 'auto' + }, + listItem: { + float: 'left', + width: '100%', + height: 46, + padding: 12, + border: [2, 'solid', 'lightblue'], + marginBottom: 8, + transformOrigin: '50% 50%' + }, + listItem2: { + float: 'none', + width: 80, + marginBottom: 0, + whiteSpace: 'nowrap', + overflow: 'hidden', + display: 'inline-block' + }, + listItem3: { + float: 'left', + width: '50%' + }, + multiListItem: {}, + placeholder: { + backgroundColor: '#CCC', + border: [1, 'solid', '#CCC'] + }, + customPlaceholder: { + opacity: 0.2 + }, + dragged: { + backgroundColor: '#EEE', + transform: 'scale(0.98, 0.98)', + opacity: 0.8 + }, + selected: { + border: [2, 'solid', 'red'] + }, + contentHolder: { + display: 'table', + width: '100%' + }, + itemName: { + display: 'table-cell' + }, + input: { + display: 'table-cell', + width: '100%' + } +}); From fac6005139464b1029334e9ee4d9e775e1f4a94c Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 12:11:37 +0100 Subject: [PATCH 244/292] Begin creating kanban example --- examples/src/js/index.js | 2 + examples/src/js/kanban.js | 90 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 examples/src/js/kanban.js diff --git a/examples/src/js/index.js b/examples/src/js/index.js index b09eee6a..707cc6cf 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -7,6 +7,7 @@ import { LockHorizontal } from './lock-horizontal'; import { LockVertical } from './lock-vertical'; import { Grid } from './grid'; import { MultiList } from './multi-list'; +import { Kanban } from './kanban'; class Main extends Component { render () { @@ -23,6 +24,7 @@ class Main extends Component { +
    ); diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js new file mode 100644 index 00000000..504afcee --- /dev/null +++ b/examples/src/js/kanban.js @@ -0,0 +1,90 @@ +import Immutable from 'immutable'; +import React, { Component } from 'react'; +import Reorder, { reorderImmutable, reorderFromToImmutable } from '../../../src/index'; + +import { classNames } from './styles'; + +let listInt = 0; + +export class Kanban extends Component { + constructor () { + super(); + + this.state = { + lists: Immutable.List([{id: 'list-' + listInt, items: Immutable.List()}]) + }; + } + + onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { + if (fromId === toId) { + const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); + + this.setState({ + [fromId]: list + }); + } else { + const lists = reorderFromToImmutable({ + from: this.state[fromId], + to: this.state[toId] + }, previousIndex, nextIndex); + + this.setState({ + [fromId]: lists.from, + [toId]: lists.to + }); + } + } + + render () { + return ( +
    +

    + Kanban Board +

    +

    + In this example users can add and remove lists +

    + + { + this.state.lists.map(({id: listId, items}) => ( +
    +

    + {listId} +

    + + { + items.map(({name, color}) => ( +
  • +
    + + {name} + + +
    +
  • + )) + } +
    +
    + )) + } +
    + ); + } +} From a82dffa04dc880fa48b7b84d5879ffb58820af29 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 12:17:44 +0100 Subject: [PATCH 245/292] More ES6 syntax --- examples/src/js/grid.js | 20 ++++---- examples/src/js/lock-horizontal.js | 38 +++++++-------- examples/src/js/lock-vertical.js | 20 ++++---- examples/src/js/multi-list.js | 76 ++++++++++++++---------------- 4 files changed, 72 insertions(+), 82 deletions(-) diff --git a/examples/src/js/grid.js b/examples/src/js/grid.js index fa18eff7..cbe40730 100644 --- a/examples/src/js/grid.js +++ b/examples/src/js/grid.js @@ -45,17 +45,15 @@ export class Grid extends Component { onReorder={this.onReorder.bind(this)} > { - this.state.list.map(function (item) { - return ( -
  • - {item.name} -
  • - ); - }.bind(this)).toArray() + this.state.list.map(({name, color}) => ( +
  • + {name} +
  • + )).toArray() }

    diff --git a/examples/src/js/lock-horizontal.js b/examples/src/js/lock-horizontal.js index 8ddbff36..6293cb67 100644 --- a/examples/src/js/lock-horizontal.js +++ b/examples/src/js/lock-horizontal.js @@ -65,26 +65,24 @@ export class LockHorizontal extends Component { placeholder={
    } > { - this.state.list.map(function (item) { - return ( -
  • -
    - - {this.state.prefix} {item.name} - - -
    -
  • - ); - }.bind(this)).toArray() + this.state.list.map(({name, color}) => ( +
  • +
    + + {this.state.prefix} {name} + + +
    +
  • + )).toArray() }
    diff --git a/examples/src/js/lock-vertical.js b/examples/src/js/lock-vertical.js index 18c6ad36..0a135708 100644 --- a/examples/src/js/lock-vertical.js +++ b/examples/src/js/lock-vertical.js @@ -72,17 +72,15 @@ export class LockVertical extends Component { disabled={this.state.disableReorder} > { - this.state.list.map(function (item) { - return ( -
  • - {item.name} -
  • - ); - }.bind(this)).toArray() + this.state.list.map(({name, color}) => ( +
  • + {name} +
  • + )).toArray() }
    diff --git a/examples/src/js/multi-list.js b/examples/src/js/multi-list.js index e7c4ee26..db9dbd01 100644 --- a/examples/src/js/multi-list.js +++ b/examples/src/js/multi-list.js @@ -64,26 +64,24 @@ export class MultiList extends Component { onReorder={this.onReorderGroup.bind(this)} > { - this.state.listA.map(function (item) { - return ( -
  • -
    - - {item.name} - - -
    -
  • - ); - }.bind(this)).toArray() + this.state.listA.map(({name, color}) => ( +
  • +
    + + {name} + + +
    +
  • + )).toArray() } @@ -97,26 +95,24 @@ export class MultiList extends Component { onReorder={this.onReorderGroup.bind(this)} > { - this.state.listB.map(function (item) { - return ( -
  • -
    - - {item.name} - - -
    -
  • - ); - }.bind(this)).toArray() + this.state.listB.map(({name, color}) => ( +
  • +
    + + {name} + + +
    +
  • + )).toArray() }
    From 0f93d98dd666049b234c6a99e90d22d0fac19074 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 12:18:04 +0100 Subject: [PATCH 246/292] To array kanban example --- examples/src/js/kanban.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index 504afcee..13297e83 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -78,7 +78,7 @@ export class Kanban extends Component { />
    - )) + )).toArray() }
    From 3f03101855574da41ac1cad29acbe82ea35f27b6 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 12:23:43 +0100 Subject: [PATCH 247/292] Clearfix examples --- examples/src/js/grid.js | 2 +- examples/src/js/kanban.js | 2 +- examples/src/js/lock-horizontal.js | 2 +- examples/src/js/lock-vertical.js | 2 +- examples/src/js/multi-list.js | 2 +- examples/src/js/styles.js | 12 ++++++++++++ 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/examples/src/js/grid.js b/examples/src/js/grid.js index cbe40730..ca33ea3c 100644 --- a/examples/src/js/grid.js +++ b/examples/src/js/grid.js @@ -28,7 +28,7 @@ export class Grid extends Component { render () { return ( -
    +

    No lock (grid)

    diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index 13297e83..4fc5addf 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -37,7 +37,7 @@ export class Kanban extends Component { render () { return ( -
    +

    Kanban Board

    diff --git a/examples/src/js/lock-horizontal.js b/examples/src/js/lock-horizontal.js index 6293cb67..979dfa52 100644 --- a/examples/src/js/lock-horizontal.js +++ b/examples/src/js/lock-horizontal.js @@ -37,7 +37,7 @@ export class LockHorizontal extends Component { render () { return ( -
    +

    Lock horizontal

    diff --git a/examples/src/js/lock-vertical.js b/examples/src/js/lock-vertical.js index 0a135708..eb4013f7 100644 --- a/examples/src/js/lock-vertical.js +++ b/examples/src/js/lock-vertical.js @@ -43,7 +43,7 @@ export class LockVertical extends Component { render () { return ( -
    +

    Lock vertical

    diff --git a/examples/src/js/multi-list.js b/examples/src/js/multi-list.js index db9dbd01..2c6bc40f 100644 --- a/examples/src/js/multi-list.js +++ b/examples/src/js/multi-list.js @@ -46,7 +46,7 @@ export class MultiList extends Component { render () { return ( -
    +

    Drag between lists

    diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index 5f260c91..30e9ec5e 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -40,6 +40,18 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ margin: 'auto', padding: 8 }, + clearfix: { + before: { + content: '\'\'', + display: 'table', + clear: 'both' + }, + after: { + content: '\'\'', + display: 'table', + clear: 'both' + } + }, myList: { float: 'left', width: '100%', From f139247564d0a235f68adc84e98d6da461ad7405 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 12:56:30 +0100 Subject: [PATCH 248/292] Style kanban --- examples/src/js/kanban.js | 86 ++++++++++++++++++++++----------------- examples/src/js/styles.js | 43 ++++++++++++++++++++ 2 files changed, 92 insertions(+), 37 deletions(-) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index 4fc5addf..da631b71 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -5,6 +5,7 @@ import Reorder, { reorderImmutable, reorderFromToImmutable } from '../../../src/ import { classNames } from './styles'; let listInt = 0; +let itemInt = 0; export class Kanban extends Component { constructor () { @@ -15,6 +16,17 @@ export class Kanban extends Component { }; } + addItem (index) { + const list = this.state.lists.get(index, {id: 'list-' + listInt, items: Immutable.List()}); + listInt += 1; + list.items = list.items.push({name: 'item-' + itemInt}); + itemInt += 1; + + this.setState({ + lists: this.state.lists.set(index, list) + }); + } + onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { if (fromId === toId) { const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); @@ -45,45 +57,45 @@ export class Kanban extends Component { In this example users can add and remove lists

    - { - this.state.lists.map(({id: listId, items}) => ( -
    -

    - {listId} -

    - + { + this.state.lists.map(({id: listId, items}, index) => ( +
    - { - items.map(({name, color}) => ( -
  • -
    - +
    + {listId} +
    + + { + items.map(({name}) => ( +
  • +
    {name} - - -
    -
  • - )).toArray() - } - -
    - )) - } +
    + + )).toArray() + } + +
    + Add item + +
    +
    + )) + } +
    ); } diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index 30e9ec5e..b7113d26 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -126,5 +126,48 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ input: { display: 'table-cell', width: '100%' + }, + kanban: { + overflowY: 'auto', + height: 500 + }, + kanbanListOuter: { + width: 200, + border: [1, 'solid', '#ddd'], + backgroundColor: '#fafafa', + borderRadius: 4 + }, + kanbanListInner: { + border: 'none', + width: '100%', + minHeight: 100, + maxHeight: 400, + overflowX: 'hidden', + overflowY: 'auto', + margin: 0 + }, + kanbanItem: { + borderRadius: 4, + border: [1, 'solid', '#ccc'], + backgroundColor: '#eee', + lastChild: { + marginBottom: 0 + } + }, + kanbanHeader: { + float: 'left', + width: '100%', + padding: 8, + borderBottom: [1, 'solid', '#ddd'], + backgroundColor: '#eee' + }, + kanbanFooter: { + float: 'left', + width: '100%', + padding: 8, + borderTop: [1, 'solid', '#ddd'], + backgroundColor: '#eee', + cursor: 'pointer', + textAlign: 'center' } }); From 855a5fea0322999c4f734518d7623870b4129cdb Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 12:57:15 +0100 Subject: [PATCH 249/292] Bold kanban header --- examples/src/js/styles.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index b7113d26..515b7cdf 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -159,7 +159,8 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ width: '100%', padding: 8, borderBottom: [1, 'solid', '#ddd'], - backgroundColor: '#eee' + backgroundColor: '#eee', + fontWeight: 'bold' }, kanbanFooter: { float: 'left', From 1e5394bce781d00d598e1264d75cd0ffb56bea4e Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 13:13:10 +0100 Subject: [PATCH 250/292] Reorder single list items in kanban --- examples/src/js/kanban.js | 56 ++++++++++++++++++++++++--------------- examples/src/js/styles.js | 5 +--- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index da631b71..be3f5b4a 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -4,45 +4,59 @@ import Reorder, { reorderImmutable, reorderFromToImmutable } from '../../../src/ import { classNames } from './styles'; -let listInt = 0; -let itemInt = 0; +let listInt = 1; +let itemInt = 1; export class Kanban extends Component { constructor () { super(); this.state = { - lists: Immutable.List([{id: 'list-' + listInt, items: Immutable.List()}]) + lists: Immutable.List.of( + Immutable.Map({ + id: 'list-' + listInt, + items: Immutable.List.of( + Immutable.Map({ + name: 'item-' + itemInt + }) + ) + }) + ) }; } addItem (index) { - const list = this.state.lists.get(index, {id: 'list-' + listInt, items: Immutable.List()}); - listInt += 1; - list.items = list.items.push({name: 'item-' + itemInt}); - itemInt += 1; + let list = this.state.lists.getIn([index, 'items']); + list = list.push(Immutable.Map({name: 'item-' + (itemInt += 1)})); this.setState({ - lists: this.state.lists.set(index, list) + lists: this.state.lists.setIn([index, 'items'], list) }); } onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { if (fromId === toId) { - const list = reorderImmutable(this.state[fromId], previousIndex, nextIndex); + const index = this.state.lists.findIndex((list) => list.get('id') === fromId); + let list = this.state.lists.getIn([index, 'items']); + list = reorderImmutable(list, previousIndex, nextIndex); this.setState({ - [fromId]: list + lists: this.state.lists.setIn([index, 'items'], list) }); } else { + const fromIndex = this.state.lists.findIndex((list) => list.get('id') === fromId); + const toIndex = this.state.lists.findIndex((list) => list.get('id') === toId); + + let fromList = this.state.lists.getIn([fromIndex, 'items']); + let toList = this.state.lists.getIn([toIndex, 'items']); + const lists = reorderFromToImmutable({ - from: this.state[fromId], - to: this.state[toId] + from: fromList, + to: toList }, previousIndex, nextIndex); this.setState({ - [fromId]: lists.from, - [toId]: lists.to + lists: this.state.lists.setIn([fromIndex, 'items'], lists.from).setIn([toIndex, 'items'], lists.to) }); } } @@ -59,16 +73,16 @@ export class Kanban extends Component {
    { - this.state.lists.map(({id: listId, items}, index) => ( + this.state.lists.map((list, index) => (
    - {listId} + {list.get('id')}
    { - items.map(({name}) => ( + list.get('items').map((item) => (
  • - {name} + {item.get('name')}
  • )).toArray() diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index 515b7cdf..3b51491a 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -149,10 +149,7 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ kanbanItem: { borderRadius: 4, border: [1, 'solid', '#ccc'], - backgroundColor: '#eee', - lastChild: { - marginBottom: 0 - } + backgroundColor: '#eee' }, kanbanHeader: { float: 'left', From f2a0d6177758366ed5819385259e091189da2e6d Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 13:13:58 +0100 Subject: [PATCH 251/292] Remove padding bottom from lists --- examples/src/js/styles.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index 3b51491a..bf1b7db2 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -58,6 +58,7 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ height: 'auto', border: [1, 'solid', 'grey'], padding: 8, + paddingBottom: 0, listStyle: 'none' }, myList1: { From e624cc4ae7a91548679468470fdb4ff06dac1c92 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 13:18:03 +0100 Subject: [PATCH 252/292] Delete lists --- examples/src/js/kanban.js | 9 +++++++++ examples/src/js/styles.js | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index be3f5b4a..d35c5ab5 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -25,6 +25,12 @@ export class Kanban extends Component { }; } + deleteList (index) { + this.setState({ + lists: this.state.lists.delete(index) + }); + } + addItem (index) { let list = this.state.lists.getIn([index, 'items']); list = list.push(Immutable.Map({name: 'item-' + (itemInt += 1)})); @@ -80,6 +86,9 @@ export class Kanban extends Component { >
    {list.get('id')} + + X +
    Date: Sun, 6 Aug 2017 13:19:15 +0100 Subject: [PATCH 253/292] Fix unmount reorder group bug --- src/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index ab4dfb96..404a7f9a 100644 --- a/src/index.js +++ b/src/index.js @@ -77,10 +77,6 @@ function unregisterReorderComponent (reorderId, reorderGroup) { validateComponentIdAndGroup(reorderId, reorderGroup); - if (!(reorderId in reorderComponents)) { - throw new Error('Unknown reorderId: ' + reorderId); - } - if (typeof reorderGroup !== 'undefined') { if (!(reorderGroup in reorderGroups)) { throw new Error('Unknown reorderGroup: ' + reorderGroup); @@ -92,6 +88,10 @@ delete reorderGroups[reorderGroup][reorderId]; } else { + if (!(reorderId in reorderComponents)) { + throw new Error('Unknown reorderId: ' + reorderId); + } + delete reorderComponents[reorderId]; } } From 2e1305cca6adc564b7d9b28cda9f743f9448820a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 13:20:45 +0100 Subject: [PATCH 254/292] Fix registering reorder group --- src/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/index.js b/src/index.js index 404a7f9a..abdaac87 100644 --- a/src/index.js +++ b/src/index.js @@ -58,10 +58,6 @@ function registerReorderComponent (reorderId, reorderGroup, callback) { validateComponentIdAndGroup(reorderId, reorderGroup); - if (reorderId in reorderComponents) { - throw new Error('Duplicate reorderId: ' + reorderId); - } - if (typeof reorderGroup !== 'undefined') { if ((reorderGroup in reorderGroups) && (reorderId in reorderGroups[reorderGroup])) { throw new Error('Duplicate reorderId: ' + reorderId + ' in reorderGroup: ' + reorderGroup); @@ -70,6 +66,10 @@ reorderGroups[reorderGroup] = reorderGroups[reorderGroup] || {}; reorderGroups[reorderGroup][reorderId] = callback; } else { + if (reorderId in reorderComponents) { + throw new Error('Duplicate reorderId: ' + reorderId); + } + reorderComponents[reorderId] = callback; } } From 4d50cc73fc9bba9499d5df484188b56bc6d408f4 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 13:29:45 +0100 Subject: [PATCH 255/292] Add more lists to kanban --- examples/src/js/kanban.js | 16 ++++++++++++++++ examples/src/js/styles.js | 21 +++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index d35c5ab5..09cc0a72 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -25,6 +25,15 @@ export class Kanban extends Component { }; } + addList () { + this.setState({ + lists: this.state.lists.push(Immutable.Map({ + id: 'list-' + (listInt += 1), + items: Immutable.List() + })) + }); + } + deleteList (index) { this.setState({ lists: this.state.lists.delete(index) @@ -118,6 +127,13 @@ export class Kanban extends Component {
    )) } + +
    + Add list + +
    ); diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index 3b67aaac..65b6b386 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -130,13 +130,18 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ }, kanban: { overflowY: 'auto', - height: 500 + height: 500, + whiteSpace: 'nowrap' }, kanbanListOuter: { width: 200, border: [1, 'solid', '#ddd'], backgroundColor: '#fafafa', - borderRadius: 4 + borderRadius: 4, + display: 'inline-block', + verticalAlign: 'top', + whiteSpace: 'normal', + marginRight: 8 }, kanbanListInner: { border: 'none', @@ -173,5 +178,17 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ float: 'right', color: '#888', cursor: 'pointer' + }, + kanbanAddList: { + width: 200, + padding: 8, + border: [1, 'solid', '#ddd'], + backgroundColor: '#fafafa', + borderRadius: 4, + display: 'inline-block', + verticalAlign: 'top', + whiteSpace: 'normal', + cursor: 'pointer', + textAlign: 'center' } }); From a009e58eafbd03621ed226680acbd0848a396c46 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 13:32:07 +0100 Subject: [PATCH 256/292] Delete kanban items --- examples/src/js/kanban.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index 09cc0a72..6a35db67 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -49,6 +49,12 @@ export class Kanban extends Component { }); } + deleteItem (index, itemIndex) { + this.setState({ + lists: this.state.lists.deleteIn([index, 'items', itemIndex]) + }); + } + onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { if (fromId === toId) { const index = this.state.lists.findIndex((list) => list.get('id') === fromId); @@ -109,13 +115,16 @@ export class Kanban extends Component { onReorder={this.onReorderGroup.bind(this)} > { - list.get('items').map((item) => ( + list.get('items').map((item, itemIndex) => (
  • {item.get('name')} + + X +
  • )).toArray() From b3ca23357929858a01621e6d8755854d30c33999 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 13:33:40 +0100 Subject: [PATCH 257/292] Update kanban description --- examples/src/js/kanban.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index 6a35db67..6f5a4f04 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -89,7 +89,7 @@ export class Kanban extends Component { Kanban Board

    - In this example users can add and remove lists + In this example users can add and remove lists and items, and drag items between lists

    From 2fd0f2b1c0f74f5720d263e9fb26db46e5db6832 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 13:35:59 +0100 Subject: [PATCH 258/292] Move kanban example to top --- examples/src/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/js/index.js b/examples/src/js/index.js index 707cc6cf..385f4d0a 100644 --- a/examples/src/js/index.js +++ b/examples/src/js/index.js @@ -20,11 +20,11 @@ class Main extends Component { Examples

    + -
    ); From 71524302670f1b1a0b3d9305ed9c3efabf9624c1 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 13:37:21 +0100 Subject: [PATCH 259/292] Update alpha version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 99f2dce1..ebd629bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-reorder", - "version": "3.0.0-alpha.1", + "version": "3.0.0-alpha.2", "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", From 688fc72f5986b60b177d4426785725d808562c93 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 14:18:10 +0100 Subject: [PATCH 260/292] Reduce height of kanban --- examples/src/js/styles.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index 65b6b386..c97a89bc 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -130,7 +130,7 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ }, kanban: { overflowY: 'auto', - height: 500, + height: 300, whiteSpace: 'nowrap' }, kanbanListOuter: { @@ -147,7 +147,7 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ border: 'none', width: '100%', minHeight: 100, - maxHeight: 400, + maxHeight: 200, overflowX: 'hidden', overflowY: 'auto', margin: 0 From 81caa214d512c8ca57c223272ab56e17327a7ccf Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 14:39:47 +0100 Subject: [PATCH 261/292] Test custom wrapper component --- examples/src/js/kanban.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index 6f5a4f04..6c1ac031 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -7,6 +7,12 @@ import { classNames } from './styles'; let listInt = 1; let itemInt = 1; +const Wrapper = (props) => ( +
      + {props.children} +
    +); + export class Kanban extends Component { constructor () { super(); @@ -108,7 +114,7 @@ export class Kanban extends Component { Date: Sun, 6 Aug 2017 14:40:15 +0100 Subject: [PATCH 262/292] Use findDOMNode if element is unavailable --- src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index abdaac87..b2b4a3e1 100644 --- a/src/index.js +++ b/src/index.js @@ -518,7 +518,7 @@ event.clientX - mouseDownOffset.clientX : this.state.draggedStyle.left }); - var element = ReactDOM.findDOMNode(this); + var element = this.rootNode; var children = element.childNodes; var collisionIndex = this.findCollisionIndex(event, children); @@ -575,6 +575,7 @@ }, storeRootNode: function (element) { + element = element || ReactDOM.findDOMNode(this); this.rootNode = element; if (typeof this.props.getRef === 'function') { From 3a9175de77d13b45de36087b760502c58c62cfe8 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 15:19:40 +0100 Subject: [PATCH 263/292] Scroll target list --- src/index.js | 172 ++++++++++++++++++++++++++++----------------------- 1 file changed, 93 insertions(+), 79 deletions(-) diff --git a/src/index.js b/src/index.js index b2b4a3e1..7a9f5965 100644 --- a/src/index.js +++ b/src/index.js @@ -13,8 +13,48 @@ var mouseOffset = null; var mouseDownOffset = null; + function getScrollOffsetX (rect, node) { + var positionInScrollArea; + var scrollLeft = node.scrollLeft; + var scrollWidth = node.scrollWidth; + + var scrollAreaX = Math.min(rect.width / 3, CONSTANTS.SCROLL_AREA_MAX); + + if (scrollLeft > 0 && mouseOffset.clientX <= rect.left + scrollAreaX) { + positionInScrollArea = Math.min(Math.abs(rect.left + scrollAreaX - mouseOffset.clientX), scrollAreaX); + return -positionInScrollArea / scrollAreaX * CONSTANTS.SCROLL_SPEED; + } + + if (scrollLeft < scrollWidth - rect.width && mouseOffset.clientX >= rect.right - scrollAreaX) { + positionInScrollArea = Math.min(Math.abs(rect.right - scrollAreaX - mouseOffset.clientX), scrollAreaX); + return positionInScrollArea / scrollAreaX * CONSTANTS.SCROLL_SPEED; + } + + return 0; + } + + function getScrollOffsetY (rect, node) { + var positionInScrollArea; + var scrollTop = node.scrollTop; + var scrollHeight = node.scrollHeight; + + var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); + + if (scrollTop > 0 && mouseOffset.clientY <= rect.top + scrollAreaY) { + positionInScrollArea = Math.min(Math.abs(rect.top + scrollAreaY - mouseOffset.clientY), scrollAreaY); + return -positionInScrollArea / scrollAreaY * CONSTANTS.SCROLL_SPEED; + } + + if (scrollTop < scrollHeight - rect.height && mouseOffset.clientY >= rect.bottom - scrollAreaY) { + positionInScrollArea = Math.min(Math.abs(rect.bottom - scrollAreaY - mouseOffset.clientY), scrollAreaY); + return positionInScrollArea / scrollAreaY * CONSTANTS.SCROLL_SPEED; + } + + return 0; + } + function Store () { - var activeGroup, draggedId, placedId, draggedElement; + var activeGroup, draggedId, placedId, draggedElement, scrollInterval, target; var draggedStyle = null; var draggedIndex = -1; @@ -23,6 +63,28 @@ var reorderComponents = {}; var reorderGroups = {}; + function autoScroll () { + if (target && target.props.autoScroll && target.rootNode) { + var rect = target.rootNode.getBoundingClientRect(); + + if (target.props.lock !== 'horizontal') { + var scrollOffsetX = getScrollOffsetX(rect, target.rootNode); + + if (scrollOffsetX) { + target.rootNode.scrollLeft = target.rootNode.scrollLeft + scrollOffsetX; + } + } + + if (target.props.lock !== 'vertical') { + var scrollOffsetY = getScrollOffsetY(rect, target.rootNode); + + if (scrollOffsetY) { + target.rootNode.scrollTop = target.rootNode.scrollTop + scrollOffsetY; + } + } + } + } + function getState () { return { draggedId: draggedId, @@ -36,12 +98,12 @@ } function trigger () { - reorderComponents[draggedId](getState()); + reorderComponents[draggedId].setDragState(getState()); } function triggerGroup () { for (var reorderId in reorderGroups[activeGroup]) { - reorderGroups[activeGroup][reorderId](getState()); + reorderGroups[activeGroup][reorderId].setDragState(getState()); } } @@ -55,7 +117,10 @@ } } - function registerReorderComponent (reorderId, reorderGroup, callback) { + function registerReorderComponent (component) { + var reorderId = component.props.reorderId; + var reorderGroup = component.props.reorderGroup; + validateComponentIdAndGroup(reorderId, reorderGroup); if (typeof reorderGroup !== 'undefined') { @@ -64,17 +129,20 @@ } reorderGroups[reorderGroup] = reorderGroups[reorderGroup] || {}; - reorderGroups[reorderGroup][reorderId] = callback; + reorderGroups[reorderGroup][reorderId] = component; } else { if (reorderId in reorderComponents) { throw new Error('Duplicate reorderId: ' + reorderId); } - reorderComponents[reorderId] = callback; + reorderComponents[reorderId] = component; } } - function unregisterReorderComponent (reorderId, reorderGroup) { + function unregisterReorderComponent (component) { + var reorderId = component.props.reorderId; + var reorderGroup = component.props.reorderGroup; + validateComponentIdAndGroup(reorderId, reorderGroup); if (typeof reorderGroup !== 'undefined') { @@ -96,7 +164,12 @@ } } - function startDrag (reorderId, reorderGroup, index, element) { + function startDrag (reorderId, reorderGroup, index, element, component) { + target = component; + + clearInterval(scrollInterval); + scrollInterval = setInterval(autoScroll, CONSTANTS.SCROLL_INTERVAL); + validateComponentIdAndGroup(reorderId, reorderGroup); draggedIndex = index; @@ -118,6 +191,10 @@ } function stopDrag (reorderId, reorderGroup) { + target = undefined; + + clearInterval(scrollInterval); + validateComponentIdAndGroup(reorderId, reorderGroup); if (typeof activeGroup !== 'undefined') { @@ -149,7 +226,9 @@ } } - function setPlacedIndex (reorderId, reorderGroup, index) { + function setPlacedIndex (reorderId, reorderGroup, index, component) { + target = component; + validateComponentIdAndGroup(reorderId, reorderGroup); if (typeof reorderGroup !== 'undefined') { @@ -345,71 +424,8 @@ return parseInt(this.props.holdTime, 10) || 0; }, - getScrollOffsetX: function (rect, node) { - var positionInScrollArea; - var scrollLeft = node.scrollLeft; - var scrollWidth = node.scrollWidth; - - var scrollAreaX = Math.min(rect.width / 3, CONSTANTS.SCROLL_AREA_MAX); - - if (scrollLeft > 0 && mouseOffset.clientX <= rect.left + scrollAreaX) { - positionInScrollArea = Math.min(Math.abs(rect.left + scrollAreaX - mouseOffset.clientX), scrollAreaX); - return -positionInScrollArea / scrollAreaX * CONSTANTS.SCROLL_SPEED; - } - - if (scrollLeft < scrollWidth - rect.width && mouseOffset.clientX >= rect.right - scrollAreaX) { - positionInScrollArea = Math.min(Math.abs(rect.right - scrollAreaX - mouseOffset.clientX), scrollAreaX); - return positionInScrollArea / scrollAreaX * CONSTANTS.SCROLL_SPEED; - } - - return 0; - }, - - getScrollOffsetY: function (rect, node) { - var positionInScrollArea; - var scrollTop = node.scrollTop; - var scrollHeight = node.scrollHeight; - - var scrollAreaY = Math.min(rect.height / 3, CONSTANTS.SCROLL_AREA_MAX); - - if (scrollTop > 0 && mouseOffset.clientY <= rect.top + scrollAreaY) { - positionInScrollArea = Math.min(Math.abs(rect.top + scrollAreaY - mouseOffset.clientY), scrollAreaY); - return -positionInScrollArea / scrollAreaY * CONSTANTS.SCROLL_SPEED; - } - - if (scrollTop < scrollHeight - rect.height && mouseOffset.clientY >= rect.bottom - scrollAreaY) { - positionInScrollArea = Math.min(Math.abs(rect.bottom - scrollAreaY - mouseOffset.clientY), scrollAreaY); - return positionInScrollArea / scrollAreaY * CONSTANTS.SCROLL_SPEED; - } - - return 0; - }, - - autoScroll: function () { - if (this.props.autoScroll) { - var rect = this.rootNode.getBoundingClientRect(); - - if (this.props.lock !== 'horizontal') { - var scrollOffsetX = this.getScrollOffsetX(rect, this.rootNode); - - if (scrollOffsetX) { - this.rootNode.scrollLeft = this.rootNode.scrollLeft + scrollOffsetX; - } - } - - if (this.props.lock !== 'vertical') { - var scrollOffsetY = this.getScrollOffsetY(rect, this.rootNode); - - if (scrollOffsetY) { - this.rootNode.scrollTop = this.rootNode.scrollTop + scrollOffsetY; - } - } - } - }, - startDrag: function (event, target, index) { if (!this.moved) { - this.scrollInterval = setInterval(this.autoScroll, CONSTANTS.SCROLL_INTERVAL); var rect = target.getBoundingClientRect(); var draggedStyle = { @@ -420,7 +436,7 @@ height: rect.height }; - store.startDrag(this.props.reorderId, this.props.reorderGroup, index, this.props.children[index]); + store.startDrag(this.props.reorderId, this.props.reorderGroup, index, this.props.children[index], this); store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); mouseOffset = { @@ -467,7 +483,6 @@ // Stop dragging - reset style & draggedIndex, handle reorder onWindowUp: function (event) { clearTimeout(this.holdTimeout); - clearInterval(this.scrollInterval); if (this.isDraggingFrom() && this.isDragging()) { var fromIndex = this.state.draggedIndex; @@ -526,7 +541,7 @@ collisionIndex <= this.props.children.length && collisionIndex >= 0 ) { - store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, collisionIndex); + store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, collisionIndex, this); } else if ( typeof this.props.reorderGroup !== 'undefined' && // Is part of a group ( @@ -535,7 +550,7 @@ ) && this.collidesWithElement(event, element) ) { - store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, 0); + store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, 0, this); } store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); @@ -553,7 +568,7 @@ // Add listeners componentWillMount: function () { - store.registerReorderComponent(this.props.reorderId, this.props.reorderGroup, this.setDragState); + store.registerReorderComponent(this); window.addEventListener('mouseup', this.onWindowUp, {passive: false}); window.addEventListener('touchend', this.onWindowUp, {passive: false}); window.addEventListener('mousemove', this.onWindowMove, {passive: false}); @@ -563,9 +578,8 @@ // Remove listeners componentWillUnmount: function () { - store.unregisterReorderComponent(this.props.reorderId, this.props.reorderGroup); + store.unregisterReorderComponent(this); clearTimeout(this.holdTimeout); - clearInterval(this.scrollInterval); window.removeEventListener('mouseup', this.onWindowUp); window.removeEventListener('touchend', this.onWindowUp); From 4d61f250f02bcd517b08dbe930a48d2c25436cbe Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 15:19:48 +0100 Subject: [PATCH 264/292] Update basic tests --- tests/basic.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index ebc8cb0a..82a038a5 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -216,10 +216,9 @@ describe('basic', function () { wrapper.unmount(); expect(clearTimeoutSpy).to.have.been.calledOnce; - expect(clearIntervalSpy).to.have.been.calledOnce; + expect(clearIntervalSpy).not.to.have.been.calledOnce; expect(clearTimeoutSpy).to.have.been.calledWith(instance.holdTimeout); - expect(clearIntervalSpy).to.have.been.calledWith(instance.scrollInterval); clearTimeoutSpy.restore(); clearIntervalSpy.restore(); From 2c37bfcae2a66e14315a4714aeb24ec1d99ef94b Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 15:19:56 +0100 Subject: [PATCH 265/292] Xit some tests temporarily --- tests/methods.test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/methods.test.js b/tests/methods.test.js index 36e5a7f3..3ea9b3ca 100644 --- a/tests/methods.test.js +++ b/tests/methods.test.js @@ -339,7 +339,7 @@ describe('methods', function () { wrapper.unmount(); }); - it('should return the scroll offset x for auto-scrolling (max scroll area)', function () { + xit('should return the scroll offset x for auto-scrolling (max scroll area)', function () { const maxScrollArea = 50; const scrollSpeed = 20; const wrapper = mount({[
  • Item
  • ]}
    ); @@ -382,7 +382,7 @@ describe('methods', function () { wrapper.unmount(); }); - it('should return the scroll offset y for auto-scrolling (max scroll area)', function () { + xit('should return the scroll offset y for auto-scrolling (max scroll area)', function () { const maxScrollArea = 50; const scrollSpeed = 20; const wrapper = mount({[
  • Item
  • ]}
    ); @@ -425,7 +425,7 @@ describe('methods', function () { wrapper.unmount(); }); - it('should scroll the root node if auto-scroll enabled & pointer is in the right location', function () { + xit('should scroll the root node if auto-scroll enabled & pointer is in the right location', function () { const wrapper = mount({[
  • Item
  • ]}
    ); const instance = wrapper.instance(); const listItem = wrapper.find('li'); From 31e911de91ce0d1f7c07e7eb71b01b5c4fc15d7d Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 6 Aug 2017 15:27:43 +0100 Subject: [PATCH 266/292] Do not drag to group if not in visible area --- src/index.js | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/index.js b/src/index.js index 7a9f5965..79f6bb96 100644 --- a/src/index.js +++ b/src/index.js @@ -534,23 +534,27 @@ }); var element = this.rootNode; - var children = element.childNodes; - var collisionIndex = this.findCollisionIndex(event, children); - if ( - collisionIndex <= this.props.children.length && - collisionIndex >= 0 - ) { - store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, collisionIndex, this); - } else if ( - typeof this.props.reorderGroup !== 'undefined' && // Is part of a group - ( - (!this.props.children || !this.props.children.length) || // If all items removed - (this.isDraggingFrom() && this.props.children.length === 1) // If dragging back to a now empty list - ) && - this.collidesWithElement(event, element) - ) { - store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, 0, this); + if (this.collidesWithElement(event, element)) { + + var children = element.childNodes; + var collisionIndex = this.findCollisionIndex(event, children); + + if ( + collisionIndex <= this.props.children.length && + collisionIndex >= 0 + ) { + store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, collisionIndex, this); + } else if ( + typeof this.props.reorderGroup !== 'undefined' && // Is part of a group + ( + (!this.props.children || !this.props.children.length) || // If all items removed + (this.isDraggingFrom() && this.props.children.length === 1) // If dragging back to a now empty list + ) + ) { + store.setPlacedIndex(this.props.reorderId, this.props.reorderGroup, 0, this); + } + } store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); From 9fb0da161aa5d45d54d5deb586ec8aa46eeff098 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 13 Aug 2017 16:58:32 +0100 Subject: [PATCH 267/292] Update demo protocol --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4c19b585..92ba56cb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ __Drag & drop, touch enabled, reorder / sortable list, React component__ React Reorder is a React component that allows the user to drag-and-drop items in a list (horizontal / vertical), or a grid. You can also allow dragging items from one list to another. -It fully supports touch devices and auto-scrolls when a component is being dragged (check out the [demo](http://jakesidsmith.github.io/react-reorder/)). +It fully supports touch devices and auto-scrolls when a component is being dragged (check out the [demo](https://jakesidsmith.github.io/react-reorder/)). It also allows the user to set a hold time (duration before drag begins) allowing additional events like clicking / tapping to be applied. @@ -46,7 +46,7 @@ import Reorder, { reorderImmutable, reorderFromTo, reorderFromToImmutable -} from 'react-reorder'; +} from 'react-reorder'; ``` ### Configuration @@ -120,7 +120,7 @@ onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { [toId]: lists.to }); } -} +} ``` ## Compatibility / Requirements From 1d821961be92ec45c2011539f5c5fe109fb2f9f7 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 13 Aug 2017 17:45:01 +0100 Subject: [PATCH 268/292] Auto scroll parents --- src/index.js | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/index.js b/src/index.js index 79f6bb96..cc7b381a 100644 --- a/src/index.js +++ b/src/index.js @@ -53,6 +53,44 @@ return 0; } + function scrollParentsX (node) { + var parent = node.parentNode; + + while (parent && parent !== document) { + var rect = parent.getBoundingClientRect(); + + var scrollOffsetX = getScrollOffsetX(rect, parent); + + if (!scrollOffsetX) { + scrollParentsX(parent); + } else if (scrollOffsetX) { + parent.scrollLeft = parent.scrollLeft + scrollOffsetX; + return; + } + + parent = parent.parentNode; + } + } + + function scrollParentsY (node) { + var parent = node.parentNode; + + while (parent && parent !== document) { + var rect = parent.getBoundingClientRect(); + + var scrollOffsetY = getScrollOffsetY(rect, parent); + + if (!scrollOffsetY) { + scrollParentsX(parent); + } else if (scrollOffsetY) { + parent.scrollTop = parent.scrollTop + scrollOffsetY; + return; + } + + parent = parent.parentNode; + } + } + function Store () { var activeGroup, draggedId, placedId, draggedElement, scrollInterval, target; @@ -70,7 +108,9 @@ if (target.props.lock !== 'horizontal') { var scrollOffsetX = getScrollOffsetX(rect, target.rootNode); - if (scrollOffsetX) { + if (target.props.autoScrollParents && !scrollOffsetX) { + scrollParentsX(target.rootNode); + } else if (scrollOffsetX) { target.rootNode.scrollLeft = target.rootNode.scrollLeft + scrollOffsetX; } } @@ -78,7 +118,9 @@ if (target.props.lock !== 'vertical') { var scrollOffsetY = getScrollOffsetY(rect, target.rootNode); - if (scrollOffsetY) { + if (target.props.autoScrollParents && !scrollOffsetY) { + scrollParentsY(target.rootNode); + } else if (scrollOffsetY) { target.rootNode.scrollTop = target.rootNode.scrollTop + scrollOffsetY; } } @@ -670,6 +712,7 @@ onReorder: PropTypes.func, placeholder: PropTypes.element, autoScroll: PropTypes.bool, + autoScrollParents: PropTypes.bool, disabled: PropTypes.bool, disableContextMenus: PropTypes.bool }; @@ -688,6 +731,7 @@ // onReorder: function, // placeholder: react element autoScroll: true, + autoScrollParents: true, disabled: false, disableContextMenus: true }; From d011ca7e70f6db79ec9b7643ffdfdb7e4ec93e2c Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 13 Aug 2017 17:48:51 +0100 Subject: [PATCH 269/292] Fix no javascript message in IE --- examples/index.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/index.html b/examples/index.html index 8c24a844..5084ab2c 100644 --- a/examples/index.html +++ b/examples/index.html @@ -32,7 +32,9 @@

    Please enable javascript

    From cb08faef4d6a7e89b1e0e6333009e822149d7ecf Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 28 Nov 2017 19:01:54 +0000 Subject: [PATCH 270/292] Test with lots of nested reorder components --- examples/src/js/kanban.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index 6c1ac031..7aa16f85 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -4,8 +4,8 @@ import Reorder, { reorderImmutable, reorderFromToImmutable } from '../../../src/ import { classNames } from './styles'; -let listInt = 1; -let itemInt = 1; +let listInt = 0; +let itemInt = 0; const Wrapper = (props) => (
      @@ -18,16 +18,19 @@ export class Kanban extends Component { super(); this.state = { - lists: Immutable.List.of( - Immutable.Map({ + lists: Immutable.Range(0, 30).toList().map(function () { + listInt += 1; + itemInt += 1; + + return Immutable.Map({ id: 'list-' + listInt, items: Immutable.List.of( Immutable.Map({ name: 'item-' + itemInt }) ) - }) - ) + }); + }) }; } From 25a91d5a47d59c3ffdfec83acaac11fe13027771 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 28 Nov 2017 20:14:49 +0000 Subject: [PATCH 271/292] Fix multiple reorder component lag --- src/index.js | 94 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 26 deletions(-) diff --git a/src/index.js b/src/index.js index cc7b381a..1a9ac071 100644 --- a/src/index.js +++ b/src/index.js @@ -92,7 +92,12 @@ } function Store () { - var activeGroup, draggedId, placedId, draggedElement, scrollInterval, target; + var activeGroup = null; + var draggedId = null; + var placedId = null; + var draggedElement = null; + var scrollInterval = null; + var target = null; var draggedStyle = null; var draggedIndex = -1; @@ -139,13 +144,29 @@ }; } - function trigger () { - reorderComponents[draggedId].setDragState(getState()); + function trigger (clear) { + var state = getState(); + + if (clear) { + for (var i = 0; i < clear.length; i += 1) { + state[clear[i]] = null; + } + } + + reorderComponents[draggedId].setDragState(state); } - function triggerGroup () { + function triggerGroup (clear) { + var state = getState(); + + if (clear) { + for (var i = 0; i < clear.length; i += 1) { + state[clear[i]] = null; + } + } + for (var reorderId in reorderGroups[activeGroup]) { - reorderGroups[activeGroup][reorderId].setDragState(getState()); + reorderGroups[activeGroup][reorderId].setDragState(state); } } @@ -221,50 +242,48 @@ draggedId = reorderId; placedId = reorderId; - activeGroup = undefined; + activeGroup = null; if (typeof reorderGroup !== 'undefined') { activeGroup = reorderGroup; triggerGroup(); - } else if (typeof draggedId !== 'undefined' && reorderId === draggedId) { + } else if (draggedId !== null && reorderId === draggedId) { trigger(); } } function stopDrag (reorderId, reorderGroup) { - target = undefined; + target = null; clearInterval(scrollInterval); validateComponentIdAndGroup(reorderId, reorderGroup); - if (typeof activeGroup !== 'undefined') { + if (activeGroup !== null) { if (reorderGroup === activeGroup) { draggedIndex = -1; placedIndex = -1; draggedStyle = null; - draggedElement = undefined; + draggedElement = null; - triggerGroup(); + triggerGroup(['activeGroup']); - // These need to be cleared after trigger to allow state updates to these components - draggedId = undefined; - placedId = undefined; - activeGroup = undefined; + draggedId = null; + placedId = null; + activeGroup = null; } - } else if (typeof draggedId !== 'undefined' && reorderId === draggedId) { + } else if (draggedId !== null && reorderId === draggedId) { draggedIndex = -1; placedIndex = -1; draggedStyle = null; - draggedElement = undefined; + draggedElement = null; - trigger(); + trigger(['activeGroup']); - // These need to be cleared after trigger to allow state updates to these components - draggedId = undefined; - placedId = undefined; - activeGroup = undefined; + draggedId = null; + placedId = null; + activeGroup = null; } } @@ -280,7 +299,7 @@ triggerGroup(); } - } else if (typeof draggedId !== 'undefined' && reorderId === draggedId) { + } else if (draggedId !== null && reorderId === draggedId) { placedIndex = index; trigger(); @@ -296,7 +315,7 @@ triggerGroup(); } - } else if (typeof draggedId !== 'undefined' && reorderId === draggedId) { + } else if (draggedId !== null && reorderId === draggedId) { draggedStyle = style; trigger(); @@ -526,7 +545,7 @@ onWindowUp: function (event) { clearTimeout(this.holdTimeout); - if (this.isDraggingFrom() && this.isDragging()) { + if (this.isDragging() && this.isDraggingFrom()) { var fromIndex = this.state.draggedIndex; var toIndex = this.state.placedIndex; @@ -609,7 +628,30 @@ }, setDragState: function (state) { - this.setState(state); + var isPartOfGroup = this.props.reorderGroup; + var isGroupDragged = state.activeGroup; + var storedActiveGroup = this.state.activeGroup; + + var wasGroupDragged = !isGroupDragged && storedActiveGroup; + + + var isActiveGroup = isPartOfGroup && isGroupDragged && + state.activeGroup === this.props.reorderGroup; + + var isDragged = this.props.reorderId === state.draggedId; + var isPlaced = this.props.reorderId === state.placedId; + var wasPlaced = this.props.reorderId === this.state.placedId; + + // This check is like a shouldComponentUpdate but specific to our store state + // Allowing prop changes to update the component + if ( + (!isGroupDragged && !isPartOfGroup && (isDragged || isPlaced)) || + (isPartOfGroup && (!storedActiveGroup || wasGroupDragged)) || + wasGroupDragged || + (isActiveGroup && (isDragged || isPlaced || wasPlaced)) + ) { + this.setState(state); + } }, // Add listeners From 3704cfea40785ae0de47cc45c81d4d0629e1f88a Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 28 Nov 2017 20:17:53 +0000 Subject: [PATCH 272/292] Put comments back --- src/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 1a9ac071..3c2af7ef 100644 --- a/src/index.js +++ b/src/index.js @@ -267,6 +267,7 @@ draggedStyle = null; draggedElement = null; + // These need to be cleared after trigger to allow state updates to these components triggerGroup(['activeGroup']); draggedId = null; @@ -279,6 +280,7 @@ draggedStyle = null; draggedElement = null; + // These need to be cleared after trigger to allow state updates to these components trigger(['activeGroup']); draggedId = null; @@ -634,7 +636,6 @@ var wasGroupDragged = !isGroupDragged && storedActiveGroup; - var isActiveGroup = isPartOfGroup && isGroupDragged && state.activeGroup === this.props.reorderGroup; From 972013bceb414942ddcff7f1285276121675c77d Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 28 Nov 2017 20:18:48 +0000 Subject: [PATCH 273/292] Increase alpha version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ebd629bc..7b03398e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-reorder", - "version": "3.0.0-alpha.2", + "version": "3.0.0-alpha.3", "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", From aad79520f66c798c49bd17c7c1c1ca737541d99e Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 28 Nov 2017 20:21:33 +0000 Subject: [PATCH 274/292] Revert "Test with lots of nested reorder components" This reverts commit cb08faef4d6a7e89b1e0e6333009e822149d7ecf. --- examples/src/js/kanban.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/examples/src/js/kanban.js b/examples/src/js/kanban.js index 7aa16f85..6c1ac031 100644 --- a/examples/src/js/kanban.js +++ b/examples/src/js/kanban.js @@ -4,8 +4,8 @@ import Reorder, { reorderImmutable, reorderFromToImmutable } from '../../../src/ import { classNames } from './styles'; -let listInt = 0; -let itemInt = 0; +let listInt = 1; +let itemInt = 1; const Wrapper = (props) => (
        @@ -18,19 +18,16 @@ export class Kanban extends Component { super(); this.state = { - lists: Immutable.Range(0, 30).toList().map(function () { - listInt += 1; - itemInt += 1; - - return Immutable.Map({ + lists: Immutable.List.of( + Immutable.Map({ id: 'list-' + listInt, items: Immutable.List.of( Immutable.Map({ name: 'item-' + itemInt }) ) - }); - }) + }) + ) }; } From 50ba1e3793f61b760b7112dd8ee2506365d6f301 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 28 Nov 2017 20:38:21 +0000 Subject: [PATCH 275/292] Use translate to offset elements --- src/index.js | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/index.js b/src/index.js index 3c2af7ef..968f12ae 100644 --- a/src/index.js +++ b/src/index.js @@ -11,7 +11,16 @@ var downPos = null; var mouseOffset = null; - var mouseDownOffset = null; + var mouseDown = null; + + function createOffsetStyles (event, props) { + var top = (!props.lock || props.lock === 'horizontal') ? mouseOffset.clientY - mouseDown.clientY : 0; + var left = (!props.lock || props.lock === 'vertical') ? mouseOffset.clientX - mouseDown.clientX : 0; + + return { + transform: 'translate(' + left + 'px,' + top + 'px)' + }; + } function getScrollOffsetX (rect, node) { var positionInScrollArea; @@ -507,9 +516,9 @@ clientY: event.clientY }; - mouseDownOffset = { - clientX: event.clientX - rect.left, - clientY: event.clientY - rect.top + mouseDown = { + clientX: event.clientX, + clientY: event.clientY }; } }, @@ -570,7 +579,7 @@ downPos = null; mouseOffset = null; - mouseDownOffset = null; + mouseDown = null; }, // Update dragged position & placeholder index, invalidate drag if moved @@ -589,13 +598,6 @@ if (this.isDragging() && this.isInvolvedInDragging()) { this.preventNativeScrolling(event); - var draggedStyle = assign({}, this.state.draggedStyle, { - top: (!this.props.lock || this.props.lock === 'horizontal') ? - event.clientY - mouseDownOffset.clientY : this.state.draggedStyle.top, - left: (!this.props.lock || this.props.lock === 'vertical') ? - event.clientX - mouseDownOffset.clientX : this.state.draggedStyle.left - }); - var element = this.rootNode; if (this.collidesWithElement(event, element)) { @@ -620,6 +622,7 @@ } + var draggedStyle = assign({}, this.state.draggedStyle, createOffsetStyles(event, this.props)); store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); mouseOffset = { From d72eccf28251404bdaaf12b77017c78f24d2ffb3 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 28 Nov 2017 20:41:34 +0000 Subject: [PATCH 276/292] Increment alpha version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7b03398e..06cc3c5c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-reorder", - "version": "3.0.0-alpha.3", + "version": "3.0.0-alpha.4", "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", From b02ce3447864a9fe75a0ec725f4ac47101e4055f Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 3 Dec 2017 19:33:40 +0000 Subject: [PATCH 277/292] Mutate dragged styles --- src/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index 968f12ae..21ea176c 100644 --- a/src/index.js +++ b/src/index.js @@ -17,9 +17,7 @@ var top = (!props.lock || props.lock === 'horizontal') ? mouseOffset.clientY - mouseDown.clientY : 0; var left = (!props.lock || props.lock === 'vertical') ? mouseOffset.clientX - mouseDown.clientX : 0; - return { - transform: 'translate(' + left + 'px,' + top + 'px)' - }; + return 'translate(' + left + 'px,' + top + 'px)'; } function getScrollOffsetX (rect, node) { @@ -622,8 +620,8 @@ } - var draggedStyle = assign({}, this.state.draggedStyle, createOffsetStyles(event, this.props)); - store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, draggedStyle); + this.state.draggedStyle.transform = createOffsetStyles(event, this.props); + store.setDraggedStyle(this.props.reorderId, this.props.reorderGroup, this.state.draggedStyle); mouseOffset = { clientX: event.clientX, From 7ff6db1a2949da7b1332b6203631e7a914daeb66 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Fri, 15 Dec 2017 16:17:53 +0000 Subject: [PATCH 278/292] Use create-react-class --- package.json | 3 ++- src/index.js | 20 +++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 06cc3c5c..8d96303d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-reorder", - "version": "3.0.0-alpha.4", + "version": "3.0.0-alpha.5", "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", @@ -33,6 +33,7 @@ "touch" ], "dependencies": { + "create-react-class": "*", "lodash.assign": "*" }, "devDependencies": { diff --git a/src/index.js b/src/index.js index 21ea176c..3577cfc0 100644 --- a/src/index.js +++ b/src/index.js @@ -386,9 +386,9 @@ return Reorder; } - function getReorderComponent (React, ReactDOM, assign) { + function getReorderComponent (React, ReactDOM, createReactClass, assign) { - var Reorder = React.createClass({ + var Reorder = createReactClass({ displayName: 'Reorder', getInitialState: function () { @@ -790,13 +790,17 @@ if (typeof exports === 'object' && typeof module !== 'undefined') { var React = require('react'); // eslint-disable-line no-undef var ReactDOM = require('react-dom'); // eslint-disable-line no-undef + var createReactClass = require('create-react-class'); // eslint-disable-line no-undef var assign = require('lodash.assign'); // eslint-disable-line no-undef - module.exports = withReorderMethods(getReorderComponent(React, ReactDOM, assign)); // eslint-disable-line no-undef + module.exports = withReorderMethods(getReorderComponent(React, ReactDOM, createReactClass, assign)); // eslint-disable-line no-undef // Export for amd / require } else if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef - define(['react', 'react-dom', 'lodash.assign'], function (ReactAMD, ReactDOMAMD, assignAMD) { // eslint-disable-line no-undef - return withReorderMethods(getReorderComponent(ReactAMD, ReactDOMAMD, assignAMD)); - }); + define( // eslint-disable-line no-undef + ['react', 'react-dom', 'create-react-class', 'lodash.assign'], + function (ReactAMD, ReactDOMAMD, createReactClassAMD, assignAMD) { + return withReorderMethods(getReorderComponent(ReactAMD, ReactDOMAMD, createReactClassAMD, assignAMD)); + } + ); // Export globally } else { var root; @@ -811,7 +815,9 @@ root = this; } - root.Reorder = withReorderMethods(getReorderComponent(root.React, root.ReactDOM, root.assign)); + root.Reorder = withReorderMethods( + getReorderComponent(root.React, root.ReactDOM, root.createReactClass, root.assign) + ); } })(); From d6d3a8db12fcc0d83cb2a42a87f1c1e3522269ec Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 20 Dec 2017 14:25:32 +0000 Subject: [PATCH 279/292] Add prop-types dep --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 8d96303d..88ee47c8 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ ], "dependencies": { "create-react-class": "*", - "lodash.assign": "*" + "lodash.assign": "*", + "prop-types": "*" }, "devDependencies": { "babel-plugin-istanbul": "4.0.0", @@ -55,6 +56,7 @@ "react": "15.4.1", "react-addons-test-utils": "15.4.1", "react-dom": "15.4.1", + "prop-types": "15.6.0", "react-style-sheets": "0.1.0", "sinon": "1.17.6", "sinon-chai": "2.8.0", From f1aea5e088e0a00b1d6d623679baa9c4992adb27 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 20 Dec 2017 14:25:47 +0000 Subject: [PATCH 280/292] Use prop-types from prop-types module --- src/index.js | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/index.js b/src/index.js index 3577cfc0..70e7fc0b 100644 --- a/src/index.js +++ b/src/index.js @@ -386,7 +386,7 @@ return Reorder; } - function getReorderComponent (React, ReactDOM, createReactClass, assign) { + function getReorderComponent (React, ReactDOM, createReactClass, PropTypes, assign) { var Reorder = createReactClass({ displayName: 'Reorder', @@ -732,7 +732,9 @@ id: this.props.id, style: this.props.style, onClick: this.props.onClick, - ref: this.storeRootNode + ref: this.props.component && + (typeof this.props.component === 'string' || this.props.component.prototype instanceof React.Component) ? + this.storeRootNode : undefined }, children ); @@ -740,8 +742,6 @@ }); - var PropTypes = React.PropTypes; - Reorder.propTypes = { component: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), getRef: PropTypes.func, @@ -791,14 +791,19 @@ var React = require('react'); // eslint-disable-line no-undef var ReactDOM = require('react-dom'); // eslint-disable-line no-undef var createReactClass = require('create-react-class'); // eslint-disable-line no-undef + var PropTypes = require('prop-types'); // eslint-disable-line no-undef var assign = require('lodash.assign'); // eslint-disable-line no-undef - module.exports = withReorderMethods(getReorderComponent(React, ReactDOM, createReactClass, assign)); // eslint-disable-line no-undef + module.exports = withReorderMethods( // eslint-disable-line no-undef + getReorderComponent(React, ReactDOM, createReactClass, PropTypes, assign) + ); // Export for amd / require } else if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef define( // eslint-disable-line no-undef - ['react', 'react-dom', 'create-react-class', 'lodash.assign'], - function (ReactAMD, ReactDOMAMD, createReactClassAMD, assignAMD) { - return withReorderMethods(getReorderComponent(ReactAMD, ReactDOMAMD, createReactClassAMD, assignAMD)); + ['react', 'react-dom', 'create-react-class', 'prop-types', 'lodash.assign'], + function (ReactAMD, ReactDOMAMD, createReactClassAMD, PropTypesAMD, assignAMD) { + return withReorderMethods( + getReorderComponent(ReactAMD, ReactDOMAMD, createReactClassAMD, PropTypesAMD, assignAMD) + ); } ); // Export globally @@ -816,7 +821,7 @@ } root.Reorder = withReorderMethods( - getReorderComponent(root.React, root.ReactDOM, root.createReactClass, root.assign) + getReorderComponent(root.React, root.ReactDOM, root.createReactClass, root.PropTypes, root.assign) ); } From 8a573b68d0c556f01ab6a07f1848d442aa8860e0 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 20 Dec 2017 14:25:56 +0000 Subject: [PATCH 281/292] Update deps --- package.json | 5 ++--- tests/helpers/mount.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 88ee47c8..16832888 100644 --- a/package.json +++ b/package.json @@ -53,10 +53,9 @@ "lodash.assign": "4.2.0", "mocha": "3.2.0", "nyc": "10.0.0", - "react": "15.4.1", - "react-addons-test-utils": "15.4.1", - "react-dom": "15.4.1", "prop-types": "15.6.0", + "react": "16.2.0", + "react-dom": "16.2.0", "react-style-sheets": "0.1.0", "sinon": "1.17.6", "sinon-chai": "2.8.0", diff --git a/tests/helpers/mount.js b/tests/helpers/mount.js index 85856b3a..eb139413 100644 --- a/tests/helpers/mount.js +++ b/tests/helpers/mount.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import React from 'react'; import ReactDOM from 'react-dom'; -import TestUtils from 'react-addons-test-utils'; +import TestUtils from 'react-dom/test-utils'; // Override trigger method with one from TestUtils $.fn.trigger = function (type, data) { From c41ad9368fc9594265c2631e2222357a45a059dc Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 20 Dec 2017 14:31:33 +0000 Subject: [PATCH 282/292] Do not use refs --- src/index.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 70e7fc0b..c036c8f6 100644 --- a/src/index.js +++ b/src/index.js @@ -666,6 +666,11 @@ window.addEventListener('contextmenu', this.preventContextMenu, {passive: false}); }, + // Store root node + componentDidMount: function () { + this.storeRootNode(); + }, + // Remove listeners componentWillUnmount: function () { store.unregisterReorderComponent(this); @@ -678,8 +683,8 @@ window.removeEventListener('contextmenu', this.preventContextMenu); }, - storeRootNode: function (element) { - element = element || ReactDOM.findDOMNode(this); + storeRootNode: function () { + var element = ReactDOM.findDOMNode(this); this.rootNode = element; if (typeof this.props.getRef === 'function') { @@ -731,10 +736,7 @@ className: this.props.className, id: this.props.id, style: this.props.style, - onClick: this.props.onClick, - ref: this.props.component && - (typeof this.props.component === 'string' || this.props.component.prototype instanceof React.Component) ? - this.storeRootNode : undefined + onClick: this.props.onClick }, children ); From 2c615b0705e0842e7a52b3dd52d90f09fd3732e1 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 20 Dec 2017 14:40:29 +0000 Subject: [PATCH 283/292] Fix tests --- tests/basic.test.js | 10 ++-------- tests/mount.test.js | 3 ++- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/tests/basic.test.js b/tests/basic.test.js index 82a038a5..fd68374d 100644 --- a/tests/basic.test.js +++ b/tests/basic.test.js @@ -172,12 +172,9 @@ describe('basic', function () { const wrapper = mount(); - expect(addEventListenerSpy).to.have.been.called; - expect(removeEventListenerSpy).not.to.have.been.called; - expect(addEventListenerSpy.callCount).to.equal(events.length); - events.forEach(function (event) { expect(addEventListenerSpy).to.have.been.calledWith(event); + expect(removeEventListenerSpy).not.to.have.been.calledWith(event); }); addEventListenerSpy.reset(); @@ -185,11 +182,8 @@ describe('basic', function () { wrapper.unmount(); - expect(addEventListenerSpy).not.to.have.been.called; - expect(removeEventListenerSpy).to.have.been.called; - expect(removeEventListenerSpy.callCount).to.equal(events.length); - events.forEach(function (event) { + expect(addEventListenerSpy).not.to.have.been.calledWith(event); expect(removeEventListenerSpy).to.have.been.calledWith(event); }); diff --git a/tests/mount.test.js b/tests/mount.test.js index 7b0435c0..57c99b65 100644 --- a/tests/mount.test.js +++ b/tests/mount.test.js @@ -1,5 +1,6 @@ import { expect } from 'chai'; import { spy } from 'sinon'; +import createReactClass from 'create-react-class'; import mount from './helpers/mount'; import React, { Component } from 'react'; @@ -43,7 +44,7 @@ describe('mount', function () { } } - const AnotherComponent = React.createClass({ + const AnotherComponent = createReactClass({ render: function () { return
        ; } From 430868cb8d3d2edec9780ab9bcf8b4af294a0db9 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 20 Dec 2017 14:46:19 +0000 Subject: [PATCH 284/292] Remove lodash assign --- package.json | 2 -- src/index.js | 37 ++++++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 16832888..487ef894 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ ], "dependencies": { "create-react-class": "*", - "lodash.assign": "*", "prop-types": "*" }, "devDependencies": { @@ -50,7 +49,6 @@ "immutable": "3.8.1", "jquery": "3.1.1", "jsdom": "9.8.3", - "lodash.assign": "4.2.0", "mocha": "3.2.0", "nyc": "10.0.0", "prop-types": "15.6.0", diff --git a/src/index.js b/src/index.js index c036c8f6..6da3255e 100644 --- a/src/index.js +++ b/src/index.js @@ -386,7 +386,31 @@ return Reorder; } - function getReorderComponent (React, ReactDOM, createReactClass, PropTypes, assign) { + function assign () { + var args = Array.prototype.slice.call(arguments); + + if (!args.length) { + return undefined; + } + + if (args.length === 1) { + return args[0]; + } + + var obj = args.shift(); + + while (args.length) { + var arg = args.shift(); + + for (var key in arg) { + obj[key] = arg[key]; + } + } + + return obj; + } + + function getReorderComponent (React, ReactDOM, createReactClass, PropTypes) { var Reorder = createReactClass({ displayName: 'Reorder', @@ -794,17 +818,16 @@ var ReactDOM = require('react-dom'); // eslint-disable-line no-undef var createReactClass = require('create-react-class'); // eslint-disable-line no-undef var PropTypes = require('prop-types'); // eslint-disable-line no-undef - var assign = require('lodash.assign'); // eslint-disable-line no-undef module.exports = withReorderMethods( // eslint-disable-line no-undef - getReorderComponent(React, ReactDOM, createReactClass, PropTypes, assign) + getReorderComponent(React, ReactDOM, createReactClass, PropTypes) ); // Export for amd / require } else if (typeof define === 'function' && define.amd) { // eslint-disable-line no-undef define( // eslint-disable-line no-undef - ['react', 'react-dom', 'create-react-class', 'prop-types', 'lodash.assign'], - function (ReactAMD, ReactDOMAMD, createReactClassAMD, PropTypesAMD, assignAMD) { + ['react', 'react-dom', 'create-react-class', 'prop-types'], + function (ReactAMD, ReactDOMAMD, createReactClassAMD, PropTypesAMD) { return withReorderMethods( - getReorderComponent(ReactAMD, ReactDOMAMD, createReactClassAMD, PropTypesAMD, assignAMD) + getReorderComponent(ReactAMD, ReactDOMAMD, createReactClassAMD, PropTypesAMD) ); } ); @@ -823,7 +846,7 @@ } root.Reorder = withReorderMethods( - getReorderComponent(root.React, root.ReactDOM, root.createReactClass, root.PropTypes, root.assign) + getReorderComponent(root.React, root.ReactDOM, root.createReactClass, root.PropTypes) ); } From 2cd784ae20a93fc5b7ca206f35c970257db8eaba Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 20 Dec 2017 14:46:26 +0000 Subject: [PATCH 285/292] Update eslint config --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 487ef894..c872eaa2 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "browserify": "12.0.1", "chai": "3.5.0", "concurrently": "3.5.0", - "eslintrc": "git+https://github.com/JakeSidSmith/eslintrc.git#v2.1.0", + "eslint-config-jakesidsmith": "github:jakesidsmith/eslint-config-jakesidsmith#v2.1.0", "http-server": "0.8.5", "immutable": "3.8.1", "jquery": "3.1.1", From 3414eb4f1b45de14bad22a442b4fbdf647cf9aee Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 20 Dec 2017 14:46:43 +0000 Subject: [PATCH 286/292] Increment alpha version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c872eaa2..a7cc4340 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-reorder", - "version": "3.0.0-alpha.5", + "version": "3.0.0-alpha.6", "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", From 547610212c765735128ac0251a52839af457e295 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Thu, 21 Dec 2017 09:26:29 +0000 Subject: [PATCH 287/292] Update examples with click events --- examples/src/js/lock-horizontal.js | 17 +++++++++++++++-- examples/src/js/lock-vertical.js | 14 +++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/examples/src/js/lock-horizontal.js b/examples/src/js/lock-horizontal.js index 979dfa52..6d3bc3a0 100644 --- a/examples/src/js/lock-horizontal.js +++ b/examples/src/js/lock-horizontal.js @@ -15,7 +15,8 @@ export class LockHorizontal extends Component { color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') }; })), - prefix: 'Prefix' + prefix: 'Prefix', + clickedItem: null }; } @@ -35,6 +36,12 @@ export class LockHorizontal extends Component { }); } + onClickItem (name) { + this.setState({ + clickedItem: name + }); + } + render () { return (
        @@ -50,7 +57,12 @@ export class LockHorizontal extends Component {

        {'Prefix: '} - + {' '} + Last item clicked: {this.state.clickedItem}

        diff --git a/examples/src/js/lock-vertical.js b/examples/src/js/lock-vertical.js index eb4013f7..9c101065 100644 --- a/examples/src/js/lock-vertical.js +++ b/examples/src/js/lock-vertical.js @@ -15,7 +15,8 @@ export class LockVertical extends Component { color: ['rgb(', (value + 1) * 25, ',', 250 - ((value + 1) * 25), ',0)'].join('') }; })), - prefix: 'Prefix' + prefix: 'Prefix', + clickedItem: null }; } @@ -41,6 +42,12 @@ export class LockVertical extends Component { }); } + onClickItem (name) { + this.setState({ + clickedItem: name + }); + } + render () { return (
        @@ -56,8 +63,8 @@ export class LockVertical extends Component { type="checkbox" value={this.state.disableReorder || false} onChange={this.onDisableToggle.bind(this)} - /> - Last item clicked: {this.state.clickedItem2 ? this.state.clickedItem2.name : undefined} + />{' '} + Last item clicked: {this.state.clickedItem}

        {name} From 1d431b49471624dee90290ac78886802f1f538cc Mon Sep 17 00:00:00 2001 From: Aman Gupta Date: Fri, 6 Apr 2018 12:13:19 -0700 Subject: [PATCH 288/292] Fix typo in example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff22b7b8..e38638e4 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ import { reorder, reorderImmutable, reorderFromTo, reorderFromToImmutable } from onReorder (event, previousIndex, nextIndex, fromId, toId) { this.setState({ - myList: reorder(this.state.myList, fromIndex, toIndex); + myList: reorder(this.state.myList, previousIndex, nextIndex); }); } From 75d7074e1e1498ab5b26c9305b2d3b7f695c725d Mon Sep 17 00:00:00 2001 From: cmccullough Date: Wed, 6 Jun 2018 07:52:57 -0400 Subject: [PATCH 289/292] moved everything from componentwillmount to componentdidmount --- src/index.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 6da3255e..b9cc050b 100644 --- a/src/index.js +++ b/src/index.js @@ -680,18 +680,14 @@ } }, - // Add listeners - componentWillMount: function () { + // Add listeners and store root node + componentDidMount: function () { store.registerReorderComponent(this); window.addEventListener('mouseup', this.onWindowUp, {passive: false}); window.addEventListener('touchend', this.onWindowUp, {passive: false}); window.addEventListener('mousemove', this.onWindowMove, {passive: false}); window.addEventListener('touchmove', this.onWindowMove, {passive: false}); window.addEventListener('contextmenu', this.preventContextMenu, {passive: false}); - }, - - // Store root node - componentDidMount: function () { this.storeRootNode(); }, From e02f5a9a6ab1bb5628cf71a7f49381faf8cde530 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Wed, 6 Jun 2018 13:13:25 +0100 Subject: [PATCH 290/292] Update alpha version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a7cc4340..3780ee0b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-reorder", - "version": "3.0.0-alpha.6", + "version": "3.0.0-alpha.7", "description": "Drag & drop, touch enabled, reorderable / sortable list, React component", "author": "Jake 'Sid' Smith", "license": "MIT", From ef898e7fba652f90904ebd219163158227041618 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 16 Mar 2021 18:21:34 +0000 Subject: [PATCH 291/292] Add 'overflow-anchor: none' to examples --- examples/src/js/styles.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/src/js/styles.js b/examples/src/js/styles.js index c97a89bc..165438bf 100644 --- a/examples/src/js/styles.js +++ b/examples/src/js/styles.js @@ -64,10 +64,12 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ myList1: { height: 200, overflow: 'auto', + overflowAnchor: 'none', paddingBottom: 0 }, myList2: { overflowX: 'auto', + overflowAnchor: 'none', overflowY: 'hidden', height: 62, whiteSpace: 'nowrap' @@ -78,7 +80,8 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ minHeight: 100, maxHeight: 400, overflowX: 'hidden', - overflowY: 'auto' + overflowY: 'auto', + overflowAnchor: 'none' }, listItem: { float: 'left', @@ -131,7 +134,8 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ kanban: { overflowY: 'auto', height: 300, - whiteSpace: 'nowrap' + whiteSpace: 'nowrap', + overflowAnchor: 'none' }, kanbanListOuter: { width: 200, @@ -150,6 +154,7 @@ export const classNames = ReactStyleSheets.createUniqueClassStyles({ maxHeight: 200, overflowX: 'hidden', overflowY: 'auto', + overflowAnchor: 'none', margin: 0 }, kanbanItem: { From 281a9d630fdd4a3bd10b10dc4b91879f2395ac09 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Tue, 16 Mar 2021 18:24:06 +0000 Subject: [PATCH 292/292] Note about overflow anchor --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e38638e4..42de9be6 100644 --- a/README.md +++ b/README.md @@ -130,3 +130,7 @@ onReorderGroup (event, previousIndex, nextIndex, fromId, toId) { ## Compatibility / Requirements * Version `3.x` tested and working with React `15`, but should be backward compatible at least a couple of versions. + +## Weird Scrolling Behavior? + +It is recommended that you apply `overflow-anchor: none;` to any parent elements with overflow auto (including on either of just the x/y axis) to prevent unwanted auto-scrolling, or surprisingly fast auto-scrolling.