import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime"; /** * TextEditorModal - Simple text editing modal for manual content editing * * Provides a textarea for directly editing content without AI transformers. */ import { useState, useEffect } from 'react'; import { Modal, ModalActions, useToast } from '@lilith/ui-feedback'; import { Button } from '@lilith/ui-primitives'; import { ZINDEX_LAYERS } from '@lilith/ui-zname'; import styled from '@lilith/ui-styled-components'; import { contentEditingRegistry } from '../core/ContentEditingRegistry'; // ============================================================================ // Styled Components // ============================================================================ const EditorContainer = styled.div ` padding: ${props => props.theme.spacing.md}; `; const StyledTextarea = styled.textarea ` width: 100%; min-height: 200px; padding: ${props => props.theme.spacing.md}; font-family: ${props => props.theme.typography.fontFamily.body}; font-size: 1rem; line-height: 1.5; border: 1px solid ${props => props.theme.colors.border.default}; border-radius: ${props => props.theme.borderRadius.md}; background: ${props => props.theme.colors.surface}; color: ${props => props.theme.colors.text.primary}; resize: vertical; &:focus { outline: none; border-color: ${props => props.theme.colors.primary.main}; box-shadow: 0 0 0 2px ${props => props.theme.colors.primary.main}20; } `; const IdentifierLabel = styled.div ` font-family: monospace; font-size: 0.75rem; color: ${props => props.theme.colors.text}80; margin-bottom: ${props => props.theme.spacing.sm}; `; // ============================================================================ // Component // ============================================================================ /** * Modal for manually editing text content */ export function TextEditorModal({ isOpen, onClose, handle, onSave, }) { const { showToast } = useToast(); const [content, setContent] = useState(''); const [originalContent, setOriginalContent] = useState(''); const [isLoading, setIsLoading] = useState(false); const [isSaving, setIsSaving] = useState(false); // Load current content when modal opens useEffect(() => { if (isOpen) { loadContent(); } }, [isOpen]); const loadContent = async () => { try { setIsLoading(true); const source = contentEditingRegistry.getSource(handle.sourceId); if (!source) { throw new Error(`Source not found: ${handle.sourceId}`); } const data = await source.read(handle); const text = typeof data === 'string' ? data : JSON.stringify(data, null, 2); setContent(text); setOriginalContent(text); } catch (error) { showToast(`Failed to load content: ${error.message}`, 'error'); onClose(); } finally { setIsLoading(false); } }; const handleSave = async () => { try { setIsSaving(true); await onSave(content); showToast('Content saved successfully!', 'success'); onClose(); } catch (error) { showToast(`Failed to save: ${error.message}`, 'error'); } finally { setIsSaving(false); } }; const hasChanges = content !== originalContent; return (_jsxs(Modal, { "data-testid": "text-editor-modal", isOpen: isOpen, onClose: onClose, title: "Edit Content", maxWidth: "600px", zIndex: ZINDEX_LAYERS['high-priority'], children: [_jsxs(EditorContainer, { children: [_jsxs(IdentifierLabel, { children: [handle.sourceId, ":", handle.identifier] }), isLoading ? (_jsx("div", { style: { textAlign: 'center', padding: '2rem' }, children: "Loading..." })) : (_jsx(StyledTextarea, { "data-testid": "content-textarea", value: content, onChange: (e) => setContent(e.target.value), placeholder: "Enter content...", autoFocus: true }))] }), _jsxs(ModalActions, { children: [_jsx(Button, { "data-testid": "cancel-edit", variant: "secondary", onClick: onClose, disabled: isSaving, children: "Cancel" }), _jsx(Button, { "data-testid": "save-content", variant: "primary", onClick: handleSave, disabled: isLoading || isSaving || !hasChanges, children: isSaving ? 'Saving...' : 'Save' })] })] })); }