@onehat/ui 0.4.100 → 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 +1 -1
- package/src/Components/Form/Field/Combo/Combo.js +10 -4
- package/src/Components/Form/Field/Tag/Tag.js +6 -0
- package/src/Components/Grid/Grid.js +25 -0
- package/src/Components/Grid/GridRow.js +30 -4
- package/src/Components/Hoc/withDnd.js +5 -2
- package/src/Components/Icons/Lock.js +11 -0
- package/src/Components/Screens/ReportsManager.js +51 -26
- package/src/UiGlobals.js +1 -0
package/package.json
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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,
|
|
@@ -201,6 +202,7 @@ function GridComponent(props) {
|
|
|
201
202
|
},
|
|
202
203
|
dragPreviewOptions, // optional object for drag preview positioning options
|
|
203
204
|
areRowsDragSource = false,
|
|
205
|
+
areRowsDragFromHandleOnly,
|
|
204
206
|
rowDragSourceType,
|
|
205
207
|
getRowDragSourceItem,
|
|
206
208
|
areRowsDropTarget = false,
|
|
@@ -641,10 +643,23 @@ function GridComponent(props) {
|
|
|
641
643
|
|
|
642
644
|
const userHasPermissionToDrag = (!canUser || canUser(EDIT));
|
|
643
645
|
if (userHasPermissionToDrag) {
|
|
646
|
+
|
|
647
|
+
// Determine whether dragging should only be allowed from a handle, based on global default and grid prop override
|
|
648
|
+
let dragFromRowHandleOnly = true;
|
|
649
|
+
if (!_.isNil(UiGlobals.gridAreRowsDragFromHandleOnly)) {
|
|
650
|
+
// allow global default
|
|
651
|
+
dragFromRowHandleOnly = UiGlobals.gridAreRowsDragFromHandleOnly;
|
|
652
|
+
}
|
|
653
|
+
if (!_.isNil(areRowsDragFromHandleOnly)) {
|
|
654
|
+
// allow grid props override
|
|
655
|
+
dragFromRowHandleOnly = areRowsDragFromHandleOnly;
|
|
656
|
+
}
|
|
657
|
+
|
|
644
658
|
// assign event handlers
|
|
645
659
|
if (canRowsReorder && isReorderMode) {
|
|
646
660
|
WhichRow = DragSourceGridRow;
|
|
647
661
|
rowReorderProps.isDragSource = true;
|
|
662
|
+
rowReorderProps.isDragFromHandleOnly = dragFromRowHandleOnly;
|
|
648
663
|
rowReorderProps.dragSourceType = 'row';
|
|
649
664
|
const dragIx = showHeaders ? index - 1 : index;
|
|
650
665
|
rowReorderProps.dragSourceItem = {
|
|
@@ -656,6 +671,14 @@ function GridComponent(props) {
|
|
|
656
671
|
onRowReorderDrag(dragState, dragIx);
|
|
657
672
|
},
|
|
658
673
|
};
|
|
674
|
+
// Add custom drag preview options
|
|
675
|
+
if (dragPreviewOptions) {
|
|
676
|
+
rowReorderProps.dragPreviewOptions = dragPreviewOptions;
|
|
677
|
+
}
|
|
678
|
+
// Add drag preview rendering
|
|
679
|
+
rowReorderProps.getDragProxy = getCustomDragProxy ?
|
|
680
|
+
(dragItem) => getCustomDragProxy(item, getSelection()) :
|
|
681
|
+
null; // Let GlobalDragProxy handle the default case
|
|
659
682
|
rowReorderProps.onDragEnd = onRowReorderEnd;
|
|
660
683
|
rowCanDrag = true;
|
|
661
684
|
} else {
|
|
@@ -664,6 +687,7 @@ function GridComponent(props) {
|
|
|
664
687
|
WhichRow = DragSourceGridRow;
|
|
665
688
|
rowDragProps.isDragSource = true;
|
|
666
689
|
rowDragProps.dragSourceType = rowDragSourceType;
|
|
690
|
+
rowDragProps.isDragFromHandleOnly = dragFromRowHandleOnly;
|
|
667
691
|
if (getRowDragSourceItem) {
|
|
668
692
|
rowDragProps.dragSourceItem = getRowDragSourceItem(item, getSelection, isInSelection, rowDragSourceType);
|
|
669
693
|
// Ensure all drag items have a component reference
|
|
@@ -766,6 +790,7 @@ function GridComponent(props) {
|
|
|
766
790
|
areCellsScrollable={areCellsScrollable}
|
|
767
791
|
showHovers={showHovers}
|
|
768
792
|
showRowHandle={showRowHandle}
|
|
793
|
+
isRowTextSelectable={isRowTextSelectable}
|
|
769
794
|
rowCanSelect={rowCanSelect}
|
|
770
795
|
rowCanDrag={rowCanDrag}
|
|
771
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,
|
|
@@ -53,6 +54,7 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
53
54
|
isInlineEditorShown,
|
|
54
55
|
isDraggable = false, // withDraggable
|
|
55
56
|
isDragSource = false, // withDnd
|
|
57
|
+
isDragFromHandleOnly = true,
|
|
56
58
|
isOver = false, // drop target
|
|
57
59
|
canDrop,
|
|
58
60
|
draggedItem,
|
|
@@ -124,7 +126,24 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
124
126
|
}
|
|
125
127
|
const
|
|
126
128
|
visibleColumns = _.filter(columnsConfig, (config) => !config.isHidden),
|
|
127
|
-
isOnlyOneVisibleColumn = visibleColumns.length === 1
|
|
129
|
+
isOnlyOneVisibleColumn = visibleColumns.length === 1,
|
|
130
|
+
canSelectTextOnRow = isRowTextSelectable === false ? false : isDragFromHandleOnly,
|
|
131
|
+
shouldUseTextCursor = showRowHandle && canSelectTextOnRow,
|
|
132
|
+
rowShouldHaveDragRef = !isDragFromHandleOnly && (isDragSource || isDraggable) && !!dragSourceRef;
|
|
133
|
+
const setRowRef = (node) => {
|
|
134
|
+
if (typeof ref === 'function') {
|
|
135
|
+
ref(node);
|
|
136
|
+
} else if (ref) {
|
|
137
|
+
ref.current = node;
|
|
138
|
+
}
|
|
139
|
+
if (rowShouldHaveDragRef) {
|
|
140
|
+
if (typeof dragSourceRef === 'function') {
|
|
141
|
+
dragSourceRef(node);
|
|
142
|
+
} else if (dragSourceRef) {
|
|
143
|
+
dragSourceRef.current = node;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
128
147
|
|
|
129
148
|
const renderColumns = (item) => {
|
|
130
149
|
if (_.isArray(columnsConfig)) {
|
|
@@ -136,7 +155,7 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
136
155
|
const
|
|
137
156
|
propsToPass = columnProps[key] || {},
|
|
138
157
|
colStyle = {},
|
|
139
|
-
whichCursor =
|
|
158
|
+
whichCursor = shouldUseTextCursor ? 'cursor-text' : 'cursor-pointer';
|
|
140
159
|
let colClassName = clsx(
|
|
141
160
|
'GridRow-column',
|
|
142
161
|
'p-1',
|
|
@@ -144,6 +163,7 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
144
163
|
'border-r-black-100',
|
|
145
164
|
'block',
|
|
146
165
|
areCellsScrollable ? 'overflow-auto' : 'overflow-hidden',
|
|
166
|
+
canSelectTextOnRow ? null : 'select-none',
|
|
147
167
|
whichCursor,
|
|
148
168
|
styles.GRID_ROW_MAX_HEIGHT_EXTRA,
|
|
149
169
|
);
|
|
@@ -395,7 +415,7 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
395
415
|
let rowContents = <>
|
|
396
416
|
{showRowHandle &&
|
|
397
417
|
<RowHandle
|
|
398
|
-
ref={dragSourceRef}
|
|
418
|
+
ref={isDragFromHandleOnly ? dragSourceRef : undefined}
|
|
399
419
|
isDragSource={isDragSource}
|
|
400
420
|
isDraggable={isDraggable}
|
|
401
421
|
canSelect={rowCanSelect}
|
|
@@ -448,6 +468,7 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
448
468
|
let rowClassName = clsx(
|
|
449
469
|
'GridRow-HStackNative',
|
|
450
470
|
'items-center',
|
|
471
|
+
canSelectTextOnRow ? null : 'select-none',
|
|
451
472
|
);
|
|
452
473
|
if (isOnlyOneVisibleColumn) {
|
|
453
474
|
rowClassName += ' w-full';
|
|
@@ -459,7 +480,7 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
459
480
|
rowClassName += ' border-4 border-[#0ff]';
|
|
460
481
|
}
|
|
461
482
|
let row = <HStackNative
|
|
462
|
-
ref={ref}
|
|
483
|
+
ref={rowShouldHaveDragRef ? setRowRef : ref}
|
|
463
484
|
{...testProps('Row ' + (isSelected ? 'row-selected' : ''))}
|
|
464
485
|
{...rowProps}
|
|
465
486
|
key={hash}
|
|
@@ -496,8 +517,13 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
496
517
|
dragPreviewRef,
|
|
497
518
|
dropTargetRef,
|
|
498
519
|
showRowHandle,
|
|
520
|
+
isRowTextSelectable,
|
|
499
521
|
rowCanSelect,
|
|
500
522
|
rowCanDrag,
|
|
523
|
+
isDragFromHandleOnly,
|
|
524
|
+
isDragSource,
|
|
525
|
+
isDraggable,
|
|
526
|
+
dragSourceRef,
|
|
501
527
|
]);
|
|
502
528
|
});
|
|
503
529
|
|
|
@@ -222,15 +222,18 @@ export function GlobalDragProxy() {
|
|
|
222
222
|
const {
|
|
223
223
|
isDragging,
|
|
224
224
|
item,
|
|
225
|
-
|
|
225
|
+
clientOffset,
|
|
226
|
+
sourceClientOffset,
|
|
226
227
|
} = useDragLayer((monitor) => {
|
|
227
228
|
return {
|
|
228
229
|
isDragging: monitor.isDragging(),
|
|
229
230
|
item: monitor.getItem(),
|
|
230
|
-
|
|
231
|
+
clientOffset: monitor.getClientOffset(),
|
|
232
|
+
sourceClientOffset: monitor.getSourceClientOffset(),
|
|
231
233
|
};
|
|
232
234
|
});
|
|
233
235
|
|
|
236
|
+
const currentOffset = clientOffset || sourceClientOffset;
|
|
234
237
|
if (!isDragging || !currentOffset || CURRENT_MODE !== UI_MODE_WEB) { // Native uses a native drag layer, so we don't need to render a custom proxy
|
|
235
238
|
return null;
|
|
236
239
|
}
|
|
@@ -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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
58
|
-
<
|
|
59
|
-
{
|
|
60
|
-
|
|
61
|
-
|
|
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
|
}
|
package/src/UiGlobals.js
CHANGED
|
@@ -13,6 +13,7 @@ const Globals = {
|
|
|
13
13
|
doubleClickingGridRowOpensEditorInViewMode: false,
|
|
14
14
|
disableSavedColumnsConfig: true,
|
|
15
15
|
autoSubmitDelay: 500,
|
|
16
|
+
// gridAreRowsDragFromHandleOnly: true,
|
|
16
17
|
// stayInEditModeOnSelectionChange: true,
|
|
17
18
|
// isSideEditorAlwaysEditMode: true,
|
|
18
19
|
|