@onehat/ui 0.3.3 → 0.3.5

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.3",
3
+ "version": "0.3.5",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -44,7 +44,8 @@
44
44
  "react-draggable": "^4.4.5",
45
45
  "react-native-draggable": "^3.3.0",
46
46
  "react-dom": "*",
47
- "react-native": "*"
47
+ "react-native": "*",
48
+ "react-uploader": "^3.41.0"
48
49
  },
49
50
  "devDependencies": {
50
51
  "@babel/core": "^7.22.1",
@@ -505,6 +505,8 @@ export function ComboComponent(props) {
505
505
  <WhichGrid
506
506
  showHeaders={false}
507
507
  showHovers={true}
508
+ pageSize={100}
509
+ disableAdjustingPageSizeToHeight={true}
508
510
  shadow={1}
509
511
  getRowProps={() => {
510
512
  return {
@@ -35,6 +35,9 @@ import _ from 'lodash';
35
35
  //
36
36
 
37
37
  function FileElement(props) {
38
+
39
+ throw new Error('Deprecated. Use platform-specific File component instead.');
40
+
38
41
  const {
39
42
  name,
40
43
  value = {
@@ -21,6 +21,11 @@ import {
21
21
  DROP_POSITION_BEFORE,
22
22
  DROP_POSITION_AFTER,
23
23
  } from '../../Constants/Grid.js';
24
+ import {
25
+ UI_MODE_WEB,
26
+ UI_MODE_REACT_NATIVE,
27
+ CURRENT_MODE,
28
+ } from '../../Constants/UiModes.js';
24
29
  import * as colourMixer from '@k-renwick/colour-mixer'
25
30
  import UiGlobals from '../../UiGlobals.js';
26
31
  import useForceUpdate from '../../Hooks/useForceUpdate.js';
@@ -70,6 +75,7 @@ function GridComponent(props) {
70
75
  pullToRefresh = true,
71
76
  hideNavColumn = true,
72
77
  noneFoundText,
78
+ disableAdjustingPageSizeToHeight = false,
73
79
  disableLoadingIndicator = false,
74
80
  disableSelectorSelected = false,
75
81
  showRowExpander = false,
@@ -608,6 +614,41 @@ function GridComponent(props) {
608
614
  dragRowSlot.marker.remove();
609
615
  }
610
616
  setDragRowSlot(null);
617
+ },
618
+ onLayout = (e) => {
619
+ if (disableAdjustingPageSizeToHeight || !Repository) {
620
+ return;
621
+ }
622
+ const {
623
+ nativeEvent: {
624
+ layout,
625
+ target,
626
+ },
627
+ } = e;
628
+ let pageSize;
629
+ if (CURRENT_MODE === UI_MODE_WEB) {
630
+ const
631
+ targetBoundingBox = target.getBoundingClientRect(),
632
+ targetHeight = targetBoundingBox.height,
633
+ firstRow = target.children[0]?.children[0]?.children[0]?.children[0]?.children[0];
634
+ if (firstRow) {
635
+ const
636
+ rowBoundingBox = firstRow.getBoundingClientRect(),
637
+ rowHeight = rowBoundingBox.height,
638
+ rowsPerTarget = Math.floor(targetHeight / rowHeight);
639
+ pageSize = rowsPerTarget;
640
+ if (showHeaders) {
641
+ pageSize--;
642
+ }
643
+ if (bottomToolbar) {
644
+ pageSize--;
645
+ }
646
+ }
647
+ }
648
+
649
+ if (pageSize) {
650
+ Repository.setPageSize(pageSize);
651
+ }
611
652
  };
612
653
 
613
654
  useEffect(() => {
@@ -752,7 +793,7 @@ function GridComponent(props) {
752
793
  if (inlineEditor) {
753
794
  rowData.push({ id: 'inlineEditor' }); // make editor the last row so it can scroll with all other rows
754
795
  }
755
- const initialNumToRender = rowData.length || 10;
796
+ const initialNumToRender = rowData?.length || 10;
756
797
 
757
798
  // headers & footers
758
799
  let listFooterComponent = null;
@@ -776,6 +817,7 @@ function GridComponent(props) {
776
817
  bg={bg}
777
818
  borderWidth={styles.GRID_BORDER_WIDTH}
778
819
  borderColor={styles.GRID_BORDER_COLOR}
820
+ onLayout={onLayout}
779
821
  {...sizeProps}
780
822
  >
781
823
  {topToolbar}
@@ -19,6 +19,7 @@ export default function withData(WrappedComponent) {
19
19
  uniqueRepository = false,
20
20
  model,
21
21
  autoLoad = false,
22
+ pageSize,
22
23
 
23
24
  // For plain JS data
24
25
  data,
@@ -51,6 +52,10 @@ export default function withData(WrappedComponent) {
51
52
  Repository = oneHatData.getRepository(model);
52
53
  }
53
54
 
55
+ if (pageSize) {
56
+ Repository.setPageSize(pageSize);
57
+ }
58
+
54
59
  if (Repository && (autoLoad || Repository.autoLoad) && !Repository.isLoaded && Repository.isRemote && !Repository.isAutoLoad && !Repository.isLoading) {
55
60
  await Repository.load();
56
61
  }
@@ -20,7 +20,6 @@ import Date from './Form/Field/Date.js';
20
20
  import DateRange from './Filter/DateRange.js';
21
21
  import DisplayField from './Form/Field/DisplayField.js';
22
22
  import FieldSet from './Form/FieldSet.js';
23
- // import File from './Form/Field/File.js'; // web only
24
23
  import FiltersForm from './Form/FiltersForm.js';
25
24
  // import FiltersToolbar from '../Components/Toolbar/FiltersToolbar.js';
26
25
  import Form from './Form/Form.js';
@@ -70,7 +69,6 @@ const components = {
70
69
  DateRange,
71
70
  DisplayField,
72
71
  FieldSet,
73
- // File,
74
72
  FiltersForm,
75
73
  // FiltersToolbar,
76
74
  Form,
@@ -2,7 +2,7 @@ import UiGlobals from '../UiGlobals.js';
2
2
  // import CKEditor from '../Components/Form/Field/CKEditor/CKEditor.js';
3
3
  import Datetime from '../PlatformImports/Web/Datetime.js';
4
4
  import Draggable from '../PlatformImports/Web/Draggable.js';
5
- import File from '../Components/Form/Field/File.js';
5
+ import File from '../PlatformImports/Web/File.js';
6
6
  import _ from 'lodash';
7
7
 
8
8
  export default function registerWebComponents() {
@@ -0,0 +1,137 @@
1
+ import React, { useState, useEffect, useRef, } from 'react';
2
+ import {
3
+ Box,
4
+ Icon,
5
+ Row,
6
+ Text,
7
+ Tooltip,
8
+ } from 'native-base';
9
+ import {
10
+ CURRENT_MODE,
11
+ UI_MODE_WEB,
12
+ UI_MODE_REACT_NATIVE,
13
+ } from '../../../Constants/UiModes.js';
14
+ import UiGlobals from '../../../UiGlobals.js';
15
+ import {
16
+ FILE_MODE_IMAGE,
17
+ FILE_MODE_FILE,
18
+ } from '../../../Constants/File.js';
19
+ import { Uploader } from 'uploader'; // Installed by "react-uploader".
20
+ import { UploadButton } from 'react-uploader';
21
+ import IconButton from '../../Buttons/IconButton.js';
22
+ import withValue from '../../Hoc/withValue.js';
23
+ import File from '../../Icons/File.js';
24
+ import Trash from '../../Icons/Trash.js';
25
+ import _ from 'lodash';
26
+
27
+ function FileElement(props) {
28
+
29
+ if (CURRENT_MODE !== UI_MODE_WEB) {
30
+ throw new Error('Not yet implemented except for web.');
31
+ }
32
+
33
+ const {
34
+ name,
35
+ value = {
36
+ dataUri: null,
37
+ control: null,
38
+ filename: null,
39
+ },
40
+ setValue,
41
+
42
+ mode = FILE_MODE_IMAGE, // FILE_MODE_IMAGE, FILE_MODE_FILE
43
+ imagePath = '',
44
+ tooltip = 'Choose or drag a file on top of this control.',
45
+ tooltipPlacement = 'bottom',
46
+ } = props,
47
+ styles = UiGlobals.styles,
48
+ dragRef = useRef(),
49
+ fileInputRef = useRef(),
50
+ [isDropping, setIsDropping] = useState(false),
51
+ onSelect = () => {
52
+ fileInputRef.current.click();
53
+
54
+ setValue({
55
+ dataUri: null,
56
+ control: null,
57
+ filename: null,
58
+ version,
59
+ });
60
+ },
61
+ setBase64 = (file, readerResult) => {
62
+ const
63
+ base64 = btoa(readerResult), // 'btoa' is deprecated in Node.js, but not browsers, so use it! // https://developer.mozilla.org/en-US/docs/Web/API/btoa
64
+ dataUri = `data:${file.type};base64,${base64}`,
65
+ control = '',
66
+ filename = file.name;
67
+
68
+ },
69
+ onDrop = (e) => {
70
+ e.preventDefault();
71
+ const
72
+ files = e.dataTransfer && e.dataTransfer.files,
73
+ file = files[0],
74
+ reader = new FileReader();
75
+
76
+ reader.readAsDataURL(file);
77
+ reader.onload = (e) => {
78
+ setBase64(file, e.target.result);
79
+ };
80
+ setIsDropping(false);
81
+ };
82
+
83
+ return <div ref={dragRef} style={{ flex: 1, height: '100%', }} onDragEnter={onDragEnter} onDragLeave={onDragLeave} onDragOver={onDragOver} onDrop={onDrop}>
84
+ <Tooltip label={tooltip} placement={tooltipPlacement}>
85
+ <Row flex={1} h={10} alignItems="center">
86
+ {isDropping && <Box position="absolute" borderWidth={isDropping ? 2 : 0} borderColor="primary.800" top={0} left={0} w="100%" h="100%" bg="trueGray.200" zIndex={10000} justifyContent="center" alignItems="center">
87
+ <Text>Set File</Text>
88
+ </Box>}
89
+ <IconButton
90
+ icon={<Icon as={File} color={styles.FORM_FILE_ICON_COLOR} />}
91
+ onPress={onSelect}
92
+ h={10}
93
+ w={10}
94
+ bg={styles.FORM_FILE_ICON_BG}
95
+ _hover={{
96
+ bg: styles.FORM_FILE_ICON_BG_HOVER,
97
+ }}
98
+ />
99
+ <IconButton
100
+ icon={<Icon as={Trash} color={styles.FORM_FILE_ICON_COLOR} />}
101
+ onPress={onClear}
102
+ h={10}
103
+ w={10}
104
+ ml={1}
105
+ isDisabled={!value?.dataUri}
106
+ bg={value?.dataUri ? styles.FORM_FILE_ICON_BG : 'disabled'}
107
+ _hover={{
108
+ bg: value?.dataUri ? styles.FORM_FILE_ICON_BG_HOVER : 'disabled',
109
+ }}
110
+ />
111
+ {mode === FILE_MODE_FILE && <Text
112
+ flex={1}
113
+ ml={3}
114
+ fontSize={styles.FORM_FILE_READOUT_FONTSIZE}
115
+ fontStyle="italic"
116
+ numberOfLines={1}
117
+ ellipsizeMode="head"
118
+ bg={styles.FORM_FILE_READOUT_BG}
119
+ >{value.filename || 'No file'}</Text>}
120
+ {mode === FILE_MODE_IMAGE && <Box
121
+ flex={1}
122
+ h="100%"
123
+ ml={1}
124
+ bg={styles.FORM_FILE_READOUT_BG}
125
+ backgroundImage={value?.dataUri ? 'url(' + imagePath + encodeURIComponent(value.dataUri) + ')' : 'none'}
126
+ backgroundSize="contain"
127
+ backgroundRepeat="no-repeat"
128
+ borderRadius={4}
129
+ borderWidth={1}
130
+ />}
131
+ <input type="file" ref={fileInputRef} name={name} onChange={onChangeFile} style={{ position: 'absolute', opacity: 0, height: 0, width: 0, }} />
132
+ </Row>
133
+ </Tooltip>
134
+ </div>;
135
+ }
136
+
137
+ export default withValue(FileElement);