diff --git a/css/styles.css b/css/styles.css index ae64b220..b794e776 100644 --- a/css/styles.css +++ b/css/styles.css @@ -1,6 +1,7 @@ .react-resizable { position: relative; } + .react-resizable-handle { position: absolute; width: 20px; @@ -15,3 +16,17 @@ box-sizing: border-box; cursor: se-resize; } + +.react-resizable-handle-x { + right: 0; + bottom: 50%; + background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCA0LjIgNiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+'); + cursor: ew-resize; +} + +.react-resizable-handle-y { + right: 50%; + bottom: 0; + background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDYgNC4yIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+'); + cursor: ns-resize; +} \ No newline at end of file diff --git a/lib/Resizable.js b/lib/Resizable.js index 51522976..ed983300 100644 --- a/lib/Resizable.js +++ b/lib/Resizable.js @@ -6,6 +6,7 @@ import cloneElement from './cloneElement'; import type {Element as ReactElement, Node as ReactNode} from 'react'; type Axis = 'both' | 'x' | 'y' | 'none'; +type Resizer = Axis | 'all'; type State = { resizing: boolean, width: number, height: number, @@ -19,7 +20,8 @@ type DragCallbackData = { }; export type ResizeCallbackData = { node: HTMLElement, - size: {width: number, height: number} + size: {width: number, height: number}, + axis: Axis, }; export type Props = { children: ReactElement, @@ -29,6 +31,7 @@ export type Props = { handleSize: [number, number], lockAspectRatio: boolean, axis: Axis, + resizer: Resizer, minConstraints: [number, number], maxConstraints: [number, number], onResizeStop?: ?(e: SyntheticEvent<>, data: ResizeCallbackData) => any, @@ -67,6 +70,14 @@ export default class Resizable extends React.Component { // 'none' - disables resizing altogether axis: PropTypes.oneOf(['both', 'x', 'y', 'none']), + // Restricts resize handle. + // 'all' -show all resizer if that axis is resizable + // 'both' - show bottom right resizer if that axis is resizable + // 'x' - only show resizer on x axis if resizable + // 'y' - only show resizer on y axis if resizable + // 'none' - disables all resizer + resizer: PropTypes.oneOf([ 'both', 'x', 'y', 'none' ]), + // Min/max size minConstraints: PropTypes.arrayOf(PropTypes.number), maxConstraints: PropTypes.arrayOf(PropTypes.number), @@ -84,6 +95,7 @@ export default class Resizable extends React.Component { handleSize: [20, 20], lockAspectRatio: false, axis: 'both', + resizer: 'both', minConstraints: [20, 20], maxConstraints: [Infinity, Infinity] }; @@ -157,12 +169,13 @@ export default class Resizable extends React.Component { * @param {String} handlerName Handler name to wrap. * @return {Function} Handler function. */ - resizeHandler(handlerName: string): Function { + resizeHandler(handlerName: string, resizeAxis: Axis): Function { return (e: SyntheticEvent<> | MouseEvent, {node, deltaX, deltaY}: DragCallbackData) => { // Axis restrictions - const canDragX = this.props.axis === 'both' || this.props.axis === 'x'; - const canDragY = this.props.axis === 'both' || this.props.axis === 'y'; + const axis = resizeAxis || this.props.axis; + const canDragX = axis === 'both' || axis === 'x'; + const canDragY = axis === 'both' || axis === 'y'; // Update w/h let width = this.state.width + (canDragX ? deltaX : 0); @@ -191,23 +204,48 @@ export default class Resizable extends React.Component { const hasCb = typeof this.props[handlerName] === 'function'; if (hasCb) { if (typeof e.persist === 'function') e.persist(); - this.setState(newState, () => this.props[handlerName](e, {node, size: {width, height}})); + this.setState(newState, () => this.props[handlerName](e, {node, size: {width, height}, axis })); } else { this.setState(newState); } }; } + + renderAxis(axis: Axis): ReactNode { + const { draggableOpts } = this.props; + return + + ; + } + render(): ReactNode { // eslint-disable-next-line no-unused-vars const {children, draggableOpts, width, height, handleSize, - lockAspectRatio, axis, minConstraints, maxConstraints, onResize, + lockAspectRatio, resizer, axis, minConstraints, maxConstraints, onResize, onResizeStop, onResizeStart, ...p} = this.props; const className = p.className ? `${p.className} react-resizable`: 'react-resizable'; + const draggableCores = []; + + ['both', 'x', 'y'].forEach(axisType => { + if ( + (axis === 'both' || axisType === axis) && + (resizer === 'all' || axisType === resizer) + ) { + draggableCores.push(this.renderAxis(axisType)); + } + }); + // What we're doing here is getting the child of this element, and cloning it with this element's props. // We are then defining its children as: // Its original children (resizable's child's children), and @@ -217,15 +255,7 @@ export default class Resizable extends React.Component { className, children: [ children.props.children, - - - + ...draggableCores, ] }); } diff --git a/lib/ResizableBox.js b/lib/ResizableBox.js index 552ae03b..338d7462 100644 --- a/lib/ResizableBox.js +++ b/lib/ResizableBox.js @@ -49,7 +49,8 @@ export default class ResizableBox extends React.Component // If you use Resizable directly, you are responsible for updating the child component // with a new width and height. const {handleSize, onResize, onResizeStart, onResizeStop, draggableOpts, - minConstraints, maxConstraints, lockAspectRatio, axis, width, height, ...props} = this.props; + minConstraints, maxConstraints, lockAspectRatio, axis, resizer, + width, height, ...props} = this.props; return ( maxConstraints={maxConstraints} lockAspectRatio={lockAspectRatio} axis={axis} + resizer={resizer} >
diff --git a/test/TestLayout.js b/test/TestLayout.js index 566ffaf2..6d1f1d14 100644 --- a/test/TestLayout.js +++ b/test/TestLayout.js @@ -45,15 +45,28 @@ export default class TestLayout extends React.Component<{}, {width: number, heig Only resizable by "x" axis. + + Only resizable by "x" axis with x resizer. + Only resizable by "y" axis. + + Only resizable by "y" axis with x resizer. + Resizable ("both" axis). + + Resizable ("both" axis with "both" resizer). + + + Resizable ("both" axis with "all" resizer). + Not resizable ("none" axis). +
);