diff --git a/components/dash-core-components/src/components/Input.react.js b/components/dash-core-components/src/components/Input.react.js
index d4656fddae..307f20a649 100644
--- a/components/dash-core-components/src/components/Input.react.js
+++ b/components/dash-core-components/src/components/Input.react.js
@@ -31,6 +31,8 @@ const inputProps = [
'size',
'style',
'id',
+ 'currencyFormat',
+ 'currencySymbol',
];
/**
@@ -46,7 +48,10 @@ export default class Input extends PureComponent {
this.state = {
pendingEvent: undefined,
- value: '',
+ value: '' | props.value,
+ displayValue: props.currencyFormat
+ ? this.formatCurrency(props.value)
+ : props.value,
};
this.input = React.createRef();
@@ -58,6 +63,7 @@ export default class Input extends PureComponent {
this.debounceEvent = this.debounceEvent.bind(this);
this.setInputValue = this.setInputValue.bind(this);
this.setPropValue = this.setPropValue.bind(this);
+ this.handleInputChange = this.handleInputChange.bind(this);
}
UNSAFE_componentWillReceiveProps(nextProps) {
@@ -90,25 +96,58 @@ export default class Input extends PureComponent {
this.setState({value: this.props.value});
}
}
+ formatCurrency(value) {
+ if (isNaN(value) || value === '') {
+ return '';
+ }
+ const {currencySymbol} = this.props;
+
+ return `${currencySymbol}${Number(value).toLocaleString()}`;
+ }
+ parseDisplayValue(value) {
+ if (!value) {
+ return '';
+ }
+ // Remove currency symbol and non-numeric characters
+ return Number(value.replace(/[^0-9.-]+/g, ''));
+ }
+ handleInputChange(event) {
+ const {value} = event.target;
+ const valueAsNumber = this.parseDisplayValue(value);
+ this.setState({
+ value: valueAsNumber,
+ displayValue: this.props.currencyFormat
+ ? this.formatCurrency(valueAsNumber)
+ : valueAsNumber,
+ });
+ }
render() {
- const valprops =
- this.props.type === 'number' ? {} : {value: this.state.value};
- const {loading_state} = this.props;
+ const {loading_state, currencyFormat} = this.props;
+ let valprops;
+ if (this.props.type === 'number' && !currencyFormat) {
+ valprops = { value: this.state.value }; // Always show the number
+ } else {
+ valprops = { value: this.state.displayValue }; // Use formatted display value for currency
+ }
let {className} = this.props;
+
+ const inputType = currencyFormat ? 'text' : 'number';
+
className = 'dash-input' + (className ? ` ${className}` : '');
return (
);
}
@@ -119,7 +158,14 @@ export default class Input extends PureComponent {
value = convert(value);
if (!isEquivalent(base, value)) {
- this.input.current.value = isNumeric(value) ? value : __value;
+ if (isNumeric(value)) {
+ const formattedValue = this.props.currencyFormat
+ ? this.formatCurrency(value)
+ : value;
+ this.setState({displayValue: formattedValue}, () => {});
+ } else {
+ this.setState({displayValue: __value});
+ }
}
}
@@ -131,18 +177,22 @@ export default class Input extends PureComponent {
this.props.setProps({value});
}
}
-
onEvent() {
const {value} = this.input.current;
- const valueAsNumber = convert(value);
+ const valueAsNumber = this.parseDisplayValue(value);
+
if (this.props.type === 'number') {
this.setPropValue(
this.props.value,
- isNil(valueAsNumber) ? value : valueAsNumber
+ isNaN(valueAsNumber) ? value : valueAsNumber
);
} else {
- this.props.setProps({value});
+ const formattedValue = this.props.currencyFormat
+ ? this.formatCurrency(valueAsNumber)
+ : value;
+ this.props.setProps({value: formattedValue});
}
+
this.setState({pendingEvent: undefined});
}
@@ -207,6 +257,8 @@ Input.defaultProps = {
step: 'any',
persisted_props: ['value'],
persistence_type: 'local',
+ currencyFormat: false,
+ currencySymbol: '$',
};
Input.propTypes = {
@@ -239,6 +291,29 @@ Input.propTypes = {
*/
debounce: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]),
+ /**
+ * If true and type is 'number', formats the input value as currency.
+ */
+ currencyFormat: (props, propName, componentName) => {
+ if (props.currencyFormat && props.type !== 'number') {
+ return new Error(
+ `Invalid prop \`${propName}\` supplied to ` +
+ `\`${componentName}\`. \`${propName}\` can only be used when \`type\` is \`number\`.`
+ );
+ }
+ return null; // Ensure to return null if there’s no error
+ },
+
+ currencySymbol: (props, propName, componentName) => {
+ if (props.currencySymbol && props.type !== 'number') {
+ return new Error(
+ `Invalid prop \`${propName}\` supplied to ` +
+ `\`${componentName}\`. \`${propName}\` can only be used when \`type\` is \`number\`.`
+ );
+ }
+ return null; // Ensure to return null if there’s no error
+ },
+
/**
* A hint to the user of what can be entered in the control . The placeholder text must not contain carriage returns or line-feeds. Note: Do not use the placeholder attribute instead of a