@etsoo/react
Version:
TypeScript ReactJs UI Independent Framework
131 lines (130 loc) • 4.83 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { DndContext } from "@dnd-kit/core";
import { SortableContext, useSortable, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import React from "react";
function SortableItem(props) {
// Destruct
const { id, itemRenderer, style = {} } = props;
// Use sortable
const { attributes, listeners, setNodeRef, transform, transition, setActivatorNodeRef } = useSortable({ id });
const allStyle = {
...style,
transform: CSS.Transform.toString(transform),
transition
};
const nodeRef = {
style: allStyle,
ref: setNodeRef,
...attributes
};
const actionNodeRef = {
...listeners,
ref: setActivatorNodeRef
};
return itemRenderer(nodeRef, actionNodeRef);
}
/**
* DnD (Drag and Drop) sortable list
* @param props Props
* @returns Component
*/
export function DnDList(props) {
// Destruct
const { getItemStyle, keyField, itemRenderer, labelField, mRef, onChange, onDragEnd } = props;
// States
const [items, setItems] = React.useState([]);
const [activeId, setActiveId] = React.useState();
const changeItems = (newItems) => {
// Possible to alter items with the handler
if (onChange)
onChange(newItems);
// Update state
setItems(newItems);
};
// Drag event handlers
function handleDragStart(event) {
const { active } = event;
setActiveId(active.id);
}
function handleDragEnd(event) {
const { active, over } = event;
if (over && active.id !== over.id) {
// Indices
const oldIndex = items.findIndex((item) => item.id === active.id);
const newIndex = items.findIndex((item) => item.id === over.id);
// Clone
const newItems = [...items];
// Removed item
const [removed] = newItems.splice(oldIndex, 1);
// Insert to the destination index
newItems.splice(newIndex, 0, removed);
changeItems(newItems);
// Drag end handler
if (onDragEnd)
onDragEnd(newItems);
}
setActiveId(undefined);
}
// Methods
React.useImperativeHandle(mRef, () => {
return {
addItem(newItem) {
// Existence check
if (items.some((item) => item[labelField] === newItem[labelField])) {
return false;
}
// Clone
const newItems = [newItem, ...items];
// Update the state
changeItems(newItems);
return true;
},
addItems(inputItems) {
// Clone
const newItems = [...items];
// Insert items
inputItems.forEach((newItem) => {
// Existence check
if (newItems.some((item) => item[labelField] === newItem[labelField])) {
return;
}
newItems.push(newItem);
});
// Update the state
changeItems(newItems);
return newItems.length - items.length;
},
editItem(newItem, index) {
// Existence check
const newIndex = items.findIndex((item) => item[labelField] === newItem[labelField]);
if (newIndex >= 0 && newIndex !== index) {
// Label field is the same with a different item
return false;
}
// Clone
const newItems = [...items];
// Remove the item
newItems.splice(index, 1, newItem);
// Update the state
changeItems(newItems);
return true;
},
deleteItem(index) {
// Clone
const newItems = [...items];
// Remove the item
newItems.splice(index, 1);
// Update the state
changeItems(newItems);
}
};
}, [items]);
React.useEffect(() => {
setItems(props.items);
}, [props.items]);
return (_jsx(DndContext, { onDragStart: handleDragStart, onDragEnd: handleDragEnd, children: _jsx(SortableContext, { items: items, strategy: verticalListSortingStrategy, children: items.map((item, index) => {
const id = item[keyField];
return (_jsx(SortableItem, { id: id, style: getItemStyle(index, id === activeId), itemRenderer: (nodeRef, actionNodeRef) => itemRenderer(item, index, nodeRef, actionNodeRef) }, id));
}) }) }));
}