-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
resizable stage #9753
base: develop
Are you sure you want to change the base?
resizable stage #9753
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import PropTypes from 'prop-types'; | ||
import React, {useEffect, useRef, useState, useCallback} from 'react'; | ||
|
||
import Box from './box.jsx'; | ||
|
||
const useMouseDrag = (ref, onDrag, onDragEnd) => { | ||
useEffect(() => { | ||
if (!onDrag) return; | ||
let isDragging = false; | ||
const onMouseMove = e => { | ||
e.preventDefault(); | ||
if (!isDragging) return; | ||
if (onDrag) onDrag(e); | ||
}; | ||
const onMouseUp = e => { | ||
isDragging = false; | ||
if (onDragEnd) onDragEnd(e); | ||
}; | ||
const onMouseDown = e => { | ||
e.preventDefault(); | ||
isDragging = true; | ||
}; | ||
ref.current.addEventListener('mousedown', onMouseDown); | ||
window.addEventListener('mousemove', onMouseMove); | ||
window.addEventListener('mouseup', onMouseUp); | ||
return () => { | ||
ref.current.removeEventListener('mousedown', onMouseDown); | ||
window.removeEventListener('mousemove', onMouseMove); | ||
window.removeEventListener('mouseup', onMouseUp); | ||
}; | ||
}, [onDrag]); | ||
}; | ||
|
||
|
||
const ResizableBox = props => { | ||
const { | ||
children, | ||
minWidth = 420, | ||
maxWidth = 480, | ||
defaultWidth = 480, | ||
onResize, | ||
initialSize, | ||
...rest | ||
} = props; | ||
|
||
const boxRef = useRef(null); | ||
const handleRef = useRef(null); | ||
const [width, setWidth] = useState(defaultWidth); | ||
|
||
// whenever the initial size changes, lets override whatever the current width is | ||
useEffect(() => { | ||
setWidth(initialSize); | ||
}, [initialSize]); | ||
|
||
// This is a workaround to force other elements to resize that | ||
// are listening to the window resize event (such as the editor). | ||
useEffect(() => { | ||
window.dispatchEvent(new Event('resize')); | ||
}, [width]); | ||
|
||
const onDrag = useCallback(e => { | ||
if (!boxRef.current) return; | ||
const rect = boxRef.current.getBoundingClientRect(); | ||
const newWidth = Math.max(Math.min(rect.width - e.movementX, maxWidth), minWidth); | ||
onResize(newWidth); | ||
setWidth(newWidth); | ||
}, [minWidth, maxWidth]); | ||
|
||
|
||
useMouseDrag(handleRef, onDrag); | ||
|
||
return ( | ||
<Box | ||
componentRef={boxRef} | ||
style={{ | ||
position: 'relative', | ||
width: width, | ||
minWidth: minWidth | ||
}} | ||
{...rest} | ||
> | ||
<div | ||
ref={handleRef} | ||
style={{ | ||
position: 'absolute', | ||
left: 0, | ||
top: 0, | ||
bottom: 0, | ||
width: '8px', | ||
cursor: 'ew-resize' | ||
}} | ||
/> | ||
{children} | ||
</Box> | ||
); | ||
}; | ||
|
||
ResizableBox.propTypes = { | ||
children: PropTypes.node, | ||
minWidth: PropTypes.number, | ||
maxWidth: PropTypes.number, | ||
defaultWidth: PropTypes.number, | ||
onResize: PropTypes.func, | ||
initialSize: PropTypes.number | ||
}; | ||
|
||
export default ResizableBox; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -207,9 +207,6 @@ | |
/* pad entire wrapper to the left and right; allow children to fill width */ | ||
padding-left: $space; | ||
padding-right: $space; | ||
|
||
/* this will only ever be as wide as the stage */ | ||
flex-basis: 0; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. needed to get rid of this to have dynamic sizing |
||
} | ||
|
||
.target-wrapper { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,15 +8,32 @@ import {stageSizeToTransform} from '../../lib/screen-utils'; | |
|
||
import styles from './monitor-list.css'; | ||
|
||
// Use static `monitor-overlay` class for bounds of draggables | ||
// This is just a dummy div which doesn't scale to make the | ||
// bounds tracking play nicer with react-draggable | ||
const MonitorOverlay = () => ( | ||
<div | ||
className="monitor-overlay" | ||
style={{ | ||
width: 480, | ||
height: 360, | ||
position: 'absolute', | ||
top: 0, | ||
left: 0, | ||
visibility: 'hidden' | ||
}} | ||
/> | ||
); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. react-draggable really did not like using a scaled container as the bounding reference, but we needed the scaling both visually as well as for proper drag deltas for the monitors. This dummy div of a constant width is a hacky solution that makes react-draggable happy. A better solution would likely be way more involved, perhaps replacing react-draggable entirely. |
||
const MonitorList = props => ( | ||
<Box | ||
// Use static `monitor-overlay` class for bounds of draggables | ||
className={classNames(styles.monitorList, 'monitor-overlay')} | ||
className={styles.monitorList} | ||
style={{ | ||
width: props.stageSize.width, | ||
height: props.stageSize.height | ||
}} | ||
> | ||
<MonitorOverlay /> | ||
<Box | ||
className={styles.monitorListScaler} | ||
style={stageSizeToTransform(props.stageSize)} | ||
|
@@ -41,6 +58,7 @@ const MonitorList = props => ( | |
x={monitorData.x} | ||
y={monitorData.y} | ||
onDragEnd={props.onMonitorChange} | ||
scale={props.stageSize.scale} | ||
/> | ||
))} | ||
</Box> | ||
|
@@ -55,7 +73,8 @@ MonitorList.propTypes = { | |
width: PropTypes.number, | ||
height: PropTypes.number, | ||
widthDefault: PropTypes.number, | ||
heightDefault: PropTypes.number | ||
heightDefault: PropTypes.number, | ||
scale: PropTypes.number | ||
}).isRequired | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,6 +52,7 @@ const MonitorComponent = props => ( | |
defaultClassNameDragging={styles.dragging} | ||
disabled={!props.draggable} | ||
onStop={props.onDragEnd} | ||
scale={props.scale} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. drilling this scale prop to the draggable element corrects the drag deltas for different stage sizes |
||
> | ||
<Box | ||
className={styles.monitorContainer} | ||
|
@@ -149,7 +150,8 @@ MonitorComponent.propTypes = { | |
onSetModeToLarge: PropTypes.func, | ||
onSetModeToSlider: PropTypes.func, | ||
onSliderPromptOpen: PropTypes.func, | ||
theme: PropTypes.string.isRequired | ||
theme: PropTypes.string.isRequired, | ||
scale: PropTypes.number | ||
}; | ||
|
||
MonitorComponent.defaultProps = { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a new "Box" wrapper which gives a drag-resizable handle on the left side of the container