Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

fixes plotly/dash-core_components#169 #277

Closed
wants to merge 13 commits into from
Closed
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
136 changes: 114 additions & 22 deletions src/components/Input.react.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {omit} from 'ramda';
import {omit, contains} from 'ramda';

/**
* A function to handle the formating of the `value` prop of the react `input`.
* @param {string} val the `value` prop of the react `input` component.
* @param {string} type the `type` prop of the react `input` component.
* @returns {string} a value formated as a number if `type` is equal to `number`
*/
function formatValue(val, type) {
if (!val === '') {
if (type === 'number') {
return Number(val);
}
}
return val;
}

/**
* A basic HTML input control for entering text, numbers, or passwords.
Expand All @@ -12,39 +27,85 @@ import {omit} from 'ramda';
export default class Input extends Component {
constructor(props) {
super(props);
this.state = {value: props.value};
this.state = {
value: formatValue(props.value, props.type),
};
}

componentWillReceiveProps(nextProps) {
this.setState({value: nextProps.value});
this.setState({value: formatValue(nextProps.value, nextProps.type)});
}

render() {
const {
fireEvent,
setProps,
type
} = this.props;
const {fireEvent, setProps, type, updatemode} = this.props;

const {value} = this.state;
return (
<input
onBlur={() => {
const newValue = formatValue(this.state.value, type);
if (updatemode === 'blur' || contains('blur', updatemode)) {
this.setState({value: newValue});
if (setProps) {
setProps({value: newValue});
}
if (fireEvent) {
fireEvent({event: 'blur'});
}
}
}}
onChange={e => {
this.setState({value: e.target.value});
if (setProps) {
if (type === 'number') {
setProps({value: Number(e.target.value)});
const newValue = formatValue(e.target.value, type);
this.setState({value: newValue});
if (
updatemode === 'keypress' ||
contains('keypress', updatemode)
) {
if (setProps) {
setProps({value: newValue});
}
}
if (fireEvent) {
fireEvent({event: 'change'});
}
}}
onKeyPress={e => {
if (type === 'number') {
const curVal = this.state.value;
const keyCode = e.keyCode || e.which;
const keyValue = String.fromCharCode(keyCode);
const unicodePlus = 43;
const unicodeNine = 57;
if (
keyCode <= unicodePlus ||
keyCode > unicodeNine ||
keyValue === '/'
) {
e.preventDefault();
}
else {
setProps({value: e.target.value});
if (keyValue === '-' && curVal.length > 0) {
e.preventDefault();
}
if (
(keyValue === '.' || keyValue === ',') &&
/[.]|,/.test(curVal)
) {
e.preventDefault();
}
}
if (fireEvent) {fireEvent({event: 'change'});}
}}
onBlur={() => {
if (fireEvent) {fireEvent({event: 'blur'});}
onClick={e => {
const newValue = formatValue(e.target.value, type);
this.setState({value: newValue});
if (setProps) {
setProps({value: newValue});
}
}}
value={value}
{...omit(['fireEvent', 'setProps', 'value'], this.props)}
{...omit(
['fireEvent', 'setProps', 'value', 'updatemode'],
this.props
)}
/>
);
}
Expand Down Expand Up @@ -78,7 +139,15 @@ Input.propTypes = {
*/
type: PropTypes.oneOf([
// Only allowing the input types with wide browser compatability
'text', 'number', 'password', 'email', 'range', 'search', 'tel', 'url', 'hidden'
'text',
'number',
'password',
'email',
'range',
'search',
'tel',
'url',
'hidden',
]),

/**
Expand Down Expand Up @@ -150,7 +219,7 @@ Input.propTypes = {
/**
* URL input. Use type="url" if possible instead.
*/
'url'
'url',
]),

/**
Expand All @@ -173,7 +242,6 @@ Input.propTypes = {
*/
maxlength: PropTypes.string,


/**
* The minimum (numeric or date-time) value for this item, which must not be greater than its maximum (max attribute) value.
*/
Expand Down Expand Up @@ -244,6 +312,25 @@ Input.propTypes = {
*/
step: PropTypes.string,

/**
* Sets the number of important digits. It can be the string any or a positive floating point number. If this attribute is not set to any, the default is zero.
*/
precision: PropTypes.string,

/**
* Determines when the component should update
* its value. If `keypress`, then the input
* will trigger its value when the user presses on
* a key while the selector is active inside the input.
* If `blur`, then the input will trigger its value when
* the user click outside the input zone or press tab.
* If `enter` ...
*/
updatemode: PropTypes.oneOfType([
PropTypes.oneOf(['keypress', 'blur', 'enter']),
PropTypes.arrayOf(PropTypes.oneOf(['keypress', 'blur', 'enter'])),
]),

/**
* Dash-assigned callback that gets fired when the input changes.
*/
Expand All @@ -254,5 +341,10 @@ Input.propTypes = {
*/
setProps: PropTypes.func,

dashEvents: PropTypes.oneOf(['blur', 'change'])
dashEvents: PropTypes.oneOf(['blur', 'change']),
};

Input.defaultProps = {
type: 'text',
updatemode: 'keypress',
};