@onehat/ui 0.2.36 → 0.2.38

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.2.36",
3
+ "version": "0.2.38",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -119,7 +119,7 @@ export default function Container(props) {
119
119
  }
120
120
  if (east) {
121
121
  componentProps.collapseDirection = HORIZONTAL;
122
- if (!east.props.h && !east.props.flex) {
122
+ if (!east.props.w && !east.props.flex) {
123
123
  componentProps.flex = 50;
124
124
  }
125
125
  if (canResize && east.props.isResizable) {
@@ -143,7 +143,7 @@ export default function Container(props) {
143
143
  }
144
144
  if (west) {
145
145
  componentProps.collapseDirection = HORIZONTAL;
146
- if (!west.props.h && !west.props.flex) {
146
+ if (!west.props.w && !west.props.flex) {
147
147
  componentProps.flex = 50;
148
148
  }
149
149
  if (canResize && west.props.isResizable) {
@@ -1,6 +1,8 @@
1
1
  import React from 'react';
2
2
  import {
3
+ Row,
3
4
  Switch,
5
+ Text,
4
6
  } from 'native-base';
5
7
  import UiGlobals from '../../../UiGlobals.js';
6
8
  import withTooltip from '../../Hoc/withTooltip.js';
@@ -19,21 +21,24 @@ const
19
21
  setValue(!value);
20
22
  };
21
23
 
22
- return <Switch
23
- ref={props.outerRef}
24
- onToggle={onToggle}
25
- isChecked={!!value}
26
- // flex={1}
27
- bg={styles.FORM_TOGGLE_BG}
28
- size={styles.FORM_TOGGLE_SIZE}
29
- onTrackColor={styles.FORM_TOGGLE_ON_COLOR}
30
- offTrackColor={styles.FORM_TOGGLE_OFF_COLOR}
31
- _hover={{
32
- onTrackColor: styles.FORM_TOGGLE_ON_HOVER_COLOR,
33
- offTrackColor: styles.FORM_TOGGLE_OFF_HOVER_COLOR,
34
- }}
35
- {...propsToPass}
36
- />;
24
+ return <Row alignItems="center">
25
+ <Switch
26
+ ref={props.outerRef}
27
+ onToggle={onToggle}
28
+ isChecked={!!value}
29
+ // flex={1}
30
+ bg={styles.FORM_TOGGLE_BG}
31
+ size={styles.FORM_TOGGLE_SIZE}
32
+ onTrackColor={styles.FORM_TOGGLE_ON_COLOR}
33
+ offTrackColor={styles.FORM_TOGGLE_OFF_COLOR}
34
+ _hover={{
35
+ onTrackColor: styles.FORM_TOGGLE_ON_HOVER_COLOR,
36
+ offTrackColor: styles.FORM_TOGGLE_OFF_HOVER_COLOR,
37
+ }}
38
+ {...propsToPass}
39
+ />
40
+ <Text fontSize={styles.FORM_TOGGLE_FONTSIZE}>{!!value ? 'Yes' : 'No'}</Text>
41
+ </Row>;
37
42
  },
38
43
  ToggleField = withValue(ToggleElement);
39
44
 
@@ -9,11 +9,12 @@ import {
9
9
  Text,
10
10
  } from 'native-base';
11
11
  import {
12
- EDITOR_TYPE_INLINE,
13
- EDITOR_TYPE_WINDOWED,
14
- EDITOR_TYPE_SMART,
15
- EDITOR_TYPE_PLAIN,
16
- } from '../../Constants/EditorTypes.js';
12
+ EDITOR_TYPE__INLINE,
13
+ EDITOR_TYPE__WINDOWED,
14
+ EDITOR_TYPE__SIDE,
15
+ EDITOR_TYPE__SMART,
16
+ EDITOR_TYPE__PLAIN,
17
+ } from '../../Constants/Editor.js';
17
18
  import { useForm, Controller } from 'react-hook-form'; // https://react-hook-form.com/api/
18
19
  import * as yup from 'yup'; // https://github.com/jquense/yup#string
19
20
  import { yupResolver } from '@hookform/resolvers/yup';
@@ -23,6 +24,7 @@ import withEditor from '../Hoc/withEditor.js';
23
24
  import inArray from '../../Functions/inArray.js';
24
25
  import getComponentFromType from '../../Functions/getComponentFromType.js';
25
26
  import IconButton from '../Buttons/IconButton.js';
27
+ import AngleLeft from '../Icons/AngleLeft.js';
26
28
  import Rotate from '../Icons/Rotate.js';
27
29
  import Pencil from '../Icons/Pencil.js';
28
30
  import Footer from '../Panel/Footer.js';
@@ -32,29 +34,32 @@ import _ from 'lodash';
32
34
  // TODO: memoize field Components
33
35
 
34
36
  // Modes:
35
- // EDITOR_TYPE_INLINE
37
+ // EDITOR_TYPE__INLINE
36
38
  // Form is a single scrollable row, based on columnsConfig and Repository
37
39
  //
38
- // EDITOR_TYPE_WINDOWED
39
- // Form is a popup window, used for editing items in a grid. Integrated with Repository
40
+ // EDITOR_TYPE__WINDOWED
41
+ // EDITOR_TYPE__SIDE
42
+ // Form is a popup or side window, used for editing items in a grid. Integrated with Repository
40
43
  //
41
- // EDITOR_TYPE_SMART
44
+ // EDITOR_TYPE__SMART
42
45
  // Form is a standalone editor
43
46
  //
44
- // EDITOR_TYPE_PLAIN
47
+ // EDITOR_TYPE__PLAIN
45
48
  // Form is embedded on screen in some other way. Mainly use startingValues, items, validator
46
49
 
47
50
  function Form(props) {
48
51
  const
49
52
  {
50
- editorType = EDITOR_TYPE_WINDOWED, // EDITOR_TYPE_INLINE | EDITOR_TYPE_WINDOWED | EDITOR_TYPE_PLAIN
53
+ editorType = EDITOR_TYPE__WINDOWED, // EDITOR_TYPE__INLINE | EDITOR_TYPE__WINDOWED | EDITOR_TYPE__SIDE | EDITOR_TYPE__SMART | EDITOR_TYPE__PLAIN
51
54
  startingValues = {},
52
55
  items = [], // Columns, FieldSets, Fields, etc to define the form
53
56
  columnDefaults = {}, // defaults for each Column defined in items (above)
54
- columnsConfig, // Which columns are shown in Grid, so the inline editor can match. Used only for EDITOR_TYPE_INLINE
55
- validator, // custom validator, mainly for EDITOR_TYPE_PLAIN
57
+ columnsConfig, // Which columns are shown in Grid, so the inline editor can match. Used only for EDITOR_TYPE__INLINE
58
+ validator, // custom validator, mainly for EDITOR_TYPE__PLAIN
56
59
  footerProps = {},
57
60
  buttonGroupProps = {}, // buttons in footer
61
+ onBack,
62
+ ancillaryComponents = [],
58
63
 
59
64
  // sizing of outer container
60
65
  h,
@@ -226,7 +231,9 @@ function Form(props) {
226
231
  return <Row>{elements}</Row>;
227
232
  },
228
233
  buildFromItems = () => {
229
- return _.map(items, (item, ix) => buildNextLayer(item, ix, columnDefaults));
234
+ const
235
+ regularItems = _.map(items, (item, ix) => buildNextLayer(item, ix, columnDefaults));
236
+ return [...regularItems, ...ancillaryComponents];
230
237
  },
231
238
  buildNextLayer = (item, ix, defaults) => {
232
239
  let {
@@ -356,7 +363,7 @@ function Form(props) {
356
363
  {...editorTypeProps}
357
364
  />;
358
365
  if (error) {
359
- if (editorType !== EDITOR_TYPE_INLINE) {
366
+ if (editorType !== EDITOR_TYPE__INLINE) {
360
367
  element = <Column pt={1} flex={1}>
361
368
  {element}
362
369
  <Text color="#f00">{error.message}</Text>
@@ -367,7 +374,7 @@ function Form(props) {
367
374
 
368
375
  }
369
376
  }
370
- if (label && editorType !== EDITOR_TYPE_INLINE) {
377
+ if (label && editorType !== EDITOR_TYPE__INLINE) {
371
378
  const labelProps = {};
372
379
  if (defaults?.labelWidth) {
373
380
  labelProps.w = defaults.labelWidth;
@@ -385,7 +392,7 @@ function Form(props) {
385
392
  },
386
393
  onSubmitError = (errors, e) => {
387
394
  debugger;
388
- if (editorType === EDITOR_TYPE_INLINE) {
395
+ if (editorType === EDITOR_TYPE__INLINE) {
389
396
  alert(errors.message);
390
397
  }
391
398
  };
@@ -429,7 +436,7 @@ function Form(props) {
429
436
 
430
437
  let formComponents,
431
438
  editor;
432
- if (editorType === EDITOR_TYPE_INLINE) {
439
+ if (editorType === EDITOR_TYPE__INLINE) {
433
440
  // for inline editor
434
441
  formComponents = buildFromColumnsConfig();
435
442
  editor = <ScrollView
@@ -451,6 +458,16 @@ function Form(props) {
451
458
  }
452
459
 
453
460
  return <Column {...sizeProps} onLayout={onLayout}>
461
+
462
+ {onBack && <Row p={2} alignItems="center">
463
+ <Button
464
+ key="backBtn"
465
+ onPress={onBack}
466
+ leftIcon={<Icon as={AngleLeft} color="#fff" size="sm" />}
467
+ color="#fff"
468
+ >Back</Button>
469
+ <Text ml={2} fontSize={18}>Edit Mode</Text>
470
+ </Row>}
454
471
 
455
472
  {editor}
456
473
 
@@ -27,6 +27,7 @@ import withContextMenu from '../Hoc/withContextMenu.js';
27
27
  import withAlert from '../Hoc/withAlert.js';
28
28
  import withData from '../Hoc/withData.js';
29
29
  import withEvents from '../Hoc/withEvents.js';
30
+ import withSideEditor from '../Hoc/withSideEditor.js';
30
31
  import withFilters from '../Hoc/withFilters.js';
31
32
  import withPresetButtons from '../Hoc/withPresetButtons.js';
32
33
  import withMultiSelection from '../Hoc/withMultiSelection.js';
@@ -839,6 +840,26 @@ export function Grid(props) {
839
840
 
840
841
  }
841
842
 
843
+ export const SideGridEditor = withAlert(
844
+ withEvents(
845
+ withData(
846
+ withMultiSelection(
847
+ withSelection(
848
+ withSideEditor(
849
+ withFilters(
850
+ withPresetButtons(
851
+ withContextMenu(
852
+ Grid
853
+ )
854
+ )
855
+ )
856
+ )
857
+ )
858
+ )
859
+ )
860
+ )
861
+ );
862
+
842
863
  export const WindowedGridEditor = withAlert(
843
864
  withEvents(
844
865
  withData(
@@ -1,4 +1,9 @@
1
1
  import { useState, } from 'react';
2
+ import {
3
+ EDITOR_VIEW_MODE__VIEW,
4
+ EDITOR_VIEW_MODE__ADD,
5
+ EDITOR_VIEW_MODE__EDIT,
6
+ } from '../../Constants/Editor.js';
2
7
  import _ from 'lodash';
3
8
 
4
9
  export default function withEditor(WrappedComponent) {
@@ -33,6 +38,7 @@ export default function withEditor(WrappedComponent) {
33
38
  [currentRecord, setCurrentRecord] = useState(null),
34
39
  [isEditorShown, setIsEditorShown] = useState(false),
35
40
  [isEditorViewOnly, setIsEditorViewOnly] = useState(false),
41
+ [editorViewMode, setEditorViewMode] = useState(EDITOR_VIEW_MODE__VIEW),
36
42
  addRecord = async () => {
37
43
  if (!userCanEdit) {
38
44
  return;
@@ -42,6 +48,7 @@ export default function withEditor(WrappedComponent) {
42
48
  entity = await Repository.add(defaultValues, false, true, true);
43
49
  setSelection([entity]);
44
50
  setIsEditorViewOnly(false);
51
+ setEditorViewMode(EDITOR_VIEW_MODE__ADD);
45
52
  setIsEditorShown(true);
46
53
  },
47
54
  editRecord = () => {
@@ -49,6 +56,7 @@ export default function withEditor(WrappedComponent) {
49
56
  return;
50
57
  }
51
58
  setIsEditorViewOnly(false);
59
+ setEditorViewMode(EDITOR_VIEW_MODE__EDIT);
52
60
  setIsEditorShown(true);
53
61
  },
54
62
  deleteRecord = (e) => {
@@ -80,6 +88,7 @@ export default function withEditor(WrappedComponent) {
80
88
  return;
81
89
  }
82
90
  setIsEditorViewOnly(true);
91
+ setEditorViewMode(EDITOR_VIEW_MODE__VIEW);
83
92
  setIsEditorShown(true);
84
93
  },
85
94
  duplicateRecord = async () => {
@@ -138,6 +147,7 @@ export default function withEditor(WrappedComponent) {
138
147
  setCurrentRecord={setCurrentRecord}
139
148
  isEditorShown={isEditorShown}
140
149
  isEditorViewOnly={isEditorViewOnly}
150
+ editorViewMode={editorViewMode}
141
151
  setIsEditorShown={setIsEditorShown}
142
152
  onAdd={addRecord}
143
153
  onEdit={editRecord}
@@ -2,6 +2,7 @@ import { useState, useEffect, } from 'react';
2
2
  import {
3
3
  Column,
4
4
  Modal,
5
+ Row,
5
6
  Text,
6
7
  } from 'native-base';
7
8
  import inArray from '../../Functions/inArray.js';
@@ -11,6 +12,7 @@ import FormPanel from '../Panel/FormPanel.js';
11
12
  import Ban from '../Icons/Ban.js';
12
13
  import Gear from '../Icons/Gear.js';
13
14
  import Toolbar from '../Toolbar/Toolbar.js';
15
+ import UiGlobals from '../../UiGlobals.js';
14
16
  import _ from 'lodash';
15
17
 
16
18
  // Filters only work with Repository; not data array
@@ -20,6 +22,7 @@ export default function withFilters(WrappedComponent) {
20
22
  const {
21
23
  useFilters = false,
22
24
  searchAllText = true,
25
+ showLabels = true,
23
26
  filter1StartingField = '',
24
27
  filter2StartingField = '',
25
28
  filter3StartingField = '',
@@ -33,7 +36,8 @@ export default function withFilters(WrappedComponent) {
33
36
 
34
37
  // withData
35
38
  Repository,
36
- } = props;
39
+ } = props,
40
+ styles = UiGlobals.styles;
37
41
 
38
42
  let modal,
39
43
  topToolbar = null;
@@ -195,15 +199,22 @@ export default function withFilters(WrappedComponent) {
195
199
  if (!Element) {
196
200
  debugger;
197
201
  }
198
- filterElements.push(<Element
199
- key={ix}
202
+ let filterElement = <Element
203
+ key={'element-' + ix}
200
204
  tooltip={titles[fieldName]}
201
205
  placeholder={titles[fieldName]}
202
206
  value={getFilterValue(ix)}
203
207
  onChangeValue={(value) => onFilterChange(ix, value)}
204
208
  {...filterProps}
205
209
  {...modelProps}
206
- />);
210
+ />;
211
+ if (showLabels) {
212
+ filterElement = <Row key={'label-' + ix}>
213
+ <Text fontSize={styles.FILTER_LABEL_FONTSIZE}>{titles[fieldName]}:</Text>
214
+ {filterElement}
215
+ </Row>;
216
+ }
217
+ filterElements.push(filterElement);
207
218
  };
208
219
  if (searchAllText) {
209
220
  addFilter(null, 'q');
@@ -6,8 +6,8 @@ import {
6
6
  Text,
7
7
  } from 'native-base';
8
8
  import {
9
- EDITOR_TYPE_INLINE,
10
- } from '../../Constants/EditorTypes.js';
9
+ EDITOR_TYPE__INLINE,
10
+ } from '../../Constants/Editor.js';
11
11
  import {
12
12
  UI_MODE_WEB,
13
13
  UI_MODE_REACT_NATIVE,
@@ -77,14 +77,14 @@ export default function withInlineEditor(WrappedComponent) {
77
77
  onChangeColumnsConfig={onChangeColumnsConfig}
78
78
  onEditorRowClick={onRowClick}
79
79
  />
80
- {useEditor && editorType === EDITOR_TYPE_INLINE && Repository &&
80
+ {useEditor && editorType === EDITOR_TYPE__INLINE && Repository &&
81
81
  <Modal
82
82
  isOpen={isEditorShown}
83
83
  onClose={() => setIsEditorShown(false)}
84
84
  >
85
85
  <Column position="absolute" ref={inlineEditorRef}>
86
86
  {isEditorShown && <Form
87
- editorType={EDITOR_TYPE_INLINE}
87
+ editorType={EDITOR_TYPE__INLINE}
88
88
  record={selection[0]}
89
89
  Repository={Repository}
90
90
  isMultiple={selection.length > 1}
@@ -0,0 +1,25 @@
1
+ import {
2
+ EDITOR_TYPE__SIDE,
3
+ } from '../../Constants/Editor.js';
4
+ import Container from '../Container/Container.js';
5
+ import withEditor from './withEditor.js';
6
+ import _ from 'lodash';
7
+
8
+
9
+ export default function withSideEditor(WrappedComponent) {
10
+ return withEditor((props) => {
11
+ const {
12
+ Editor,
13
+ editorProps = {},
14
+ } = props;
15
+
16
+ return <Container
17
+ center={<WrappedComponent {...props} />}
18
+ east={<Editor
19
+ editorType={EDITOR_TYPE__SIDE}
20
+ {...props}
21
+ {...editorProps}
22
+ />}
23
+ />;
24
+ });
25
+ }
@@ -4,8 +4,8 @@ import {
4
4
  Text,
5
5
  } from 'native-base';
6
6
  import {
7
- EDITOR_TYPE_WINDOWED,
8
- } from '../../Constants/EditorTypes.js';
7
+ EDITOR_TYPE__WINDOWED,
8
+ } from '../../Constants/Editor.js';
9
9
  import withEditor from './withEditor.js';
10
10
  // import withDraggable from './withDraggable.js';
11
11
  import _ from 'lodash';
@@ -31,7 +31,8 @@ export default function withWindowedEditor(WrappedComponent) {
31
31
  useEditor = false,
32
32
  isEditorShown,
33
33
  setIsEditorShown,
34
- EditorWindow,
34
+ Editor,
35
+ editorProps = {},
35
36
  } = props;
36
37
 
37
38
  return <>
@@ -41,9 +42,10 @@ export default function withWindowedEditor(WrappedComponent) {
41
42
  isOpen={true}
42
43
  onClose={() => setIsEditorShown(false)}
43
44
  >
44
- <EditorWindow
45
- editorType={EDITOR_TYPE_WINDOWED}
45
+ <Editor
46
+ editorType={EDITOR_TYPE__WINDOWED}
46
47
  {...props}
48
+ {...editorProps}
47
49
  />
48
50
  </Modal>}
49
51
  </>;
@@ -1,23 +1,36 @@
1
1
  import { useEffect, useState, } from 'react';
2
2
  import Panel from './Panel.js';
3
- import Grid, { InlineGridEditor, } from '../Grid/Grid.js';
3
+ import Grid, { InlineGridEditor, SideGridEditor, } from '../Grid/Grid.js';
4
4
  import {
5
- EDITOR_TYPE_INLINE,
6
- EDITOR_TYPE_WINDOWED,
7
- } from '../../Constants/EditorTypes.js';
5
+ EDITOR_TYPE__INLINE,
6
+ EDITOR_TYPE__WINDOWED,
7
+ EDITOR_TYPE__SIDE,
8
+ } from '../../Constants/Editor.js';
8
9
  import _ from 'lodash';
9
10
 
10
11
  export function GridPanel(props) {
11
12
  const {
12
- editorType,
13
+ editorType = EDITOR_TYPE__WINDOWED,
13
14
  disableTitleChange = false,
14
15
  selectorSelected,
15
16
  } = props,
16
17
  originalTitle = props.title,
17
- WhichGrid = (editorType === EDITOR_TYPE_INLINE) ? InlineGridEditor : Grid,
18
18
  [isReady, setIsReady] = useState(disableTitleChange),
19
19
  [title, setTitle] = useState(originalTitle);
20
20
 
21
+ let WhichGrid;
22
+ switch(editorType) {
23
+ case EDITOR_TYPE__INLINE:
24
+ WhichGrid = InlineGridEditor;
25
+ break;
26
+ case EDITOR_TYPE__WINDOWED:
27
+ WhichGrid = Grid;
28
+ break;
29
+ case EDITOR_TYPE__SIDE:
30
+ WhichGrid = SideGridEditor;
31
+ break;
32
+ }
33
+
21
34
  useEffect(() => {
22
35
  if (!disableTitleChange && originalTitle) {
23
36
  let newTitle = originalTitle;
@@ -0,0 +1,8 @@
1
+ export const EDITOR_TYPE__INLINE = 'EDITOR_TYPE__INLINE';
2
+ export const EDITOR_TYPE__WINDOWED = 'EDITOR_TYPE__WINDOWED';
3
+ export const EDITOR_TYPE__SIDE = 'EDITOR_TYPE__SIDE';
4
+ export const EDITOR_TYPE__SMART = 'EDITOR_TYPE__SMART';
5
+ export const EDITOR_TYPE__PLAIN = 'EDITOR_TYPE__PLAIN';
6
+ export const EDITOR_VIEW_MODE__VIEW = 'EDITOR_VIEW_MODE__VIEW';
7
+ export const EDITOR_VIEW_MODE__ADD = 'EDITOR_VIEW_MODE__ADD';
8
+ export const EDITOR_VIEW_MODE__EDIT = 'EDITOR_VIEW_MODE__EDIT';
@@ -6,6 +6,7 @@ const
6
6
  FOCUS = '#ffd';
7
7
 
8
8
  const defaults = {
9
+ FILTER_LABEL_FONTSIZE: DEFAULT_FONTSIZE,
9
10
  FORM_COLOR_READOUT_FONTSIZE: DEFAULT_FONTSIZE,
10
11
  FORM_COLOR_INPUT_BG: WHITE,
11
12
  FORM_COLOR_INPUT_FOCUS_BG: FOCUS,
@@ -41,6 +42,7 @@ const defaults = {
41
42
  FORM_TEXTAREA_FONTSIZE: DEFAULT_FONTSIZE,
42
43
  FORM_TEXTAREA_HEIGHT: 130,
43
44
  FORM_TOGGLE_BG: null,
45
+ FORM_TOGGLE_FONTSIZE: DEFAULT_FONTSIZE,
44
46
  FORM_TOGGLE_SIZE: 'md',
45
47
  FORM_TOGGLE_ON_COLOR: '#0b0',
46
48
  FORM_TOGGLE_ON_HOVER_COLOR: '#090',
@@ -1,4 +0,0 @@
1
- export const EDITOR_TYPE_INLINE = 'EDITOR_TYPE_INLINE';
2
- export const EDITOR_TYPE_WINDOWED = 'EDITOR_TYPE_WINDOWED';
3
- export const EDITOR_TYPE_SMART = 'EDITOR_TYPE_SMART';
4
- export const EDITOR_TYPE_PLAIN = 'EDITOR_TYPE_PLAIN';