numericInputComponent.tsx 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import * as React from "react";
  2. interface INumericInputComponentProps {
  3. label: string;
  4. value: number;
  5. step?: number;
  6. onChange: (value: number) => void;
  7. }
  8. export class NumericInputComponent extends React.Component<INumericInputComponentProps, { value: string }> {
  9. static defaultProps = {
  10. step: 1,
  11. };
  12. private _localChange = false;
  13. constructor(props: INumericInputComponentProps) {
  14. super(props);
  15. this.state = { value: this.props.value.toFixed(3) }
  16. }
  17. shouldComponentUpdate(nextProps: INumericInputComponentProps, nextState: { value: string }) {
  18. if (this._localChange) {
  19. this._localChange = false;
  20. return true;
  21. }
  22. if (nextProps.value.toString() !== nextState.value) {
  23. nextState.value = nextProps.value.toFixed(3);
  24. return true;
  25. }
  26. return false;
  27. }
  28. updateValue(evt: any) {
  29. let value = evt.target.value;
  30. if (/[^0-9\.\-]/g.test(value)) {
  31. return;
  32. }
  33. let valueAsNumber = parseFloat(value);
  34. this._localChange = true;
  35. this.setState({ value: value });
  36. if (isNaN(valueAsNumber)) {
  37. return;
  38. }
  39. this.props.onChange(valueAsNumber);
  40. }
  41. render() {
  42. return (
  43. <div className="numeric">
  44. {
  45. this.props.label &&
  46. <div className="numeric-label">
  47. {`${this.props.label}: `}
  48. </div>
  49. }
  50. <input type="number" step={this.props.step} className="numeric-input" value={this.state.value} onChange={evt => this.updateValue(evt)} />
  51. </div>
  52. )
  53. }
  54. }