| 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; |