UNPKG

@etsoo/materialui

Version:

TypeScript Material-UI Implementation

239 lines (238 loc) 9.45 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DnDItemStyle = void 0; exports.DnDList = DnDList; const jsx_runtime_1 = require("react/jsx-runtime"); const Skeleton_1 = __importDefault(require("@mui/material/Skeleton")); const styles_1 = require("@mui/material/styles"); const react_1 = __importDefault(require("react")); function SortableItem(props) { // Destruct const { id, useSortableType, CSSType, itemRenderer, style = {} } = props; // Use sortable const { attributes, listeners, setNodeRef, transform, transition, setActivatorNodeRef } = useSortableType({ id }); const allStyle = { ...style, transform: CSSType.Transform.toString(transform), transition }; const nodeRef = { style: allStyle, ref: setNodeRef, ...attributes }; const actionNodeRef = { ...listeners, ref: setActivatorNodeRef }; return itemRenderer(nodeRef, actionNodeRef); } /** * DnD item default style * @param index Item index * @param isDragging Is dragging * @param theme Theme * @returns Style */ const DnDItemStyle = (index, isDragging, theme) => ({ padding: theme.spacing(1), zIndex: isDragging ? 1 : "auto", background: isDragging ? theme.palette.primary.light : index % 2 === 0 ? theme.palette.grey[100] : theme.palette.grey[50] }); exports.DnDItemStyle = DnDItemStyle; /** * DnD (Drag and Drop) sortable list * @param props Props * @returns Component */ function DnDList(props) { // Destruct const { componentProps, height = 360, itemRenderer, labelField, mRef, sortingStrategy, onChange, onFormChange, onDragEnd } = props; const Component = props.component || react_1.default.Fragment; // Theme const theme = (0, styles_1.useTheme)(); // States const [items, setItems] = react_1.default.useState([]); const [activeId, setActiveId] = react_1.default.useState(); react_1.default.useEffect(() => { setItems(props.items); }, [props.items]); const doFormChange = react_1.default.useCallback((newItems) => { if (onFormChange) { const locals = Array.isArray(newItems) ? newItems : items; onFormChange(locals); } }, [items, onFormChange]); const changeItems = react_1.default.useCallback((newItems) => { // Possible to alter items with the handler if (onChange) onChange(newItems); doFormChange(newItems); // Update state setItems(newItems); }, [onChange, doFormChange]); // Methods react_1.default.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); }, getItems() { return items; } }; }, [items, labelField, changeItems]); // Dynamic import library const [dnd, setDnd] = react_1.default.useState(); react_1.default.useEffect(() => { Promise.all([ import("@dnd-kit/core"), import("@dnd-kit/sortable"), import("@dnd-kit/utilities") ]).then(([{ DndContext }, { SortableContext, useSortable, rectSortingStrategy, rectSwappingStrategy, horizontalListSortingStrategy, verticalListSortingStrategy }, { CSS }]) => { setDnd([ DndContext, SortableContext, useSortable, rectSortingStrategy, rectSwappingStrategy, horizontalListSortingStrategy, verticalListSortingStrategy, CSS ]); }); }, []); const setupDiv = (div, clearup = false) => { // Inputs div .querySelectorAll("input") .forEach((input) => clearup ? input.removeEventListener("change", doFormChange) : input.addEventListener("change", doFormChange)); // Textareas div .querySelectorAll("textarea") .forEach((input) => clearup ? input.removeEventListener("change", doFormChange) : input.addEventListener("change", doFormChange)); // Select div .querySelectorAll("select") .forEach((input) => clearup ? input.removeEventListener("change", doFormChange) : input.addEventListener("change", doFormChange)); }; const divRef = react_1.default.useRef(); if (dnd == null) { return (0, jsx_runtime_1.jsx)(Skeleton_1.default, { variant: "rectangular", width: "100%", height: height }); } const [DndContextType, SortableContextType, useSortableType, rectSortingStrategyType, rectSwappingStrategyType, horizontalListSortingStrategyType, verticalListSortingStrategyType, CSSType] = dnd; const strategy = typeof sortingStrategy === "function" ? sortingStrategy() : sortingStrategy === "rect" ? rectSortingStrategyType : sortingStrategy === "rectSwapping" ? rectSwappingStrategyType : sortingStrategy === "horizontal" ? horizontalListSortingStrategyType : sortingStrategy === "vertical" ? verticalListSortingStrategyType : undefined; let getItemStyle = props.getItemStyle; if (getItemStyle == null) { getItemStyle = (index, isDragging) => (0, exports.DnDItemStyle)(index, isDragging, theme); } // 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); } const children = ((0, jsx_runtime_1.jsx)(DndContextType, { onDragStart: handleDragStart, onDragEnd: handleDragEnd, children: (0, jsx_runtime_1.jsx)(SortableContextType, { items: items, strategy: strategy, children: (0, jsx_runtime_1.jsx)(Component, { ...componentProps, children: items.map((item, index) => { const id = item.id; return ((0, jsx_runtime_1.jsx)(SortableItem, { id: id, useSortableType: useSortableType, CSSType: CSSType, style: getItemStyle(index, id === activeId), itemRenderer: (nodeRef, actionNodeRef) => itemRenderer(item, index, nodeRef, actionNodeRef) }, id)); }) }) }) })); if (onFormChange) { return ((0, jsx_runtime_1.jsx)("div", { style: { width: "100%" }, ref: (div) => { if (div && divRef.current != div) { if (divRef.current) { setupDiv(divRef.current, true); } divRef.current = div; setupDiv(div); } }, children: children })); } return children; }