Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add story for dragging between two vertical lists #58

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions stories/5-multiple-vertical-lists-story.js
Original file line number Diff line number Diff line change
@@ -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', () => (
<QuoteApp initial={initialQuotes} />
));
142 changes: 142 additions & 0 deletions stories/src/multiple-vertical/quote-app.js
Original file line number Diff line number Diff line change
@@ -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 (
<DragDropContext
onDragStart={this.onDragStart}
onDragEnd={this.onDragEnd}
>
<Root>
<QuoteList
listId="alpha"
listType="card"
style={style}
quotes={quotes.alpha}
/>
<QuoteList
listId="beta"
listType="card"
style={style}
quotes={quotes.beta}
/>
</Root>
</DragDropContext>
);
}
}
66 changes: 66 additions & 0 deletions stories/src/multiple-vertical/quote-list.js
Original file line number Diff line number Diff line change
@@ -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 (
<Droppable droppableId={listId} type={listType}>
{(dropProvided: DroppableProvided, dropSnapshot: DroppableStateSnapshot) => (
<Container
isDraggingOver={dropSnapshot.isDraggingOver}
innerRef={dropProvided.innerRef}
style={style}
>
{quotes.map((quote: Quote) => (
<Draggable key={quote.id} draggableId={quote.id} type={listType}>
{(dragProvided: DraggableProvided, dragSnapshot: DraggableStateSnapshot) => (
<div>
<QuoteItem
key={quote.id}
quote={quote}
isDragging={dragSnapshot.isDragging}
provided={dragProvided}
/>
{dragProvided.placeholder}
</div>
)}
</Draggable>
))}
</Container>
)}
</Droppable>
);
}
}