@onehat/ui 0.3.295 → 0.3.298

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.295",
3
+ "version": "0.3.298",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -31,6 +31,7 @@ import inArray from '../../Functions/inArray.js';
31
31
  import getComponentFromType from '../../Functions/getComponentFromType.js';
32
32
  import buildAdditionalButtons from '../../Functions/buildAdditionalButtons.js';
33
33
  import testProps from '../../Functions/testProps.js';
34
+ import Toolbar from '../Toolbar/Toolbar.js';
34
35
  import Button from '../Buttons/Button.js';
35
36
  import IconButton from '../Buttons/IconButton.js';
36
37
  import AngleLeft from '../Icons/AngleLeft.js';
@@ -88,6 +89,7 @@ function Form(props) {
88
89
  additionalEditButtons,
89
90
  useAdditionalEditButtons = true,
90
91
  additionalFooterButtons,
92
+ disableFooter = false,
91
93
 
92
94
  // sizing of outer container
93
95
  h,
@@ -847,7 +849,8 @@ function Form(props) {
847
849
  }
848
850
 
849
851
  const formButtons = [];
850
- let formComponents,
852
+ let modeHeader = null,
853
+ formComponents,
851
854
  editor,
852
855
  additionalButtons,
853
856
  isSaveDisabled = false,
@@ -888,16 +891,23 @@ function Form(props) {
888
891
 
889
892
  additionalButtons = buildAdditionalButtons(additionalEditButtons);
890
893
 
891
- formButtons.push(<Row key="buttonsRow" px={4} pt={4} alignItems="center" justifyContent="flex-end">
892
- {isSingle && editorMode === EDITOR_MODE__EDIT && onBack &&
893
- <Button
894
- {...testProps('backBtn')}
895
- key="backBtn"
896
- onPress={onBack}
897
- leftIcon={<Icon as={AngleLeft} color="#fff" size="sm" />}
898
- color="#fff"
899
- >Back</Button>}
900
- {isSingle && editorMode === EDITOR_MODE__EDIT && onViewMode && !disableView &&
894
+ if (inArray(editorType, [EDITOR_TYPE__SIDE, EDITOR_TYPE__SMART, EDITOR_TYPE__WINDOWED]) &&
895
+ isSingle && editorMode === EDITOR_MODE__EDIT &&
896
+ (onBack || (onViewMode && !disableView))) {
897
+ modeHeader = <Toolbar>
898
+ <Row flex={1} alignItems="center">
899
+ {onBack &&
900
+ <Button
901
+ {...testProps('backBtn')}
902
+ key="backBtn"
903
+ onPress={onBack}
904
+ leftIcon={<Icon as={AngleLeft} color="#fff" size="sm" />}
905
+ color="#fff"
906
+ mr={4}
907
+ >Back</Button>}
908
+ <Text fontSize={20} ml={2} color="trueGray.500">Edit Mode</Text>
909
+ </Row>
910
+ {onViewMode && !disableView &&
901
911
  <Button
902
912
  {...testProps('toViewBtn')}
903
913
  key="viewBtn"
@@ -905,11 +915,12 @@ function Form(props) {
905
915
  leftIcon={<Icon as={Eye} color="#fff" size="sm" />}
906
916
  color="#fff"
907
917
  >To View</Button>}
908
- </Row>);
918
+ </Toolbar>;
919
+ }
909
920
  if (editorMode === EDITOR_MODE__EDIT && !_.isEmpty(additionalButtons)) {
910
- formButtons.push(<Row key="additionalButtonsRow" p={4} alignItems="center" justifyContent="flex-end" flexWrap="wrap">
921
+ formButtons.push(<Toolbar justifyContent="flex-end" flexWrap="wrap">
911
922
  {additionalButtons}
912
- </Row>)
923
+ </Toolbar>)
913
924
  }
914
925
  }
915
926
 
@@ -947,23 +958,9 @@ function Form(props) {
947
958
  showCloseBtn = true;
948
959
  } else {
949
960
  const formIsDirty = formState.isDirty;
950
- // console.log('formIsDirty', formIsDirty);
951
- // console.log('isPhantom', isPhantom);
952
-
953
-
954
-
955
-
956
- // LEFT OFF HERE
957
- // The code I wrote below was supposed to be for the Tree search but messed up the standard
958
- // windowed editors. Need to figure out how to make it work for both.
959
- // Also, when crudding two records on the same tree in succession, the second record throws an error.
960
-
961
-
962
-
963
-
964
- if (editorType === EDITOR_TYPE__WINDOWED && onCancel) {
965
- showCancelBtn = true;
966
- }
961
+ // if (editorType === EDITOR_TYPE__WINDOWED && onCancel) {
962
+ // showCancelBtn = true;
963
+ // }
967
964
  if (formIsDirty || isPhantom) {
968
965
  if (isSingle && onCancel) {
969
966
  showCancelBtn = true;
@@ -998,84 +995,86 @@ function Form(props) {
998
995
  >{editor}</Row>}
999
996
  {editorType !== EDITOR_TYPE__INLINE &&
1000
997
  <ScrollView _web={{ minHeight, }} width="100%" pb={1}>
998
+ {modeHeader}
1001
999
  {formHeader}
1002
1000
  {formButtons}
1003
1001
  {editor}
1004
1002
  </ScrollView>}
1005
1003
 
1006
- <Footer justifyContent="flex-end" {...footerProps} {...savingProps}>
1007
- {onDelete && editorMode === EDITOR_MODE__EDIT && isSingle &&
1004
+ {!disableFooter &&
1005
+ <Footer justifyContent="flex-end" {...footerProps} {...savingProps}>
1006
+ {onDelete && editorMode === EDITOR_MODE__EDIT && isSingle &&
1008
1007
 
1009
- <Row flex={1} justifyContent="flex-start">
1010
- <Button
1011
- {...testProps('deleteBtn')}
1012
- key="deleteBtn"
1013
- onPress={onDelete}
1014
- bg="warning"
1015
- _hover={{
1016
- bg: 'warningHover',
1008
+ <Row flex={1} justifyContent="flex-start">
1009
+ <Button
1010
+ {...testProps('deleteBtn')}
1011
+ key="deleteBtn"
1012
+ onPress={onDelete}
1013
+ bg="warning"
1014
+ _hover={{
1015
+ bg: 'warningHover',
1016
+ }}
1017
+ color="#fff"
1018
+ >Delete</Button>
1019
+ </Row>}
1020
+
1021
+ {showResetBtn &&
1022
+ <IconButton
1023
+ {...testProps('resetBtn')}
1024
+ key="resetBtn"
1025
+ onPress={() => doReset()}
1026
+ icon={Rotate}
1027
+ _icon={{
1028
+ color: !formState.isDirty ? 'trueGray.400' : '#000',
1017
1029
  }}
1018
- color="#fff"
1019
- >Delete</Button>
1020
- </Row>}
1030
+ isDisabled={!formState.isDirty}
1031
+ mr={2}
1032
+ />}
1021
1033
 
1022
- {showResetBtn &&
1023
- <IconButton
1024
- {...testProps('resetBtn')}
1025
- key="resetBtn"
1026
- onPress={() => doReset()}
1027
- icon={Rotate}
1028
- _icon={{
1029
- color: !formState.isDirty ? 'trueGray.400' : '#000',
1030
- }}
1031
- isDisabled={!formState.isDirty}
1032
- mr={2}
1033
- />}
1034
+ {showCancelBtn &&
1035
+ <Button
1036
+ {...testProps('cancelBtn')}
1037
+ key="cancelBtn"
1038
+ variant="ghost"
1039
+ onPress={onCancel}
1040
+ color="#fff"
1041
+ >Cancel</Button>}
1042
+
1043
+ {showCloseBtn &&
1044
+ <Button
1045
+ {...testProps('closeBtn')}
1046
+ key="closeBtn"
1047
+ variant="ghost"
1048
+ onPress={onClose}
1049
+ color="#fff"
1050
+ >Close</Button>}
1034
1051
 
1035
- {showCancelBtn &&
1036
- <Button
1037
- {...testProps('cancelBtn')}
1038
- key="cancelBtn"
1039
- variant="ghost"
1040
- onPress={onCancel}
1041
- color="#fff"
1042
- >Cancel</Button>}
1052
+ {showSaveBtn &&
1053
+ <Button
1054
+ {...testProps('saveBtn')}
1055
+ key="saveBtn"
1056
+ onPress={(e) => handleSubmit(onSaveDecorated, onSubmitError)(e)}
1057
+ isDisabled={isSaveDisabled}
1058
+ color="#fff"
1059
+ >{editorMode === EDITOR_MODE__ADD ? 'Add' : 'Save'}</Button>}
1043
1060
 
1044
- {showCloseBtn &&
1045
- <Button
1046
- {...testProps('closeBtn')}
1047
- key="closeBtn"
1048
- variant="ghost"
1049
- onPress={onClose}
1050
- color="#fff"
1051
- >Close</Button>}
1052
-
1053
- {showSaveBtn &&
1054
- <Button
1055
- {...testProps('saveBtn')}
1056
- key="saveBtn"
1057
- onPress={(e) => handleSubmit(onSaveDecorated, onSubmitError)(e)}
1058
- isDisabled={isSaveDisabled}
1059
- color="#fff"
1060
- >{editorMode === EDITOR_MODE__ADD ? 'Add' : 'Save'}</Button>}
1061
+ {showSubmitBtn &&
1062
+ <Button
1063
+ {...testProps('submitBtn')}
1064
+ key="submitBtn"
1065
+ onPress={(e) => handleSubmit(onSubmitDecorated, onSubmitError)(e)}
1066
+ isDisabled={isSubmitDisabled}
1067
+ color="#fff"
1068
+ >{submitBtnLabel || 'Submit'}</Button>}
1061
1069
 
1062
- {showSubmitBtn &&
1063
- <Button
1064
- {...testProps('submitBtn')}
1065
- key="submitBtn"
1066
- onPress={(e) => handleSubmit(onSubmitDecorated, onSubmitError)(e)}
1067
- isDisabled={isSubmitDisabled}
1068
- color="#fff"
1069
- >{submitBtnLabel || 'Submit'}</Button>}
1070
-
1071
- {additionalFooterButtons && _.map(additionalFooterButtons, (props) => {
1072
- return <Button
1073
- {...testProps('additionalFooterBtn-' + props.key)}
1074
- {...props}
1075
- onPress={(e) => handleSubmit(props.onPress, onSubmitError)(e)}
1076
- >{props.text}</Button>;
1077
- })}
1078
- </Footer>
1070
+ {additionalFooterButtons && _.map(additionalFooterButtons, (props) => {
1071
+ return <Button
1072
+ {...testProps('additionalFooterBtn-' + props.key)}
1073
+ {...props}
1074
+ onPress={(e) => handleSubmit(props.onPress, onSubmitError)(e)}
1075
+ >{props.text}</Button>;
1076
+ })}
1077
+ </Footer>}
1079
1078
  </>}
1080
1079
  </Column>;
1081
1080
  }
@@ -20,6 +20,9 @@ import TriangleExclamation from '../Icons/TriangleExclamation.js';
20
20
  import CircleInfo from '../Icons/CircleInfo.js';
21
21
  import _ from 'lodash';
22
22
 
23
+ // This HOC enables easy usage of alert dialogs in the wrapped component.
24
+ // It can be used for simple alerts, confirmations, and custom dialogs.
25
+
23
26
  export default function withAlert(WrappedComponent) {
24
27
  return (props) => {
25
28
 
@@ -14,6 +14,11 @@ import useAdjustedWindowSize from '../../Hooks/useAdjustedWindowSize.js';
14
14
  import testProps from '../../Functions/testProps.js';
15
15
  import _ from 'lodash';
16
16
 
17
+ // This HOC enables easy usage of more complex dialogs in the wrapped component.
18
+ // Add en embedded Form,
19
+
20
+ // Use withAlert for simple alerts, confirmations, and custom dialogs.
21
+
17
22
  export default function withModal(WrappedComponent) {
18
23
  return (props) => {
19
24
 
@@ -27,14 +32,17 @@ export default function withModal(WrappedComponent) {
27
32
  [canClose, setCanClose] = useState(true),
28
33
  [includeCancel, setIncludeCancel] = useState(false),
29
34
  [isModalShown, setIsModalShown] = useState(false),
35
+ [h, setHeight] = useState(250),
36
+ [w, setWidth] = useState(400),
30
37
  [onOk, setOnOk] = useState(),
31
38
  [onYes, setOnYes] = useState(),
32
39
  [onNo, setOnNo] = useState(),
33
40
  [customButtons, setCustomButtons] = useState(),
34
41
  [color, setColor] = useState('#000'),
42
+ [body, setBody] = useState(),
35
43
  autoFocusRef = useRef(null),
36
44
  cancelRef = useRef(null),
37
- [width, height] = useAdjustedWindowSize(400, 250),
45
+ [width, height] = useAdjustedWindowSize(w, h),
38
46
  onCancel = () => {
39
47
  setIsModalShown(false);
40
48
  },
@@ -49,58 +57,65 @@ export default function withModal(WrappedComponent) {
49
57
  onNo,
50
58
  customButtons,
51
59
  color,
60
+ // formItems = {},
61
+ body,
62
+ h,
63
+ w,
52
64
  } = args;
53
65
 
66
+ if (!message && !body) {
67
+ throw new Error('Either message or body is required for showModal');
68
+ }
69
+
54
70
  if (title) {
55
71
  setTitle(title);
56
72
  }
57
- if (!message) {
58
- throw new Error('Message is required for showModal');
73
+ if (message) {
74
+ setMessage(message);
59
75
  }
60
- setMessage(message);
61
76
  setCanClose(canClose);
62
77
  setIncludeCancel(includeCancel);
78
+ if (onNo) {
79
+ setOnNo(() => onNo);
80
+ }
63
81
  if (onOk) {
64
82
  setOnOk(() => onOk);
65
83
  }
66
84
  if (onYes) {
67
85
  setOnYes(() => onYes);
68
86
  }
69
- if (onNo) {
70
- setOnNo(() => onNo);
71
- }
72
87
  if (customButtons) {
73
88
  setCustomButtons(customButtons);
74
89
  }
75
90
  if (color) {
76
91
  setColor(color);
77
92
  }
93
+ if (body) {
94
+ setBody(body);
95
+ }
96
+ if (h) {
97
+ setHeight(h);
98
+ }
99
+ if (w) {
100
+ setWidth(w);
101
+ }
78
102
 
79
103
  setIsModalShown(true);
80
104
  };
81
105
 
82
106
  let buttons = [];
83
107
  if (isModalShown) {
108
+ // assemble buttons
84
109
  if (includeCancel) {
85
110
  buttons.push(<Button
86
111
  {...testProps('cancelBtn')}
87
112
  key="cancelBtn"
88
113
  onPress={onCancel}
89
- color="#fff"
90
114
  colorScheme="coolGray"
91
115
  variant="ghost" // or unstyled
92
116
  ref={cancelRef}
93
117
  >Cancel</Button>);
94
118
  }
95
- if (onOk) {
96
- buttons.push(<Button
97
- {...testProps('okBtn')}
98
- key="okBtn"
99
- ref={autoFocusRef}
100
- onPress={onOk}
101
- color="#fff"
102
- >OK</Button>);
103
- }
104
119
  if (onNo) {
105
120
  buttons.push(<Button
106
121
  {...testProps('noBtn')}
@@ -108,18 +123,23 @@ export default function withModal(WrappedComponent) {
108
123
  onPress={onNo}
109
124
  color="trueGray.800"
110
125
  variant="ghost"
111
- // colorScheme="neutral"
112
126
  mr={2}
113
127
  >No</Button>);
114
128
  }
129
+ if (onOk) {
130
+ buttons.push(<Button
131
+ {...testProps('okBtn')}
132
+ key="okBtn"
133
+ ref={autoFocusRef}
134
+ onPress={onOk}
135
+ >OK</Button>);
136
+ }
115
137
  if (onYes) {
116
138
  buttons.push(<Button
117
139
  {...testProps('yesBtn')}
118
140
  key="yesBtn"
119
141
  ref={autoFocusRef}
120
142
  onPress={onYes}
121
- color="#fff"
122
- // colorScheme="danger"
123
143
  >Yes</Button>);
124
144
  }
125
145
  if (customButtons) {
@@ -150,21 +170,24 @@ export default function withModal(WrappedComponent) {
150
170
  h={height}
151
171
  flex={null}
152
172
  >
153
-
173
+ {canClose && <Modal.CloseButton />}
154
174
  {title && <Modal.Header>{title}</Modal.Header>}
155
175
  <Modal.Body
156
176
  borderTopWidth={0}
157
177
  bg="#fff"
158
178
  p={3}
159
- justifyContent="center"
179
+ justifyContent=" center"
160
180
  alignItems="center"
161
181
  borderRadius={5}
162
182
  flexDirection="row"
163
183
  >
164
- <Box w="50px" mx={2}>
165
- <Icon as={TriangleExclamation} color={color} size="10" />
166
- </Box>
167
- <Text flex={1} color={color} fontSize="18px">{message}</Text>
184
+ {body ||
185
+ <>
186
+ <Box w="50px" mx={2}>
187
+ <Icon as={TriangleExclamation} color={color} size="10" />
188
+ </Box>
189
+ <Text flex={1} color={color} fontSize="18px">{message}</Text>
190
+ </>}
168
191
  </Modal.Body>
169
192
  <Modal.Footer py={2} pr={4} justifyContent="flex-end">
170
193
  {buttons}
@@ -80,7 +80,17 @@ export default function Header(props) {
80
80
  }
81
81
  }}
82
82
  >
83
- <Column alignItems="center" justifyContent="flex-start" h="100%" w="100%" bg={styles.PANEL_HEADER_BG_VERTICAL} style={{ userSelect: 'none', }} testID={testID}>
83
+ <Column
84
+ alignItems="center"
85
+ justifyContent="flex-start"
86
+ h="100%"
87
+ w="100%"
88
+ bg={styles.PANEL_HEADER_BG_VERTICAL}
89
+ borderBottomWidth={styles.PANEL_HEADER_BORDER_BOTTOM_WIDTH}
90
+ borderBottomColor={styles.PANEL_HEADER_BORDER_BOTTOM_COLOR}
91
+ style={{ userSelect: 'none', }}
92
+ testID={testID}
93
+ >
84
94
  {collapseBtn}
85
95
  <div style={{ textOrientation: 'mixed', writingMode: 'vertical-rl', }}>
86
96
  <Text flex={1} fontSize={styles.PANEL_HEADER_TEXT_FONTSIZE} color={styles.PANEL_HEADER_TEXT_COLOR} numberOfLines={1} ellipsizeMode="head" testID="text">{title}</Text>
@@ -99,7 +109,16 @@ export default function Header(props) {
99
109
  }
100
110
  }}
101
111
  >
102
- <Row alignItems="center" justifyContent="flex-start" px={styles.PANEL_HEADER_PX} py={styles.PANEL_HEADER_PY} bg={styles.PANEL_HEADER_BG} style={{ userSelect: 'none', }} testID={testID}>
112
+ <Row
113
+ alignItems="center"
114
+ justifyContent="flex-start"
115
+ px={styles.PANEL_HEADER_PX}
116
+ py={styles.PANEL_HEADER_PY}
117
+ bg={styles.PANEL_HEADER_BG}
118
+ borderBottomWidth={styles.PANEL_HEADER_BORDER_BOTTOM_WIDTH}
119
+ borderBottomColor={styles.PANEL_HEADER_BORDER_BOTTOM_COLOR}
120
+ style={{ userSelect: 'none', }}
121
+ testID={testID}>
103
122
  {closeBtn}
104
123
  <Text flex={1} fontSize={styles.PANEL_HEADER_TEXT_FONTSIZE} color={styles.PANEL_HEADER_TEXT_COLOR} numberOfLines={1} ellipsizeMode="head" testID="text">{title}</Text>
105
124
  {collapseBtn}
@@ -128,6 +147,8 @@ export default function Header(props) {
128
147
  h="100%"
129
148
  w="100%"
130
149
  bg={styles.PANEL_HEADER_BG_VERTICAL}
150
+ borderBottomWidth={styles.PANEL_HEADER_BORDER_BOTTOM_WIDTH}
151
+ borderBottomColor={styles.PANEL_HEADER_BORDER_BOTTOM_COLOR}
131
152
  >
132
153
  {collapseBtn}
133
154
  <Column
@@ -167,6 +188,8 @@ export default function Header(props) {
167
188
  px={styles.PANEL_HEADER_PX}
168
189
  py={styles.PANEL_HEADER_PY}
169
190
  bg={styles.PANEL_HEADER_BG}
191
+ borderBottomWidth={styles.PANEL_HEADER_BORDER_BOTTOM_WIDTH}
192
+ borderBottomColor={styles.PANEL_HEADER_BORDER_BOTTOM_COLOR}
170
193
  >
171
194
  {closeBtn}
172
195
  <Text
@@ -16,6 +16,7 @@ import inArray from '../../Functions/inArray.js';
16
16
  import getComponentFromType from '../../Functions/getComponentFromType.js';
17
17
  import buildAdditionalButtons from '../../Functions/buildAdditionalButtons.js';
18
18
  import testProps from '../../Functions/testProps.js';
19
+ import Toolbar from '../Toolbar/Toolbar.js';
19
20
  import Button from '../Buttons/Button.js';
20
21
  import Label from '../Form/Label.js';
21
22
  import Pencil from '../Icons/Pencil.js';
@@ -254,7 +255,10 @@ function Viewer(props) {
254
255
 
255
256
  <ScrollView _web={{ height: 1 }} width="100%" pb={1} ref={scrollViewRef}>
256
257
  {canEdit && onEditMode &&
257
- <Row px={4} pt={4} alignItems="center" justifyContent="flex-end">
258
+ <Toolbar justifyContent="flex-end">
259
+ <Row flex={1} alignItems="center">
260
+ <Text fontSize={20} ml={2} color="trueGray.500">View Mode</Text>
261
+ </Row>
258
262
  <Button
259
263
  {...testProps('toEditBtn')}
260
264
  key="editBtn"
@@ -262,11 +266,11 @@ function Viewer(props) {
262
266
  leftIcon={<Icon as={Pencil} color="#fff" size="sm" />}
263
267
  color="#fff"
264
268
  >To Edit</Button>
265
- </Row>}
269
+ </Toolbar>}
266
270
  {!_.isEmpty(additionalButtons) &&
267
- <Row p={4} alignItems="center" justifyContent="flex-end" flexWrap="wrap">
271
+ <Toolbar justifyContent="flex-end" flexWrap="wrap">
268
272
  {additionalButtons}
269
- </Row>}
273
+ </Toolbar>}
270
274
  <Column>
271
275
  {containerWidth >= CONTAINER_THRESHOLD ? <Row p={4} pl={0}>{viewerComponents}</Row> : null}
272
276
  {containerWidth < CONTAINER_THRESHOLD ? <Column p={4}>{viewerComponents}</Column> : null}
@@ -87,6 +87,8 @@ const defaults = {
87
87
  ICON_BUTTON_PY: 2,
88
88
  INLINE_EDITOR_MIN_WIDTH: 150,
89
89
  PANEL_FOOTER_BG: 'primary.100', // :alpha.50
90
+ PANEL_HEADER_BORDER_BOTTOM_COLOR: 'trueGray.400',
91
+ PANEL_HEADER_BORDER_BOTTOM_WIDTH: 1,
90
92
  PANEL_HEADER_BG: 'primary.100',
91
93
  PANEL_HEADER_BG_VERTICAL: 'primary.100',
92
94
  PANEL_HEADER_ICON_COLOR: WHITE,