uiconfig-blueprint 0.1.0-dev.7 → 0.1.0-dev.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/dist/ConfigObject.d.ts +2 -1
  2. package/dist/{allPaths-BOo4cECg.js → allPaths-C4QHVET-.js} +5 -5
  3. package/dist/{allPaths-BOo4cECg.js.map → allPaths-C4QHVET-.js.map} +1 -1
  4. package/dist/{allPathsLoader-B4vYL2gG.js → allPathsLoader-Dm-MlOxQ.js} +4 -4
  5. package/dist/{allPathsLoader-B4vYL2gG.js.map → allPathsLoader-Dm-MlOxQ.js.map} +1 -1
  6. package/dist/bpComponents/BPContainerComponent.d.ts +1 -1
  7. package/dist/bpComponents/BPNumberInputComponent.d.ts +3 -1
  8. package/dist/bpComponents/BPSliderInputComponent.d.ts +1 -0
  9. package/dist/bpComponents/BPTreeComponent.d.ts +1 -1
  10. package/dist/bpComponents/BPVectorInputComponent.d.ts +1 -0
  11. package/dist/bpComponents/GetNumberTransformFunctions.d.ts +4 -0
  12. package/dist/bpComponents/NumberUnits.d.ts +7 -0
  13. package/dist/components/ExtendedNumericInput.d.ts +13 -3
  14. package/dist/components/NumericInput.d.ts +79 -0
  15. package/dist/components/bpIconWrapper.d.ts +1 -1
  16. package/dist/{index-13b-jSvJ.js → index-2Z2Mq97s.js} +4907 -4700
  17. package/dist/index-2Z2Mq97s.js.map +1 -0
  18. package/dist/{index-B0IO--x7.js → index-BKXNXgJi.js} +2 -2
  19. package/dist/{index-B0IO--x7.js.map → index-BKXNXgJi.js.map} +1 -1
  20. package/dist/{index-BttMe1vP.js → index-BVSBMJ4w.js} +2 -2
  21. package/dist/{index-BttMe1vP.js.map → index-BVSBMJ4w.js.map} +1 -1
  22. package/dist/index.js +18 -18
  23. package/dist/index.js.map +1 -1
  24. package/dist/index.mjs +2 -2
  25. package/dist/lib.d.ts +3 -0
  26. package/dist/{splitPathsBySizeLoader-nUv2DYaP.js → splitPathsBySizeLoader-CJaJimKZ.js} +5 -5
  27. package/dist/{splitPathsBySizeLoader-nUv2DYaP.js.map → splitPathsBySizeLoader-CJaJimKZ.js.map} +1 -1
  28. package/docs/classes/UI.html +3 -3
  29. package/docs/classes/UiConfigRendererBlueprint.html +3 -3
  30. package/lib/css/renderer.css +76 -1
  31. package/lib/css/renderer.css.map +1 -1
  32. package/lib/esm/ConfigObject.d.ts +2 -1
  33. package/lib/esm/ConfigObject.js +5 -4
  34. package/lib/esm/ConfigObject.js.map +1 -1
  35. package/lib/esm/bpComponents/BPContainerComponent.d.ts +1 -1
  36. package/lib/esm/bpComponents/BPContainerComponent.js +11 -1
  37. package/lib/esm/bpComponents/BPContainerComponent.js.map +1 -1
  38. package/lib/esm/bpComponents/BPFolderComponent.js +2 -2
  39. package/lib/esm/bpComponents/BPFolderComponent.js.map +1 -1
  40. package/lib/esm/bpComponents/BPNumberInputComponent.d.ts +3 -1
  41. package/lib/esm/bpComponents/BPNumberInputComponent.js +6 -1
  42. package/lib/esm/bpComponents/BPNumberInputComponent.js.map +1 -1
  43. package/lib/esm/bpComponents/BPSliderInputComponent.d.ts +1 -0
  44. package/lib/esm/bpComponents/BPSliderInputComponent.js +16 -15
  45. package/lib/esm/bpComponents/BPSliderInputComponent.js.map +1 -1
  46. package/lib/esm/bpComponents/BPTreeComponent.d.ts +1 -1
  47. package/lib/esm/bpComponents/BPTreeComponent.js +11 -7
  48. package/lib/esm/bpComponents/BPTreeComponent.js.map +1 -1
  49. package/lib/esm/bpComponents/BPVectorInputComponent.d.ts +1 -0
  50. package/lib/esm/bpComponents/BPVectorInputComponent.js +14 -8
  51. package/lib/esm/bpComponents/BPVectorInputComponent.js.map +1 -1
  52. package/lib/esm/bpComponents/GetNumberTransformFunctions.d.ts +4 -0
  53. package/lib/esm/bpComponents/GetNumberTransformFunctions.js +14 -0
  54. package/lib/esm/bpComponents/GetNumberTransformFunctions.js.map +1 -0
  55. package/lib/esm/bpComponents/NumberUnits.d.ts +7 -0
  56. package/lib/esm/bpComponents/NumberUnits.js +101 -0
  57. package/lib/esm/bpComponents/NumberUnits.js.map +1 -0
  58. package/lib/esm/components/DialogContext.js +12 -3
  59. package/lib/esm/components/DialogContext.js.map +1 -1
  60. package/lib/esm/components/ExtendedNumericInput.d.ts +13 -3
  61. package/lib/esm/components/ExtendedNumericInput.js +62 -17
  62. package/lib/esm/components/ExtendedNumericInput.js.map +1 -1
  63. package/lib/esm/components/NumericInput.d.ts +79 -0
  64. package/lib/esm/components/NumericInput.js +311 -0
  65. package/lib/esm/components/NumericInput.js.map +1 -0
  66. package/lib/esm/components/Tree2.js +2 -2
  67. package/lib/esm/components/Tree2.js.map +1 -1
  68. package/lib/esm/components/TreeNode2.js +2 -2
  69. package/lib/esm/components/TreeNode2.js.map +1 -1
  70. package/lib/esm/components/VisualStyleContext.js +7 -1
  71. package/lib/esm/components/VisualStyleContext.js.map +1 -1
  72. package/lib/esm/components/bpIconWrapper.d.ts +1 -1
  73. package/lib/esm/components/bpIconWrapper.js +2 -2
  74. package/lib/esm/components/bpIconWrapper.js.map +1 -1
  75. package/lib/esm/components/iconMapping.js +1 -1
  76. package/lib/esm/components/iconMapping.js.map +1 -1
  77. package/lib/esm/lib.d.ts +3 -0
  78. package/lib/esm/lib.js +3 -0
  79. package/lib/esm/lib.js.map +1 -1
  80. package/package.json +2 -2
  81. package/src/ConfigObject.tsx +8 -6
  82. package/src/bpComponents/BPButtonComponent.scss +3 -1
  83. package/src/bpComponents/BPContainerComponent.tsx +11 -0
  84. package/src/bpComponents/BPFolderComponent.tsx +2 -2
  85. package/src/bpComponents/BPNumberInputComponent.tsx +13 -2
  86. package/src/bpComponents/BPSliderInputComponent.tsx +37 -29
  87. package/src/bpComponents/BPTreeComponent.tsx +14 -8
  88. package/src/bpComponents/BPVectorInputComponent.tsx +23 -20
  89. package/src/bpComponents/GetNumberTransformFunctions.tsx +14 -0
  90. package/src/bpComponents/NumberUnits.tsx +123 -0
  91. package/src/components/DialogContext.tsx +16 -2
  92. package/src/components/ExtendedNumericInput.tsx +70 -19
  93. package/src/components/NumericInput.tsx +679 -0
  94. package/src/components/Tree2.tsx +3 -3
  95. package/src/components/TreeNode2.tsx +2 -2
  96. package/src/components/VisualStyleContext.tsx +8 -0
  97. package/src/components/bpIconWrapper.tsx +2 -2
  98. package/src/components/iconMapping.ts +1 -1
  99. package/src/components/tree2.scss +27 -0
  100. package/src/lib.ts +3 -0
  101. package/src/renderer.scss +19 -0
  102. package/dist/index-13b-jSvJ.js.map +0 -1
@@ -6,12 +6,14 @@ import type {Vector2, Vector3, Vector4} from "three";
6
6
  import {ExtendedNumericInput} from "../components/ExtendedNumericInput";
7
7
  import {wIcon3, xIcon3, yIcon3, zIcon3} from "../components/variableIcons";
8
8
  import {getOrCall} from 'ts-browser-helpers'
9
+ import {getNumberTransformFunctions} from "./GetNumberTransformFunctions";
9
10
 
10
11
  export type BPVectorComponentState = BPValueComponentState<Vector2|Vector3|Vector4> & {
11
12
  min: number,
12
13
  max: number,
13
14
  step: number,
14
15
  components: 1|2|3|4,
16
+ unit?: string,
15
17
  }
16
18
 
17
19
  export class BPVectorInputComponent extends BPInputComponent<Vector2|Vector3|Vector4, BPVectorComponentState> {
@@ -73,21 +75,34 @@ export class BPVectorInputComponent extends BPInputComponent<Vector2|Vector3|Vec
73
75
  let ret = []
74
76
  if (!this.state.value) return <></>;
75
77
 
78
+ const unit = this.props.config.unit as string|undefined; // todo add to uiconfig, getOrCall
79
+ const unitType = this.props.config.unitType as string|undefined; // todo add to uiconfig, getOrCall
80
+ const targetUnit = this.state.unit || unit
81
+ const transformValue = getNumberTransformFunctions(unit, unitType, targetUnit);
82
+
83
+ const props = {
84
+ disabled: this.state.disabled,
85
+ readOnly: this.state.readOnly,
86
+ min: this.state.min,
87
+ max: this.state.max,
88
+ stepSize: this.state.step,
89
+ minorStepSize: this.state.step / 10,
90
+ majorStepSize: this.state.step * 10,
91
+ buttonPosition: "none",
92
+ ...transformValue,
93
+ } as const
94
+
76
95
  // console.warn(this.state.value)
77
96
  if (this.state.components > 0) {
78
97
  const x = (
79
98
  <ExtendedNumericInput
80
99
  style={{maxWidth: "8rem", minWidth: "2rem"}}
81
- disabled={this.state.disabled} readOnly={this.state.readOnly}
82
100
  // defaultValue={state}
83
101
  leftIcon={xIcon3}
84
102
  value={this.state.value.x}
85
103
  key={this.props.config.uuid + '_x'}
86
104
  ref={this._inputs[0]}
87
- min={this.state.min} max={this.state.max} stepSize={this.state.step}
88
- minorStepSize={this.state.step / 10}
89
- majorStepSize={this.state.step * 10}
90
- buttonPosition="none"
105
+ {...props}
91
106
  onChange2={(v, last) => {
92
107
  this.state.value.x = v
93
108
  this.setValue(this.state.value, last) // todo: does need refresh?
@@ -100,15 +115,11 @@ export class BPVectorInputComponent extends BPInputComponent<Vector2|Vector3|Vec
100
115
  <ExtendedNumericInput
101
116
  style={{maxWidth: "8rem", minWidth: "2rem"}}
102
117
  // defaultValue={state}
103
- disabled={this.state.disabled} readOnly={this.state.readOnly}
104
118
  value={this.state.value.y}
105
119
  leftIcon={yIcon3}
106
120
  key={this.props.config.uuid + '_y'}
107
121
  ref={this._inputs[1]}
108
- min={this.state.min} max={this.state.max} stepSize={this.state.step}
109
- minorStepSize={this.state.step / 10}
110
- majorStepSize={this.state.step * 10}
111
- buttonPosition="none"
122
+ {...props}
112
123
  onChange2={(v, last) => {
113
124
  this.state.value.y = v
114
125
  this.setValue(this.state.value, last) // todo: does need refresh?
@@ -121,15 +132,11 @@ export class BPVectorInputComponent extends BPInputComponent<Vector2|Vector3|Vec
121
132
  <ExtendedNumericInput
122
133
  style={{maxWidth: "8rem", minWidth: "2rem"}}
123
134
  // defaultValue={state}
124
- disabled={this.state.disabled} readOnly={this.state.readOnly}
125
135
  value={(this.state.value as Vector3|Vector4).z}
126
136
  key={this.props.config.uuid + '_z'}
127
137
  leftIcon={zIcon3}
128
- min={this.state.min} max={this.state.max} stepSize={this.state.step}
129
138
  ref={this._inputs[2]}
130
- minorStepSize={this.state.step / 10}
131
- majorStepSize={this.state.step * 10}
132
- buttonPosition="none"
139
+ {...props}
133
140
  onChange2={(v, last) => {
134
141
  (this.state.value as Vector3 | Vector4).z = v
135
142
  this.setValue(this.state.value, last) // todo: does need refresh?
@@ -142,15 +149,11 @@ export class BPVectorInputComponent extends BPInputComponent<Vector2|Vector3|Vec
142
149
  <ExtendedNumericInput
143
150
  style={{maxWidth: "8rem", minWidth: "2rem"}}
144
151
  // defaultValue={state}
145
- disabled={this.state.disabled} readOnly={this.state.readOnly}
146
152
  value={(this.state.value as Vector4).w}
147
153
  key={this.props.config.uuid + '_w'}
148
154
  leftIcon={wIcon3}
149
155
  ref={this._inputs[3]}
150
- min={this.state.min} max={this.state.max} stepSize={this.state.step}
151
- minorStepSize={this.state.step / 10}
152
- majorStepSize={this.state.step * 10}
153
- buttonPosition="none"
156
+ {...props}
154
157
  onChange2={(v, last) => {
155
158
  (this.state.value as Vector4).w = v
156
159
  this.setValue(this.state.value, last) // todo: does need refresh?
@@ -0,0 +1,14 @@
1
+ import {NumberUnits} from "./NumberUnits";
2
+
3
+ export function getNumberTransformFunctions(unit: string | undefined, unitType1: string | undefined, targetUnit: string | undefined) {
4
+ const unitType = unit ? Object.entries(NumberUnits).find(([k, v]) => !!v[unit] && (!unitType1 || k === unitType1)) : undefined
5
+ const target = targetUnit !== unit && unitType && targetUnit ? unitType[1][targetUnit] : undefined
6
+ const source = targetUnit !== unit && unitType && unit ? unitType[1][unit] : undefined
7
+ const transformValue = target && source ?
8
+ (v: number) => target.from(source.to(v)) :
9
+ undefined;
10
+ const invTransformValue = target && source ?
11
+ (v: number) => source.from(target.to(v)) :
12
+ undefined;
13
+ return {transformValue, invTransformValue};
14
+ }
@@ -0,0 +1,123 @@
1
+ export interface NumberUnit{
2
+ name: string;
3
+ symbol: string;
4
+ from: (value: number) => number;
5
+ to: (value: number) => number;
6
+ }
7
+ export const NumberUnits: Record<string, Record<string, NumberUnit>> = {
8
+ 'distance': {
9
+ 'm': {
10
+ 'name': 'Meters',
11
+ 'symbol': 'm',
12
+ from: (v: number) => v,
13
+ to: (v: number) => v,
14
+ },
15
+ 'cm': {
16
+ 'name': 'Centimeters',
17
+ 'symbol': 'cm',
18
+ from: (v: number) => v / 100,
19
+ to: (v: number) => v * 100,
20
+ },
21
+ 'mm': {
22
+ 'name': 'Millimeters',
23
+ 'symbol': 'mm',
24
+ from: (v: number) => v / 1000,
25
+ to: (v: number) => v * 1000,
26
+ },
27
+ 'in': {
28
+ 'name': 'Inches',
29
+ 'symbol': 'in',
30
+ from: (v: number) => v * 0.0254,
31
+ to: (v: number) => v / 0.0254,
32
+ },
33
+ 'ft': {
34
+ 'name': 'Feet',
35
+ 'symbol': 'ft',
36
+ from: (v: number) => v * 0.3048,
37
+ to: (v: number) => v / 0.3048,
38
+ },
39
+ 'km': {
40
+ 'name': 'Kilometers',
41
+ 'symbol': 'km',
42
+ from: (v: number) => v * 1000,
43
+ to: (v: number) => v / 1000,
44
+ },
45
+ 'mi': {
46
+ 'name': 'Miles',
47
+ 'symbol': 'mi',
48
+ from: (v: number) => v * 1609.34,
49
+ to: (v: number) => v / 1609.34,
50
+ },
51
+ },
52
+ 'angle': {
53
+ 'rad': {
54
+ 'name': 'Radians',
55
+ 'symbol': 'rad',
56
+ from: (v: number) => v,
57
+ to: (v: number) => v,
58
+ },
59
+ 'deg': {
60
+ 'name': 'Degrees',
61
+ 'symbol': 'deg',
62
+ from: (v: number) => v * Math.PI / 180,
63
+ to: (v: number) => v * 180 / Math.PI,
64
+ },
65
+ 'grad': {
66
+ 'name': 'Gradians',
67
+ 'symbol': 'grad',
68
+ from: (v: number) => v * Math.PI / 200,
69
+ to: (v: number) => v * 200 / Math.PI,
70
+ },
71
+ },
72
+ 'temperature': {
73
+ 'celsius': {
74
+ 'name': 'Celsius',
75
+ 'symbol': '°C',
76
+ from: (v: number) => v,
77
+ to: (v: number) => v,
78
+ },
79
+ 'fahrenheit': {
80
+ 'name': 'Fahrenheit',
81
+ 'symbol': '°F',
82
+ from: (v: number) => (v - 32) * 5 / 9,
83
+ to: (v: number) => v * 9 / 5 + 32,
84
+ },
85
+ 'kelvin': {
86
+ 'name': 'Kelvin',
87
+ 'symbol': 'K',
88
+ from: (v: number) => v - 273.15,
89
+ to: (v: number) => v + 273.15,
90
+ },
91
+ },
92
+ 'pixel': {
93
+ 'px': {
94
+ 'name': 'Pixels',
95
+ 'symbol': 'px',
96
+ from: (v: number) => v,
97
+ to: (v: number) => v,
98
+ },
99
+ 'dp': {
100
+ 'name': 'Density-independent Pixels',
101
+ 'symbol': 'dp',
102
+ from: (v: number) => v * window.devicePixelRatio,
103
+ to: (v: number) => v / window.devicePixelRatio,
104
+ },
105
+ // todo
106
+ // 'sp': {
107
+ // 'name': 'Scale-independent Pixels',
108
+ // 'symbol': 'sp',
109
+ // from: (v: number) => {
110
+ // const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize) / 16;
111
+ // return v * fontSize * window.devicePixelRatio;
112
+ // }
113
+ // },
114
+ // 'rem': {
115
+ // 'name': 'Root em',
116
+ // 'symbol': 'rem',
117
+ // from: (v: number) => {
118
+ // const fontSize = parseFloat(getComputedStyle(document.documentElement).fontSize) / 16;
119
+ // return v * fontSize * window.devicePixelRatio;
120
+ // }
121
+ // }
122
+ }
123
+ }
@@ -156,6 +156,7 @@ function DialogPromptButtons({
156
156
  onClick={() => updateLoading('popup-close', doClose())}/>
157
157
  <Button text={submitButtonText}
158
158
  intent="primary"
159
+ data-dialog-submit="true"
159
160
  loading={loadingState['popup-submit']}
160
161
  onClick={() => updateLoading('popup-submit', doSubmit())}/>
161
162
  </>
@@ -172,6 +173,18 @@ function DialogPromptContent({
172
173
  showInput?: boolean,
173
174
  }){
174
175
  const {state, setState} = useDialog() as {state: DialogPromptState, setState: Dispatch<SetStateAction<DialogPromptState>>}
176
+ const {loadingState} = useLoadingState()
177
+
178
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
179
+ if (e.key === 'Enter') {
180
+ // Get the submit button using the data attribute and simulate a click
181
+ const submitButton = document.querySelector('[data-dialog-submit="true"]') as HTMLButtonElement;
182
+ if (submitButton && !loadingState['popup-submit']) {
183
+ submitButton.click();
184
+ }
185
+ }
186
+ }
187
+
175
188
  return <FormGroup
176
189
  helperText={state.helperText||undefined}
177
190
  intent={state.intent}
@@ -184,13 +197,14 @@ function DialogPromptContent({
184
197
  placeholder={placeholder}
185
198
  defaultValue={state.value}
186
199
  style={{display: showInput ? 'block' : 'none'}}
200
+ autoFocus={true}
187
201
  onChange={(e: any) => {
188
202
  state.value = e.target.value
189
203
  state.helperText = ''
190
204
  state.intent = Intent.NONE
191
205
  setState({...state})
192
- }} // todo: submit on enter
206
+ }}
207
+ onKeyDown={handleKeyDown}
193
208
  />
194
209
  </FormGroup>
195
-
196
210
  }
@@ -20,7 +20,7 @@
20
20
  import React from "react";
21
21
 
22
22
  import type {HTMLInputProps, NumericInputProps} from "@blueprintjs/core";
23
- import {NumericInput} from "@blueprintjs/core";
23
+ import {NumericInput} from "./NumericInput";
24
24
  import {DraggableIcon} from "./DraggableIcon";
25
25
 
26
26
  export interface IExtendedNumericInputState {
@@ -35,40 +35,87 @@ const NumberAbbreviation = {
35
35
 
36
36
  const NUMBER_ABBREVIATION_REGEX = /((\.\d+)|(\d+(\.\d+)?))(k|m|b)\b/gi;
37
37
  const SCIENTIFIC_NOTATION_REGEX = /((\.\d+)|(\d+(\.\d+)?))(e\d+)\b/gi;
38
+ type Props = HTMLInputProps & NumericInputProps & {
39
+ onChange2?: (v: number, last?: boolean) => void,
40
+ transformValue?: (v: number) => number,
41
+ invTransformValue?: (v: number) => number,
42
+ draggableIcon?: boolean
43
+ value?: number | undefined
44
+ defaultValue?: number | undefined
45
+ }
38
46
  // todo: bounds and stepsize
39
- export class ExtendedNumericInput extends React.PureComponent<HTMLInputProps & NumericInputProps & { onChange2: (v: number, last?: boolean) => void }, IExtendedNumericInputState> {
47
+ export class ExtendedNumericInput extends React.PureComponent<Props, IExtendedNumericInputState> {
48
+ invTransformValue = (v: number|undefined) => {
49
+ v = v || 0
50
+ const v1 = this.props.invTransformValue ? this.props.invTransformValue(v) : v;
51
+ return v1
52
+ }
53
+ transformValue = (v: number|undefined) => {
54
+ v = v || 0
55
+ const v1 = this.props.transformValue ? this.props.transformValue(v) : v;
56
+ return v1
57
+ }
58
+
40
59
  public state: IExtendedNumericInputState = {
41
- value: (this.props.value ?? this.props.defaultValue ?? '').toString(),
60
+ value: this.invTransformValue(this.props.value ?? this.props.defaultValue).toString(),
42
61
  };
43
62
 
44
63
  async setValue(val?: number) {
45
64
  return new Promise<void>((resolve) => {
46
- this.setState({value: (val ?? this.props.value ?? this.props.defaultValue ?? '').toString()}, resolve)
65
+ this.setState({value: this.invTransformValue(val ?? this.props.value ?? this.props.defaultValue).toString()}, resolve)
47
66
  })
48
67
  }
49
68
 
69
+ componentDidUpdate(prevProps: Props) {
70
+ if (prevProps.value !== this.props.value && this.props.value !== undefined) {
71
+ this.setState({ value: this.invTransformValue(this.props.value).toString() });
72
+ }
73
+ }
50
74
  public render() {
51
75
  const {value} = this.state;
52
- const props2: HTMLInputProps & NumericInputProps & { onChange2?: (v: number, last?: boolean) => void } = {...this.props, leftIcon: undefined}
53
- if (props2.onChange2) delete props2.onChange2
76
+ const {
77
+ invTransformValue,
78
+ transformValue,
79
+ draggableIcon,
80
+ onChange2,
81
+ value: _value,
82
+ leftIcon,
83
+ defaultValue,
84
+ ...props2
85
+ } = this.props;
86
+
87
+ if(transformValue && !invTransformValue ||
88
+ !transformValue && invTransformValue) {
89
+ console.error('ExtendedNumericInput: Both transformValue and invTransformValue must be provided or neither. This is to ensure that the value can be transformed back and forth correctly.');
90
+ }
91
+
92
+ if(transformValue){
93
+ if(props2.min !== undefined) props2.min = this.invTransformValue(props2.min);
94
+ if(props2.max !== undefined) props2.max = this.invTransformValue(props2.max);
95
+ if(props2.stepSize !== undefined) props2.stepSize = this.invTransformValue(props2.stepSize);
96
+ if(props2.minorStepSize /*!== undefined*/) props2.minorStepSize = this.invTransformValue(props2.minorStepSize);
97
+ if(props2.majorStepSize /*!== undefined*/) props2.majorStepSize = this.invTransformValue(props2.majorStepSize);
98
+ }
54
99
 
55
100
  return (
56
101
  <NumericInput
57
102
  {...props2}
58
- leftElement={(
59
- <DraggableIcon icon={this.props.leftIcon ?? "variable"}
103
+ leftElement={( // props2.leftElement could be null
104
+ props2.leftElement !== undefined ? props2.leftElement :
105
+ draggableIcon !== false ? <DraggableIcon icon={leftIcon ?? "variable"}
60
106
  size={16}
61
- disabled={this.props.readOnly}
62
- small={this.props.small}
107
+ disabled={props2.readOnly}
108
+ small={props2.small}
63
109
  value={parseFloat(value ?? '0')}
64
- stepSize={this.props.stepSize}
110
+ stepSize={props2.stepSize}
65
111
  onChange={(v, last) => {
66
112
  this.handleValueChange(v, v.toString(), null, last, true)
67
- }}/>
113
+ }}/> : undefined
68
114
  )}
69
115
  // leftIcon={"variable"}
70
- buttonPosition={this.props.buttonPosition ?? (this.props.disabled ? "none" : "right")}
116
+ buttonPosition={props2.buttonPosition ?? (props2.disabled ? "none" : "right")}
71
117
  allowNumericCharactersOnly={false}
118
+ clampValueOnBlur={true}
72
119
  onBlur={this.handleBlur}
73
120
  onKeyDown={this.handleKeyDown}
74
121
  onButtonClick={this.handleButtonClick}
@@ -108,9 +155,11 @@ export class ExtendedNumericInput extends React.PureComponent<HTMLInputProps & N
108
155
  private handleValueChange = (_valueAsNumber: number, valueAsString: string, inputElement: HTMLInputElement | null, last?: boolean, dispatchOnChange2 = false) => {
109
156
  this._lastChangedValue = [_valueAsNumber, valueAsString]
110
157
  this.setState({value: valueAsString}, () => {
111
- this.props.onValueChange?.(_valueAsNumber, valueAsString, inputElement)
112
- if(dispatchOnChange2)
113
- this.props.onChange2?.(_valueAsNumber, last)
158
+ const transformed = this.transformValue(_valueAsNumber)
159
+ this.props.onValueChange?.(transformed, valueAsString, inputElement)
160
+ if(dispatchOnChange2) {
161
+ this.props.onChange2?.(transformed, last)
162
+ }
114
163
  });
115
164
  };
116
165
 
@@ -125,8 +174,10 @@ export class ExtendedNumericInput extends React.PureComponent<HTMLInputProps & N
125
174
  result = this.evaluateSimpleMathExpression(result);
126
175
  result = this.nanStringToEmptyString(result);
127
176
  this.setState({value: result}, () => {
128
- this.props.onValueChange?.(parseFloat(result) || 0, result, null)
129
- this.props.onChange2?.(parseFloat(result) || 0)
177
+ const _valueAsNumber = parseFloat(result) || 0;
178
+ const transformed = this.transformValue(_valueAsNumber)
179
+ this.props.onValueChange?.(transformed, result, null)
180
+ this.props.onChange2?.(transformed, true)
130
181
  });
131
182
 
132
183
  // the user could have typed a different expression that evaluates to
@@ -152,7 +203,7 @@ export class ExtendedNumericInput extends React.PureComponent<HTMLInputProps & N
152
203
  };
153
204
 
154
205
  // Adapted from http://stackoverflow.com/questions/2276021/evaluating-a-string-as-a-mathematical-expression-in-javascript
155
- // maybe try a better solution from above, right now it only works left to right
206
+ // todo - use a proper parser and evaluator, right now it only works left to right
156
207
  private evaluateSimpleMathExpression = (value: string) => {
157
208
  // leave empty strings empty
158
209
  if (!value) {