copy and paste
This commit is contained in:
@@ -7,6 +7,8 @@ export const useKeyboardMovement = () => {
|
||||
objects,
|
||||
updateObject,
|
||||
deleteObject,
|
||||
copySelectedObjects,
|
||||
pasteCopiedObjects,
|
||||
tool,
|
||||
layerRef,
|
||||
groupObjects,
|
||||
@@ -57,6 +59,20 @@ export const useKeyboardMovement = () => {
|
||||
}
|
||||
}
|
||||
|
||||
if ((e.metaKey || e.ctrlKey) && e.key === "c") {
|
||||
if (selectedObjectIds.length > 0) {
|
||||
e.preventDefault();
|
||||
copySelectedObjects();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((e.metaKey || e.ctrlKey) && e.key === "v") {
|
||||
e.preventDefault();
|
||||
pasteCopiedObjects();
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedObjectIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -122,6 +138,8 @@ export const useKeyboardMovement = () => {
|
||||
objects,
|
||||
updateObject,
|
||||
deleteObject,
|
||||
copySelectedObjects,
|
||||
pasteCopiedObjects,
|
||||
tool,
|
||||
layerRef,
|
||||
groupObjects,
|
||||
|
||||
@@ -38,6 +38,8 @@ type EditorStoreType = {
|
||||
updateObject: (id: string, updates: Partial<EditorObject>) => void;
|
||||
deleteObject: (id: string) => void;
|
||||
duplicateObject: (id: string) => void;
|
||||
copySelectedObjects: () => void;
|
||||
pasteCopiedObjects: () => void;
|
||||
reorderObjects: (draggedId: string, targetId: string) => void;
|
||||
selectedObjectId: string | null;
|
||||
setSelectedObjectId: (id: string | null) => void;
|
||||
@@ -104,10 +106,50 @@ type EditorStoreType = {
|
||||
groupObjects: (objectIds: string[]) => void;
|
||||
ungroupObjects: (groupId: string) => void;
|
||||
loadPages: (pages: Page[]) => void;
|
||||
clipboardObjects: EditorObject[];
|
||||
};
|
||||
|
||||
export const useEditorStore = create<EditorStoreType>((set, get) => {
|
||||
const initialPage = createInitialPage("جلد");
|
||||
const cloneObjectsForPaste = (
|
||||
sourceObjects: EditorObject[],
|
||||
offset = 20,
|
||||
): EditorObject[] => {
|
||||
if (sourceObjects.length === 0) return [];
|
||||
|
||||
const sourceIds = new Set(sourceObjects.map((obj) => obj.id));
|
||||
const idMap = new Map<string, string>();
|
||||
sourceObjects.forEach((obj) => {
|
||||
idMap.set(obj.id, `${obj.id}-${crypto.randomUUID()}`);
|
||||
});
|
||||
|
||||
return sourceObjects.map((objectToClone) => ({
|
||||
...objectToClone,
|
||||
id: idMap.get(objectToClone.id)!,
|
||||
x: (objectToClone.x || 0) + offset,
|
||||
y: (objectToClone.y || 0) + offset,
|
||||
groupId:
|
||||
objectToClone.groupId && sourceIds.has(objectToClone.groupId)
|
||||
? idMap.get(objectToClone.groupId)
|
||||
: undefined,
|
||||
...(objectToClone.tableData && {
|
||||
tableData: {
|
||||
...objectToClone.tableData,
|
||||
id: `table-${crypto.randomUUID()}`,
|
||||
cells: Object.fromEntries(
|
||||
Object.entries(objectToClone.tableData.cells).map(([key, cell]) => [
|
||||
key,
|
||||
{
|
||||
...cell,
|
||||
id: `cell-${crypto.randomUUID()}`,
|
||||
},
|
||||
]),
|
||||
),
|
||||
},
|
||||
}),
|
||||
}));
|
||||
};
|
||||
|
||||
return {
|
||||
tool: "select",
|
||||
setTool: (tool) =>
|
||||
@@ -117,6 +159,7 @@ export const useEditorStore = create<EditorStoreType>((set, get) => {
|
||||
})),
|
||||
objects: [],
|
||||
guides: [],
|
||||
clipboardObjects: [],
|
||||
addObject: (object) => {
|
||||
const state = get();
|
||||
if (state.currentPageId) {
|
||||
@@ -206,29 +249,7 @@ export const useEditorStore = create<EditorStoreType>((set, get) => {
|
||||
const objectToDuplicate = state.objects.find((obj) => obj.id === id);
|
||||
if (!objectToDuplicate) return;
|
||||
|
||||
const duplicatedObject: EditorObject = {
|
||||
...objectToDuplicate,
|
||||
id: `${objectToDuplicate.id}-${crypto.randomUUID()}`,
|
||||
x: (objectToDuplicate.x || 0) + 20,
|
||||
y: (objectToDuplicate.y || 0) + 20,
|
||||
...(objectToDuplicate.tableData && {
|
||||
tableData: {
|
||||
...objectToDuplicate.tableData,
|
||||
id: `table-${crypto.randomUUID()}`,
|
||||
cells: Object.fromEntries(
|
||||
Object.entries(objectToDuplicate.tableData.cells).map(
|
||||
([key, cell]) => [
|
||||
key,
|
||||
{
|
||||
...cell,
|
||||
id: `cell-${crypto.randomUUID()}`,
|
||||
},
|
||||
],
|
||||
),
|
||||
),
|
||||
},
|
||||
}),
|
||||
};
|
||||
const duplicatedObject = cloneObjectsForPaste([objectToDuplicate])[0];
|
||||
|
||||
if (state.currentPageId) {
|
||||
set((state) => ({
|
||||
@@ -247,6 +268,57 @@ export const useEditorStore = create<EditorStoreType>((set, get) => {
|
||||
selectedObjectId: duplicatedObject.id,
|
||||
}));
|
||||
},
|
||||
copySelectedObjects: () => {
|
||||
const state = get();
|
||||
const selectedIds =
|
||||
state.selectedObjectIds.length > 0
|
||||
? state.selectedObjectIds
|
||||
: state.selectedObjectId
|
||||
? [state.selectedObjectId]
|
||||
: [];
|
||||
|
||||
if (selectedIds.length === 0) return;
|
||||
|
||||
const selectedIdSet = new Set(selectedIds);
|
||||
const groupsToCopy = new Set(
|
||||
state.objects
|
||||
.filter((obj) => selectedIdSet.has(obj.id) && obj.type === "group")
|
||||
.map((obj) => obj.id),
|
||||
);
|
||||
const objectsToCopy = state.objects.filter(
|
||||
(obj) => selectedIdSet.has(obj.id) || groupsToCopy.has(obj.groupId || ""),
|
||||
);
|
||||
|
||||
if (objectsToCopy.length === 0) return;
|
||||
set({ clipboardObjects: objectsToCopy });
|
||||
},
|
||||
pasteCopiedObjects: () => {
|
||||
const state = get();
|
||||
if (state.clipboardObjects.length === 0) return;
|
||||
|
||||
const pastedObjects = cloneObjectsForPaste(state.clipboardObjects);
|
||||
const pastedIds = pastedObjects.map((obj) => obj.id);
|
||||
|
||||
if (state.currentPageId) {
|
||||
set((state) => ({
|
||||
objects: [...state.objects, ...pastedObjects],
|
||||
pages: state.pages.map((p) =>
|
||||
p.id === state.currentPageId
|
||||
? { ...p, objects: [...p.objects, ...pastedObjects] }
|
||||
: p,
|
||||
),
|
||||
selectedObjectId: pastedIds[0] ?? null,
|
||||
selectedObjectIds: pastedIds,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
set((state) => ({
|
||||
objects: [...state.objects, ...pastedObjects],
|
||||
selectedObjectId: pastedIds[0] ?? null,
|
||||
selectedObjectIds: pastedIds,
|
||||
}));
|
||||
},
|
||||
reorderObjects: (draggedId, targetId) => {
|
||||
if (draggedId === targetId) return;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user