-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
React 16 upgrade #406
React 16 upgrade #406
Changes from 48 commits
1aecb36
a239603
23265cf
dc1c883
ee4b62c
0f14e89
85dc4d5
866d8a9
6849915
bdc7a7d
10110c4
e4084f6
f1d8072
bca56b4
c10645b
dbd17de
190160f
820c735
26084ab
2f00bee
a29f747
098ff97
6817c29
5ecf037
a8347de
c865e54
393024a
ed2e2ab
4a31794
6a2ee84
fdb91ff
7310391
8efa9fc
4a371ee
c666f04
b19dfad
abd2a39
d257a75
8fd4036
31744b8
eb7195f
d1cec09
350eb9a
42d4bcb
431f417
d69574b
ec03035
0ba08a2
0bf62e0
c1a6a99
9b19065
704f5a0
27643d0
e8d5f23
acaec94
23e413c
eecb5c7
a9e6aaa
d1abdef
9aa5374
1a5e0ec
2cbe25f
8056b5c
864b85f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# Tables | ||
|
||
| Benefits of using `<table>` | Provider | | ||
|--------------------------------------------------|-------------------------| | ||
| Clean way of displaying tabular data | Browser | | ||
| Great browser support | Browser | | ||
| Can copy paste the table into other applications | Browser | | ||
| Can reorder items in the table! | `react-beautiful-dnd` 😎| | ||
|
||
`react-beautiful-dnd` supports requires no additional wrapping elements to create `Draggable` and `Droppable` components. Therefore it is possible to have a `<table>` that has valid HTML as well as supporting drag and drop. | ||
|
||
> We have not found a way to achieve semantic reordering of table columns at this stage. This is because there is no one element that represents a table column - rather, a column is a result of cell placements within repeating rows. As such as cannot wrap a `Draggable` around a 'column' in order to make it draggable. PR's to this guide are welcome if you find a working approach! | ||
|
||
## Strategies | ||
|
||
There are two strategies you can use when reordering tables. | ||
|
||
1. Fixed layouts (faster and simplier) | ||
2. Dimension locking (slower but more robust) | ||
|
||
### Strategy 1: fixed layouts | ||
|
||
In order to use this strategy the widths of your columns need to be fixed - that is, they will not change depending on what content is placed in the cells. This can be achieve with either a `table-layout: fixed` or `table-layout: auto` as long as you manually set the width of the cells (eg `50%`). | ||
|
||
The only thing you need to do is set `display: table` on a `Draggable` row while it is dragging. | ||
|
||
[See example code here](TODO) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We do now! 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll update the links |
||
|
||
### Strategy 2: dimension locking | ||
|
||
This strategy will work with columns that have automatic column widths based on content. It will also work with fixed layouts. **It is a more robust strategy than the first, but it is also less performant.** | ||
|
||
When we apply `position: fixed` to the dragging item it removes it from the automatic column width calculations that a table uses. So before a drag starts we *lock* all of the cell widths using inline styles to prevent the column dimensions from changing when a drag starts. | ||
|
||
This has poor performance characteristics at scale as it requires: | ||
|
||
1. Calling `render()` on every row | ||
2. Reading the DOM (`window.getComputedStyles`) on every row | ||
|
||
For tables with less than 50 rows this should approach be fine! | ||
|
||
[See example code here](TODO) | ||
|
||
## Advanced: using [`React.Portal`](https://reactjs.org/docs/portals.html) | ||
|
||
If you want to use `React.Portal` in combination with table row reordering then there are few extra steps you need to go through. | ||
|
||
First up, have a read of our [using a portal guide](docs/guides/using-a-portal.md) to get familiar with the approach. | ||
|
||
It is important to know things timings of mount / unmount actions in React. We have created a [codesandbox.io example](https://codesandbox.io/s/nkl52y1wn0) to show how the mount timings work when moving in and out of a `React.Portal`. | ||
|
||
When moving an existing `<tr>` into a `React.Portal` it is important to know that the existing `<tr>` is unmounted and a new `<tr>` is mounted into the portal. Here is the order of those operations: | ||
|
||
1. The old `<tr>` has `componentWillUnmount` called | ||
2. The new `<tr>` has `componentWillMount` called | ||
|
||
In order to preserve the cell dimensions of the cells in the row that we are moving into a `React.Portal` we need to lock its dimensions using inline styles (see strategy #2). Sadly though, the new component does not directly have access to the information about the component that was in the tree before it moved to the portal. So in order to do this we need to obtain the cell dimensions of the `<tr>` when it is unmounting and re-apply it to the new `<tr>` when it mounted in `componentDidMount`. | ||
|
||
There is no great way to do this as when `componentDidMount` is called we are not sure if the component is unmouting as the `tr` is no longer needed, or if it is unmounting because it is about to move into a portal. | ||
|
||
It seems like the only way to get things working is to: | ||
|
||
1. In `componentWillUnmount` of the `tr` read the current widths of the cells from the DOM. You then store this value outside of the component so that it can be read by new components that are mounting. | ||
2. If a component is mounting and `DraggableStateSnapshot > isDragging` is true then you can see if there is a previously recorded width. If there is then you can apply that width. | ||
|
||
This gets a little complicated - so we [created another example](TODO) for you showing you how this technique works! You're welcome! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Using a Portal | ||
|
||
> This guide will go through how you can move your `Draggable` into a [`React.Portal`](https://reactjs.org/docs/portals.html) while dragging. | ||
|
||
## Background | ||
|
||
We leave elements in place when dragging. We apply `position: fixed` on elements when we are moving them around. This is quite robust and allows for you to have `position: relative | absolute | fixed` parents. However, unfortunately `position:fixed` is [impacted by `transform`](http://meyerweb.com/eric/thoughts/2011/09/12/un-fixing-fixed-elements-with-css-transforms/) (such as `transform: rotate(10deg);`). This means that if you have a `transform: *` on one of the parents of a `Draggable` then the positioning logic will be incorrect while dragging. Lame! For most consumers this will not be an issue. | ||
|
||
To get around the issue you can use a `portal`. | ||
|
||
## `Portals` | ||
|
||
Wait, what is a `portal`? A `portal` is a simply another DOM node outside of the current component tree. By using a portal you are able to move the `Draggable` into another DOM node while dragging. This can allow you to get around the limitations of `position: fixed`. | ||
|
||
## Not using `React.Portal` by default | ||
|
||
React provides a first class api for using `portals`: [`React.Portal`](https://reactjs.org/docs/portals.html). Originally we wanted to use it for all `Draggable`s while dragging. Unfortunately it has a big performance penalty - especially when dragging nodes with a lot of children ([React issue](https://github.com/facebook/react/issues/12247)). The reason for this is because components moving to a `React.Portal` are mounted and remounted which is quite expensive. Therefore we are currently not supporting it out of the box. | ||
|
||
If your `Draggable` does not have many children nodes then you are welcome to use `React.Portal` on top of `react-beautiful-dnd`. If you are simply dragging cards in a list then you *should* be fine using `React.Portal`. However, if you are dragging a column full of cards then you will get significant jank when a drag is starting. | ||
|
||
## Example | ||
|
||
<!-- TODO: embed example here on new website --> | ||
|
||
We have created a [working example](https://react-beautiful-dnd.netlify.com/?selectedKind=Portals&selectedStory=Using%20your%20own%20portal&full=0&addons=1&stories=1&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel) that uses `React.Portal` to guide you. You can view the [source here](https://github.com/atlassian/react-beautiful-dnd/blob/master/stories/11-portal-story.js) | ||
|
||
## Tables | ||
|
||
If are doing drag and drop reordering within a `<table>` we have created a portal section inside our [table guide](/docs/patterns/tables) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"
react-beautiful-dnd
requires no additional"