@rnaga/wp-next-ui 1.1.2 → 1.1.4

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/SortableList.d.ts CHANGED
@@ -15,10 +15,25 @@ export declare const SortableList: <T extends any = string>(props: {
15
15
  label?: SxProps;
16
16
  };
17
17
  displayType: DisplayType;
18
+ /**
19
+ * Unique ID for this list. Used as a `data-drop-target-id` on the wrapper Box
20
+ * so that items dragged from another SortableList can be dropped here via
21
+ * the dragging list's `onDropToTarget` callback.
22
+ * Also used to prevent cross-list item swapping.
23
+ */
24
+ dropZoneId?: string;
18
25
  renderItem?: (item: SortableListItemType<T>) => JSX.Element;
19
26
  onDelete?: (index: number) => void;
20
27
  onEdit?: (index: number) => void;
21
- onChange?: (items: SortableListItemType<T>[]) => void;
28
+ onChange?: (items: SortableListItemType<T>[], fromIndex: number, toIndex: number) => void;
29
+ onDrop?: (item: SortableListItemType<T>) => void;
30
+ onDropToTarget?: (item: SortableListItemType<T>, targetId: string) => void;
31
+ onDropTargetEnter?: (targetId: string) => void;
32
+ onDropTargetLeave?: (targetId: string) => void;
33
+ cursor?: {
34
+ idle?: string;
35
+ dragging?: string;
36
+ };
22
37
  }) => import("react/jsx-runtime").JSX.Element;
23
38
  export {};
24
39
  //# sourceMappingURL=SortableList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SortableList.d.ts","sourceRoot":"","sources":["../src/SortableList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAEL,GAAG,EAKJ,MAAM,OAAO,CAAC;AAGf,MAAM,MAAM,oBAAoB,CAAC,CAAC,GAAG,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;AAE/D,KAAK,WAAW,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,GAAG,gBAAgB,CAAC;AAczE,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnE,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,GAAG,GAAG,MAAM,EAAE,OAAO;IAC1D,IAAI,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpC,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IACF,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC;IAC5D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC;CACvD,4CAgPA,CAAC"}
1
+ {"version":3,"file":"SortableList.d.ts","sourceRoot":"","sources":["../src/SortableList.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAEL,GAAG,EAOJ,MAAM,OAAO,CAAC;AAIf,MAAM,MAAM,oBAAoB,CAAC,CAAC,GAAG,MAAM,IAAI,YAAY,CAAC,CAAC,CAAC,CAAC;AAE/D,KAAK,WAAW,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,GAAG,gBAAgB,CAAC;AAczE,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnE,eAAO,MAAM,YAAY,GAAI,CAAC,SAAS,GAAG,GAAG,MAAM,EAAE,OAAO;IAC1D,IAAI,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACpC,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC1B,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,WAAW,CAAC,EAAE;QACZ,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC;IACF,WAAW,EAAE,WAAW,CAAC;IACzB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,CAAC;IAC5D,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,QAAQ,CAAC,EAAE,CACT,KAAK,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,EAChC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,KACZ,IAAI,CAAC;IACV,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IACjD,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3E,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C,4CA8TA,CAAC"}
package/SortableList.js CHANGED
@@ -1,12 +1,17 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useMouseMove } from "./hooks/use-mouse-move";
3
- import { createContext, useEffect, useRef, useState, } from "react";
3
+ import { createContext, useEffect, useId, useMemo, useRef, useState, } from "react";
4
+ import { Box } from "@mui/material";
4
5
  import { ListBase } from "./ListBase";
5
6
  const SortableContext = createContext({});
6
7
  export const SortableList = (props) => {
7
- const { size = "small", displayType = "vertical", renderItem, onDelete, onChange, onEdit, } = props;
8
+ const { size = "small", displayType = "vertical", renderItem, onDelete, onChange, onEdit, onDrop, onDropToTarget, onDropTargetEnter, onDropTargetLeave, cursor, dropZoneId, } = props;
9
+ // Stable unique ID for this list instance (used to tag items)
10
+ const generatedId = useId();
11
+ const listId = dropZoneId ?? generatedId;
8
12
  const [items, setItems] = useState([]);
9
13
  const targetRef = useRef(null);
14
+ const dropTargetRef = useRef(null);
10
15
  const refPos = useRef({ x: 0, y: 0 });
11
16
  const itemRefs = useRef(new Map());
12
17
  const draggedItemRef = useRef(null);
@@ -16,7 +21,6 @@ export const SortableList = (props) => {
16
21
  return items.find((item) => item.index === index);
17
22
  };
18
23
  const swapItems = (_e, fromIndex, toIndex) => {
19
- console.log("Swapping items", fromIndex, toIndex);
20
24
  const currentItems = itemsRef.current;
21
25
  if (fromIndex < 0 ||
22
26
  toIndex < 0 ||
@@ -31,7 +35,7 @@ export const SortableList = (props) => {
31
35
  newItems[fromIndex].index = fromIndex;
32
36
  newItems[toIndex].index = toIndex;
33
37
  setItems(newItems);
34
- onChange?.(newItems);
38
+ onChange?.(newItems, fromIndex, toIndex);
35
39
  };
36
40
  const handleDeltaChange = (e, delta) => {
37
41
  const dragged = draggedItemRef.current;
@@ -62,12 +66,18 @@ export const SortableList = (props) => {
62
66
  const sortableItem = el.closest("[data-sortable-item-index]");
63
67
  if (!sortableItem)
64
68
  continue;
69
+ // Only accept items that belong to THIS list (same listId)
70
+ if (sortableItem.getAttribute("data-sortable-list-id") !== listId) {
71
+ continue;
72
+ }
65
73
  const itemIndex = sortableItem.getAttribute("data-sortable-item-index");
66
- if (!itemIndex || itemIndex === String(index))
74
+ if (!itemIndex || itemIndex === String(index)) {
67
75
  continue;
76
+ }
68
77
  const itemIndexNumber = parseInt(itemIndex);
69
- if (itemIndexNumber < 0 || itemIndexNumber >= itemsRef.current.length)
78
+ if (itemIndexNumber < 0 || itemIndexNumber >= itemsRef.current.length) {
70
79
  continue;
80
+ }
71
81
  foundTarget = sortableItem;
72
82
  break;
73
83
  }
@@ -78,13 +88,47 @@ export const SortableList = (props) => {
78
88
  foundTarget.style.border = "1px solid red";
79
89
  }
80
90
  targetRef.current = foundTarget;
91
+ // Check for external drop targets: both explicit [data-drop-target-id] elements
92
+ // and foreign SortableList drop zones ([data-sortable-drop-zone-id] that differ from this list)
93
+ {
94
+ let foundDropTarget = null;
95
+ if (!foundTarget) {
96
+ for (const el of elementsAtPoint) {
97
+ // Look for explicit external drop targets (e.g. collection headers)
98
+ const explicitTarget = el.closest("[data-drop-target-id]");
99
+ if (explicitTarget) {
100
+ foundDropTarget = explicitTarget;
101
+ break;
102
+ }
103
+ // Look for foreign SortableList drop zones (different list ID)
104
+ const dropZone = el.closest("[data-sortable-drop-zone-id]");
105
+ if (dropZone &&
106
+ dropZone.getAttribute("data-sortable-drop-zone-id") !== listId) {
107
+ foundDropTarget = dropZone;
108
+ break;
109
+ }
110
+ }
111
+ }
112
+ if (dropTargetRef.current && dropTargetRef.current !== foundDropTarget) {
113
+ const leavingId = dropTargetRef.current.getAttribute("data-drop-target-id") ??
114
+ dropTargetRef.current.getAttribute("data-sortable-drop-zone-id");
115
+ if (leavingId)
116
+ onDropTargetLeave?.(leavingId);
117
+ }
118
+ if (foundDropTarget && foundDropTarget !== dropTargetRef.current) {
119
+ const enteringId = foundDropTarget.getAttribute("data-drop-target-id") ??
120
+ foundDropTarget.getAttribute("data-sortable-drop-zone-id");
121
+ if (enteringId)
122
+ onDropTargetEnter?.(enteringId);
123
+ }
124
+ dropTargetRef.current = foundDropTarget;
125
+ }
81
126
  };
82
127
  const handleMouseDown = (e) => {
83
128
  const dragged = draggedItemRef.current;
84
129
  if (!dragged)
85
130
  return;
86
131
  const { element, index } = dragged;
87
- console.log("Mouse down on item", index);
88
132
  const rect = element.getBoundingClientRect();
89
133
  if (rect) {
90
134
  refPos.current.y = e.clientY - rect.top - rect.height / 2;
@@ -105,16 +149,34 @@ export const SortableList = (props) => {
105
149
  if (targetRef.current) {
106
150
  const toItemIndex = targetRef.current.getAttribute("data-sortable-item-index");
107
151
  swapItems(e, index, toItemIndex ? parseInt(toItemIndex) : -1);
108
- targetRef.current?.style.removeProperty("border");
152
+ targetRef.current.style.removeProperty("border");
109
153
  targetRef.current = null;
110
154
  }
155
+ else if (dropTargetRef.current) {
156
+ // Dropped onto an external drop target or foreign SortableList drop zone
157
+ const targetId = dropTargetRef.current.getAttribute("data-drop-target-id") ??
158
+ dropTargetRef.current.getAttribute("data-sortable-drop-zone-id");
159
+ const droppedItem = itemsRef.current.find((i) => i.index === index);
160
+ if (droppedItem && targetId) {
161
+ onDropToTarget?.(droppedItem, targetId);
162
+ }
163
+ onDropTargetLeave?.(targetId ?? "");
164
+ dropTargetRef.current = null;
165
+ }
166
+ else {
167
+ // Dropped outside any list or target — fire onDrop
168
+ const droppedItem = itemsRef.current.find((i) => i.index === index);
169
+ if (droppedItem) {
170
+ onDrop?.(droppedItem);
171
+ }
172
+ }
111
173
  draggedItemRef.current = null;
112
174
  };
113
175
  const { initMouseMove } = useMouseMove({
114
176
  onDeltaChange: handleDeltaChange,
115
177
  onMouseUp: handleMouseUp,
116
178
  onMouseDown: handleMouseDown,
117
- cursor: "grabbing",
179
+ cursor: cursor?.dragging ?? "grabbing",
118
180
  threshold: 1,
119
181
  });
120
182
  useEffect(() => {
@@ -126,26 +188,20 @@ export const SortableList = (props) => {
126
188
  }));
127
189
  setItems(initialItems);
128
190
  }, [props.enum]);
129
- let sx = {};
130
- if (props.displayType === "horizontal") {
131
- sx = {
132
- display: "flex",
133
- flexDirection: "row",
134
- };
135
- }
136
- else if (props.displayType === "horizontal-fit") {
137
- sx = {
138
- display: "flex",
139
- flexDirection: "row",
140
- };
141
- }
142
- else if (props.displayType === "grid") {
143
- sx = {
144
- display: "grid",
145
- gridTemplateColumns: "repeat(auto-fill, minmax(100px, 1fr))",
146
- gap: 1,
147
- };
148
- }
191
+ const sx = useMemo(() => {
192
+ if (props.displayType === "horizontal" ||
193
+ props.displayType === "horizontal-fit") {
194
+ return { display: "flex", flexDirection: "row" };
195
+ }
196
+ if (props.displayType === "grid") {
197
+ return {
198
+ display: "grid",
199
+ gridTemplateColumns: "repeat(auto-fill, minmax(100px, 1fr))",
200
+ gap: 1,
201
+ };
202
+ }
203
+ return {};
204
+ }, [props.displayType]);
149
205
  const handleItemMouseDown = (item, e) => {
150
206
  // Find the MuiListItem parent element
151
207
  const listItemElement = e.target.closest("[data-sortable-item-index]");
@@ -155,9 +211,6 @@ export const SortableList = (props) => {
155
211
  initMouseMove(listItemElement)(e);
156
212
  }
157
213
  };
158
- const renderSortableItem = (item) => {
159
- return renderItem ? renderItem(item) : item.label;
160
- };
161
214
  return (_jsx(SortableContext.Provider, { value: {
162
215
  items,
163
216
  findItem: findItem,
@@ -165,11 +218,12 @@ export const SortableList = (props) => {
165
218
  refPos,
166
219
  targetRef,
167
220
  displayType,
168
- }, children: _jsx(ListBase, { items: items, size: size, sx: { ...sx, ...props.sx }, displayType: displayType, renderItem: renderSortableItem, onDelete: onDelete, onEdit: onEdit, onMouseDown: handleItemMouseDown, getItemDataAttributes: (item) => ({
169
- "data-sortable-item-index": item.index,
170
- }), slotSxProps: {
171
- listItem: {
172
- cursor: "move",
173
- },
174
- } }) }));
221
+ }, children: _jsx(Box, { "data-sortable-drop-zone-id": listId, children: _jsx(ListBase, { items: items, size: size, sx: { ...sx, ...props.sx }, displayType: displayType, renderItem: (item) => renderItem ? renderItem(item) : _jsx(_Fragment, { children: item.label }), onDelete: onDelete, onEdit: onEdit, onMouseDown: handleItemMouseDown, getItemDataAttributes: (item) => ({
222
+ "data-sortable-item-index": item.index,
223
+ "data-sortable-list-id": listId,
224
+ }), slotSxProps: {
225
+ listItem: {
226
+ cursor: cursor?.idle ?? "move",
227
+ },
228
+ } }) }) }));
175
229
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rnaga/wp-next-ui",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "scripts": {
5
5
  "build": "node ../../scripts/build-ui.mjs",
6
6
  "release-old": "node ../../scripts/release.mjs",