@onehat/ui 0.4.70 → 0.4.72

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.
Files changed (120) hide show
  1. package/package.json +2 -1
  2. package/src/Components/Accordion/Accordion.js +1 -0
  3. package/src/Components/Blank.js +1 -0
  4. package/src/Components/Buttons/BackButton.js +1 -0
  5. package/src/Components/Buttons/Button.js +18 -10
  6. package/src/Components/Buttons/CartButtonWithBadge.js +1 -0
  7. package/src/Components/Buttons/IconButton.js +9 -8
  8. package/src/Components/Buttons/PlusMinusButton.js +5 -4
  9. package/src/Components/Buttons/SquareButton.js +19 -18
  10. package/src/Components/Container/Container.js +1 -0
  11. package/src/Components/Container/ContainerColumn.js +4 -3
  12. package/src/Components/Container/ScreenContainer.js +14 -13
  13. package/src/Components/Container/Splitter.js +33 -28
  14. package/src/Components/Editor/InlineEditor.js +32 -30
  15. package/src/Components/Fab/DynamicFab.js +14 -13
  16. package/src/Components/Fab/FabWithTooltip.js +1 -0
  17. package/src/Components/Filter/DateRange.js +8 -7
  18. package/src/Components/Filter/NumberRange.js +8 -7
  19. package/src/Components/Form/Field/CKEditor/CKEditor.js +1 -0
  20. package/src/Components/Form/Field/Checkbox/CheckboxGroup.js +1 -0
  21. package/src/Components/Form/Field/Color.js +41 -40
  22. package/src/Components/Form/Field/Combo/Combo.js +173 -172
  23. package/src/Components/Form/Field/Combo/MeterTypesCombo.js +4 -2
  24. package/src/Components/Form/Field/Combo/PageSizeCombo.js +1 -0
  25. package/src/Components/Form/Field/Date.js +117 -116
  26. package/src/Components/Form/Field/DisplayField.js +6 -5
  27. package/src/Components/Form/Field/File.js +1 -0
  28. package/src/Components/Form/Field/FormikForm.js +1 -0
  29. package/src/Components/Form/Field/Input.js +20 -18
  30. package/src/Components/Form/Field/Json.js +7 -6
  31. package/src/Components/Form/Field/Number.js +31 -30
  32. package/src/Components/Form/Field/RadioGroup/RadioGroup.js +1 -0
  33. package/src/Components/Form/Field/Select/PageSizeSelect.js +1 -0
  34. package/src/Components/Form/Field/Select/Select.js +9 -8
  35. package/src/Components/Form/Field/Slider.js +15 -14
  36. package/src/Components/Form/Field/Tag/Tag.js +25 -24
  37. package/src/Components/Form/Field/Tag/ValueBox.js +32 -31
  38. package/src/Components/Form/Field/Text.js +9 -8
  39. package/src/Components/Form/Field/TextArea.js +9 -8
  40. package/src/Components/Form/Field/Toggle.js +16 -15
  41. package/src/Components/Form/FieldSet.js +27 -26
  42. package/src/Components/Form/Form.js +104 -103
  43. package/src/Components/Form/Label.js +15 -14
  44. package/src/Components/Grid/Grid.js +62 -52
  45. package/src/Components/Grid/GridHeaderRow.js +42 -40
  46. package/src/Components/Grid/GridRow.js +92 -90
  47. package/src/Components/Grid/HeaderColumnSelectorHandle.js +9 -8
  48. package/src/Components/Grid/HeaderReorderHandle.js +9 -8
  49. package/src/Components/Grid/HeaderResizeHandle.js +9 -8
  50. package/src/Components/Grid/NoRecordsFound.js +4 -3
  51. package/src/Components/Grid/RowDragHandle.js +26 -10
  52. package/src/Components/Grid/RowHandle.js +55 -0
  53. package/src/Components/Grid/RowSelectHandle.js +1 -0
  54. package/src/{Hooks → Components/Grid}/useAsyncRenderers.js +1 -1
  55. package/src/Components/Hoc/Secondary/withSecondaryData.js +2 -1
  56. package/src/Components/Hoc/Secondary/withSecondaryEditor.js +4 -3
  57. package/src/Components/Hoc/Secondary/withSecondarySelection.js +3 -2
  58. package/src/Components/Hoc/Secondary/withSecondaryValue.js +2 -1
  59. package/src/Components/Hoc/Secondary/withSecondaryWindowedEditor.js +6 -5
  60. package/src/Components/Hoc/withAlert.js +38 -35
  61. package/src/Components/Hoc/withCollapsible.js +9 -4
  62. package/src/Components/Hoc/withComponent.js +6 -0
  63. package/src/Components/Hoc/withContextMenu.js +33 -26
  64. package/src/Components/Hoc/withData.js +3 -2
  65. package/src/Components/Hoc/withDnd.js +17 -8
  66. package/src/Components/Hoc/withDraggable.js +21 -5
  67. package/src/Components/Hoc/withEditor.js +3 -2
  68. package/src/Components/Hoc/withEvents.js +11 -1
  69. package/src/Components/Hoc/withFilters.js +26 -20
  70. package/src/Components/Hoc/withModal.js +10 -8
  71. package/src/Components/Hoc/withPdfButtons.js +3 -2
  72. package/src/Components/Hoc/withPermissions.js +3 -2
  73. package/src/Components/Hoc/withPresetButtons.js +3 -2
  74. package/src/Components/Hoc/withSelection.js +2 -8
  75. package/src/Components/Hoc/withToast.js +5 -2
  76. package/src/Components/Hoc/withTooltip.js +10 -1
  77. package/src/Components/Hoc/withValue.js +3 -9
  78. package/src/Components/Hoc/withWindowedEditor.js +6 -5
  79. package/src/Components/Layout/AsyncOperation.js +1 -0
  80. package/src/Components/Layout/CenterBox.js +9 -8
  81. package/src/Components/Layout/Footer.js +11 -10
  82. package/src/Components/Layout/ScreenHeader.js +5 -4
  83. package/src/Components/Layout/TextWithTooltip.js +1 -0
  84. package/src/Components/Messages/ConfirmationMessage.js +6 -5
  85. package/src/Components/Messages/ErrorMessage.js +40 -39
  86. package/src/Components/Messages/GlobalModals.js +47 -0
  87. package/src/Components/Messages/Loading.js +1 -0
  88. package/src/Components/Messages/OkMessage.js +11 -10
  89. package/src/Components/Messages/Unauthorized.js +1 -0
  90. package/src/Components/Messages/WaitMessage.js +16 -15
  91. package/src/Components/Panel/AccordionGridPanel.js +1 -0
  92. package/src/Components/Panel/FormPanel.js +1 -0
  93. package/src/Components/Panel/Header.js +59 -58
  94. package/src/Components/Panel/Mask.js +1 -0
  95. package/src/Components/Panel/Panel.js +7 -6
  96. package/src/Components/Picker/Picker.js +1 -0
  97. package/src/Components/Report/Report.js +35 -34
  98. package/src/Components/Screens/Manager.js +1 -0
  99. package/src/Components/Screens/ReportsManager.js +1 -0
  100. package/src/Components/Tab/Tab.js +1 -0
  101. package/src/Components/Tab/TabBar.js +67 -66
  102. package/src/Components/Toolbar/FilterToolbar.js +14 -11
  103. package/src/Components/Toolbar/Pagination.js +26 -25
  104. package/src/Components/Toolbar/PaginationToolbar.js +13 -12
  105. package/src/Components/Toolbar/Toolbar.js +13 -12
  106. package/src/Components/Tooltip/Tooltip.js +1 -0
  107. package/src/Components/Tree/Tree.js +34 -17
  108. package/src/Components/Tree/TreeNode.js +30 -29
  109. package/src/Components/Tree/TreeNodeDragHandle.js +18 -13
  110. package/src/Components/Viewer/MeterTypeText.js +29 -8
  111. package/src/Components/Viewer/TextWithLinks.js +16 -15
  112. package/src/Components/Viewer/Viewer.js +23 -22
  113. package/src/Components/Window/UploadsDownloadsWindow.js +6 -5
  114. package/src/Components/index.js +1 -0
  115. package/src/Constants/MeterTypes.js +2 -0
  116. package/src/Functions/addIconProps.js +46 -0
  117. package/src/Functions/testProps.js +1 -1
  118. package/src/Hooks/useWhyDidYouUpdate.js +33 -0
  119. package/src/PlatformImports/Web/Attachments.js +1 -1
  120. package/src/Components/Hoc/withBlank.js +0 -10
@@ -8,6 +8,7 @@ import {
8
8
  VStack,
9
9
  VStackNative,
10
10
  } from '@project-components/Gluestack';
11
+ import clsx from 'clsx';
11
12
  import {
12
13
  HORIZONTAL,
13
14
  VERTICAL,
@@ -130,11 +131,11 @@ function TabBar(props) {
130
131
  tooltip={isCollapsed ? 'Expand' : 'Collapse'}
131
132
  />;
132
133
  } else {
133
- tabClassName += `
134
- ${direction === VERTICAL ? 'w-[200px]' : ''}
135
- pr-0
136
- mr-0
137
- `;
134
+ tabClassName += clsx(
135
+ direction === VERTICAL ? 'w-[200px]' : '',
136
+ 'pr-0',
137
+ 'mr-0',
138
+ );
138
139
  _icon.as = Minimize;
139
140
  button = <Button
140
141
  {...testProps('toggleBtn')}
@@ -158,59 +159,59 @@ function TabBar(props) {
158
159
  getTabProps = () => {
159
160
  const
160
161
  tabProps = {
161
- className: `
162
- ${styles.TAB_BG}
163
- ${isCollapsed ? 'justify-center' : 'justify-start'}
164
- `,
162
+ className: clsx(
163
+ styles.TAB_BG,
164
+ isCollapsed ? 'justify-center' : 'justify-start',
165
+ ),
165
166
  },
166
167
  textProps = {
167
168
  // numberOfLines: 1,
168
169
  // ellipsizeMode: 'head',
169
- className: `
170
- ${styles.TAB_FONTSIZE}
171
- ${styles.TAB_COLOR}
172
- `,
170
+ className: clsx(
171
+ styles.TAB_FONTSIZE,
172
+ styles.TAB_COLOR,
173
+ ),
173
174
  },
174
175
  iconProps = {
175
176
  // size: 'md',
176
- className: `
177
- ${styles.TAB_ICON_COLOR}
178
- `,
177
+ className: clsx(
178
+ styles.TAB_ICON_COLOR,
179
+ ),
179
180
  };
180
181
  switch(direction) {
181
182
  case VERTICAL:
182
- tabProps.className += `
183
- rounded-l-lg
184
- rounded-r-none
185
- w-full
186
- ml-2
187
- mr-0
188
- mb-1
189
- px-4
190
- `;
191
- textProps.className += `
192
- w-full
193
- mr-0
194
- mb-1
195
- py-0
196
- pl-3
197
- pr-0
198
- flex-1
199
- text-left
200
- `;
183
+ tabProps.className += clsx(
184
+ 'rounded-l-lg',
185
+ 'rounded-r-none',
186
+ 'w-full',
187
+ 'ml-2',
188
+ 'mr-0',
189
+ 'mb-1',
190
+ 'px-4',
191
+ );
192
+ textProps.className += clsx(
193
+ 'w-full',
194
+ 'mr-0',
195
+ 'mb-1',
196
+ 'py-0',
197
+ 'pl-3',
198
+ 'pr-0',
199
+ 'flex-1',
200
+ 'text-left',
201
+ );
201
202
  break;
202
203
  case HORIZONTAL:
203
- tabProps.className += `
204
- rounded-t
205
- rounded-b-none
206
- mr-1
207
- py-1
208
- `;
209
- textProps.className += `
210
- px-1
211
- py-0
212
- mr-1
213
- `;
204
+ tabProps.className += clsx(
205
+ 'rounded-t',
206
+ 'rounded-b-none',
207
+ 'mr-1',
208
+ 'py-1',
209
+ );
210
+ textProps.className += clsx(
211
+ 'px-1',
212
+ 'py-0',
213
+ 'mr-1',
214
+ );
214
215
  break;
215
216
  default:
216
217
  }
@@ -459,16 +460,16 @@ function TabBar(props) {
459
460
  tabBar = <VStackNative
460
461
  {...testProps('TabBar')}
461
462
  {...propsToPass}
462
- className={`
463
- ${isCollapsed ? 'w-[50px]' : 'w-[' + tabWidth + 'px]'}
464
- ${isCollapsed ? 'pl-1' : 'pl-4'}
465
- items-center
466
- justify-start
467
- py-2
468
- overflow-x-hidden
469
- overflow-y-auto
470
- ${styles.TAB_BAR_CLASSNAME}
471
- `}
463
+ className={clsx(
464
+ isCollapsed ? 'w-[50px]' : 'w-[' + tabWidth + 'px]',
465
+ isCollapsed ? 'pl-1' : 'pl-4',
466
+ 'items-center',
467
+ 'justify-start',
468
+ 'py-2',
469
+ 'overflow-x-hidden',
470
+ 'overflow-y-auto',
471
+ styles.TAB_BAR_CLASSNAME
472
+ )}
472
473
  >
473
474
  {renderedTabs}
474
475
  {canToggleCollapse ?
@@ -488,16 +489,16 @@ function TabBar(props) {
488
489
  if (direction === HORIZONTAL) {
489
490
  tabBar = <HStackNative
490
491
  {...testProps('TabBar')}
491
- className={`
492
- ${'h-[' + tabHeight + 'px]'}
493
- items-center
494
- justify-start
495
- overflow-x-auto
496
- overflow-y-hidden
497
- p-1
498
- pb-0
499
- ${styles.TAB_BAR_CLASSNAME}
500
- `}
492
+ className={clsx(
493
+ 'h-[' + tabHeight + 'px]',
494
+ 'items-center',
495
+ 'justify-start',
496
+ 'overflow-x-auto',
497
+ 'overflow-y-hidden',
498
+ 'p-1',
499
+ 'pb-0',
500
+ styles.TAB_BAR_CLASSNAME
501
+ )}
501
502
  >
502
503
  <ScrollView
503
504
  horizontal={true}
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  HStack,
3
3
  } from '@project-components/Gluestack';
4
+ import clsx from 'clsx';
4
5
  import Toolbar from './Toolbar.js'
5
6
  import _ from 'lodash';
6
7
 
@@ -8,17 +9,19 @@ export default function FilterToolbar(props) {
8
9
  const {
9
10
  toolbarItems = [],
10
11
  } = props;
11
- return <Toolbar className={`
12
- bg-grey-200
13
- border-t
14
- border-t-grey-400
15
- w-full
16
- `} >
12
+ return <Toolbar
13
+ className={clsx(
14
+ 'bg-grey-200',
15
+ 'border-t',
16
+ 'border-t-grey-400',
17
+ 'w-full',
18
+ )}
19
+ >
17
20
  {toolbarItems.length &&
18
- <HStack className={`
19
- flex-1
20
- border
21
- border-l-grey-100
22
- `}>{toolbarItems}</HStack>}
21
+ <HStack className={clsx(
22
+ 'flex-1',
23
+ 'border',
24
+ 'border-l-grey-100',
25
+ )}>{toolbarItems}</HStack>}
23
26
  </Toolbar>;
24
27
  };
@@ -4,6 +4,7 @@ import {
4
4
  HStackNative,
5
5
  Text,
6
6
  } from '@project-components/Gluestack';
7
+ import clsx from 'clsx';
7
8
  import useForceUpdate from '../../Hooks/useForceUpdate.js';
8
9
  import testProps from '../../Functions/testProps.js';
9
10
  import Button from '../Buttons/Button.js';
@@ -154,25 +155,25 @@ export default function Pagination(props) {
154
155
  onChangeValue={(value) => Repository.setPage(value)}
155
156
  maxValue={totalPages}
156
157
  isDisabled={totalPages === 1}
157
- className={`
158
- Pagination-pageInput
159
- min-w-[40px]
160
- w-[40px]
161
- text-center
162
- bg-grey-100
163
- `}
158
+ className={clsx(
159
+ 'Pagination-pageInput',
160
+ 'min-w-[40px]',
161
+ 'w-[40px]',
162
+ 'text-center',
163
+ 'bg-grey-100',
164
+ )}
164
165
  textAlignIsCenter={true}
165
166
  tooltip="Set Page"
166
167
  tooltipClassName="w-[40px]"
167
168
  />);
168
169
  items.push(<Text
169
170
  key="totalPages"
170
- className={`
171
- Pagination-totalPages
172
- whitespace-nowrap
173
- inline-flex
174
- mx-1
175
- `}
171
+ className={clsx(
172
+ 'Pagination-totalPages',
173
+ 'whitespace-nowrap',
174
+ 'inline-flex',
175
+ 'mx-1',
176
+ )}
176
177
  >{`of ${totalPages}`}</Text>);
177
178
  }
178
179
  }
@@ -194,12 +195,12 @@ export default function Pagination(props) {
194
195
  }
195
196
  items.push(<Text
196
197
  key="pageDisplay"
197
- className={`
198
- Pagination-pageDisplay
199
- whitespace-nowrap
200
- inline-flex
201
- mx-1
202
- `}
198
+ className={clsx(
199
+ 'Pagination-pageDisplay',
200
+ 'whitespace-nowrap',
201
+ 'inline-flex',
202
+ 'mx-1',
203
+ )}
203
204
  >{`Displaying ${pageSpan} of ${total}`}</Text>);
204
205
  }
205
206
  }
@@ -207,12 +208,12 @@ export default function Pagination(props) {
207
208
  style={{
208
209
  userSelect: 'none',
209
210
  }}
210
- className={`
211
- Pagination
212
- items-center
213
- shrink-0
214
- gap-2
215
- `}
211
+ className={clsx(
212
+ 'Pagination',
213
+ 'items-center',
214
+ 'shrink-0',
215
+ 'gap-2',
216
+ )}
216
217
  >
217
218
  {items}
218
219
  </HStack>;
@@ -2,6 +2,7 @@ import { useState } from 'react';
2
2
  import {
3
3
  HStack,
4
4
  } from '@project-components/Gluestack';
5
+ import clsx from 'clsx';
5
6
  import Pagination from './Pagination.js'
6
7
  import Toolbar from './Toolbar.js'
7
8
  import _ from 'lodash';
@@ -37,22 +38,22 @@ export default function PaginationToolbar(props) {
37
38
  };
38
39
 
39
40
  return <Toolbar
40
- className={`
41
- border-t
42
- border-t-grey-400
43
- `}
41
+ className={clsx(
42
+ 'border-t',
43
+ 'border-t-grey-400',
44
+ )}
44
45
  onLayout={(e) => onLayout(e)}
45
46
  >
46
47
  {toolbarItems.length ?
47
48
  <HStack
48
- className={`
49
- PaginationToolbar-HStack
50
- shrink-0
51
- border-r
52
- border-r-grey-400
53
- mr-3
54
- pr-3
55
- `}
49
+ className={clsx(
50
+ 'PaginationToolbar-HStack',
51
+ 'shrink-0',
52
+ 'border-r',
53
+ 'border-r-grey-400',
54
+ 'mr-3',
55
+ 'pr-3',
56
+ )}
56
57
  >{toolbarItems}</HStack> : null}
57
58
  <Pagination
58
59
  {...propsToPass}
@@ -1,24 +1,25 @@
1
1
  import {
2
2
  HStackNative,
3
3
  } from '@project-components/Gluestack';
4
+ import clsx from 'clsx';
4
5
  import UiGlobals from '../../UiGlobals.js';
5
6
 
6
7
  export default function Toolbar(props) {
7
8
 
8
9
  const styles = UiGlobals.styles;
9
10
 
10
- let className = `
11
- Toolbar
12
- overflow-auto
13
- items-center
14
- justify-start
15
- gap-2
16
- p-2
17
- border-b
18
- border-solid
19
- border-b-grey-400
20
- ${styles.TOOLBAR_CLASSNAME}
21
- `;
11
+ let className = clsx(
12
+ 'Toolbar',
13
+ 'overflow-auto',
14
+ 'items-center',
15
+ 'justify-start',
16
+ 'gap-2',
17
+ 'p-2',
18
+ 'border-b',
19
+ 'border-solid',
20
+ 'border-b-grey-400',
21
+ styles.TOOLBAR_CLASSNAME,
22
+ );
22
23
  if (props.className) {
23
24
  className += ' ' + props.className
24
25
  }
@@ -3,6 +3,7 @@ import {
3
3
  BoxNative as Box,
4
4
  Tooltip, TooltipContent, TooltipText,
5
5
  } from '@project-components/Gluestack';
6
+ import clsx from 'clsx';
6
7
 
7
8
  const TooltipElement = forwardRef((props, ref) => {
8
9
  const {
@@ -6,6 +6,7 @@ import {
6
6
  VStack,
7
7
  VStackNative,
8
8
  } from '@project-components/Gluestack';
9
+ import clsx from 'clsx';
9
10
  import {
10
11
  SELECTION_MODE_SINGLE,
11
12
  SELECTION_MODE_MULTI,
@@ -1051,11 +1052,11 @@ function TreeComponent(props) {
1051
1052
  onContextMenu(item, e, selection);
1052
1053
  }
1053
1054
  }}
1054
- className={`
1055
- Pressable
1056
- Node
1057
- flex-row
1058
- `}
1055
+ className={clsx(
1056
+ 'Pressable',
1057
+ 'Node',
1058
+ 'flex-row',
1059
+ )}
1059
1060
  style={{
1060
1061
  paddingLeft: (areRootsVisible ? depth : depth -1) * DEPTH_INDENT_PX,
1061
1062
  }}
@@ -1087,17 +1088,26 @@ function TreeComponent(props) {
1087
1088
  id: item.id,
1088
1089
  item,
1089
1090
  getSelection,
1091
+ isInSelection,
1090
1092
  type: nodeDragSourceType,
1093
+ onDragStart: () => {
1094
+ if (!isInSelection(item)) { // get updated isSelected (will be stale if using one in closure)
1095
+ // reset the selection to just this one node if it's not already selected
1096
+ setSelection([item]);
1097
+ }
1098
+ },
1091
1099
  };
1092
1100
 
1093
1101
  // Prevent root nodes from being dragged, and use custom logic if provided
1094
1102
  nodeDragProps.canDrag = (monitor) => {
1095
1103
  const currentSelection = getSelection();
1096
1104
 
1097
- // Check if any selected node is a root node (can't drag root nodes)
1098
- const hasRootNode = currentSelection.some(node => node.isRoot);
1099
- if (hasRootNode) {
1100
- return false;
1105
+ if (isInSelection(item)) {
1106
+ // make sure root node is not selected (can't drag root nodes)
1107
+ const hasRootNode = currentSelection.some(node => node.isRoot);
1108
+ if (hasRootNode) {
1109
+ return false;
1110
+ }
1101
1111
  }
1102
1112
 
1103
1113
  // Use custom drag validation if provided
@@ -1117,7 +1127,7 @@ function TreeComponent(props) {
1117
1127
  // Add drag preview rendering
1118
1128
  nodeDragProps.getDragProxy = getCustomDragProxy ?
1119
1129
  (dragItem) => getCustomDragProxy(item, getSelection()) :
1120
- null; // Let GlobalDragProxy handle the default case
1130
+ null; // let GlobalDragProxy handle the default case
1121
1131
 
1122
1132
  const dropTargetAccept = 'internal';
1123
1133
  nodeDragProps.isDropTarget = true;
@@ -1177,15 +1187,22 @@ function TreeComponent(props) {
1177
1187
  nodeDragProps.isDragSource = !item.isRoot; // Root nodes cannot be dragged
1178
1188
  nodeDragProps.dragSourceType = nodeDragSourceType;
1179
1189
  if (getNodeDragSourceItem) {
1180
- nodeDragProps.dragSourceItem = getNodeDragSourceItem(item, getSelection, nodeDragSourceType);
1190
+ nodeDragProps.dragSourceItem = getNodeDragSourceItem(item, getSelection, isInSelection, nodeDragSourceType);
1181
1191
  } else {
1182
1192
  nodeDragProps.dragSourceItem = {
1183
1193
  id: item.id,
1184
1194
  item,
1185
1195
  getSelection,
1196
+ isInSelection,
1186
1197
  type: nodeDragSourceType,
1187
1198
  };
1188
1199
  }
1200
+ nodeDragProps.dragSourceItem.onDragStart = () => {
1201
+ if (!isInSelection(item)) { // get updated isSelected (will be stale if using one in closure)
1202
+ // reset the selection to just this one node if it's not already selected
1203
+ setSelection([item]);
1204
+ }
1205
+ };
1189
1206
  if (canNodeMoveExternally) {
1190
1207
  nodeDragProps.canDrag = canNodeMoveExternally;
1191
1208
  }
@@ -1400,12 +1417,12 @@ function TreeComponent(props) {
1400
1417
  }
1401
1418
  }
1402
1419
 
1403
- let className = `
1404
- Tree-VStack
1405
- flex-1
1406
- w-full
1407
- min-w-[300px]
1408
- `;
1420
+ let className = clsx(
1421
+ 'Tree-VStack',
1422
+ 'flex-1',
1423
+ 'w-full',
1424
+ 'min-w-[300px]',
1425
+ );
1409
1426
  if (isLoading) {
1410
1427
  className += ' border-t-2 border-[#f00]';
1411
1428
  } else {
@@ -6,6 +6,7 @@ import {
6
6
  Spinner,
7
7
  TextNative,
8
8
  } from '@project-components/Gluestack';
9
+ import clsx from 'clsx';
9
10
  import * as colourMixer from '@k-renwick/colour-mixer';
10
11
  import {
11
12
  UI_MODE_WEB,
@@ -15,7 +16,7 @@ import UiGlobals from '../../UiGlobals.js';
15
16
  import withDraggable from '../Hoc/withDraggable.js';
16
17
  import IconButton from '../Buttons/IconButton.js';
17
18
  import { withDragSource, withDropTarget } from '../Hoc/withDnd.js';
18
- import TreeNodeDragHandle from './TreeNodeDragHandle.js';
19
+ import RowHandle from '../Grid/RowHandle.js';
19
20
  import testProps from '../../Functions/testProps.js';
20
21
  import ChevronRight from '../Icons/ChevronRight.js';
21
22
  import ChevronDown from '../Icons/ChevronDown.js';
@@ -39,11 +40,13 @@ export default function TreeNode(props) {
39
40
  nodeProps = {},
40
41
  onToggle,
41
42
  bg,
43
+ isDraggable,
42
44
  isDragSource,
43
45
  isHovered,
44
46
  isHighlighted,
45
47
  isOver,
46
48
  isSelected,
49
+ showSelectHandle,
47
50
  canDrop,
48
51
  draggedItem,
49
52
  validateDrop, // same as canDrop (for visual feedback)
@@ -114,15 +117,15 @@ export default function TreeNode(props) {
114
117
  bg = colourMixer.blend(bg, 0.5, mixWith);
115
118
  }
116
119
 
117
- let className = `
118
- TreeNode
119
- items-center
120
- flex-1
121
- grow-1
122
- select-none
123
- cursor-pointer
124
- `;
125
-
120
+ let className = clsx(
121
+ 'TreeNode',
122
+ 'items-center',
123
+ 'flex-1',
124
+ 'grow-1',
125
+ 'select-none',
126
+ 'cursor-pointer',
127
+ );
128
+
126
129
  // Add drop state classes for additional styling
127
130
  if (isOver && actualCanDrop) {
128
131
  className += ' TreeNode--dropValid border-2 border-green-400';
@@ -143,19 +146,21 @@ export default function TreeNode(props) {
143
146
  backgroundColor: bg,
144
147
  }}
145
148
  ref={(element) => {
146
- // Attach both drag and drop refs to the same element
147
- if (dragSourceRef && typeof dragSourceRef === 'function') {
148
- dragSourceRef(element);
149
- }
150
149
  if (dropTargetRef && dropTargetRef.current !== undefined) {
151
150
  // dropTargetRef is a ref object, not a callback
152
151
  dropTargetRef.current = element;
153
152
  }
154
153
  }}
155
154
  >
156
- {isPhantom && <Box t={0} l={0} className="absolute bg-[#f00] h-[2px] w-[2px]" />}
155
+ {isPhantom && <Box className="absolute t-0 l-0 bg-[#f00] h-[2px] w-[2px]" />}
157
156
 
158
- {isDragSource && <TreeNodeDragHandle />}
157
+ {(isDragSource || showSelectHandle) &&
158
+ <RowHandle
159
+ ref={dragSourceRef}
160
+ isDragSource={isDragSource}
161
+ isDraggable={isDraggable}
162
+ showSelectHandle={showSelectHandle}
163
+ />}
159
164
 
160
165
  {hasChildren && <IconButton
161
166
  {...testProps('expandBtn')}
@@ -172,19 +177,15 @@ export default function TreeNode(props) {
172
177
  numberOfLines={1}
173
178
  ellipsizeMode="head"
174
179
  // {...propsToPass}
175
- className={`
176
- TreeNode-TextNative
177
- self-center
178
- overflow-hidden
179
- flex
180
- flex-1
181
- text-ellipsis
182
- select-none
183
- ${styles.TREE_NODE_CLASSNAME}
184
- `}
185
- style={{
186
- userSelect: 'none',
187
- }}
180
+ className={clsx(
181
+ 'TreeNode-TextNative',
182
+ 'self-center',
183
+ 'overflow-hidden',
184
+ 'flex',
185
+ 'flex-1',
186
+ 'text-ellipsis',
187
+ styles.TREE_NODE_CLASSNAME,
188
+ )}
188
189
  >{text}</TextNative>}
189
190
 
190
191
  {content}
@@ -1,33 +1,38 @@
1
+ import { forwardRef } from 'react';
1
2
  import {
2
3
  Icon,
3
4
  VStack,
4
5
  } from '@project-components/Gluestack';
6
+ import clsx from 'clsx';
5
7
  import styles from '../../Styles/StyleSheets.js';
6
8
  import GripVertical from '../Icons/GripVertical.js';
7
9
 
8
- function TreeNodeDragHandle(props) {
9
- let className = `
10
- TreeNodeDragHandle
11
- h-full
12
- w-[14px]
13
- px-[2px]
14
- border-l-2
15
- items-center
16
- justify-center
17
- select-none
18
- `;
10
+ const TreeNodeDragHandle = forwardRef(function(props, ref) {
11
+ let className = clsx(
12
+ 'TreeNodeDragHandle',
13
+ 'h-full',
14
+ 'w-[17px]',
15
+ 'px-[2px]',
16
+ 'border-l-2',
17
+ 'items-center',
18
+ 'justify-center',
19
+ 'select-none',
20
+ );
19
21
  if (props.className) {
20
22
  className += ' ' + props.className;
21
23
  }
22
24
  return <VStack
25
+ {...props}
26
+ ref={ref}
23
27
  style={styles.ewResize}
24
28
  className={className}
25
29
  >
26
30
  <Icon
27
31
  as={GripVertical}
28
32
  size="xs"
29
- className="handle w-full h-full text-[#ccc]" />
33
+ className="handle w-full h-full text-[#ccc]"
34
+ />
30
35
  </VStack>;
31
- }
36
+ });
32
37
 
33
38
  export default TreeNodeDragHandle;