ui-dev-content/dist/components/TextEditorModal.js

99 lines
4.3 KiB
JavaScript
Raw Permalink Normal View History

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' })] })] }));
}