Skip to content

Commit

Permalink
CustomDragLayer component for enabling Drag & Drop ghost row
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Paul Sturgess committed Aug 21, 2017
1 parent 10b49d4 commit 19b052b
Show file tree
Hide file tree
Showing 19 changed files with 683 additions and 109 deletions.
46 changes: 45 additions & 1 deletion CHANGELOG.md
Expand Up @@ -4,12 +4,56 @@

* `ConfigurableItems` now accepts an `onReset` prop to be passed in.

### npm
## npm

* Carbon now require `npm` version 5 for installing dependencies.
* To upgrade your version of npm, run `npm install npm@latest`.
* Then, before running `npm install` in your project folder, run `npm verify cache` to update your cache.

## 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.4.4

* `Date`: Fixes missing background color on validation errors.
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;
}
}
}
14 changes: 14 additions & 0 deletions src/components/drag-and-drop/custom-drag-layer/__definition__.js
@@ -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;

0 comments on commit 19b052b

Please sign in to comment.