Skip to content

Commit c8a53a3

Browse files
author
Joey Hobbs
committed
feat(toolbox): introducing toolbox in example 14
1 parent 9ff2d83 commit c8a53a3

File tree

8 files changed

+323
-21
lines changed

8 files changed

+323
-21
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ RGL is React-only and does not require jQuery.
7676
* Responsive breakpoints
7777
* Separate layouts per responsive breakpoint
7878
* Grid Items placed using CSS Transforms
79+
* Interactive toolbox for additional widgets
7980
* Performance: [on](http://i.imgur.com/FTogpLp.jpg) / [off](http://i.imgur.com/gOveMm8.jpg), note paint (green) as % of time
8081

8182
|Version | Compatibility |

examples/13-error-case.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ <h3>React-Grid-Layout Demo 13 - Error Case</h3>
1616
<li><a href="https://github.com/STRML/react-grid-layout/blob/master/test/examples/13-error-case.jsx">View this example's source</a></li>
1717

1818
<li><a href="12-prevent-collision.html"><b></b> View the previous example: "Prevent Collision"</a></li>
19-
</ul>
19+
20+
<li><a href="14-toolbox.html"><b></b>View the next example: "Toolbox"</a></li>
21+
</ul>
2022
<p>This is an extra test case for a collision bug fixed in November 2017. When you drag 1 over 2, it should not move over 3.</p>
2123
<div id="content"></div>
2224
</body>

examples/14-toolbox.html

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<!--
2+
Do not edit this file! It is generated by `generate.js` in this folder, from `template.ejs` and vars.js.
3+
-->
4+
<!DOCTYPE html>
5+
<html>
6+
<head>
7+
<meta charset="UTF-8">
8+
<script src="http://localhost:4002/dist/commons.js"></script>
9+
<script src="http://localhost:4002/dist/14-toolbox.bundle.js"></script>
10+
<title>RGL Example 14 - Toolbox</title>
11+
</head>
12+
<body>
13+
<h3>React-Grid-Layout Demo 14 - Toolbox</h3>
14+
<ul>
15+
<li><a href="https://github.com/STRML/react-grid-layout">View project on GitHub</a></li>
16+
<li><a href="https://github.com/STRML/react-grid-layout/blob/master/test/examples/14-toolbox.jsx">View this example's source</a></li>
17+
18+
<li><a href="13-error-case.html"><b></b> View the previous example: "Error Case"</a></li>
19+
</ul>
20+
<p>This includes an interactive toolbox. Try dragging widgets into it!</p>
21+
<div id="content"></div>
22+
</body>
23+
</html>

examples/example-styles.css

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ body {
5050
.react-grid-item .add {
5151
cursor: pointer;
5252
}
53-
.react-grid-dragHandleExample{
53+
.react-grid-dragHandleExample {
5454
cursor: move; /* fallback if grab cursor is unsupported */
5555
cursor: grab;
5656
cursor: -moz-grab;
@@ -60,3 +60,34 @@ li b {
6060
font-size: 19px;
6161
line-height: 14px;
6262
}
63+
64+
.react-grid-layout__toolbox {
65+
background-color: #dfd;
66+
width: 100%;
67+
height: 120px;
68+
overflow: scroll;
69+
}
70+
71+
.react-grid-layout__toolbox.is-active {
72+
background-color: #fdd;
73+
}
74+
75+
.toolbox__title {
76+
font-size: 24px;
77+
margin-bottom: 5px;
78+
}
79+
.toolbox__items {
80+
display: block;
81+
}
82+
.toolbox__items__item {
83+
display: inline-block;
84+
text-align: center;
85+
line-height: 40px;
86+
cursor: pointer;
87+
width: 40px;
88+
height: 40px;
89+
padding: 10px;
90+
margin: 5px;
91+
border: 1px solid black;
92+
background-color: #ddd;
93+
}

examples/vars.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,11 @@ module.exports = [
124124
'move over 3.'
125125
]
126126
},
127+
{
128+
title: 'Toolbox',
129+
source: 'toolbox',
130+
paragraphs: [
131+
'This includes an interactive toolbox. Try dragging widgets into it!'
132+
]
133+
},
127134
];

lib/ReactGridLayout.jsx

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import classNames from "classnames";
66
import {
77
autoBindHandlers,
88
bottom,
9+
nodesCollide,
910
childrenEqual,
1011
cloneLayoutItem,
1112
compact,
@@ -38,7 +39,8 @@ type State = {
3839
mounted: boolean,
3940
oldDragItem: ?LayoutItem,
4041
oldLayout: ?Layout,
41-
oldResizeItem: ?LayoutItem
42+
oldResizeItem: ?LayoutItem,
43+
draggingOverToolbox: boolean
4244
};
4345

4446
export type Props = {
@@ -58,6 +60,7 @@ export type Props = {
5860
maxRows: number,
5961
isDraggable: boolean,
6062
isResizable: boolean,
63+
toolbox: ReactElement<any>,
6164
preventCollision: boolean,
6265
useCSSTransforms: boolean,
6366

@@ -69,6 +72,7 @@ export type Props = {
6972
onResize: EventCallback,
7073
onResizeStart: EventCallback,
7174
onResizeStop: EventCallback,
75+
onPutItem: EventCallback,
7276
children: ReactChildrenArray<ReactElement<any>>
7377
};
7478
// End Types
@@ -196,7 +200,9 @@ export default class ReactGridLayout extends React.Component<Props, State> {
196200
}
197201
keys[child.key] = true;
198202
});
199-
}
203+
},
204+
205+
toolbox: PropTypes.element
200206
};
201207

202208
static defaultProps = {
@@ -238,9 +244,12 @@ export default class ReactGridLayout extends React.Component<Props, State> {
238244
mounted: false,
239245
oldDragItem: null,
240246
oldLayout: null,
241-
oldResizeItem: null
247+
oldResizeItem: null,
248+
draggingOverToolbox: false
242249
};
243250

251+
toolboxRef: ?HTMLDivElement = null;
252+
244253
constructor(props: Props, context: any): void {
245254
super(props, context);
246255
autoBindHandlers(this, [
@@ -372,6 +381,15 @@ export default class ReactGridLayout extends React.Component<Props, State> {
372381
cols
373382
);
374383

384+
if (this.toolboxRef) {
385+
let draggingOverToolbox = false;
386+
if (nodesCollide(node, this.toolboxRef)) {
387+
placeholder = null;
388+
draggingOverToolbox = true;
389+
}
390+
this.setState({ draggingOverToolbox });
391+
}
392+
375393
this.props.onDrag(layout, oldDragItem, l, placeholder, e, node);
376394

377395
this.setState({
@@ -408,6 +426,15 @@ export default class ReactGridLayout extends React.Component<Props, State> {
408426
cols
409427
);
410428

429+
if (this.toolboxRef) {
430+
if (nodesCollide(node, this.toolboxRef)) {
431+
layout = layout.filter(({ i }) => i !== l.i);
432+
if (this.props.onPutItem) {
433+
this.props.onPutItem(layout, oldDragItem, l, null, e, node);
434+
}
435+
}
436+
}
437+
411438
this.props.onDragStop(layout, oldDragItem, l, null, e, node);
412439

413440
// Set state
@@ -417,7 +444,8 @@ export default class ReactGridLayout extends React.Component<Props, State> {
417444
activeDrag: null,
418445
layout: newLayout,
419446
oldDragItem: null,
420-
oldLayout: null
447+
oldLayout: null,
448+
draggingOverToolbox: false
421449
});
422450

423451
this.onLayoutMaybeChanged(newLayout, oldLayout);
@@ -453,14 +481,17 @@ export default class ReactGridLayout extends React.Component<Props, State> {
453481
// to find collisions faster
454482
let hasCollisions;
455483
if (preventCollision) {
456-
const collisions = getAllCollisions(layout, { ...l, w, h }).filter((layoutItem) => layoutItem.i !== l.i);
484+
const collisions = getAllCollisions(layout, { ...l, w, h }).filter(
485+
layoutItem => layoutItem.i !== l.i
486+
);
457487
hasCollisions = collisions.length > 0;
458488

459489
// If we're colliding, we need adjust the placeholder.
460490
if (hasCollisions) {
461491
// adjust w && h to maximum allowed space
462-
let leastX = Infinity, leastY = Infinity;
463-
collisions.forEach((layoutItem) => {
492+
let leastX = Infinity,
493+
leastY = Infinity;
494+
collisions.forEach(layoutItem => {
464495
if (layoutItem.x > l.x) leastX = Math.min(leastX, layoutItem.x);
465496
if (layoutItem.y > l.y) leastY = Math.min(leastY, layoutItem.y);
466497
});
@@ -625,20 +656,35 @@ export default class ReactGridLayout extends React.Component<Props, State> {
625656
}
626657

627658
render() {
628-
const { className, style } = this.props;
629-
630-
const mergedClassName = classNames("react-grid-layout", className);
631-
const mergedStyle = {
632-
height: this.containerHeight(),
633-
...style
634-
};
659+
const mergedClassName = classNames(
660+
"react-grid-layout",
661+
this.props.className
662+
);
635663

636664
return (
637-
<div className={mergedClassName} style={mergedStyle}>
638-
{React.Children.map(this.props.children, child =>
639-
this.processGridItem(child)
640-
)}
641-
{this.placeholder()}
665+
<div className={mergedClassName} style={this.props.style}>
666+
{this.props.toolbox ? (
667+
<div
668+
className={classNames("react-grid-layout__toolbox", {
669+
"is-active": this.state.draggingOverToolbox
670+
})}
671+
ref={elem => (this.toolboxRef = elem)}
672+
>
673+
{this.props.toolbox}
674+
</div>
675+
) : null}
676+
<div
677+
className="react-grid-layout__grid-items"
678+
style={{
679+
position: "relative",
680+
height: this.containerHeight()
681+
}}
682+
>
683+
{React.Children.map(this.props.children, child =>
684+
this.processGridItem(child)
685+
)}
686+
{this.placeholder()}
687+
</div>
642688
</div>
643689
);
644690
}

lib/utils.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,15 @@ export function validateLayout(
664664
}
665665
}
666666

667+
function layoutItemFromNode(node: HTMLElement) {
668+
const { width: w, height: h, left: x, top: y } = node.getBoundingClientRect();
669+
return { w, h, x, y, i: "" };
670+
}
671+
672+
export function nodesCollide(node1: HTMLElement, node2: HTMLElement): boolean {
673+
return collides(layoutItemFromNode(node1), layoutItemFromNode(node2));
674+
}
675+
667676
// Flow can't really figure this out, so we just use Object
668677
export function autoBindHandlers(el: Object, fns: Array<string>): void {
669678
fns.forEach(key => (el[key] = el[key].bind(el)));

0 commit comments

Comments
 (0)