|
|
import React, { useState, useEffect } from 'react';
|
|
|
import { Handle, NodeProps, Position } from 'reactflow';
|
|
|
import './EditableColorNode.css';
|
|
|
import * as MdIcons from 'react-icons/md';
|
|
|
|
|
|
const icons = MdIcons as Record<string, React.ComponentType<any>>;
|
|
|
|
|
|
const EditableColorNode: React.FC<NodeProps> = ({ id, data, selected, isConnectable, ...props }) => {
|
|
|
const [editing, setEditing] = useState(false);
|
|
|
const [label, setLabel] = useState(data.label || '');
|
|
|
const [nodeStyle, setNodeStyle] = useState({
|
|
|
backgroundColor: data.bgColor || '#fff',
|
|
|
color: data.textColor || '#222',
|
|
|
});
|
|
|
|
|
|
useEffect(() => {
|
|
|
setNodeStyle({
|
|
|
backgroundColor: data.bgColor || '#fff',
|
|
|
color: data.textColor || '#222',
|
|
|
});
|
|
|
}, [data.bgColor, data.textColor]);
|
|
|
|
|
|
|
|
|
const handleLabelChange = (e: React.ChangeEvent<HTMLInputElement>) => setLabel(e.target.value);
|
|
|
const handleLabelBlur = () => {
|
|
|
setEditing(false);
|
|
|
if (data.onChange) data.onChange(id, { ...data, label });
|
|
|
};
|
|
|
const handleLabelKeyDown = (e: React.KeyboardEvent) => {
|
|
|
if (e.key === 'Enter') handleLabelBlur();
|
|
|
};
|
|
|
|
|
|
|
|
|
const handleDrop = (e: React.DragEvent) => {
|
|
|
e.preventDefault();
|
|
|
const iconName = e.dataTransfer.getData('icon');
|
|
|
if (iconName && data.onChange) {
|
|
|
data.onChange(id, { ...data, icon: iconName });
|
|
|
}
|
|
|
};
|
|
|
const handleDragOver = (e: React.DragEvent) => e.preventDefault();
|
|
|
|
|
|
|
|
|
let IconComponent = null;
|
|
|
if (data.icon && icons[data.icon]) {
|
|
|
IconComponent = React.createElement(icons[data.icon], { size: 24, style: { marginBottom: 4 } });
|
|
|
}
|
|
|
|
|
|
return (
|
|
|
<div
|
|
|
className={`editable-color-node ${selected ? 'selected' : ''}`}
|
|
|
style={{
|
|
|
...nodeStyle,
|
|
|
boxShadow: selected ? '0 0 0 3px #007bff' : undefined,
|
|
|
border: selected ? '2px solid #007bff' : '1px solid #ccc',
|
|
|
transition: 'box-shadow 0.2s, border 0.2s',
|
|
|
}}
|
|
|
onDrop={handleDrop}
|
|
|
onDragOver={handleDragOver}
|
|
|
>
|
|
|
<Handle type="target" position={Position.Top} isConnectable={isConnectable} />
|
|
|
{IconComponent && <div style={{ display: 'flex', justifyContent: 'center' }}>{IconComponent}</div>}
|
|
|
<div
|
|
|
className="editable-color-node-label"
|
|
|
title={label}
|
|
|
style={{ color: data.textColor || '#222' }}
|
|
|
>
|
|
|
{label}
|
|
|
</div>
|
|
|
<Handle type="source" position={Position.Bottom} isConnectable={isConnectable} />
|
|
|
</div>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
export default EditableColorNode; |