Skip to content

Commit

Permalink
WIP resizable
Browse files Browse the repository at this point in the history
Implement absolute right edge
  • Loading branch information
inukshuk committed Feb 24, 2017
1 parent 50f9dcc commit e7717af
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 57 deletions.
6 changes: 6 additions & 0 deletions src/common/util.js
Expand Up @@ -245,6 +245,12 @@ module.exports = {

context[method] = (...args) =>
refinement.call(context, args, original.apply(context, args))
},

restrict(value, lower, upper) {
value = Math.max(value, (lower != null) ? lower : value)
value = Math.min(value, (upper != null) ? upper : value)
return value
}

}
2 changes: 1 addition & 1 deletion src/components/panel.js
Expand Up @@ -57,7 +57,7 @@ const PanelGroup = ({ header, children, height }) => {
</header>
<div className="panel-group-body">
{panels.map((panel, idx) => (
<Resizable key={idx} relative edge="bottom" value={height[idx]}>
<Resizable key={idx} isRelative edge="bottom" value={height[idx]}>
{panel}
</Resizable>
))}
Expand Down
156 changes: 128 additions & 28 deletions src/components/resizable.js
@@ -1,9 +1,13 @@
'use strict'

const React = require('react')
const { PropTypes } = React
const { Shapes } = require('./util')
const cn = require('classnames')
const { PureComponent, PropTypes } = React
const { func, node, bool, number, oneOf } = PropTypes
const cx = require('classnames')
const { bounds, on, off } = require('../dom')
const { restrict } = require('../common/util')
const { keys } = Object


const DIR = {
top: 'row', right: 'col', bottom: 'row', left: 'col'
Expand All @@ -13,36 +17,132 @@ const DIM = {
top: 'height', right: 'width', bottom: 'height', left: 'width'
}

const OPP = {
top: 'bottom', right: 'left', bottom: 'top', left: 'right'
}

const ResizableHandle = ({ edge }) => (
<div className={cn([
`resizable-handle-${DIR[edge]}`,
`resizable-handle-${edge}`
])}/>
)

ResizableHandle.propTypes = {
edge: Shapes.edge.isRequired
const AXS = {
top: 'pageY', right: 'pageX', bottom: 'pageY', left: 'pageX'
}


const Resizable = ({ value, children, edge, relative }) => (
<div
className="resizable"
style={{ [DIM[edge]]: `${value}${relative ? '%' : 'px'}` }}>
{children}
<ResizableHandle edge={edge}/>
</div>
)

Resizable.propTypes = {
children: PropTypes.node,
edge: Shapes.edge.isRequired,
relative: PropTypes.bool,
value: PropTypes.number.isRequired
class Resizable extends PureComponent {
constructor(props) {
super(props)

this.state = {
value: props.value,
isDragging: false
}
}

componentWillUnmount() {
if (this.state.isDragging) {
this.stop()
}
}

componentWillReceiveProps(props) {
this.setState({ value: props.value })
}

get dimension() {
return DIM[this.props.edge]
}

get value() {
return `${this.state.value}${this.props.isRelative ? '%' : 'px'}`
}

get style() {
return {
[this.dimension]: this.value
}
}

handleMouseDown = () => {
this.start()
}

setContainer = (container) => {
this.container = container
}

update = (event) => {
const { edge, min, max } = this.props

const origin = bounds(this.container)[OPP[edge]]
const value = restrict(event[AXS[edge]] - origin, min, max)

this.setState({ value })
}

start() {
this.setState({ isDragging: true })

on(document, 'mousemove', this.update)
on(document, 'mouseup', this.stop, { capture: true })
on(document, 'mouseleave', this.stop)
on(window, 'blur', this.stop)
}

stop = () => {
this.setState({ isDragging: false })

off(document, 'mousemove', this.update)
off(document, 'mouseup', this.stop, { capture: true })
off(document, 'mouseleave', this.stop)
off(window, 'blur', this.stop)

if (this.props.value !== this.state.value) {
//this.props.onResize(value)
//console.log('resize', this.state.value)
}
}


renderHandle() {
const { edge, isDisabled } = this.props

return !isDisabled && (
<div
onMouseDown={this.handleMouseDown}
className={cx([
`resizable-handle-${DIR[edge]}`,
`resizable-handle-${edge}`
])}/>
)
}

render() {
return (
<div
ref={this.setContainer}
className="resizable"
style={this.style}>
{this.props.children}
{this.renderHandle()}
</div>
)
}

static propTypes = {
children: node,
edge: oneOf(keys(DIM)).isRequired,
isDisabled: bool,
isRelative: bool,
value: number.isRequired,
min: number,
max: number,
onResize: func //.isRequired
}

static defaultProps = {
min: 0
}
}


module.exports = {
Resizable,
ResizableHandle
Resizable
}
35 changes: 10 additions & 25 deletions src/components/slider.js
Expand Up @@ -5,8 +5,9 @@ const { PureComponent, PropTypes } = React
const { IconButton } = require('./button')
const cx = require('classnames')
const { bounds, borders, on, off } = require('../dom')
const { noop } = require('../common/util')
const { restrict } = require('../common/util')
const { bool, element, func, number, oneOf } = PropTypes
const { round } = Math


class Slider extends PureComponent {
Expand All @@ -20,7 +21,7 @@ class Slider extends PureComponent {

componentWillReceiveProps({ value }) {
if (value !== this.props.value &&
value !== Math.round(this.state.value)) {
value !== round(this.state.value)) {
this.setState({ value })
}
}
Expand All @@ -44,7 +45,7 @@ class Slider extends PureComponent {
const left = box.left + border.left
const width = box.width - border.left - border.right

this.set(min + restrict((event.pageX - left) / width) * max)
this.set(min + restrict((event.pageX - left) / width, 0, 1) * max)
}

handleMouseDown = ({ button, pageX }) => {
Expand All @@ -54,21 +55,10 @@ class Slider extends PureComponent {
this.startDragging()
}

handleMouseUp = (event) => {
try {
if (event instanceof MouseEvent) {
this.update(event)
}

} finally {
this.stopDragging()
}
}

set = (value) => {
this.setState({ value })

const nearest = Math.round(value)
const nearest = round(value)

if (nearest !== this.props.value) {
this.props.onChange(nearest)
Expand Down Expand Up @@ -106,18 +96,18 @@ class Slider extends PureComponent {
this.setState({ isDragging: true })

on(document, 'mousemove', this.update)
on(document, 'mouseup', this.handleMouseUp, { capture: true })
on(document, 'mouseup', this.stopDragging, { capture: true })
on(document, 'mouseleave', this.stopDragging)
on(window, 'blur', this.handleMouseUp)
on(window, 'blur', this.stopDragging)
}

stopDragging = () => {
this.setState({ isDragging: false })

off(document, 'mousemove', this.update)
off(document, 'mouseup', this.handleMouseUp, { capture: true })
off(document, 'mouseup', this.stopDragging, { capture: true })
off(document, 'mouseleave', this.stopDragging)
off(window, 'blur', this.handleMouseUp)
off(window, 'blur', this.stopDragging)

if (this.delayed) {
clearTimeout(this.delayed)
Expand Down Expand Up @@ -197,15 +187,10 @@ class Slider extends PureComponent {
static defaultProps = {
min: 0,
max: 1,
size: 'md',
onChange: noop
size: 'md'
}
}

function restrict(value, lower = 0, upper = 1) {
return Math.min(Math.max(value, lower), upper)
}

module.exports = {
Slider
}
4 changes: 1 addition & 3 deletions src/components/util.js
@@ -1,7 +1,7 @@
'use strict'

const {
Children, PropTypes, PureComponent, createElement: create
Children, PureComponent, createElement: create
} = require('react')

const { diff } = require('../common/util')
Expand Down Expand Up @@ -86,8 +86,6 @@ module.exports = {
},

Shapes: {
edge: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),

number(min, max, required = true) {
return (props, name, component) => {
const value = props[name]
Expand Down

0 comments on commit e7717af

Please sign in to comment.