diff --git a/packages/xpub-faraday/app/component-wizard/components/SortableList.js b/packages/xpub-faraday/app/component-wizard/components/SortableList.js new file mode 100644 index 0000000000000000000000000000000000000000..2cccc49a6fe28b35de719070b5cc73a9c8e988f1 --- /dev/null +++ b/packages/xpub-faraday/app/component-wizard/components/SortableList.js @@ -0,0 +1,70 @@ +import React from 'react' +import { compose } from 'recompose' +import { findDOMNode } from 'react-dom' +import { DragSource, DropTarget } from 'react-dnd' + +const itemSource = { + beginDrag(props) { + return { index: props.index } + }, +} + +const itemTarget = { + hover(props, monitor, component) { + const dragIndex = monitor.getItem().index + const hoverIndex = props.index + + // Don't replace items with themselves + if (dragIndex === hoverIndex) { + return + } + + const hoverBoundingRect = findDOMNode(component).getBoundingClientRect() // eslint-disable-line + const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2 + const clientOffset = monitor.getClientOffset() + const hoverClientY = clientOffset.y - hoverBoundingRect.top + + if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { + return + } + + if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { + return + } + + props.moveItem(dragIndex, hoverIndex) + monitor.getItem().index = hoverIndex + }, +} + +const Item = ({ name, isDragging, connectDragSource, connectDropTarget }) => + connectDragSource( + connectDropTarget( + <div style={{ backgroundColor: 'wheat', margin: 5 }}>{name}</div>, + ), + ) + +const DecoratedItem = compose( + DropTarget('item', itemTarget, connect => ({ + connectDropTarget: connect.dropTarget(), + })), + DragSource('item', itemSource, (connect, monitor) => ({ + connectDragSource: connect.dragSource(), + isDragging: monitor.isDragging(), + })), +)(Item) + +const SortableList = ({ items, moveItem }) => ( + <div> + {items.map((item, i) => ( + <DecoratedItem + index={i} + key={item.name} + moveItem={moveItem} + name={item.name} + /> + ))} + </div> +) + +export default SortableList diff --git a/packages/xpub-faraday/app/component-wizard/components/Steps.js b/packages/xpub-faraday/app/component-wizard/components/Steps.js index cb7c40c958b280a15b433d5d0a236a5e69ee613d..0bee01f14197e15d902fa32713a894b9938a44de 100644 --- a/packages/xpub-faraday/app/component-wizard/components/Steps.js +++ b/packages/xpub-faraday/app/component-wizard/components/Steps.js @@ -14,13 +14,13 @@ const Step = ({ title, index, currentStep }) => ( </div> ) -const Steps = ({ currentStep, children, renderSeparator, renderSteps }) => ( +const Steps = ({ currentStep, children, renderSteps }) => ( <div className={classes.container}>{renderSteps()}</div> ) const DecoratedSteps = compose( withHandlers({ - renderSteps: ({ children, currentStep }) => () => { + renderSteps: ({ children }) => () => { const c = [] React.Children.forEach(children, (child, idx) => { c.push(child) diff --git a/packages/xpub-faraday/app/component-wizard/components/Wizard.js b/packages/xpub-faraday/app/component-wizard/components/Wizard.js index 104e4ec99af593a67adf8f6019e59778c380f3f7..34f0e30a194b9ff42f08d30319268b5922abe095 100644 --- a/packages/xpub-faraday/app/component-wizard/components/Wizard.js +++ b/packages/xpub-faraday/app/component-wizard/components/Wizard.js @@ -2,7 +2,7 @@ import React from 'react' import { compose, withHandlers, withState } from 'recompose' import { withJournal } from 'xpub-journal' -import { Dropdown, Steps } from '../' +import { Dropdown, Steps, SortableList } from '../' const { Step } = Steps @@ -13,7 +13,22 @@ const options = [ { label: 'vaca 4', value: 'opt4' }, ] -const Wizard = ({ journal: { wizard }, getSteps, step, incrementStep }) => ( +const items = [ + { name: '1aurel' }, + { name: '2costel' }, + { name: '3dorel' }, + { name: '4cocojambo' }, + { name: '5gicuta' }, +] + +const Wizard = ({ + journal: { wizard }, + getSteps, + step, + incrementStep, + moveItem, + listItems, +}) => ( <div> <Dropdown defaultValue={options[0]} label="My dropdown" options={options} /> <Dropdown defaultValue={options[1]} label="Altceva" options={options} /> @@ -24,14 +39,35 @@ const Wizard = ({ journal: { wizard }, getSteps, step, incrementStep }) => ( <Step index={index} key={step} title={step} /> ))} </Steps> + <hr style={{ marginTop: 40 }} /> + <SortableList items={listItems} moveItem={moveItem} /> </div> ) export default compose( withJournal, withState('step', 'changeStep', 1), + withState('listItems', 'changeItems', items), withHandlers({ getSteps: ({ journal: { wizard } }) => () => wizard.map(w => w.label), incrementStep: ({ changeStep }) => () => changeStep(step => step + 1), + moveItem: ({ changeItems }) => (dragIndex, hoverIndex) => { + changeItems(prev => { + if (dragIndex <= hoverIndex) { + return [ + ...prev.slice(0, dragIndex), + prev[hoverIndex], + prev[dragIndex], + ...prev.slice(hoverIndex + 1), + ] + } + return [ + ...prev.slice(0, hoverIndex), + prev[dragIndex], + prev[hoverIndex], + ...prev.slice(dragIndex + 1), + ] + }) + }, }), )(Wizard) diff --git a/packages/xpub-faraday/app/component-wizard/index.js b/packages/xpub-faraday/app/component-wizard/index.js index 142a3246fdf1e664c9dd755cd8dc9ab51874028c..6fee086ce0d400564c8cf9846b4f5d52d9da4d22 100644 --- a/packages/xpub-faraday/app/component-wizard/index.js +++ b/packages/xpub-faraday/app/component-wizard/index.js @@ -1,3 +1,4 @@ export { default as Steps } from './components/Steps' export { default as Wizard } from './components/Wizard' export { default as Dropdown } from './components/Dropdown' +export { default as SortableList } from './components/SortableList' diff --git a/packages/xpub-faraday/app/routes.js b/packages/xpub-faraday/app/routes.js index cabdaa468a2c7b91cb5e89b44c9bca37d7e981af..d39a3cffe16c627b24877c517dc9e3c801f7070e 100644 --- a/packages/xpub-faraday/app/routes.js +++ b/packages/xpub-faraday/app/routes.js @@ -1,5 +1,7 @@ import React from 'react' import { Route } from 'react-router-dom' +import { DragDropContext } from 'react-dnd' +import HTML5Backend from 'react-dnd-html5-backend' import App from 'pubsweet-component-xpub-app/src/components' @@ -22,4 +24,4 @@ const Routes = () => ( </App> ) -export default Routes +export default DragDropContext(HTML5Backend)(Routes) diff --git a/packages/xpub-faraday/package.json b/packages/xpub-faraday/package.json index 85b2bca01215af093f8c714bb0df9edb9155bf02..9131984012af9750269c3ba90d628b8f57504873 100644 --- a/packages/xpub-faraday/package.json +++ b/packages/xpub-faraday/package.json @@ -30,6 +30,8 @@ "pubsweet-component-xpub-submit": "^0.0.2", "pubsweet-server": "^1.0.1", "react": "^15.6.1", + "react-dnd": "^2.5.4", + "react-dnd-html5-backend": "^2.5.4", "react-dom": "^15.6.1", "react-router-dom": "^4.2.2", "recompose": "^0.26.0", diff --git a/yarn.lock b/yarn.lock index 45153ba3ddae739ac8b836a94610161191eee779..d17e4c6441874c5933d3e266b43bc99653bae1d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -380,7 +380,7 @@ arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" -asap@~2.0.3: +asap@^2.0.6, asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -2673,10 +2673,23 @@ discontinuous-range@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/discontinuous-range/-/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" +disposables@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/disposables/-/disposables-1.0.2.tgz#36c6a674475f55a2d6913567a601444e487b4b6e" + dlv@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.0.tgz#fee1a7c43f63be75f3f679e85262da5f102764a7" +dnd-core@^2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-2.5.4.tgz#0c70a8dcbb609c0b222e275fcae9fa83e5897397" + dependencies: + asap "^2.0.6" + invariant "^2.0.0" + lodash "^4.2.0" + redux "^3.7.1" + dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" @@ -4274,7 +4287,7 @@ hoist-non-react-statics@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" -hoist-non-react-statics@^2.2.1, hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1: +hoist-non-react-statics@^2.1.0, hoist-non-react-statics@^2.2.1, hoist-non-react-statics@^2.3.0, hoist-non-react-statics@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.3.1.tgz#343db84c6018c650778898240135a1420ee22ce0" @@ -8015,6 +8028,23 @@ react-dev-utils@^4.2.1: strip-ansi "3.0.1" text-table "0.2.0" +react-dnd-html5-backend@^2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-2.5.4.tgz#974ad083f67b12d56977a5b171f5ffeb29d78352" + dependencies: + lodash "^4.2.0" + +react-dnd@^2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-2.5.4.tgz#0b6dc5e9d0dfc2909f4f4fe736e5534f3afd1bd9" + dependencies: + disposables "^1.0.1" + dnd-core "^2.5.4" + hoist-non-react-statics "^2.1.0" + invariant "^2.1.0" + lodash "^4.2.0" + prop-types "^15.5.10" + react-docgen-annotation-resolver@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/react-docgen-annotation-resolver/-/react-docgen-annotation-resolver-1.0.0.tgz#abbb343698b3b319537142082b6bb7d835fe2f1f" @@ -8471,7 +8501,7 @@ redux-thunk@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5" -redux@^3.6.0, redux@^3.7.2: +redux@^3.6.0, redux@^3.7.1, redux@^3.7.2: version "3.7.2" resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b" dependencies: