Skip to content

Commit

Permalink
Merge pull request #50 from machacekjan/master
Browse files Browse the repository at this point in the history
Adds new prop primary. It defines which Pane will keep its size.
  • Loading branch information
tomkp committed Mar 4, 2016
2 parents df7f908 + 76548a1 commit e6cc893
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 23 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ Check out the [demo](http://react-split-pane.surge.sh/)
</SplitPane>
```

### Primary pane

By dragging 'draggable' surface you can change size of the first pane.
The first pane keeps then its size while the second pane is resized by browser window.
By default it is the left pane for 'vertical' SplitPane and the top pane for 'horizontal' SplitPane.
If you want to keep size of the second pane and let the first pane to shrink or grow by browser window dimensions,
set SplitPane prop `primary` to `second`. In case of 'horizontal' SplitPane the height of bottom pane remains the same.

In this example right pane keeps its width 200px while user is resizing browser window.

```html
<SplitPane split="vertical" defaultSize="200" primary="second">
<div></div>
<div></div>
</SplitPane>
```

### Persisting Positions

Each SplitPane accepts an onChange function prop. Used in conjunction with
Expand Down
20 changes: 15 additions & 5 deletions demo/bundle.js

Large diffs are not rendered by default.

16 changes: 12 additions & 4 deletions src/SplitPane.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import VendorPrefix from 'react-vendor-prefix';

export default React.createClass({

propTypes: {
primary: React.PropTypes.oneOf(['first', 'second']),
split: React.PropTypes.oneOf(['vertical', 'horizontal'])
},

getInitialState() {
return {
active: false,
Expand All @@ -20,15 +25,16 @@ export default React.createClass({
getDefaultProps() {
return {
split: 'vertical',
minSize: 0
minSize: 0,
primary: 'first'
};
},


componentDidMount() {
document.addEventListener('mouseup', this.onMouseUp);
document.addEventListener('mousemove', this.onMouseMove);
const ref = this.refs.pane1;
const ref = this.props.primary === 'first' ? this.refs.pane1 : this.refs.pane2;
if (ref && this.props.defaultSize !== undefined && !this.state.resized) {
ref.setState({
size: this.props.defaultSize
Expand Down Expand Up @@ -59,17 +65,19 @@ export default React.createClass({
onMouseMove(event) {
if (this.state.active) {
this.unFocus();
const ref = this.refs.pane1;
const ref = this.props.primary === 'first' ? this.refs.pane1 : this.refs.pane2;
if (ref) {
const node = ReactDOM.findDOMNode(ref);

if (node.getBoundingClientRect) {
const width = node.getBoundingClientRect().width;
const height = node.getBoundingClientRect().height;
const current = this.props.split === 'vertical' ? event.clientX : event.clientY;
const size = this.props.split === 'vertical' ? width : height;
const position = this.state.position;
const newPosition = this.props.primary === 'first' ? (position - current) : (current - position);

let newSize = size - (position - current);
let newSize = size - newPosition;
this.setState({
position: current,
resized: true
Expand Down
82 changes: 71 additions & 11 deletions test/assertions/Asserter.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,23 @@ const expect = chai.expect;
import VendorPrefix from 'react-vendor-prefix';
import ReactTestUtils from 'react-addons-test-utils';

/**
* getBoundingClientRect() does not work correctly with ReactTestUtils.renderIntoDocument().
* So for testing resizing we need ReactDOM.render()
*/
const render = (jsx, renderToDOM) => {
if (renderToDOM) {
const testDiv = document.createElement('div');
document.body.appendChild(testDiv);
return ReactDOM.render(jsx, testDiv);
} else {
return ReactTestUtils.renderIntoDocument(jsx);
}
};


export default (jsx) => {


const splitPane = ReactTestUtils.renderIntoDocument(jsx);
export default (jsx, renderToDom = false) => {
const splitPane = render(jsx, renderToDom);
const component = ReactTestUtils.findRenderedComponentWithType(splitPane, SplitPane);


Expand All @@ -26,6 +37,13 @@ export default (jsx) => {
return findPanes()[0];
};

const findBottomPane = () => {
return findPanes()[1];
};

const findPaneByOrder = (paneString) => {
return paneString === 'first' ? findTopPane() : findBottomPane();
};

const findResizer = () => {
return ReactTestUtils.scryRenderedComponentsWithType(splitPane, Resizer);
Expand All @@ -48,13 +66,49 @@ export default (jsx) => {
};


const assertFirstPaneStyles= (expectedStyles) => {
return assertStyles('First Pane', ReactDOM.findDOMNode(findTopPane()).style, expectedStyles);
const assertPaneStyles = (expectedStyles, paneString) => {
const pane = findPaneByOrder(paneString);
return assertStyles(`${paneString} Pane`, ReactDOM.findDOMNode(pane).style, expectedStyles);
};


return {
const getResizerPosition = () => {
const resizerNode = ReactDOM.findDOMNode(findResizer()[0]);
return resizerNode.getBoundingClientRect();
};


const calculateMouseMove = (mousePositionDifference) => {
const resizerPosition = getResizerPosition();
let mouseMove = {
start: {
clientX: resizerPosition.left,
clientY: resizerPosition.top
},
end: {
clientX: resizerPosition.left,
clientY: resizerPosition.top
}
};

if (mousePositionDifference.x) {
mouseMove.end.clientX = resizerPosition.left + mousePositionDifference.x;
} else if (mousePositionDifference.y) {
mouseMove.end.clientY = resizerPosition.top + mousePositionDifference.y;
}

return mouseMove;
};

const simulateDragAndDrop = (mousePositionDifference) => {
const mouseMove = calculateMouseMove(mousePositionDifference);
component.onMouseDown(mouseMove.start);
component.onMouseMove(mouseMove.end);
component.onMouseUp();
};


return {
assertOrientation(expectedOrientation) {
expect(ReactDOM.findDOMNode(component).className).to.contain(expectedOrientation, `Incorrect orientation`);
return this;
Expand All @@ -78,13 +132,19 @@ export default (jsx) => {
},


assertFirstPaneWidth(expectedWidth) {
return assertFirstPaneStyles({width: expectedWidth});
assertPaneWidth(expectedWidth, pane = 'first') {
return assertPaneStyles({width: expectedWidth}, pane);
},


assertPaneHeight(expectedHeight, pane = 'first') {
return assertPaneStyles({height: expectedHeight}, pane);
},


assertFirstPaneHeight(expectedHeight) {
return assertFirstPaneStyles({height: expectedHeight});
assertResizeByDragging(mousePositionDifference, expectedStyle) {
simulateDragAndDrop(mousePositionDifference);
return assertPaneStyles(expectedStyle, component.props.primary);
}
}
}
Expand Down
61 changes: 60 additions & 1 deletion test/horizontal-split-pane-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,66 @@ describe('Horizontal SplitPane', function () {


it('should have correct height for the top Pane', function () {
asserter(splitPane).assertFirstPaneHeight('99px');
asserter(splitPane).assertPaneHeight('99px');
});
});

describe('With primary property set to second', function () {

const splitPane = (
<SplitPane split="horizontal" defaultSize="99" primary="second">
<div>one</div>
<div>two</div>
</SplitPane>
);


it('should have correct height for the bottom Pane', function () {
asserter(splitPane).assertPaneHeight('99px', 'second');
});
});

describe('Resizer move up and down', function () {

const splitPane = (
<SplitPane split="horizontal" defaultSize="200">
<div>one</div>
<div>two</div>
</SplitPane>
);

const moveToRight = { y: 200 };

it('after move down, the first pane should be larger then before', function () {
asserter(splitPane, true).assertResizeByDragging(moveToRight, { height: '400px' });
});

const moveToLeft = { y: -120 };

it('after move up, the first pane should be smaller then before', function () {
asserter(splitPane, true).assertResizeByDragging(moveToLeft, { height: '80px' });
});
});

describe('Resizer move up and down and primary prop is set to second', function () {

const splitPane = (
<SplitPane split="horizontal" defaultSize="400" primary="second">
<div>one</div>
<div>two</div>
</SplitPane>
);

const moveToRight = { y: 160 };

it('after move down, the second pane should be smaller then before', function () {
asserter(splitPane, true).assertResizeByDragging(moveToRight, { height: '240px' });
});

const moveToLeft = { y: -111 };

it('after move up, the second pane should be larger then before', function () {
asserter(splitPane, true).assertResizeByDragging(moveToLeft, { height: '511px' });
});
});
});
Expand Down
65 changes: 63 additions & 2 deletions test/vertical-split-pane-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ describe('Vertical SplitPane', function () {
});



describe('With defaultSize property', function () {

const splitPane = (
Expand All @@ -45,8 +44,70 @@ describe('Vertical SplitPane', function () {


it('should have correct width for the left Pane', function () {
asserter(splitPane).assertFirstPaneWidth('99px');
asserter(splitPane).assertPaneWidth('99px');
asserter(splitPane).assertPaneWidth(null, 'second');
});
});


describe('With primary property set to second', function () {

const splitPane = (
<SplitPane split="vertical" defaultSize="99" primary="second" >
<div>one</div>
<div>two</div>
</SplitPane>
);


it('should have correct width for the right Pane', function () {
asserter(splitPane).assertPaneWidth(null);
asserter(splitPane).assertPaneWidth('99px', 'second');
});
});


describe('Resizer move to the right and left', function () {

const splitPane = (
<SplitPane split="vertical" defaultSize="200">
<div>one</div>
<div>two</div>
</SplitPane>
);

const moveToRight = { x: 200 };

it('after move to right, the first pane should be larger then before', function () {
asserter(splitPane, true).assertResizeByDragging(moveToRight, { width: '400px' });
});

const moveToLeft = { x: -120 };

it('after move to left, the first pane should be smaller then before', function () {
asserter(splitPane, true).assertResizeByDragging(moveToLeft, { width: '80px' });
});
});

describe('Resizer move to the right and left and primary prop is set to second', function () {

const splitPane = (
<SplitPane split="vertical" defaultSize="400" primary="second">
<div>one</div>
<div>two</div>
</SplitPane>
);

const moveToRight = { x: 160 };

it('after move to right, the second pane should be smaller then before', function () {
asserter(splitPane, true).assertResizeByDragging(moveToRight, { width: '240px' });
});

const moveToLeft = { x: -111 };

it('after move to left, the second pane should be larger then before', function () {
asserter(splitPane, true).assertResizeByDragging(moveToLeft, { width: '511px' });
});
});
});

0 comments on commit e6cc893

Please sign in to comment.