tgui-core 1.0.2 → 1.0.3

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 (158) hide show
  1. package/{src/components → components}/AnimatedNumber.tsx +185 -185
  2. package/{src/components → components}/BlockQuote.tsx +15 -15
  3. package/{src/components → components}/BodyZoneSelector.tsx +149 -149
  4. package/{src/components → components}/Box.tsx +255 -255
  5. package/{src/components → components}/Button.tsx +415 -415
  6. package/{src/components → components}/ByondUi.jsx +121 -121
  7. package/{src/components → components}/Chart.tsx +160 -160
  8. package/{src/components → components}/ColorBox.tsx +30 -30
  9. package/{src/components → components}/Dimmer.tsx +19 -19
  10. package/{src/components → components}/Divider.tsx +26 -26
  11. package/{src/components → components}/DmIcon.tsx +72 -72
  12. package/{src/components → components}/DraggableControl.jsx +282 -282
  13. package/{src/components → components}/Dropdown.tsx +246 -246
  14. package/{src/components → components}/Flex.tsx +105 -105
  15. package/{src/components → components}/Icon.tsx +91 -91
  16. package/{src/components → components}/Input.tsx +181 -181
  17. package/{src/components → components}/KeyListener.tsx +40 -40
  18. package/{src/components → components}/Knob.tsx +185 -185
  19. package/{src/components → components}/LabeledList.tsx +130 -130
  20. package/{src/components → components}/MenuBar.tsx +233 -238
  21. package/{src/components → components}/Modal.tsx +25 -25
  22. package/{src/components → components}/NoticeBox.tsx +48 -48
  23. package/{src/components → components}/NumberInput.tsx +328 -328
  24. package/{src/components → components}/ProgressBar.tsx +79 -79
  25. package/{src/components → components}/RestrictedInput.jsx +301 -301
  26. package/{src/components → components}/RoundGauge.tsx +189 -189
  27. package/{src/components → components}/Section.tsx +125 -125
  28. package/{src/components → components}/Slider.tsx +173 -173
  29. package/{src/components → components}/Stack.tsx +101 -101
  30. package/{src/components → components}/Table.tsx +90 -90
  31. package/{src/components → components}/Tabs.tsx +90 -90
  32. package/{src/components → components}/TextArea.tsx +198 -198
  33. package/{src/components → components}/TimeDisplay.jsx +64 -64
  34. package/components/index.ts +51 -0
  35. package/{src/debug/KitchenSink.jsx → debug/KitchenSink.tsx} +56 -56
  36. package/{src/debug/actions.js → debug/actions.ts} +11 -11
  37. package/{src/debug/hooks.js → debug/hooks.ts} +10 -10
  38. package/{src/debug/middleware.js → debug/middleware.ts} +86 -86
  39. package/{src/debug/reducer.js → debug/reducer.ts} +27 -22
  40. package/{src/debug/selectors.js → debug/selectors.ts} +7 -7
  41. package/{src/layouts → layouts}/Layout.tsx +75 -75
  42. package/{src/layouts → layouts}/NtosWindow.tsx +162 -162
  43. package/{src/layouts → layouts}/Pane.tsx +56 -56
  44. package/{src/layouts → layouts}/Window.tsx +227 -227
  45. package/layouts/index.ts +10 -0
  46. package/package.json +3 -2
  47. package/src/assets.ts +43 -43
  48. package/src/backend.ts +369 -369
  49. package/src/drag.ts +280 -280
  50. package/src/events.ts +237 -237
  51. package/src/hotkeys.ts +212 -212
  52. package/src/renderer.ts +50 -50
  53. package/stories/Blink.stories.tsx +20 -0
  54. package/stories/BlockQuote.stories.tsx +23 -0
  55. package/stories/Box.stories.tsx +27 -0
  56. package/stories/Button.stories.tsx +68 -0
  57. package/stories/ByondUi.stories.tsx +45 -0
  58. package/stories/Collapsible.stories.tsx +23 -0
  59. package/stories/Flex.stories.tsx +68 -0
  60. package/stories/Input.stories.tsx +124 -0
  61. package/stories/LabeledList.stories.tsx +73 -0
  62. package/stories/Popper.stories.tsx +58 -0
  63. package/stories/ProgressBar.stories.tsx +58 -0
  64. package/stories/Stack.stories.tsx +55 -0
  65. package/stories/Storage.stories.tsx +46 -0
  66. package/stories/Themes.stories.tsx +30 -0
  67. package/stories/Tooltip.stories.tsx +48 -0
  68. package/stories/common.tsx +19 -0
  69. package/tsconfig.json +0 -21
  70. package/src/components/Grid.tsx +0 -44
  71. /package/{src/common → common}/collections.ts +0 -0
  72. /package/{src/common → common}/color.ts +0 -0
  73. /package/{src/common → common}/events.ts +0 -0
  74. /package/{src/common → common}/exhaustive.ts +0 -0
  75. /package/{src/common → common}/fp.ts +0 -0
  76. /package/{src/common → common}/keycodes.ts +0 -0
  77. /package/{src/common → common}/keys.ts +0 -0
  78. /package/{src/common → common}/math.ts +0 -0
  79. /package/{src/common → common}/perf.ts +0 -0
  80. /package/{src/common → common}/random.ts +0 -0
  81. /package/{src/common → common}/react.ts +0 -0
  82. /package/{src/common → common}/redux.ts +0 -0
  83. /package/{src/common → common}/storage.js +0 -0
  84. /package/{src/common → common}/string.ts +0 -0
  85. /package/{src/common → common}/timer.ts +0 -0
  86. /package/{src/common → common}/type-utils.ts +0 -0
  87. /package/{src/common → common}/types.ts +0 -0
  88. /package/{src/common → common}/uuid.ts +0 -0
  89. /package/{src/common → common}/vector.ts +0 -0
  90. /package/{src/components → components}/Autofocus.tsx +0 -0
  91. /package/{src/components → components}/Blink.jsx +0 -0
  92. /package/{src/components → components}/Collapsible.tsx +0 -0
  93. /package/{src/components → components}/Dialog.tsx +0 -0
  94. /package/{src/components → components}/FakeTerminal.jsx +0 -0
  95. /package/{src/components → components}/FitText.tsx +0 -0
  96. /package/{src/components → components}/Image.tsx +0 -0
  97. /package/{src/components → components}/InfinitePlane.jsx +0 -0
  98. /package/{src/components → components}/LabeledControls.tsx +0 -0
  99. /package/{src/components → components}/Popper.tsx +0 -0
  100. /package/{src/components → components}/StyleableSection.tsx +0 -0
  101. /package/{src/components → components}/Tooltip.tsx +0 -0
  102. /package/{src/components → components}/TrackOutsideClicks.tsx +0 -0
  103. /package/{src/components → components}/VirtualList.tsx +0 -0
  104. /package/{src/debug → debug}/index.ts +0 -0
  105. /package/{src/styles → styles}/base.scss +0 -0
  106. /package/{src/styles → styles}/colors.scss +0 -0
  107. /package/{src/styles → styles}/components/BlockQuote.scss +0 -0
  108. /package/{src/styles → styles}/components/Button.scss +0 -0
  109. /package/{src/styles → styles}/components/ColorBox.scss +0 -0
  110. /package/{src/styles → styles}/components/Dialog.scss +0 -0
  111. /package/{src/styles → styles}/components/Dimmer.scss +0 -0
  112. /package/{src/styles → styles}/components/Divider.scss +0 -0
  113. /package/{src/styles → styles}/components/Dropdown.scss +0 -0
  114. /package/{src/styles → styles}/components/Flex.scss +0 -0
  115. /package/{src/styles → styles}/components/Icon.scss +0 -0
  116. /package/{src/styles → styles}/components/Input.scss +0 -0
  117. /package/{src/styles → styles}/components/Knob.scss +0 -0
  118. /package/{src/styles → styles}/components/LabeledList.scss +0 -0
  119. /package/{src/styles → styles}/components/MenuBar.scss +0 -0
  120. /package/{src/styles → styles}/components/Modal.scss +0 -0
  121. /package/{src/styles → styles}/components/NoticeBox.scss +0 -0
  122. /package/{src/styles → styles}/components/NumberInput.scss +0 -0
  123. /package/{src/styles → styles}/components/ProgressBar.scss +0 -0
  124. /package/{src/styles → styles}/components/RoundGauge.scss +0 -0
  125. /package/{src/styles → styles}/components/Section.scss +0 -0
  126. /package/{src/styles → styles}/components/Slider.scss +0 -0
  127. /package/{src/styles → styles}/components/Stack.scss +0 -0
  128. /package/{src/styles → styles}/components/Table.scss +0 -0
  129. /package/{src/styles → styles}/components/Tabs.scss +0 -0
  130. /package/{src/styles → styles}/components/TextArea.scss +0 -0
  131. /package/{src/styles → styles}/components/Tooltip.scss +0 -0
  132. /package/{src/styles → styles}/functions.scss +0 -0
  133. /package/{src/styles → styles}/layouts/Layout.scss +0 -0
  134. /package/{src/styles → styles}/layouts/NtosHeader.scss +0 -0
  135. /package/{src/styles → styles}/layouts/NtosWindow.scss +0 -0
  136. /package/{src/styles → styles}/layouts/TitleBar.scss +0 -0
  137. /package/{src/styles → styles}/layouts/Window.scss +0 -0
  138. /package/{src/styles → styles}/main.scss +0 -0
  139. /package/{src/styles → styles}/reset.scss +0 -0
  140. /package/{src/styles → styles}/themes/abductor.scss +0 -0
  141. /package/{src/styles → styles}/themes/admin.scss +0 -0
  142. /package/{src/styles → styles}/themes/cardtable.scss +0 -0
  143. /package/{src/styles → styles}/themes/hackerman.scss +0 -0
  144. /package/{src/styles → styles}/themes/malfunction.scss +0 -0
  145. /package/{src/styles → styles}/themes/neutral.scss +0 -0
  146. /package/{src/styles → styles}/themes/ntOS95.scss +0 -0
  147. /package/{src/styles → styles}/themes/ntos.scss +0 -0
  148. /package/{src/styles → styles}/themes/ntos_cat.scss +0 -0
  149. /package/{src/styles → styles}/themes/ntos_darkmode.scss +0 -0
  150. /package/{src/styles → styles}/themes/ntos_lightmode.scss +0 -0
  151. /package/{src/styles → styles}/themes/ntos_spooky.scss +0 -0
  152. /package/{src/styles → styles}/themes/ntos_synth.scss +0 -0
  153. /package/{src/styles → styles}/themes/ntos_terminal.scss +0 -0
  154. /package/{src/styles → styles}/themes/paper.scss +0 -0
  155. /package/{src/styles → styles}/themes/retro.scss +0 -0
  156. /package/{src/styles → styles}/themes/spookyconsole.scss +0 -0
  157. /package/{src/styles → styles}/themes/syndicate.scss +0 -0
  158. /package/{src/styles → styles}/themes/wizard.scss +0 -0
@@ -1,282 +1,282 @@
1
- /**
2
- * @file
3
- * @copyright 2020 Aleksej Komarov
4
- * @license MIT
5
- */
6
-
7
- import { clamp } from '../common/math';
8
- import { Component, createRef } from 'react';
9
-
10
- import { AnimatedNumber } from './AnimatedNumber';
11
-
12
- const DEFAULT_UPDATE_RATE = 400;
13
-
14
- /**
15
- * Reduces screen offset to a single number based on the matrix provided.
16
- */
17
- const getScalarScreenOffset = (e, matrix) => {
18
- return e.screenX * matrix[0] + e.screenY * matrix[1];
19
- };
20
-
21
- export class DraggableControl extends Component {
22
- constructor(props) {
23
- super(props);
24
- this.inputRef = createRef();
25
- this.state = {
26
- value: props.value,
27
- dragging: false,
28
- editing: false,
29
- internalValue: null,
30
- origin: null,
31
- suppressingFlicker: false,
32
- };
33
-
34
- // Suppresses flickering while the value propagates through the backend
35
- this.flickerTimer = null;
36
- this.suppressFlicker = () => {
37
- const { suppressFlicker } = this.props;
38
- if (suppressFlicker > 0) {
39
- this.setState({
40
- suppressingFlicker: true,
41
- });
42
- clearTimeout(this.flickerTimer);
43
- this.flickerTimer = setTimeout(() => {
44
- this.setState({
45
- suppressingFlicker: false,
46
- });
47
- }, suppressFlicker);
48
- }
49
- };
50
-
51
- this.handleDragStart = (e) => {
52
- const { value, dragMatrix } = this.props;
53
- const { editing } = this.state;
54
- if (editing) {
55
- return;
56
- }
57
- document.body.style['pointer-events'] = 'none';
58
- this.ref = e.target;
59
- this.setState({
60
- dragging: false,
61
- origin: getScalarScreenOffset(e, dragMatrix),
62
- value,
63
- internalValue: value,
64
- });
65
- this.timer = setTimeout(() => {
66
- this.setState({
67
- dragging: true,
68
- });
69
- }, 250);
70
- this.dragInterval = setInterval(() => {
71
- const { dragging, value } = this.state;
72
- const { onDrag } = this.props;
73
- if (dragging && onDrag) {
74
- onDrag(e, value);
75
- }
76
- }, this.props.updateRate || DEFAULT_UPDATE_RATE);
77
- document.addEventListener('mousemove', this.handleDragMove);
78
- document.addEventListener('mouseup', this.handleDragEnd);
79
- };
80
-
81
- this.handleDragMove = (e) => {
82
- const { minValue, maxValue, step, stepPixelSize, dragMatrix } =
83
- this.props;
84
- this.setState((prevState) => {
85
- const state = { ...prevState };
86
- const offset = getScalarScreenOffset(e, dragMatrix) - state.origin;
87
- if (prevState.dragging) {
88
- const stepOffset = Number.isFinite(minValue) ? minValue % step : 0;
89
- // Translate mouse movement to value
90
- // Give it some headroom (by increasing clamp range by 1 step)
91
- state.internalValue = clamp(
92
- state.internalValue + (offset * step) / stepPixelSize,
93
- minValue - step,
94
- maxValue + step
95
- );
96
- // Clamp the final value
97
- state.value = clamp(
98
- state.internalValue - (state.internalValue % step) + stepOffset,
99
- minValue,
100
- maxValue
101
- );
102
- state.origin = getScalarScreenOffset(e, dragMatrix);
103
- } else if (Math.abs(offset) > 4) {
104
- state.dragging = true;
105
- }
106
- return state;
107
- });
108
- };
109
-
110
- this.handleDragEnd = (e) => {
111
- const { onChange, onDrag } = this.props;
112
- const { dragging, value, internalValue } = this.state;
113
- document.body.style['pointer-events'] = 'auto';
114
- clearTimeout(this.timer);
115
- clearInterval(this.dragInterval);
116
- this.setState({
117
- dragging: false,
118
- editing: !dragging,
119
- origin: null,
120
- });
121
- document.removeEventListener('mousemove', this.handleDragMove);
122
- document.removeEventListener('mouseup', this.handleDragEnd);
123
- if (dragging) {
124
- this.suppressFlicker();
125
- if (onChange) {
126
- onChange(e, value);
127
- }
128
- if (onDrag) {
129
- onDrag(e, value);
130
- }
131
- } else if (this.inputRef) {
132
- const input = this.inputRef.current;
133
- input.value = internalValue;
134
- // IE8: Dies when trying to focus a hidden element
135
- // (Error: Object does not support this action)
136
- try {
137
- input.focus();
138
- input.select();
139
- } catch {}
140
- }
141
- };
142
- }
143
-
144
- render() {
145
- const {
146
- dragging,
147
- editing,
148
- value: intermediateValue,
149
- suppressingFlicker,
150
- } = this.state;
151
- const {
152
- animated,
153
- value,
154
- unit,
155
- minValue,
156
- maxValue,
157
- unclamped,
158
- format,
159
- onChange,
160
- onDrag,
161
- children,
162
- // Input props
163
- height,
164
- lineHeight,
165
- fontSize,
166
- } = this.props;
167
- let displayValue = value;
168
- if (dragging || suppressingFlicker) {
169
- displayValue = intermediateValue;
170
- }
171
-
172
- const displayElement = (
173
- <>
174
- {animated && !dragging && !suppressingFlicker ? (
175
- <AnimatedNumber value={displayValue} format={format} />
176
- ) : format ? (
177
- format(displayValue)
178
- ) : (
179
- displayValue
180
- )}
181
-
182
- {unit ? ' ' + unit : ''}
183
- </>
184
- );
185
-
186
- // Setup an input element
187
- // Handles direct input via the keyboard
188
- const inputElement = (
189
- <input
190
- ref={this.inputRef}
191
- className="NumberInput__input"
192
- style={{
193
- display: !editing ? 'none' : undefined,
194
- height: height,
195
- lineHeight: lineHeight,
196
- fontsize: fontSize,
197
- }}
198
- onBlur={(e) => {
199
- if (!editing) {
200
- return;
201
- }
202
- let value;
203
- if (unclamped) {
204
- value = parseFloat(e.target.value);
205
- } else {
206
- value = clamp(parseFloat(e.target.value), minValue, maxValue);
207
- }
208
- if (Number.isNaN(value)) {
209
- this.setState({
210
- editing: false,
211
- });
212
- return;
213
- }
214
- this.setState({
215
- editing: false,
216
- value,
217
- });
218
- this.suppressFlicker();
219
- if (onChange) {
220
- onChange(e, value);
221
- }
222
- if (onDrag) {
223
- onDrag(e, value);
224
- }
225
- }}
226
- onKeyDown={(e) => {
227
- if (e.keyCode === 13) {
228
- let value;
229
- if (unclamped) {
230
- value = parseFloat(e.target.value);
231
- } else {
232
- value = clamp(parseFloat(e.target.value), minValue, maxValue);
233
- }
234
- if (Number.isNaN(value)) {
235
- this.setState({
236
- editing: false,
237
- });
238
- return;
239
- }
240
- this.setState({
241
- editing: false,
242
- value,
243
- });
244
- this.suppressFlicker();
245
- if (onChange) {
246
- onChange(e, value);
247
- }
248
- if (onDrag) {
249
- onDrag(e, value);
250
- }
251
- return;
252
- }
253
- if (e.keyCode === 27) {
254
- this.setState({
255
- editing: false,
256
- });
257
- return;
258
- }
259
- }}
260
- />
261
- );
262
- // Return a part of the state for higher-level components to use.
263
- return children({
264
- dragging,
265
- editing,
266
- value,
267
- displayValue,
268
- displayElement,
269
- inputElement,
270
- handleDragStart: this.handleDragStart,
271
- });
272
- }
273
- }
274
-
275
- DraggableControl.defaultProps = {
276
- minValue: -Infinity,
277
- maxValue: +Infinity,
278
- step: 1,
279
- stepPixelSize: 1,
280
- suppressFlicker: 50,
281
- dragMatrix: [1, 0],
282
- };
1
+ /**
2
+ * @file
3
+ * @copyright 2020 Aleksej Komarov
4
+ * @license MIT
5
+ */
6
+
7
+ import { clamp } from '../common/math';
8
+ import { Component, createRef } from 'react';
9
+
10
+ import { AnimatedNumber } from './AnimatedNumber';
11
+
12
+ const DEFAULT_UPDATE_RATE = 400;
13
+
14
+ /**
15
+ * Reduces screen offset to a single number based on the matrix provided.
16
+ */
17
+ const getScalarScreenOffset = (e, matrix) => {
18
+ return e.screenX * matrix[0] + e.screenY * matrix[1];
19
+ };
20
+
21
+ export class DraggableControl extends Component {
22
+ constructor(props) {
23
+ super(props);
24
+ this.inputRef = createRef();
25
+ this.state = {
26
+ value: props.value,
27
+ dragging: false,
28
+ editing: false,
29
+ internalValue: null,
30
+ origin: null,
31
+ suppressingFlicker: false,
32
+ };
33
+
34
+ // Suppresses flickering while the value propagates through the backend
35
+ this.flickerTimer = null;
36
+ this.suppressFlicker = () => {
37
+ const { suppressFlicker } = this.props;
38
+ if (suppressFlicker > 0) {
39
+ this.setState({
40
+ suppressingFlicker: true,
41
+ });
42
+ clearTimeout(this.flickerTimer);
43
+ this.flickerTimer = setTimeout(() => {
44
+ this.setState({
45
+ suppressingFlicker: false,
46
+ });
47
+ }, suppressFlicker);
48
+ }
49
+ };
50
+
51
+ this.handleDragStart = (e) => {
52
+ const { value, dragMatrix } = this.props;
53
+ const { editing } = this.state;
54
+ if (editing) {
55
+ return;
56
+ }
57
+ document.body.style['pointer-events'] = 'none';
58
+ this.ref = e.target;
59
+ this.setState({
60
+ dragging: false,
61
+ origin: getScalarScreenOffset(e, dragMatrix),
62
+ value,
63
+ internalValue: value,
64
+ });
65
+ this.timer = setTimeout(() => {
66
+ this.setState({
67
+ dragging: true,
68
+ });
69
+ }, 250);
70
+ this.dragInterval = setInterval(() => {
71
+ const { dragging, value } = this.state;
72
+ const { onDrag } = this.props;
73
+ if (dragging && onDrag) {
74
+ onDrag(e, value);
75
+ }
76
+ }, this.props.updateRate || DEFAULT_UPDATE_RATE);
77
+ document.addEventListener('mousemove', this.handleDragMove);
78
+ document.addEventListener('mouseup', this.handleDragEnd);
79
+ };
80
+
81
+ this.handleDragMove = (e) => {
82
+ const { minValue, maxValue, step, stepPixelSize, dragMatrix } =
83
+ this.props;
84
+ this.setState((prevState) => {
85
+ const state = { ...prevState };
86
+ const offset = getScalarScreenOffset(e, dragMatrix) - state.origin;
87
+ if (prevState.dragging) {
88
+ const stepOffset = Number.isFinite(minValue) ? minValue % step : 0;
89
+ // Translate mouse movement to value
90
+ // Give it some headroom (by increasing clamp range by 1 step)
91
+ state.internalValue = clamp(
92
+ state.internalValue + (offset * step) / stepPixelSize,
93
+ minValue - step,
94
+ maxValue + step
95
+ );
96
+ // Clamp the final value
97
+ state.value = clamp(
98
+ state.internalValue - (state.internalValue % step) + stepOffset,
99
+ minValue,
100
+ maxValue
101
+ );
102
+ state.origin = getScalarScreenOffset(e, dragMatrix);
103
+ } else if (Math.abs(offset) > 4) {
104
+ state.dragging = true;
105
+ }
106
+ return state;
107
+ });
108
+ };
109
+
110
+ this.handleDragEnd = (e) => {
111
+ const { onChange, onDrag } = this.props;
112
+ const { dragging, value, internalValue } = this.state;
113
+ document.body.style['pointer-events'] = 'auto';
114
+ clearTimeout(this.timer);
115
+ clearInterval(this.dragInterval);
116
+ this.setState({
117
+ dragging: false,
118
+ editing: !dragging,
119
+ origin: null,
120
+ });
121
+ document.removeEventListener('mousemove', this.handleDragMove);
122
+ document.removeEventListener('mouseup', this.handleDragEnd);
123
+ if (dragging) {
124
+ this.suppressFlicker();
125
+ if (onChange) {
126
+ onChange(e, value);
127
+ }
128
+ if (onDrag) {
129
+ onDrag(e, value);
130
+ }
131
+ } else if (this.inputRef) {
132
+ const input = this.inputRef.current;
133
+ input.value = internalValue;
134
+ // IE8: Dies when trying to focus a hidden element
135
+ // (Error: Object does not support this action)
136
+ try {
137
+ input.focus();
138
+ input.select();
139
+ } catch {}
140
+ }
141
+ };
142
+ }
143
+
144
+ render() {
145
+ const {
146
+ dragging,
147
+ editing,
148
+ value: intermediateValue,
149
+ suppressingFlicker,
150
+ } = this.state;
151
+ const {
152
+ animated,
153
+ value,
154
+ unit,
155
+ minValue,
156
+ maxValue,
157
+ unclamped,
158
+ format,
159
+ onChange,
160
+ onDrag,
161
+ children,
162
+ // Input props
163
+ height,
164
+ lineHeight,
165
+ fontSize,
166
+ } = this.props;
167
+ let displayValue = value;
168
+ if (dragging || suppressingFlicker) {
169
+ displayValue = intermediateValue;
170
+ }
171
+
172
+ const displayElement = (
173
+ <>
174
+ {animated && !dragging && !suppressingFlicker ? (
175
+ <AnimatedNumber value={displayValue} format={format} />
176
+ ) : format ? (
177
+ format(displayValue)
178
+ ) : (
179
+ displayValue
180
+ )}
181
+
182
+ {unit ? ' ' + unit : ''}
183
+ </>
184
+ );
185
+
186
+ // Setup an input element
187
+ // Handles direct input via the keyboard
188
+ const inputElement = (
189
+ <input
190
+ ref={this.inputRef}
191
+ className="NumberInput__input"
192
+ style={{
193
+ display: !editing ? 'none' : undefined,
194
+ height: height,
195
+ lineHeight: lineHeight,
196
+ fontsize: fontSize,
197
+ }}
198
+ onBlur={(e) => {
199
+ if (!editing) {
200
+ return;
201
+ }
202
+ let value;
203
+ if (unclamped) {
204
+ value = parseFloat(e.target.value);
205
+ } else {
206
+ value = clamp(parseFloat(e.target.value), minValue, maxValue);
207
+ }
208
+ if (Number.isNaN(value)) {
209
+ this.setState({
210
+ editing: false,
211
+ });
212
+ return;
213
+ }
214
+ this.setState({
215
+ editing: false,
216
+ value,
217
+ });
218
+ this.suppressFlicker();
219
+ if (onChange) {
220
+ onChange(e, value);
221
+ }
222
+ if (onDrag) {
223
+ onDrag(e, value);
224
+ }
225
+ }}
226
+ onKeyDown={(e) => {
227
+ if (e.keyCode === 13) {
228
+ let value;
229
+ if (unclamped) {
230
+ value = parseFloat(e.target.value);
231
+ } else {
232
+ value = clamp(parseFloat(e.target.value), minValue, maxValue);
233
+ }
234
+ if (Number.isNaN(value)) {
235
+ this.setState({
236
+ editing: false,
237
+ });
238
+ return;
239
+ }
240
+ this.setState({
241
+ editing: false,
242
+ value,
243
+ });
244
+ this.suppressFlicker();
245
+ if (onChange) {
246
+ onChange(e, value);
247
+ }
248
+ if (onDrag) {
249
+ onDrag(e, value);
250
+ }
251
+ return;
252
+ }
253
+ if (e.keyCode === 27) {
254
+ this.setState({
255
+ editing: false,
256
+ });
257
+ return;
258
+ }
259
+ }}
260
+ />
261
+ );
262
+ // Return a part of the state for higher-level components to use.
263
+ return children({
264
+ dragging,
265
+ editing,
266
+ value,
267
+ displayValue,
268
+ displayElement,
269
+ inputElement,
270
+ handleDragStart: this.handleDragStart,
271
+ });
272
+ }
273
+ }
274
+
275
+ DraggableControl.defaultProps = {
276
+ minValue: -Infinity,
277
+ maxValue: +Infinity,
278
+ step: 1,
279
+ stepPixelSize: 1,
280
+ suppressFlicker: 50,
281
+ dragMatrix: [1, 0],
282
+ };