diff --git a/src/component/TemplateManager/ElementConstructor.tsx b/src/component/TemplateManager/ElementConstructor.tsx index b75e5a1..db14f98 100644 --- a/src/component/TemplateManager/ElementConstructor.tsx +++ b/src/component/TemplateManager/ElementConstructor.tsx @@ -578,6 +578,15 @@ export const ElementConstructor: React.FC = ({ resetForm() } + const handleElementCopy = (element: Omit) => { + const newElement: TemplateElement = { + ...element, + id: Date.now().toString(), + order: elements.length, + } + onElementAdd(newElement) + } + return (
= ({ onElementDelete={handleDeleteAndSelect} onLayoutSettingsChange={onLayoutSettingsChange || (() => {})} onElementEdit={handleEditElement} + onElementAdd={handleElementCopy} />
diff --git a/src/component/TemplateManager/VisualLayoutEditor.tsx b/src/component/TemplateManager/VisualLayoutEditor.tsx index aeedbd7..9e21d8e 100644 --- a/src/component/TemplateManager/VisualLayoutEditor.tsx +++ b/src/component/TemplateManager/VisualLayoutEditor.tsx @@ -1,5 +1,5 @@ import { Edit, Grid, Move, Trash2 } from 'lucide-react' -import React, { useCallback, useMemo, useState } from 'react' +import React, { useCallback, useEffect, useMemo, useState } from 'react' import { Rnd } from 'react-rnd' import { getElementDefinition } from '../../entitiy/element/model/interface' import { @@ -35,6 +35,7 @@ interface VisualLayoutEditorProps { onElementDelete: (elementId: string) => void onLayoutSettingsChange: (settings: FormLayoutSettings) => void onElementEdit?: (element: TemplateElement) => void + onElementAdd?: (element: Omit) => void } interface DraggableElementProps { @@ -219,11 +220,45 @@ export const VisualLayoutEditor: React.FC = ({ onElementDelete, onLayoutSettingsChange, onElementEdit, + onElementAdd, }) => { // console.log('VisualLayoutEditor render with elements:', elements) const [selectedElementId, setSelectedElementId] = useState( null ) + const [copiedElement, setCopiedElement] = useState( + null + ) + + // Обработчик клавиш для копирования/вставки + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.ctrlKey || e.metaKey) { + if (e.key === 'c' && selectedElementId) { + e.preventDefault() + const elementToCopy = elements.find(el => el.id === selectedElementId) + if (elementToCopy) { + setCopiedElement(elementToCopy) + } + } else if (e.key === 'v' && copiedElement && onElementAdd) { + e.preventDefault() + const newElement = { + ...copiedElement, + layout: { + ...copiedElement.layout, + x: (copiedElement.layout?.x || 0) + 20, + y: (copiedElement.layout?.y || 0) + 20, + }, + } + delete (newElement as any).id // Удаляем id чтобы создался новый + onElementAdd(newElement) + } + } + } + + document.addEventListener('keydown', handleKeyDown) + return () => document.removeEventListener('keydown', handleKeyDown) + }, [selectedElementId, elements, copiedElement, onElementAdd]) const canvasSize = useMemo(() => { const PADDING_Y = 200 @@ -267,12 +302,15 @@ export const VisualLayoutEditor: React.FC = ({ [onElementUpdate] ) - const handleCanvasClick = useCallback((e: React.MouseEvent) => { - // Снимаем выделение при клике по пустому месту - if (e.target === e.currentTarget) { - setSelectedElementId(null) - } - }, []) + const handleCanvasClick = useCallback( + (e: React.MouseEvent) => { + // Снимаем выделение при клике по пустому месту + if (e.target === e.currentTarget) { + setSelectedElementId(null) + } + }, + [] + ) const toggleGrid = useCallback(() => { onLayoutSettingsChange({