summaryrefslogtreecommitdiffstats
path: root/devtools/client/shared/components/HSplitBox.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/shared/components/HSplitBox.js')
-rw-r--r--devtools/client/shared/components/HSplitBox.js165
1 files changed, 165 insertions, 0 deletions
diff --git a/devtools/client/shared/components/HSplitBox.js b/devtools/client/shared/components/HSplitBox.js
new file mode 100644
index 0000000000..65dfc0aaf6
--- /dev/null
+++ b/devtools/client/shared/components/HSplitBox.js
@@ -0,0 +1,165 @@
+/* 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 {
+ Component,
+} = require("resource://devtools/client/shared/vendor/react.js");
+const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
+const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
+const { assert } = require("resource://devtools/shared/DevToolsUtils.js");
+
+class HSplitBox extends Component {
+ static get propTypes() {
+ return {
+ // 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,
+ };
+ }
+
+ static get defaultProps() {
+ return {
+ startWidth: 0.5,
+ minStartWidth: "20px",
+ minEndWidth: "20px",
+ };
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ mouseDown: false,
+ };
+
+ this._onMouseDown = this._onMouseDown.bind(this);
+ this._onMouseUp = this._onMouseUp.bind(this);
+ this._onMouseMove = this._onMouseMove.bind(this);
+ }
+
+ componentDidMount() {
+ document.defaultView.top.addEventListener("mouseup", this._onMouseUp);
+ document.defaultView.top.addEventListener("mousemove", this._onMouseMove);
+ }
+
+ componentWillUnmount() {
+ document.defaultView.top.removeEventListener("mouseup", this._onMouseUp);
+ document.defaultView.top.removeEventListener(
+ "mousemove",
+ this._onMouseMove
+ );
+ }
+
+ _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 direction = this.refs.box.ownerDocument.dir;
+ const relative =
+ direction == "rtl" ? right - event.clientX : 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
+ )
+ );
+ }
+}
+
+module.exports = HSplitBox;