Skip to content

Commit

Permalink
Drag and Drop (#1733)
Browse files Browse the repository at this point in the history
* WIP: wrapping react-beautiful-dnd, adding eui opinions

* WIP: support cloning items

* add drag result services; update for style prop support

* update service types; actual clone behavior on copy

* WIP: docs 📓

* deps

* start to example explanations

* use animation speed variable

* docs example write ups

* bump react-beautiful-dnd

* typescript fixes; start to testing; a11y focus fix

* more docs

* complex docs example; nested focus fix

* update clone behavior to work with latest dnd release

* zIndex change for current dragging item only

* a11y improvement for drag handles

* Altered styles and added some props

* simple docs edits

* clean up scss; add remove fn

* add more euidragdropcontext docs

* fix drop in clone example

* disabledInteractiveElementBlocking; beta badge

* cherry-pick beta badge from cchaos/eui-selectable

* clone docs improvements: no box resize, no drop animation on remove

* update clone example container sizes

* Reverted using EuiListGroup for custom handle doc

* isRemovable prop name change; clean up

* #1733 changelog entry

* fix guide prop table; add prop table descriptions

* docs account for empty list size

* Revert "cherry-pick beta badge from cchaos/eui-selectable"

This reverts commit 3fcfd01.

* isRemovable blurb
  • Loading branch information
thompsongl authored Apr 3, 2019
1 parent 26d8686 commit 1b200b1
Show file tree
Hide file tree
Showing 32 changed files with 1,711 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## [`master`](https://github.com/elastic/eui/tree/master)

- **[Beta]** Added new `EuiSelectable` component ([#1699](https://github.com/elastic/eui/pull/1699))
- **[Beta]** Added new drag and drop components: `EuiDragDropContext`, `EuiDraggable`, and `EuiDroppable` ([#1733](https://github.com/elastic/eui/pull/1733))


## [`9.7.2`](https://github.com/elastic/eui/tree/v9.7.2)
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"dependencies": {
"@types/lodash": "^4.14.116",
"@types/numeral": "^0.0.25",
"@types/react-beautiful-dnd": "^10.1.0",
"classnames": "^2.2.5",
"core-js": "^2.5.1",
"highlight.js": "^9.12.0",
Expand All @@ -56,6 +57,7 @@
"numeral": "^2.0.6",
"prop-types": "^15.6.0",
"react-ace": "^5.5.0",
"react-beautiful-dnd": "^10.1.0",
"react-color": "^2.13.8",
"react-focus-lock": "^1.17.7",
"react-input-autosize": "^2.2.1",
Expand Down
2 changes: 1 addition & 1 deletion src-docs/src/components/guide_section/guide_section.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ export class GuideSection extends Component {

const rows = propNames.map(propName => {
const {
description: propDescription,
description: propDescription = '',
required,
defaultValue,
type,
Expand Down
4 changes: 4 additions & 0 deletions src-docs/src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ import { DelayHideExample }
import { DescriptionListExample }
from './views/description_list/description_list_example';

import { DragAndDropExample }
from './views/drag_and_drop/drag_and_drop_example';

import { EmptyPromptExample }
from './views/empty_prompt/empty_prompt_example';

Expand Down Expand Up @@ -388,6 +391,7 @@ const navigation = [{
CardExample,
CodeExample,
DescriptionListExample,
DragAndDropExample,
EmptyPromptExample,
HealthExample,
IconExample,
Expand Down
41 changes: 41 additions & 0 deletions src-docs/src/views/drag_and_drop/drag_and_drop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React, { useState } from 'react';
import {
EuiDragDropContext,
EuiDraggable,
EuiDroppable,
EuiPanel
} from '../../../../src/components';

import { reorder } from '../../../../src/components/drag_and_drop';

import { makeList } from './helper';

export default () => {
const [list, setList] = useState(makeList(3));
const onDragEnd = ({ source, destination }) => {
if (source && destination) {
const items = reorder(
list,
source.index,
destination.index
);

setList(items);
}
};
return (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="DROPPABLE_AREA" spacing="m" withPanel>
{list.map(({ content, id }, idx) => (
<EuiDraggable spacing="m" key={id} index={idx} draggableId={id}>
{(provided, state) => (
<EuiPanel hasShadow={state.isDragging}>
{content}{state.isDragging && ' ✨'}
</EuiPanel>
)}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
);
};
30 changes: 30 additions & 0 deletions src-docs/src/views/drag_and_drop/drag_and_drop_bare.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { useState } from 'react';
import {
EuiDragDropContext,
EuiDraggable,
EuiDroppable
} from '../../../../src/components';

import { makeList } from './helper';

export default () => {
const [list] = useState(makeList(3));
const onDragEnd = ({ source, destination }) => {
console.log(source, destination);
};
return (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="DROPPABLE_AREA_BARE">
{list.map(({ content, id }, idx) => (
<EuiDraggable key={id} index={idx} draggableId={id}>
{() => (
<div>
{content}
</div>
)}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
);
};
119 changes: 119 additions & 0 deletions src-docs/src/views/drag_and_drop/drag_and_drop_clone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React, { useState } from 'react';
import {
EuiButtonIcon,
EuiDragDropContext,
EuiFlexGroup,
EuiFlexItem,
EuiDraggable,
EuiDroppable,
EuiIcon,
EuiPanel
} from '../../../../src/components';

import {
copy,
reorder
} from '../../../../src/components/drag_and_drop';

import { makeId, makeList } from './helper';

export default () => {
const [isItemRemovable, setIsItemRemovable] = useState(false);
const [list1, setList1] = useState(makeList(3));
const [list2, setList2] = useState([]);
const lists = { DROPPABLE_AREA_COPY_1: list1, DROPPABLE_AREA_COPY_2: list2 };
const actions = { DROPPABLE_AREA_COPY_1: setList1, DROPPABLE_AREA_COPY_2: setList2 };
const remove = (droppableId, index) => {
const list = Array.from(lists[droppableId]);
list.splice(index, 1);

actions[droppableId](list);
};
const onDragUpdate = ({ source, destination }) => {
const shouldRemove = !destination && source.droppableId === 'DROPPABLE_AREA_COPY_2';
setIsItemRemovable(shouldRemove);
};
const onDragEnd = ({ source, destination }) => {
if (source && destination) {
if (source.droppableId === destination.droppableId) {
const items = reorder(
lists[destination.droppableId],
source.index,
destination.index
);

actions[destination.droppableId](items);
} else {
const sourceId = source.droppableId;
const destinationId = destination.droppableId;
const result = copy(
lists[sourceId],
lists[destinationId],
source,
destination,
{
property: 'id',
modifier: makeId
}
);

actions[sourceId](result[sourceId]);
actions[destinationId](result[destinationId]);
}
} else if (!destination && source.droppableId === 'DROPPABLE_AREA_COPY_2') {
remove(source.droppableId, source.index);
}
};
return (
<EuiDragDropContext onDragEnd={onDragEnd} onDragUpdate={onDragUpdate}>
<EuiFlexGroup>
<EuiFlexItem style={{ width: '50%' }}>

<EuiDroppable droppableId="DROPPABLE_AREA_COPY_1" cloneDraggables={true} spacing="l" grow>
{list1.map(({ content, id }, idx) => (
<EuiDraggable key={id} index={idx} draggableId={id} spacing="l">
<EuiPanel>
{content}
</EuiPanel>
</EuiDraggable>
))}
</EuiDroppable>

</EuiFlexItem>
<EuiFlexItem style={{ width: '50%' }}>

<EuiDroppable droppableId="DROPPABLE_AREA_COPY_2" withPanel grow>
{list2.length ?
(
list2.map(({ content, id }, idx) => (
<EuiDraggable key={id} index={idx} draggableId={id} spacing="l" isRemovable={isItemRemovable}>
<EuiPanel>
<EuiFlexGroup gutterSize="none" alignItems="center">
<EuiFlexItem>{content}</EuiFlexItem>
<EuiFlexItem grow={false}>
{isItemRemovable ? (
<EuiIcon type="trash" color="danger" />
) : (
<EuiButtonIcon
iconType="cross"
aria-label="Remove"
onClick={() => remove('DROPPABLE_AREA_COPY_2', idx)}
/>
)}
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiDraggable>
))
) : (
<EuiFlexGroup alignItems="center" justifyContent="spaceAround" gutterSize="none" style={{ height: '100%' }}>
<EuiFlexItem grow={false}>Drop Items Here</EuiFlexItem>
</EuiFlexGroup>
)}
</EuiDroppable>

</EuiFlexItem>
</EuiFlexGroup>
</EuiDragDropContext>
);
};
90 changes: 90 additions & 0 deletions src-docs/src/views/drag_and_drop/drag_and_drop_complex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import React, { useState } from 'react';
import {
EuiDragDropContext,
EuiDraggable,
EuiDroppable,
EuiButtonIcon,
EuiPanel
} from '../../../../src/components';

import { move, reorder } from '../../../../src/components/drag_and_drop';

import { makeList } from './helper';

export default () => {
const [list, setList] = useState([1, 2]);
const [list1, setList1] = useState(makeList(3));
const [list2, setList2] = useState(makeList(3, 4));
const lists = { COMPLEX_DROPPABLE_PARENT: list, COMPLEX_DROPPABLE_AREA_1: list1, COMPLEX_DROPPABLE_AREA_2: list2 };
const actions = { COMPLEX_DROPPABLE_PARENT: setList, COMPLEX_DROPPABLE_AREA_1: setList1, COMPLEX_DROPPABLE_AREA_2: setList2 };
const onDragEnd = ({ source, destination }) => {
if (source && destination) {
if (source.droppableId === destination.droppableId) {
const items = reorder(
lists[destination.droppableId],
source.index,
destination.index
);

actions[destination.droppableId](items);
} else {
const sourceId = source.droppableId;
const destinationId = destination.droppableId;
const result = move(
lists[sourceId],
lists[destinationId],
source,
destination
);

actions[sourceId](result[sourceId]);
actions[destinationId](result[destinationId]);
}

}
};
return (
<EuiDragDropContext onDragEnd={onDragEnd}>

<EuiDroppable
droppableId="COMPLEX_DROPPABLE_PARENT"
type="MACRO"
direction="horizontal"
withPanel
spacing="l"
style={{ display: 'flex' }}
>
{list.map((did, didx) => (
<EuiDraggable
key={did}
index={didx}
draggableId={`COMPLEX_DRAGGABLE_${did}`}
spacing="l"
style={{ flex: '1 0 50%' }}
disableInteractiveElementBlocking // Allows button to be drag handle
>
{(provided) => (
<EuiPanel paddingSize="s">
<EuiButtonIcon
iconType="grab"
aria-label="Drag Handle"
{...provided.dragHandleProps}
/>
<EuiDroppable droppableId={`COMPLEX_DROPPABLE_AREA_${did}`} type="MICRO" spacing="m" style={{ flex: '1 0 50%' }}>
{lists[`COMPLEX_DROPPABLE_AREA_${did}`].map(({ content, id }, idx) => (
<EuiDraggable key={id} index={idx} draggableId={id} spacing="m">
<EuiPanel>
{content}
</EuiPanel>
</EuiDraggable>
))}
</EuiDroppable>
</EuiPanel>
)}
</EuiDraggable>
))}
</EuiDroppable>

</EuiDragDropContext>
);
};
53 changes: 53 additions & 0 deletions src-docs/src/views/drag_and_drop/drag_and_drop_custom_handle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React, { useState } from 'react';
import {
EuiDragDropContext,
EuiDraggable,
EuiDroppable,
EuiFlexGroup,
EuiFlexItem,
EuiIcon,
EuiPanel
} from '../../../../src/components';

import { reorder } from '../../../../src/components/drag_and_drop';

import { makeList } from './helper';

export default () => {
const [list, setList] = useState(makeList(3));
const onDragEnd = ({ source, destination }) => {
if (source && destination) {
const items = reorder(
list,
source.index,
destination.index
);

setList(items);
}
};
return (
<EuiDragDropContext onDragEnd={onDragEnd}>
<EuiDroppable droppableId="CUSTOM_HANDLE_DROPPABLE_AREA" spacing="m" withPanel>
{list.map(({ content, id }, idx) => (
<EuiDraggable spacing="m" key={id} index={idx} draggableId={id} customDragHandle={true}>
{(provided) => (
<EuiPanel className="custom" paddingSize="m">
<EuiFlexGroup>
<EuiFlexItem grow={false}>
<div {...provided.dragHandleProps}>
<EuiIcon type="grab" />
</div>
</EuiFlexItem>
<EuiFlexItem>
{content}
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
)}
</EuiDraggable>
))}
</EuiDroppable>
</EuiDragDropContext>
);
};
Loading

0 comments on commit 1b200b1

Please sign in to comment.