@onehat/ui 0.4.102 → 0.4.103

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 (46) hide show
  1. package/package.json +1 -1
  2. package/src/Components/Accordion/Accordion.js +65 -6
  3. package/src/Components/Container/Container.js +10 -4
  4. package/src/Components/Form/Form.js +8 -3
  5. package/src/Components/Grid/Grid.js +230 -154
  6. package/src/Components/Hoc/withPresetButtons.js +18 -6
  7. package/src/Components/Icons/ArrowsLeftRight.js +10 -0
  8. package/src/Components/Icons/Bar.js +10 -0
  9. package/src/Components/Icons/Box.js +11 -0
  10. package/src/Components/Icons/BoxOpen.js +11 -0
  11. package/src/Components/Icons/Bucket.js +10 -0
  12. package/src/Components/Icons/Bump.js +21 -0
  13. package/src/Components/Icons/Calculator.js +12 -0
  14. package/src/Components/Icons/Dots.js +20 -0
  15. package/src/Components/Icons/Fleets.js +26 -0
  16. package/src/Components/Icons/Microchip.js +12 -0
  17. package/src/Components/Icons/Num1.js +10 -0
  18. package/src/Components/Icons/Num2.js +10 -0
  19. package/src/Components/Icons/Num3.js +10 -0
  20. package/src/Components/Icons/Num4.js +10 -0
  21. package/src/Components/Icons/OilCan.js +11 -0
  22. package/src/Components/Icons/Operations.js +10 -0
  23. package/src/Components/Icons/OverduePms.js +10 -0
  24. package/src/Components/Icons/SackDollar.js +11 -0
  25. package/src/Components/Icons/ShortBar.js +15 -0
  26. package/src/Components/Icons/Tower.js +10 -0
  27. package/src/Components/Icons/UpcomingPms.js +10 -0
  28. package/src/Components/Layout/ScreenHeader.js +35 -3
  29. package/src/Components/Layout/SetupButton.js +31 -0
  30. package/src/Components/Layout/UserIndicator.js +35 -0
  31. package/src/Components/Pms/Editor/BumpPmsEditor.js +9 -0
  32. package/src/Components/Pms/Editor/MetersEditor.js +173 -0
  33. package/src/Components/Pms/Editor/PmEventsEditor.js +291 -0
  34. package/src/Components/Pms/Grid/UpcomingPmsGrid.js +569 -0
  35. package/src/Components/Pms/Layout/TreeSpecific/MakeTreeSelection.js +11 -0
  36. package/src/Components/Pms/Layout/TreeSpecific/TreeSpecific.js +30 -0
  37. package/src/Components/Pms/Modals/BulkAssignTechnician.js +104 -0
  38. package/src/Components/Pms/Screens/PmsManager.js +136 -0
  39. package/src/Components/Pms/Window/BumpPmsEditorWindow.js +25 -0
  40. package/src/Components/Screens/Manager.js +3 -0
  41. package/src/Components/Tree/Tree.js +15 -6
  42. package/src/Components/Viewer/PmCalcDebugViewer.js +164 -146
  43. package/src/Components/Viewer/TextWithLinks.js +9 -1
  44. package/src/Components/Viewer/Viewer.js +38 -30
  45. package/src/Functions/flatten.js +39 -0
  46. package/src/Functions/verifyCanCrudPmEvents.js +33 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.4.102",
3
+ "version": "0.4.103",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -1,14 +1,21 @@
1
1
  import { useState, useEffect, useRef, } from 'react';
2
2
  import {
3
+ Box,
3
4
  HStack,
4
- ScrollView,
5
+ Icon,
5
6
  Pressable,
7
+ ScrollView,
8
+ Text,
9
+ TextNative,
6
10
  VStack,
7
11
  VStackNative,
8
12
  } from '@project-components/Gluestack';
9
13
  import clsx from 'clsx';
14
+ import Plus from '../Icons/Plus.js';
15
+ import Minus from '../Icons/Minus.js';
10
16
  import inArray from '../../Functions/inArray.js';
11
17
  import emptyFn from '../../Functions/emptyFn.js';
18
+ import UiGlobals from '../../UiGlobals.js';
12
19
  import _ from 'lodash';
13
20
 
14
21
  // The Accordion has two modes.
@@ -25,11 +32,61 @@ import _ from 'lodash';
25
32
 
26
33
  export default function Accordion(props) {
27
34
  const {
35
+ styles = UiGlobals.styles,
28
36
  sections = [],
29
37
  activeSections = [],
30
38
  setActiveSections = emptyFn,
31
- renderHeader = emptyFn,
32
- renderContent = emptyFn,
39
+ renderHeader = (section, ix, isActive) => {
40
+ return <HStack
41
+ className={clsx(
42
+ 'Header',
43
+ 'bg-grey-300',
44
+ 'items-center',
45
+ 'justify-start',
46
+ 'py-1',
47
+ 'px-2',
48
+ 'border-b-grey-400',
49
+ 'border-b-1',
50
+ styles.PANEL_HEADER_BG,
51
+ )}
52
+ >
53
+ {/* <Text className="text-white flex-1">{section.header}</Text> */}
54
+
55
+ <TextNative
56
+ numberOfLines={1}
57
+ ellipsizeMode="head"
58
+ className={clsx(
59
+ 'Header-TextNative1',
60
+ 'flex-1',
61
+ 'font-bold',
62
+ styles.PANEL_HEADER_TEXT_CLASSNAME,
63
+ )}>{section.header}</TextNative>
64
+ <Icon
65
+ as={isActive ? Minus : Plus}
66
+ className={clsx(
67
+ 'text-black',
68
+ )}
69
+ />
70
+ </HStack>;
71
+ },
72
+ unmountInactiveContent = true,
73
+ renderContent = (section, ix, isActive, ref) => {
74
+ if (unmountInactiveContent) {
75
+ if (!isActive) {
76
+ return null;
77
+ }
78
+ return section.content;
79
+ }
80
+
81
+ // This keeps all content rendered, just hidden (zero height) if it's inActive
82
+ let className = 'w-full overflow-hidden';
83
+ if (!isActive) {
84
+ className += ' h-[0px]';
85
+ }
86
+ return <Box className={className}>
87
+ {section.content}
88
+ </Box>;
89
+ },
33
90
  onAnimationEnd = emptyFn,
34
91
  onLayout,
35
92
  onlyOne = true,
@@ -67,7 +124,9 @@ export default function Accordion(props) {
67
124
 
68
125
  // TODO: Animate height. Possible help here: https://stackoverflow.com/a/57333550 and https://stackoverflow.com/a/64797961
69
126
  if (isActive) {
70
- rowProps.flex = 1;
127
+ if (onlyOne) {
128
+ rowProps.flex = 1;
129
+ }
71
130
  } else {
72
131
  rowProps.h = 0;
73
132
  rowProps.overflow = 'hidden'; // otherwise some elements mistakenly show
@@ -94,7 +153,7 @@ export default function Accordion(props) {
94
153
  >
95
154
  {header}
96
155
  </Pressable>
97
- <HStack {...rowProps} className="bg-[#f00]">
156
+ <HStack {...rowProps}>
98
157
  {content}
99
158
  </HStack>
100
159
  </VStack>;
@@ -129,7 +188,7 @@ export default function Accordion(props) {
129
188
  keyboardShouldPersistTaps="always"
130
189
  className="Accordion-ScrollView flex-1 w-full"
131
190
  contentContainerStyle={{
132
- height: '100%',
191
+ height: onlyOne ? '100%' : undefined,
133
192
  }}
134
193
  >
135
194
  <VStackNative
@@ -125,16 +125,20 @@ function Container(props) {
125
125
  localSouthIsCollapsedRef = useRef(southInitialIsCollapsed),
126
126
  localEastIsCollapsedRef = useRef(eastInitialIsCollapsed),
127
127
  localWestIsCollapsedRef = useRef(westInitialIsCollapsed),
128
+ isSplitterDraggingRef = useRef(false),
128
129
  onLayout = async (e) => {
129
- console.log('Container onLayout', e.nativeEvent.layout.width);
130
+ if (isSplitterDraggingRef.current) {
131
+ return;
132
+ }
130
133
  if (id) {
131
134
  // save prevScreenSize if changed
132
135
  const
133
- height = parseFloat(e.nativeEvent.layout.height),
134
- width = parseFloat(e.nativeEvent.layout.width),
136
+ height = windowSize?.height ?? parseFloat(e.nativeEvent.layout.height),
137
+ width = windowSize?.width ?? parseFloat(e.nativeEvent.layout.width),
135
138
  key = id + '-prevScreenSize',
136
139
  prevScreenSize = await getSaved(key);
137
- if (!prevScreenSize || prevScreenSize.width !== width || prevScreenSize.height !== height) {
140
+ const hasChanged = !prevScreenSize || Math.abs((prevScreenSize.width ?? 0) - width) > 1 || Math.abs((prevScreenSize.height ?? 0) - height) > 1;
141
+ if (hasChanged) {
138
142
  await setSaved(key, {
139
143
  height,
140
144
  width,
@@ -300,10 +304,12 @@ function Container(props) {
300
304
  }
301
305
  },
302
306
  onSplitterDragStart = () => {
307
+ isSplitterDraggingRef.current = true;
303
308
  setIsComponentsDisabled(true);
304
309
  },
305
310
  onSplitterDragStop = (delta, which) => {
306
311
  setIsComponentsDisabled(false);
312
+ isSplitterDraggingRef.current = false;
307
313
  switch(which) {
308
314
  case 'north':
309
315
  onNorthResize(delta);
@@ -1213,6 +1213,10 @@ function Form(props) {
1213
1213
  style.maxHeight = maxHeight;
1214
1214
  }
1215
1215
 
1216
+ const
1217
+ // allow horizontal layouts only if there are top-level columns, and screen is wide enough
1218
+ hasTopLevelColumns = _.some(items, (item) => item?.type === 'Column'),
1219
+ shouldUseHorizontalFormLayout = !isItemsCustomLayout && hasTopLevelColumns && containerWidth >= styles.FORM_ONE_COLUMN_THRESHOLD;
1216
1220
  let modeHeader = null,
1217
1221
  formButtons = null,
1218
1222
  scrollButtons = null,
@@ -1246,8 +1250,8 @@ function Form(props) {
1246
1250
  formComponents = buildFromItems();
1247
1251
  const formAncillaryComponents = buildAncillary();
1248
1252
  editor = <>
1249
- {containerWidth >= styles.FORM_ONE_COLUMN_THRESHOLD && !isItemsCustomLayout ? <HStack className="Form-formComponents-HStack p-4 gap-4 justify-center">{formComponents}</HStack> : null}
1250
- {containerWidth < styles.FORM_ONE_COLUMN_THRESHOLD || isItemsCustomLayout ? <VStack className="Form-formComponents-VStack p-4">{formComponents}</VStack> : null}
1253
+ {shouldUseHorizontalFormLayout ? <HStack className="Form-formComponents-HStack w-full min-w-0 p-4 gap-4 justify-start items-stretch">{formComponents}</HStack> : null}
1254
+ {!shouldUseHorizontalFormLayout ? <VStack className="Form-formComponents-VStack p-4">{formComponents}</VStack> : null}
1251
1255
  {formAncillaryComponents.length ? <VStack className="Form-AncillaryComponents m-2 pt-4 px-2">{formAncillaryComponents}</VStack> : null}
1252
1256
  </>;
1253
1257
 
@@ -1532,7 +1536,8 @@ function Form(props) {
1532
1536
  onScroll={onScroll}
1533
1537
  scrollEventThrottle={16 /* ms */}
1534
1538
  contentContainerStyle={{
1535
- // height: '100%',
1539
+ width: '100%',
1540
+ minWidth: '100%',
1536
1541
  }}
1537
1542
  >
1538
1543
  {scrollToTopAnchor}