@onehat/ui 0.4.65 → 0.4.66
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/Grid/Grid.js +12 -3
- package/src/Components/Grid/GridHeaderRow.js +3 -3
- package/src/Components/Grid/GridRow.js +7 -3
- package/src/Components/Grid/RowDragHandle.js +1 -1
- package/src/Components/Grid/RowSelectHandle.js +3 -3
- package/src/Components/Hoc/withAlert.js +4 -0
- package/src/Components/Hoc/withDnd.js +54 -57
- package/src/Components/Icons/Arcs.js +10 -0
- package/src/Components/Tree/Tree.js +312 -310
- package/src/Components/Tree/TreeNode.js +89 -15
- package/src/Components/Tree/TreeNodeDragHandle.js +20 -0
- package/src/Components/index.js +2 -0
- package/src/Constants/Styles.js +2 -0
- package/src/PlatformImports/Web/Attachments.js +19 -4
package/package.json
CHANGED
|
@@ -133,6 +133,8 @@ function GridComponent(props) {
|
|
|
133
133
|
showHeaders = true,
|
|
134
134
|
showHovers = true,
|
|
135
135
|
showSelectHandle = true,
|
|
136
|
+
isRowSelectable = true,
|
|
137
|
+
isRowHoverable = true,
|
|
136
138
|
canColumnsSort = true,
|
|
137
139
|
canColumnsReorder = true,
|
|
138
140
|
canColumnsResize = true,
|
|
@@ -473,7 +475,13 @@ function GridComponent(props) {
|
|
|
473
475
|
onContextMenu(item, e, newSelection);
|
|
474
476
|
}
|
|
475
477
|
}}
|
|
476
|
-
className=
|
|
478
|
+
className={`
|
|
479
|
+
Pressable
|
|
480
|
+
Row
|
|
481
|
+
flex-row
|
|
482
|
+
grow
|
|
483
|
+
`}
|
|
484
|
+
>
|
|
477
485
|
{({
|
|
478
486
|
hovered,
|
|
479
487
|
focused,
|
|
@@ -505,12 +513,11 @@ function GridComponent(props) {
|
|
|
505
513
|
}
|
|
506
514
|
return headerRow;
|
|
507
515
|
}
|
|
508
|
-
|
|
509
516
|
const
|
|
510
517
|
rowReorderProps = {},
|
|
511
518
|
rowDragProps = {};
|
|
512
519
|
let WhichRow = GridRow;
|
|
513
|
-
if (CURRENT_MODE === UI_MODE_WEB) { // DND is
|
|
520
|
+
if (CURRENT_MODE === UI_MODE_WEB) { // DND is currently web-only TODO: implement for RN
|
|
514
521
|
// Create a method that gets an always-current copy of the selection ids
|
|
515
522
|
dragSelectionRef.current = selection;
|
|
516
523
|
const getSelection = () => dragSelectionRef.current;
|
|
@@ -569,6 +576,8 @@ function GridComponent(props) {
|
|
|
569
576
|
fields={fields}
|
|
570
577
|
rowProps={rowProps}
|
|
571
578
|
hideNavColumn={hideNavColumn}
|
|
579
|
+
isRowSelectable={isRowSelectable}
|
|
580
|
+
isRowHoverable={isRowHoverable}
|
|
572
581
|
isSelected={isSelected}
|
|
573
582
|
isHovered={hovered}
|
|
574
583
|
showHovers={showHovers}
|
|
@@ -20,7 +20,7 @@ import UiGlobals from '../../UiGlobals.js';
|
|
|
20
20
|
import useBlocking from '../../Hooks/useBlocking.js';
|
|
21
21
|
import testProps from '../../Functions/testProps.js';
|
|
22
22
|
import AngleRight from '../Icons/AngleRight.js';
|
|
23
|
-
import
|
|
23
|
+
import Arcs from '../Icons/Arcs.js';
|
|
24
24
|
import HeaderReorderHandle from './HeaderReorderHandle.js';
|
|
25
25
|
import HeaderResizeHandle from './HeaderResizeHandle.js';
|
|
26
26
|
import HeaderColumnSelectorHandle from './HeaderColumnSelectorHandle.js';
|
|
@@ -469,13 +469,13 @@ export default function GridHeaderRow(props) {
|
|
|
469
469
|
key="RowSelectHandle"
|
|
470
470
|
className="Spacer-RowSelectHandle px-2 items-center justify-center flex-none w-[40px]"
|
|
471
471
|
>
|
|
472
|
-
<Icon as={
|
|
472
|
+
<Icon as={Arcs} className={`Arcs w-[20px] h-[20px] text-[#aaa]`} />
|
|
473
473
|
</Box>);
|
|
474
474
|
}
|
|
475
475
|
if (areRowsDragSource) {
|
|
476
476
|
headerColumns.unshift(<Box
|
|
477
477
|
key="spacer"
|
|
478
|
-
className="Spacer w-[
|
|
478
|
+
className="Spacer w-[7px]"
|
|
479
479
|
/>);
|
|
480
480
|
}
|
|
481
481
|
if (!hideNavColumn) {
|
|
@@ -29,6 +29,8 @@ function GridRow(props) {
|
|
|
29
29
|
rowProps,
|
|
30
30
|
hideNavColumn,
|
|
31
31
|
showSelectHandle,
|
|
32
|
+
isRowSelectable,
|
|
33
|
+
isRowHoverable,
|
|
32
34
|
isSelected,
|
|
33
35
|
isHovered,
|
|
34
36
|
bg,
|
|
@@ -57,13 +59,13 @@ function GridRow(props) {
|
|
|
57
59
|
|
|
58
60
|
let bg = rowProps.bg || props.bg || styles.GRID_ROW_BG,
|
|
59
61
|
mixWith;
|
|
60
|
-
if (isSelected) {
|
|
62
|
+
if (isRowSelectable && isSelected) {
|
|
61
63
|
if (showHovers && isHovered) {
|
|
62
64
|
mixWith = styles.GRID_ROW_SELECTED_BG_HOVER;
|
|
63
65
|
} else {
|
|
64
66
|
mixWith = styles.GRID_ROW_SELECTED_BG;
|
|
65
67
|
}
|
|
66
|
-
} else if (showHovers && isHovered) {
|
|
68
|
+
} else if (isRowHoverable && showHovers && isHovered) {
|
|
67
69
|
mixWith = styles.GRID_ROW_BG_HOVER;
|
|
68
70
|
} else if (alternateRowBackgrounds && index % alternatingInterval === 0) { // i.e. every second line, or every third line
|
|
69
71
|
mixWith = styles.GRID_ROW_ALTERNATE_BG;
|
|
@@ -87,7 +89,8 @@ function GridRow(props) {
|
|
|
87
89
|
}
|
|
88
90
|
const
|
|
89
91
|
propsToPass = columnProps[key] || {},
|
|
90
|
-
colStyle = {}
|
|
92
|
+
colStyle = {},
|
|
93
|
+
whichCursor = showSelectHandle ? 'cursor-text' : 'cursor-pointer'; // when using rowSelectHandle, indicate that the row text is selectable, otherwise indicate that the row itself is selectable
|
|
91
94
|
let colClassName = `
|
|
92
95
|
GridRow-column
|
|
93
96
|
p-1
|
|
@@ -95,6 +98,7 @@ function GridRow(props) {
|
|
|
95
98
|
border-r-black-100
|
|
96
99
|
block
|
|
97
100
|
overflow-auto
|
|
101
|
+
${whichCursor}
|
|
98
102
|
${styles.GRID_ROW_MAX_HEIGHT_EXTRA}
|
|
99
103
|
`;
|
|
100
104
|
if (isOnlyOneVisibleColumn) {
|
|
@@ -7,7 +7,7 @@ import GripVertical from '../Icons/GripVertical.js';
|
|
|
7
7
|
|
|
8
8
|
function RowDragHandle(props) { return <VStack
|
|
9
9
|
style={styles.ewResize}
|
|
10
|
-
className="RowDragHandle bg-grey-100 w-[
|
|
10
|
+
className="RowDragHandle bg-grey-100 w-[7px] items-center justify-center select-none"
|
|
11
11
|
>
|
|
12
12
|
<Icon
|
|
13
13
|
as={GripVertical}
|
|
@@ -2,14 +2,14 @@ import {
|
|
|
2
2
|
Icon,
|
|
3
3
|
VStack,
|
|
4
4
|
} from '@project-components/Gluestack';
|
|
5
|
-
import
|
|
5
|
+
import Arcs from '../Icons/Arcs.js';
|
|
6
6
|
|
|
7
7
|
function RowSelectHandle(props) {
|
|
8
8
|
return <VStack
|
|
9
|
-
className="RowSelectHandle w-[40px] px-2 items-center justify-center select-none cursor-
|
|
9
|
+
className="RowSelectHandle w-[40px] px-2 items-center justify-center select-none cursor-pointer"
|
|
10
10
|
>
|
|
11
11
|
<Icon
|
|
12
|
-
as={
|
|
12
|
+
as={Arcs}
|
|
13
13
|
size="xs"
|
|
14
14
|
className="w-[20px] h-[20px] text-[#ddd]" />
|
|
15
15
|
</VStack>;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { forwardRef, useEffect, useRef, } from 'react';
|
|
2
2
|
import { useDrag, useDrop, useDragLayer } from 'react-dnd'; // https://react-dnd.github.io/react-dnd/about don't forget the wrapping <DndProvider /> as shown here: https://react-dnd.github.io/react-dnd/docs/api/dnd-provider
|
|
3
|
-
|
|
3
|
+
import {
|
|
4
|
+
Box,
|
|
5
|
+
} from '@project-components/Gluestack';
|
|
6
|
+
import {
|
|
7
|
+
UI_MODE_WEB,
|
|
8
|
+
UI_MODE_NATIVE,
|
|
9
|
+
CURRENT_MODE,
|
|
10
|
+
} from '../../Constants/UiModes.js';
|
|
4
11
|
|
|
5
12
|
// This HOC allows components to be dragged and dropped onto another component.
|
|
6
13
|
// It can't contrain the movement of the preview item, because react-dnd uses
|
|
@@ -32,6 +39,7 @@ export function withDragSource(WrappedComponent) {
|
|
|
32
39
|
onDragEnd = null,
|
|
33
40
|
canDrag = null,
|
|
34
41
|
isDragging = null,
|
|
42
|
+
getDragProxy,
|
|
35
43
|
dragCollect = (monitor, props2) => { // Optional. The collecting function. It should return a plain object of the props to return for injection into your component. It receives two parameters, monitor and props. Read the overview for an introduction to the monitors and the collecting function. See the collecting function described in detail in the next section.
|
|
36
44
|
// monitor fn determines which props from dnd state get passed
|
|
37
45
|
return {
|
|
@@ -54,7 +62,10 @@ export function withDragSource(WrappedComponent) {
|
|
|
54
62
|
|
|
55
63
|
return {
|
|
56
64
|
type: dragSourceType, // Required. This must be either a string or a symbol. Only the drop targets registered for the same type will react to this item.
|
|
57
|
-
item:
|
|
65
|
+
item: {
|
|
66
|
+
...dragSourceItem,
|
|
67
|
+
getDragProxy,
|
|
68
|
+
}, // Required (object or function).
|
|
58
69
|
// When an object, it is a plain JavaScript object describing the data being dragged. This is the only information available to the drop targets about the drag source so it's important to pick the minimal data they need to know. You may be tempted to put a complex reference here, but you should try very hard to avoid doing this because it couples the drag sources and drop targets. It's a good idea to use something like { id }.
|
|
59
70
|
// When a function, it is fired at the beginning of the drag operation and returns an object representing the drag operation (see first bullet). If null is returned, the drag operation is cancelled.
|
|
60
71
|
previewOptions: dragPreviewOptions, // Optional. A plain JavaScript object describing drag preview options.
|
|
@@ -139,6 +150,7 @@ export function withDropTarget(WrappedComponent) {
|
|
|
139
150
|
return {
|
|
140
151
|
canDrop: !!monitor.canDrop(),
|
|
141
152
|
isOver: !!monitor.isOver(),
|
|
153
|
+
draggedItem: monitor.getItem(), // Pass the dragged item so TreeNode can evaluate custom logic
|
|
142
154
|
};
|
|
143
155
|
},
|
|
144
156
|
} = props,
|
|
@@ -171,6 +183,7 @@ export function withDropTarget(WrappedComponent) {
|
|
|
171
183
|
{
|
|
172
184
|
canDrop: stateCanDrop,
|
|
173
185
|
isOver,
|
|
186
|
+
draggedItem,
|
|
174
187
|
// didDrop,
|
|
175
188
|
// clientOffset,
|
|
176
189
|
// differenceFromInitialOffset,
|
|
@@ -187,64 +200,48 @@ export function withDropTarget(WrappedComponent) {
|
|
|
187
200
|
ref={ref}
|
|
188
201
|
isOver={isOver}
|
|
189
202
|
dropTargetRef={localTargetRef}
|
|
203
|
+
draggedItem={draggedItem} // Pass the dragged item
|
|
190
204
|
{...props}
|
|
191
205
|
/>;
|
|
192
206
|
});
|
|
193
207
|
}
|
|
194
208
|
|
|
195
209
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
// return (
|
|
236
|
-
// <div id="dragLayer" style={{
|
|
237
|
-
// background: '#f00',
|
|
238
|
-
// position: 'fixed',
|
|
239
|
-
// pointerEvents: 'none',
|
|
240
|
-
// zIndex: 10000,
|
|
241
|
-
// width: '200px',
|
|
242
|
-
// height: '10px',
|
|
243
|
-
// left: 0,
|
|
244
|
-
// top: 0,
|
|
245
|
-
// transform,
|
|
246
|
-
// }}>
|
|
247
|
-
// {children}
|
|
248
|
-
// </div>
|
|
249
|
-
// );
|
|
250
|
-
// }
|
|
210
|
+
export function GlobalDragProxy() {
|
|
211
|
+
const {
|
|
212
|
+
isDragging,
|
|
213
|
+
item,
|
|
214
|
+
currentOffset,
|
|
215
|
+
} = useDragLayer((monitor) => ({
|
|
216
|
+
isDragging: monitor.isDragging(),
|
|
217
|
+
item: monitor.getItem(),
|
|
218
|
+
currentOffset: monitor.getSourceClientOffset(),
|
|
219
|
+
}));
|
|
220
|
+
|
|
221
|
+
if (!isDragging || !currentOffset || CURRENT_MODE !== UI_MODE_WEB) { // Native uses a native drag layer, so we don't need to render a custom proxy
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const getDragProxy = item?.getDragProxy;
|
|
226
|
+
if (!getDragProxy) {
|
|
227
|
+
// Only render a custom proxy if one is provided - let React DnD handle default case
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
let proxyContent = null;
|
|
232
|
+
try {
|
|
233
|
+
proxyContent = getDragProxy(item);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.warn('Failed to render custom drag proxy:', error);
|
|
236
|
+
return null; // use default React DnD proxy
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return <Box
|
|
240
|
+
className="fixed pointer-events-none z-[10000] left-0 top-0"
|
|
241
|
+
style={{
|
|
242
|
+
transform: `translate(${currentOffset.x}px, ${currentOffset.y}px)`,
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
{proxyContent}
|
|
246
|
+
</Box>;
|
|
247
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createIcon } from "../Gluestack/icon";
|
|
2
|
+
import { Path, Svg } from 'react-native-svg';
|
|
3
|
+
|
|
4
|
+
const SvgComponent = createIcon({
|
|
5
|
+
Root: Svg,
|
|
6
|
+
viewBox: '0 0 53.98 53.98',
|
|
7
|
+
path: <Path d="M14.59 0c1.1 1.66 1.74 3.65 1.74 5.79 0 5.82-4.72 10.54-10.54 10.54-2.14 0-4.13-.64-5.79-1.74 1.89 2.86 5.12 4.75 8.8 4.75 5.82 0 10.54-4.72 10.54-10.54 0-3.68-1.89-6.92-4.75-8.8zM49.23 0c1.1 1.66 1.74 3.65 1.74 5.79 0 5.82-4.72 10.54-10.54 10.54-2.14 0-4.13-.64-5.79-1.74 1.89 2.86 5.12 4.75 8.8 4.75 5.82 0 10.54-4.72 10.54-10.54 0-3.68-1.89-6.92-4.75-8.8zM14.59 34.64c1.1 1.66 1.74 3.65 1.74 5.79 0 5.82-4.72 10.54-10.54 10.54-2.14 0-4.13-.64-5.79-1.74 1.89 2.86 5.12 4.75 8.8 4.75 5.82 0 10.54-4.72 10.54-10.54 0-3.68-1.89-6.92-4.75-8.8zM49.23 34.64c1.1 1.66 1.74 3.65 1.74 5.79 0 5.82-4.72 10.54-10.54 10.54-2.14 0-4.13-.64-5.79-1.74 1.89 2.86 5.12 4.75 8.8 4.75 5.82 0 10.54-4.72 10.54-10.54 0-3.68-1.89-6.92-4.75-8.8z" />,
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
export default SvgComponent
|