"use client" import type React from "react" import { useRef, useEffect, useState } from "react" import { Label } from "@/components/ui/label" import { Button } from "@/components/ui/button" import { Bold, Italic, List, ListOrdered, ImageIcon, Trash2 } from "lucide-react" interface RichTextEditorProps { value: string onChange: (value: string) => void placeholder?: string label?: string rows?: number } export function RichTextEditor({ value, onChange, placeholder, label, rows = 8 }: RichTextEditorProps) { const editorRef = useRef(null) const fileInputRef = useRef(null) const [isFocused, setIsFocused] = useState(false) const [isDragging, setIsDragging] = useState(false) const [selectedImage, setSelectedImage] = useState(null) // Sincronizar el valor inicial useEffect(() => { if (editorRef.current && editorRef.current.innerHTML !== value) { editorRef.current.innerHTML = value } }, [value]) useEffect(() => { const handleClick = (e: MouseEvent) => { const target = e.target as HTMLElement if (target.tagName === "IMG" && editorRef.current?.contains(target)) { setSelectedImage(target as HTMLImageElement) } else { setSelectedImage(null) } } document.addEventListener("click", handleClick) return () => document.removeEventListener("click", handleClick) }, []) // Manejar cambios en el contenido const handleInput = () => { if (editorRef.current) { onChange(editorRef.current.innerHTML) } } const insertImageFromFile = (file: File) => { if (file && file.type.startsWith("image/")) { const reader = new FileReader() reader.onload = (event) => { const img = document.createElement("img") img.src = event.target?.result as string img.style.maxWidth = "100%" img.style.height = "auto" img.style.margin = "8px 0" img.style.borderRadius = "4px" img.style.cursor = "pointer" img.className = "editor-image" img.setAttribute("data-resizable", "true") // Insertar la imagen en la posición del cursor const selection = window.getSelection() if (selection && selection.rangeCount > 0) { const range = selection.getRangeAt(0) range.deleteContents() range.insertNode(img) // Mover el cursor después de la imagen range.setStartAfter(img) range.setEndAfter(img) selection.removeAllRanges() selection.addRange(range) } else if (editorRef.current) { editorRef.current.appendChild(img) } handleInput() } reader.readAsDataURL(file) } } // Manejar paste de imágenes const handlePaste = (e: React.ClipboardEvent) => { const items = e.clipboardData?.items if (!items) return // Buscar imágenes en el clipboard for (let i = 0; i < items.length; i++) { const item = items[i] if (item.type.indexOf("image") !== -1) { e.preventDefault() const blob = item.getAsFile() if (blob) { insertImageFromFile(blob) } } } } const handleDragOver = (e: React.DragEvent) => { e.preventDefault() e.stopPropagation() setIsDragging(true) } const handleDragLeave = (e: React.DragEvent) => { e.preventDefault() e.stopPropagation() setIsDragging(false) } const handleDrop = (e: React.DragEvent) => { e.preventDefault() e.stopPropagation() setIsDragging(false) const files = e.dataTransfer?.files if (files && files.length > 0) { Array.from(files).forEach((file) => { if (file.type.startsWith("image/")) { insertImageFromFile(file) } }) } } // Comandos de formato const execCommand = (command: string, value?: string) => { document.execCommand(command, false, value) editorRef.current?.focus() handleInput() } const insertImage = () => { fileInputRef.current?.click() } const handleFileSelect = (e: React.ChangeEvent) => { const files = e.target.files if (files && files.length > 0) { Array.from(files).forEach((file) => { insertImageFromFile(file) }) } // Limpiar el input para permitir seleccionar el mismo archivo nuevamente e.target.value = "" } const resizeImage = (width: string) => { if (selectedImage) { selectedImage.style.width = width selectedImage.style.maxWidth = width selectedImage.style.height = "auto" handleInput() } } // Limpiar contenido const clearContent = () => { if (editorRef.current && confirm("¿Está seguro de que desea limpiar todo el contenido?")) { editorRef.current.innerHTML = "" onChange("") } } return (
{label && } {/* Barra de herramientas */}
{selectedImage && (
Tamaño de imagen:
)} {/* Editor */}
setIsFocused(true)} onBlur={() => setIsFocused(false)} className={`min-h-[${rows * 24}px] rounded-b-lg border border-border bg-background p-4 text-sm outline-none transition-colors ${isFocused ? "ring-2 ring-ring ring-offset-2" : "" } ${isDragging ? "ring-2 ring-primary bg-primary/5" : ""}`} style={{ minHeight: `${rows * 24}px`, }} data-placeholder={placeholder} />

Puede pegar o arrastrar imágenes directamente, o usar el botón de imagen para seleccionar archivos. Haga clic en una imagen para redimensionarla.

) }