@onehat/ui 0.3.274 → 0.3.277

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.3.274",
3
+ "version": "0.3.277",
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.20.0",
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
 
@@ -237,7 +237,7 @@ export function ComboComponent(props) {
237
237
  }
238
238
 
239
239
  if (_.isEmpty(gridSelection)) {
240
- confirm('You have nothing selected in the dropdown menu. Clear value?', doIt, true);
240
+ hideMenu();
241
241
  return;
242
242
  }
243
243
 
@@ -304,7 +304,11 @@ export function ComboComponent(props) {
304
304
  return;
305
305
  }
306
306
  clearGridFilters();
307
- showMenu();
307
+ if (isMenuShown) {
308
+ hideMenu();
309
+ } else {
310
+ showMenu();
311
+ }
308
312
  },
309
313
  onTriggerBlur = (e) => {
310
314
  if (!isMenuShown) {
@@ -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
- onInputChangeText = (value) => {
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
- {...testProps('input')}
361
+ testID={testID}
362
362
  ref={inputRef}
363
363
  value={textInputValue}
364
364
  // setValue={onInputSetValue}
365
- onChangeValue={onInputChangeText}
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={onInputChangeText}
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
- // Make local value conform to externally changed value
59
- setLocalValue(value);
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 flex={1} h="100%" p={0} borderWidth={1} borderColor="trueGray.400" borderRadius={6} {...props}>
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
- {...testProps('input')}
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 {
@@ -52,6 +53,7 @@ import ReorderRows from '../Icons/ReorderRows.js';
52
53
  import PaginationToolbar from '../Toolbar/PaginationToolbar.js';
53
54
  import NoRecordsFound from '../Grid/NoRecordsFound.js';
54
55
  import Toolbar from '../Toolbar/Toolbar.js';
56
+ import Loading from '../Messages/Loading.js';
55
57
  import _ from 'lodash';
56
58
 
57
59
  const DEPTH_INDENT_PX = 25;
@@ -361,7 +363,7 @@ function TreeComponent(props) {
361
363
 
362
364
  const isMultipleHits = found.length > 1;
363
365
  if (!isMultipleHits) {
364
- expandPath(found[0].path); // highlights and selects the last node in the path
366
+ expandPath(found[0].cPath); // highlights and selects the last node in the cPath
365
367
  return;
366
368
  }
367
369
 
@@ -650,23 +652,23 @@ function TreeComponent(props) {
650
652
  }
651
653
  });
652
654
  },
653
- expandPath = async (path) => {
655
+ expandPath = async (cPath) => {
654
656
  // First, close thw whole tree.
655
657
  let newTreeNodeData = _.clone(getTreeNodeData());
656
658
  collapseNodes(newTreeNodeData);
657
659
 
658
660
  // As it navigates down, it will expand the appropriate branches,
659
661
  // and then finally highlight & select the node in question
660
- let pathParts,
662
+ let cPathParts,
661
663
  id,
662
664
  currentLevelData = newTreeNodeData,
663
665
  currentDatum,
664
666
  parentDatum,
665
667
  currentNode;
666
668
 
667
- while(path.length) {
668
- pathParts = path.split('/');
669
- id = parseInt(pathParts[0], 10); // grab the first part of the path
669
+ while(cPath.length) {
670
+ cPathParts = cPath.split('/');
671
+ id = parseInt(cPathParts[0], 10); // grab the first part of the cPath
670
672
 
671
673
  // find match in current level
672
674
  currentDatum = _.find(currentLevelData, (treeNodeDatum) => {
@@ -687,7 +689,7 @@ function TreeComponent(props) {
687
689
  // THE MAGIC!
688
690
  currentDatum.isExpanded = true;
689
691
 
690
- path = pathParts.slice(1).join('/'); // put the rest of it back together
692
+ cPath = cPathParts.slice(1).join('/'); // put the rest of it back together
691
693
  currentLevelData = currentDatum.children;
692
694
  parentDatum = currentDatum;
693
695
  }
@@ -729,7 +731,7 @@ function TreeComponent(props) {
729
731
  // 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
732
 
731
733
  // ... 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 path?
734
+ // Maybe I first collapse the tree, then expand just the cPath?
733
735
  },
734
736
 
735
737
  // render
@@ -1088,18 +1090,22 @@ function TreeComponent(props) {
1088
1090
 
1089
1091
  useEffect(() => {
1090
1092
 
1091
- if (!isReady) {
1092
- if (Repository) {
1093
- Repository.setBaseParams(extraParams);
1094
- }
1093
+ if (!Repository) {
1095
1094
  (async () => {
1096
1095
  await buildAndSetTreeNodeData();
1097
1096
  setIsReady(true);
1098
1097
  })();
1098
+ return () => {};
1099
1099
  }
1100
1100
 
1101
- if (!Repository) {
1102
- return () => {};
1101
+ if (!_.isEmpty(extraParams)) {
1102
+ Repository.setBaseParams(extraParams);
1103
+ }
1104
+
1105
+ async function rebuildTree() {
1106
+ setIsReady(false);
1107
+ await buildAndSetTreeNodeData();
1108
+ setIsReady(true);
1103
1109
  }
1104
1110
 
1105
1111
  // set up @onehat/data repository
@@ -1109,12 +1115,14 @@ function TreeComponent(props) {
1109
1115
 
1110
1116
  Repository.on('beforeLoad', setTrue);
1111
1117
  Repository.on('load', setFalse);
1118
+ Repository.on('loadRootNodes', rebuildTree);
1112
1119
  Repository.on('changeFilters', reloadTree);
1113
1120
  Repository.on('changeSorters', reloadTree);
1114
1121
 
1115
1122
  return () => {
1116
1123
  Repository.off('beforeLoad', setTrue);
1117
1124
  Repository.off('load', setFalse);
1125
+ Repository.off('loadRootNodes', rebuildTree);
1118
1126
  Repository.off('changeFilters', reloadTree);
1119
1127
  Repository.off('changeSorters', reloadTree);
1120
1128
  };
@@ -1149,7 +1157,7 @@ function TreeComponent(props) {
1149
1157
  footerToolbarItemComponents = useMemo(() => getFooterToolbarItems(), [Repository?.hash, additionalToolbarButtons, isDragMode, getTreeNodeData()]);
1150
1158
 
1151
1159
  if (!isReady) {
1152
- return null;
1160
+ return <Loading />;
1153
1161
  }
1154
1162
 
1155
1163
  const treeNodes = renderTreeNodes(getTreeNodeData());
@@ -1197,9 +1205,11 @@ function TreeComponent(props) {
1197
1205
  }
1198
1206
  }}
1199
1207
  >
1200
- {!treeNodes?.length ?
1201
- <NoRecordsFound text={noneFoundText} onRefresh={reloadTree} /> :
1202
- treeNodes}
1208
+ <ScrollView flex={1} w="100%">
1209
+ {!treeNodes?.length ?
1210
+ <NoRecordsFound text={noneFoundText} onRefresh={reloadTree} /> :
1211
+ treeNodes}
1212
+ </ScrollView>
1203
1213
  </Column>
1204
1214
 
1205
1215
  {treeFooterComponent}
@@ -1239,8 +1249,8 @@ function TreeComponent(props) {
1239
1249
  treeNode = _.find(searchResults, (item) => {
1240
1250
  return item.id === data.node_id;
1241
1251
  }),
1242
- path = treeNode.path;
1243
- expandPath(path);
1252
+ cPath = treeNode.cPath;
1253
+ expandPath(cPath);
1244
1254
 
1245
1255
  // Close the modal
1246
1256
  setIsModalShown(false);