@onehat/ui 0.4.40 → 0.4.42
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/package.json +1 -1
- package/src/Components/Buttons/Button.js +6 -13
- package/src/Components/Buttons/ReloadButton.js +0 -1
- package/src/Components/Filter/DateRange.js +3 -1
- package/src/Components/Filter/NumberRange.js +4 -1
- package/src/Components/Form/Field/Checkbox/CheckboxGroup.js +11 -9
- package/src/Components/Form/Field/Combo/Combo.js +118 -83
- package/src/Components/Form/Field/Combo/PageSizeCombo.js +1 -0
- package/src/Components/Form/Field/Date.js +15 -2
- package/src/Components/Form/Field/Number.js +5 -6
- package/src/Components/Form/Field/RadioGroup/RadioGroup.js +11 -9
- package/src/Components/Form/Field/Select/PageSizeSelect.js +2 -1
- package/src/Components/Form/Field/Slider.js +186 -191
- package/src/Components/Form/Field/Tag/Tag.js +12 -10
- package/src/Components/Form/Field/TextArea.js +96 -98
- package/src/Components/Form/Form.js +12 -9
- package/src/Components/Grid/Grid.js +21 -22
- package/src/Components/Grid/GridRow.js +11 -12
- package/src/Components/Hoc/Secondary/withSecondarySelection.js +22 -7
- package/src/Components/Hoc/withEditor.js +60 -21
- package/src/Components/Hoc/withFilters.js +1 -1
- package/src/Components/Hoc/withMultiSelection.js +1 -2
- package/src/Components/Hoc/withPdfButtons.js +3 -0
- package/src/Components/Hoc/withSelection.js +63 -35
- package/src/Components/Hoc/withTooltip.js +7 -1
- package/src/Components/Toolbar/Pagination.js +56 -56
- package/src/Components/Toolbar/PaginationToolbar.js +18 -15
- package/src/Components/Toolbar/Toolbar.js +4 -7
- package/src/Components/Tooltip/Tooltip.js +13 -10
- package/src/Components/Tree/Tree.js +14 -10
- package/src/Components/Viewer/MeterTypeText.js +3 -3
- package/src/Constants/Styles.js +2 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { useState, useEffect, useRef, } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
HStack,
|
|
4
4
|
Text,
|
|
@@ -13,211 +13,206 @@ import Slider from '@react-native-community/slider'; // https://www.npmjs.com/pa
|
|
|
13
13
|
import UiGlobals from '../../../UiGlobals.js';
|
|
14
14
|
import testProps from '../../../Functions/testProps.js';
|
|
15
15
|
import withComponent from '../../Hoc/withComponent.js';
|
|
16
|
-
import withTooltip from '../../Hoc/withTooltip.js';
|
|
17
16
|
import withValue from '../../Hoc/withValue.js';
|
|
18
17
|
import _ from 'lodash';
|
|
19
18
|
|
|
20
19
|
const FAKE_ZERO = 0.0000000001; // Slider doesn't like zero
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
case 'Tab':
|
|
57
|
-
case 'Backspace':
|
|
58
|
-
return;
|
|
59
|
-
default:
|
|
60
|
-
}
|
|
61
|
-
if (!key.match(/^[\-\d\.]*$/)) {
|
|
62
|
-
e.preventDefault(); // kill anything that's not a number
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
onChangeText = (value) => {
|
|
66
|
-
if (!value || value === '') {
|
|
67
|
-
value = 0; // empty string makes value null
|
|
68
|
-
} else if (value.match(/\.$/)) { // value ends with a decimal point
|
|
69
|
-
// don't parseFloat, otherwise we'll lose the decimal point
|
|
70
|
-
} else if (value.match(/0$/)) { // value ends with a zero
|
|
71
|
-
// don't parseFloat, otherwise we'll lose the ability to do things like 1.03
|
|
72
|
-
} else {
|
|
73
|
-
value = parseFloat(value, 10);
|
|
74
|
-
}
|
|
75
|
-
if (value < minValue) {
|
|
76
|
-
value = minValue;
|
|
77
|
-
} else if (value > maxValue) {
|
|
78
|
-
value = maxValue;
|
|
79
|
-
}
|
|
80
|
-
setLocalValue(value);
|
|
81
|
-
debouncedSetValueRef.current(value);
|
|
82
|
-
},
|
|
83
|
-
onDecrement = () => {
|
|
84
|
-
let localValue = value;
|
|
85
|
-
if (minValue && localValue === minValue) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
if (!localValue) {
|
|
89
|
-
localValue = 0;
|
|
90
|
-
}
|
|
91
|
-
localValue = new Decimal(localValue).minus(step).toNumber();
|
|
92
|
-
if (minValue > localValue) {
|
|
93
|
-
localValue = minValue;
|
|
94
|
-
}
|
|
95
|
-
setValue(localValue);
|
|
96
|
-
},
|
|
97
|
-
onIncrement = () => {
|
|
98
|
-
let localValue = value;
|
|
99
|
-
if (maxValue && localValue === maxValue) {
|
|
21
|
+
function SliderElement(props) {
|
|
22
|
+
let {
|
|
23
|
+
value = 0,
|
|
24
|
+
setValue,
|
|
25
|
+
minValue = 0,
|
|
26
|
+
maxValue = 100,
|
|
27
|
+
step = 10,
|
|
28
|
+
autoSubmitDelay = UiGlobals.autoSubmitDelay,
|
|
29
|
+
minimizeForRow = false,
|
|
30
|
+
tooltip,
|
|
31
|
+
tooltipPlacement,
|
|
32
|
+
isDisabled = false,
|
|
33
|
+
testID,
|
|
34
|
+
} = props,
|
|
35
|
+
styles = UiGlobals.styles,
|
|
36
|
+
debouncedSetValueRef = useRef(),
|
|
37
|
+
[localValue, setLocalValue] = useState(value),
|
|
38
|
+
onInputKeyPress = (e) => {
|
|
39
|
+
const key = e.nativeEvent.key; // e.key works on web, but not mobile; so use e.nativeEvent.key which works on both
|
|
40
|
+
switch(key) {
|
|
41
|
+
case 'ArrowDown':
|
|
42
|
+
onDecrement();
|
|
43
|
+
break;
|
|
44
|
+
case 'ArrowUp':
|
|
45
|
+
onIncrement();
|
|
46
|
+
break;
|
|
47
|
+
case 'Enter':
|
|
48
|
+
debouncedSetValueRef.current?.cancel();
|
|
49
|
+
setValue(value);
|
|
50
|
+
break;
|
|
51
|
+
case 'ArrowLeft':
|
|
52
|
+
case 'ArrowRight':
|
|
53
|
+
case 'Tab':
|
|
54
|
+
case 'Backspace':
|
|
100
55
|
return;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
56
|
+
default:
|
|
57
|
+
}
|
|
58
|
+
if (!key.match(/^[\-\d\.]*$/)) {
|
|
59
|
+
e.preventDefault(); // kill anything that's not a number
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
onChangeText = (value) => {
|
|
63
|
+
if (!value || value === '') {
|
|
64
|
+
value = 0; // empty string makes value null
|
|
65
|
+
} else if (value.match(/\.$/)) { // value ends with a decimal point
|
|
66
|
+
// don't parseFloat, otherwise we'll lose the decimal point
|
|
67
|
+
} else if (value.match(/0$/)) { // value ends with a zero
|
|
68
|
+
// don't parseFloat, otherwise we'll lose the ability to do things like 1.03
|
|
69
|
+
} else {
|
|
70
|
+
value = parseFloat(value, 10);
|
|
71
|
+
}
|
|
72
|
+
if (value < minValue) {
|
|
73
|
+
value = minValue;
|
|
74
|
+
} else if (value > maxValue) {
|
|
75
|
+
value = maxValue;
|
|
76
|
+
}
|
|
77
|
+
setLocalValue(value);
|
|
78
|
+
debouncedSetValueRef.current(value);
|
|
79
|
+
},
|
|
80
|
+
onDecrement = () => {
|
|
81
|
+
let localValue = value;
|
|
82
|
+
if (minValue && localValue === minValue) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (!localValue) {
|
|
86
|
+
localValue = 0;
|
|
87
|
+
}
|
|
88
|
+
localValue = new Decimal(localValue).minus(step).toNumber();
|
|
89
|
+
if (minValue > localValue) {
|
|
90
|
+
localValue = minValue;
|
|
91
|
+
}
|
|
92
|
+
setValue(localValue);
|
|
93
|
+
},
|
|
94
|
+
onIncrement = () => {
|
|
95
|
+
let localValue = value;
|
|
96
|
+
if (maxValue && localValue === maxValue) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (!localValue) {
|
|
100
|
+
localValue = 0;
|
|
124
101
|
}
|
|
102
|
+
localValue = new Decimal(localValue).plus(step).toNumber();
|
|
103
|
+
if (maxValue < localValue) {
|
|
104
|
+
localValue = maxValue;
|
|
105
|
+
}
|
|
106
|
+
setValue(localValue);
|
|
107
|
+
};
|
|
125
108
|
|
|
126
|
-
|
|
109
|
+
useEffect(() => {
|
|
110
|
+
// Set up debounce fn
|
|
111
|
+
// Have to do this because otherwise, lodash tries to create a debounced version of the fn from only this render
|
|
112
|
+
debouncedSetValueRef.current?.cancel(); // Cancel any previous debounced fn
|
|
113
|
+
debouncedSetValueRef.current = _.debounce(setValue, autoSubmitDelay);
|
|
114
|
+
}, [setValue]);
|
|
127
115
|
|
|
128
|
-
|
|
116
|
+
useEffect(() => {
|
|
129
117
|
|
|
130
|
-
|
|
131
|
-
|
|
118
|
+
// Make local value conform to externally changed value
|
|
119
|
+
if (value !== localValue) {
|
|
120
|
+
setLocalValue(value);
|
|
132
121
|
}
|
|
133
122
|
|
|
134
|
-
|
|
135
|
-
sliderValue = 0; // If the value is null or undefined, force slider to use zero
|
|
136
|
-
}
|
|
123
|
+
}, [value]);
|
|
137
124
|
|
|
138
|
-
|
|
139
|
-
let inputValue = localValue;
|
|
140
|
-
if (_.isNumber(inputValue)) {
|
|
141
|
-
inputValue = '' + inputValue;
|
|
142
|
-
}
|
|
125
|
+
let sliderValue = value;
|
|
143
126
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
127
|
+
if (localValue === null || typeof localValue === 'undefined') {
|
|
128
|
+
localValue = ''; // If the value is null or undefined, don't let this be an uncontrolled input
|
|
129
|
+
}
|
|
148
130
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
131
|
+
if (sliderValue === null || typeof sliderValue === 'undefined') {
|
|
132
|
+
sliderValue = 0; // If the value is null or undefined, force slider to use zero
|
|
133
|
+
}
|
|
152
134
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
135
|
+
// convert localValue to string if necessary, because numbers work on web but not mobile; while strings work in both places
|
|
136
|
+
let inputValue = localValue;
|
|
137
|
+
if (_.isNumber(inputValue)) {
|
|
138
|
+
inputValue = '' + inputValue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const style = props.style || {};
|
|
142
|
+
if (!hasWidth(props) && !hasFlex(props)) {
|
|
143
|
+
style.flex = 1;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (sliderValue === 0) {
|
|
147
|
+
sliderValue = FAKE_ZERO; // Slider doesn't like zero
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let className = `
|
|
151
|
+
w-full
|
|
152
|
+
items-center
|
|
153
|
+
`,
|
|
154
|
+
inputClassName = `
|
|
155
|
+
Input
|
|
156
|
+
h-full
|
|
157
|
+
w-[60px]
|
|
158
|
+
mr-4
|
|
159
|
+
text-center
|
|
160
|
+
rounded-md
|
|
161
|
+
${styles.SLIDER_READOUT_FONTSIZE}
|
|
162
|
+
`;
|
|
163
|
+
if (props.className) {
|
|
164
|
+
className += ' ' + props.className;
|
|
165
|
+
}
|
|
166
|
+
if (minimizeForRow) {
|
|
167
|
+
inputClassName += ' h-auto min-h-0 max-h-[50px] mr-1';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return <HStack
|
|
171
|
+
className={className}
|
|
172
|
+
style={props.style}
|
|
173
|
+
>
|
|
174
|
+
<Input
|
|
175
|
+
{...testProps('readout')}
|
|
176
|
+
value={inputValue}
|
|
177
|
+
onChangeText={onChangeText}
|
|
178
|
+
onKeyPress={onInputKeyPress}
|
|
179
|
+
isDisabled={isDisabled}
|
|
180
|
+
disableAutoFlex={true}
|
|
181
|
+
className={inputClassName}
|
|
182
|
+
textAlignIsCenter={true}
|
|
183
|
+
tooltip={tooltip}
|
|
184
|
+
tooltipPlacement={tooltipPlacement}
|
|
185
|
+
{...props._input}
|
|
186
|
+
/>
|
|
187
|
+
<HStack className="flex-1">
|
|
188
|
+
<Slider
|
|
189
|
+
{...testProps('slider')}
|
|
190
|
+
ref={props.outerRef}
|
|
191
|
+
style={{
|
|
192
|
+
width: '100%',
|
|
193
|
+
height: 40,
|
|
194
|
+
}}
|
|
195
|
+
minimumTrackTintColor={styles.SLIDER_MIN_TRACK_COLOR}
|
|
196
|
+
maximumTrackTintColor={styles.SLIDER_MAX_TRACK_COLOR}
|
|
197
|
+
thumbTintColor={styles.SLIDER_THUMB_COLOR}
|
|
198
|
+
minimumValue={minValue}
|
|
199
|
+
maximumValue={maxValue}
|
|
200
|
+
step={step}
|
|
201
|
+
value={sliderValue}
|
|
202
|
+
onValueChange={(value) => {
|
|
203
|
+
// This sets the localValue, only for display purposes
|
|
204
|
+
setLocalValue(value);
|
|
205
|
+
}}
|
|
206
|
+
onSlidingComplete={(value) => {
|
|
207
|
+
// This sets the actual value
|
|
208
|
+
if (value === FAKE_ZERO) {
|
|
209
|
+
value = 0;
|
|
210
|
+
}
|
|
211
|
+
setValue(value);
|
|
212
|
+
}}
|
|
187
213
|
/>
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
ref={props.outerRef}
|
|
192
|
-
style={{
|
|
193
|
-
width: '100%',
|
|
194
|
-
height: 40,
|
|
195
|
-
}}
|
|
196
|
-
minimumTrackTintColor={styles.SLIDER_MIN_TRACK_COLOR}
|
|
197
|
-
maximumTrackTintColor={styles.SLIDER_MAX_TRACK_COLOR}
|
|
198
|
-
thumbTintColor={styles.SLIDER_THUMB_COLOR}
|
|
199
|
-
minimumValue={minValue}
|
|
200
|
-
maximumValue={maxValue}
|
|
201
|
-
step={step}
|
|
202
|
-
value={sliderValue}
|
|
203
|
-
onValueChange={(value) => {
|
|
204
|
-
// This sets the localValue, only for display purposes
|
|
205
|
-
setLocalValue(value);
|
|
206
|
-
}}
|
|
207
|
-
onSlidingComplete={(value) => {
|
|
208
|
-
// This sets the actual value
|
|
209
|
-
if (value === FAKE_ZERO) {
|
|
210
|
-
value = 0;
|
|
211
|
-
}
|
|
212
|
-
setValue(value);
|
|
213
|
-
}}
|
|
214
|
-
/>
|
|
215
|
-
</HStack>
|
|
216
|
-
</HStack>;
|
|
217
|
-
},
|
|
218
|
-
SliderField = withComponent(withValue(SliderElement));
|
|
214
|
+
</HStack>
|
|
215
|
+
</HStack>;
|
|
216
|
+
};
|
|
219
217
|
|
|
220
|
-
|
|
221
|
-
export default withTooltip(React.forwardRef((props, ref) => {
|
|
222
|
-
return <SliderField {...props} outerRef={ref} />;
|
|
223
|
-
}));
|
|
218
|
+
export default withComponent(withValue(SliderElement));
|
|
@@ -124,11 +124,13 @@ function TagComponent(props) {
|
|
|
124
124
|
if (!id) {
|
|
125
125
|
displayValue = '';
|
|
126
126
|
} else if (Repository) {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
if (!Repository.isDestroyed) {
|
|
128
|
+
item = Repository.getById(id);
|
|
129
|
+
if (!item) {
|
|
130
|
+
throw Error('item not found');
|
|
131
|
+
}
|
|
132
|
+
displayValue = item.displayValue;
|
|
130
133
|
}
|
|
131
|
-
displayValue = item.displayValue;
|
|
132
134
|
} else {
|
|
133
135
|
item = _.find(data, (datum) => datum[idIx] === id);
|
|
134
136
|
if (!item) {
|
|
@@ -248,19 +250,19 @@ function TagComponent(props) {
|
|
|
248
250
|
className += ' ' + props.className;
|
|
249
251
|
}
|
|
250
252
|
const style = {};
|
|
251
|
-
if (
|
|
253
|
+
if (props.style) {
|
|
254
|
+
_.assign(style, props.style); // needed for grid; otherwise valuebox width can be too wide
|
|
255
|
+
}
|
|
256
|
+
if (!props.flex && !props.w && !style.width) {
|
|
252
257
|
style.flex = 1;
|
|
253
258
|
} else {
|
|
254
|
-
if (props.w) {
|
|
259
|
+
if (props.w && !style.width) {
|
|
255
260
|
style.width = props.w;
|
|
256
261
|
}
|
|
257
|
-
if (props.flex) {
|
|
262
|
+
if (props.flex && !style.width) {
|
|
258
263
|
style.flex = props.flex;
|
|
259
264
|
}
|
|
260
265
|
}
|
|
261
|
-
if (props.style) {
|
|
262
|
-
_.assign(style, props.style); // needed for grid; otherwise valuebox width can be too wide
|
|
263
|
-
}
|
|
264
266
|
let valueBoxesClassName = `
|
|
265
267
|
Tag-valueBoxes-container
|
|
266
268
|
w-full
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { forwardRef, useState, useEffect, useRef, } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Textarea, TextareaInput,
|
|
4
4
|
} from '@project-components/Gluestack';
|
|
@@ -8,106 +8,104 @@ import withTooltip from '../../Hoc/withTooltip.js';
|
|
|
8
8
|
import withValue from '../../Hoc/withValue.js';
|
|
9
9
|
import _ from 'lodash';
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
useEffect(() => {
|
|
63
|
-
// Set up debounce fn
|
|
64
|
-
// Have to do this because otherwise, lodash tries to create a debounced version of the fn from only this render
|
|
65
|
-
debouncedSetValueRef.current?.cancel(); // Cancel any previous debounced fn
|
|
66
|
-
debouncedSetValueRef.current = _.debounce(setValue, autoSubmitDelay);
|
|
67
|
-
}, [setValue]);
|
|
68
|
-
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
|
|
71
|
-
if (!isTyping() && value !== localValue) {
|
|
72
|
-
// Make local value conform to externally changed value
|
|
73
|
-
setLocalValue(value);
|
|
11
|
+
const TextAreaElement = forwardRef((props, ref) => {
|
|
12
|
+
let { // so localValue can be changed, if needed
|
|
13
|
+
setValue,
|
|
14
|
+
autoSubmit = true, // automatically setValue after user stops typing for autoSubmitDelay
|
|
15
|
+
autoSubmitDelay = UiGlobals.autoSubmitDelay,
|
|
16
|
+
onChangeText,
|
|
17
|
+
placeholder,
|
|
18
|
+
minimizeForRow = false,
|
|
19
|
+
testID,
|
|
20
|
+
className,
|
|
21
|
+
...propsToPass
|
|
22
|
+
} = props,
|
|
23
|
+
value = _.isNil(props.value) ? '' : props.value, // null value may not actually reset this TextArea, so set it explicitly to empty string
|
|
24
|
+
styles = UiGlobals.styles,
|
|
25
|
+
debouncedSetValueRef = useRef(),
|
|
26
|
+
[localValue, setLocalValue] = useState(value),
|
|
27
|
+
isTypingRef = useRef(),
|
|
28
|
+
isTypingTimeoutRef = useRef(),
|
|
29
|
+
isTyping = () => {
|
|
30
|
+
return isTypingRef.current;
|
|
31
|
+
},
|
|
32
|
+
setIsTyping = (isTyping) => {
|
|
33
|
+
isTypingRef.current = isTyping;
|
|
34
|
+
if (isTyping) {
|
|
35
|
+
startIsTypingTimeout();
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
startIsTypingTimeout = () => {
|
|
39
|
+
clearIsTypingTimeout();
|
|
40
|
+
isTypingTimeoutRef.current = setTimeout(() => {
|
|
41
|
+
setIsTyping(false);
|
|
42
|
+
}, autoSubmitDelay + 1000);
|
|
43
|
+
},
|
|
44
|
+
clearIsTypingTimeout = () => {
|
|
45
|
+
if (isTypingTimeoutRef.current) {
|
|
46
|
+
clearTimeout(isTypingTimeoutRef.current);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
onChangeTextLocal = (value) => {
|
|
50
|
+
setIsTyping(true);
|
|
51
|
+
if (value === '') {
|
|
52
|
+
value = null; // empty string makes value null
|
|
53
|
+
}
|
|
54
|
+
setLocalValue(value);
|
|
55
|
+
if (autoSubmit) {
|
|
56
|
+
debouncedSetValueRef.current(value);
|
|
57
|
+
}
|
|
58
|
+
if (onChangeText) {
|
|
59
|
+
onChangeText(value);
|
|
74
60
|
}
|
|
61
|
+
};
|
|
75
62
|
|
|
76
|
-
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
// Set up debounce fn
|
|
65
|
+
// Have to do this because otherwise, lodash tries to create a debounced version of the fn from only this render
|
|
66
|
+
debouncedSetValueRef.current?.cancel(); // Cancel any previous debounced fn
|
|
67
|
+
debouncedSetValueRef.current = _.debounce(setValue, autoSubmitDelay);
|
|
68
|
+
}, [setValue]);
|
|
77
69
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`,
|
|
84
|
-
inputClassName = `
|
|
85
|
-
TextAreaInput
|
|
86
|
-
flex-1
|
|
87
|
-
${styles.FORM_TEXTAREA_CLASSNAME}
|
|
88
|
-
`;
|
|
89
|
-
if (props.className) {
|
|
90
|
-
inputClassName += ' ' + props.className;
|
|
91
|
-
}
|
|
92
|
-
if (minimizeForRow) {
|
|
93
|
-
textareaClassName += ' h-auto min-h-0 max-h-[40px] overflow-auto';
|
|
94
|
-
inputClassName += ' py-0';
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
|
|
72
|
+
if (!isTyping() && value !== localValue) {
|
|
73
|
+
// Make local value conform to externally changed value
|
|
74
|
+
setLocalValue(value);
|
|
95
75
|
}
|
|
96
76
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
77
|
+
}, [value]);
|
|
78
|
+
|
|
79
|
+
if (localValue === null || typeof localValue === 'undefined') {
|
|
80
|
+
localValue = ''; // If the value is null or undefined, don't let this be an uncontrolled input
|
|
81
|
+
}
|
|
82
|
+
let textareaClassName = `
|
|
83
|
+
Textarea
|
|
84
|
+
`,
|
|
85
|
+
inputClassName = `
|
|
86
|
+
TextAreaInput
|
|
87
|
+
flex-1
|
|
88
|
+
${styles.FORM_TEXTAREA_CLASSNAME}
|
|
89
|
+
`;
|
|
90
|
+
if (className) {
|
|
91
|
+
inputClassName += ' ' + className;
|
|
92
|
+
}
|
|
93
|
+
if (minimizeForRow) {
|
|
94
|
+
textareaClassName += ' h-auto min-h-0 max-h-[40px] overflow-auto';
|
|
95
|
+
inputClassName += ' py-0';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return <Textarea className={textareaClassName}>
|
|
99
|
+
<TextareaInput
|
|
100
|
+
{...propsToPass}
|
|
101
|
+
testID={testID}
|
|
102
|
+
ref={ref}
|
|
103
|
+
onChangeText={onChangeTextLocal}
|
|
104
|
+
value={localValue}
|
|
105
|
+
className={inputClassName}
|
|
106
|
+
placeholder={placeholder}
|
|
107
|
+
/>
|
|
108
|
+
</Textarea>;
|
|
109
|
+
});
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
export default withTooltip(React.forwardRef((props, ref) => {
|
|
112
|
-
return <TextAreaField {...props} outerRef={ref} />;
|
|
113
|
-
}));
|
|
111
|
+
export default withComponent(withValue(withTooltip(TextAreaElement)));
|