@uxf/core-react 11.90.1 → 11.93.0
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/README.md +204 -0
- package/dnd/hooks/use-sortable-core.d.ts +9 -0
- package/dnd/hooks/use-sortable-core.js +32 -0
- package/dnd/hooks/use-sortable-items.d.ts +15 -0
- package/dnd/hooks/use-sortable-items.js +57 -0
- package/dnd/hooks/use-sortable-multi.d.ts +12 -0
- package/dnd/hooks/use-sortable-multi.js +91 -0
- package/dnd/hooks/use-sortable-single.d.ts +13 -0
- package/dnd/hooks/use-sortable-single.js +37 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -395,6 +395,210 @@ import { twScreens } from "@generated/tw-tokens/tw-screens";
|
|
|
395
395
|
const isDesktop = useMediaQuery(`(min-width: ${twScreens.sm})`);
|
|
396
396
|
```
|
|
397
397
|
|
|
398
|
+
## Drag and Drop (DND) Hooks
|
|
399
|
+
|
|
400
|
+
Provides a set of hooks built on top of [@dnd-kit](https://dndkit.com/) for implementing drag-and-drop functionality with different patterns.
|
|
401
|
+
|
|
402
|
+
### useSortableCore
|
|
403
|
+
|
|
404
|
+
Low-level hook that provides the core drag-and-drop functionality. Used as a building block for other sortable hooks.
|
|
405
|
+
|
|
406
|
+
```tsx
|
|
407
|
+
import { useSortableCore } from "@uxf/core-react/dnd/hooks/use-sortable-core";
|
|
408
|
+
|
|
409
|
+
const {
|
|
410
|
+
activeElement, // Currently dragged element
|
|
411
|
+
setActiveElement, // Set active element manually
|
|
412
|
+
onDragStart, // Drag start handler
|
|
413
|
+
onDragCancel, // Drag cancel handler
|
|
414
|
+
sensors, // DND sensors (pointer, keyboard)
|
|
415
|
+
dropAnimationConfig // Animation configuration for drop
|
|
416
|
+
} = useSortableCore();
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
### useSortableSingle
|
|
421
|
+
|
|
422
|
+
Hook for implementing drag-and-drop sorting within a single list. Manages item reordering and state internally.
|
|
423
|
+
|
|
424
|
+
```tsx
|
|
425
|
+
import { DndContext, DragOverlay } from "@dnd-kit/core";
|
|
426
|
+
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
427
|
+
import { useSortableSingle } from "@uxf/core-react/dnd/hooks/use-sortable-single";
|
|
428
|
+
import { SortableItem } from "./sortable-item"; // Your sortable item component
|
|
429
|
+
|
|
430
|
+
interface Task {
|
|
431
|
+
id: string;
|
|
432
|
+
title: string;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function TaskList() {
|
|
436
|
+
const initialTasks: Task[] = [
|
|
437
|
+
{ id: "1", title: "Write documentation" },
|
|
438
|
+
{ id: "2", title: "Review PR" },
|
|
439
|
+
{ id: "3", title: "Deploy to production" }
|
|
440
|
+
];
|
|
441
|
+
|
|
442
|
+
const {
|
|
443
|
+
items, // Current items state
|
|
444
|
+
setItems, // Update items manually
|
|
445
|
+
activeItem, // Currently dragged item
|
|
446
|
+
onDragStart,
|
|
447
|
+
onDragEnd,
|
|
448
|
+
onDragCancel,
|
|
449
|
+
sensors,
|
|
450
|
+
dropAnimationConfig
|
|
451
|
+
} = useSortableSingle(
|
|
452
|
+
initialTasks,
|
|
453
|
+
(fromIndex, toIndex, updatedList) => {
|
|
454
|
+
// Optional callback when items are reordered
|
|
455
|
+
console.log(`Moved from ${fromIndex} to ${toIndex}`, updatedList);
|
|
456
|
+
}
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
return (
|
|
460
|
+
<DndContext
|
|
461
|
+
sensors={sensors}
|
|
462
|
+
onDragStart={onDragStart}
|
|
463
|
+
onDragEnd={onDragEnd}
|
|
464
|
+
onDragCancel={onDragCancel}
|
|
465
|
+
>
|
|
466
|
+
<SortableContext items={items.map(item => item.id)} strategy={verticalListSortingStrategy}>
|
|
467
|
+
{items.map(task => (
|
|
468
|
+
<SortableItem key={task.id} id={task.id}>
|
|
469
|
+
{task.title}
|
|
470
|
+
</SortableItem>
|
|
471
|
+
))}
|
|
472
|
+
</SortableContext>
|
|
473
|
+
|
|
474
|
+
<DragOverlay dropAnimation={dropAnimationConfig}>
|
|
475
|
+
{activeItem ? <div>{activeItem.title}</div> : null}
|
|
476
|
+
</DragOverlay>
|
|
477
|
+
</DndContext>
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
---
|
|
483
|
+
### useSortableMulti
|
|
484
|
+
|
|
485
|
+
Hook for implementing drag-and-drop between multiple sections/lists. Ideal for kanban boards, categorized lists, or visible/hidden column management.
|
|
486
|
+
|
|
487
|
+
```tsx
|
|
488
|
+
import { DndContext, DragOverlay, rectIntersection } from "@dnd-kit/core";
|
|
489
|
+
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
|
|
490
|
+
import { useSortableMulti } from "@uxf/core-react/dnd/hooks/use-sortable-multi";
|
|
491
|
+
import { SortableItem } from "./sortable-item"; // Your sortable item component
|
|
492
|
+
|
|
493
|
+
interface Task {
|
|
494
|
+
id: string;
|
|
495
|
+
title: string;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
interface Sections {
|
|
499
|
+
todo: Task[];
|
|
500
|
+
inProgress: Task[];
|
|
501
|
+
done: Task[];
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function KanbanBoard() {
|
|
505
|
+
const [sections, setSections] = useState<Sections>({
|
|
506
|
+
todo: [
|
|
507
|
+
{ id: "1", title: "Design UI" },
|
|
508
|
+
{ id: "2", title: "Write tests" }
|
|
509
|
+
],
|
|
510
|
+
inProgress: [
|
|
511
|
+
{ id: "3", title: "Implement feature" }
|
|
512
|
+
],
|
|
513
|
+
done: [
|
|
514
|
+
{ id: "4", title: "Setup project" }
|
|
515
|
+
]
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
const {
|
|
519
|
+
getSectionItemsIds, // Get IDs for a section (handles empty sections)
|
|
520
|
+
activeItem, // Currently dragged item
|
|
521
|
+
onDragStart,
|
|
522
|
+
onDragEnd,
|
|
523
|
+
onDragCancel,
|
|
524
|
+
sensors,
|
|
525
|
+
dropAnimationConfig
|
|
526
|
+
} = useSortableMulti<Task, Sections>(
|
|
527
|
+
sections,
|
|
528
|
+
setSections,
|
|
529
|
+
(sourceKey, destKey, fromIndex, toIndex, nextState) => {
|
|
530
|
+
// Optional callback when items are moved between sections
|
|
531
|
+
console.log(`Moved from ${String(sourceKey)} to ${String(destKey)}`);
|
|
532
|
+
// Save to backend, analytics, etc.
|
|
533
|
+
}
|
|
534
|
+
);
|
|
535
|
+
|
|
536
|
+
return (
|
|
537
|
+
<DndContext
|
|
538
|
+
sensors={sensors}
|
|
539
|
+
collisionDetection={rectIntersection}
|
|
540
|
+
onDragStart={onDragStart}
|
|
541
|
+
onDragEnd={onDragEnd}
|
|
542
|
+
onDragCancel={onDragCancel}
|
|
543
|
+
>
|
|
544
|
+
<div className="kanban-board">
|
|
545
|
+
{(Object.keys(sections) as Array<keyof Sections>).map((sectionKey) => (
|
|
546
|
+
<div key={sectionKey} className="kanban-column">
|
|
547
|
+
<h3>{sectionKey}</h3>
|
|
548
|
+
<SortableContext
|
|
549
|
+
items={getSectionItemsIds(sectionKey)}
|
|
550
|
+
strategy={verticalListSortingStrategy}
|
|
551
|
+
>
|
|
552
|
+
{sections[sectionKey].map(task => (
|
|
553
|
+
<SortableItem key={task.id} id={task.id}>
|
|
554
|
+
{task.title}
|
|
555
|
+
</SortableItem>
|
|
556
|
+
))}
|
|
557
|
+
</SortableContext>
|
|
558
|
+
</div>
|
|
559
|
+
))}
|
|
560
|
+
</div>
|
|
561
|
+
|
|
562
|
+
<DragOverlay dropAnimation={dropAnimationConfig}>
|
|
563
|
+
{activeItem ? <div>{activeItem.title}</div> : null}
|
|
564
|
+
</DragOverlay>
|
|
565
|
+
</DndContext>
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
**Notes:**
|
|
571
|
+
- Items must have an `id: string` property
|
|
572
|
+
- `getSectionItemsIds` automatically handles empty sections by returning placeholder IDs
|
|
573
|
+
- Use `rectIntersection` collision detection for better multi-section behavior
|
|
574
|
+
- The hook manages item movement between sections automatically
|
|
575
|
+
|
|
576
|
+
---
|
|
577
|
+
### useSortableItems
|
|
578
|
+
|
|
579
|
+
Legacy hook for drag-and-drop sorting. Consider using `useSortableSingle` for new implementations.
|
|
580
|
+
|
|
581
|
+
```tsx
|
|
582
|
+
import { useSortableItems } from "@uxf/core-react/dnd/hooks/use-sortable-items";
|
|
583
|
+
|
|
584
|
+
const {
|
|
585
|
+
memoizedSensors,
|
|
586
|
+
dropAnimationConfig,
|
|
587
|
+
itemsIds,
|
|
588
|
+
activeItem,
|
|
589
|
+
onDragStart,
|
|
590
|
+
onDragEnd,
|
|
591
|
+
onDragCancel
|
|
592
|
+
} = useSortableItems({
|
|
593
|
+
items: myItems,
|
|
594
|
+
handleDragEnd: (activeIndex, overIndex) => {
|
|
595
|
+
// Handle reorder
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
398
602
|
## Translations
|
|
399
603
|
|
|
400
604
|
Provides a translation system that can be used in both single-language and multi-language projects.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Active, DragStartEvent } from "@dnd-kit/core";
|
|
2
|
+
export declare const useSortableCore: () => {
|
|
3
|
+
activeElement: Active | null;
|
|
4
|
+
setActiveElement: import("react").Dispatch<import("react").SetStateAction<Active | null>>;
|
|
5
|
+
onDragStart: ({ active }: DragStartEvent) => void;
|
|
6
|
+
onDragCancel: () => void;
|
|
7
|
+
sensors: import("@dnd-kit/core").SensorDescriptor<import("@dnd-kit/core").SensorOptions>[];
|
|
8
|
+
dropAnimationConfig: import("@dnd-kit/core/dist/components/DragOverlay/hooks/useDropAnimation").DropAnimationOptions;
|
|
9
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSortableCore = void 0;
|
|
4
|
+
const core_1 = require("@dnd-kit/core");
|
|
5
|
+
const sortable_1 = require("@dnd-kit/sortable");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const useSortableCore = () => {
|
|
8
|
+
const [activeElement, setActiveElement] = (0, react_1.useState)(null);
|
|
9
|
+
const sensors = (0, core_1.useSensors)((0, core_1.useSensor)(core_1.PointerSensor), (0, core_1.useSensor)(core_1.KeyboardSensor, {
|
|
10
|
+
coordinateGetter: sortable_1.sortableKeyboardCoordinates,
|
|
11
|
+
}));
|
|
12
|
+
const dropAnimationConfig = {
|
|
13
|
+
sideEffects: (0, core_1.defaultDropAnimationSideEffects)({
|
|
14
|
+
styles: { active: { opacity: "0.4" } },
|
|
15
|
+
}),
|
|
16
|
+
};
|
|
17
|
+
const onDragStart = (0, react_1.useCallback)(({ active }) => {
|
|
18
|
+
setActiveElement(active);
|
|
19
|
+
}, []);
|
|
20
|
+
const onDragCancel = (0, react_1.useCallback)(() => {
|
|
21
|
+
setActiveElement(null);
|
|
22
|
+
}, []);
|
|
23
|
+
return {
|
|
24
|
+
activeElement,
|
|
25
|
+
setActiveElement,
|
|
26
|
+
onDragStart,
|
|
27
|
+
onDragCancel,
|
|
28
|
+
sensors,
|
|
29
|
+
dropAnimationConfig,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
exports.useSortableCore = useSortableCore;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DragEndEvent, DragStartEvent } from "@dnd-kit/core";
|
|
2
|
+
type Props = {
|
|
3
|
+
items: any[];
|
|
4
|
+
handleDragEnd: (activeIndex: number, overIndex: number) => void;
|
|
5
|
+
};
|
|
6
|
+
export declare const useSortableItems: ({ items, handleDragEnd }: Props) => {
|
|
7
|
+
memoizedSensors: import("@dnd-kit/core").SensorDescriptor<import("@dnd-kit/core").SensorOptions>[];
|
|
8
|
+
dropAnimationConfig: import("@dnd-kit/core/dist/components/DragOverlay/hooks/useDropAnimation").DropAnimationOptions;
|
|
9
|
+
itemsIds: any[];
|
|
10
|
+
activeItem: any;
|
|
11
|
+
onDragStart: ({ active }: DragStartEvent) => void;
|
|
12
|
+
onDragEnd: ({ active, over }: DragEndEvent) => void;
|
|
13
|
+
onDragCancel: () => void;
|
|
14
|
+
};
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSortableItems = void 0;
|
|
4
|
+
const core_1 = require("@dnd-kit/core");
|
|
5
|
+
const sortable_1 = require("@dnd-kit/sortable");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const useSortableItems = ({ items, handleDragEnd }) => {
|
|
8
|
+
const [sortableItems, setSortableItems] = (0, react_1.useState)(items);
|
|
9
|
+
const [activeElement, setActiveElement] = (0, react_1.useState)(null);
|
|
10
|
+
const activeItem = (0, react_1.useMemo)(() => sortableItems.find((item) => item.id === (activeElement === null || activeElement === void 0 ? void 0 : activeElement.id)), [activeElement, sortableItems]);
|
|
11
|
+
const sensors = (0, core_1.useSensors)((0, core_1.useSensor)(core_1.PointerSensor), (0, core_1.useSensor)(core_1.KeyboardSensor, {
|
|
12
|
+
coordinateGetter: sortable_1.sortableKeyboardCoordinates,
|
|
13
|
+
}));
|
|
14
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
15
|
+
const memoizedSensors = (0, react_1.useMemo)(() => sensors, []);
|
|
16
|
+
const idsStringified = JSON.stringify(sortableItems.map((i) => i.id));
|
|
17
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
18
|
+
const itemsIds = (0, react_1.useMemo)(() => sortableItems.map((i) => i.id), [idsStringified]);
|
|
19
|
+
(0, react_1.useEffect)(() => {
|
|
20
|
+
setSortableItems(items);
|
|
21
|
+
}, [items]);
|
|
22
|
+
const dropAnimationConfig = {
|
|
23
|
+
sideEffects: (0, core_1.defaultDropAnimationSideEffects)({
|
|
24
|
+
styles: {
|
|
25
|
+
active: {
|
|
26
|
+
opacity: "0.4",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
const onDragStart = (0, react_1.useCallback)(({ active }) => {
|
|
32
|
+
setActiveElement(active);
|
|
33
|
+
}, [setActiveElement]);
|
|
34
|
+
const onDragEnd = (0, react_1.useCallback)(({ active, over }) => {
|
|
35
|
+
if (over && active.id !== over.id) {
|
|
36
|
+
const activeIndex = sortableItems.findIndex(({ id }) => id === active.id);
|
|
37
|
+
const overIndex = sortableItems.findIndex(({ id }) => id === over.id);
|
|
38
|
+
const resorted = (0, sortable_1.arrayMove)(sortableItems, activeIndex, overIndex);
|
|
39
|
+
handleDragEnd(activeIndex, overIndex);
|
|
40
|
+
setSortableItems(resorted);
|
|
41
|
+
}
|
|
42
|
+
setActiveElement(null);
|
|
43
|
+
}, [setActiveElement, setSortableItems, handleDragEnd, sortableItems]);
|
|
44
|
+
const onDragCancel = (0, react_1.useCallback)(() => {
|
|
45
|
+
setActiveElement(null);
|
|
46
|
+
}, [setActiveElement]);
|
|
47
|
+
return {
|
|
48
|
+
memoizedSensors,
|
|
49
|
+
dropAnimationConfig,
|
|
50
|
+
itemsIds,
|
|
51
|
+
activeItem,
|
|
52
|
+
onDragStart,
|
|
53
|
+
onDragEnd,
|
|
54
|
+
onDragCancel,
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
exports.useSortableItems = useSortableItems;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { DragEndEvent } from "@dnd-kit/core";
|
|
2
|
+
export declare function useSortableMulti<T extends {
|
|
3
|
+
id: string;
|
|
4
|
+
}, SectionMap extends Record<string, T[]>>(sections: SectionMap, setSections: (next: SectionMap) => void, onMove?: (source: keyof SectionMap, destination: keyof SectionMap, fromIndex: number, toIndex: number, nextState: SectionMap) => void): {
|
|
5
|
+
getSectionItemsIds: (section: keyof SectionMap) => string[];
|
|
6
|
+
activeItem: T | null;
|
|
7
|
+
onDragStart: ({ active }: import("@dnd-kit/core").DragStartEvent) => void;
|
|
8
|
+
onDragEnd: ({ active, over }: DragEndEvent) => void;
|
|
9
|
+
onDragCancel: () => void;
|
|
10
|
+
sensors: import("@dnd-kit/core").SensorDescriptor<import("@dnd-kit/core").SensorOptions>[];
|
|
11
|
+
dropAnimationConfig: import("@dnd-kit/core/dist/components/DragOverlay/hooks/useDropAnimation").DropAnimationOptions;
|
|
12
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSortableMulti = useSortableMulti;
|
|
4
|
+
const sortable_1 = require("@dnd-kit/sortable");
|
|
5
|
+
const types_1 = require("@uxf/data-grid/hidden-columns/types");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const use_sortable_core_1 = require("./use-sortable-core");
|
|
8
|
+
function useSortableMulti(sections, setSections, onMove) {
|
|
9
|
+
const { activeElement, setActiveElement, onDragStart, onDragCancel, sensors, dropAnimationConfig } = (0, use_sortable_core_1.useSortableCore)();
|
|
10
|
+
const activeItem = (0, react_1.useMemo)(() => {
|
|
11
|
+
if (!(activeElement === null || activeElement === void 0 ? void 0 : activeElement.id)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
for (const items of Object.values(sections)) {
|
|
15
|
+
const item = items.find((i) => i.id === activeElement.id);
|
|
16
|
+
if (item) {
|
|
17
|
+
return item;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
21
|
+
}, [activeElement, sections]);
|
|
22
|
+
const onDragEnd = (0, react_1.useCallback)(({ active, over }) => {
|
|
23
|
+
if (!over || active.id === over.id) {
|
|
24
|
+
setActiveElement(null);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const isDroppingToEmptyPlaceholder = over.id === types_1.EMPTY_HIDDEN_COLUMNS_PLACEHOLDER_ID || over.id === types_1.EMPTY_VISIBLE_COLUMNS_PLACEHOLDER_ID;
|
|
28
|
+
let sourceKey = null;
|
|
29
|
+
let destKey = null;
|
|
30
|
+
// Determine source key by checking where the active item currently is
|
|
31
|
+
for (const key in sections) {
|
|
32
|
+
if (sections[key].find((item) => item.id === active.id)) {
|
|
33
|
+
sourceKey = key;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Determine destination key based on over.id
|
|
37
|
+
if (isDroppingToEmptyPlaceholder) {
|
|
38
|
+
destKey = over.id === types_1.EMPTY_VISIBLE_COLUMNS_PLACEHOLDER_ID ? "visible" : "hidden";
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
for (const key in sections) {
|
|
42
|
+
if (sections[key].find((item) => item.id === over.id)) {
|
|
43
|
+
destKey = key;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (!sourceKey || !destKey) {
|
|
48
|
+
setActiveElement(null);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const sourceList = [...sections[sourceKey]];
|
|
52
|
+
const destList = [...sections[destKey]];
|
|
53
|
+
const fromIndex = sourceList.findIndex((item) => item.id === active.id);
|
|
54
|
+
let toIndex = destList.findIndex((item) => item.id === over.id);
|
|
55
|
+
// If dropping onto a placeholder or not found in list, append at end
|
|
56
|
+
if (toIndex === -1 || isDroppingToEmptyPlaceholder) {
|
|
57
|
+
toIndex = destList.length;
|
|
58
|
+
}
|
|
59
|
+
const nextState = { ...sections };
|
|
60
|
+
if (sourceKey === destKey) {
|
|
61
|
+
nextState[sourceKey] = (0, sortable_1.arrayMove)(sourceList, fromIndex, toIndex);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const [moved] = sourceList.splice(fromIndex, 1);
|
|
65
|
+
destList.splice(toIndex, 0, moved);
|
|
66
|
+
nextState[sourceKey] = sourceList;
|
|
67
|
+
nextState[destKey] = destList;
|
|
68
|
+
}
|
|
69
|
+
setSections(nextState);
|
|
70
|
+
onMove === null || onMove === void 0 ? void 0 : onMove(sourceKey, destKey, fromIndex, toIndex, nextState);
|
|
71
|
+
setActiveElement(null);
|
|
72
|
+
}, [sections, setSections, onMove, setActiveElement]);
|
|
73
|
+
const getSectionItemsIds = (0, react_1.useCallback)((section) => {
|
|
74
|
+
const ids = sections[section].map((i) => i.id);
|
|
75
|
+
if (ids.length === 0) {
|
|
76
|
+
return [
|
|
77
|
+
section === "visible" ? types_1.EMPTY_VISIBLE_COLUMNS_PLACEHOLDER_ID : types_1.EMPTY_HIDDEN_COLUMNS_PLACEHOLDER_ID,
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
return ids;
|
|
81
|
+
}, [sections]);
|
|
82
|
+
return {
|
|
83
|
+
getSectionItemsIds,
|
|
84
|
+
activeItem,
|
|
85
|
+
onDragStart,
|
|
86
|
+
onDragEnd,
|
|
87
|
+
onDragCancel,
|
|
88
|
+
sensors,
|
|
89
|
+
dropAnimationConfig,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { DragEndEvent } from "@dnd-kit/core";
|
|
2
|
+
export declare const useSortableSingle: <T extends {
|
|
3
|
+
id: string;
|
|
4
|
+
}>(initialItems: T[], onReorder?: (fromIndex: number, toIndex: number, updatedList: T[]) => void) => {
|
|
5
|
+
items: T[];
|
|
6
|
+
setItems: import("react").Dispatch<import("react").SetStateAction<T[]>>;
|
|
7
|
+
activeItem: T | null;
|
|
8
|
+
onDragStart: ({ active }: import("@dnd-kit/core").DragStartEvent) => void;
|
|
9
|
+
onDragEnd: ({ active, over }: DragEndEvent) => void;
|
|
10
|
+
onDragCancel: () => void;
|
|
11
|
+
sensors: import("@dnd-kit/core").SensorDescriptor<import("@dnd-kit/core").SensorOptions>[];
|
|
12
|
+
dropAnimationConfig: import("@dnd-kit/core/dist/components/DragOverlay/hooks/useDropAnimation").DropAnimationOptions;
|
|
13
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useSortableSingle = void 0;
|
|
4
|
+
const sortable_1 = require("@dnd-kit/sortable");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const use_sortable_core_1 = require("./use-sortable-core");
|
|
7
|
+
const useSortableSingle = (initialItems, onReorder) => {
|
|
8
|
+
const [items, setItems] = (0, react_1.useState)(initialItems);
|
|
9
|
+
const { activeElement, setActiveElement, onDragStart, onDragCancel, sensors, dropAnimationConfig } = (0, use_sortable_core_1.useSortableCore)();
|
|
10
|
+
(0, react_1.useEffect)(() => {
|
|
11
|
+
setItems(initialItems);
|
|
12
|
+
}, [initialItems]);
|
|
13
|
+
const activeItem = (0, react_1.useMemo)(() => { var _a; return (_a = items.find((item) => item.id === (activeElement === null || activeElement === void 0 ? void 0 : activeElement.id))) !== null && _a !== void 0 ? _a : null; }, [activeElement, items]);
|
|
14
|
+
const onDragEnd = (0, react_1.useCallback)(({ active, over }) => {
|
|
15
|
+
if (!over || active.id === over.id) {
|
|
16
|
+
setActiveElement(null);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const fromIndex = items.findIndex((i) => i.id === active.id);
|
|
20
|
+
const toIndex = items.findIndex((i) => i.id === over.id);
|
|
21
|
+
const reordered = (0, sortable_1.arrayMove)(items, fromIndex, toIndex);
|
|
22
|
+
setItems(reordered);
|
|
23
|
+
onReorder === null || onReorder === void 0 ? void 0 : onReorder(fromIndex, toIndex, reordered);
|
|
24
|
+
setActiveElement(null);
|
|
25
|
+
}, [items, setActiveElement, onReorder]);
|
|
26
|
+
return {
|
|
27
|
+
items,
|
|
28
|
+
setItems,
|
|
29
|
+
activeItem,
|
|
30
|
+
onDragStart,
|
|
31
|
+
onDragEnd,
|
|
32
|
+
onDragCancel,
|
|
33
|
+
sensors,
|
|
34
|
+
dropAnimationConfig,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
exports.useSortableSingle = useSortableSingle;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uxf/core-react",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.93.0",
|
|
4
4
|
"description": "UXF Core",
|
|
5
5
|
"author": "UX Fans s.r.o",
|
|
6
6
|
"license": "MIT",
|
|
@@ -12,7 +12,9 @@
|
|
|
12
12
|
"typecheck": "tsc --noEmit --skipLibCheck"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@uxf/core": "11.
|
|
15
|
+
"@uxf/core": "11.93.0",
|
|
16
|
+
"@dnd-kit/core": "6.3.1",
|
|
17
|
+
"@dnd-kit/sortable": "10.0.0"
|
|
16
18
|
},
|
|
17
19
|
"peerDependencies": {
|
|
18
20
|
"react": ">=18.2.0"
|