import { useCallback } from "react"; import { useEditorStore, type EditorObject } from "../../store/editorStore"; export const useObjectHandlers = () => { // All handlers read live state via getState() and are wrapped in useCallback // with empty deps so their references never change between renders. // This prevents ObjectsLayer (and every ObjectRenderer inside it) from // re-rendering whenever unrelated EditorCanvas state (e.g. active guide IDs) // changes during drag — eliminating lag and flickering on masked groups. const handleObjectUpdate = useCallback((id: string, updates: Partial) => { const { objects, updateObject } = useEditorStore.getState(); const obj = objects.find((o) => o.id === id); if (!obj) return; if (obj.type === "group" && (updates.x !== undefined || updates.y !== undefined)) { const groupMembers = objects.filter((o) => o.groupId === id); const deltaX = updates.x !== undefined ? updates.x - (obj.x || 0) : 0; const deltaY = updates.y !== undefined ? updates.y - (obj.y || 0) : 0; updateObject(id, updates); groupMembers.forEach((member) => { updateObject(member.id, { x: (member.x || 0) + deltaX, y: (member.y || 0) + deltaY, }); }); } else { updateObject(id, updates); } }, []); const handleGroupWithMask = useCallback((objectId: string, maskId: string) => { useEditorStore.getState().groupObjects([objectId, maskId]); }, []); const handleUngroupFromMask = useCallback((groupId: string) => { useEditorStore.getState().ungroupObjects(groupId); }, []); const handleCellEditorSave = useCallback((text: string) => { const { editingCell, updateCellValue, setEditingCell } = useEditorStore.getState(); if (editingCell) { updateCellValue(editingCell.tableId, editingCell.cellId, text); setEditingCell(null); } }, []); const handleCellEditorCancel = useCallback(() => { useEditorStore.getState().setEditingCell(null); }, []); return { handleObjectUpdate, handleGroupWithMask, handleUngroupFromMask, handleCellEditorSave, handleCellEditorCancel, }; };