@onehat/ui 0.3.321 → 0.3.322

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.321",
3
+ "version": "0.3.322",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -82,6 +82,8 @@ function Form(props) {
82
82
  onReset,
83
83
  onInit,
84
84
  onViewMode,
85
+ onValidityChange,
86
+ onDirtyChange,
85
87
  submitBtnLabel,
86
88
  onSubmit,
87
89
  formSetup, // this fn will be executed after the form setup is complete
@@ -807,6 +809,18 @@ function Form(props) {
807
809
  };
808
810
  }, [Repository]);
809
811
 
812
+ if (onValidityChange) {
813
+ useEffect(() => {
814
+ onValidityChange(formState.isValid);
815
+ }, [formState.isValid]);
816
+ }
817
+
818
+ if (onDirtyChange) {
819
+ useEffect(() => {
820
+ onDirtyChange(formState.isDirty);
821
+ }, [formState.isDirty]);
822
+ }
823
+
810
824
  if (skipAll) {
811
825
  return null;
812
826
  }
@@ -821,6 +835,8 @@ function Form(props) {
821
835
 
822
836
  if (self) {
823
837
  self.ref = formRef;
838
+ self.reset = doReset;
839
+ self.submit = handleSubmit;
824
840
  self.formState = formState;
825
841
  self.formSetValue = formSetValue;
826
842
  self.formGetValues = formGetValues;
@@ -1,4 +1,4 @@
1
- import React, { useState, useRef, useEffect, } from 'react';
1
+ import React, { useState, useRef } from 'react';
2
2
  import {
3
3
  Box,
4
4
  Button,
@@ -8,7 +8,10 @@ import {
8
8
  Row,
9
9
  Text,
10
10
  } from 'native-base';
11
+ import Form from '../Form/Form.js';
11
12
  import Panel from '../Panel/Panel.js';
13
+ import IconButton from '../Buttons/IconButton.js';
14
+ import Rotate from '../Icons/Rotate.js';
12
15
  import TriangleExclamation from '../Icons/TriangleExclamation.js';
13
16
  import useAdjustedWindowSize from '../../Hooks/useAdjustedWindowSize.js';
14
17
  import testProps from '../../Functions/testProps.js';
@@ -31,19 +34,36 @@ export default function withModal(WrappedComponent) {
31
34
  [message, setMessage] = useState(''),
32
35
  [canClose, setCanClose] = useState(true),
33
36
  [includeCancel, setIncludeCancel] = useState(false),
37
+ [includeReset, setIncludeReset] = useState(false),
34
38
  [isModalShown, setIsModalShown] = useState(false),
39
+ [isValid, setIsValid] = useState(false),
40
+ [isDirty, setIsDirty] = useState(false),
35
41
  [h, setHeight] = useState(250),
36
42
  [w, setWidth] = useState(400),
37
43
  [onOk, setOnOk] = useState(),
38
44
  [okBtnLabel, setOkBtnLabel] = useState('OK'),
39
45
  [onYes, setOnYes] = useState(),
40
46
  [onNo, setOnNo] = useState(),
47
+ [onSubmit, setOnSubmit] = useState(),
48
+ [submitBtnLabel, setSubmitBtnLabel] = useState(),
41
49
  [customButtons, setCustomButtons] = useState(),
50
+ [formProps, setFormProps] = useState(),
51
+ [self, setSelf] = useState(),
42
52
  [color, setColor] = useState('#000'),
43
53
  [body, setBody] = useState(),
54
+ useForm = !!formProps, // convenience flag
44
55
  autoFocusRef = useRef(null),
45
56
  cancelRef = useRef(null),
46
57
  [width, height] = useAdjustedWindowSize(w, h),
58
+ onValidityChange = (isValid) => {
59
+ setIsValid(isValid);
60
+ },
61
+ onDirtyChange = (isDirty) => {
62
+ setIsDirty(isDirty);
63
+ },
64
+ onReset = () => {
65
+ self?.children?.ModalForm?.reset();
66
+ },
47
67
  onCancel = () => {
48
68
  setIsModalShown(false);
49
69
  },
@@ -51,35 +71,41 @@ export default function withModal(WrappedComponent) {
51
71
  const {
52
72
  title = '',
53
73
  message = '',
74
+ body,
54
75
  canClose = true,
55
76
  includeCancel = false,
56
77
  onOk,
57
78
  okBtnLabel,
58
79
  onYes,
59
80
  onNo,
81
+ onSubmit,
82
+ submitBtnLabel,
60
83
  customButtons,
84
+ includeReset = false,
85
+ formProps,
86
+ self,
61
87
  color,
62
- // formItems = {},
63
- body,
64
88
  h,
65
89
  w,
66
90
  } = args;
67
91
 
68
- if (!message && !body) {
69
- throw new Error('Either message or body is required for showModal');
92
+ if (!message && !body && !formProps) {
93
+ throw new Error('Either message, body, or formProps is required for showModal');
94
+ }
95
+ if (includeReset && !self) {
96
+ throw new Error('self is required when using includeReset');
70
97
  }
71
-
72
98
  if (title) {
73
99
  setTitle(title);
74
100
  }
75
101
  if (message) {
76
102
  setMessage(message);
77
103
  }
104
+ if (body) {
105
+ setBody(body);
106
+ }
78
107
  setCanClose(canClose);
79
108
  setIncludeCancel(includeCancel);
80
- if (onNo) {
81
- setOnNo(() => onNo);
82
- }
83
109
  if (onOk) {
84
110
  setOnOk(() => onOk);
85
111
  }
@@ -89,15 +115,28 @@ export default function withModal(WrappedComponent) {
89
115
  if (onYes) {
90
116
  setOnYes(() => onYes);
91
117
  }
118
+ if (onNo) {
119
+ setOnNo(() => onNo);
120
+ }
121
+ if (onSubmit) {
122
+ setOnSubmit(() => onSubmit);
123
+ }
124
+ if (submitBtnLabel) {
125
+ setSubmitBtnLabel(submitBtnLabel);
126
+ }
92
127
  if (customButtons) {
93
128
  setCustomButtons(customButtons);
94
129
  }
130
+ setIncludeReset(includeReset);
131
+ if (formProps) {
132
+ setFormProps(formProps);
133
+ }
134
+ if (self) {
135
+ setSelf(self);
136
+ }
95
137
  if (color) {
96
138
  setColor(color);
97
139
  }
98
- if (body) {
99
- setBody(body);
100
- }
101
140
  if (h) {
102
141
  setHeight(h);
103
142
  }
@@ -111,6 +150,19 @@ export default function withModal(WrappedComponent) {
111
150
  let buttons = [];
112
151
  if (isModalShown) {
113
152
  // assemble buttons
153
+ if (includeReset) {
154
+ buttons.push(<IconButton
155
+ {...testProps('resetBtn')}
156
+ key="resetBtn"
157
+ onPress={onReset}
158
+ icon={Rotate}
159
+ _icon={{
160
+ color: !isDirty ? 'trueGray.400' : '#000',
161
+ }}
162
+ isDisabled={!isDirty}
163
+ mr={2}
164
+ />);
165
+ }
114
166
  if (includeCancel) {
115
167
  buttons.push(<Button
116
168
  {...testProps('cancelBtn')}
@@ -147,6 +199,15 @@ export default function withModal(WrappedComponent) {
147
199
  onPress={onYes}
148
200
  >Yes</Button>);
149
201
  }
202
+ if (useForm && onSubmit) {
203
+ buttons.push(<Button
204
+ {...testProps('submitBtn')}
205
+ key="submitBtn"
206
+ onPress={onSubmit}
207
+ isDisabled={!isValid}
208
+ color="#fff"
209
+ >{submitBtnLabel || 'Submit'}</Button>);
210
+ }
150
211
  if (customButtons) {
151
212
  _.each(customButtons, (button) => {
152
213
  buttons.push(button);
@@ -154,6 +215,25 @@ export default function withModal(WrappedComponent) {
154
215
  }
155
216
  }
156
217
 
218
+ let modalBody = null;
219
+ if (useForm) {
220
+ modalBody = <Form
221
+ {...formProps}
222
+ reference="ModalForm"
223
+ onValidityChange={onValidityChange}
224
+ onDirtyChange={onDirtyChange}
225
+ />;
226
+ } else if (body) {
227
+ modalBody = body;
228
+ } else {
229
+ modalBody = <>
230
+ <Box w="50px" mx={2}>
231
+ <Icon as={TriangleExclamation} color={color} size="10" />
232
+ </Box>
233
+ <Text flex={1} color={color} fontSize="18px">{message}</Text>
234
+ </>;
235
+ }
236
+
157
237
  return <>
158
238
  <WrappedComponent
159
239
  {...props}
@@ -185,13 +265,7 @@ export default function withModal(WrappedComponent) {
185
265
  borderRadius={5}
186
266
  flexDirection="row"
187
267
  >
188
- {body ||
189
- <>
190
- <Box w="50px" mx={2}>
191
- <Icon as={TriangleExclamation} color={color} size="10" />
192
- </Box>
193
- <Text flex={1} color={color} fontSize="18px">{message}</Text>
194
- </>}
268
+ {modalBody}
195
269
  </Modal.Body>
196
270
  <Modal.Footer py={2} pr={4} justifyContent="flex-end">
197
271
  {buttons}