@onehat/ui 0.3.273 → 0.3.276
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 +2 -2
- package/src/Components/Form/Field/CKEditor/CKEditor.js +1 -0
- package/src/Components/Form/Field/Combo/Combo.js +19 -8
- package/src/Components/Form/Field/Date.js +11 -11
- package/src/Components/Form/Field/Input.js +9 -2
- package/src/Components/Form/Field/Number.js +14 -2
- package/src/Components/Form/Field/TextArea.js +1 -0
- package/src/Components/Panel/Panel.js +5 -3
- package/src/Components/Tree/Tree.js +16 -13
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onehat/ui",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.276",
|
|
4
4
|
"description": "Base UI for OneHat apps",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@gluestack-ui/themed": "^1.1.26",
|
|
31
31
|
"@hookform/resolvers": "^3.3.1",
|
|
32
32
|
"@k-renwick/colour-mixer": "^1.2.1",
|
|
33
|
-
"@onehat/data": "^1.
|
|
33
|
+
"@onehat/data": "^1.21.0",
|
|
34
34
|
"@reduxjs/toolkit": "^1.9.5",
|
|
35
35
|
"inflector-js": "^1.0.1",
|
|
36
36
|
"js-cookie": "^3.0.5",
|
|
@@ -29,6 +29,7 @@ const
|
|
|
29
29
|
useEffect(() => {
|
|
30
30
|
// Set up debounce fn
|
|
31
31
|
// Have to do this because otherwise, lodash tries to create a debounced version of the fn from only this render
|
|
32
|
+
debouncedSetValueRef.current?.cancel(); // Cancel any previous debounced fn
|
|
32
33
|
debouncedSetValueRef.current = _.debounce(setValue, autoSubmitDelay);
|
|
33
34
|
}, [setValue]);
|
|
34
35
|
|
|
@@ -58,6 +58,7 @@ export function ComboComponent(props) {
|
|
|
58
58
|
onGridSave, // to hook into when menu saves (ComboEditor only)
|
|
59
59
|
onGridDelete, // to hook into when menu deletes (ComboEditor only)
|
|
60
60
|
newEntityDisplayProperty,
|
|
61
|
+
testID,
|
|
61
62
|
|
|
62
63
|
// withComponent
|
|
63
64
|
self,
|
|
@@ -236,7 +237,7 @@ export function ComboComponent(props) {
|
|
|
236
237
|
}
|
|
237
238
|
|
|
238
239
|
if (_.isEmpty(gridSelection)) {
|
|
239
|
-
|
|
240
|
+
hideMenu();
|
|
240
241
|
return;
|
|
241
242
|
}
|
|
242
243
|
|
|
@@ -303,7 +304,11 @@ export function ComboComponent(props) {
|
|
|
303
304
|
return;
|
|
304
305
|
}
|
|
305
306
|
clearGridFilters();
|
|
306
|
-
|
|
307
|
+
if (isMenuShown) {
|
|
308
|
+
hideMenu();
|
|
309
|
+
} else {
|
|
310
|
+
showMenu();
|
|
311
|
+
}
|
|
307
312
|
},
|
|
308
313
|
onTriggerBlur = (e) => {
|
|
309
314
|
if (!isMenuShown) {
|
|
@@ -361,7 +366,7 @@ export function ComboComponent(props) {
|
|
|
361
366
|
menuRef.current === relatedTarget ||
|
|
362
367
|
menuRef.current?.contains(relatedTarget);
|
|
363
368
|
},
|
|
364
|
-
getFilterName = () => {
|
|
369
|
+
getFilterName = (isId) => {
|
|
365
370
|
// Only used for remote repositories
|
|
366
371
|
// Gets the filter name of the query, which becomes the condition sent to server
|
|
367
372
|
let filterName = FILTER_NAME;
|
|
@@ -372,7 +377,10 @@ export function ComboComponent(props) {
|
|
|
372
377
|
displayFieldDef = schema.getPropertyDefinition(displayFieldName);
|
|
373
378
|
|
|
374
379
|
// Verify displayField is a real field
|
|
375
|
-
if (
|
|
380
|
+
if (isId) {
|
|
381
|
+
const idFieldName = schema.model.idProperty;
|
|
382
|
+
filterName = idFieldName;
|
|
383
|
+
} else if (!displayFieldDef.isVirtual) {
|
|
376
384
|
filterName = displayFieldName + ' LIKE';
|
|
377
385
|
}
|
|
378
386
|
}
|
|
@@ -418,10 +426,13 @@ export function ComboComponent(props) {
|
|
|
418
426
|
}
|
|
419
427
|
|
|
420
428
|
// Set filter
|
|
421
|
-
const
|
|
429
|
+
const
|
|
430
|
+
idRegex = /^id:(.*)$/,
|
|
431
|
+
isId = _.isString(value) && !!value.match(idRegex),
|
|
432
|
+
filterName = getFilterName(isId);
|
|
422
433
|
if (Repository.isRemote) {
|
|
423
434
|
// remote
|
|
424
|
-
const filterValue = _.isEmpty(value) ? null : value + '%';
|
|
435
|
+
const filterValue = _.isEmpty(value) ? null : (isId ? value.match(idRegex)[1] : value + '%');
|
|
425
436
|
await Repository.filter(filterName, filterValue);
|
|
426
437
|
if (!Repository.isAutoLoad) {
|
|
427
438
|
await Repository.reload();
|
|
@@ -958,7 +969,7 @@ export function ComboComponent(props) {
|
|
|
958
969
|
if (isRendered && additionalButtons?.length && containerWidth < 500) {
|
|
959
970
|
// be responsive for small screen sizes and bump additionalButtons to the next line
|
|
960
971
|
assembledComponents =
|
|
961
|
-
<Column>
|
|
972
|
+
<Column testID={testID}>
|
|
962
973
|
<Row {...refProps} justifyContent="center" alignItems="center" flex={1} h="100%">
|
|
963
974
|
{xButton}
|
|
964
975
|
{eyeButton}
|
|
@@ -971,7 +982,7 @@ export function ComboComponent(props) {
|
|
|
971
982
|
</Column>;
|
|
972
983
|
} else {
|
|
973
984
|
assembledComponents =
|
|
974
|
-
<Row {...refProps} justifyContent="center" alignItems="center" flex={1} h="100%" onLayout={onLayout}>
|
|
985
|
+
<Row testID={testID} {...refProps} justifyContent="center" alignItems="center" flex={1} h="100%" onLayout={onLayout}>
|
|
975
986
|
{xButton}
|
|
976
987
|
{eyeButton}
|
|
977
988
|
{inputAndTrigger}
|
|
@@ -50,10 +50,15 @@ export function DateElement(props) {
|
|
|
50
50
|
isDisabled = false,
|
|
51
51
|
tooltipPlacement = 'bottom',
|
|
52
52
|
placeholder = 'Choose a date.',
|
|
53
|
+
testID,
|
|
54
|
+
|
|
55
|
+
// withComponent
|
|
56
|
+
self,
|
|
53
57
|
|
|
54
58
|
// withValue
|
|
55
59
|
value,
|
|
56
60
|
setValue,
|
|
61
|
+
...propsToPass
|
|
57
62
|
} = props,
|
|
58
63
|
styles = UiGlobals.styles,
|
|
59
64
|
Datetime = getComponentFromType('Datetime'),
|
|
@@ -97,9 +102,6 @@ export function DateElement(props) {
|
|
|
97
102
|
return value;
|
|
98
103
|
},
|
|
99
104
|
showPicker = () => {
|
|
100
|
-
if (isPickerShown) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
105
|
if (UiGlobals.mode === UI_MODE_WEB && triggerRef.current?.getBoundingClientRect) {
|
|
104
106
|
// For web, ensure it's in the proper place
|
|
105
107
|
const
|
|
@@ -124,9 +126,6 @@ export function DateElement(props) {
|
|
|
124
126
|
setIsPickerShown(true);
|
|
125
127
|
},
|
|
126
128
|
hidePicker = () => {
|
|
127
|
-
if (!isPickerShown) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
129
|
setIsPickerShown(false);
|
|
131
130
|
},
|
|
132
131
|
togglePicker = () => {
|
|
@@ -165,7 +164,7 @@ export function DateElement(props) {
|
|
|
165
164
|
}
|
|
166
165
|
showPicker();
|
|
167
166
|
},
|
|
168
|
-
|
|
167
|
+
onInputChangeValue = (value) => {
|
|
169
168
|
if (disableDirectEntry) {
|
|
170
169
|
return;
|
|
171
170
|
}
|
|
@@ -174,6 +173,7 @@ export function DateElement(props) {
|
|
|
174
173
|
setTextInputValue('');
|
|
175
174
|
return;
|
|
176
175
|
}
|
|
176
|
+
|
|
177
177
|
value = formatByMode(value);
|
|
178
178
|
|
|
179
179
|
if (value !== 'Invalid date') {
|
|
@@ -358,11 +358,11 @@ export function DateElement(props) {
|
|
|
358
358
|
>{_.isEmpty(textInputValue) ? placeholder : textInputValue}</Text>
|
|
359
359
|
</Pressable> :
|
|
360
360
|
<Input
|
|
361
|
-
{
|
|
361
|
+
testID={testID}
|
|
362
362
|
ref={inputRef}
|
|
363
363
|
value={textInputValue}
|
|
364
364
|
// setValue={onInputSetValue}
|
|
365
|
-
onChangeValue={
|
|
365
|
+
onChangeValue={onInputChangeValue}
|
|
366
366
|
onKeyPress={onInputKeyPress}
|
|
367
367
|
onBlur={onInputBlur}
|
|
368
368
|
onFocus={onInputFocus}
|
|
@@ -559,7 +559,7 @@ export function DateElement(props) {
|
|
|
559
559
|
value={textInputValue}
|
|
560
560
|
autoSubmit={true}
|
|
561
561
|
isDisabled={isDisabled}
|
|
562
|
-
onChangeValue={
|
|
562
|
+
onChangeValue={onInputChangeValue}
|
|
563
563
|
onKeyPress={onInputKeyPress}
|
|
564
564
|
onFocus={onInputFocus}
|
|
565
565
|
onBlur={onInputBlur}
|
|
@@ -619,7 +619,7 @@ export function DateElement(props) {
|
|
|
619
619
|
if (tooltipRef) {
|
|
620
620
|
refProps.ref = tooltipRef;
|
|
621
621
|
}
|
|
622
|
-
assembledComponents = <Row {...refProps} justifyContent="center" alignItems="center" h={styles.FORM_COMBO_HEIGHT} flex={1} onLayout={() => setIsRendered(true)}>
|
|
622
|
+
assembledComponents = <Row {...refProps} {...propsToPass} justifyContent="center" alignItems="center" h={styles.FORM_COMBO_HEIGHT} flex={1} onLayout={() => setIsRendered(true)}>
|
|
623
623
|
{xButton}
|
|
624
624
|
{inputAndTrigger}
|
|
625
625
|
{additionalButtons}
|
|
@@ -20,12 +20,14 @@ function InputElement(props) {
|
|
|
20
20
|
onChangeText,
|
|
21
21
|
tooltip = null,
|
|
22
22
|
tooltipPlacement = 'bottom',
|
|
23
|
+
self,
|
|
23
24
|
} = props,
|
|
24
25
|
styles = UiGlobals.styles,
|
|
25
26
|
debouncedSetValueRef = useRef(),
|
|
26
27
|
[localValue, setLocalValue] = useState(value),
|
|
27
28
|
onKeyPressLocal = (e) => {
|
|
28
29
|
if (e.key === 'Enter') {
|
|
30
|
+
debouncedSetValueRef.current?.cancel();
|
|
29
31
|
setValue(localValue);
|
|
30
32
|
}
|
|
31
33
|
if (onKeyPress) {
|
|
@@ -48,15 +50,20 @@ function InputElement(props) {
|
|
|
48
50
|
};
|
|
49
51
|
|
|
50
52
|
useEffect(() => {
|
|
53
|
+
|
|
51
54
|
// Set up debounce fn
|
|
52
55
|
// Have to do this because otherwise, lodash tries to create a debounced version of the fn from only this render
|
|
56
|
+
debouncedSetValueRef.current?.cancel(); // Cancel any previous debounced fn
|
|
53
57
|
debouncedSetValueRef.current = _.debounce(setValue, autoSubmitDelay);
|
|
58
|
+
|
|
54
59
|
}, [setValue]);
|
|
55
60
|
|
|
56
61
|
useEffect(() => {
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
if (value !== localValue) {
|
|
64
|
+
// Make local value conform to externally changed value
|
|
65
|
+
setLocalValue(value);
|
|
66
|
+
}
|
|
60
67
|
|
|
61
68
|
}, [value]);
|
|
62
69
|
|
|
@@ -26,6 +26,8 @@ function NumberElement(props) {
|
|
|
26
26
|
autoSubmitDelay = UiGlobals.autoSubmitDelay,
|
|
27
27
|
tooltip = null,
|
|
28
28
|
isDisabled = false,
|
|
29
|
+
testID,
|
|
30
|
+
...propsToPass
|
|
29
31
|
} = props,
|
|
30
32
|
styles = UiGlobals.styles,
|
|
31
33
|
debouncedSetValueRef = useRef(),
|
|
@@ -40,6 +42,7 @@ function NumberElement(props) {
|
|
|
40
42
|
onIncrement();
|
|
41
43
|
break;
|
|
42
44
|
case 'Enter':
|
|
45
|
+
debouncedSetValueRef.current?.cancel();
|
|
43
46
|
setValue(value);
|
|
44
47
|
break;
|
|
45
48
|
case 'ArrowLeft':
|
|
@@ -93,6 +96,7 @@ function NumberElement(props) {
|
|
|
93
96
|
useEffect(() => {
|
|
94
97
|
// Set up debounce fn
|
|
95
98
|
// Have to do this because otherwise, lodash tries to create a debounced version of the fn from only this render
|
|
99
|
+
debouncedSetValueRef.current?.cancel(); // Cancel any previous debounced fn
|
|
96
100
|
debouncedSetValueRef.current = _.debounce(setValue, autoSubmitDelay);
|
|
97
101
|
}, [setValue]);
|
|
98
102
|
|
|
@@ -119,7 +123,15 @@ function NumberElement(props) {
|
|
|
119
123
|
isIncrementDisabled = typeof maxValue !== 'undefined' && value === maxValue,
|
|
120
124
|
isDecrementDisabled = typeof minValue !== 'undefined' && (value === minValue || (!value && minValue === 0));
|
|
121
125
|
|
|
122
|
-
return <Row
|
|
126
|
+
return <Row
|
|
127
|
+
flex={1}
|
|
128
|
+
h="100%"
|
|
129
|
+
p={0}
|
|
130
|
+
borderWidth={1}
|
|
131
|
+
borderColor="trueGray.400"
|
|
132
|
+
borderRadius={6}
|
|
133
|
+
{...propsToPass}
|
|
134
|
+
>
|
|
123
135
|
<IconButton
|
|
124
136
|
{...testProps('decrementBtn')}
|
|
125
137
|
icon={<Icon as={Minus} color={(isDecrementDisabled || isDisabled) ? 'disabled' : 'trueGray.500'} />}
|
|
@@ -135,7 +147,7 @@ function NumberElement(props) {
|
|
|
135
147
|
zIndex={10}
|
|
136
148
|
/>
|
|
137
149
|
<InputWithTooltip
|
|
138
|
-
{
|
|
150
|
+
testID={testID}
|
|
139
151
|
value={inputValue}
|
|
140
152
|
onChangeText={onChangeText}
|
|
141
153
|
onKeyPress={onInputKeyPress}
|
|
@@ -36,6 +36,7 @@ const
|
|
|
36
36
|
useEffect(() => {
|
|
37
37
|
// Set up debounce fn
|
|
38
38
|
// Have to do this because otherwise, lodash tries to create a debounced version of the fn from only this render
|
|
39
|
+
debouncedSetValueRef.current?.cancel(); // Cancel any previous debounced fn
|
|
39
40
|
debouncedSetValueRef.current = _.debounce(setValue, autoSubmitDelay);
|
|
40
41
|
}, [setValue]);
|
|
41
42
|
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import Inflector from 'inflector-js';
|
|
13
13
|
import Header from './Header.js';
|
|
14
14
|
import Mask from './Mask.js';
|
|
15
|
+
import testProps from '../../Functions/testProps.js';
|
|
15
16
|
import withCollapsible from '../Hoc/withCollapsible.js';
|
|
16
17
|
import withComponent from '../Hoc/withComponent.js';
|
|
17
18
|
import emptyFn from '../../Functions/emptyFn.js';
|
|
@@ -145,19 +146,20 @@ function Panel(props) {
|
|
|
145
146
|
framePropsToUse = frameProps;
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
const self = props.self;
|
|
148
150
|
if (isCollapsed) {
|
|
149
151
|
if (collapseDirection === HORIZONTAL) {
|
|
150
|
-
return <Column overflow="hidden" {...propsToPass} {...framePropsToUse} {...sizeProps} w="33px">
|
|
152
|
+
return <Column {...testProps(self?.reference)} overflow="hidden" {...propsToPass} {...framePropsToUse} {...sizeProps} w="33px">
|
|
151
153
|
{isDisabled && <Mask />}
|
|
152
154
|
{headerComponent}
|
|
153
155
|
</Column>;
|
|
154
156
|
}
|
|
155
|
-
return <Column overflow="hidden" {...propsToPass} {...framePropsToUse} {...sizeProps} h="33px">
|
|
157
|
+
return <Column {...testProps(self?.reference)} overflow="hidden" {...propsToPass} {...framePropsToUse} {...sizeProps} h="33px">
|
|
156
158
|
{isDisabled && <Mask />}
|
|
157
159
|
{headerComponent}
|
|
158
160
|
</Column>;
|
|
159
161
|
}
|
|
160
|
-
return <Column overflow="hidden" {...propsToPass} {...framePropsToUse} {...sizeProps} onLayout={onLayout}>
|
|
162
|
+
return <Column {...testProps(self?.reference)} overflow="hidden" {...propsToPass} {...framePropsToUse} {...sizeProps} onLayout={onLayout}>
|
|
161
163
|
{isDisabled && <Mask />}
|
|
162
164
|
{headerComponent}
|
|
163
165
|
{topToolbar}
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
Pressable,
|
|
7
7
|
Icon,
|
|
8
8
|
Row,
|
|
9
|
+
ScrollView,
|
|
9
10
|
Text,
|
|
10
11
|
} from 'native-base';
|
|
11
12
|
import {
|
|
@@ -361,7 +362,7 @@ function TreeComponent(props) {
|
|
|
361
362
|
|
|
362
363
|
const isMultipleHits = found.length > 1;
|
|
363
364
|
if (!isMultipleHits) {
|
|
364
|
-
expandPath(found[0].
|
|
365
|
+
expandPath(found[0].cPath); // highlights and selects the last node in the cPath
|
|
365
366
|
return;
|
|
366
367
|
}
|
|
367
368
|
|
|
@@ -650,23 +651,23 @@ function TreeComponent(props) {
|
|
|
650
651
|
}
|
|
651
652
|
});
|
|
652
653
|
},
|
|
653
|
-
expandPath = async (
|
|
654
|
+
expandPath = async (cPath) => {
|
|
654
655
|
// First, close thw whole tree.
|
|
655
656
|
let newTreeNodeData = _.clone(getTreeNodeData());
|
|
656
657
|
collapseNodes(newTreeNodeData);
|
|
657
658
|
|
|
658
659
|
// As it navigates down, it will expand the appropriate branches,
|
|
659
660
|
// and then finally highlight & select the node in question
|
|
660
|
-
let
|
|
661
|
+
let cPathParts,
|
|
661
662
|
id,
|
|
662
663
|
currentLevelData = newTreeNodeData,
|
|
663
664
|
currentDatum,
|
|
664
665
|
parentDatum,
|
|
665
666
|
currentNode;
|
|
666
667
|
|
|
667
|
-
while(
|
|
668
|
-
|
|
669
|
-
id = parseInt(
|
|
668
|
+
while(cPath.length) {
|
|
669
|
+
cPathParts = cPath.split('/');
|
|
670
|
+
id = parseInt(cPathParts[0], 10); // grab the first part of the cPath
|
|
670
671
|
|
|
671
672
|
// find match in current level
|
|
672
673
|
currentDatum = _.find(currentLevelData, (treeNodeDatum) => {
|
|
@@ -687,7 +688,7 @@ function TreeComponent(props) {
|
|
|
687
688
|
// THE MAGIC!
|
|
688
689
|
currentDatum.isExpanded = true;
|
|
689
690
|
|
|
690
|
-
|
|
691
|
+
cPath = cPathParts.slice(1).join('/'); // put the rest of it back together
|
|
691
692
|
currentLevelData = currentDatum.children;
|
|
692
693
|
parentDatum = currentDatum;
|
|
693
694
|
}
|
|
@@ -729,7 +730,7 @@ function TreeComponent(props) {
|
|
|
729
730
|
// Also, keep in mind that document.getElementById(id).scrollIntoView() might not work as expected in all situations, especially in complex layouts or when using certain CSS properties. Always test your code thoroughly to make sure it works as expected.
|
|
730
731
|
|
|
731
732
|
// ... Not sure how to do this with NativeBase, as I've had trouble assigning IDs
|
|
732
|
-
// Maybe I first collapse the tree, then expand just the
|
|
733
|
+
// Maybe I first collapse the tree, then expand just the cPath?
|
|
733
734
|
},
|
|
734
735
|
|
|
735
736
|
// render
|
|
@@ -1197,9 +1198,11 @@ function TreeComponent(props) {
|
|
|
1197
1198
|
}
|
|
1198
1199
|
}}
|
|
1199
1200
|
>
|
|
1200
|
-
{
|
|
1201
|
-
|
|
1202
|
-
|
|
1201
|
+
<ScrollView flex={1} w="100%">
|
|
1202
|
+
{!treeNodes?.length ?
|
|
1203
|
+
<NoRecordsFound text={noneFoundText} onRefresh={reloadTree} /> :
|
|
1204
|
+
treeNodes}
|
|
1205
|
+
</ScrollView>
|
|
1203
1206
|
</Column>
|
|
1204
1207
|
|
|
1205
1208
|
{treeFooterComponent}
|
|
@@ -1239,8 +1242,8 @@ function TreeComponent(props) {
|
|
|
1239
1242
|
treeNode = _.find(searchResults, (item) => {
|
|
1240
1243
|
return item.id === data.node_id;
|
|
1241
1244
|
}),
|
|
1242
|
-
|
|
1243
|
-
expandPath(
|
|
1245
|
+
cPath = treeNode.cPath;
|
|
1246
|
+
expandPath(cPath);
|
|
1244
1247
|
|
|
1245
1248
|
// Close the modal
|
|
1246
1249
|
setIsModalShown(false);
|