diff options
Diffstat (limited to 'devtools/client/shared/components/h-split-box.js')
-rw-r--r-- | devtools/client/shared/components/h-split-box.js | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/devtools/client/shared/components/h-split-box.js b/devtools/client/shared/components/h-split-box.js new file mode 100644 index 000000000..d804a6ba1 --- /dev/null +++ b/devtools/client/shared/components/h-split-box.js @@ -0,0 +1,154 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* eslint-env browser */ +"use strict"; + +// A box with a start and a end pane, separated by a dragable splitter that +// allows the user to resize the relative widths of the panes. +// +// +-----------------------+---------------------+ +// | | | +// | | | +// | S | +// | Start Pane p End Pane | +// | l | +// | i | +// | t | +// | t | +// | e | +// | r | +// | | | +// | | | +// +-----------------------+---------------------+ + +const { + DOM: dom, + createClass, + PropTypes, +} = require("devtools/client/shared/vendor/react"); +const { assert } = require("devtools/shared/DevToolsUtils"); + +module.exports = createClass({ + displayName: "HSplitBox", + + propTypes: { + // The contents of the start pane. + start: PropTypes.any.isRequired, + + // The contents of the end pane. + end: PropTypes.any.isRequired, + + // The relative width of the start pane, expressed as a number between 0 and + // 1. The relative width of the end pane is 1 - startWidth. For example, + // with startWidth = .5, both panes are of equal width; with startWidth = + // .25, the start panel will take up 1/4 width and the end panel will take + // up 3/4 width. + startWidth: PropTypes.number, + + // A minimum css width value for the start and end panes. + minStartWidth: PropTypes.any, + minEndWidth: PropTypes.any, + + // A callback fired when the user drags the splitter to resize the relative + // pane widths. The function is passed the startWidth value that would put + // the splitter underneath the users mouse. + onResize: PropTypes.func.isRequired, + }, + + getDefaultProps() { + return { + startWidth: 0.5, + minStartWidth: "20px", + minEndWidth: "20px", + }; + }, + + getInitialState() { + return { + mouseDown: false + }; + }, + + componentDidMount() { + document.defaultView.top.addEventListener("mouseup", this._onMouseUp, + false); + document.defaultView.top.addEventListener("mousemove", this._onMouseMove, + false); + }, + + componentWillUnmount() { + document.defaultView.top.removeEventListener("mouseup", this._onMouseUp, + false); + document.defaultView.top.removeEventListener("mousemove", this._onMouseMove, + false); + }, + + _onMouseDown(event) { + if (event.button !== 0) { + return; + } + + this.setState({ mouseDown: true }); + event.preventDefault(); + }, + + _onMouseUp(event) { + if (event.button !== 0 || !this.state.mouseDown) { + return; + } + + this.setState({ mouseDown: false }); + event.preventDefault(); + }, + + _onMouseMove(event) { + if (!this.state.mouseDown) { + return; + } + + const rect = this.refs.box.getBoundingClientRect(); + const { left, right } = rect; + const width = right - left; + const relative = event.clientX - left; + this.props.onResize(relative / width); + + event.preventDefault(); + }, + + render() { + /* eslint-disable no-shadow */ + const { start, end, startWidth, minStartWidth, minEndWidth } = this.props; + assert(startWidth => 0 && startWidth <= 1, + "0 <= this.props.startWidth <= 1"); + /* eslint-enable */ + return dom.div( + { + className: "h-split-box", + ref: "box", + }, + + dom.div( + { + className: "h-split-box-pane", + style: { flex: startWidth, minWidth: minStartWidth }, + }, + start + ), + + dom.div({ + className: "devtools-side-splitter", + onMouseDown: this._onMouseDown, + }), + + dom.div( + { + className: "h-split-box-pane", + style: { flex: 1 - startWidth, minWidth: minEndWidth }, + }, + end + ) + ); + } +}); |