UNPKG

@asup/tree-of-nodes

Version:
561 lines (516 loc) 26 kB
require("./main.css"); var $gTuX4$reactjsxruntime = require("react/jsx-runtime"); var $gTuX4$asupcontextmenu = require("@asup/context-menu"); var $gTuX4$react = require("react"); var $gTuX4$reactbootstrapicons = require("react-bootstrap-icons"); var $gTuX4$reactbootstrap = require("react-bootstrap"); function $parcel$exportWildcard(dest, source) { Object.keys(source).forEach(function(key) { if (key === 'default' || key === '__esModule' || Object.prototype.hasOwnProperty.call(dest, key)) { return; } Object.defineProperty(dest, key, { enumerable: true, get: function get() { return source[key]; } }); }); return dest; } function $parcel$export(e, n, v, s) { Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); } function $parcel$interopDefault(a) { return a && a.__esModule ? a.default : a; } var $a68bd8a6c0fd98c2$exports = {}; $parcel$export($a68bd8a6c0fd98c2$exports, "TreeNode", function () { return $a56aac35d4408806$export$2eba8ec3a333fdbb; }); $parcel$export($a68bd8a6c0fd98c2$exports, "TreeOfNodes", function () { return $9becaaec3a803ae7$export$5580fff3e08a8be5; }); $parcel$export($a68bd8a6c0fd98c2$exports, "WordEntry", function () { return $176d21a51def1fce$export$14f190ac910bde69; }); const $580f9b3e262282c9$export$c6fd3ab3f44300d0 = (id, included, hierarchyNodes)=>{ const processIds = Array.isArray(id) ? id : [ id ]; const current = processIds.map((i)=>hierarchyNodes.find((h)=>h.id === i)).filter((h)=>h !== undefined); if (current.length === 0) return included; const parents = current.map((h)=>h.parentId).map((pid)=>hierarchyNodes.find((h)=>pid === h.id)).filter((p)=>p !== undefined); if (parents.length === 0) return included; else return $580f9b3e262282c9$export$c6fd3ab3f44300d0(parents.map((p)=>p.id), [ ...included, ...parents.filter((p)=>!included.includes(p)) ], hierarchyNodes); }; const $a19ef65643ae39e0$export$bd923365b402cb04 = (id, hierarchyNodes)=>{ const processIds = Array.isArray(id) ? id : [ id ]; const newChildren = hierarchyNodes.filter((h)=>h.parentId !== undefined && processIds.includes(h.parentId) && !processIds.includes(h.id)).map((h)=>h.id); return newChildren.length === 0 ? processIds : $a19ef65643ae39e0$export$bd923365b402cb04([ ...processIds, ...newChildren ], hierarchyNodes); }; const $ff9cca1fe8f6b24e$export$29ec378200e05207 = (0, $gTuX4$react.createContext)(undefined); const $176d21a51def1fce$export$14f190ac910bde69 = /*#__PURE__*/ (0, ($parcel$interopDefault($gTuX4$react))).forwardRef(({ id: id, value: value, editing: editing, saving: saving, setValue: setValue, sendEscape: sendEscape, style: style, spellCheck: spellCheck = "true" }, ref)=>{ const [currentValue, setCurrentValue] = (0, $gTuX4$react.useState)(value !== null && value !== void 0 ? value : ""); (0, $gTuX4$react.useEffect)(()=>{ setCurrentValue(value !== null && value !== void 0 ? value : ""); }, [ value ]); const returnData = (0, $gTuX4$react.useCallback)(()=>{ setValue === null || setValue === void 0 ? void 0 : setValue(currentValue); }, [ currentValue, setValue ]); const keyPress = (0, $gTuX4$react.useCallback)((e)=>{ if (e.code === "Escape") { setCurrentValue(value !== null && value !== void 0 ? value : ""); sendEscape === null || sendEscape === void 0 ? void 0 : sendEscape(); } else if (e.code === "Enter") returnData(); }, [ returnData, sendEscape, value ]); // Add window onMouseDown event to stop events when editing (0, $gTuX4$react.useEffect)(()=>{ const handleMouseDown = (e)=>{ const target = e.target; if (editing && target.id !== `${id}` && target.id !== `${id}-holder` && target.id !== `${id}-spinner` && target.className !== "ton-rename") { e.preventDefault(); e.stopPropagation(); returnData(); } }; window.addEventListener("mousedown", handleMouseDown); return ()=>{ window.removeEventListener("mousedown", handleMouseDown); }; }, [ editing, id, returnData ]); return !editing ? /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("span", { className: "ton-label-span", style: style, id: `${id}`, children: value ? value : /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $gTuX4$reactjsxruntime.Fragment), { children: "\xa0" }) }) : /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("div", { style: style, id: `${id}-holder`, className: "ton-rename-holder", children: [ saving && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $gTuX4$reactbootstrap.Spinner), { id: `${id}-spinner`, size: "sm", animation: "border" }), /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("input", { autoFocus: true, spellCheck: spellCheck, id: String(id), ref: ref, type: "text", className: "ton-rename", value: currentValue, disabled: saving, onChange: (e)=>setCurrentValue(e.currentTarget.value), onBlur: returnData, onKeyDownCapture: keyPress }) ] }); }); $176d21a51def1fce$export$14f190ac910bde69.displayName = "WordEntry"; const $a56aac35d4408806$export$2eba8ec3a333fdbb = ({ id: id, canRemove: canRemove, canRename: canRename, canAddChildren: canAddChildren, canRemoveChildren: canRemoveChildren, canRenameChildren: canRenameChildren })=>{ // Contexts const treeContext = (0, $gTuX4$react.useContext)((0, $ff9cca1fe8f6b24e$export$29ec378200e05207)); // Node information const thisNode = (0, $gTuX4$react.useMemo)(()=>treeContext === null || treeContext === void 0 ? void 0 : treeContext.nodeList.find((n)=>n.id === id), [ id, treeContext === null || treeContext === void 0 ? void 0 : treeContext.nodeList ]); const childNodes = (0, $gTuX4$react.useMemo)(()=>treeContext === null || treeContext === void 0 ? void 0 : treeContext.nodeList.filter((n)=>n.parentId === id), [ id, treeContext === null || treeContext === void 0 ? void 0 : treeContext.nodeList ]); const descendents = (0, $gTuX4$react.useMemo)(()=>{ var _treeContext_nodeList; return (0, $a19ef65643ae39e0$export$bd923365b402cb04)(id, (_treeContext_nodeList = treeContext === null || treeContext === void 0 ? void 0 : treeContext.nodeList) !== null && _treeContext_nodeList !== void 0 ? _treeContext_nodeList : []); }, [ id, treeContext ]); // State const [error, setError] = (0, $gTuX4$react.useState)(false); const [errorText, setErrorText] = (0, $gTuX4$react.useState)(""); const expanded = (0, $gTuX4$react.useMemo)(()=>{ var _treeContext_expandedNodes_findIndex; return ((_treeContext_expandedNodes_findIndex = treeContext === null || treeContext === void 0 ? void 0 : treeContext.expandedNodes.findIndex((e)=>e === id)) !== null && _treeContext_expandedNodes_findIndex !== void 0 ? _treeContext_expandedNodes_findIndex : -1) > -1; }, [ id, treeContext === null || treeContext === void 0 ? void 0 : treeContext.expandedNodes ]); // Ensures that child nodes are drawn before they are expanded const [hasRenderedClosed, setHasRenderedClosed] = (0, $gTuX4$react.useState)(childNodes !== undefined && childNodes.length > 0); (0, $gTuX4$react.useEffect)(()=>{ if (childNodes && childNodes.length > 0 && !hasRenderedClosed) setHasRenderedClosed(true); }, [ childNodes, hasRenderedClosed ]); // Checkbox const checkRef = (0, $gTuX4$react.useRef)(null); (0, $gTuX4$react.useEffect)(()=>{ if (checkRef.current) { if (treeContext === null || treeContext === void 0 ? void 0 : treeContext.selected.includes(id)) { checkRef.current.checked = true; checkRef.current.indeterminate = false; } else if (descendents.some((d)=>treeContext === null || treeContext === void 0 ? void 0 : treeContext.selected.includes(d))) { checkRef.current.checked = false; checkRef.current.indeterminate = true; } else { checkRef.current.checked = false; checkRef.current.indeterminate = false; } } }, [ descendents, id, treeContext === null || treeContext === void 0 ? void 0 : treeContext.selected ]); // Apply selected border const currentBorder = (0, $gTuX4$react.useMemo)(()=>{ return (treeContext === null || treeContext === void 0 ? void 0 : treeContext.selected.includes(id)) ? "1px solid black" : ""; }, [ id, treeContext === null || treeContext === void 0 ? void 0 : treeContext.selected ]); const nodeColour = (0, $gTuX4$react.useMemo)(()=>{ if (treeContext && treeContext.selected) { const anc = (0, $580f9b3e262282c9$export$c6fd3ab3f44300d0)(treeContext.selected, [], treeContext === null || treeContext === void 0 ? void 0 : treeContext.nodeList).map((n)=>n.id); if ([ ...anc, treeContext.selected ].includes(id)) return treeContext.nodeHighlight; } return; }, [ id, treeContext ]); // New node parameters const newNameRef = (0, $gTuX4$react.useRef)(null); const [showNewNode, setShowNewNode] = (0, $gTuX4$react.useState)(false); const [savingNewNode, setSavingNewNode] = (0, $gTuX4$react.useState)(false); // Rename parameters const currentNameRef = (0, $gTuX4$react.useRef)(null); const [renaming, setRenaming] = (0, $gTuX4$react.useState)(false); const [updatingNode, setUpdatingNode] = (0, $gTuX4$react.useState)(false); // Context functions const handleReturn = (0, $gTuX4$react.useCallback)((ret)=>{ if (!ret.success) { setError(true); var _ret_ErrorText; setErrorText((_ret_ErrorText = ret.ErrorText) !== null && _ret_ErrorText !== void 0 ? _ret_ErrorText : "An unknown error has occured"); } else { setError(false); setErrorText(""); } }, []); const confirmNewNode = (0, $gTuX4$react.useCallback)(async (label)=>{ setSavingNewNode(true); if (treeContext === null || treeContext === void 0 ? void 0 : treeContext.onAddChild) handleReturn(await treeContext.onAddChild(id, label)); setSavingNewNode(false); setShowNewNode(false); }, [ handleReturn, id, treeContext ]); const renameNode = (0, $gTuX4$react.useCallback)(async (newLabel)=>{ setRenaming(false); if (treeContext === null || treeContext === void 0 ? void 0 : treeContext.onRename) { setUpdatingNode(true); handleReturn(await treeContext.onRename(id, newLabel)); setUpdatingNode(false); } }, [ handleReturn, id, treeContext ]); const deleteThis = (0, $gTuX4$react.useCallback)(async ()=>{ if (treeContext === null || treeContext === void 0 ? void 0 : treeContext.onRemove) { setUpdatingNode(true); handleReturn(await treeContext.onRemove(id)); setUpdatingNode(false); } }, [ handleReturn, id, treeContext ]); // Context actions const addChild = (0, $gTuX4$react.useCallback)(()=>{ var _treeContext_handleExpandClick; setShowNewNode(true); treeContext === null || treeContext === void 0 ? void 0 : (_treeContext_handleExpandClick = treeContext.handleExpandClick) === null || _treeContext_handleExpandClick === void 0 ? void 0 : _treeContext_handleExpandClick.call(treeContext, id, true); }, [ id, treeContext ]); (0, $gTuX4$react.useEffect)(()=>{ if (showNewNode === true && newNameRef.current) newNameRef.current.focus(); }, [ showNewNode ]); const renameThis = (0, $gTuX4$react.useCallback)(()=>{ var _treeContext_handleSelect; setRenaming(true); treeContext === null || treeContext === void 0 ? void 0 : (_treeContext_handleSelect = treeContext.handleSelect) === null || _treeContext_handleSelect === void 0 ? void 0 : _treeContext_handleSelect.call(treeContext, id); }, [ id, treeContext ]); // Context menu const menuItems = (0, $gTuX4$react.useMemo)(()=>{ const menuItems = []; if (canAddChildren) menuItems.push({ label: "Add", action: addChild }); if (canRename) menuItems.push({ label: "Rename", action: renameThis }); if (canRemove && (childNodes === undefined || childNodes.length === 0)) menuItems.push({ label: "Delete", action: deleteThis }); return menuItems; }, [ addChild, canAddChildren, canRemove, canRename, childNodes, deleteThis, renameThis ]); // Return node return !treeContext ? null : /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)((0, $gTuX4$reactjsxruntime.Fragment), { children: [ /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $gTuX4$asupcontextmenu.ContextMenuHandler), { menuItems: menuItems, style: { display: "inline-block", width: "100%" }, children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", { id: `${treeContext.id}-treenode-${id}`, className: "treenode", children: error ? /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)((0, $gTuX4$reactjsxruntime.Fragment), { children: [ /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $gTuX4$reactbootstrapicons.ExclamationCircleFill), { color: "var(--bs-danger)" }), " ", errorText ] }) : /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsxs)("div", { className: "ton-node", children: [ treeContext.showCheckBox && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("input", { ref: checkRef, type: "checkbox", role: "checkbox", className: "ton-checkbox", id: `${treeContext.id}-treenode-checkbox-${id}`, onClick: ()=>{ var _treeContext_handleSelect; return (_treeContext_handleSelect = treeContext.handleSelect) === null || _treeContext_handleSelect === void 0 ? void 0 : _treeContext_handleSelect.call(treeContext, descendents); } }), childNodes && childNodes.length > 0 ? !expanded ? /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $gTuX4$reactbootstrapicons.CaretRightFill), { id: `${treeContext.id}-treenode-caret-${id}`, style: { width: "16px", height: "16px" }, className: "ton-expander", role: "button", color: nodeColour, "aria-expanded": false, "aria-label": "Expander", onClick: ()=>treeContext.handleExpandClick(id) }) : /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $gTuX4$reactbootstrapicons.CaretDownFill), { id: `${treeContext.id}-treenode-caret-${id}`, className: "ton-expander", role: "button", "aria-expanded": true, "aria-label": "Expander", color: nodeColour, onClick: ()=>treeContext.handleExpandClick(id) }) : /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $gTuX4$reactbootstrapicons.CaretRight), { id: `${treeContext.id}-treenode-caret-${id}`, className: "ton-expander", role: "button", color: nodeColour, "aria-expanded": false, "aria-label": "Disabled expander", onClick: ()=>{ var _treeContext_handleSelect; return (_treeContext_handleSelect = treeContext.handleSelect) === null || _treeContext_handleSelect === void 0 ? void 0 : _treeContext_handleSelect.call(treeContext, id); } }), thisNode && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", { className: "ton-label", style: { width: `calc(100% - ${treeContext.showCheckBox ? "32px" : "16px"})` }, onContextMenuCapture: ()=>{ var _treeContext_handleSelect; return (_treeContext_handleSelect = treeContext.handleSelect) === null || _treeContext_handleSelect === void 0 ? void 0 : _treeContext_handleSelect.call(treeContext, id); }, onClickCapture: ()=>{ var _treeContext_handleSelect; if (!treeContext.expandedNodes.includes(id)) treeContext.handleExpandClick(id); (_treeContext_handleSelect = treeContext.handleSelect) === null || _treeContext_handleSelect === void 0 ? void 0 : _treeContext_handleSelect.call(treeContext, id); }, onFocusCapture: ()=>{ var _treeContext_handleSelect; return (_treeContext_handleSelect = treeContext.handleSelect) === null || _treeContext_handleSelect === void 0 ? void 0 : _treeContext_handleSelect.call(treeContext, id); }, children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $176d21a51def1fce$export$14f190ac910bde69), { id: `${treeContext.id}-treenode-entry-${id}`, ref: currentNameRef, value: thisNode.label, editing: renaming, saving: updatingNode, setValue: (ret)=>renameNode(ret), sendEscape: ()=>setRenaming(false), style: { border: currentBorder, margin: currentBorder === "" ? "1px" : "", backgroundColor: currentBorder === "" ? "" : treeContext.textHighlight }, spellCheck: treeContext.spellCheck }) }) ] }) }) }), childNodes && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", { className: `ton-collapsible-wrapper ${expanded && hasRenderedClosed && childNodes.length > 0 ? "" : "collapsed"}`, children: childNodes.length > 0 && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", { className: "ton-collapsible", children: childNodes.map((h)=>/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("span", { id: `${treeContext.id}-treenode-child-${h.id}`, className: "ton-child", children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)($a56aac35d4408806$export$2eba8ec3a333fdbb, { id: h.id, canRemove: canRemoveChildren, canRename: canRenameChildren, canAddChildren: canAddChildren, canRemoveChildren: canRemoveChildren, canRenameChildren: canRenameChildren }) }, h.id)) }) }), showNewNode && /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $176d21a51def1fce$export$14f190ac910bde69), { style: { marginLeft: "14px" }, id: `treenode-new-${id}`, ref: newNameRef, editing: true, setValue: (ret)=>confirmNewNode(ret), saving: savingNewNode, sendEscape: ()=>setShowNewNode(false), spellCheck: treeContext.spellCheck }) ] }); }; $a56aac35d4408806$export$2eba8ec3a333fdbb.displayName = "TreeNode"; const $f31429c9cc6d3bce$export$40c47a7ac5f85aba = (nodeList, selected, expandedNodes)=>{ return [ ...expandedNodes, ...(0, $580f9b3e262282c9$export$c6fd3ab3f44300d0)(selected, [], nodeList).map((n)=>n.id).filter((k)=>!expandedNodes.includes(k)) ].sort((a, b)=>`${a}`.localeCompare(`${b}`)); }; const $9becaaec3a803ae7$export$5580fff3e08a8be5 = ({ id: id, nodeList: nodeList, roots: roots, selected: selected = [], showCheckBox: showCheckBox = false, handleSelect: handleSelect, onAdd: onAdd, onRename: onRename, onRemove: onRemove, canRemoveRoot: canRemoveRoot = false, canRenameRoot: canRenameRoot = false, canAddChildren: canAddChildren = false, canRemoveChildren: canRemoveChildren = false, canRenameChildren: canRenameChildren = false, nodeHighlight: nodeHighlight = "red", textHighlight: textHighlight = "rgba(255, 0, 0, 0.2)", spellCheck: spellCheck = "true" })=>{ const [expandedNodes, setExpandedNodes] = (0, $gTuX4$react.useState)([]); const selectedArray = (0, $gTuX4$react.useMemo)(()=>Array.isArray(selected) ? selected : [ selected ], [ selected ]); (0, $gTuX4$react.useEffect)(()=>{ if (selectedArray.length > 0) { // Check all nodes are showing that should be const shouldExpand = (0, $f31429c9cc6d3bce$export$40c47a7ac5f85aba)(nodeList, selectedArray, expandedNodes); if (shouldExpand.filter((n)=>!expandedNodes.includes(n)).length > 0) setExpandedNodes(shouldExpand); } }, [ expandedNodes, nodeList, selectedArray ]); // Change expansion and update contexts const changeExpand = (0, $gTuX4$react.useCallback)((eKey, force)=>{ const newExpandedNodes = [ ...expandedNodes ]; const ix = newExpandedNodes.findIndex((nKey)=>nKey === eKey); if (ix === -1 && force === undefined || force === true) newExpandedNodes.push(eKey); else newExpandedNodes.splice(ix, 1); setExpandedNodes(newExpandedNodes); }, [ expandedNodes ]); return /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)("div", { id: id, className: "tree-of-nodes", children: /*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $ff9cca1fe8f6b24e$export$29ec378200e05207).Provider, { value: { id: id, nodeList: nodeList, selected: selectedArray, showCheckBox: showCheckBox, handleSelect: handleSelect, expandedNodes: expandedNodes, handleExpandClick: (r, f)=>changeExpand(r, f), onAddChild: onAdd, onRename: onRename, onRemove: onRemove, nodeHighlight: nodeHighlight, textHighlight: textHighlight, spellCheck: spellCheck }, children: roots.map((r)=>/*#__PURE__*/ (0, $gTuX4$reactjsxruntime.jsx)((0, $a56aac35d4408806$export$2eba8ec3a333fdbb), { id: r, canRemove: canRemoveRoot, canAddChildren: canAddChildren, canRename: canRenameRoot, canRemoveChildren: canRemoveChildren, canRenameChildren: canRenameChildren }, r)) }) }); }; $9becaaec3a803ae7$export$5580fff3e08a8be5.displayName = "TreeOfNodes"; var $f8937e88ee74204e$exports = {}; $parcel$export($f8937e88ee74204e$exports, "getParents", function () { return $580f9b3e262282c9$export$c6fd3ab3f44300d0; }); $parcel$exportWildcard(module.exports, $a68bd8a6c0fd98c2$exports); $parcel$exportWildcard(module.exports, $f8937e88ee74204e$exports); //# sourceMappingURL=main.js.map