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

[CARBON-865] CustomDragLayer component for enabling Drag & Drop ghost row #1439

Merged
merged 10 commits into from Aug 29, 2017
46 changes: 46 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,49 @@
# 1.6.0

### Draggable ghost row

The `DraggableContext` component now includes a `CustomDragLayer` to enable a ghost row when dragging.

In order to enable this you need to define the `draggableNode` prop on the `<WithDrag>` component. For example:

```
class DraggableItems extends React.Component {
render() {
return (
<DraggableContext onDrag={ onItemMoved }>
<ol>
{
items.map((item, index) => {
return (
<WithDrop key={ index } index={ index }>
<DraggableItem />
</WithDrop>
);
});
}
</ol>
</DraggableContext>
);
}
}

...

class DraggableItem extends React.Component {
render() {
return (
<li ref={ (node) => { this._listItem = node; } } >
<WithDrag draggableNode={ () => { return this._listItem; } }>
<span>{ item.content }</span>
</WithDrag>
</li>
);
}
}
```

Note that the `draggableNode` is passed as a function because the ref `_listItem` is undefined until the component is mounted.

# 1.5.0

## Component Improvements
Expand Down
@@ -1,9 +1,10 @@
import React from 'react';
import { shallow } from 'enzyme';
import { shallow, mount } from 'enzyme';
import ConfigurableItemRow from './configurable-item-row';
import Checkbox from './../../checkbox';
import Icon from './../../icon';
import { WithDrag, WithDrop } from './../../drag-and-drop';
import DraggableContext from './../../drag-and-drop/draggable-context';
import { rootTagTest } from './../../../utils/helpers/tags/tags-specs';

describe('ConfigurableItemRow', () => {
Expand Down Expand Up @@ -140,13 +141,20 @@ describe('ConfigurableItemRow', () => {

describe('icon', () => {
beforeEach(() => {
wrapper = shallow(
<ConfigurableItemRow name='Foo' />
wrapper = mount(
<DraggableContext onDrag={() => {}}>
<ConfigurableItemRow name='Foo' />
</DraggableContext>
);
});

it('renders a drag vertical icon', () => {
expect(wrapper.find(Icon).props().type).toEqual('drag_vertical')
it('renders a drag vertical icon wrapped in WithDrag', () => {
wrapper.update(); // this is required because the _draggableNode ref is initially undefined.
const withDrag = wrapper.find(WithDrag);
const row = wrapper.find(ConfigurableItemRow);
expect(withDrag.length).toEqual(1);
expect(withDrag.find(Icon).props().type).toEqual('drag_vertical');
expect(withDrag.props().draggableNode()).toEqual(row.node._listItem)
});
});

Expand All @@ -157,8 +165,10 @@ describe('ConfigurableItemRow', () => {
);
});

it('renders an <li>', () => {
expect(wrapper.find('li').length).toEqual(1)
it('renders an <li> wrapped in WithDrop', () => {
const withDrop = wrapper.find(WithDrop);
expect(withDrop.length).toEqual(1);
expect(withDrop.find('li').length).toEqual(1);
});
})
});
});
Expand Up @@ -73,15 +73,21 @@ class ConfigurableItemRow extends React.Component {
);
}

iconHTML() {
return (
<div>
<Icon
className='configurable-item-row__icon'
type='drag_vertical'
/>
</div>
);
}

icon() {
return (
<WithDrag>
<div>
<Icon
className='configurable-item-row__icon'
type='drag_vertical'
/>
</div>
<WithDrag draggableNode={ () => { return this._listItem; } } >
{this.iconHTML()}
</WithDrag>
);
}
Expand Down Expand Up @@ -119,16 +125,25 @@ class ConfigurableItemRow extends React.Component {
return typeof (dragAndDropActiveIndex) === 'number';
}

render() {
listItemHTML = () => {
const { rowIndex, enabled, locked, name, onChange } = this.props;
return (
<WithDrop index={ rowIndex } { ...tagComponent('configurable-item-row', this.props) }>
<li className={ this.classes(this.context.dragAndDropActiveIndex, rowIndex) }>
<div className='configurable-item-row__content-wrapper'>
{ this.icon() }
{ this.checkbox(enabled, locked, name, onChange) }
</div>
</li>
<li
className={ this.classes(this.context.dragAndDropActiveIndex, rowIndex) }
ref={ (node) => { this._listItem = node; } }
>
<div className='configurable-item-row__content-wrapper'>
{ this.icon() }
{ this.checkbox(enabled, locked, name, onChange) }
</div>
</li>
);
}

render() {
return (
<WithDrop index={ this.props.rowIndex } { ...tagComponent('configurable-item-row', this.props) }>
{ this.listItemHTML() }
</WithDrop>
);
}
Expand Down
Expand Up @@ -13,6 +13,12 @@
cursor: -webkit-grabbing;
}

.configurable-item-row--dragged {
.configurable-item-row__content-wrapper {
visibility: hidden;
}
}

.configurable-item-row__content-wrapper {
align-items: center;
display: flex;
Expand All @@ -22,3 +28,23 @@
.configurable-item-row__icon {
cursor: move;
}

.custom-drag-layer {
.configurable-item-row {
background-color: $grey-light;
border: none;
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;

.configurable-item-row__icon {
cursor: grabbing;
cursor: -moz-grabbing;
cursor: -webkit-grabbing;
}

.configurable-item-row__content-wrapper {
visibility: visible;
}
}
}
@@ -0,0 +1,14 @@
import CustomDragLayer from './';
import Definition from './../../../../demo/utils/definition';

const definition = new Definition('custom-drag-layer', CustomDragLayer, {
props: ['className'],
propTypes: {
className: 'String'
},
propDescriptions: {
className: 'Custom classes to apply to the component'
}
});

export default definition;