UNPKG

@etsoo/react

Version:

TypeScript ReactJs UI Independent Framework

131 lines (130 loc) 4.83 kB
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)); }) }) })); }