Skip to content

Commit

Permalink
Merge branch 'master' of github.com:atlassian/react-beautiful-dnd int…
Browse files Browse the repository at this point in the history
…o pivot
  • Loading branch information
alexreardon committed Jun 15, 2018
2 parents adfe9a9 + ffa1405 commit c542979
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 34 deletions.
38 changes: 30 additions & 8 deletions ISSUE_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,52 @@
(answer here)

<!--
If raising a feature request please be sure to have a search
through other open and closed issues tagged with 'new feature'
## Duplicates
https://github.com/atlassian/react-beautiful-dnd/issues?utf8=%E2%9C%93&q=is%3Aopen%20is%3Aclosed%20is%3Aissue%20
Before raising a feature request or bug please search through our open and closed issues
to see if there is something similiar. If you do find one similiar you can show it is important
to you by adding a reaction (such as 👍) to the issue
Before raising a new feature please take a look at the core design
principles of the library:
Open and closed issues:
https://github.com/atlassian/react-beautiful-dnd/issues?utf8=%E2%9C%93&q=is%3Aopen%20is%3Aclosed%20is%3Aissue%20
-->

https://github.com/atlassian/react-beautiful-dnd#driving-philosophy-physicality
<!--
## Feature request
This is not a general purpose drag and drop library and is attempting
to create an experience that is more physical than standard drag and drop
interactions on the web.
Before raising a new feature please ensure that it falls within the philosophy
of the library.
https://github.com/atlassian/react-beautiful-dnd#driving-philosophy-physicality
-->

<!-- If raising a bug -->
<!-- ## Bug -->

### Expected behavior

### Actual behavior

### Steps to reproduce

### Browser version
### What version of `React` are you using?

<!--
Take a look at your package.json
Ensure that it satifies our peer dependency version - see our package.json. (Currently it is "^16.3.1")
-->

### What version of `react-beautiful-dnd` are you running?

<!--
We will only look into issues that are effecting the latest version.
At this stage we are not releasing fixes for previous releases
-->

### What browser are you using?

<!--
Keep in mind our supported browser matrix https://confluence.atlassian.com/cloud/supported-browsers-744721663.html
Expand Down
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Beautiful, accessible drag and drop for lists with [`React.js`](https://facebook

[![Build Status](https://travis-ci.org/atlassian/react-beautiful-dnd.svg?branch=master)](https://travis-ci.org/atlassian/react-beautiful-dnd) [![npm](https://img.shields.io/npm/v/react-beautiful-dnd.svg)](https://www.npmjs.com/package/react-beautiful-dnd) [![dependencies](https://david-dm.org/atlassian/react-beautiful-dnd.svg)](https://david-dm.org/atlassian/react-beautiful-dnd) [![Greenkeeper badge](https://badges.greenkeeper.io/atlassian/react-beautiful-dnd.svg)](https://greenkeeper.io/) [![SemVer](https://img.shields.io/badge/SemVer-2.0.0-brightgreen.svg)](http://semver.org/spec/v2.0.0.html)

![example](https://raw.githubusercontent.com/alexreardon/files/master/resources/dnd.small.gif?raw=true)
![quote application example](https://raw.githubusercontent.com/alexreardon/files/master/resources/website-board.gif?raw=true)

## Examples 🎉

Expand Down Expand Up @@ -381,7 +381,7 @@ cursor: grab;
An optimisation to avoid processing `pointer-events` while dragging. Also used to allow scrolling through a drag handle with a track pad or mouse wheel.

```css
point-events: none;
pointer-events: none;
```

#### (Phase: dragging): Draggable element
Expand Down Expand Up @@ -768,8 +768,11 @@ type DroppableProps = {|
|}
```
- `provided.innerRef`: In order for the droppable to function correctly, **you must** bind the `provided.innerRef` to the highest possible DOM node in the `ReactElement`. We do this in order to avoid needing to use `ReactDOM` to look up your DOM node. *This prop is planned to be removed when we move to React 16*
- `provided.placeholder`: This is used to create space in the `Droppable` as needed during a drag. This space is needed when a user is dragging over a list that is not the home list. Please be sure to put the placeholder inside of the component for which you have provided the ref. We need to increase the size of the `Droppable` itself. This is different from `Draggable` where the `placeholder` needs to be a *sibling* to the draggable node.
- `provided.innerRef`: In order for the droppable to function correctly, **you must** bind the `provided.innerRef` to the highest possible DOM node in the `ReactElement`. We do this in order to avoid needing to use `ReactDOM` to look up your DOM node.
> For more information on using `innerRef` see our [using `innerRef` guide](/docs/patterns/using-inner-ref.md)
- `provided.placeholder`: This is used to create space in the `Droppable` as needed during a drag. This space is needed when a user is dragging over a list that is not the home list. Please be sure to put the placeholder inside of the component for which you have provided the ref. We need to increase the size of the `Droppable` itself.
- `provided.droppableProps (DroppableProps)`: This is an Object that contains properties that need to be applied to a Droppable element. It needs to be applied to the same element that you apply `provided.innerRef` to. It currently contains a `data` attribute that we use to control some non-visible css.
```js
Expand Down Expand Up @@ -969,6 +972,8 @@ Everything within the *provided* object must be applied for the `Draggable` to f
- `provided.innerRef (innerRef: (HTMLElement) => void)`: In order for the `Droppable` to function correctly, **you must** bind the `innerRef` function to the `ReactElement` that you want to be considered the `Draggable` node. We do this in order to avoid needing to use `ReactDOM` to look up your DOM node.
> For more information on using `innerRef` see our [using `innerRef` guide](/docs/patterns/using-inner-ref.md)
##### `innerRef` Example
```js
Expand Down Expand Up @@ -1242,7 +1247,7 @@ The `children` function is also provided with a small amount of state relating t
### `Draggable` placeholder
When dragging a `Draggable` we leave behind a *placeholder* `React.Element` to maintain space in the `Droppable` in order to prevent it from collapsing. The placeholder mimics the styling and layout (including `width`, `height`, `margin`, `tagName` and `display`) to ensure the list dimensions remain unaffected while dragging. It will be inserted as a direct sibling to the `React.Node` returned by the `Draggable` children function.
When dragging a `Draggable` we leave behind a *placeholder* `React.Element` to maintain space in the `Droppable` in order to prevent it from collapsing. The placeholder mimics the styling and layout (including `width`, `height`, `margin`, `tagName` and `display`) to ensure the list dimensions remain unaffected while dragging. It will be inserted by `react-beautiful-dnd` as a direct sibling to the `React.Node` returned by the `Draggable` children function.
### Adding an `onClick` handler to a `Draggable` or a *drag handle*
Expand Down Expand Up @@ -1448,6 +1453,12 @@ These translations are maintained by the community and are not reviewed or maint
Alex Reardon - [@alexandereardon](https://twitter.com/alexandereardon)
## Other maintainers
## Maintainers
Jared Crowe - [@jaredjcrowe](https://twitter.com/jaredjcrowe)
## Collaborators
Bogdan Chadkin - [@IAmTrySound](https://twitter.com/)
Luke Batchelor - [@alukebatchelor](https://twitter.com/alukebatchelor)
Many other [@Atlassian](https://twitter.com/Atlassian)'s!
214 changes: 214 additions & 0 deletions docs/guides/using-inner-ref.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
# Using `innerRef`

> If you have not used `ref`'s before, please take a look at the [`React`: Refs and the DOM guide](https://reactjs.org/docs/refs-and-the-dom.html) on their documentation website.
Our `Draggable` and `Droppable` components both require a *DOM node* to be provided to them. This is done using the `innerRef` property on the `DraggableProvided` and `DroppableProvided` objects.

```diff
<Draggable draggableId="draggable-1" index={0}>
{(provided, snapshot) => (
<div
+ ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<h4>My draggable</h4>
</div>
)}
</Draggable>;
```

```diff
<Droppable droppableId="droppable-1">
{(provided, snapshot) => (
<div
+ ref={provided.innerRef}
{...provided.droppableProps}
>
<h2>I am a droppable!</h2>
{provided.placeholder}
</div>
)}
</Droppable>;
```

## Not all `ref`s are created equal

Confusion can arise because of how the `ref` callback works in `React`.

On a *Component* such as `<Person />` the `ref` callback will return the *instance* of the `Person` component.

On a *Element* such as `<div />` the `ref` callback will return the *DOM node* that the *Element* is tied to.

[See on `codesandbox.io`](https://codesandbox.io/s/xok96ovo8p)

```js
class Person extends React.Component {
state = {
sayHello: false,
};
sayHello() {
this.setState({
sayHello: true,
});
}
render() {
if (this.state.sayHello) {
return <div {...this.props}>Hello</div>;
}

return <div {...this.props}>'I am a person, I think..'</div>;
}
}

class App extends React.Component {
setPersonRef = ref => {
this.personRef = ref;

// When the ref changes it will firstly be set to null
if (this.personRef) {
// personRef is an instance of the Person class
this.personRef.sayHello();
}
};
setDivRef = ref => {
this.divRef = ref;

if (this.divRef) {
// div ref is a HTMLElement
this.divRef.style.backgroundColor = 'lightgreen';
}
};
render() {
return (
<React.Fragment>
<Person ref={this.setPersonRef} />
<div ref={this.setDivRef}>hi there</div>
</React.Fragment>
);
}
}
```

## A common error 🐞

Take a look at this example:

```js
<Draggable draggableId="draggable-1" index={0}>
{(provided, snapshot) => (
<Person
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
/>
)}
</Draggable>
```

While it looks correct, it **will cause your application to explode 💥!**

This is because `react-beautiful-dnd` expects the `provided.innerRef` function for a `Draggable` and a `Droppable` to be called with the DOM node of the component, and not the *instance* of the class. In this example we are calling `provided.innerRef` with an *instance* of `Person` and not the underlying DOM node.

## Exposing a DOM ref from your Component 🤩

A simple way to expose the *DOM node* of your component is to **create your own `innerRef` prop**:

```js
class Person extends React.Component {
render() {
return (
<div {...this.props} ref={this.props.innerRef}>
I am a person, I think..
</div>
);
}
}
```

> Note, the name `innerRef` is just a convention. You could call it whatever you want for your component. Something like `domRef` is fine.
You can then correctly supply the DOM node to a `Draggable` or `Droppable`

```diff
<Draggable draggableId="draggable-1" index={0}>
{(provided, snapshot) => (
<Person
- ref={provided.innerRef}
+ innerRef={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<h4>My draggable</h4>
</div>
)}
</Draggable>
```

⚠️ This approach will cause a `React` warning as we are spreading all of the props of the component onto the DOM node. `{...this.props}` This includes the `innerRef` prop which `React` does not like you adding to an element. So you can set things up like this:

```diff
class Person extends React.Component {
render() {
- return (
- <div {...this.props} ref={this.props.innerRef}>
- I am a person, I think..
- </div>
- );
}
}
class Person extends React.Component {
render() {
+ const { provided, innerRef } = this.props;
+ return (
+ <div
+ {...provided.draggableProps}
+ {...provided.dragHandleProps}
+ ref={innerRef}
+ >
+ I am a person, I think..
+ </div>
+ );
}
}

<Draggable draggableId="draggable-1" index={0}>
{(provided, snapshot) => (
<Person
innerRef={provided.innerRef}
- {...provided.draggableProps}
- {...provided.dragHandleProps}
+ provided={provided}
/>
)}
</Draggable>
```

If you also need to use the *DOM node* within your *Component* you can have a more powerful ref setting approach:

```js
class Person extends React.Component {
setRef = ref => {
// keep a reference to the dom ref as an instance property
this.ref = ref;
// give the dom ref to react-beautiful-dnd
this.props.innerRef(ref);
};
render() {
const { provided, innerRef } = this.props;
return (
<div
{...provided.draggableProps}
{...provided.dragHandleProps}
ref={this.setRef}
>
I am a person, I think..
</div>
);
}
}
```

## Putting it all together

Here is an example that shows off the learnings presented in this guide: https://codesandbox.io/s/v3p0q71qn5
2 changes: 1 addition & 1 deletion website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"gatsby-transformer-remark": "^1.7.39",
"lodash.lowercase": "^4.3.0",
"react": "^16.3.1",
"react-codesandboxer": "^2.0.3",
"react-codesandboxer": "^2.1.2",
"react-dom": "^16.3.1",
"react-helmet": "^5.2.0",
"react-icons": "^2.2.7",
Expand Down
7 changes: 3 additions & 4 deletions website/src/components/ExampleWrapper.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@ import pkg from '../../../package.json';
import { grid } from '../constants';

const gitInfo = {
account: 'noviny',
account: 'atlassian',
repository: 'react-beautiful-dnd',
host: 'github',
branch: 'website-layout',
};

// this needs to handle internal v external
Expand Down Expand Up @@ -68,8 +67,8 @@ const Wrapper = styled.div`
type Props = {
children: Node,
path: string,
title: string,
}
title: string
};

const ExampleWrapper = ({ children, path, title }: Props) => (
<div>
Expand Down
Loading

0 comments on commit c542979

Please sign in to comment.