копирование элемента по ctrl+c и ctrl+v

This commit is contained in:
2025-07-25 14:11:15 +03:00
parent d9b51014e9
commit 0d25446a7e
2 changed files with 55 additions and 7 deletions

View File

@@ -578,6 +578,15 @@ export const ElementConstructor: React.FC<ElementConstructorProps> = ({
resetForm()
}
const handleElementCopy = (element: Omit<TemplateElement, 'id'>) => {
const newElement: TemplateElement = {
...element,
id: Date.now().toString(),
order: elements.length,
}
onElementAdd(newElement)
}
return (
<div className="flex h-full w-full flex-col bg-background">
<ElementFormulaBar
@@ -611,6 +620,7 @@ export const ElementConstructor: React.FC<ElementConstructorProps> = ({
onElementDelete={handleDeleteAndSelect}
onLayoutSettingsChange={onLayoutSettingsChange || (() => {})}
onElementEdit={handleEditElement}
onElementAdd={handleElementCopy}
/>
</div>

View File

@@ -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<TemplateElement, 'id'>) => void
}
interface DraggableElementProps {
@@ -219,11 +220,45 @@ export const VisualLayoutEditor: React.FC<VisualLayoutEditorProps> = ({
onElementDelete,
onLayoutSettingsChange,
onElementEdit,
onElementAdd,
}) => {
// console.log('VisualLayoutEditor render with elements:', elements)
const [selectedElementId, setSelectedElementId] = useState<string | null>(
null
)
const [copiedElement, setCopiedElement] = useState<TemplateElement | null>(
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<VisualLayoutEditorProps> = ({
[onElementUpdate]
)
const handleCanvasClick = useCallback((e: React.MouseEvent) => {
const handleCanvasClick = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
// Снимаем выделение при клике по пустому месту
if (e.target === e.currentTarget) {
setSelectedElementId(null)
}
}, [])
},
[]
)
const toggleGrid = useCallback(() => {
onLayoutSettingsChange({