+const SortableFruitList = ParcelDrag({
+ element: (fruitParcel) =>
+ {(parcel) =>
parcel.insertAfter(`${parcel.value} copy`)}>+
parcel.delete()}>x
}
- ;
-});
-
-const SortableFruitList = SortableContainer(({fruitListParcel}) => {
- return
- {fruitListParcel.toArray((fruitParcel, index) => {
- return ;
- })}
-
;
+
});
const FruitListEditor = (props) => {
let {fruitListParcel} = props;
return
- fruitListParcel.move(oldIndex, newIndex)}
- />
+
fruitListParcel.push("New fruit")}>Add new fruit
;
};
@@ -120,7 +107,6 @@ import React from 'react';
import FlipMove from 'react-flip-move';
import ParcelHoc from 'react-dataparcels/ParcelHoc';
import ParcelBoundary from 'react-dataparcels/ParcelBoundary';
-import ExampleHoc from 'component/ExampleHoc';
const FruitListEditor = (props) => {
let {fruitListParcel} = props;
@@ -149,6 +135,6 @@ const FruitListParcelHoc = ParcelHoc({
name: "fruitListParcel"
});
-export default FruitListParcelHoc(ExampleHoc(FruitListEditor));
+export default FruitListParcelHoc(FruitListEditor);
```
diff --git a/packages/react-dataparcels-drag/README.md b/packages/react-dataparcels-drag/README.md
new file mode 100644
index 00000000..4e54d20d
--- /dev/null
+++ b/packages/react-dataparcels-drag/README.md
@@ -0,0 +1,14 @@
+![dataparcels](https://user-images.githubusercontent.com/345320/48319791-4eece200-e666-11e8-8b19-252cd1135ae2.png)
+
+
+[![CircleCI](https://circleci.com/gh/blueflag/dataparcels/tree/master.svg?style=shield)](https://circleci.com/gh/blueflag/dataparcels/tree/master)
+
+A plugin for [`react-dataparcels`](https://www.npmjs.com/package/react-dataparcels) that adds drag and drop re-ordering of elements, using the wonderful [react-sortable-hoc](https://github.com/clauderic/react-sortable-hoc).
+
+## Example
+
+**[See the example](https://dataparcels.blueflag.codes/examples/editing-arrays)**
+
+## Packages
+
+Get [`react-dataparcels-drag`](https://www.npmjs.com/package/react-dataparcels-drag).
diff --git a/packages/react-dataparcels-drag/__test__/Exports-test.js b/packages/react-dataparcels-drag/__test__/Exports-test.js
new file mode 100644
index 00000000..9ed38e32
--- /dev/null
+++ b/packages/react-dataparcels-drag/__test__/Exports-test.js
@@ -0,0 +1,9 @@
+// @flow
+
+// dataparcels exports
+import Drag from '../src/index';
+import InternalDrag from '../src/Drag';
+
+test('index should export Drag', () => {
+ expect(Drag).toBe(InternalDrag);
+});
diff --git a/packages/react-dataparcels-drag/package.json b/packages/react-dataparcels-drag/package.json
new file mode 100644
index 00000000..17b927c7
--- /dev/null
+++ b/packages/react-dataparcels-drag/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "react-dataparcels-drag",
+ "version": "0.18.0-2",
+ "description": "A plugin for react-dataparcels that adds drag and drop re-ordering of elements.",
+ "main": "lib/index.js",
+ "license": "UNLICENSED",
+ "author": "Damien Clarke",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/blueflag/dataparcels.git"
+ },
+ "files": [
+ "lib"
+ ],
+ "bugs": {
+ "url": "https://github.com/blueflag/dataparcels/issues"
+ },
+ "private": false,
+ "scripts": {
+ "build": "rm -rf lib && NODE_ENV=production babel src --out-dir lib --ignore '**/__test__/*.js'",
+ "build-all": "yarn build",
+ "watch": "yarn run build -w"
+ },
+ "dependencies": {
+ "babel-runtime": "6.23.0",
+ "react-sortable-hoc": "1.4.0"
+ },
+ "peerDependencies": {
+ "react": "16.4.2",
+ "react-dataparcels": "^0.18.0-2"
+ }
+}
diff --git a/packages/react-dataparcels-drag/src/Drag.js b/packages/react-dataparcels-drag/src/Drag.js
new file mode 100644
index 00000000..bccba709
--- /dev/null
+++ b/packages/react-dataparcels-drag/src/Drag.js
@@ -0,0 +1,47 @@
+// @flow
+
+import type {ComponentType} from 'react';
+import type {Node} from 'react';
+import type Parcel from 'react-dataparcels';
+
+import React from 'react';
+import {SortableContainer} from 'react-sortable-hoc';
+import {SortableElement} from 'react-sortable-hoc';
+
+type Config = {
+ element: (parcel: Parcel, rest: *) => Node,
+ container?: ComponentType<*>
+};
+
+type Props = {
+ parcel: Parcel,
+ onSortEnd?: ({oldIndex: number, newIndex: number}) => void
+};
+
+export default ({element, container, ...configRest}: Config) => {
+ let Container = container || 'div';
+ let ConfiguredElement = SortableElement(({parcel, ...rest}) => element(parcel, rest));
+ let ConfiguredContainer = SortableContainer(({parcel}) =>
+ {parcel.toArray((elementParcel, index) => )}
+ );
+
+ return ({parcel, onSortEnd, ...rest}: Props): Node => {
+ if(!parcel.isIndexed()) {
+ throw new Error(`react-dataparcels-drag's parcel prop must be of type indexed`);
+ }
+ return
{
+ let {oldIndex, newIndex} = param;
+ parcel.move(oldIndex, newIndex);
+ onSortEnd && onSortEnd(param);
+ }}
+ {...configRest}
+ {...rest}
+ />;
+ };
+};
diff --git a/packages/react-dataparcels-drag/src/__test__/Drag-test.js b/packages/react-dataparcels-drag/src/__test__/Drag-test.js
new file mode 100644
index 00000000..beebed12
--- /dev/null
+++ b/packages/react-dataparcels-drag/src/__test__/Drag-test.js
@@ -0,0 +1,151 @@
+// // @flow
+import React from 'react';
+import Parcel from 'react-dataparcels';
+import Drag from '../Drag';
+
+test('Drag must pass props correctly', () => {
+
+ let handleChange = jest.fn();
+
+ let parcel = new Parcel({
+ value: [1,2,3],
+ handleChange
+ });
+
+ let MyDrag = Drag({
+ element: () =>
+ });
+
+ // $FlowFixMe
+ let wrapper = shallow( , {disableLifecycleMethods: true});
+
+ // first level in
+ let props1 = wrapper.props();
+ expect(props1.parcel).toBe(parcel);
+ props1.onSortEnd({oldIndex: 0, newIndex: 2});
+ expect(handleChange.mock.calls[0][0].value).toEqual([2,3,1]);
+
+ // second level in
+ let props2 = wrapper.dive().props();
+ expect(props2.parcel).toBe(parcel);
+
+ // third level in
+ let props3 = wrapper.dive().dive().props();
+ expect(props3.children.length).toBe(3);
+});
+
+test('Drag should throw if parcel is not indexed', () => {
+
+ let parcel = new Parcel({
+ value: {abc: 123}
+ });
+
+ let MyDrag = Drag({
+ element: () =>
+ });
+
+ expect(() => {
+ // $FlowFixMe
+ shallow( , {disableLifecycleMethods: true});
+ }).toThrow(`react-dataparcels-drag's parcel prop must be of type indexed`);
+});
+
+test('Drag must accept onSortEnd and still call internal onSortEnd', () => {
+
+ let handleChange = jest.fn();
+
+ let parcel = new Parcel({
+ value: [1,2,3],
+ handleChange
+ });
+
+ let MyDrag = Drag({
+ element: () =>
+ });
+
+ let onSortEnd = jest.fn();
+
+ // $FlowFixMe
+ let wrapper = shallow( , {disableLifecycleMethods: true});
+
+ let props = wrapper.props();
+ let sortEndArg = {oldIndex: 0, newIndex: 2};
+
+ expect(props.parcel).toBe(parcel);
+ props.onSortEnd(sortEndArg);
+ expect(handleChange.mock.calls[0][0].value).toEqual([2,3,1]);
+ expect(onSortEnd.mock.calls[0][0]).toEqual(sortEndArg);
+});
+
+
+test('Drag must accept additional props and pass them to react-sortable-hoc as props', () => {
+
+ let parcel = new Parcel({
+ value: [1,2,3]
+ });
+
+ let MyDrag = Drag({
+ element: () =>
+ });
+
+ // $FlowFixMe
+ let wrapper = shallow( , {disableLifecycleMethods: true});
+
+ let props = wrapper.props();
+ expect(props.woo).toBe(123);
+});
+
+test('Drag must accept additional config and pass them to react-sortable-hoc as props', () => {
+
+ let parcel = new Parcel({
+ value: [1,2,3]
+ });
+
+ let MyDrag = Drag({
+ element: () =>
,
+ woo: 123
+ });
+
+ // $FlowFixMe
+ let wrapper = shallow( , {disableLifecycleMethods: true});
+
+ let props = wrapper.props();
+ expect(props.woo).toBe(123);
+});
+
+test('Drag must prefer props over config', () => {
+
+ let parcel = new Parcel({
+ value: [1,2,3]
+ });
+
+ let MyDrag = Drag({
+ element: () =>
,
+ woo: 123
+ });
+
+ // $FlowFixMe
+ let wrapper = shallow( , {disableLifecycleMethods: true});
+
+ let props = wrapper.props();
+ expect(props.woo).toBe(456);
+});
+
+test('Drag must render elements and pass parcels to them', () => {
+
+ let value = [1,2,3];
+
+ let parcel = new Parcel({
+ value
+ });
+
+ let element = jest.fn(() =>
);
+
+ let MyDrag = Drag({
+ element
+ });
+
+ // $FlowFixMe
+ let wrapper = mount( );
+ expect(element.mock.calls.map(call => call[0].value)).toEqual([1,2,3]);
+});
diff --git a/packages/react-dataparcels-drag/src/index.js b/packages/react-dataparcels-drag/src/index.js
new file mode 100644
index 00000000..a5099964
--- /dev/null
+++ b/packages/react-dataparcels-drag/src/index.js
@@ -0,0 +1,4 @@
+// @flow
+
+import Drag from './Drag';
+export default Drag;
diff --git a/packages/react-dataparcels/package.json b/packages/react-dataparcels/package.json
index 58115fd8..91fb4567 100644
--- a/packages/react-dataparcels/package.json
+++ b/packages/react-dataparcels/package.json
@@ -25,5 +25,8 @@
"babel-runtime": "6.23.0",
"dataparcels": "^0.18.0-2",
"unmutable": "^0.39.0"
+ },
+ "peerDependencies": {
+ "react": "16.4.2"
}
}
diff --git a/yarn.lock b/yarn.lock
index 7c2cbccb..d08aeb59 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -97,8 +97,8 @@
js-tokens "^3.0.0"
"@babel/runtime@^7.2.0":
- version "7.2.0"
- resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.2.0.tgz#b03e42eeddf5898e00646e4c840fa07ba8dcad7f"
+ version "7.3.1"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a"
dependencies:
regenerator-runtime "^0.12.0"
@@ -11190,7 +11190,7 @@ react-side-effect@^1.1.0:
exenv "^1.2.1"
shallowequal "^1.0.1"
-react-sortable-hoc@^1.4.0:
+react-sortable-hoc@1.4.0, react-sortable-hoc@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/react-sortable-hoc/-/react-sortable-hoc-1.4.0.tgz#b477ce700ba755754200a1dabd36e588e2f5608d"
dependencies: