GridElementWidthResizer.js (3951B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 "use strict"; 6 7 const { 8 Component, 9 createFactory, 10 } = require("resource://devtools/client/shared/vendor/react.mjs"); 11 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs"); 12 const Draggable = createFactory( 13 require("resource://devtools/client/shared/components/splitter/Draggable.js") 14 ); 15 16 class GridElementWidthResizer extends Component { 17 static get propTypes() { 18 return { 19 getControlledElementNode: PropTypes.func.isRequired, 20 enabled: PropTypes.bool, 21 position: PropTypes.string.isRequired, 22 className: PropTypes.string, 23 onResizeEnd: PropTypes.func, 24 }; 25 } 26 27 constructor(props) { 28 super(props); 29 30 this.onStartMove = this.onStartMove.bind(this); 31 this.onStopMove = this.onStopMove.bind(this); 32 this.onMove = this.onMove.bind(this); 33 this.state = { 34 dragging: false, 35 isRTLElement: false, 36 defaultCursor: null, 37 defaultWidth: null, 38 }; 39 } 40 41 componentDidUpdate(prevProps) { 42 if (prevProps.enabled === true && this.props.enabled === false) { 43 this.onStopMove(); 44 const controlledElementNode = this.props.getControlledElementNode(); 45 controlledElementNode.style.width = this.state.defaultWidth; 46 } 47 } 48 49 // Dragging Events 50 51 /** 52 * Set 'resizing' cursor on entire document during splitter dragging. 53 * This avoids cursor-flickering that happens when the mouse leaves 54 * the splitter bar area (happens frequently). 55 */ 56 onStartMove() { 57 const controlledElementNode = this.props.getControlledElementNode(); 58 if (!controlledElementNode) { 59 return; 60 } 61 62 const doc = controlledElementNode.ownerDocument; 63 const defaultCursor = doc.documentElement.style.cursor; 64 const defaultWidth = doc.documentElement.style.width; 65 doc.documentElement.style.cursor = "ew-resize"; 66 doc.firstElementChild.classList.add("dragging"); 67 68 this.setState({ 69 dragging: true, 70 isRTLElement: 71 controlledElementNode.ownerDocument.defaultView.getComputedStyle( 72 controlledElementNode 73 ).direction === "rtl", 74 defaultCursor, 75 defaultWidth, 76 }); 77 } 78 79 onStopMove() { 80 const controlledElementNode = this.props.getControlledElementNode(); 81 if (!this.state.dragging || !controlledElementNode) { 82 return; 83 } 84 const doc = controlledElementNode.ownerDocument; 85 doc.documentElement.style.cursor = this.state.defaultCursor; 86 doc.firstElementChild.classList.remove("dragging"); 87 88 this.setState({ 89 dragging: false, 90 }); 91 92 if (this.props.onResizeEnd) { 93 const { width } = controlledElementNode.getBoundingClientRect(); 94 this.props.onResizeEnd(width); 95 } 96 } 97 98 /** 99 * Adjust size of the controlled panel. 100 */ 101 onMove(x) { 102 const controlledElementNode = this.props.getControlledElementNode(); 103 if (!this.state.dragging || !controlledElementNode) { 104 return; 105 } 106 const nodeBounds = controlledElementNode.getBoundingClientRect(); 107 const { isRTLElement } = this.state; 108 const { position } = this.props; 109 110 const size = 111 (isRTLElement && position === "end") || 112 (!isRTLElement && position === "start") 113 ? nodeBounds.width + (nodeBounds.left - x) 114 : x - nodeBounds.left; 115 116 controlledElementNode.style.width = `${size}px`; 117 } 118 119 render() { 120 if (!this.props.enabled) { 121 return null; 122 } 123 124 const classNames = ["grid-element-width-resizer", this.props.position]; 125 if (this.props.className) { 126 classNames.push(this.props.className); 127 } 128 129 return Draggable({ 130 className: classNames.join(" "), 131 onStart: this.onStartMove, 132 onStop: this.onStopMove, 133 onMove: this.onMove, 134 }); 135 } 136 } 137 138 module.exports = GridElementWidthResizer;