funda-ui 4.5.677 → 4.5.682
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/ColorPicker/index.js +3 -1
- package/DragDropList/index.css +188 -0
- package/DragDropList/index.d.ts +43 -0
- package/DragDropList/index.js +1589 -0
- package/LICENSE +21 -0
- package/MultipleSelect/index.css +237 -144
- package/MultipleSelect/index.d.ts +23 -10
- package/MultipleSelect/index.js +2242 -1225
- package/README.md +3 -1
- package/Utils/useBoundedDrag.d.ts +127 -0
- package/Utils/useBoundedDrag.js +382 -0
- package/Utils/useDragDropPosition.d.ts +169 -0
- package/Utils/useDragDropPosition.js +456 -0
- package/all.d.ts +1 -0
- package/all.js +1 -0
- package/lib/cjs/ColorPicker/index.js +3 -1
- package/lib/cjs/DragDropList/index.d.ts +43 -0
- package/lib/cjs/DragDropList/index.js +1589 -0
- package/lib/cjs/MultipleSelect/index.d.ts +23 -10
- package/lib/cjs/MultipleSelect/index.js +2242 -1225
- package/lib/cjs/Utils/useBoundedDrag.d.ts +127 -0
- package/lib/cjs/Utils/useBoundedDrag.js +382 -0
- package/lib/cjs/Utils/useDragDropPosition.d.ts +169 -0
- package/lib/cjs/Utils/useDragDropPosition.js +456 -0
- package/lib/cjs/index.d.ts +1 -0
- package/lib/cjs/index.js +1 -0
- package/lib/css/DragDropList/index.css +188 -0
- package/lib/css/MultipleSelect/index.css +237 -144
- package/lib/esm/ColorPicker/index.tsx +53 -49
- package/lib/esm/DragDropList/index.scss +245 -0
- package/lib/esm/DragDropList/index.tsx +493 -0
- package/lib/esm/MultipleSelect/index.scss +288 -183
- package/lib/esm/MultipleSelect/index.tsx +304 -166
- package/lib/esm/MultipleSelect/utils/func.ts +21 -1
- package/lib/esm/Tabs/Tabs.tsx +1 -1
- package/lib/esm/Utils/hooks/useBoundedDrag.tsx +303 -0
- package/lib/esm/Utils/hooks/useDragDropPosition.tsx +420 -0
- package/lib/esm/index.js +1 -0
- package/package.json +1 -1
- package/lib/esm/MultipleSelect/ItemList.tsx +0 -323
|
@@ -34,8 +34,28 @@ export function multiSelControlOptionExist(arr: any[], val: any) {
|
|
|
34
34
|
* @returns
|
|
35
35
|
*/
|
|
36
36
|
export function uniqueArr(arr: any[]) {
|
|
37
|
-
return arr.filter((item: any, index: number, self: any[]) => index === self.findIndex((t) => (t.
|
|
37
|
+
return arr.filter((item: any, index: number, self: any[]) => index === self.findIndex((t) => (t.id == item.id)));
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Remove Duplicate objects from Options
|
|
42
|
+
* @param {Array} arr
|
|
43
|
+
* @returns
|
|
44
|
+
*/
|
|
45
|
+
export function uniqueOpt(arr: any[]) {
|
|
46
|
+
return arr.flat().filter((item: any, index: number, self: any[]) => index === self.findIndex((t) => (t.id === item.id)));
|
|
47
|
+
}
|
|
40
48
|
|
|
41
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Sort JSON arrays according to the order of the numeric arrays
|
|
52
|
+
* @param {Array<Number>|Array<String>} orderArray
|
|
53
|
+
* @param {Array<*>} arr
|
|
54
|
+
* @param {String} field
|
|
55
|
+
* @returns
|
|
56
|
+
*/
|
|
57
|
+
export function sortedJsonArray(orderArray: number[] | string[], arr: any[], field: string = 'value') {
|
|
58
|
+
return orderArray.map((orderId: number | string) =>
|
|
59
|
+
arr.find(item => item[field] === orderId)
|
|
60
|
+
);
|
|
61
|
+
}
|
package/lib/esm/Tabs/Tabs.tsx
CHANGED
|
@@ -18,7 +18,7 @@ export type TabsProps = {
|
|
|
18
18
|
animTransitionDuration?: number;
|
|
19
19
|
/** -- */
|
|
20
20
|
style?: React.CSSProperties;
|
|
21
|
-
onChange?: (nav:
|
|
21
|
+
onChange?: (nav: HTMLElement, targetId: string, index: number, persistentIndex: number) => void;
|
|
22
22
|
onLoad?: (func: Function) => void;
|
|
23
23
|
children: React.ReactNode | React.ReactNode[];
|
|
24
24
|
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded Drag
|
|
3
|
+
*
|
|
4
|
+
* @usage:
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const App = () => {
|
|
8
|
+
const [items, setItems] = useState<ListItem[]>([]);
|
|
9
|
+
// ... other states and refs
|
|
10
|
+
|
|
11
|
+
const deepCloneWithReactNode = (obj: any): any => {
|
|
12
|
+
if (obj === null || typeof obj !== 'object') {
|
|
13
|
+
return obj;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Handle array
|
|
17
|
+
if (Array.isArray(obj)) {
|
|
18
|
+
return obj.map(item => deepCloneWithReactNode(item));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Handle object
|
|
22
|
+
const clonedObj: any = {};
|
|
23
|
+
for (const key in obj) {
|
|
24
|
+
if (key === 'appendControl') {
|
|
25
|
+
clonedObj[key] = obj[key];
|
|
26
|
+
} else {
|
|
27
|
+
clonedObj[key] = deepCloneWithReactNode(obj[key]);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return clonedObj;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
const getItemWithChildrenIndices = (items: ListItem[], startIndex: number): number[] => {
|
|
35
|
+
const indices = [startIndex];
|
|
36
|
+
const startItem = items[startIndex];
|
|
37
|
+
const startDepth = startItem.depth || 0;
|
|
38
|
+
|
|
39
|
+
// Check if subsequent items are child items
|
|
40
|
+
for (let i = startIndex + 1; i < items.length; i++) {
|
|
41
|
+
const currentItem = items[i];
|
|
42
|
+
const currentDepth = currentItem.depth || 0;
|
|
43
|
+
if (currentDepth > startDepth) {
|
|
44
|
+
indices.push(i);
|
|
45
|
+
} else {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return indices;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
const { isDragging, dragHandlers } = useBoundedDrag({
|
|
55
|
+
dragMode,
|
|
56
|
+
boundarySelector: '.custom-draggable-list',
|
|
57
|
+
itemSelector:'.custom-draggable-list__item',
|
|
58
|
+
dragHandleSelector: '.custom-draggable-list__handle',
|
|
59
|
+
onDragStart: (index: number) => {
|
|
60
|
+
// Additional drag start logic if needed
|
|
61
|
+
},
|
|
62
|
+
onDragOver: (dragIndex: number | null, dropIndex: number | null) => {
|
|
63
|
+
// Additional drag over logic if needed
|
|
64
|
+
},
|
|
65
|
+
onDragEnd: (dragIndex: number | null, dropIndex: number | null) => {
|
|
66
|
+
if (dragIndex !== null && dropIndex !== null && dragIndex !== dropIndex) {
|
|
67
|
+
// Handle item movement
|
|
68
|
+
const newItems = deepCloneWithReactNode(items);
|
|
69
|
+
const itemsToMove = getItemWithChildrenIndices(newItems, dragIndex);
|
|
70
|
+
const itemsBeingMoved = itemsToMove.map(index => newItems[index]);
|
|
71
|
+
|
|
72
|
+
// ... rest of your existing drag end logic ...
|
|
73
|
+
|
|
74
|
+
setItems(updatedItems);
|
|
75
|
+
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Update your JSX to use the new handlers
|
|
81
|
+
return (
|
|
82
|
+
<ul className="custom-draggable-list">
|
|
83
|
+
{items.map((item: any, index: number) => (
|
|
84
|
+
<li
|
|
85
|
+
// ... other props
|
|
86
|
+
draggable={!draggable ? undefined : editingItem !== item.id && "true"}
|
|
87
|
+
onDragStart={!draggable ? undefined : (e) => dragHandlers.handleDragStart(e, index)}
|
|
88
|
+
onDragOver={!draggable ? undefined : dragHandlers.handleDragOver}
|
|
89
|
+
onDragEnd={!draggable ? undefined : dragHandlers.handleDragEnd}
|
|
90
|
+
onTouchStart={!draggable ? undefined : (e) => dragHandlers.handleDragStart(e, index)}
|
|
91
|
+
onTouchMove={!draggable ? undefined : dragHandlers.handleDragOver}
|
|
92
|
+
onTouchEnd={!draggable ? undefined : dragHandlers.handleDragEnd}
|
|
93
|
+
>
|
|
94
|
+
<li className="custom-draggable-list__item">
|
|
95
|
+
<span className="custom-draggable-list__handle">☰</span>
|
|
96
|
+
<i>content {indec}<i>
|
|
97
|
+
</li>
|
|
98
|
+
</li>
|
|
99
|
+
))}
|
|
100
|
+
</ul>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
import { useRef, useState } from 'react';
|
|
108
|
+
|
|
109
|
+
export interface TouchOffset {
|
|
110
|
+
x: number;
|
|
111
|
+
y: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface BoundedDragOptions {
|
|
115
|
+
dragMode?: 'handle' | 'block';
|
|
116
|
+
boundarySelector?: string;
|
|
117
|
+
itemSelector?: string;
|
|
118
|
+
dragHandleSelector?: string;
|
|
119
|
+
onDragStart?: (index: number) => void;
|
|
120
|
+
onDragOver?: (dragIndex: number | null, dropIndex: number | null) => void;
|
|
121
|
+
onDragEnd?: (dragIndex: number | null, dropIndex: number | null) => void;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const useBoundedDrag = (options: BoundedDragOptions = {}) => {
|
|
125
|
+
const {
|
|
126
|
+
dragMode = 'handle',
|
|
127
|
+
boundarySelector = '.custom-draggable-list',
|
|
128
|
+
itemSelector = '.custom-draggable-list__item',
|
|
129
|
+
dragHandleSelector = '.custom-draggable-list__handle',
|
|
130
|
+
onDragStart,
|
|
131
|
+
onDragOver,
|
|
132
|
+
onDragEnd
|
|
133
|
+
} = options;
|
|
134
|
+
|
|
135
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
136
|
+
const dragItem = useRef<number | null>(null);
|
|
137
|
+
const dragOverItem = useRef<number | null>(null);
|
|
138
|
+
const dragNode = useRef<HTMLElement | null>(null);
|
|
139
|
+
const touchOffset = useRef<TouchOffset>({ x: 0, y: 0 });
|
|
140
|
+
const currentHoverItem = useRef<HTMLElement | null>(null);
|
|
141
|
+
|
|
142
|
+
const handleDragStart = (e: React.DragEvent | React.TouchEvent, position: number) => {
|
|
143
|
+
const isTouch = 'touches' in e;
|
|
144
|
+
const target = e.target as HTMLElement;
|
|
145
|
+
|
|
146
|
+
// For block mode or handle mode check
|
|
147
|
+
if (dragMode === 'handle') {
|
|
148
|
+
const handle = target.closest(dragHandleSelector);
|
|
149
|
+
if (!handle) {
|
|
150
|
+
if (!isTouch) e.preventDefault();
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Find the draggable item
|
|
156
|
+
const listItem = target.closest(itemSelector) as HTMLElement;
|
|
157
|
+
if (!listItem) return;
|
|
158
|
+
|
|
159
|
+
// Check boundary
|
|
160
|
+
const boundary = listItem.closest(boundarySelector);
|
|
161
|
+
if (!boundary) return;
|
|
162
|
+
|
|
163
|
+
dragItem.current = position;
|
|
164
|
+
onDragStart?.(position);
|
|
165
|
+
|
|
166
|
+
if (isTouch) {
|
|
167
|
+
e.preventDefault(); // Prevent scrolling
|
|
168
|
+
const touch = (e as React.TouchEvent).touches[0];
|
|
169
|
+
const rect = listItem.getBoundingClientRect();
|
|
170
|
+
const boundaryRect = boundary.getBoundingClientRect();
|
|
171
|
+
|
|
172
|
+
// Calculate offset relative to the boundary
|
|
173
|
+
touchOffset.current = {
|
|
174
|
+
x: touch.clientX - rect.left,
|
|
175
|
+
y: touch.clientY - rect.top
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Clone the item for dragging
|
|
179
|
+
dragNode.current = listItem.cloneNode(true) as HTMLElement;
|
|
180
|
+
dragNode.current.classList.add('dragging');
|
|
181
|
+
|
|
182
|
+
// Style the clone
|
|
183
|
+
Object.assign(dragNode.current.style, {
|
|
184
|
+
position: 'fixed',
|
|
185
|
+
width: `${rect.width}px`,
|
|
186
|
+
height: `${rect.height}px`,
|
|
187
|
+
left: `${rect.left}px`,
|
|
188
|
+
top: `${rect.top}px`,
|
|
189
|
+
zIndex: '1000',
|
|
190
|
+
pointerEvents: 'none',
|
|
191
|
+
transform: 'scale(1.05)',
|
|
192
|
+
transition: 'transform 0.1s',
|
|
193
|
+
opacity: '0.9'
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
document.body.appendChild(dragNode.current);
|
|
197
|
+
setIsDragging(true);
|
|
198
|
+
listItem.classList.add('dragging-placeholder');
|
|
199
|
+
} else {
|
|
200
|
+
// ... desktop drag logic remains the same ...
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const handleDragOver = (e: React.DragEvent | React.TouchEvent) => {
|
|
205
|
+
e.preventDefault();
|
|
206
|
+
const isTouch = 'touches' in e;
|
|
207
|
+
|
|
208
|
+
if (!isTouch) {
|
|
209
|
+
(e as React.DragEvent).dataTransfer.dropEffect = 'move';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Get the current pointer/touch position
|
|
213
|
+
const point = isTouch ?
|
|
214
|
+
(e as React.TouchEvent).touches[0] :
|
|
215
|
+
{ clientX: (e as React.DragEvent).clientX, clientY: (e as React.DragEvent).clientY };
|
|
216
|
+
|
|
217
|
+
// Update dragged element position for touch events
|
|
218
|
+
if (isTouch && isDragging && dragNode.current) {
|
|
219
|
+
dragNode.current.style.left = `${point.clientX - touchOffset.current.x}px`;
|
|
220
|
+
dragNode.current.style.top = `${point.clientY - touchOffset.current.y}px`;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Find the element below the pointer/touch
|
|
224
|
+
const elemBelow = document.elementFromPoint(
|
|
225
|
+
point.clientX,
|
|
226
|
+
point.clientY
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
if (!elemBelow) return;
|
|
230
|
+
|
|
231
|
+
// Find the closest list item
|
|
232
|
+
const listItem = elemBelow.closest(itemSelector) as HTMLElement;
|
|
233
|
+
if (!listItem || listItem === currentHoverItem.current) return;
|
|
234
|
+
|
|
235
|
+
// Check boundary
|
|
236
|
+
const boundary = listItem.closest(boundarySelector);
|
|
237
|
+
if (!boundary) return;
|
|
238
|
+
|
|
239
|
+
// Update hover states
|
|
240
|
+
if (currentHoverItem.current) {
|
|
241
|
+
currentHoverItem.current.classList.remove('drag-over', 'drag-over-top', 'drag-over-bottom');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
currentHoverItem.current = listItem;
|
|
245
|
+
listItem.classList.add('drag-over');
|
|
246
|
+
|
|
247
|
+
// Calculate position in list
|
|
248
|
+
const position = Array.from(listItem.parentNode!.children).indexOf(listItem);
|
|
249
|
+
dragOverItem.current = position;
|
|
250
|
+
|
|
251
|
+
// Determine drop position (top/bottom)
|
|
252
|
+
const rect = listItem.getBoundingClientRect();
|
|
253
|
+
const middleY = rect.top + rect.height / 2;
|
|
254
|
+
|
|
255
|
+
if (point.clientY < middleY) {
|
|
256
|
+
listItem.classList.add('drag-over-top');
|
|
257
|
+
} else {
|
|
258
|
+
listItem.classList.add('drag-over-bottom');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
onDragOver?.(dragItem.current, dragOverItem.current);
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
const handleDragEnd = (e: React.DragEvent | React.TouchEvent) => {
|
|
265
|
+
const isTouch = 'touches' in e;
|
|
266
|
+
if (isTouch && !isDragging) return;
|
|
267
|
+
|
|
268
|
+
onDragEnd?.(dragItem.current, dragOverItem.current);
|
|
269
|
+
|
|
270
|
+
// Cleanup
|
|
271
|
+
if (dragNode.current) {
|
|
272
|
+
dragNode.current.remove();
|
|
273
|
+
dragNode.current = null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
document.querySelectorAll(itemSelector).forEach(item => {
|
|
277
|
+
(item as HTMLElement).style.opacity = '1';
|
|
278
|
+
item.classList.remove(
|
|
279
|
+
'dragging',
|
|
280
|
+
'dragging-placeholder',
|
|
281
|
+
'drag-over',
|
|
282
|
+
'drag-over-top',
|
|
283
|
+
'drag-over-bottom'
|
|
284
|
+
);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
setIsDragging(false);
|
|
288
|
+
currentHoverItem.current = null;
|
|
289
|
+
dragItem.current = null;
|
|
290
|
+
dragOverItem.current = null;
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
isDragging,
|
|
295
|
+
dragHandlers: {
|
|
296
|
+
handleDragStart,
|
|
297
|
+
handleDragOver,
|
|
298
|
+
handleDragEnd
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
export default useBoundedDrag;
|