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.
- package/dist/ConfigObject.d.ts +2 -1
- package/dist/{allPaths-BOo4cECg.js → allPaths-C4QHVET-.js} +5 -5
- package/dist/{allPaths-BOo4cECg.js.map → allPaths-C4QHVET-.js.map} +1 -1
- package/dist/{allPathsLoader-B4vYL2gG.js → allPathsLoader-Dm-MlOxQ.js} +4 -4
- package/dist/{allPathsLoader-B4vYL2gG.js.map → allPathsLoader-Dm-MlOxQ.js.map} +1 -1
- package/dist/bpComponents/BPContainerComponent.d.ts +1 -1
- package/dist/bpComponents/BPNumberInputComponent.d.ts +3 -1
- package/dist/bpComponents/BPSliderInputComponent.d.ts +1 -0
- package/dist/bpComponents/BPTreeComponent.d.ts +1 -1
- package/dist/bpComponents/BPVectorInputComponent.d.ts +1 -0
- package/dist/bpComponents/GetNumberTransformFunctions.d.ts +4 -0
- package/dist/bpComponents/NumberUnits.d.ts +7 -0
- package/dist/components/ExtendedNumericInput.d.ts +13 -3
- package/dist/components/NumericInput.d.ts +79 -0
- package/dist/components/bpIconWrapper.d.ts +1 -1
- package/dist/{index-13b-jSvJ.js → index-2Z2Mq97s.js} +4907 -4700
- package/dist/index-2Z2Mq97s.js.map +1 -0
- package/dist/{index-B0IO--x7.js → index-BKXNXgJi.js} +2 -2
- package/dist/{index-B0IO--x7.js.map → index-BKXNXgJi.js.map} +1 -1
- package/dist/{index-BttMe1vP.js → index-BVSBMJ4w.js} +2 -2
- package/dist/{index-BttMe1vP.js.map → index-BVSBMJ4w.js.map} +1 -1
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/lib.d.ts +3 -0
- package/dist/{splitPathsBySizeLoader-nUv2DYaP.js → splitPathsBySizeLoader-CJaJimKZ.js} +5 -5
- package/dist/{splitPathsBySizeLoader-nUv2DYaP.js.map → splitPathsBySizeLoader-CJaJimKZ.js.map} +1 -1
- package/docs/classes/UI.html +3 -3
- package/docs/classes/UiConfigRendererBlueprint.html +3 -3
- package/lib/css/renderer.css +76 -1
- package/lib/css/renderer.css.map +1 -1
- package/lib/esm/ConfigObject.d.ts +2 -1
- package/lib/esm/ConfigObject.js +5 -4
- package/lib/esm/ConfigObject.js.map +1 -1
- package/lib/esm/bpComponents/BPContainerComponent.d.ts +1 -1
- package/lib/esm/bpComponents/BPContainerComponent.js +11 -1
- package/lib/esm/bpComponents/BPContainerComponent.js.map +1 -1
- package/lib/esm/bpComponents/BPFolderComponent.js +2 -2
- package/lib/esm/bpComponents/BPFolderComponent.js.map +1 -1
- package/lib/esm/bpComponents/BPNumberInputComponent.d.ts +3 -1
- package/lib/esm/bpComponents/BPNumberInputComponent.js +6 -1
- package/lib/esm/bpComponents/BPNumberInputComponent.js.map +1 -1
- package/lib/esm/bpComponents/BPSliderInputComponent.d.ts +1 -0
- package/lib/esm/bpComponents/BPSliderInputComponent.js +16 -15
- package/lib/esm/bpComponents/BPSliderInputComponent.js.map +1 -1
- package/lib/esm/bpComponents/BPTreeComponent.d.ts +1 -1
- package/lib/esm/bpComponents/BPTreeComponent.js +11 -7
- package/lib/esm/bpComponents/BPTreeComponent.js.map +1 -1
- package/lib/esm/bpComponents/BPVectorInputComponent.d.ts +1 -0
- package/lib/esm/bpComponents/BPVectorInputComponent.js +14 -8
- package/lib/esm/bpComponents/BPVectorInputComponent.js.map +1 -1
- package/lib/esm/bpComponents/GetNumberTransformFunctions.d.ts +4 -0
- package/lib/esm/bpComponents/GetNumberTransformFunctions.js +14 -0
- package/lib/esm/bpComponents/GetNumberTransformFunctions.js.map +1 -0
- package/lib/esm/bpComponents/NumberUnits.d.ts +7 -0
- package/lib/esm/bpComponents/NumberUnits.js +101 -0
- package/lib/esm/bpComponents/NumberUnits.js.map +1 -0
- package/lib/esm/components/DialogContext.js +12 -3
- package/lib/esm/components/DialogContext.js.map +1 -1
- package/lib/esm/components/ExtendedNumericInput.d.ts +13 -3
- package/lib/esm/components/ExtendedNumericInput.js +62 -17
- package/lib/esm/components/ExtendedNumericInput.js.map +1 -1
- package/lib/esm/components/NumericInput.d.ts +79 -0
- package/lib/esm/components/NumericInput.js +311 -0
- package/lib/esm/components/NumericInput.js.map +1 -0
- package/lib/esm/components/Tree2.js +2 -2
- package/lib/esm/components/Tree2.js.map +1 -1
- package/lib/esm/components/TreeNode2.js +2 -2
- package/lib/esm/components/TreeNode2.js.map +1 -1
- package/lib/esm/components/VisualStyleContext.js +7 -1
- package/lib/esm/components/VisualStyleContext.js.map +1 -1
- package/lib/esm/components/bpIconWrapper.d.ts +1 -1
- package/lib/esm/components/bpIconWrapper.js +2 -2
- package/lib/esm/components/bpIconWrapper.js.map +1 -1
- package/lib/esm/components/iconMapping.js +1 -1
- package/lib/esm/components/iconMapping.js.map +1 -1
- package/lib/esm/lib.d.ts +3 -0
- package/lib/esm/lib.js +3 -0
- package/lib/esm/lib.js.map +1 -1
- package/package.json +2 -2
- package/src/ConfigObject.tsx +8 -6
- package/src/bpComponents/BPButtonComponent.scss +3 -1
- package/src/bpComponents/BPContainerComponent.tsx +11 -0
- package/src/bpComponents/BPFolderComponent.tsx +2 -2
- package/src/bpComponents/BPNumberInputComponent.tsx +13 -2
- package/src/bpComponents/BPSliderInputComponent.tsx +37 -29
- package/src/bpComponents/BPTreeComponent.tsx +14 -8
- package/src/bpComponents/BPVectorInputComponent.tsx +23 -20
- package/src/bpComponents/GetNumberTransformFunctions.tsx +14 -0
- package/src/bpComponents/NumberUnits.tsx +123 -0
- package/src/components/DialogContext.tsx +16 -2
- package/src/components/ExtendedNumericInput.tsx +70 -19
- package/src/components/NumericInput.tsx +679 -0
- package/src/components/Tree2.tsx +3 -3
- package/src/components/TreeNode2.tsx +2 -2
- package/src/components/VisualStyleContext.tsx +8 -0
- package/src/components/bpIconWrapper.tsx +2 -2
- package/src/components/iconMapping.ts +1 -1
- package/src/components/tree2.scss +27 -0
- package/src/lib.ts +3 -0
- package/src/renderer.scss +19 -0
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}}
|
|
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 "
|
|
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<
|
|
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
|
|
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
|
|
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
|
-
|
|
53
|
-
|
|
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
|
-
|
|
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={
|
|
62
|
-
small={
|
|
107
|
+
disabled={props2.readOnly}
|
|
108
|
+
small={props2.small}
|
|
63
109
|
value={parseFloat(value ?? '0')}
|
|
64
|
-
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={
|
|
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.
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
129
|
-
this.
|
|
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
|
-
//
|
|
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) {
|