Skip to content

Commit 843f699

Browse files
committed
Initial check-in of resize handle support.
1 parent 4ce15ee commit 843f699

File tree

3 files changed

+103
-23
lines changed

3 files changed

+103
-23
lines changed

css/styles.css

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,61 @@
55
position: absolute;
66
width: 20px;
77
height: 20px;
8-
bottom: 0;
9-
right: 0;
10-
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+');
11-
background-position: bottom right;
12-
padding: 0 3px 3px 0;
138
background-repeat: no-repeat;
149
background-origin: content-box;
1510
box-sizing: border-box;
11+
background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+');
12+
background-position: bottom right;
13+
padding: 0 3px 3px 0;
14+
}
15+
.react-resizable-handle-sw {
16+
bottom: 0;
17+
left: 0;
18+
cursor: sw-resize;
19+
transform: rotate(90deg);
20+
}
21+
.react-resizable-handle-se {
22+
bottom: 0;
23+
right: 0;
1624
cursor: se-resize;
1725
}
26+
.react-resizable-handle-nw {
27+
top: 0;
28+
left: 0;
29+
cursor: nw-resize;
30+
transform: rotate(180deg);
31+
}
32+
.react-resizable-handle-ne {
33+
top: 0;
34+
right: 0;
35+
cursor: ne-resize;
36+
transform: rotate(270deg);
37+
}
38+
.react-resizable-handle-w,
39+
.react-resizable-handle-e {
40+
top: 50%;
41+
margin-top: -10px;
42+
cursor: ew-resize;
43+
}
44+
.react-resizable-handle-w {
45+
left: 0;
46+
transform: rotate(135deg);
47+
}
48+
.react-resizable-handle-e {
49+
right: 0;
50+
transform: rotate(315deg);
51+
}
52+
.react-resizable-handle-n,
53+
.react-resizable-handle-s {
54+
left: 50%;
55+
margin-left: -10px;
56+
cursor: ns-resize;
57+
}
58+
.react-resizable-handle-n {
59+
top: 0;
60+
transform: rotate(225deg);
61+
}
62+
.react-resizable-handle-s {
63+
bottom: 0;
64+
transform: rotate(45deg);
65+
}

lib/Resizable.js

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import cloneElement from './cloneElement';
66
import type {Element as ReactElement, Node as ReactNode} from 'react';
77

88
type Axis = 'both' | 'x' | 'y' | 'none';
9+
type ResizeHandle = 's' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne';
910
type State = {
1011
resizing: boolean,
1112
width: number, height: number,
@@ -35,7 +36,8 @@ export type Props = {
3536
onResizeStop?: ?(e: SyntheticEvent<>, data: ResizeCallbackData) => any,
3637
onResizeStart?: ?(e: SyntheticEvent<>, data: ResizeCallbackData) => any,
3738
onResize?: ?(e: SyntheticEvent<>, data: ResizeCallbackData) => any,
38-
draggableOpts?: ?Object
39+
draggableOpts?: ?Object,
40+
resizeHandles?: ?ResizeHandle[]
3941
};
4042

4143
export default class Resizable extends React.Component<Props, State> {
@@ -61,6 +63,18 @@ export default class Resizable extends React.Component<Props, State> {
6163
// If you change this, be sure to update your css
6264
handleSize: PropTypes.array,
6365

66+
// Defines which resize handles should be rendered (default: 'se')
67+
// Allows for any combination of:
68+
// 's' - South handle (bottom-center)
69+
// 'w' - West handle (left-center)
70+
// 'e' - East handle (right-center)
71+
// 'n' - North handle (top-center)
72+
// 'sw' - Southwest handle (bottom-left)
73+
// 'nw' - Northwest handle (top-left)
74+
// 'se' - Southeast handle (bottom-right)
75+
// 'ne' - Northeast handle (top-center)
76+
resizeHandles: PropTypes.arrayOf(PropTypes.oneOf(['s', 'w', 'e', 'n', 'sw', 'nw', 'se', 'ne'])),
77+
6478
// If true, will only allow width/height to move in lockstep
6579
lockAspectRatio: PropTypes.bool,
6680

@@ -89,7 +103,8 @@ export default class Resizable extends React.Component<Props, State> {
89103
lockAspectRatio: false,
90104
axis: 'both',
91105
minConstraints: [20, 20],
92-
maxConstraints: [Infinity, Infinity]
106+
maxConstraints: [Infinity, Infinity],
107+
resizeHandles: ['se']
93108
};
94109

95110
state: State = {
@@ -161,12 +176,19 @@ export default class Resizable extends React.Component<Props, State> {
161176
* @param {String} handlerName Handler name to wrap.
162177
* @return {Function} Handler function.
163178
*/
164-
resizeHandler(handlerName: string): Function {
179+
resizeHandler(handlerName: string, axis: ResizeHandle): Function {
165180
return (e: SyntheticEvent<> | MouseEvent, {node, deltaX, deltaY}: DragCallbackData) => {
166181

167182
// Axis restrictions
168-
const canDragX = this.props.axis === 'both' || this.props.axis === 'x';
169-
const canDragY = this.props.axis === 'both' || this.props.axis === 'y';
183+
const canDragX = (this.props.axis === 'both' || this.props.axis === 'x') && ['n', 's'].indexOf(axis) === -1;
184+
const canDragY = (this.props.axis === 'both' || this.props.axis === 'y') && ['e', 'w'].indexOf(axis) === -1;
185+
186+
if (axis[0] === 'n') {
187+
deltaY = -deltaY;
188+
}
189+
if (axis[axis.length - 1] === 'w') {
190+
deltaX = -deltaX;
191+
}
170192

171193
// Update w/h
172194
let width = this.state.width + (canDragX ? deltaX : 0);
@@ -202,9 +224,27 @@ export default class Resizable extends React.Component<Props, State> {
202224
};
203225
}
204226

227+
renderResizeHandles(): ReactNode {
228+
const {draggableOpts, handle, resizeHandles} = this.props;
229+
if (handle) {
230+
return handle;
231+
}
232+
return resizeHandles.map(h => (
233+
<DraggableCore
234+
{...draggableOpts}
235+
key={`resizableHandle-${h}`}
236+
onStop={this.resizeHandler('onResizeStop', h)}
237+
onStart={this.resizeHandler('onResizeStart', h)}
238+
onDrag={this.resizeHandler('onResize', h)}
239+
>
240+
<span key={h} className={`react-resizable-handle react-resizable-handle-${h}`} />
241+
</DraggableCore>
242+
));
243+
}
244+
205245
render(): ReactNode {
206246
// eslint-disable-next-line no-unused-vars
207-
const {children, draggableOpts, width, height, handle, handleSize,
247+
const {children, width, height, handle, handleSize,
208248
lockAspectRatio, axis, minConstraints, maxConstraints, onResize,
209249
onResizeStop, onResizeStart, ...p} = this.props;
210250

@@ -215,21 +255,13 @@ export default class Resizable extends React.Component<Props, State> {
215255
// What we're doing here is getting the child of this element, and cloning it with this element's props.
216256
// We are then defining its children as:
217257
// Its original children (resizable's child's children), and
218-
// A draggable handle.
258+
// One or more draggable handles.
219259
return cloneElement(children, {
220260
...p,
221261
className,
222262
children: [
223263
children.props.children,
224-
<DraggableCore
225-
{...draggableOpts}
226-
key="resizableHandle"
227-
onStop={this.resizeHandler('onResizeStop')}
228-
onStart={this.resizeHandler('onResizeStart')}
229-
onDrag={this.resizeHandler('onResize')}
230-
>
231-
{handle || <span className="react-resizable-handle" />}
232-
</DraggableCore>
264+
this.renderResizeHandles()
233265
]
234266
});
235267
}

test/TestLayout.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ export default class TestLayout extends React.Component<{}, {width: number, heig
1919
<div>
2020
<button onClick={this.onClick} style={{'marginBottom': '10px'}}>Reset first element's width/height</button>
2121
<div className="layoutRoot">
22-
<Resizable className="box" height={this.state.height} width={this.state.width} onResize={this.onResize}>
22+
<Resizable className="box" height={this.state.height} width={this.state.width} onResize={this.onResize} resizeHandles={['sw', 'se', 'nw', 'ne', 'w', 'e', 'n', 's']}>
2323
<div className="box" style={{width: this.state.width + 'px', height: this.state.height + 'px'}}>
24-
<span className="text">{"Raw use of <Resizable> element. 200x200, no constraints."}</span>
24+
<span className="text">{"Raw use of <Resizable> element. 200x200, all Resize Handles."}</span>
2525
</div>
2626
</Resizable>
2727
<ResizableBox className="box" width={200} height={200}>

0 commit comments

Comments
 (0)