@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/ui",
3
- "version": "0.4.65",
3
+ "version": "0.4.66",
4
4
  "description": "Base UI for OneHat apps",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -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="Pressable Row flex-row grow">
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 currrently web-only TODO: implement for RN
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 ArrowPointer from '../Icons/ArrowPointer.js';
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={ArrowPointer} className={`ArrowPointer w-[20px] h-[20px] text-[#aaa]`} />
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-[3px]"
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-[3px] items-center justify-center select-none"
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 ArrowPointer from '../Icons/ArrowPointer.js';
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-grab"
9
+ className="RowSelectHandle w-[40px] px-2 items-center justify-center select-none cursor-pointer"
10
10
  >
11
11
  <Icon
12
- as={ArrowPointer}
12
+ as={Arcs}
13
13
  size="xs"
14
14
  className="w-[20px] h-[20px] text-[#ddd]" />
15
15
  </VStack>;
@@ -63,6 +63,10 @@ function withAlert(WrappedComponent) {
63
63
  text-[18px]
64
64
  flex-none
65
65
  mr-2
66
+ w-full
67
+ break-words
68
+ whitespace-normal
69
+ overflow-wrap-anywhere
66
70
  `}>{message}</Text>
67
71
  </Box>
68
72
  </HStack>;
@@ -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: dragSourceItem, // Required (object or function).
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
- // export function CustomDragLayer(props) {
197
-
198
- // // if (CURRENT_MODE !== UI_MODE_WEB) {
199
- // // throw Error('CustomDragLayer only works in web mode');
200
- // // }
201
-
202
- // const
203
- // {
204
- // onDrag,
205
- // axis = null,
206
- // } = props,
207
- // layer = useDragLayer((monitor) => ({
208
- // isDragging: monitor.isDragging(),
209
- // item: monitor.getItem(),
210
- // currentOffset: monitor.getSourceClientOffset(),
211
- // })),
212
- // { isDragging, item, currentOffset } = layer;
213
-
214
- // useEffect(() => {
215
- // if (layer.isDragging) {
216
- // onDrag(layer);
217
- // }
218
- // }, [layer]);
219
-
220
- // return null;
221
-
222
- // if (!isDragging || !currentOffset) {
223
- // return null;
224
- // }
225
-
226
- // let transform;
227
- // if (axis === 'x') {
228
- // transform = `translate(${currentOffset.x}px, 0)`;
229
- // } else if (axis === 'y') {
230
- // transform = `translate(0, ${currentOffset.y}px)`;
231
- // } else {
232
- // transform = `translate(${currentOffset.x}px, ${currentOffset.y}px)`;
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