UNPKG

@ichigo_san/graphing

Version:

A lightweight UML-style diagram editor built with React Flow and Tailwind CSS

472 lines (469 loc) 16.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _reactflow = require("reactflow"); var _gradientUtils = require("../utils/gradientUtils"); var _shadowUtils = require("../utils/shadowUtils"); var _transformUtils = require("../utils/transformUtils"); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } // Draw.io-style connection point styles const drawioHandleStyle = { background: '#3b82f6', border: '2px solid #ffffff', width: 14, height: 14, borderRadius: '50%', zIndex: 10, cursor: 'crosshair', transition: 'all 0.2s ease', opacity: 1, transform: 'scale(1)', boxShadow: '0 2px 4px rgba(0, 0, 0, 0.2)' }; const drawioHandleHoverStyle = { ...drawioHandleStyle, opacity: 1, transform: 'scale(1.3)', boxShadow: '0 0 0 4px rgba(59, 130, 246, 0.4)', background: '#2563eb' }; const drawioHandleActiveStyle = { ...drawioHandleHoverStyle, background: '#10b981', boxShadow: '0 0 0 4px rgba(16, 185, 129, 0.4)' }; const hiddenTargetHandleStyle = { opacity: 0, pointerEvents: 'none', width: 1, height: 1, background: 'transparent', border: 'none' }; const ContainerNode = ({ data, id, selected, isConnectable }) => { const [isEditing, setIsEditing] = (0, _react.useState)(false); const [label, setLabel] = (0, _react.useState)(data.label || 'Container'); const [hoveredHandle, setHoveredHandle] = (0, _react.useState)(null); const [activeHandle, setActiveHandle] = (0, _react.useState)(null); (0, _react.useEffect)(() => { setLabel(data.label || 'Container'); }, [data.label]); const inputRef = (0, _react.useRef)(null); const handleDoubleClick = (0, _react.useCallback)(e => { e.stopPropagation(); setIsEditing(true); }, []); const handleLabelSubmit = (0, _react.useCallback)(() => { setIsEditing(false); if (data.onLabelChange && label !== data.label) { data.onLabelChange(id, label); } }, [id, label, data]); const handleKeyDown = (0, _react.useCallback)(e => { if (e.key === 'Enter') { handleLabelSubmit(); } if (e.key === 'Escape') { setLabel(data.label); setIsEditing(false); } }, [handleLabelSubmit, data.label]); // Enhanced connection point handlers const handleConnectionPointMouseEnter = (0, _react.useCallback)(position => { setHoveredHandle(position); }, []); const handleConnectionPointMouseLeave = (0, _react.useCallback)(() => { setHoveredHandle(null); }, []); const getHandleStyle = (0, _react.useCallback)(position => { const baseStyle = { ...drawioHandleStyle }; // Always show handles more prominently when node is selected or hovered if (selected || hoveredHandle === 'node') { baseStyle.opacity = 1; baseStyle.transform = 'scale(1.1)'; } if (activeHandle === position) { return { ...baseStyle, ...drawioHandleActiveStyle }; } if (hoveredHandle === position) { return { ...baseStyle, ...drawioHandleHoverStyle }; } return baseStyle; }, [hoveredHandle, activeHandle, selected]); return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_reactflow.NodeResizer, { isVisible: selected, minWidth: 200, minHeight: 150, handleClassName: "w-2.5 h-2.5 bg-gray-500 rounded-full border-2 border-white", lineClassName: "border-2 border-dashed border-indigo-500 opacity-60", nodeWidth: data.width, nodeHeight: data.height }), /*#__PURE__*/_react.default.createElement("div", { style: { background: (0, _gradientUtils.ensureBackwardCompatibility)(data.background || data.contentColor || data.color || '#ffffff'), border: `${data.borderWidth || 2}px ${data.borderStyle || 'solid'} ${data.borderColor || '#ddd'}`, borderRadius: `${data.borderRadius || 8}px`, width: '100%', height: '100%', display: 'flex', flexDirection: 'column', cursor: 'move', transition: 'all 0.2s ease', boxShadow: selected ? `${(0, _shadowUtils.ensureShadowCompatibility)(data.boxShadow || 'none')}, 0 0 0 2px #2196F3` : (0, _shadowUtils.ensureShadowCompatibility)(data.boxShadow || 'none'), boxSizing: 'border-box', position: 'relative', fontSize: `${data.fontSize || 14}px`, opacity: data.opacity ?? 1, ...(0, _transformUtils.createTransformStyles)(data, 'container') }, onMouseEnter: () => setHoveredHandle('node'), onMouseLeave: () => setHoveredHandle(null) }, /*#__PURE__*/_react.default.createElement("div", { className: "border-b border-gray-300 dark:border-gray-600 text-gray-800 dark:text-gray-100 flex items-center gap-2", style: { background: (0, _gradientUtils.ensureBackwardCompatibility)(data.headerColor || '#f9f9f9'), height: `${data.headerHeight || 32}px`, padding: `${data.padding || 8}px`, borderRadius: `${(data.borderRadius || 8) - 1}px ${(data.borderRadius || 8) - 1}px 0 0`, fontSize: `${data.headerFontSize || 14}px`, minHeight: '24px', alignItems: 'center' }, onDoubleClick: handleDoubleClick }, data.icon && /*#__PURE__*/_react.default.createElement("span", { style: { fontSize: '14px' } }, data.icon), isEditing ? /*#__PURE__*/_react.default.createElement("input", { ref: inputRef, value: label, onChange: e => setLabel(e.target.value), onBlur: handleLabelSubmit, onKeyDown: handleKeyDown, autoFocus: true, style: { fontSize: `${data.headerFontSize || 14}px`, border: 'none', borderBottom: '2px solid #2196F3', outline: 'none', background: 'transparent', padding: '4px', width: '100%', color: data.textColor || '#000000' } }) : /*#__PURE__*/_react.default.createElement("span", { style: { fontSize: `${data.headerFontSize || 14}px`, fontWeight: 'bold', color: data.textColor || '#000000' } }, label)), /*#__PURE__*/_react.default.createElement("div", { style: { flex: 1, padding: `${data.padding || 8}px`, overflow: 'hidden', position: 'relative', fontSize: `${data.fontSize || 14}px` } }, data.description && /*#__PURE__*/_react.default.createElement("div", { style: { fontSize: `${Math.max((data.fontSize || 14) - 2, 10)}px`, color: data.textColor || '#666', marginBottom: '8px', lineHeight: '1.4' } }, data.description)), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Top, id: "top-left-source", style: { ...getHandleStyle('top'), left: '25%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('top'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Top, id: "top-center-source", style: { ...getHandleStyle('top'), left: '50%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('top'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Top, id: "top-right-source", style: { ...getHandleStyle('top'), left: '75%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('top'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Right, id: "right-top-source", style: { ...getHandleStyle('right'), top: '25%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('right'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Right, id: "right-center-source", style: { ...getHandleStyle('right'), top: '50%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('right'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Right, id: "right-bottom-source", style: { ...getHandleStyle('right'), top: '75%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('right'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Bottom, id: "bottom-left-source", style: { ...getHandleStyle('bottom'), left: '25%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('bottom'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Bottom, id: "bottom-center-source", style: { ...getHandleStyle('bottom'), left: '50%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('bottom'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Bottom, id: "bottom-right-source", style: { ...getHandleStyle('bottom'), left: '75%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('bottom'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Left, id: "left-top-source", style: { ...getHandleStyle('left'), top: '25%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('left'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Left, id: "left-center-source", style: { ...getHandleStyle('left'), top: '50%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('left'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "source", position: _reactflow.Position.Left, id: "left-bottom-source", style: { ...getHandleStyle('left'), top: '75%' }, isConnectable: isConnectable, className: "drawio-connection-point", onMouseEnter: () => handleConnectionPointMouseEnter('left'), onMouseLeave: handleConnectionPointMouseLeave }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Top, id: "top-left-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Top, id: "top-center-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Top, id: "top-right-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Right, id: "right-top-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Right, id: "right-center-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Right, id: "right-bottom-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Bottom, id: "bottom-left-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Bottom, id: "bottom-center-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Bottom, id: "bottom-right-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Left, id: "left-top-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Left, id: "left-center-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), /*#__PURE__*/_react.default.createElement(_reactflow.Handle, { type: "target", position: _reactflow.Position.Left, id: "left-bottom-target", style: hiddenTargetHandleStyle, isConnectable: isConnectable }), hoveredHandle === 'node' && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("div", { style: { position: 'absolute', top: '-6px', left: '50%', transform: 'translateX(-50%)', width: '12px', height: '12px', background: '#3b82f6', border: '2px solid #ffffff', borderRadius: '50%', opacity: 0.6, pointerEvents: 'none', zIndex: 5 } }), /*#__PURE__*/_react.default.createElement("div", { style: { position: 'absolute', right: '-6px', top: '50%', transform: 'translateY(-50%)', width: '12px', height: '12px', background: '#3b82f6', border: '2px solid #ffffff', borderRadius: '50%', opacity: 0.6, pointerEvents: 'none', zIndex: 5 } }), /*#__PURE__*/_react.default.createElement("div", { style: { position: 'absolute', bottom: '-6px', left: '50%', transform: 'translateX(-50%)', width: '12px', height: '12px', background: '#3b82f6', border: '2px solid #ffffff', borderRadius: '50%', opacity: 0.6, pointerEvents: 'none', zIndex: 5 } }), /*#__PURE__*/_react.default.createElement("div", { style: { position: 'absolute', left: '-6px', top: '50%', transform: 'translateY(-50%)', width: '12px', height: '12px', background: '#3b82f6', border: '2px solid #ffffff', borderRadius: '50%', opacity: 0.6, pointerEvents: 'none', zIndex: 5 } })))); }; var _default = exports.default = ContainerNode;