Skip to content

Commit 72ff4e3

Browse files
authored
Merge pull request #35 from jrowny/2.0-pure
2.0 pure components
2 parents 4013705 + c169d4b commit 72ff4e3

8 files changed

+364
-276
lines changed

README.md

+46-28
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,38 @@ Usage:
77

88
Install with `npm install react-absolute-grid`
99

10-
import React from 'react';
11-
import AbsoluteGrid from './lib/AbsoluteGrid.jsx';
10+
```javascript
11+
import React from 'react';
12+
import createAbosluteGrid from './lib/AbsoluteGrid.jsx';
1213

13-
var sampleItems = [
14-
{key: 1, name: 'Test', sort: 0, filtered: 0},
15-
{key: 2, name: 'Test 1', sort: 1, filtered: 0},
16-
];
14+
// This is the component that will display your data
15+
import YourDisplayComponent from 'your-display-component';
1716

18-
React.render(<AbsoluteGrid items={sampleItems} />, document.getElementById('Container'));
17+
var sampleItems = [
18+
{key: 1, name: 'Test', sort: 0, filtered: 0},
19+
{key: 2, name: 'Test 1', sort: 1, filtered: 0},
20+
];
1921

22+
// Pass your display component to create a new grid
23+
const AbsoluteGrid = createAbsoluteGrid(YourDisplayComponent, {someProp: 'my component needs this'});
24+
React.render(<AbsoluteGrid items={sampleItems} />, document.getElementById('Container'));
25+
```
2026

21-
Options (Properties)
27+
CreateAbsoluteGrid
2228
------
29+
```javascript
30+
createAbsoluteGrid(DisplayComponent, displayProps = {}, forceImpure = false)
31+
```
32+
33+
* `DisplayComponent`: is a react component to display in your grid
34+
* `displayProps`: *optional* : are properties you want passed down to the DisplayComponent such as event handlers.
35+
* `forceImpure`: *optional* : **not recommended** Will make this function as an impure component, meaning it always renders.
2336

37+
Options (Properties)
38+
------
2439
| Property | Default | Description |
2540
|---|:---:|---|
2641
| **items** | [] | The array of items in the grid |
27-
| **displayObject** | (required) | The React component to render items |
2842
| **keyProp** | 'key' | The property to be used as a key |
2943
| **filterProp** | 'filtered' | The property to be used for filtering, if the filtered value is true, the item won't be displayed. It's important to not remove items from the array because that will cause React to remove the DOM, for performance we would rather hide it then remove it. |
3044
| **sortProp** | 'sort' | The property to sort on |
@@ -36,47 +50,51 @@ Options (Properties)
3650
| **animation** | 'transform 300ms ease' | The CSS animation to use on elements. Pass a blank string or `false` for no animation. |
3751
| **zoom** | 1 | Zooms the contents of the grid, 1 = 100% |
3852
| **onMove** | `fn(from, to)` | This function is called when an item is dragged over another item. It is your responsibility to update the sort of all items when this happens. |
53+
| **onDragStart** | `fn(e)` | This function is called when an item starts dragging, this is NOT required. |
54+
| **onDragMove** | `fn(e)` | This function is called when as an item is being moved, this is NOT required. |
55+
| **onDragEnd** | `fn(e)` | This function is called when an item has finished its drag, this is NOT required. |
3956

40-
Creating a DisplayObject component
57+
Your Component
4158
------
42-
displayObject component will receive `item`, `index` and `itemsLength` as props. Here's the simplest possible example:
43-
44-
import React from 'react';
45-
46-
export default class SampleDisplay extends React.Component {
47-
48-
render() {
49-
// Supposing your item shape is something like {name: 'foo'}
50-
const { item, index, itemsLength } = this.props;
51-
return <div>Item {index} of {itemsLength}: {item.name}</div>;
52-
}
53-
}
59+
Your component will receive `item`, `index` and `itemsLength` as props, as well as anything you pass into the createAbsoluteGrid function. Here's the simplest possible example:
5460

55-
Once you've created a display object, use it like this:
61+
```javascript
62+
import React from 'react';
5663

57-
var grid = (<AbsoluteGrid ... displayObject={(<SampleDisplay {...pass props normally} />)}/>);
64+
export default function SampleDisplay(props) {
65+
// Supposing your item shape is something like {name: 'foo'}
66+
const { item, index, itemsLength } = props;
67+
return <div>Item {index} of {itemsLength}: {item.name}</div>;
68+
}
69+
```
5870

5971
What Makes AbsoluteGrid Unique?
6072
----
61-
The idea behind AbsoluteGrid is high performance. This is achieved by using Translate3d to position each item in the layout. Items are never removed from the DOM, instead they are hidden. For best performance you should avoid re-arranging or removing items which you pass into AbsoluteGrid, instead you can use the `filtered` and `sort` properties to hide or sort an item. Those properties are customizable using the `keyProp` and `filterProp` properties.
73+
The idea behind AbsoluteGrid is high performance. This is achieved by using Translate3d to position each item in the layout. Items are never removed from the DOM, instead they are hidden. For best performance you should avoid re-arranging or removing items which you pass into AbsoluteGrid, instead you can use the `filtered` and `sort` properties to hide or sort an item. Those properties are customizable using the `keyProp` and `filterProp` properties. In addition, all data passed must be immutable so that we don't waste any renders.
6274

63-
DisplayObject props
75+
Your Display Component props
6476
----
65-
Each DisplayObject component is passed the following props.
77+
Each Component is passed the following props, as well as anything passed into the second parameter of `createAbsoluteGrid`
6678

6779
| Property | Description |
6880
|---|:---|
6981
| **item** | The data associated with the GridItem |
7082
| **index** | The index of the item data in the `items` array |
7183
| **itemsLength** | The total length of the `items` array |
72-
84+
| **...displayProps** | props passed into `createAbsoluteGrid` |
7385

7486
ToDo:
7587
-----
88+
* Tests
7689
* Improve Drag & Drop browser support and reliability
7790

7891
Browser Compatibility
7992
-----
8093
This component should work in all browsers that [support CSS3 3D Transforms](http://caniuse.com/#feat=transforms3d). If you need IE9 support you can modify it to use transform rather than transform3d. Pull requests welcome!
8194

8295
Drag and Drop only works on IE11+ due to lack of pointer events, although there is a workaround coming soon.
96+
97+
Migrating from 2.x
98+
-----
99+
100+
Instead of passing `displayObject` to the AbsoluteGrid component, pass the component directly into the composer function, `createAbsoluteGrid` which returns an AbsoluteGrid component. That's it!

demo.js

+38-18
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
import React from 'react';
44
import ReactDOM from 'react-dom';
5-
import AbsoluteGrid from './index.js';
5+
import Perf from 'react-addons-perf';
6+
import createAbsoluteGrid from './index.js';
67
import SampleDisplay from './demo/SampleDisplay.jsx';
78
import * as data from './demo/sampleData.js';
89
import * as _ from 'lodash';
@@ -20,16 +21,22 @@ demo();
2021

2122
function demo() {
2223

23-
var sampleItems = data.screens;
24-
var displayObject = (<SampleDisplay/>);
25-
var render;
26-
var zoom = 0.7;
24+
let sampleItems = data.screens;
25+
let render;
26+
let zoom = 0.7;
2727

2828
//We set a property on each item to let the grid know not to show it
2929
var onFilter = function(event){
3030
var search = new RegExp(event.target.value, 'i');
31-
sampleItems.forEach(function(item){
32-
item.filtered = !item.name.match(search);
31+
sampleItems = sampleItems.map(function(item){
32+
const isMatched = !item.name.match(search);
33+
if(!item.filtered || isMatched !== item.filtered) {
34+
return {
35+
...item,
36+
filtered: isMatched
37+
}
38+
}
39+
return item;
3340
});
3441
render();
3542
};
@@ -39,24 +46,37 @@ function demo() {
3946
source = _.find(sampleItems, {key: parseInt(source, 10)});
4047
target = _.find(sampleItems, {key: parseInt(target, 10)});
4148

42-
var targetSort = target.sort;
49+
const targetSort = target.sort;
4350

4451
//CAREFUL, For maximum performance we must maintain the array's order, but change sort
45-
sampleItems.forEach(function(item){
52+
sampleItems = sampleItems.map(function(item){
4653
//Decrement sorts between positions when target is greater
47-
if(target.sort > source.sort && (item.sort <= target.sort && item.sort > source.sort)){
48-
item.sort --;
49-
//Incremenet sorts between positions when source is greator
50-
}else if(item.sort >= target.sort && item.sort < source.sort){
51-
item.sort ++;
54+
if(item.key === source.key) {
55+
return {
56+
...item,
57+
sort: targetSort
58+
}
59+
} else if(target.sort > source.sort && (item.sort <= target.sort && item.sort > source.sort)){
60+
return {
61+
...item,
62+
sort: item.sort - 1
63+
};
64+
//Increment sorts between positions when source is greater
65+
} else if (item.sort >= target.sort && item.sort < source.sort){
66+
return {
67+
...item,
68+
sort: item.sort + 1
69+
};
5270
}
71+
return item;
5372
});
54-
55-
source.sort = targetSort;
73+
Perf.start();
5674
render();
75+
Perf.stop();
76+
Perf.printWasted();
5777
};
5878

59-
var onMoveDebounced = _.debounce(onMove, 80);
79+
var onMoveDebounced = _.debounce(onMove, 40);
6080

6181
var unMountTest = function(){
6282
if(ReactDOM.unmountComponentAtNode(document.getElementById('Demo'))){
@@ -67,9 +87,9 @@ function demo() {
6787
}
6888
};
6989

90+
const AbsoluteGrid = createAbsoluteGrid(SampleDisplay);
7091
render = function(){
7192
ReactDOM.render(<AbsoluteGrid items={sampleItems}
72-
displayObject={displayObject}
7393
onMove={onMoveDebounced}
7494
dragEnabled={true}
7595
zoom={zoom}

demo/AbsoluteGrid.js

+14-9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)