@ducor/react
Version:
admin template ui interface
156 lines (155 loc) • 7.72 kB
JavaScript
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React, { createContext, memo, useContext, useEffect, useMemo, useState, } from "react";
import _ from "lodash";
import { twJoin, twMerge } from "tailwind-merge";
import { array_swap, uuidv4 } from "@ducor/helpers";
import Button from "../button";
import Flex from "../flex";
import { FormContext } from ".";
var ArrayFieldContext = createContext(undefined);
export var ArrayFieldItemContext = createContext(undefined);
/*
* @see https://teslamotors.github.io/informed/getting-started/array-field
*/
var ArrayField = function (_a) {
var _b = _a.name, name = _b === void 0 ? "" : _b, children = _a.children, appendItem = _a.appendItem;
// react nodes[ ]
var _c = useState([]), chilItems = _c[0], setChildItems = _c[1];
useEffect(function () {
setChildItems(children ? __spreadArray([], children, true) : []);
}, [children]);
var _d = useState(null), activeIndex = _d[0], setActiveIndex = _d[1];
var add = function () {
if (React.isValidElement(appendItem)) {
// Clone the React element and update its key and index
var newElement_1 = React.cloneElement(appendItem, {
key: chilItems.length,
index: chilItems.length, // Valid now
});
// Add the cloned element to the state
setChildItems(function (prevItems) { return __spreadArray(__spreadArray([], prevItems, true), [newElement_1], false); });
}
};
var hasField = function (key) {
return chilItems[key] !== undefined;
};
var remove = function (key) {
setChildItems(function (prevItems) { return __spreadArray([], __spreadArray([], prevItems.filter(function (ch, k) {
return React.isValidElement(ch) && k !== key;
}), true).map(function (child, key) {
return React.cloneElement(child, {
key: key,
index: key, // Valid now
});
}), true); });
};
var reset = function () {
setChildItems(children ? __spreadArray([], children, true) : []);
};
var swap = function (sourceIndex, targetIndex) {
setChildItems(function (prevCards) {
return array_swap(prevCards, sourceIndex, targetIndex);
});
};
useEffect(function () {
return function () {
setChildItems([]);
};
}, []);
return (_jsxs(ArrayFieldContext.Provider, { value: { name: name, activeIndex: activeIndex, setActiveIndex: setActiveIndex, add: add, remove: remove, reset: reset, swap: swap }, children: [chilItems, _jsxs(Flex, { gap: 2, children: [_jsx(Button, { size: 'sm', type: 'button', variant: 'success', onClick: function () { return add(); }, children: "Add" }), _jsx(Button, { size: 'sm', variant: 'black', type: 'button', onClick: function () { return reset(); }, children: "reset" })] })] }));
};
var Item = memo(function (_a) {
var children = _a.children, title = _a.title, index = _a.index;
var filedMap = useState(new Map())[0];
var _b = useField(), name = _b.name, activeIndex = _b.activeIndex, setActiveIndex = _b.setActiveIndex, remove = _b.remove, swap = _b.swap;
// Create a debounced version of the click handler
var handleClick = React.useMemo(function () {
var debounced = _.debounce(function () {
setActiveIndex(activeIndex === index ? null : index);
}, 300);
return Object.assign(debounced, {
cancel: debounced.cancel.bind(debounced),
});
}, [activeIndex, index, setActiveIndex]);
// Create a debounced version of the remove handler
var handleRemove = React.useMemo(function () {
var debounced = _.debounce(function () {
remove(index);
}, 300);
return Object.assign(debounced, {
cancel: debounced.cancel.bind(debounced),
});
}, [index, remove]);
// Example usage to clear/cancel debounce
React.useEffect(function () {
return function () {
handleClick.cancel();
handleRemove.cancel();
};
}, [handleClick, handleRemove]);
var isActive = activeIndex === index;
var value = {
isActive: isActive,
filedMap: filedMap,
groupIndex: index,
groupName: name,
};
return (_jsx(ArrayFieldItemContext.Provider, { value: value, children: _jsxs("div", { className: 'border mb-1', children: [_jsxs(Flex, { justify: 'between', align: 'center', gap: 2, className: twMerge("p-2 bg-gray-200", isActive && "border-b"), children: [_jsxs(Flex, { gap: 2, children: [_jsx("div", { className: 'cursor-move mx-1', children: _jsx("i", { className: 'feather-move' }) }), _jsx("h5", { children: "[".concat(index, "] ").concat(title) })] }), _jsxs(Flex, { justify: 'end', align: 'center', gap: 1, children: [_jsx(Button, { size: 'sm', onClick: handleClick, children: _jsx("i", { className: isActive ? "feather-eye" : "feather-eye-off" }) }), _jsx(Button, { size: 'sm', variant: 'gray', onClick: handleClick, children: _jsx("i", { className: 'feather-copy' }) }), _jsx(Button, { size: 'sm', variant: 'gray', onClick: function () { return swap(index, index - 1); }, children: _jsx("i", { className: 'feather-chevron-down' }) }), _jsx(Button, { size: 'sm', variant: 'gray', onClick: function () { return swap(index, index + 1); }, children: _jsx("i", { className: 'feather-chevron-up' }) }), _jsx(Button, { size: 'sm', variant: 'danger', onClick: handleRemove, children: _jsx("i", { className: 'feather-trash' }) })] })] }), _jsx("div", { className: twJoin("m-2", isActive ? "" : "hidden"), children: children })] }) }));
});
var useField = function () {
var context = useContext(ArrayFieldContext);
if (!context) {
throw new Error("ArrayFieldContext not found");
}
return context;
};
export var useFieldName = function (name) {
var formCtx = useContext(FormContext);
var arrayFieldCtx = useContext(ArrayFieldItemContext);
if (typeof name !== "string") {
throw new Error("Invalid field name: ".concat(name));
}
// Use memo to ensure fieldMap isn't recreated on each render
var filedMap = useMemo(function () {
return (arrayFieldCtx === null || arrayFieldCtx === void 0 ? void 0 : arrayFieldCtx.filedMap) || new Map();
}, [arrayFieldCtx === null || arrayFieldCtx === void 0 ? void 0 : arrayFieldCtx.filedMap]);
var _a = arrayFieldCtx || {}, groupName = _a.groupName, groupIndex = _a.groupIndex;
var field = filedMap.get(name);
if (!field) {
var fieldName = groupIndex !== undefined ? "".concat(groupName, "[").concat(groupIndex, "].").concat(name) : name;
field = {
_uid: uuidv4(),
name: fieldName,
};
filedMap.set(name, field); // Store the new field in the map
}
/// form field context
if (!formCtx) {
// return {
// method: undefined,
// processing: false,
// isDirty: false,
// defaultValue: undefined,
// value: "",
// setValue: () => {},
// error: [],
// setError: () => {},
// };
}
return {
_uid: field._uid,
fieldName: field.name,
};
};
export default Object.assign(ArrayField, {
Item: Item,
});