@deadragdoll/reactnu 0.1.74 → 0.1.75

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/dist/index.cjs CHANGED
@@ -71,7 +71,6 @@ __export(index_exports, {
71
71
  ToolDropButton: () => ToolDropButton,
72
72
  ToolSeparator: () => ToolSeparator,
73
73
  TreeListView: () => TreeListView,
74
- TreeTable: () => TreeTable,
75
74
  TreeView: () => TreeView,
76
75
  Window: () => Window,
77
76
  WindowBar: () => WindowBar,
@@ -1062,226 +1061,167 @@ var import_react6 = require("react");
1062
1061
 
1063
1062
  // src/components/DragDrop/NuDragDropProvider.tsx
1064
1063
  var import_react5 = require("react");
1065
-
1066
- // src/components/_shared/themePortal.ts
1067
- function getThemePortalStyle(anchor) {
1068
- if (typeof window === "undefined") {
1069
- return void 0;
1070
- }
1071
- const themeRoot = anchor?.closest(".nu-theme-root");
1072
- if (!themeRoot) {
1073
- return void 0;
1074
- }
1075
- const computed = window.getComputedStyle(themeRoot);
1076
- const style = {
1077
- color: computed.color,
1078
- fontFamily: computed.fontFamily,
1079
- fontSize: computed.fontSize
1080
- };
1081
- for (const propertyName of computed) {
1082
- if (propertyName.startsWith("--nu-")) {
1083
- style[propertyName] = computed.getPropertyValue(propertyName).trim();
1084
- }
1085
- }
1086
- return style;
1087
- }
1088
-
1089
- // src/components/DragDrop/NuDragDropProvider.tsx
1064
+ var import_react_dnd = require("react-dnd");
1065
+ var import_react_dnd_html5_backend = require("react-dnd-html5-backend");
1090
1066
  var import_jsx_runtime10 = require("react/jsx-runtime");
1091
- var DRAG_THRESHOLD = 3;
1092
- function createDragPreview(sourceElement) {
1093
- const rect = sourceElement.getBoundingClientRect();
1094
- const preview = sourceElement.cloneNode(true);
1095
- preview.removeAttribute("id");
1096
- preview.setAttribute("aria-hidden", "true");
1097
- Object.assign(preview.style, {
1098
- height: `${rect.height}px`,
1099
- left: `${rect.left}px`,
1100
- margin: "0",
1101
- opacity: "0.85",
1102
- pointerEvents: "none",
1103
- position: "fixed",
1104
- top: `${rect.top}px`,
1105
- width: `${rect.width}px`,
1106
- zIndex: "2147483647"
1107
- });
1108
- const themeStyle = getThemePortalStyle(sourceElement);
1109
- Object.entries(themeStyle ?? {}).forEach(([property, value]) => {
1110
- if (value !== void 0) {
1111
- preview.style.setProperty(property, String(value));
1112
- }
1113
- });
1114
- document.body.append(preview);
1115
- return preview;
1116
- }
1117
- function createController() {
1118
- const targets = /* @__PURE__ */ new Map();
1119
- let activeDrag = null;
1120
- function findTarget(clientX, clientY) {
1121
- const elementAtPoint = document.elementFromPoint(clientX, clientY);
1122
- let candidate = elementAtPoint;
1123
- while (candidate) {
1124
- const target = targets.get(candidate);
1125
- if (target) {
1126
- return target;
1127
- }
1128
- candidate = candidate.parentElement;
1129
- }
1130
- return Array.from(targets.values()).reverse().find((target) => {
1131
- const rect = target.element.getBoundingClientRect();
1132
- return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
1133
- });
1134
- }
1135
- function clearActiveDrag() {
1136
- activeDrag?.preview.remove();
1137
- activeDrag = null;
1138
- }
1067
+ var NU_DRAG_ITEM_TYPE = "reactnu-shared-item";
1068
+ function getDropContext(item, element, type, clientOffset) {
1139
1069
  return {
1140
- beginDrag(item, sourceElement, sourceType) {
1141
- clearActiveDrag();
1142
- activeDrag = {
1143
- item,
1144
- preview: createDragPreview(sourceElement),
1145
- sourceElement,
1146
- sourceType
1147
- };
1148
- },
1149
- cancelDrag: clearActiveDrag,
1150
- dropAt(clientX, clientY) {
1151
- const currentDrag = activeDrag;
1152
- if (!currentDrag) {
1153
- return false;
1154
- }
1155
- const target = findTarget(clientX, clientY);
1156
- clearActiveDrag();
1157
- if (!target || target.element === currentDrag.sourceElement) {
1158
- return false;
1159
- }
1160
- if (target.accepts?.(currentDrag.item) === false) {
1161
- return false;
1162
- }
1163
- return target.onDrop(currentDrag.item, {
1164
- clientX,
1165
- clientY,
1166
- source: {
1167
- element: currentDrag.sourceElement,
1168
- type: currentDrag.sourceType
1169
- },
1170
- target: { element: target.element, type: target.type }
1171
- }) !== false;
1172
- },
1173
- moveDrag(clientX, clientY) {
1174
- const currentDrag = activeDrag;
1175
- if (!currentDrag) {
1176
- return;
1177
- }
1178
- const rect = currentDrag.sourceElement.getBoundingClientRect();
1179
- currentDrag.preview.style.left = `${Math.round(clientX - rect.width / 2)}px`;
1180
- currentDrag.preview.style.top = `${Math.round(clientY - rect.height / 2)}px`;
1070
+ clientX: clientOffset?.x ?? 0,
1071
+ clientY: clientOffset?.y ?? 0,
1072
+ source: {
1073
+ element: item.sourceElement ?? element,
1074
+ type: item.sourceType
1181
1075
  },
1182
- registerTarget(element, options) {
1183
- targets.set(element, { ...options, element });
1184
- return () => targets.delete(element);
1185
- }
1076
+ target: { element, type }
1186
1077
  };
1187
1078
  }
1188
- var fallbackController = createController();
1189
- var NuDragDropContext = (0, import_react5.createContext)(null);
1079
+ function NuDragPreviewLayer() {
1080
+ const { isDragging, item, offset } = (0, import_react_dnd.useDragLayer)((monitor) => ({
1081
+ isDragging: monitor.isDragging(),
1082
+ item: monitor.getItem() ?? null,
1083
+ offset: monitor.getClientOffset()
1084
+ }));
1085
+ if (!isDragging || !item?.preview || !offset) {
1086
+ return null;
1087
+ }
1088
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1089
+ "div",
1090
+ {
1091
+ "aria-hidden": "true",
1092
+ style: {
1093
+ left: 0,
1094
+ pointerEvents: "none",
1095
+ position: "fixed",
1096
+ top: 0,
1097
+ transform: `translate(${Math.round(offset.x + 12)}px, ${Math.round(offset.y + 12)}px)`,
1098
+ zIndex: 2147483647
1099
+ },
1100
+ children: item.preview
1101
+ }
1102
+ );
1103
+ }
1190
1104
  function NuDragDropProvider({ children }) {
1191
- const controller = (0, import_react5.useMemo)(() => createController(), []);
1192
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NuDragDropContext.Provider, { value: controller, children });
1105
+ const { dragDropManager } = (0, import_react5.useContext)(import_react_dnd.DndContext);
1106
+ if (dragDropManager) {
1107
+ return children;
1108
+ }
1109
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react_dnd.DndProvider, { backend: import_react_dnd_html5_backend.HTML5Backend, children: [
1110
+ children,
1111
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(NuDragPreviewLayer, {})
1112
+ ] });
1193
1113
  }
1194
1114
  function useNuDragDrop() {
1195
- return (0, import_react5.useContext)(NuDragDropContext) ?? fallbackController;
1115
+ return (0, import_react_dnd.useDragDropManager)();
1196
1116
  }
1197
1117
  function useNuDropTarget(element, options) {
1198
- const controller = useNuDragDrop();
1118
+ const [{ canDrop, isOver, item }, drop] = (0, import_react_dnd.useDrop)(
1119
+ () => ({
1120
+ accept: NU_DRAG_ITEM_TYPE,
1121
+ canDrop: (dragItem) => options ? options.accepts?.(dragItem) !== false : false,
1122
+ collect: (monitor) => ({
1123
+ canDrop: monitor.canDrop(),
1124
+ isOver: monitor.isOver({ shallow: true }),
1125
+ item: monitor.isOver({ shallow: true }) ? monitor.getItem() ?? null : null
1126
+ }),
1127
+ drop: (dragItem, monitor) => {
1128
+ if (!options || monitor.didDrop()) {
1129
+ return void 0;
1130
+ }
1131
+ const result = options.onDrop(
1132
+ dragItem,
1133
+ getDropContext(
1134
+ dragItem,
1135
+ element ?? dragItem.sourceElement ?? document.body,
1136
+ options.type,
1137
+ monitor.getClientOffset()
1138
+ )
1139
+ );
1140
+ if (result === false) {
1141
+ return { accepted: false };
1142
+ }
1143
+ return {
1144
+ ...typeof result === "object" && result ? result : {},
1145
+ accepted: true
1146
+ };
1147
+ }
1148
+ }),
1149
+ [element, options]
1150
+ );
1199
1151
  (0, import_react5.useEffect)(() => {
1200
1152
  if (!element || !options) {
1153
+ drop(null);
1201
1154
  return void 0;
1202
1155
  }
1203
- return controller.registerTarget(element, options);
1204
- }, [controller, element, options]);
1156
+ drop(element);
1157
+ return () => {
1158
+ drop(null);
1159
+ };
1160
+ }, [drop, element, options]);
1161
+ const previousItemRef = (0, import_react5.useRef)(null);
1162
+ (0, import_react5.useEffect)(() => {
1163
+ const previousItem = previousItemRef.current;
1164
+ if (isOver && item && (!previousItem || previousItem !== item)) {
1165
+ options?.onDragEnter?.(item, canDrop);
1166
+ } else if (!isOver && previousItem) {
1167
+ options?.onDragLeave?.(previousItem);
1168
+ }
1169
+ previousItemRef.current = isOver ? item : null;
1170
+ }, [canDrop, isOver, item, options]);
1171
+ return { canDrop, isOver, item };
1205
1172
  }
1206
1173
  function useNuDragSource({
1207
1174
  disabled = false,
1208
1175
  getItem,
1209
1176
  onDropAccepted,
1177
+ renderPreview,
1210
1178
  sourceType
1211
1179
  }) {
1212
- const controller = useNuDragDrop();
1213
- const stateRef = (0, import_react5.useRef)({
1214
- dragging: false,
1215
- pointerId: -1,
1216
- sourceElement: null,
1217
- startX: 0,
1218
- startY: 0
1219
- });
1220
- const state = stateRef.current;
1221
- function stop(event, shouldDrop) {
1222
- if (state.pointerId !== event.pointerId) {
1223
- return;
1224
- }
1225
- if (event.currentTarget.hasPointerCapture(event.pointerId)) {
1226
- event.currentTarget.releasePointerCapture(event.pointerId);
1227
- }
1228
- state.pointerId = -1;
1229
- if (state.dragging && shouldDrop && controller.dropAt(event.clientX, event.clientY)) {
1230
- onDropAccepted?.();
1231
- } else if (state.dragging) {
1232
- controller.cancelDrag();
1233
- }
1234
- state.dragging = false;
1235
- state.sourceElement = null;
1236
- }
1237
- return {
1238
- onPointerCancel(event) {
1239
- stop(event, false);
1240
- },
1241
- onPointerDown(event) {
1242
- if (disabled || event.button !== 0) {
1243
- return;
1244
- }
1245
- if (event.target instanceof HTMLElement && event.target.closest("button, input, select, textarea, a")) {
1246
- return;
1247
- }
1248
- state.dragging = false;
1249
- state.pointerId = event.pointerId;
1250
- state.sourceElement = event.currentTarget;
1251
- state.startX = event.clientX;
1252
- state.startY = event.clientY;
1253
- event.currentTarget.setPointerCapture(event.pointerId);
1254
- },
1255
- onPointerMove(event) {
1256
- if (state.pointerId !== event.pointerId || !state.sourceElement) {
1257
- return;
1258
- }
1259
- if (!state.dragging) {
1260
- const distance = Math.max(
1261
- Math.abs(event.clientX - state.startX),
1262
- Math.abs(event.clientY - state.startY)
1263
- );
1264
- if (distance < DRAG_THRESHOLD) {
1265
- return;
1266
- }
1180
+ const sourceElementRef = (0, import_react5.useRef)(null);
1181
+ const [{ isDragging }, drag, preview] = (0, import_react_dnd.useDrag)(
1182
+ () => ({
1183
+ type: NU_DRAG_ITEM_TYPE,
1184
+ canDrag: () => !disabled && Boolean(getItem()),
1185
+ item: () => {
1267
1186
  const item = getItem();
1268
1187
  if (!item) {
1269
- if (event.currentTarget.hasPointerCapture(event.pointerId)) {
1270
- event.currentTarget.releasePointerCapture(event.pointerId);
1271
- }
1272
- state.pointerId = -1;
1273
- state.sourceElement = null;
1274
- return;
1188
+ throw new Error("getItem must return a drag item when dragging is enabled.");
1275
1189
  }
1276
- state.dragging = true;
1277
- controller.beginDrag(item, state.sourceElement, sourceType);
1190
+ return {
1191
+ ...item,
1192
+ preview: renderPreview?.(item),
1193
+ sourceElement: sourceElementRef.current,
1194
+ sourceType
1195
+ };
1196
+ },
1197
+ end: (_item, monitor) => {
1198
+ const result = monitor.getDropResult();
1199
+ if (monitor.didDrop() && result?.accepted !== false) {
1200
+ onDropAccepted?.(result ?? {});
1201
+ }
1202
+ },
1203
+ collect: (monitor) => ({ isDragging: monitor.isDragging() })
1204
+ }),
1205
+ [disabled, getItem, onDropAccepted, renderPreview, sourceType]
1206
+ );
1207
+ const dragRef = (0, import_react5.useCallback)(
1208
+ (element) => {
1209
+ if (disabled) {
1210
+ sourceElementRef.current = null;
1211
+ drag(null);
1212
+ return;
1278
1213
  }
1279
- controller.moveDrag(event.clientX, event.clientY);
1214
+ sourceElementRef.current = element;
1215
+ drag(element);
1280
1216
  },
1281
- onPointerUp(event) {
1282
- stop(event, true);
1217
+ [disabled, drag]
1218
+ );
1219
+ (0, import_react5.useEffect)(() => {
1220
+ if (renderPreview) {
1221
+ preview((0, import_react_dnd_html5_backend.getEmptyImage)(), { captureDraggingState: true });
1283
1222
  }
1284
- };
1223
+ }, [preview, renderPreview]);
1224
+ return { dragRef, isDragging };
1285
1225
  }
1286
1226
 
1287
1227
  // src/components/ListBox/internals/ListBoxCheckControl.tsx
@@ -1332,6 +1272,7 @@ function ListBoxItemViewInner({
1332
1272
  onDoubleClick,
1333
1273
  onDragOut,
1334
1274
  onToggleCheck,
1275
+ renderDragPreview,
1335
1276
  registerItemRef,
1336
1277
  rightCheckBox,
1337
1278
  uncheckedShape
@@ -1340,6 +1281,7 @@ function ListBoxItemViewInner({
1340
1281
  disabled: item.disabled || !getDragItem,
1341
1282
  getItem: () => getDragItem?.(item, group) ?? false,
1342
1283
  onDropAccepted: () => onDragOut?.(item, group),
1284
+ renderPreview: renderDragPreview ? () => renderDragPreview(item, group) : void 0,
1343
1285
  sourceType: "listbox-item"
1344
1286
  });
1345
1287
  function handleActivate() {
@@ -1387,11 +1329,10 @@ function ListBoxItemViewInner({
1387
1329
  onClick: handleActivate,
1388
1330
  onContextMenu: onPopupMenu ? handleContextMenu : void 0,
1389
1331
  onDoubleClick: handleDoubleClick,
1390
- onPointerCancel: dragSource.onPointerCancel,
1391
- onPointerDown: dragSource.onPointerDown,
1392
- onPointerMove: dragSource.onPointerMove,
1393
- onPointerUp: dragSource.onPointerUp,
1394
- ref: (node) => registerItemRef(itemId, node),
1332
+ ref: (node) => {
1333
+ registerItemRef(itemId, node);
1334
+ dragSource.dragRef(node);
1335
+ },
1395
1336
  role: "option",
1396
1337
  children: [
1397
1338
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { className: "nu-listbox__item-main", children: [
@@ -1417,6 +1358,7 @@ function ListBoxGroupView({
1417
1358
  onActivateItem,
1418
1359
  onDoubleClickItem,
1419
1360
  onItemDragOut,
1361
+ renderDragPreview,
1420
1362
  onPopupMenuItem,
1421
1363
  onToggleItemCheck,
1422
1364
  registerItemRef,
@@ -1451,6 +1393,7 @@ function ListBoxGroupView({
1451
1393
  onActivate: onActivateItem,
1452
1394
  onDoubleClick: onDoubleClickItem,
1453
1395
  onDragOut: onItemDragOut,
1396
+ renderDragPreview,
1454
1397
  onPopupMenu: onPopupMenuItem,
1455
1398
  onToggleCheck: onToggleItemCheck,
1456
1399
  registerItemRef,
@@ -1478,6 +1421,7 @@ function ListBoxInner({
1478
1421
  onItemDragOut,
1479
1422
  onItemSelect,
1480
1423
  onDrop,
1424
+ renderDragPreview,
1481
1425
  rightCheckBox = false,
1482
1426
  selectedId,
1483
1427
  uncheckedShape = "box",
@@ -1680,6 +1624,7 @@ function ListBoxInner({
1680
1624
  onItemDragOut,
1681
1625
  onPopupMenuItem: handleItemPopupMenu,
1682
1626
  onToggleItemCheck: toggleItemCheck,
1627
+ renderDragPreview,
1683
1628
  registerItemRef,
1684
1629
  resolvedActiveId,
1685
1630
  rightCheckBox,
@@ -1691,7 +1636,10 @@ function ListBoxInner({
1691
1636
  }
1692
1637
  );
1693
1638
  }
1694
- var ListBox = (0, import_react7.forwardRef)(ListBoxInner);
1639
+ function ListBoxWithDragDrop(props, ref) {
1640
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(NuDragDropProvider, { children: ListBoxInner(props, ref) });
1641
+ }
1642
+ var ListBox = (0, import_react7.forwardRef)(ListBoxWithDragDrop);
1695
1643
 
1696
1644
  // src/components/Stack/Stack.tsx
1697
1645
  var import_jsx_runtime15 = require("react/jsx-runtime");
@@ -4725,6 +4673,31 @@ var import_react27 = require("react");
4725
4673
  // src/components/PopupMenu/PopupMenu.tsx
4726
4674
  var import_react24 = require("react");
4727
4675
  var import_react_dom2 = require("react-dom");
4676
+
4677
+ // src/components/_shared/themePortal.ts
4678
+ function getThemePortalStyle(anchor) {
4679
+ if (typeof window === "undefined") {
4680
+ return void 0;
4681
+ }
4682
+ const themeRoot = anchor?.closest(".nu-theme-root");
4683
+ if (!themeRoot) {
4684
+ return void 0;
4685
+ }
4686
+ const computed = window.getComputedStyle(themeRoot);
4687
+ const style = {
4688
+ color: computed.color,
4689
+ fontFamily: computed.fontFamily,
4690
+ fontSize: computed.fontSize
4691
+ };
4692
+ for (const propertyName of computed) {
4693
+ if (propertyName.startsWith("--nu-")) {
4694
+ style[propertyName] = computed.getPropertyValue(propertyName).trim();
4695
+ }
4696
+ }
4697
+ return style;
4698
+ }
4699
+
4700
+ // src/components/PopupMenu/PopupMenu.tsx
4728
4701
  var import_jsx_runtime37 = require("react/jsx-runtime");
4729
4702
  function hasVisibleChildren2(item) {
4730
4703
  return Boolean(
@@ -4957,7 +4930,6 @@ function useNuIconGridContext() {
4957
4930
 
4958
4931
  // src/components/IconGrid/NuIconGrid.tsx
4959
4932
  var import_jsx_runtime38 = require("react/jsx-runtime");
4960
- var DRAG_THRESHOLD2 = 3;
4961
4933
  var gridRegistrations = /* @__PURE__ */ new Map();
4962
4934
  function clamp2(value, minimum, maximum) {
4963
4935
  return Math.min(Math.max(value, minimum), maximum);
@@ -4968,23 +4940,6 @@ function resolveIconContextMenuItems(source, icon) {
4968
4940
  function resolveGridContextMenuItems(source, manager) {
4969
4941
  return typeof source === "function" ? source(manager) : source ?? [];
4970
4942
  }
4971
- function findGridRegistrationAtPoint(clientX, clientY) {
4972
- const target = document.elementFromPoint(clientX, clientY);
4973
- const gridElement = target?.closest(".nu-icon-grid");
4974
- if (gridElement) {
4975
- return gridRegistrations.get(gridElement);
4976
- }
4977
- if (target?.closest(".nu-window")) {
4978
- return void 0;
4979
- }
4980
- return Array.from(gridRegistrations.values()).reverse().find((registration) => {
4981
- if (!registration.dropTarget) {
4982
- return false;
4983
- }
4984
- const rect = registration.element.getBoundingClientRect();
4985
- return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
4986
- });
4987
- }
4988
4943
  function getTransferredPosition(targetGrid, iconElement, clientX, clientY) {
4989
4944
  const targetRect = targetGrid.getBoundingClientRect();
4990
4945
  const iconRect = iconElement.getBoundingClientRect();
@@ -5006,149 +4961,31 @@ function getTransferredPosition(targetGrid, iconElement, clientX, clientY) {
5006
4961
  };
5007
4962
  }
5008
4963
  function NuIconGridItem({
5009
- gridElement,
5010
4964
  icon,
5011
- onDragOut,
5012
- onIconMoveOut
4965
+ onDragOut
5013
4966
  }) {
5014
4967
  const manager = useNuIconGridContext();
5015
- const dragDrop = useNuDragDrop();
5016
4968
  const contextMenu = usePopupMenu();
5017
- const dragStartRef = (0, import_react27.useRef)(void 0);
5018
- const isDraggingRef = (0, import_react27.useRef)(false);
5019
- const [isDragging, setIsDragging] = (0, import_react27.useState)(false);
5020
- const suppressClickRef = (0, import_react27.useRef)(false);
5021
- const latestPositionRef = (0, import_react27.useRef)(icon.position);
5022
4969
  const contextMenuItems = resolveIconContextMenuItems(
5023
4970
  icon.contextMenuItems,
5024
4971
  icon
5025
4972
  );
5026
- function handlePointerDown(event) {
5027
- if (event.button !== 0 || icon.disabled) {
5028
- return;
5029
- }
5030
- manager.selectIcon(icon.id);
5031
- latestPositionRef.current = icon.position;
5032
- isDraggingRef.current = false;
5033
- dragStartRef.current = {
5034
- clientX: event.clientX,
5035
- clientY: event.clientY,
5036
- pointerId: event.pointerId,
5037
- position: icon.position
5038
- };
5039
- event.currentTarget.setPointerCapture(event.pointerId);
5040
- }
5041
- function handlePointerMove(event) {
5042
- const dragStart = dragStartRef.current;
5043
- if (!dragStart || dragStart.pointerId !== event.pointerId || !gridElement) {
5044
- return;
5045
- }
5046
- const deltaX = event.clientX - dragStart.clientX;
5047
- const deltaY = event.clientY - dragStart.clientY;
5048
- if (!isDraggingRef.current && Math.max(Math.abs(deltaX), Math.abs(deltaY)) < DRAG_THRESHOLD2) {
5049
- return;
5050
- }
5051
- if (!isDraggingRef.current) {
5052
- isDraggingRef.current = true;
5053
- setIsDragging(true);
5054
- dragDrop.beginDrag(
5055
- { data: icon, id: icon.id, type: "icon" },
5056
- event.currentTarget,
5057
- "icon-grid"
5058
- );
5059
- }
5060
- dragDrop.moveDrag(event.clientX, event.clientY);
5061
- const gridRect = gridElement.getBoundingClientRect();
5062
- const iconRect = event.currentTarget.getBoundingClientRect();
5063
- const position = {
5064
- x: Math.round(
5065
- clamp2(
5066
- dragStart.position.x + deltaX,
5067
- 0,
5068
- Math.max(0, gridRect.width - iconRect.width)
5069
- )
5070
- ),
5071
- y: Math.round(
5072
- clamp2(
5073
- dragStart.position.y + deltaY,
5074
- 0,
5075
- Math.max(0, gridRect.height - iconRect.height)
5076
- )
5077
- )
5078
- };
5079
- latestPositionRef.current = position;
5080
- }
5081
- function finishDragging(event) {
5082
- const dragStart = dragStartRef.current;
5083
- if (!dragStart || dragStart.pointerId !== event.pointerId) {
5084
- return;
5085
- }
5086
- if (event.currentTarget.hasPointerCapture(event.pointerId)) {
5087
- event.currentTarget.releasePointerCapture(event.pointerId);
5088
- }
5089
- dragStartRef.current = void 0;
5090
- if (!isDraggingRef.current) {
5091
- return;
5092
- }
5093
- suppressClickRef.current = true;
5094
- isDraggingRef.current = false;
5095
- setIsDragging(false);
5096
- if (event.type === "pointercancel" || !gridElement) {
5097
- dragDrop.cancelDrag();
5098
- return;
5099
- }
5100
- if (dragDrop.dropAt(event.clientX, event.clientY)) {
5101
- manager.removeIcon(icon.id);
5102
- onDragOut?.({ data: icon, id: icon.id, type: "icon" });
5103
- return;
5104
- }
5105
- const targetRegistration = findGridRegistrationAtPoint(
5106
- event.clientX,
5107
- event.clientY
5108
- );
5109
- if (!targetRegistration) {
5110
- return;
5111
- }
5112
- if (targetRegistration.element === gridElement) {
5113
- manager.moveIcon(icon.id, latestPositionRef.current);
5114
- icon.onPositionChange?.(latestPositionRef.current, {
5115
- ...icon,
5116
- position: latestPositionRef.current
5117
- });
5118
- return;
5119
- }
5120
- if (!targetRegistration.manager.icons.some(
5121
- (targetIcon) => targetIcon.id === icon.id
5122
- )) {
5123
- const position = getTransferredPosition(
5124
- targetRegistration.element,
5125
- event.currentTarget,
5126
- event.clientX,
5127
- event.clientY
5128
- );
5129
- const transferredIcon = { ...icon, position };
5130
- const context = {
5131
- position,
5132
- source: manager,
5133
- sourceGrid: gridElement,
5134
- target: targetRegistration.manager,
5135
- targetGrid: targetRegistration.element
5136
- };
5137
- if (targetRegistration.accepts?.(transferredIcon) !== false && targetRegistration.onIconDrop?.(transferredIcon, context) !== false) {
5138
- targetRegistration.manager.addIcon(transferredIcon);
5139
- targetRegistration.manager.selectIcon(transferredIcon.id);
5140
- manager.removeIcon(icon.id);
5141
- onIconMoveOut?.(transferredIcon, context);
4973
+ const dragSource = useNuDragSource({
4974
+ disabled: icon.disabled,
4975
+ getItem: () => ({ data: icon, id: icon.id, type: "icon" }),
4976
+ onDropAccepted: (result) => {
4977
+ if (result.targetType === "icon-grid") {
5142
4978
  return;
5143
4979
  }
5144
- }
5145
- }
4980
+ const dragItem = { data: icon, id: icon.id, type: "icon" };
4981
+ const shouldMove = result.action !== "copy" && onDragOut?.(dragItem, result) !== false;
4982
+ if (shouldMove) {
4983
+ manager.removeIcon(icon.id);
4984
+ }
4985
+ },
4986
+ sourceType: "icon-grid"
4987
+ });
5146
4988
  function handleClick(event) {
5147
- if (suppressClickRef.current) {
5148
- suppressClickRef.current = false;
5149
- event.preventDefault();
5150
- return;
5151
- }
5152
4989
  manager.selectIcon(icon.id);
5153
4990
  icon.onClick?.(event);
5154
4991
  }
@@ -5176,17 +5013,14 @@ function NuIconGridItem({
5176
5013
  {
5177
5014
  "aria-haspopup": contextMenuItems.length > 0 ? "menu" : void 0,
5178
5015
  className: "nu-icon-grid__icon",
5179
- "data-dragging": isDragging || void 0,
5016
+ "data-dragging": dragSource.isDragging || void 0,
5180
5017
  "data-selected": manager.selectedIconId === icon.id || void 0,
5181
5018
  disabled: icon.disabled,
5182
5019
  onClick: handleClick,
5183
5020
  onContextMenu: handleContextMenu,
5184
5021
  onDoubleClick: icon.onDoubleClick,
5185
5022
  onKeyDown: handleKeyDown,
5186
- onPointerDown: handlePointerDown,
5187
- onPointerMove: handlePointerMove,
5188
- onPointerUp: finishDragging,
5189
- onPointerCancel: finishDragging,
5023
+ ref: dragSource.dragRef,
5190
5024
  style: { left: icon.position.x, top: icon.position.y },
5191
5025
  type: "button",
5192
5026
  children: [
@@ -5206,7 +5040,7 @@ function NuIconGridItem({
5206
5040
  )
5207
5041
  ] });
5208
5042
  }
5209
- function NuIconGrid({
5043
+ function NuIconGridContent({
5210
5044
  accepts,
5211
5045
  acceptsDrop,
5212
5046
  className,
@@ -5231,15 +5065,89 @@ function NuIconGrid({
5231
5065
  () => resolveGridContextMenuItems(contextMenuItemsSource, manager),
5232
5066
  [contextMenuItemsSource, manager]
5233
5067
  );
5234
- const sharedDropTargetOptions = (0, import_react27.useMemo)(
5235
- () => onDrop ? {
5236
- accepts: (item) => item.type !== "icon" && acceptsDrop?.(item) !== false,
5237
- onDrop,
5068
+ const sharedDropTargetOptions = (0, import_react27.useMemo)(() => {
5069
+ if (!gridElement) {
5070
+ return void 0;
5071
+ }
5072
+ return {
5073
+ accepts: (item) => {
5074
+ if (item.type === "icon") {
5075
+ return accepts?.(item.data) !== false;
5076
+ }
5077
+ return Boolean(onDrop) && acceptsDrop?.(item) !== false;
5078
+ },
5079
+ onDrop: (item, context) => {
5080
+ if (item.type !== "icon") {
5081
+ return onDrop?.(item, context) ?? false;
5082
+ }
5083
+ const sourceGridElement = context.source.element.closest(
5084
+ ".nu-icon-grid"
5085
+ );
5086
+ const sourceRegistration = sourceGridElement ? gridRegistrations.get(sourceGridElement) : void 0;
5087
+ if (!sourceRegistration) {
5088
+ return false;
5089
+ }
5090
+ const sourceIcon = item.data;
5091
+ const position = getTransferredPosition(
5092
+ gridElement,
5093
+ context.source.element,
5094
+ context.clientX,
5095
+ context.clientY
5096
+ );
5097
+ if (sourceRegistration.element === gridElement) {
5098
+ manager.moveIcon(sourceIcon.id, position);
5099
+ sourceIcon.onPositionChange?.(position, {
5100
+ ...sourceIcon,
5101
+ position
5102
+ });
5103
+ return { action: "move", targetType: "icon-grid" };
5104
+ }
5105
+ if (manager.icons.some((targetIcon) => targetIcon.id === sourceIcon.id)) {
5106
+ return false;
5107
+ }
5108
+ const transferredIcon = { ...sourceIcon, position };
5109
+ const dropContext = {
5110
+ position,
5111
+ source: sourceRegistration.manager,
5112
+ sourceGrid: sourceRegistration.element,
5113
+ target: manager,
5114
+ targetGrid: gridElement
5115
+ };
5116
+ if (onIconDrop?.(transferredIcon, dropContext) === false) {
5117
+ return false;
5118
+ }
5119
+ manager.addIcon(transferredIcon);
5120
+ manager.selectIcon(transferredIcon.id);
5121
+ sourceRegistration.manager.removeIcon(sourceIcon.id);
5122
+ sourceRegistration.onIconMoveOut?.(transferredIcon, dropContext);
5123
+ return { action: "move", targetType: "icon-grid" };
5124
+ },
5238
5125
  type: "icon-grid"
5239
- } : void 0,
5240
- [acceptsDrop, onDrop]
5241
- );
5126
+ };
5127
+ }, [accepts, acceptsDrop, gridElement, manager, onDrop, onIconDrop]);
5242
5128
  useNuDropTarget(gridElement, sharedDropTargetOptions);
5129
+ const backgroundDropTargetOptions = (0, import_react27.useMemo)(() => {
5130
+ if (!dropTarget || !gridElement || !sharedDropTargetOptions) {
5131
+ return void 0;
5132
+ }
5133
+ return {
5134
+ ...sharedDropTargetOptions,
5135
+ onDrop: (item, context) => {
5136
+ const rect = gridElement.getBoundingClientRect();
5137
+ if (context.clientX < rect.left || context.clientX > rect.right || context.clientY < rect.top || context.clientY > rect.bottom) {
5138
+ return false;
5139
+ }
5140
+ return sharedDropTargetOptions.onDrop(item, {
5141
+ ...context,
5142
+ target: { element: gridElement, type: "icon-grid" }
5143
+ });
5144
+ }
5145
+ };
5146
+ }, [dropTarget, gridElement, sharedDropTargetOptions]);
5147
+ useNuDropTarget(
5148
+ dropTarget && typeof document !== "undefined" ? document.body : null,
5149
+ backgroundDropTargetOptions
5150
+ );
5243
5151
  (0, import_react27.useLayoutEffect)(() => {
5244
5152
  if (!gridElement) {
5245
5153
  return;
@@ -5266,16 +5174,15 @@ function NuIconGrid({
5266
5174
  return;
5267
5175
  }
5268
5176
  gridRegistrations.set(gridElement, {
5269
- accepts,
5270
- dropTarget,
5271
5177
  element: gridElement,
5272
5178
  manager,
5273
- onIconDrop
5179
+ onIconDrop,
5180
+ onIconMoveOut
5274
5181
  });
5275
5182
  return () => {
5276
5183
  gridRegistrations.delete(gridElement);
5277
5184
  };
5278
- }, [accepts, dropTarget, gridElement, manager, onIconDrop]);
5185
+ }, [gridElement, manager, onIconDrop, onIconMoveOut]);
5279
5186
  function handleContextMenu(event) {
5280
5187
  onContextMenu?.(event);
5281
5188
  if (event.defaultPrevented || contextMenuItems.length === 0) {
@@ -5291,6 +5198,7 @@ function NuIconGrid({
5291
5198
  ...props,
5292
5199
  "aria-label": props["aria-label"] ?? "Application icons",
5293
5200
  className: ["nu-icon-grid", className].filter(Boolean).join(" "),
5201
+ "data-drop-target": dropTarget || void 0,
5294
5202
  onContextMenu: handleContextMenu,
5295
5203
  onPointerDown: (event) => {
5296
5204
  onPointerDown?.(event);
@@ -5307,10 +5215,8 @@ function NuIconGrid({
5307
5215
  manager.icons.map((icon) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
5308
5216
  NuIconGridItem,
5309
5217
  {
5310
- gridElement,
5311
5218
  icon,
5312
- onDragOut,
5313
- onIconMoveOut
5219
+ onDragOut
5314
5220
  },
5315
5221
  icon.id
5316
5222
  )),
@@ -5327,6 +5233,9 @@ function NuIconGrid({
5327
5233
  }
5328
5234
  );
5329
5235
  }
5236
+ function NuIconGrid(props) {
5237
+ return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(NuDragDropProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(NuIconGridContent, { ...props }) });
5238
+ }
5330
5239
 
5331
5240
  // src/components/IconGrid/NuIconProvider.tsx
5332
5241
  var import_react28 = require("react");
@@ -6213,16 +6122,26 @@ function ListViewRowInner({
6213
6122
  isActive,
6214
6123
  isChecked,
6215
6124
  isSelected,
6125
+ getDragItem,
6216
6126
  onActivate,
6217
6127
  onDoubleClick,
6128
+ onDragOut,
6218
6129
  onToggleCheck,
6219
6130
  registerRowRef,
6131
+ renderDragPreview,
6220
6132
  row,
6221
6133
  showCheckBox,
6222
6134
  templateColumns,
6223
6135
  uncheckedShape
6224
6136
  }) {
6225
6137
  const rowId = row.id;
6138
+ const dragSource = useNuDragSource({
6139
+ disabled: row.disabled || !getDragItem,
6140
+ getItem: () => getDragItem?.(row) ?? false,
6141
+ onDropAccepted: () => onDragOut?.(row),
6142
+ renderPreview: renderDragPreview ? () => renderDragPreview(row) : void 0,
6143
+ sourceType: "list-view-row"
6144
+ });
6226
6145
  function handleActivate() {
6227
6146
  if (!row.disabled) {
6228
6147
  onActivate(rowId);
@@ -6253,7 +6172,10 @@ function ListViewRowInner({
6253
6172
  id: rowId,
6254
6173
  onClick: handleActivate,
6255
6174
  onDoubleClick: handleDoubleClick,
6256
- ref: (node) => registerRowRef(rowId, node),
6175
+ ref: (node) => {
6176
+ registerRowRef(rowId, node);
6177
+ dragSource.dragRef(node);
6178
+ },
6257
6179
  role: "row",
6258
6180
  style: {
6259
6181
  "--nu-list-view-columns": templateColumns
@@ -6290,6 +6212,7 @@ var ListViewRow = (0, import_react32.memo)(ListViewRowInner);
6290
6212
  // src/components/ListView/ListView.tsx
6291
6213
  var import_jsx_runtime45 = require("react/jsx-runtime");
6292
6214
  function ListViewInner({
6215
+ acceptsDrop,
6293
6216
  activeRowId: activeRowIdProp,
6294
6217
  checkedIds,
6295
6218
  className,
@@ -6297,16 +6220,21 @@ function ListViewInner({
6297
6220
  data,
6298
6221
  defaultActiveRowId,
6299
6222
  emptyText = "No rows",
6223
+ getDragItem,
6300
6224
  onActiveRowChange,
6301
6225
  onRowCheckChange,
6302
6226
  onRowDoubleClick,
6227
+ onRowDragOut,
6303
6228
  onRowSelect,
6229
+ onDrop,
6230
+ renderDragPreview,
6304
6231
  selectedId,
6305
6232
  showCheckBox = false,
6306
6233
  uncheckedShape = "box",
6307
6234
  ...props
6308
6235
  }, ref) {
6309
6236
  const rootRef = (0, import_react33.useRef)(null);
6237
+ const [rootElement, setRootElement] = (0, import_react33.useState)(null);
6310
6238
  const rowRefs = (0, import_react33.useRef)({});
6311
6239
  const selectableRows = (0, import_react33.useMemo)(
6312
6240
  () => data.filter((row) => !row.disabled),
@@ -6325,6 +6253,15 @@ function ListViewInner({
6325
6253
  );
6326
6254
  return [checkboxColumn, ...dataColumns].filter(Boolean).join(" ");
6327
6255
  }, [columns, showCheckBox]);
6256
+ const dropTargetOptions = (0, import_react33.useMemo)(
6257
+ () => onDrop ? { accepts: acceptsDrop, onDrop, type: "list-view" } : void 0,
6258
+ [acceptsDrop, onDrop]
6259
+ );
6260
+ useNuDropTarget(rootElement, dropTargetOptions);
6261
+ const setRootRef = (0, import_react33.useCallback)((node) => {
6262
+ rootRef.current = node;
6263
+ setRootElement(node);
6264
+ }, []);
6328
6265
  (0, import_react33.useEffect)(() => {
6329
6266
  if (!resolvedActiveRowId) {
6330
6267
  return;
@@ -6463,7 +6400,7 @@ function ListViewInner({
6463
6400
  "aria-activedescendant": resolvedActiveRowId ?? void 0,
6464
6401
  className: ["nu-list-view", className].filter(Boolean).join(" "),
6465
6402
  onKeyDown: handleKeyDown,
6466
- ref: rootRef,
6403
+ ref: setRootRef,
6467
6404
  role: "grid",
6468
6405
  tabIndex: 0,
6469
6406
  children: [
@@ -6497,13 +6434,16 @@ function ListViewInner({
6497
6434
  ListViewRow,
6498
6435
  {
6499
6436
  columns,
6437
+ getDragItem,
6500
6438
  isActive: row.id === resolvedActiveRowId,
6501
6439
  isChecked: isRowChecked(row),
6502
6440
  isSelected: row.id === selectedId,
6503
6441
  onActivate: activateRowId,
6504
6442
  onDoubleClick: onRowDoubleClick,
6443
+ onDragOut: onRowDragOut,
6505
6444
  onToggleCheck: toggleRowCheck,
6506
6445
  registerRowRef,
6446
+ renderDragPreview,
6507
6447
  row,
6508
6448
  showCheckBox,
6509
6449
  templateColumns,
@@ -6515,7 +6455,10 @@ function ListViewInner({
6515
6455
  }
6516
6456
  );
6517
6457
  }
6518
- var ListView = (0, import_react33.forwardRef)(ListViewInner);
6458
+ function ListViewWithDragDrop(props, ref) {
6459
+ return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(NuDragDropProvider, { children: ListViewInner(props, ref) });
6460
+ }
6461
+ var ListView = (0, import_react33.forwardRef)(ListViewWithDragDrop);
6519
6462
 
6520
6463
  // src/components/MaskedField/MaskedField.tsx
6521
6464
  var import_react34 = require("react");
@@ -9523,6 +9466,7 @@ function TreeListViewRowInner({
9523
9466
  onActivateItem,
9524
9467
  onDoubleClickItem,
9525
9468
  onItemDragOut,
9469
+ renderDragPreview,
9526
9470
  onPopupMenuItem,
9527
9471
  onToggleItemCheck,
9528
9472
  onToggleItemExpanded,
@@ -9554,6 +9498,7 @@ function TreeListViewRowInner({
9554
9498
  disabled: item.disabled || !getDragItem,
9555
9499
  getItem: () => getDragItem?.(item, dragContext) ?? false,
9556
9500
  onDropAccepted: () => onItemDragOut?.(item, dragContext),
9501
+ renderPreview: renderDragPreview ? () => renderDragPreview(item, dragContext) : void 0,
9557
9502
  sourceType: "tree-list-item"
9558
9503
  });
9559
9504
  function handleActivate() {
@@ -9620,11 +9565,10 @@ function TreeListViewRowInner({
9620
9565
  onClick: handleActivate,
9621
9566
  onContextMenu: onPopupMenuItem ? handleContextMenu : void 0,
9622
9567
  onDoubleClick: handleDoubleClick,
9623
- onPointerCancel: dragSource.onPointerCancel,
9624
- onPointerDown: dragSource.onPointerDown,
9625
- onPointerMove: dragSource.onPointerMove,
9626
- onPointerUp: dragSource.onPointerUp,
9627
- ref: (node) => registerItemRef(itemId, node),
9568
+ ref: (node) => {
9569
+ registerItemRef(itemId, node);
9570
+ dragSource.dragRef(node);
9571
+ },
9628
9572
  role: "row",
9629
9573
  style: {
9630
9574
  "--nu-tree-list-view-columns": templateColumns
@@ -9855,6 +9799,7 @@ function TreeListViewInner({
9855
9799
  onItemCheckChange,
9856
9800
  onItemDoubleClick,
9857
9801
  onItemDragOut,
9802
+ renderDragPreview,
9858
9803
  onItemSelect,
9859
9804
  onDrop,
9860
9805
  selectedId,
@@ -10373,6 +10318,7 @@ function TreeListViewInner({
10373
10318
  onActivateItem: activateEntry,
10374
10319
  onDoubleClickItem: onItemDoubleClick ? handleItemDoubleClick : void 0,
10375
10320
  onItemDragOut,
10321
+ renderDragPreview,
10376
10322
  onPopupMenuItem: handleItemPopupMenu,
10377
10323
  onToggleItemCheck: handleItemCheckChange,
10378
10324
  onToggleItemExpanded: setExpandedState,
@@ -10391,8 +10337,10 @@ function TreeListViewInner({
10391
10337
  }
10392
10338
  );
10393
10339
  }
10394
- var TreeListView = (0, import_react47.forwardRef)(TreeListViewInner);
10395
- var TreeTable = TreeListView;
10340
+ function TreeListViewWithDragDrop(props, ref) {
10341
+ return /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(NuDragDropProvider, { children: TreeListViewInner(props, ref) });
10342
+ }
10343
+ var TreeListView = (0, import_react47.forwardRef)(TreeListViewWithDragDrop);
10396
10344
 
10397
10345
  // src/theme/NuThemeProvider.tsx
10398
10346
  var import_react49 = require("react");
@@ -10852,7 +10800,6 @@ function NuThemeProvider({
10852
10800
  ToolDropButton,
10853
10801
  ToolSeparator,
10854
10802
  TreeListView,
10855
- TreeTable,
10856
10803
  TreeView,
10857
10804
  Window,
10858
10805
  WindowBar,