@onehat/ui 0.4.101 → 0.4.102

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.101",
3
+ "version": "0.4.102",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -100,6 +100,8 @@ export const ComboComponent = forwardRef((props, ref) => {
100
100
  onGridSave, // to hook into when menu saves (ComboEditor only)
101
101
  onGridDelete, // to hook into when menu deletes (ComboEditor only)
102
102
  onSubmit, // when Combo is used in a Tag, call this when the user submits the Combo value (i.e. presses Enter or clicks a row)
103
+ displayProperty, // override for Repository.schema.model.displayProperty
104
+ valueProperty, // override for Repository.schema.model.idProperty
103
105
  newEntityDisplayProperty,
104
106
  testID,
105
107
 
@@ -242,7 +244,7 @@ export const ComboComponent = forwardRef((props, ref) => {
242
244
  displayValue = _.each(value, (id) => {
243
245
  const entity = Repository.getById(id);
244
246
  if (entity) {
245
- displayValue.push(entity.displayValue);
247
+ displayValue.push((displayProperty ? entity?.[displayProperty] : entity?.displayValue) || '');
246
248
  }
247
249
  });
248
250
  }
@@ -272,7 +274,7 @@ export const ComboComponent = forwardRef((props, ref) => {
272
274
  }
273
275
  }
274
276
  }
275
- displayValue = entity?.displayValue || '';
277
+ displayValue = (displayProperty ? entity?.[displayProperty] : entity?.displayValue) || '';
276
278
  }
277
279
  } else {
278
280
  const item = _.find(data, (datum) => datum[idIx] === value);
@@ -318,7 +320,11 @@ export const ComboComponent = forwardRef((props, ref) => {
318
320
 
319
321
  let id = null;
320
322
  if (gridSelection.length) {
321
- id = Repository ? gridSelection[0].id : gridSelection[0][idIx];
323
+ if (Repository) {
324
+ id = valueProperty ? gridSelection[0][valueProperty] : gridSelection[0].id;
325
+ } else {
326
+ id = gridSelection[0][idIx];
327
+ }
322
328
  }
323
329
  if (id !== value) {
324
330
  setValue(id);
@@ -863,7 +869,7 @@ export const ComboComponent = forwardRef((props, ref) => {
863
869
  return;
864
870
  }
865
871
 
866
- setValue(selection[0] ? selection[0].id : null);
872
+ setValue(selection[0] ? (valueProperty ? selection[0][valueProperty] : selection[0].id) : null);
867
873
 
868
874
  } else {
869
875
 
@@ -545,10 +545,16 @@ function TagComponent(props) {
545
545
 
546
546
  function withAdditionalProps(WrappedComponent) {
547
547
  return (props) => {
548
+ const tooltipTriggerClassName = clsx(
549
+ 'w-full',
550
+ 'flex-1',
551
+ props.tooltipTriggerClassName,
552
+ );
548
553
  return <WrappedComponent
549
554
  isValueAlwaysArray={true}
550
555
  isValueAsStringifiedJson={true}
551
556
  {...props}
557
+ tooltipTriggerClassName={tooltipTriggerClassName}
552
558
  />;
553
559
  };
554
560
  }
@@ -147,6 +147,7 @@ function GridComponent(props) {
147
147
  showHeaders = true,
148
148
  showHovers = true,
149
149
  showSelectHandle = true,
150
+ isRowTextSelectable, // if false, user can't select text in rows (e.g. to copy/paste)
150
151
  isRowSelectable = true,
151
152
  isRowHoverable = true,
152
153
  isDisabled = false,
@@ -789,6 +790,7 @@ function GridComponent(props) {
789
790
  areCellsScrollable={areCellsScrollable}
790
791
  showHovers={showHovers}
791
792
  showRowHandle={showRowHandle}
793
+ isRowTextSelectable={isRowTextSelectable}
792
794
  rowCanSelect={rowCanSelect}
793
795
  rowCanDrag={rowCanDrag}
794
796
  index={index}
@@ -38,6 +38,7 @@ const GridRow = forwardRef((props, ref) => {
38
38
  rowProps,
39
39
  hideNavColumn,
40
40
  showRowHandle,
41
+ isRowTextSelectable,
41
42
  areCellsScrollable,
42
43
  rowCanSelect,
43
44
  rowCanDrag,
@@ -126,6 +127,8 @@ const GridRow = forwardRef((props, ref) => {
126
127
  const
127
128
  visibleColumns = _.filter(columnsConfig, (config) => !config.isHidden),
128
129
  isOnlyOneVisibleColumn = visibleColumns.length === 1,
130
+ canSelectTextOnRow = isRowTextSelectable === false ? false : isDragFromHandleOnly,
131
+ shouldUseTextCursor = showRowHandle && canSelectTextOnRow,
129
132
  rowShouldHaveDragRef = !isDragFromHandleOnly && (isDragSource || isDraggable) && !!dragSourceRef;
130
133
  const setRowRef = (node) => {
131
134
  if (typeof ref === 'function') {
@@ -152,7 +155,7 @@ const GridRow = forwardRef((props, ref) => {
152
155
  const
153
156
  propsToPass = columnProps[key] || {},
154
157
  colStyle = {},
155
- whichCursor = showRowHandle && isDragFromHandleOnly ? 'cursor-text' : 'cursor-pointer'; // when using rowSelectHandle, indicate that the row text is selectable, otherwise indicate that the row itself is selectable
158
+ whichCursor = shouldUseTextCursor ? 'cursor-text' : 'cursor-pointer';
156
159
  let colClassName = clsx(
157
160
  'GridRow-column',
158
161
  'p-1',
@@ -160,7 +163,7 @@ const GridRow = forwardRef((props, ref) => {
160
163
  'border-r-black-100',
161
164
  'block',
162
165
  areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
163
- isDragFromHandleOnly ? null : 'select-none',
166
+ canSelectTextOnRow ? null : 'select-none',
164
167
  whichCursor,
165
168
  styles.GRID_ROW_MAX_HEIGHT_EXTRA,
166
169
  );
@@ -465,7 +468,7 @@ const GridRow = forwardRef((props, ref) => {
465
468
  let rowClassName = clsx(
466
469
  'GridRow-HStackNative',
467
470
  'items-center',
468
- isDragFromHandleOnly ? null : 'select-none',
471
+ canSelectTextOnRow ? null : 'select-none',
469
472
  );
470
473
  if (isOnlyOneVisibleColumn) {
471
474
  rowClassName += ' w-full';
@@ -514,6 +517,7 @@ const GridRow = forwardRef((props, ref) => {
514
517
  dragPreviewRef,
515
518
  dropTargetRef,
516
519
  showRowHandle,
520
+ isRowTextSelectable,
517
521
  rowCanSelect,
518
522
  rowCanDrag,
519
523
  isDragFromHandleOnly,
@@ -0,0 +1,11 @@
1
+ import { createIcon } from "../Gluestack/icon";
2
+ // Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc.
3
+ import { Path, Svg } from 'react-native-svg';
4
+
5
+ const SvgComponent = createIcon({
6
+ Root: Svg,
7
+ viewBox: '0 0 640 640',
8
+ path: <Path d="M256 160v64h128v-64c0-35.3-28.7-64-64-64s-64 28.7-64 64zm-64 64v-64c0-70.7 57.3-128 128-128s128 57.3 128 128v64c35.3 0 64 28.7 64 64v224c0 35.3-28.7 64-64 64H192c-35.3 0-64-28.7-64-64V288c0-35.3 28.7-64 64-64z" />,
9
+ });
10
+
11
+ export default SvgComponent
@@ -8,44 +8,63 @@ import {
8
8
  import clsx from 'clsx';
9
9
  import ChartPie from '../Icons/ChartPie.js';
10
10
  import ScreenHeader from '../Layout/ScreenHeader.js';
11
+ import TabBar from '../Tab/TabBar.js';
12
+ import _ from 'lodash';
11
13
 
12
14
  const CONTAINER_THRESHOLD = 1100;
13
15
 
14
16
  export default function ReportsManager(props) {
15
17
  const {
16
18
  reports = [],
19
+ reportTabs,
20
+ initialReportTabIx = 0,
21
+ id,
22
+ self,
17
23
  isActive = false,
18
24
  } = props,
19
25
  [containerWidth, setContainerWidth] = useState(),
20
26
  onLayout = (e) => {
21
27
  setContainerWidth(e.nativeEvent.layout.width);
28
+ },
29
+ renderReportLayout = (reportsToRender = []) => {
30
+ if (!containerWidth) {
31
+ return null;
32
+ }
33
+
34
+ if (containerWidth >= CONTAINER_THRESHOLD) {
35
+ const
36
+ reportsPerColumn = Math.ceil(reportsToRender.length / 2),
37
+ col1Reports = reportsToRender.slice(0, reportsPerColumn),
38
+ col2Reports = reportsToRender.slice(reportsPerColumn);
39
+ return <HStack className="gap-3">
40
+ <VStack className="flex-1">
41
+ {col1Reports}
42
+ </VStack>
43
+ <VStack className="flex-1">
44
+ {col2Reports}
45
+ </VStack>
46
+ </HStack>;
47
+ }
48
+
49
+ return reportsToRender;
22
50
  };
23
51
 
24
52
  if (!isActive) {
25
53
  return null;
26
54
  }
27
55
 
28
- let reportElements = [];
29
- if (containerWidth) {
30
- if (containerWidth >= CONTAINER_THRESHOLD) {
31
- // two column layout
32
- const
33
- reportsPerColumn = Math.ceil(reports.length / 2),
34
- col1Reports = reports.slice(0, reportsPerColumn),
35
- col2Reports = reports.slice(reportsPerColumn);
36
- reportElements = <HStack className="gap-3">
37
- <VStack className="flex-1">
38
- {col1Reports}
39
- </VStack>
40
- <VStack className="flex-1">
41
- {col2Reports}
42
- </VStack>
43
- </HStack>;
44
- } else {
45
- // one column layout
46
- reportElements = reports;
47
- }
48
- }
56
+ const
57
+ hasReportTabs = _.isArray(reportTabs) && reportTabs.length > 0,
58
+ tabBarId = `${id || self?.path || 'ReportsManager'}-reportTabs`,
59
+ reportElements = renderReportLayout(reports),
60
+ tabBarTabs = hasReportTabs ? _.map(reportTabs, (tab, ix) => ({
61
+ ...tab,
62
+ content: <ScrollView className="flex-1 w-full" key={`reportTabContent-${ix}`}>
63
+ <VStackNative className="w-full p-4" onLayout={onLayout}>
64
+ {renderReportLayout(tab.reports || [])}
65
+ </VStackNative>
66
+ </ScrollView>,
67
+ })) : [];
49
68
 
50
69
  return <VStack
51
70
  className="overflow-hidden flex-1 w-full"
@@ -54,10 +73,16 @@ export default function ReportsManager(props) {
54
73
  title="Reports"
55
74
  icon={ChartPie}
56
75
  />
57
- <ScrollView className="flex-1 w-full">
58
- <VStackNative className="w-full p-4" onLayout={onLayout}>
59
- {containerWidth && reportElements}
60
- </VStackNative>
61
- </ScrollView>
76
+ {hasReportTabs ?
77
+ <TabBar
78
+ id={tabBarId}
79
+ initialTabIx={initialReportTabIx}
80
+ tabs={tabBarTabs}
81
+ /> :
82
+ <ScrollView className="flex-1 w-full">
83
+ <VStackNative className="w-full p-4" onLayout={onLayout}>
84
+ {containerWidth && reportElements}
85
+ </VStackNative>
86
+ </ScrollView>}
62
87
  </VStack>;
63
88
  }