@onehat/ui 0.4.57 → 0.4.58

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.4.57",
3
+ "version": "0.4.58",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -1,11 +1,12 @@
1
1
  import { useState, } from 'react';
2
2
  import {
3
+ Box,
3
4
  Text,
4
5
  VStack,
5
6
  } from '@project-components/Gluestack';
7
+ import isJson from '../../Functions/isJson.js';
6
8
  import Form from '../Form/Form.js';
7
9
  import Button from '../Buttons/Button.js';
8
- import CenterBox from '../Layout/CenterBox.js';
9
10
  import withComponent from '../Hoc/withComponent.js';
10
11
  import withAlert from '../Hoc/withAlert.js';
11
12
  import ChevronLeft from '../Icons/ChevronLeft.js';
@@ -23,6 +24,7 @@ function AsyncOperation(props) {
23
24
  action,
24
25
  Repository,
25
26
  formItems = [],
27
+ formStartingValues = {},
26
28
 
27
29
  // withComponent
28
30
  self,
@@ -40,7 +42,7 @@ function AsyncOperation(props) {
40
42
  setFooter(getFooter('processing'));
41
43
 
42
44
  const
43
- method = Repository.methods.post,
45
+ method = Repository.methods.edit,
44
46
  uri = Repository.getModel() + '/' + action,
45
47
  formValues = self.children.form.formGetValues(),
46
48
  result = await Repository._send(method, uri, formValues);
@@ -52,16 +54,19 @@ function AsyncOperation(props) {
52
54
  return;
53
55
  }
54
56
 
55
- let results = <CenterBox><Text>Success</Text></CenterBox>;
57
+ let results = <Text>Success</Text>;
56
58
  if (response.message) {
57
- const decodedMessage = JSON.parse(response.message);
58
- results = _.isArray(decodedMessage) ?
59
+ let message = response.message;
60
+ if (isJson(message)) {
61
+ message = JSON.parse(message);
62
+ }
63
+ results = _.isArray(message) ?
59
64
  <VStack>
60
- {decodedMessage?.map((line, ix)=> {
65
+ {message?.map((line, ix)=> {
61
66
  return <Text key={ix}>{line}</Text>;
62
67
  })}
63
- </VStack> :
64
- <Text>{decodedMessage}</Text>;
68
+ </VStack> :
69
+ <Text>{message}</Text>;
65
70
  }
66
71
  showResults(results);
67
72
  },
@@ -119,17 +124,19 @@ function AsyncOperation(props) {
119
124
  className="w-full h-full flex-1"
120
125
  disableFooter={true}
121
126
  items={formItems}
127
+ startingValues={formStartingValues}
122
128
  />,
123
129
  },
124
130
  {
125
131
  title: 'Results',
126
132
  icon: Stop,
127
133
  isDisabled: currentTabIx !== 1,
128
- content: results,
134
+ content: <Box className="p-2">{results}</Box>,
129
135
  },
130
136
  ]}
131
137
  currentTabIx={currentTabIx}
132
138
  canToggleCollapse={false}
139
+ tabsAreButtons={false}
133
140
  />
134
141
  </Panel>;
135
142
  }
@@ -0,0 +1,93 @@
1
+ import { forwardRef, useRef } from 'react';
2
+ import {
3
+ HStack,
4
+ Icon,
5
+ } from '@project-components/Gluestack';
6
+ import {
7
+ HORIZONTAL,
8
+ VERTICAL,
9
+ } from '../../Constants/Directions.js';
10
+ import withTooltip from '../Hoc/withTooltip.js';
11
+ import IconButton from '../Buttons/IconButton.js';
12
+ import Xmark from '../Icons/Xmark.js';
13
+ import UiGlobals from '../../UiGlobals.js';
14
+ import _ from 'lodash';
15
+
16
+ const Tab = forwardRef((props, ref) => {
17
+ let {
18
+ className,
19
+ direction,
20
+ isDisabled,
21
+ isCurrentTab,
22
+ text,
23
+ _text,
24
+ useIconOnly,
25
+ icon,
26
+ _icon,
27
+ useCloseBtn,
28
+ onClose,
29
+ onPress, // remove it from propsToPass
30
+ ...propsToPass
31
+ } = props,
32
+ styles = UiGlobals.styles;
33
+
34
+ if (!ref) {
35
+ ref = useRef();
36
+ }
37
+
38
+ if (isCurrentTab) {
39
+ className += ' ' + styles.TAB_BG_CURRENT;
40
+ _icon.className += ' ' + styles.TAB_ICON_COLOR_CURRENT;
41
+ _text.className += ' ' + styles.TAB_COLOR_CURRENT;
42
+ }
43
+ if (isDisabled) {
44
+ className += ' ' + styles.TAB_BG_DISABLED_2;
45
+ _icon.className += ' ' + styles.TAB_COLOR_DISABLED;
46
+ _text.className += ' ' + styles.TAB_COLOR_DISABLED;
47
+ }
48
+
49
+ let tab = null;
50
+ if (useIconOnly) {
51
+ tab = <HStack className={className + ' Tab px-[20px] py-2'}>
52
+ <Icon
53
+ {...propsToPass}
54
+ className={className}
55
+ ref={ref}
56
+ {..._icon}
57
+ as={icon}
58
+ />
59
+ </HStack>;
60
+ } else {
61
+ if (direction === VERTICAL) {
62
+ className += ' w-[200px]';
63
+ }
64
+
65
+ let closeBtn = null;
66
+ if (useCloseBtn) {
67
+ closeBtn = <IconButton
68
+ {...testProps('tabCloseButton-' + ix)}
69
+ onPress={onClose}
70
+ icon={Xmark}
71
+ _icon={_icon}
72
+ tooltip="Close Tab"
73
+ className="p-0"
74
+ />;
75
+ }
76
+ tab = <HStack
77
+ {...propsToPass}
78
+ className={className}
79
+ ref={ref}
80
+ >
81
+ <Icon
82
+ {..._icon}
83
+ as={icon}
84
+ />
85
+ <Text {..._text}>{text}</Text>
86
+ {closeBtn}
87
+ </HStack>;
88
+ }
89
+
90
+ return tab;
91
+ });
92
+
93
+ export default withTooltip(Tab);
@@ -1,7 +1,9 @@
1
1
  import { cloneElement, useState, useEffect, } from 'react';
2
2
  import {
3
+ Box,
3
4
  HStack,
4
5
  HStackNative,
6
+ Icon,
5
7
  ScrollView,
6
8
  VStack,
7
9
  VStackNative,
@@ -10,6 +12,8 @@ import {
10
12
  HORIZONTAL,
11
13
  VERTICAL,
12
14
  } from '../../Constants/Directions.js';
15
+ import Tab from './Tab.js';
16
+ import TabButton from './TabButton.js';
13
17
  import Button from '../Buttons/Button.js';
14
18
  import UiGlobals from '../../UiGlobals.js';
15
19
  import getComponentFromType from '../../Functions/getComponentFromType.js';
@@ -20,7 +24,6 @@ import Minimize from '../Icons/Minimize.js';
20
24
  import Maximize from '../Icons/Maximize.js';
21
25
  import getSaved from '../../Functions/getSaved.js';
22
26
  import setSaved from '../../Functions/setSaved.js';
23
- import Xmark from '../Icons/Xmark.js';
24
27
  import _ from 'lodash';
25
28
 
26
29
 
@@ -37,6 +40,7 @@ function TabBar(props) {
37
40
  disableCollapse = false,
38
41
  startsCollapsed = true,
39
42
  canToggleCollapse = true,
43
+ tabsAreButtons = true,
40
44
  onChangeCurrentTab,
41
45
  onChangeIsCollapsed,
42
46
  onPressTab,
@@ -88,9 +92,9 @@ function TabBar(props) {
88
92
  },
89
93
  renderToggleButton = () => {
90
94
  const {
91
- buttonProps: {
92
- className: buttonPropsClassName,
93
- ...buttonPropsToPass
95
+ tabProps: {
96
+ className: tabPropsClassName,
97
+ ...tabPropsToPass
94
98
  },
95
99
  textProps: {
96
100
  className: textPropsClassName,
@@ -100,9 +104,9 @@ function TabBar(props) {
100
104
  className: iconPropsClassName,
101
105
  ...iconPropsToPass
102
106
  },
103
- } = getButtonProps();
107
+ } = getTabProps();
104
108
 
105
- let buttonClassName = buttonPropsClassName,
109
+ let tabClassName = tabPropsClassName,
106
110
  textClassName = textPropsClassName,
107
111
  iconClassName = iconPropsClassName;
108
112
 
@@ -119,14 +123,14 @@ function TabBar(props) {
119
123
  {...testProps('toggleBtn')}
120
124
  key="toggleBtn"
121
125
  onPress={onPress}
122
- {...buttonPropsToPass}
126
+ {...tabPropsToPass}
123
127
  icon={icon}
124
128
  _icon={_icon}
125
- className={buttonClassName}
129
+ className={tabClassName}
126
130
  tooltip={isCollapsed ? 'Expand' : 'Collapse'}
127
131
  />;
128
132
  } else {
129
- buttonClassName += `
133
+ tabClassName += `
130
134
  ${direction === VERTICAL ? 'w-[200px]' : ''}
131
135
  pr-0
132
136
  mr-0
@@ -136,10 +140,10 @@ function TabBar(props) {
136
140
  {...testProps('toggleBtn')}
137
141
  key="toggleBtn"
138
142
  onPress={onPress}
139
- {...buttonPropsToPass}
143
+ {...tabPropsToPass}
140
144
  icon={icon}
141
145
  _icon={_icon}
142
- className={buttonClassName}
146
+ className={tabClassName}
143
147
  text="Collapse"
144
148
  _text={{
145
149
  className: textClassName,
@@ -151,15 +155,12 @@ function TabBar(props) {
151
155
  }
152
156
  return button;
153
157
  },
154
- getButtonProps = () => {
158
+ getTabProps = () => {
155
159
  const
156
- buttonProps = {
160
+ tabProps = {
157
161
  className: `
158
162
  ${styles.TAB_BG}
159
163
  ${isCollapsed ? 'justify-center' : 'justify-start'}
160
- ${styles.TAB_BG_HOVER}
161
- ${styles.TAB_BG_ACTIVE}
162
- ${styles.TAB_BG_DISABLED}
163
164
  `,
164
165
  },
165
166
  textProps = {
@@ -174,14 +175,11 @@ function TabBar(props) {
174
175
  // size: 'md',
175
176
  className: `
176
177
  ${styles.TAB_ICON_COLOR}
177
- ${styles.TAB_ICON_COLOR_HOVER}
178
- ${styles.TAB_ICON_COLOR_ACTIVE}
179
- ${styles.TAB_ICON_COLOR_DISABLED}
180
178
  `,
181
179
  };
182
180
  switch(direction) {
183
181
  case VERTICAL:
184
- buttonProps.className += `
182
+ tabProps.className += `
185
183
  rounded-l-lg
186
184
  rounded-r-none
187
185
  w-full
@@ -202,7 +200,7 @@ function TabBar(props) {
202
200
  `;
203
201
  break;
204
202
  case HORIZONTAL:
205
- buttonProps.className += `
203
+ tabProps.className += `
206
204
  rounded-t
207
205
  rounded-b-none
208
206
  mr-1
@@ -217,16 +215,16 @@ function TabBar(props) {
217
215
  default:
218
216
  }
219
217
  return {
220
- buttonProps,
218
+ tabProps,
221
219
  textProps,
222
220
  iconProps,
223
221
  };
224
222
  },
225
223
  renderTabs = () => {
226
224
  const {
227
- buttonProps: {
228
- className: buttonPropsClassName,
229
- ...buttonPropsToPass
225
+ tabProps: {
226
+ className: tabPropsClassName,
227
+ ...tabPropsToPass
230
228
  },
231
229
  textProps: {
232
230
  className: textPropsClassName,
@@ -236,8 +234,8 @@ function TabBar(props) {
236
234
  className: iconPropsClassName,
237
235
  ...iconPropsToPass
238
236
  },
239
- } = getButtonProps(),
240
- buttons = [];
237
+ } = getTabProps(),
238
+ tabComponents = [];
241
239
 
242
240
  _.each(tabs, (tab, ix) => {
243
241
  if (!tab.icon) {
@@ -245,7 +243,7 @@ function TabBar(props) {
245
243
  }
246
244
  const
247
245
  isCurrentTab = ix === getCurrentTab(),
248
- useIconButton = (isCollapsed || !tab.title),
246
+ useIconTab = (isCollapsed || !tab.title),
249
247
  tabIcon = tab._icon ? _.clone(tab._icon) : {};
250
248
  if (tabIcon.as && _.isString(tabIcon.as)) {
251
249
  const Type = getComponentFromType(tabIcon.as);
@@ -254,20 +252,13 @@ function TabBar(props) {
254
252
  }
255
253
  }
256
254
 
257
- let buttonClassName = buttonPropsClassName,
255
+ let tabClassName = tabPropsClassName,
258
256
  textClassName = textPropsClassName,
259
257
  iconClassName = iconPropsClassName;
260
258
 
261
- if (isCurrentTab) {
262
- buttonClassName += ' ' + styles.TAB_BG_CURRENT +
263
- ' ' + styles.TAB_BG_CURRENT_HOVER;
264
- iconClassName += ' ' + styles.TAB_ICON_COLOR_CURRENT;
265
- textClassName += ' ' + styles.TAB_COLOR_CURRENT;
266
- }
267
-
268
259
  // overrides
269
260
  if (tab._button?.className) {
270
- buttonClassName += ' ' + tab._button.className;
261
+ tabClassName += ' ' + tab._button.className;
271
262
  }
272
263
  if (tab._text?.className) {
273
264
  textClassName += ' ' + tab._text.className;
@@ -284,59 +275,28 @@ function TabBar(props) {
284
275
  },
285
276
  onPress = () => setCurrentTab(ix);
286
277
 
287
- let button;
288
- if (useIconButton) {
289
- button = <IconButton
290
- {...testProps(tab.path)}
291
- key={'tabIconBtn' + ix}
292
- onPress={onPress}
293
- {...buttonPropsToPass}
294
- icon={tab.icon}
295
- _icon={_icon}
296
- className={buttonClassName}
297
- tooltip={tab.title}
298
- isDisabled={tab.isDisabled}
299
- />;
300
- } else {
301
- if (direction === VERTICAL) {
302
- buttonClassName += ' w-[200px]';
303
- }
304
-
305
- let closeBtn = null;
306
- if (onTabClose && !tab.disableCloseBox) {
307
- closeBtn = <IconButton
308
- {...testProps('tabCloseButton-' + ix)}
309
- key={'tabCloseButton' + ix}
310
- onPress={() => onTabClose(ix)}
311
- icon={Xmark}
312
- _icon={{
313
- ...iconProps,
314
- className: iconClassName,
278
+ const WhichTabType = tabsAreButtons ? TabButton : Tab
279
+ tabComponents.push(<WhichTabType
280
+ {...testProps(tab.path)}
281
+ key={'tab' + ix}
282
+ onPress={onPress}
283
+ {...tabPropsToPass}
284
+ icon={tab.icon}
285
+ _icon={_icon}
286
+ className={tabClassName}
287
+ tooltip={tab.title}
288
+ text={tab.title}
289
+ _text={{
290
+ className: textClassName,
291
+ ...textPropsToPass,
315
292
  }}
316
- tooltip="Close Tab"
317
- className="p-0"
318
- />;
319
- }
320
- button = <Button
321
- {...testProps(tab.path)}
322
- key={'tabBtn' + ix}
323
- onPress={onPress}
324
- {...buttonPropsToPass}
325
- icon={tab.icon}
326
- _icon={_icon}
327
- rightIcon={closeBtn}
328
- className={buttonClassName}
329
- text={tab.title}
330
- _text={{
331
- className: textClassName,
332
- ...textPropsToPass,
333
- }}
334
- isDisabled={tab.isDisabled}
335
- action="none"
336
- variant="none"
337
- />;
338
- }
339
- buttons.push(button);
293
+ isDisabled={tab.isDisabled}
294
+ isCurrentTab={isCurrentTab}
295
+ useIconOnly={useIconTab}
296
+ direction={direction}
297
+ useCloseBtn={onTabClose && !tab.disableCloseBox}
298
+ onClose={() => onTabClose(ix)}
299
+ />);
340
300
  });
341
301
 
342
302
  if (additionalButtons) {
@@ -346,7 +306,7 @@ function TabBar(props) {
346
306
  }
347
307
 
348
308
  const
349
- useIconButton = (isCollapsed || !additionalButton.text),
309
+ useIconTab = (isCollapsed || !additionalButton.text),
350
310
  additionalButtonIcon = _.clone(additionalButton._icon);
351
311
 
352
312
  if (additionalButtonIcon.as && _.isString(additionalButtonIcon.as)) {
@@ -356,13 +316,13 @@ function TabBar(props) {
356
316
  }
357
317
  }
358
318
 
359
- let buttonClassName = buttonPropsClassName,
319
+ let tabClassName = tabPropsClassName,
360
320
  textClassName = textPropsClassName,
361
321
  iconClassName = iconPropsClassName;
362
322
 
363
323
  // overrides
364
324
  if (additionalButton._button?.className) {
365
- buttonClassName += ' ' + additionalButton._button.className;
325
+ tabClassName += ' ' + additionalButton._button.className;
366
326
  }
367
327
  if (additionalButton._text?.className) {
368
328
  textClassName += ' ' + additionalButton._text.className;
@@ -375,10 +335,10 @@ function TabBar(props) {
375
335
  // First button should have a gap before it
376
336
  switch(direction) {
377
337
  case VERTICAL:
378
- buttonClassName += ' mt-6';
338
+ tabClassName += ' mt-6';
379
339
  break;
380
340
  case HORIZONTAL:
381
- buttonClassName += ' ml-6';
341
+ tabClassName += ' ml-6';
382
342
  break;
383
343
  default:
384
344
  }
@@ -393,27 +353,27 @@ function TabBar(props) {
393
353
  onPress = additionalButton.onPress;
394
354
 
395
355
  let button;
396
- if (useIconButton) {
356
+ if (useIconTab) {
397
357
  button = <IconButton
398
358
  {...testProps('additionalBtn' + ix)}
399
359
  key={'additionalBtn' + ix}
400
360
  onPress={onPress}
401
- {...buttonPropsToPass}
361
+ {...tabPropsToPass}
402
362
  _icon={_icon}
403
- className={buttonClassName}
363
+ className={tabClassName}
404
364
  tooltip={additionalButton.text}
405
365
  />;
406
366
  } else {
407
367
  if (direction === VERTICAL) {
408
- buttonClassName += ' w-[200px]';
368
+ tabClassName += ' w-[200px]';
409
369
  }
410
370
  button = <Button
411
371
  {...testProps('additionalBtn' + ix)}
412
372
  key={'additionalBtn' + ix}
413
373
  onPress={onPress}
414
- {...buttonPropsToPass}
374
+ {...tabPropsToPass}
415
375
  _icon={_icon}
416
- className={buttonClassName}
376
+ className={tabClassName}
417
377
  text={additionalButton.text}
418
378
  _text={{
419
379
  className: textClassName,
@@ -423,11 +383,11 @@ function TabBar(props) {
423
383
  variant="none"
424
384
  />;
425
385
  }
426
- buttons.push(button);
386
+ tabComponents.push(button);
427
387
  });
428
388
  }
429
389
 
430
- return buttons;
390
+ return tabComponents;
431
391
  },
432
392
  renderCurrentTabContent = () => {
433
393
  if (content) {
@@ -0,0 +1,82 @@
1
+ import {
2
+ HORIZONTAL,
3
+ VERTICAL,
4
+ } from '../../Constants/Directions.js';
5
+ import Button from '../Buttons/Button.js';
6
+ import IconButton from '../Buttons/IconButton.js';
7
+ import Xmark from '../Icons/Xmark.js';
8
+ import UiGlobals from '../../UiGlobals.js';
9
+ import _ from 'lodash';
10
+
11
+
12
+ export default function TabButton(props) {
13
+ let {
14
+ className,
15
+ direction,
16
+ isDisabled,
17
+ isCurrentTab,
18
+ text,
19
+ _text,
20
+ useIconOnly,
21
+ _icon,
22
+ useCloseBtn,
23
+ onClose,
24
+ ...propsToPass
25
+ } = props,
26
+ styles = UiGlobals.styles;
27
+
28
+ className += ' ' + styles.TAB_BG_HOVER +
29
+ ' ' + styles.TAB_BG_ACTIVE;
30
+ _icon.className += ' ' + styles.TAB_ICON_COLOR_HOVER +
31
+ ' ' + styles.TAB_ICON_COLOR_ACTIVE;
32
+
33
+ if (isCurrentTab) {
34
+ className += ' ' + styles.TAB_BG_CURRENT +
35
+ ' ' + styles.TAB_BG_CURRENT_HOVER;
36
+ _icon.className += ' ' + styles.TAB_ICON_COLOR_CURRENT;
37
+ _text.className += ' ' + styles.TAB_COLOR_CURRENT;
38
+ }
39
+ if (isDisabled) {
40
+ className += ' ' + styles.TAB_BG_DISABLED;
41
+ _icon.className += ' ' + styles.TAB_ICON_COLOR_DISABLED;
42
+ _text.className += ' ' + styles.TAB_COLOR_DISABLED;
43
+ }
44
+
45
+ let tab = null;
46
+ if (useIconOnly) {
47
+ tab = <IconButton
48
+ {...propsToPass}
49
+ {..._icon}
50
+ className={className}
51
+ />;
52
+
53
+ } else {
54
+ if (direction === VERTICAL) {
55
+ className += ' w-[200px]';
56
+ }
57
+
58
+ let closeBtn = null;
59
+ if (useCloseBtn) {
60
+ closeBtn = <IconButton
61
+ {...testProps('tabCloseButton-' + ix)}
62
+ onPress={onClose}
63
+ icon={Xmark}
64
+ _icon={_icon}
65
+ tooltip="Close Tab"
66
+ className="p-0"
67
+ />;
68
+ }
69
+ tab = <Button
70
+ {...propsToPass}
71
+ className={className}
72
+ text={text}
73
+ _text={_text}
74
+ _icon={_icon}
75
+ rightIcon={closeBtn}
76
+ action="none"
77
+ variant="none"
78
+ />;
79
+ }
80
+
81
+ return tab;
82
+ }
@@ -103,12 +103,14 @@ const defaults = {
103
103
  TAB_BG_ACTIVE: 'active:bg-grey-900/50',
104
104
  TAB_BG_CURRENT: 'bg-grey-0',
105
105
  TAB_BG_DISABLED: 'disabled:bg-grey-200',
106
+ TAB_BG_DISABLED_2: 'bg-grey-200',
106
107
  TAB_BG_HOVER: 'hover:bg-grey-900/30',
107
108
  TAB_BG_ACTIVE_HOVER: 'hover:bg-grey-200',
108
109
  TAB_BG_CURRENT_HOVER: 'hover:bg-grey-900/30',
109
110
  TAB_COLOR: 'text-' + BLACK,
110
111
  TAB_COLOR_ACTIVE: 'active:text-primary-800',
111
- TAB_COLOR_CURRENT: 'active:text-primary-800',
112
+ TAB_COLOR_CURRENT: 'text-primary-800',
113
+ TAB_COLOR_DISABLED: 'text-grey-400',
112
114
  TAB_ICON_COLOR: 'text-' + BLACK,
113
115
  TAB_ICON_COLOR_ACTIVE: 'text-' + BLACK,
114
116
  TAB_ICON_COLOR_CURRENT: 'text-' + BLACK,