@onehat/ui 0.4.93 → 0.4.96
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/Container/Container.js +4 -4
- package/src/Components/Form/Form.js +1 -1
- package/src/Components/Grid/Grid.js +47 -6
- package/src/Components/Grid/GridRow.js +15 -10
- package/src/Components/Hoc/withAlert.js +2 -1
- package/src/Components/Hoc/withEditor.js +21 -3
- package/src/Components/Hoc/withPresetButtons.js +5 -5
- package/src/Components/Panel/GridPanel.js +4 -6
- package/src/Components/Panel/TabPanel.js +6 -2
- package/src/Components/Panel/TreePanel.js +4 -2
- package/src/Components/Tree/Tree.js +12 -1
- package/src/Components/Viewer/Viewer.js +21 -20
package/package.json
CHANGED
|
@@ -368,7 +368,7 @@ function Container(props) {
|
|
|
368
368
|
wrapperProps = {};
|
|
369
369
|
|
|
370
370
|
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
371
|
-
componentProps.className = (north.props.className || '')
|
|
371
|
+
componentProps.className = 'h-full w-full ' + (north.props.className || '');
|
|
372
372
|
wrapperProps.onLayout = (e) => {
|
|
373
373
|
const height = parseFloat(e.nativeEvent.layout.height);
|
|
374
374
|
if (height && height !== northHeight) {
|
|
@@ -406,7 +406,7 @@ function Container(props) {
|
|
|
406
406
|
wrapperProps = {};
|
|
407
407
|
|
|
408
408
|
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
409
|
-
componentProps.className = (south.props.className || '')
|
|
409
|
+
componentProps.className = 'h-full w-full ' + (south.props.className || '');
|
|
410
410
|
wrapperProps.onLayout = (e) => {
|
|
411
411
|
const height = parseFloat(e.nativeEvent.layout.height);
|
|
412
412
|
if (height && height !== getSouthHeight()) {
|
|
@@ -444,7 +444,7 @@ function Container(props) {
|
|
|
444
444
|
wrapperProps = {};
|
|
445
445
|
|
|
446
446
|
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
447
|
-
componentProps.className = (east.props.className || '')
|
|
447
|
+
componentProps.className = 'h-full w-full ' + (east.props.className || '');
|
|
448
448
|
wrapperProps.onLayout = (e) => {
|
|
449
449
|
const width = parseFloat(e.nativeEvent.layout.width);
|
|
450
450
|
if (width && width !== getEastWidth()) {
|
|
@@ -482,7 +482,7 @@ function Container(props) {
|
|
|
482
482
|
wrapperProps = {};
|
|
483
483
|
|
|
484
484
|
componentProps.isDisabled = isDisabled || isComponentsDisabled;
|
|
485
|
-
componentProps.className = (west.props.className || '')
|
|
485
|
+
componentProps.className = 'h-full w-full ' + (west.props.className || '');
|
|
486
486
|
wrapperProps.onLayout = (e) => {
|
|
487
487
|
const width = parseFloat(e.nativeEvent.layout.width);
|
|
488
488
|
if (width && width !== getWestWidth()) {
|
|
@@ -1247,7 +1247,7 @@ function Form(props) {
|
|
|
1247
1247
|
|
|
1248
1248
|
if (inArray(editorType, [EDITOR_TYPE__SIDE, EDITOR_TYPE__SMART, EDITOR_TYPE__WINDOWED]) &&
|
|
1249
1249
|
isSingle && getEditorMode() === EDITOR_MODE__EDIT &&
|
|
1250
|
-
(onBack ||
|
|
1250
|
+
(onBack || onViewMode)) {
|
|
1251
1251
|
modeHeader = <Toolbar>
|
|
1252
1252
|
<HStack className="flex-1 items-center">
|
|
1253
1253
|
{onBack &&
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
HStack,
|
|
6
6
|
Pressable,
|
|
7
7
|
// ScrollView,
|
|
8
|
+
Text,
|
|
8
9
|
VStack,
|
|
9
10
|
VStackNative,
|
|
10
11
|
} from '@project-components/Gluestack';
|
|
@@ -187,7 +188,17 @@ function GridComponent(props) {
|
|
|
187
188
|
canRowsReorder = false,
|
|
188
189
|
canRowDrag, // optional fn to customize whether each row can be dragged
|
|
189
190
|
canRowAcceptDrop, // optional fn to customize whether each node can accept a dropped item: (targetItem, draggedItem) => boolean
|
|
190
|
-
|
|
191
|
+
dragProxyField,
|
|
192
|
+
getCustomDragProxy = (item, selection) => { // optional fn to render custom drag preview: (item, selection) => ReactElement
|
|
193
|
+
let selectionCount = selection?.length || 1,
|
|
194
|
+
displayText = dragProxyField ? item[dragProxyField] : (item.displayValue || 'Selected Row');
|
|
195
|
+
return <VStack className="bg-white border border-gray-300 rounded-lg p-3 shadow-lg max-w-[200px]">
|
|
196
|
+
<Text className="font-semibold text-gray-800">{displayText}</Text>
|
|
197
|
+
{selectionCount > 1 &&
|
|
198
|
+
<Text className="text-sm text-gray-600">(+{selectionCount -1} more item{selectionCount > 2 ? 's' : ''})</Text>
|
|
199
|
+
}
|
|
200
|
+
</VStack>;
|
|
201
|
+
},
|
|
191
202
|
dragPreviewOptions, // optional object for drag preview positioning options
|
|
192
203
|
areRowsDragSource = false,
|
|
193
204
|
rowDragSourceType,
|
|
@@ -260,6 +271,7 @@ function GridComponent(props) {
|
|
|
260
271
|
} = props,
|
|
261
272
|
styles = UiGlobals.styles,
|
|
262
273
|
id = props.id || props.self?.path,
|
|
274
|
+
entities = Repository ? (Repository.isRemote ? Repository.entities : Repository.getEntitiesOnPage()) : data,
|
|
263
275
|
localColumnsConfigKey = id && id + '-localColumnsConfig',
|
|
264
276
|
[hasUnserializableColumns] = useState(() => {
|
|
265
277
|
return !isSerializable(columnsConfig); // (runs only once, when the component is first created)
|
|
@@ -280,6 +292,8 @@ function GridComponent(props) {
|
|
|
280
292
|
measuredRowsRef = useRef([]),
|
|
281
293
|
footerToolbarRef = useRef(null),
|
|
282
294
|
rowRefs = useRef([]),
|
|
295
|
+
previousEntitiesLength = useRef(0),
|
|
296
|
+
hasRemeasuredAfterRowsAppeared = useRef(false),
|
|
283
297
|
[isInited, setIsInited] = useState(false),
|
|
284
298
|
[isReady, setIsReady] = useState(false),
|
|
285
299
|
[isLoading, setIsLoading] = useState(false),
|
|
@@ -1118,12 +1132,12 @@ function GridComponent(props) {
|
|
|
1118
1132
|
// Keep the current estimated pageSize, just hide the loading overlay
|
|
1119
1133
|
}
|
|
1120
1134
|
},
|
|
1121
|
-
adjustPageSizeToHeight = (containerHeight) => {
|
|
1135
|
+
adjustPageSizeToHeight = (containerHeight, forceRemeasure = false) => {
|
|
1122
1136
|
if (!Repository || Repository.isDestroyed) { // This method gets delayed, so it's possible for Repository to have been destroyed. Check for this
|
|
1123
1137
|
return;
|
|
1124
1138
|
}
|
|
1125
1139
|
if (DEBUG) {
|
|
1126
|
-
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A`);
|
|
1140
|
+
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A forceRemeasure=${forceRemeasure}`);
|
|
1127
1141
|
}
|
|
1128
1142
|
|
|
1129
1143
|
let doAdjustment = autoAdjustPageSizeToHeight;
|
|
@@ -1135,11 +1149,11 @@ function GridComponent(props) {
|
|
|
1135
1149
|
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A2 doAdjustment=${doAdjustment}, autoAdjustPageSizeToHeight=${autoAdjustPageSizeToHeight}, UiGlobals.autoAdjustPageSizeToHeight=${UiGlobals.autoAdjustPageSizeToHeight}, containerHeight=${containerHeight}`);
|
|
1136
1150
|
}
|
|
1137
1151
|
|
|
1138
|
-
// Only proceed if height changed significantly
|
|
1152
|
+
// Only proceed if height changed significantly or forced
|
|
1139
1153
|
const
|
|
1140
1154
|
heightChanged = Math.abs(containerHeight - lastMeasuredContainerHeight) > 5, // 5px tolerance
|
|
1141
1155
|
isFirstMeasurement = lastMeasuredContainerHeight === 0;
|
|
1142
|
-
if (containerHeight > 0 && (isFirstMeasurement || heightChanged)) {
|
|
1156
|
+
if (containerHeight > 0 && (isFirstMeasurement || heightChanged || forceRemeasure)) {
|
|
1143
1157
|
if (editorType === EDITOR_TYPE__SIDE && getIsEditorShown()) {
|
|
1144
1158
|
// When side editor is shown, skip adjustment to avoid layout thrashing
|
|
1145
1159
|
console.log(`${getMeasurementPhase()}, adjustPageSizeToHeight A4 height changed significantly, but side editor is shown, skipping remeasurement`);
|
|
@@ -1543,6 +1557,34 @@ function GridComponent(props) {
|
|
|
1543
1557
|
}
|
|
1544
1558
|
}, [autoAdjustPageSizeToHeight]);
|
|
1545
1559
|
|
|
1560
|
+
// Reset measurement when rows were first empty then became populated
|
|
1561
|
+
useEffect(() => {
|
|
1562
|
+
const
|
|
1563
|
+
currentLength = entities?.length || 0,
|
|
1564
|
+
wasEmpty = previousEntitiesLength.current === 0,
|
|
1565
|
+
isNowPopulated = currentLength > 0;
|
|
1566
|
+
|
|
1567
|
+
// Only remeasure the FIRST time rows appear after being empty
|
|
1568
|
+
if (autoAdjustPageSizeToHeight && wasEmpty && isNowPopulated && !hasRemeasuredAfterRowsAppeared.current) {
|
|
1569
|
+
// Rows just appeared for the first time - restart measurement cycle to use actual heights
|
|
1570
|
+
if (DEBUG) {
|
|
1571
|
+
console.log(`${getMeasurementPhase()}, useEffect 5 - rows appeared for first time, restarting measurement cycle`);
|
|
1572
|
+
}
|
|
1573
|
+
hasRemeasuredAfterRowsAppeared.current = true;
|
|
1574
|
+
|
|
1575
|
+
setMeasurementPhase(PHASES__INITIAL);
|
|
1576
|
+
setMeasuredRowHeight(null);
|
|
1577
|
+
measuredRowsRef.current = [];
|
|
1578
|
+
|
|
1579
|
+
// Trigger remeasurement with force flag since actual rows are now available
|
|
1580
|
+
if (lastMeasuredContainerHeight > 0) {
|
|
1581
|
+
adjustPageSizeToHeight(lastMeasuredContainerHeight, true);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
previousEntitiesLength.current = currentLength;
|
|
1586
|
+
}, [entities?.length, autoAdjustPageSizeToHeight]);
|
|
1587
|
+
|
|
1546
1588
|
if (canUser && !canUser('view')) {
|
|
1547
1589
|
return <Unauthorized />;
|
|
1548
1590
|
}
|
|
@@ -1579,7 +1621,6 @@ function GridComponent(props) {
|
|
|
1579
1621
|
}
|
|
1580
1622
|
|
|
1581
1623
|
// Actual data to show in the grid
|
|
1582
|
-
const entities = Repository ? (Repository.isRemote ? Repository.entities : Repository.getEntitiesOnPage()) : data;
|
|
1583
1624
|
let rowData = [...entities]; // don't use the original array, make a new one so alterations to it are temporary
|
|
1584
1625
|
if (showHeaders) {
|
|
1585
1626
|
rowData.unshift({ id: 'headerRow' });
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
CURRENT_MODE,
|
|
15
15
|
} from '../../Constants/UiModes.js';
|
|
16
16
|
import * as colourMixer from '@k-renwick/colour-mixer';
|
|
17
|
+
import Tooltip from '../Tooltip/Tooltip.js';
|
|
17
18
|
import getComponentFromType from '../../Functions/getComponentFromType.js';
|
|
18
19
|
import UiGlobals from '../../UiGlobals.js';
|
|
19
20
|
import { withDragSource, withDropTarget } from '../Hoc/withDnd.js';
|
|
@@ -457,16 +458,20 @@ const GridRow = forwardRef((props, ref) => {
|
|
|
457
458
|
if (isOver) {
|
|
458
459
|
rowClassName += ' border-4 border-[#0ff]';
|
|
459
460
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
461
|
+
let row = <HStackNative
|
|
462
|
+
ref={ref}
|
|
463
|
+
{...testProps('Row ' + (isSelected ? 'row-selected' : ''))}
|
|
464
|
+
{...rowProps}
|
|
465
|
+
key={hash}
|
|
466
|
+
className={rowClassName}
|
|
467
|
+
style={{
|
|
468
|
+
backgroundColor: bg,
|
|
469
|
+
}}
|
|
470
|
+
>{rowContents}</HStackNative>;
|
|
471
|
+
if (rowProps.tooltip) {
|
|
472
|
+
row = <Tooltip label={rowProps.tooltip} placement="bottom left">{row}</Tooltip>;
|
|
473
|
+
}
|
|
474
|
+
return row;
|
|
470
475
|
}, [
|
|
471
476
|
columnsConfig,
|
|
472
477
|
asyncResults,
|
|
@@ -61,6 +61,7 @@ function withAlert(WrappedComponent) {
|
|
|
61
61
|
'flex-1',
|
|
62
62
|
'items-start',
|
|
63
63
|
'justify-center',
|
|
64
|
+
'p-4',
|
|
64
65
|
)}>
|
|
65
66
|
<Text className={clsx(
|
|
66
67
|
'withAlert-Text',
|
|
@@ -164,7 +165,7 @@ function withAlert(WrappedComponent) {
|
|
|
164
165
|
}),
|
|
165
166
|
onOk: () => hideModal(),
|
|
166
167
|
canClose: true,
|
|
167
|
-
h:
|
|
168
|
+
h: 250,
|
|
168
169
|
w: 400,
|
|
169
170
|
whichModal: 'info',
|
|
170
171
|
});
|
|
@@ -30,6 +30,8 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
30
30
|
userCanView = true,
|
|
31
31
|
canEditorViewOnly = false, // whether the editor can *ever* change state out of 'View' mode
|
|
32
32
|
canProceedWithCrud, // fn returns bool on if the CRUD operation can proceed
|
|
33
|
+
canRecordBeEdited, // fn(selection) returns bool on if the current record(s) can be edited
|
|
34
|
+
canRecordBeDeleted, // fn(selection) returns bool on if the current record(s) can be deleted
|
|
33
35
|
disableAdd = false,
|
|
34
36
|
disableEdit = false,
|
|
35
37
|
disableDelete = false,
|
|
@@ -87,6 +89,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
87
89
|
editorModeRef = useRef(initialEditorMode),
|
|
88
90
|
isIgnoreNextSelectionChangeRef = useRef(false),
|
|
89
91
|
isEditorShownRef = useRef(false),
|
|
92
|
+
canEditorBeInEditModeRef = useRef(true), // whether the editor is allowed to be in edit mode based on canRecordBeEdited
|
|
90
93
|
[currentRecord, setCurrentRecord] = useState(null),
|
|
91
94
|
[isAdding, setIsAdding] = useState(false),
|
|
92
95
|
[isSaving, setIsSaving] = useState(false),
|
|
@@ -108,6 +111,13 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
108
111
|
getIsEditorShown = () => {
|
|
109
112
|
return isEditorShownRef.current;
|
|
110
113
|
},
|
|
114
|
+
setCanEditorBeInEditMode = (bool) => {
|
|
115
|
+
canEditorBeInEditModeRef.current = bool;
|
|
116
|
+
forceUpdate();
|
|
117
|
+
},
|
|
118
|
+
getCanEditorBeInEditMode = () => {
|
|
119
|
+
return canEditorBeInEditModeRef.current;
|
|
120
|
+
},
|
|
111
121
|
setIsWaitModalShown = (bool) => {
|
|
112
122
|
const
|
|
113
123
|
dispatch = UiGlobals.redux?.dispatch,
|
|
@@ -624,6 +634,9 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
624
634
|
});
|
|
625
635
|
},
|
|
626
636
|
calculateEditorMode = () => {
|
|
637
|
+
if (!getCanEditorBeInEditMode()) { // this is a result of canRecordBeEdited returning false
|
|
638
|
+
return EDITOR_MODE__VIEW;
|
|
639
|
+
}
|
|
627
640
|
|
|
628
641
|
let isIgnoreNextSelectionChange = getIsIgnoreNextSelectionChange(),
|
|
629
642
|
doStayInEditModeOnSelectionChange = stayInEditModeOnSelectionChange;
|
|
@@ -691,7 +704,7 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
691
704
|
useEffect(() => {
|
|
692
705
|
|
|
693
706
|
if (editorType === EDITOR_TYPE__SIDE) {
|
|
694
|
-
if (selection?.length) { //
|
|
707
|
+
if (selection?.length) { // || isAdding
|
|
695
708
|
// there is a selection, so show the editor
|
|
696
709
|
setIsEditorShown(true);
|
|
697
710
|
} else {
|
|
@@ -700,6 +713,11 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
700
713
|
}
|
|
701
714
|
}
|
|
702
715
|
|
|
716
|
+
if (canRecordBeEdited && canRecordBeEdited(selection) === false) {
|
|
717
|
+
setCanEditorBeInEditMode(false);
|
|
718
|
+
} else {
|
|
719
|
+
setCanEditorBeInEditMode(true);
|
|
720
|
+
}
|
|
703
721
|
setEditorMode(calculateEditorMode());
|
|
704
722
|
setLastSelection(selection);
|
|
705
723
|
|
|
@@ -749,8 +767,8 @@ export default function withEditor(WrappedComponent, isTree = false) {
|
|
|
749
767
|
setIsEditorShown={setIsEditorShown}
|
|
750
768
|
setIsIgnoreNextSelectionChange={setIsIgnoreNextSelectionChange}
|
|
751
769
|
onAdd={(!userCanEdit || disableAdd) ? null : doAdd}
|
|
752
|
-
onEdit={(!userCanEdit || disableEdit) ? null : doEdit}
|
|
753
|
-
onDelete={(!userCanEdit || disableDelete) ? null : doDelete}
|
|
770
|
+
onEdit={(!userCanEdit || disableEdit || (canRecordBeEdited && !canRecordBeEdited(selection))) ? null : doEdit}
|
|
771
|
+
onDelete={(!userCanEdit || disableDelete || (canRecordBeDeleted && !canRecordBeDeleted(selection))) ? null : doDelete}
|
|
754
772
|
onView={doView}
|
|
755
773
|
onDuplicate={doDuplicate}
|
|
756
774
|
onEditorSave={doEditorSave}
|
|
@@ -48,7 +48,7 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
const {
|
|
51
|
-
//
|
|
51
|
+
// for local use
|
|
52
52
|
contextMenuItems = [],
|
|
53
53
|
additionalToolbarButtons = [],
|
|
54
54
|
useUploadDownload = false,
|
|
@@ -59,18 +59,18 @@ export default function withPresetButtons(WrappedComponent, isGrid = false) {
|
|
|
59
59
|
downloadHeaders,
|
|
60
60
|
downloadParams,
|
|
61
61
|
onChangeColumnsConfig,
|
|
62
|
-
canRecordBeEdited,
|
|
63
|
-
canRecordBeDeleted,
|
|
64
|
-
canRecordBeDuplicated,
|
|
65
62
|
...propsToPass
|
|
66
63
|
} = props,
|
|
67
64
|
{
|
|
68
|
-
//
|
|
65
|
+
// extract and pass down
|
|
69
66
|
isEditor = false,
|
|
70
67
|
isTree = false,
|
|
71
68
|
canDeleteRootNode = false,
|
|
72
69
|
isSideEditor = false,
|
|
73
70
|
canEditorViewOnly = false,
|
|
71
|
+
canRecordBeEdited, // fn(selection) returns bool on if the current record(s) can be edited
|
|
72
|
+
canRecordBeDeleted, // fn(selection) returns bool on if the current record(s) can be deleted
|
|
73
|
+
canRecordBeDuplicated, // fn(selection) returns bool on if the current record(s) can be duplicated
|
|
74
74
|
disableAdd = !isEditor,
|
|
75
75
|
disableEdit = !isEditor,
|
|
76
76
|
disableDelete = !isEditor,
|
|
@@ -11,6 +11,8 @@ export function GridPanel(props) {
|
|
|
11
11
|
const {
|
|
12
12
|
isEditor = false,
|
|
13
13
|
editorType = EDITOR_TYPE__WINDOWED,
|
|
14
|
+
_panel = {},
|
|
15
|
+
_grid = {},
|
|
14
16
|
} = props;
|
|
15
17
|
|
|
16
18
|
let WhichGrid = Grid;
|
|
@@ -28,12 +30,8 @@ export function GridPanel(props) {
|
|
|
28
30
|
}
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return <Panel {...props} {...props._panel}>
|
|
36
|
-
<WhichGrid {...props} />
|
|
33
|
+
return <Panel {...props} {..._panel}>
|
|
34
|
+
<WhichGrid {...props} {..._grid} />
|
|
37
35
|
</Panel>;
|
|
38
36
|
}
|
|
39
37
|
|
|
@@ -3,7 +3,11 @@ import Panel from './Panel.js';
|
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
export default function TabPanel(props) {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
const {
|
|
7
|
+
_panel = {},
|
|
8
|
+
_tab = {},
|
|
9
|
+
} = props;
|
|
10
|
+
return <Panel className="w-full flex" {..._panel}>
|
|
11
|
+
<TabBar {...props} {..._tab} />
|
|
8
12
|
</Panel>;
|
|
9
13
|
}
|
|
@@ -10,6 +10,8 @@ export function TreePanel(props) {
|
|
|
10
10
|
const {
|
|
11
11
|
isEditor = false,
|
|
12
12
|
editorType = EDITOR_TYPE__WINDOWED,
|
|
13
|
+
_panel = {},
|
|
14
|
+
_tree = {},
|
|
13
15
|
} = props;
|
|
14
16
|
|
|
15
17
|
let WhichTree = Tree;
|
|
@@ -24,8 +26,8 @@ export function TreePanel(props) {
|
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
|
|
27
|
-
return <Panel {...
|
|
28
|
-
<WhichTree {...props} {...
|
|
29
|
+
return <Panel {..._panel}>
|
|
30
|
+
<WhichTree {...props} {..._tree} />
|
|
29
31
|
</Panel>;
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
HStack,
|
|
4
4
|
Pressable,
|
|
5
5
|
ScrollView,
|
|
6
|
+
Text,
|
|
6
7
|
VStack,
|
|
7
8
|
VStackNative,
|
|
8
9
|
} from '@project-components/Gluestack';
|
|
@@ -133,7 +134,17 @@ function TreeComponent(props) {
|
|
|
133
134
|
canNodeMoveInternally, // optional fn to customize whether each node can be dragged INternally
|
|
134
135
|
canNodeMoveExternally, // optional fn to customize whether each node can be dragged EXternally
|
|
135
136
|
canNodeAcceptDrop, // optional fn to customize whether each node can accept a dropped item: (targetItem, draggedItem) => boolean
|
|
136
|
-
|
|
137
|
+
dragProxyField,
|
|
138
|
+
getCustomDragProxy = (item, selection) => { // optional fn to render custom drag preview: (item, selection) => ReactElement
|
|
139
|
+
let selectionCount = selection?.length || 1,
|
|
140
|
+
displayText = dragProxyField ? item[dragProxyField] : (item.displayValue || 'Selected TreeNode');
|
|
141
|
+
return <VStack className="bg-white border border-gray-300 rounded-lg p-3 shadow-lg max-w-[200px]">
|
|
142
|
+
<Text className="font-semibold text-gray-800">{displayText}</Text>
|
|
143
|
+
{selectionCount > 1 &&
|
|
144
|
+
<Text className="text-sm text-gray-600">(+{selectionCount -1} more item{selectionCount > 2 ? 's' : ''})</Text>
|
|
145
|
+
}
|
|
146
|
+
</VStack>;
|
|
147
|
+
},
|
|
137
148
|
dragPreviewOptions, // optional object for drag preview positioning options
|
|
138
149
|
areNodesDragSource = false,
|
|
139
150
|
nodeDragSourceType,
|
|
@@ -543,26 +543,27 @@ function Viewer(props) {
|
|
|
543
543
|
)}
|
|
544
544
|
>
|
|
545
545
|
{scrollToTopAnchor}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
546
|
+
|
|
547
|
+
<Toolbar className="justify-end">
|
|
548
|
+
<HStack className="flex-1 items-center">
|
|
549
|
+
<Text className="text-[20px] ml-1 text-grey-500">View Mode</Text>
|
|
550
|
+
</HStack>
|
|
551
|
+
{onEditMode && (!canUser || canUser(EDIT)) &&
|
|
552
|
+
<Button
|
|
553
|
+
{...testProps('toEditBtn')}
|
|
554
|
+
key="editBtn"
|
|
555
|
+
onPress={onEditMode}
|
|
556
|
+
icon={Pencil}
|
|
557
|
+
_icon={{
|
|
558
|
+
size: 'sm',
|
|
559
|
+
className: 'text-white'
|
|
560
|
+
}}
|
|
561
|
+
className="text-white"
|
|
562
|
+
text="To Edit"
|
|
563
|
+
tooltip="Switch to Edit Mode"
|
|
564
|
+
isDisabled={!canEdit}
|
|
565
|
+
/>}
|
|
566
|
+
</Toolbar>
|
|
566
567
|
|
|
567
568
|
{!_.isEmpty(additionalButtons) &&
|
|
568
569
|
<Toolbar className="justify-end flex-wrap gap-2">
|