optionsLineComponent.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. import * as React from "react";
  2. import { Observable } from "babylonjs/Misc/observable";
  3. import { PropertyChangedEvent } from "./propertyChangedEvent";
  4. class ListLineOption {
  5. public label: string;
  6. public value: number | string;
  7. }
  8. interface IOptionsLineComponentProps {
  9. label: string,
  10. target: any,
  11. className?: string,
  12. propertyName?: string,
  13. options: ListLineOption[],
  14. noDirectUpdate?: boolean,
  15. onSelect?: (value: number | string) => void,
  16. onPropertyChangedObservable?: Observable<PropertyChangedEvent>,
  17. valuesAreStrings?: boolean
  18. defaultIfNull?: number,
  19. getSelection?: (target: any) => number;
  20. }
  21. export class OptionsLineComponent extends React.Component<IOptionsLineComponentProps, { value: number | string }> {
  22. private _localChange = false;
  23. private _getValue(props: IOptionsLineComponentProps) {
  24. if (props.getSelection) {
  25. return props.getSelection(props.target);
  26. }
  27. return (props.target && props.propertyName) ? props.target[props.propertyName] : props.options[props.defaultIfNull || 0];
  28. }
  29. constructor(props: IOptionsLineComponentProps) {
  30. super(props);
  31. this.state = { value: this._getValue(props) };
  32. }
  33. setValue(value: string | number) {
  34. this.setState({ value: value });
  35. }
  36. shouldComponentUpdate(nextProps: IOptionsLineComponentProps, nextState: { value: number }) {
  37. if (this._localChange) {
  38. this._localChange = false;
  39. return true;
  40. }
  41. const newValue = this._getValue(nextProps);
  42. if (newValue != null && newValue !== nextState.value) {
  43. nextState.value = newValue;
  44. return true;
  45. }
  46. return false;
  47. }
  48. raiseOnPropertyChanged(newValue: number | string, previousValue: number | string) {
  49. if (!this.props.onPropertyChangedObservable) {
  50. return;
  51. }
  52. this.props.onPropertyChangedObservable.notifyObservers({
  53. object: this.props.target,
  54. property: this.props.propertyName!,
  55. value: newValue,
  56. initialValue: previousValue
  57. });
  58. }
  59. updateValue(valueString: string) {
  60. const value = this.props.valuesAreStrings ? valueString : parseInt(valueString);
  61. this._localChange = true;
  62. const store = this.state.value;
  63. if (!this.props.noDirectUpdate) {
  64. this.props.target[this.props.propertyName!] = value;
  65. }
  66. this.setState({ value: value });
  67. this.raiseOnPropertyChanged(value, store);
  68. if (this.props.onSelect) {
  69. this.props.onSelect(value);
  70. }
  71. }
  72. render() {
  73. return (
  74. <div className="listLine">
  75. <div className="label">
  76. {this.props.label}
  77. </div>
  78. <div className={"options" + (this.props.className ? " " + this.props.className : "")}>
  79. <select onChange={evt => this.updateValue(evt.target.value)} value={this.state.value ?? ""}>
  80. {
  81. this.props.options.map(option => {
  82. return (
  83. <option key={option.label} value={option.value}>{option.label}</option>
  84. )
  85. })
  86. }
  87. </select>
  88. </div>
  89. </div>
  90. );
  91. }
  92. }