From c3cdb8facb5e0ecbc41e9e6824e7bc5556076e54 Mon Sep 17 00:00:00 2001 From: Jared Crowe Date: Fri, 25 Aug 2017 11:56:08 +1000 Subject: [PATCH] add story for dragging between two vertical lists --- stories/5-multiple-vertical-lists-story.js | 26 ++++ stories/src/multiple-vertical/quote-app.js | 142 ++++++++++++++++++++ stories/src/multiple-vertical/quote-list.js | 66 +++++++++ 3 files changed, 234 insertions(+) create mode 100644 stories/5-multiple-vertical-lists-story.js create mode 100644 stories/src/multiple-vertical/quote-app.js create mode 100644 stories/src/multiple-vertical/quote-list.js diff --git a/stories/5-multiple-vertical-lists-story.js b/stories/5-multiple-vertical-lists-story.js new file mode 100644 index 0000000000..8d2a5cb3e0 --- /dev/null +++ b/stories/5-multiple-vertical-lists-story.js @@ -0,0 +1,26 @@ +// @flow +import React from 'react'; +import { storiesOf } from '@storybook/react'; +import QuoteApp from './src/multiple-vertical/quote-app'; +import { quotes } from './src/data'; + +const namespaceQuoteIds = (quoteList, namespace) => quoteList.map( + quote => ({ + ...quote, + id: `${namespace}::${quote.id}`, + }) +); + +// I don't want these to be random +const alphaQuotes = quotes.slice(0, 2); +const betaQuotes = quotes.slice(6, 8); + +const initialQuotes = { + alpha: namespaceQuoteIds(alphaQuotes, 'alpha'), + beta: namespaceQuoteIds(betaQuotes, 'beta'), +}; + +storiesOf('multiple vertical lists', module) + .add('simple example', () => ( + + )); diff --git a/stories/src/multiple-vertical/quote-app.js b/stories/src/multiple-vertical/quote-app.js new file mode 100644 index 0000000000..f5a928e486 --- /dev/null +++ b/stories/src/multiple-vertical/quote-app.js @@ -0,0 +1,142 @@ +// @flow +import React, { Component } from 'react'; +import styled, { injectGlobal } from 'styled-components'; +import { action } from '@storybook/addon-actions'; +import { DragDropContext } from '../../../src/'; +import QuoteList from './quote-list'; +import { colors, grid } from '../constants'; +import reorder from '../reorder'; +import type { Quote } from '../types'; +import type { DropResult, DragStart } from '../../../src/types'; + +const publishOnDragStart = action('onDragStart'); +const publishOnDragEnd = action('onDragEnd'); + +const Root = styled.div` + background-color: ${colors.blue.deep}; + box-sizing: border-box; + padding: ${grid * 2}px; + min-height: 100vh; + + /* flexbox */ + display: flex; + justify-content: center; + align-items: flex-start; +`; + +const isDraggingClassName = 'is-dragging'; + +type Quotes = { + alpha: Quote[], + beta: Quote[], +} + +type Props = {| + initial: Quotes, + listStyle?: Object, +|} + +type State = {| + quotes: Quotes, +|} + +const resolveDrop = (quotes: Quotes, { source, destination }): Quotes => { + const newQuotes: Quotes = { ...quotes }; + + const movedQuote = quotes[source.droppableId][source.index]; + + Object.entries(newQuotes).forEach(([listId, listQuotes]: [string, Quote[]]) => { + let newListQuotes = [...listQuotes]; + + if (listId === source.droppableId) { + newListQuotes = [ + ...newListQuotes.slice(0, source.index), + ...newListQuotes.slice(source.index + 1), + ]; + } + + if (listId === destination.droppableId) { + newListQuotes = [ + ...newListQuotes.slice(0, destination.index), + movedQuote, + ...newListQuotes.slice(destination.index), + ]; + } + + newQuotes[listId] = newListQuotes; + }); + + return newQuotes; +}; + +export default class QuoteApp extends Component { + /* eslint-disable react/sort-comp */ + props: Props + state: State + + state: State = { + quotes: this.props.initial, + }; + /* eslint-enable react/sort-comp */ + + onDragStart = (initial: DragStart) => { + publishOnDragStart(initial); + // $ExpectError - body could be null? + document.body.classList.add(isDraggingClassName); + } + + onDragEnd = (result: DropResult) => { + publishOnDragEnd(result); + // $ExpectError - body could be null? + document.body.classList.remove(isDraggingClassName); + + // // dropped outside the list + if (!result.destination) { + return; + } + + const quotes = resolveDrop(this.state.quotes, result); + + this.setState({ quotes }); + } + + componentDidMount() { + // eslint-disable-next-line no-unused-expressions + injectGlobal` + body.${isDraggingClassName} { + cursor: grabbing; + user-select: none; + } + `; + } + + render() { + const { quotes } = this.state; + const style = { + ...this.props.listStyle, + margin: '0 20px', + }; + + return ( + + + + + + + ); + } +} diff --git a/stories/src/multiple-vertical/quote-list.js b/stories/src/multiple-vertical/quote-list.js new file mode 100644 index 0000000000..d78cceb237 --- /dev/null +++ b/stories/src/multiple-vertical/quote-list.js @@ -0,0 +1,66 @@ +// @flow +import React, { Component } from 'react'; +import styled from 'styled-components'; +import { Droppable, Draggable } from '../../../src'; +import QuoteItem from '../primatives/quote-item'; +import { grid, colors } from '../constants'; +import type { Quote } from '../types'; +import type { + Provided as DroppableProvided, + StateSnapshot as DroppableStateSnapshot, +} from '../../../src/view/droppable/droppable-types'; +import type { + Provided as DraggableProvided, + StateSnapshot as DraggableStateSnapshot, +} from '../../../src/view/draggable/draggable-types'; + +const Container = styled.div` + background-color: ${({ isDraggingOver }) => (isDraggingOver ? colors.blue.lighter : colors.blue.light)}; + display: flex; + flex-direction: column; + padding: ${grid}px; + padding-bottom: 0; + user-select: none; + transition: background-color 0.1s ease; + width: 250px; +`; + +export default class QuoteList extends Component { + props: {| + listId: string, + quotes: Quote[], + listType?: string, + style?: Object, + |} + + render() { + const { listId, listType, style, quotes } = this.props; + return ( + + {(dropProvided: DroppableProvided, dropSnapshot: DroppableStateSnapshot) => ( + + {quotes.map((quote: Quote) => ( + + {(dragProvided: DraggableProvided, dragSnapshot: DraggableStateSnapshot) => ( +
+ + {dragProvided.placeholder} +
+ )} +
+ ))} +
+ )} +
+ ); + } +}