Skip to content
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

Number input and component improvements #264

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions web/src/scripts/components/input/NumberInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
*/

import _ from 'lodash'
import React, { Component, } from 'react'
import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import { StylesEnhancer } from 'react-styles-provider'
import pureRender from 'pure-render-decorator'

import { getLockedValue } from '../../utils/NumberUtils'

const stylesCreator = ({input}, {type, width, disabled}) => ({
input: {
...(type === 'platform' ? input.platform : input.regular),
Expand All @@ -36,10 +38,13 @@ const stylesCreator = ({input}, {type, width, disabled}) => ({
export default class NumberInput extends Component {

static propTypes = {
onChange: React.PropTypes.func.isRequired,
onSubmit: React.PropTypes.func,
value: React.PropTypes.number.isRequired,
disabled: React.PropTypes.bool,
onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func,
value: PropTypes.number.isRequired,
min: PropTypes.number,
max: PropTypes.number,
step: PropTypes.number,
disabled: PropTypes.bool,
}

static defaultProps = {
Expand Down Expand Up @@ -89,23 +94,28 @@ export default class NumberInput extends Component {
}

onKeyDown = (e) => {
const {step, max, min} = this.props
let stopPropagation = false
let incrementBy = 0

switch (e.keyCode) {
// Tab
case 9:
;
break
// Enter
case 13:
stopPropagation = true
this.props.onSubmit(e.target.value)
break
// Up arrow
case 38:
incrementBy = 1
incrementBy = step || 1
stopPropagation = true
break
// Down arrow
case 40:
incrementBy = -1
incrementBy = step ? step * -1 : -1
stopPropagation = true
break
default:
Expand Down Expand Up @@ -142,6 +152,7 @@ export default class NumberInput extends Component {
}

value = this.roundInput(value)
value = getLockedValue(value, min, max, step)

this.props.onChange(value)

Expand Down
20 changes: 12 additions & 8 deletions web/src/scripts/components/input/SliderInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
*/

import _ from 'lodash'
import React, { Component, } from 'react'
import React, { Component, PropTypes } from 'react'
import { StylesEnhancer } from 'react-styles-provider'
import pureRender from 'pure-render-decorator'

import { getLockedValue } from '../../utils/NumberUtils'

let SLIDER_REF = 'slider'

const stylesCreator = ({input, colors}, {type, width, height, trackHeight, disabled, knobWidth}) => {
Expand Down Expand Up @@ -86,17 +88,19 @@ const stylesCreator = ({input, colors}, {type, width, height, trackHeight, disab
export default class SliderInput extends Component {

static propTypes = {
value: React.PropTypes.number,
min: React.PropTypes.number,
max: React.PropTypes.number,
onChange: React.PropTypes.func,
disabled: React.PropTypes.bool,
value: PropTypes.number,
min: PropTypes.number,
max: PropTypes.number,
step: PropTypes.number,
onChange: PropTypes.func,
disabled: PropTypes.bool,
}

static defaultProps = {
value: 0,
min: 0,
max: 100,
step: 1,
height: 30,
trackHeight: 3,
knobWidth: 12,
Expand Down Expand Up @@ -168,7 +172,7 @@ export default class SliderInput extends Component {

calculateValueFromPosition(position, bounds) {
const trackWidth = this.getTrackWidth(bounds)
const {min, max, knobWidth} = this.props
const {min, max, knobWidth, step} = this.props

// Prevent division by 0
if (trackWidth === 0) {
Expand All @@ -180,7 +184,7 @@ export default class SliderInput extends Component {
const percent = (position - bounds.min) / trackWidth
const range = max - min
const value = (percent * range) + min
return Math.round(_.clamp(value, min, max))
return getLockedValue(value, min, max, step)
}

getPercentValue() {
Expand Down
2 changes: 1 addition & 1 deletion web/src/scripts/components/inspector/Property.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export default class Property extends Component {
const {name, value, type, editWith} = prop

const inputProps = {
value,
...prop,
title: name,
onChange: this.onChange,
actions,
Expand Down
18 changes: 11 additions & 7 deletions web/src/scripts/components/inspector/PropertyNumberInput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import React, { Component } from 'react'
import { StylesEnhancer } from 'react-styles-provider'
import pureRender from 'pure-render-decorator'
import _ from 'lodash'

import PropertyField from './PropertyField'
import PropertyDivider from './PropertyDivider'
Expand All @@ -37,17 +38,24 @@ const stylesCreator = ({fonts}) => ({
}
})

const inputPropKeys = ['value', 'min', 'max', 'step', 'onChange', 'disabled']

@StylesEnhancer(stylesCreator)
@pureRender
export default class PropertyNumberInput extends Component {

static defaultProps = {
title: '',
value: 0,
min: 0,
max: 100,
step: 1,
}

render() {
const {styles, title, value, onChange, actions, dividerType, disabled} = this.props
const {styles, title, actions, dividerType} = this.props

const inputProps = _.pick(this.props, inputPropKeys)

return (
<PropertyField
Expand All @@ -57,15 +65,11 @@ export default class PropertyNumberInput extends Component {
>
<div style={styles.row}>
<SliderInput
value={value}
onChange={onChange}
disabled={disabled}
{...inputProps}
/>
<div style={styles.spacer} />
<NumberInput
value={value}
onChange={onChange}
disabled={disabled}
{...inputProps}
/>
</div>
</PropertyField>
Expand Down
17 changes: 16 additions & 1 deletion web/src/scripts/containers/ComponentInspector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import { StylesEnhancer } from 'react-styles-provider'

import { elementTreeActions } from '../actions'
import * as uiActions from '../actions/uiActions'
import * as tabActions from '../actions/tabActions'
import * as URIUtils from '../utils/URIUtils'
import * as selectors from '../selectors'
import { ComponentMenuItem, PaneHeader } from '../components'
import ComponentProps from './ComponentProps'
Expand All @@ -48,15 +50,18 @@ const mapStateToProps = (state) => createSelector(
selectors.selectedElement,
selectors.selectedComponent,
selectors.focusedFileId,
(element, component, focusedFileId) => ({
selectors.tabContainerId,
(element, component, focusedFileId, tabContainerId) => ({
component: component || element,
focusedFileId,
tabContainerId,
})
)

const mapDispatchToProps = (dispatch) => ({
elementTreeActions: bindActionCreators(elementTreeActions, dispatch),
uiActions: bindActionCreators(uiActions, dispatch),
tabActions: bindActionCreators(tabActions, dispatch),
})

@StylesEnhancer(stylesCreator, ({style}) => ({style}))
Expand All @@ -69,6 +74,15 @@ class ComponentInspector extends Component {
uiActions.setSidebarContext()
}

onTitleClick = (component) => {
// TODO: if we're not in dev mode or with correct permissions, return instead
const {tabActions, tabContainerId} = this.props
const uri = URIUtils.componentIdToURI(component.id)

this.onBack()
tabActions.addTab(tabContainerId, uri)
}

render() {
const {style, styles, width, component, elementTreeActions} = this.props

Expand All @@ -80,6 +94,7 @@ class ComponentInspector extends Component {
/>
{component && (
<ComponentMenuItem
onClick={this.onTitleClick}
name={component.name}
item={component}
/>
Expand Down
45 changes: 45 additions & 0 deletions web/src/scripts/utils/NumberUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Copyright (C) 2015 Deco Software Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

export const getNearestValue = (val, low, high) => {
return Math.abs(val - low) < Math.abs(val - high) ? low : high
}

export const getDecimalCount = (num) => {
const decSplitArr = num.toString().split('.')
return decSplitArr[1] ? decSplitArr[1].length : 0
}

export const conditionalClamp = (val, min, max) => {
if (min && val <= min) {
return min
}
if (max && val >= max) {
return max
}
return val
}

export const getLockedValue = (val, min, max, step) => {
const stepCount = val / step
const nearestLower = Math.max(Math.floor(stepCount) * step, min)
const nearestUpper = Math.min(Math.ceil(stepCount) * step, max)
// If step=.1, value=.82, this gets us .8
const newValue = getNearestValue(val, nearestLower, nearestUpper)
// Clip value to step's decimals, and then remove trailing 0s
return Number(conditionalClamp(newValue, min, max).toFixed(getDecimalCount(step)))
}