@onehat/ui 0.2.81 → 0.2.84

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.81",
3
+ "version": "0.2.84",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -25,12 +25,14 @@
25
25
  },
26
26
  "license": "UNLICENSED",
27
27
  "dependencies": {
28
- "@onehat/data": "^1.18.7",
29
- "@hookform/resolvers": "^3.1.1",
28
+ "@onehat/data": "^1.18.12",
29
+ "@hookform/resolvers": "^3.3.1",
30
30
  "@k-renwick/colour-mixer": "^1.2.1",
31
+ "@reduxjs/toolkit": "^1.9.5",
31
32
  "js-cookie": "^3.0.5",
32
33
  "native-base": "^3.4.28",
33
34
  "react-hook-form": "^7.45.0",
35
+ "react-redux": "^8.1.2",
34
36
  "yup": "^1.2.0"
35
37
  },
36
38
  "peerDependencies": {
@@ -1,3 +1,6 @@
1
+ import {
2
+ Box,
3
+ } from 'native-base';
1
4
  import {
2
5
  EDITOR_MODE__VIEW,
3
6
  } from '../../Constants/Editor.js';
@@ -25,10 +28,11 @@ export default function Editor(props) {
25
28
  } = props;
26
29
 
27
30
  if (_.isEmpty(selection)) {
28
- return null;
31
+ return null; // hide the editor when no selection
32
+ return <Box {...props} bg="#ddd" />;
29
33
  }
30
34
 
31
- if (Repository.isRemotePhantomMode && selection.length === 1 && editorMode === EDITOR_MODE__VIEW) {
35
+ if (Repository?.isRemotePhantomMode && selection.length === 1 && editorMode === EDITOR_MODE__VIEW) {
32
36
  return <Viewer
33
37
  {...props}
34
38
  record={selection[0]}
@@ -31,6 +31,7 @@ export default function Viewer(props) {
31
31
  onDelete,
32
32
  } = props,
33
33
  styles = UiGlobals.styles,
34
+ flex = props.flex || 1,
34
35
  buildAncillary = () => {
35
36
  let components = [];
36
37
  if (ancillaryItems.length) {
@@ -55,14 +56,14 @@ export default function Viewer(props) {
55
56
  fontWeight="bold"
56
57
  >{title}</Text>;
57
58
  }
58
- return <Column key={'ancillary-' + ix} px={2} pb={1}>{title}{element}</Column>;
59
+ return <Column key={'ancillary-' + ix} my={5}>{title}{element}</Column>;
59
60
  });
60
61
  }
61
62
  return components;
62
63
  };
63
64
 
64
- return <Column flex={1} w="100%">
65
- <ScrollView flex={1} w="100%">
65
+ return <Column flex={flex} {...props}>
66
+ <ScrollView width="100%" _web={{ height: 1 }}>
66
67
  <Column m={2}>
67
68
  {onEditMode && <Row mb={4} justifyContent="flex-end">
68
69
  <Button
@@ -427,7 +427,7 @@ function Form(props) {
427
427
  fontWeight="bold"
428
428
  >{title}</Text>;
429
429
  }
430
- return <Column key={'ancillary-' + ix} px={2} pb={1}>{title}{element}</Column>;
430
+ return <Column key={'ancillary-' + ix} mx={2} my={5}>{title}{element}</Column>;
431
431
  });
432
432
  }
433
433
  return components;
@@ -499,7 +499,7 @@ function Form(props) {
499
499
  // for all other editor types
500
500
  formComponents = buildFromItems();
501
501
  const formAncillaryComponents = buildAncillary();
502
- editor = <ScrollView flex={1} width="100%" pb={1}>
502
+ editor = <ScrollView _web={{ height: 1 }} width="100%" pb={1}>
503
503
  <Row>{formComponents}</Row>
504
504
  <Column pt={4}>{formAncillaryComponents}</Column>
505
505
  </ScrollView>;
@@ -774,6 +774,8 @@ function GridComponent(props) {
774
774
  {...testProps('Grid')}
775
775
  w="100%"
776
776
  bg={bg}
777
+ borderWidth={styles.GRID_BORDER_WIDTH}
778
+ borderColor={styles.GRID_BORDER_COLOR}
777
779
  {...sizeProps}
778
780
  >
779
781
  {topToolbar}
@@ -52,6 +52,17 @@ export default function withEditor(WrappedComponent, isTree = false) {
52
52
  [isEditorShown, setIsEditorShown] = useState(false),
53
53
  [isEditorViewOnly, setIsEditorViewOnly] = useState(false),
54
54
  [lastSelection, setLastSelection] = useState(),
55
+ setSelectionDecorated = (newSelection) => {
56
+ function doIt() {
57
+ setSelection(newSelection);
58
+ }
59
+ const formState = editorStateRef.current;
60
+ if (!_.isEmpty(formState?.dirtyFields) && newSelection !== selection && editorMode === EDITOR_MODE__EDIT) {
61
+ confirm('This record has unsaved changes. Are you sure you want to cancel editing? Changes will be lost.', doIt);
62
+ } else {
63
+ doIt();
64
+ }
65
+ },
55
66
  getListeners = () => {
56
67
  return listeners.current;
57
68
  },
@@ -342,6 +353,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
342
353
  disableDelete={disableDelete}
343
354
  disableDuplicate={disableDuplicate}
344
355
  disableView ={disableView}
356
+ setSelection={setSelectionDecorated}
345
357
  />;
346
358
  };
347
359
  }
@@ -1,4 +1,3 @@
1
- import { useState, } from 'react';
2
1
  import {
3
2
  EDITOR_TYPE__SIDE,
4
3
  } from '../../Constants/Editor.js';
@@ -13,9 +12,7 @@ export default function withSideEditor(WrappedComponent, isTree = false) {
13
12
  Editor,
14
13
  editorProps = {},
15
14
  sideFlex = 100,
16
- } = props,
17
- [selection, setSelection] = useState(null);
18
-
15
+ } = props;
19
16
 
20
17
  if (!Editor) {
21
18
  throw Error('Editor is not defined');
@@ -25,13 +22,13 @@ export default function withSideEditor(WrappedComponent, isTree = false) {
25
22
  center={<WrappedComponent
26
23
  isTree={isTree}
27
24
  {...props}
28
- onSelectionChange={setSelection}
29
25
  />}
30
26
  east={<Editor
27
+ {...props}
31
28
  editorType={EDITOR_TYPE__SIDE}
32
29
  flex={sideFlex}
33
- selection={selection} // This needs to be whatever the selection is in the center component
34
- // {...props}
30
+ borderLeftWidth={1}
31
+ borderLeftColor="#ccc"
35
32
  {...editorProps}
36
33
  />}
37
34
  />;
@@ -28,7 +28,11 @@ export function GridPanel(props) {
28
28
  }
29
29
  }
30
30
 
31
- return <Panel {...props} {..._panel}>
31
+ if (!props._panel) {
32
+ props._panel = {};
33
+ }
34
+
35
+ return <Panel {...props} {...props._panel}>
32
36
  <WhichGrid {...props} />
33
37
  </Panel>;
34
38
  }
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useMemo, useId, } from 'react';
1
+ import React, { useState, useEffect, } from 'react';
2
2
  import {
3
3
  Column,
4
4
  Row,
@@ -20,8 +20,8 @@ export default function ManagerScreen(props) {
20
20
  title,
21
21
  sideModeComponent,
22
22
  fullModeComponent,
23
+ id,
23
24
  } = props,
24
- id = useId(),
25
25
  [isReady, setIsReady] = useState(false),
26
26
  [mode, setModeRaw] = useState(MODE_FULL),
27
27
  setMode = (newMode) => {
@@ -64,6 +64,8 @@ export default function ManagerScreen(props) {
64
64
  <Row
65
65
  h="80px"
66
66
  py={2}
67
+ borderBottomWidth={2}
68
+ borderBottomColor="#ccc"
67
69
  >
68
70
  <Text p={4} fontSize="26" fontWeight={700}>{title}</Text>
69
71
  <IconButton
@@ -63,6 +63,8 @@ const defaults = {
63
63
  GRID_ROW_HOVER_BG: 'hover',
64
64
  GRID_ROW_SELECTED_BG: 'selected',
65
65
  GRID_ROW_SELECTED_HOVER_BG: 'selectedHover',
66
+ GRID_BORDER_WIDTH: 1,
67
+ GRID_BORDER_COLOR: 'trueGray.300',
66
68
  ICON_BUTTON_BG: 'trueGray.200:alpha.0',
67
69
  ICON_BUTTON_BG_DISABLED: 'trueGray.200',
68
70
  ICON_BUTTON_BG_HOVER: '#000:alpha.20',
@@ -0,0 +1,40 @@
1
+ import { useSelector, useDispatch } from 'react-redux'
2
+ import _ from 'lodash';
3
+
4
+
5
+ // Usage example:
6
+ // const [
7
+ // {
8
+ // user,
9
+ // isLoading,
10
+ // },
11
+ // dispatch
12
+ // ] = useRedux([
13
+ // 'user',
14
+ // 'isLoading',
15
+ // ]);
16
+
17
+
18
+ export default function useRedux(properties) {
19
+ let values = {};
20
+ _.forEach(properties, (property) => {
21
+ values[property] = useSelector((state) => getPropertyFromState(property, state));
22
+ });
23
+
24
+ return [
25
+ values,
26
+ useDispatch(),
27
+ ];
28
+ };
29
+
30
+ function getPropertyFromState(property, state) {
31
+ let found;
32
+ const reducers = _.keys(state);
33
+ _.each(reducers, (reducer) => {
34
+ if (state[reducer].hasOwnProperty(property)) {
35
+ found = state[reducer][property];
36
+ return false; // break
37
+ }
38
+ });
39
+ return found;
40
+ }