From 318b7358e1c6b320fb36e269376d87d2bf7c2f14 Mon Sep 17 00:00:00 2001 From: Hiren Kangad Date: Thu, 12 Mar 2026 19:06:27 +0530 Subject: [PATCH] =?UTF-8?q?fix(review):=20address=20code=20review=20findin?= =?UTF-8?q?gs=20=E2=80=94=20tool=20conflicts,=20dual=20inputs,=20pin=20ani?= =?UTF-8?q?mation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. TEXT and ERASER tool clicks now suppressed during review mode via reviewMode flag on ToolContext (read from ref for live value) 2. Object-comment input hidden when draftPin is active — only one creation input visible at a time 3. PinOverlay entrance animation removed — focus styling (scale 1.15x, alpha changes) no longer fights with fade-in animation loop --- frontend/src/canvas/PinOverlay.ts | 28 +------------------ frontend/src/canvas/tools.ts | 4 +++ .../src/components/feedback/FeedbackPanel.tsx | 2 +- frontend/src/pages/Editor.tsx | 8 ++++++ 4 files changed, 14 insertions(+), 28 deletions(-) diff --git a/frontend/src/canvas/PinOverlay.ts b/frontend/src/canvas/PinOverlay.ts index 45d3458..935d258 100644 --- a/frontend/src/canvas/PinOverlay.ts +++ b/frontend/src/canvas/PinOverlay.ts @@ -178,11 +178,7 @@ export class PinOverlay extends Container { this.addChild(container); - // Entrance animation - container.alpha = 0; - container.scale.set(0.6); - this._animateEntrance(container); - + // No entrance animation — focus styling must not be overwritten by animation. return entry; } @@ -241,28 +237,6 @@ export class PinOverlay extends Container { } } - private _animateEntrance(pin: Container) { - const tick = () => { - if (pin.destroyed) return; - let done = true; - if (pin.alpha < 0.99) { - pin.alpha += (1 - pin.alpha) * 0.3; - done = false; - } else { - pin.alpha = 1; - } - const s = pin.scale.x; - if (s < 0.99) { - pin.scale.set(s + (1 - s) * 0.3); - done = false; - } else { - pin.scale.set(1); - } - if (!done) requestAnimationFrame(tick); - }; - requestAnimationFrame(tick); - } - setGhostPin(pin: { objectId: string; pinX: number; pinY: number } | null) { this._ghostPin = pin; this._updateGhostPin(); diff --git a/frontend/src/canvas/tools.ts b/frontend/src/canvas/tools.ts index c3a8e90..85b7ab2 100644 --- a/frontend/src/canvas/tools.ts +++ b/frontend/src/canvas/tools.ts @@ -49,6 +49,8 @@ export interface ToolContext { textEditor?: TextEditor; /** Switch back to select tool after placing text. */ switchToSelect?: () => void; + /** When true, destructive/creative tool clicks (TEXT, ERASER) are suppressed. */ + reviewMode?: boolean; } export function activateTool( @@ -82,6 +84,7 @@ export function activateTool( container.style.cursor = 'text'; const onClick = (e: PointerEvent) => { + if (ctx.reviewMode) return; // Review mode suppresses text creation const rect = container.getBoundingClientRect(); const world = viewport.toWorld(e.clientX - rect.left, e.clientY - rect.top); @@ -154,6 +157,7 @@ export function activateTool( selection.transformBox.update([]); const onClick = (e: PointerEvent) => { + if (ctx.reviewMode) return; // Review mode suppresses eraser const rect = container.getBoundingClientRect(); const world = viewport.toWorld(e.clientX - rect.left, e.clientY - rect.top); const hit = selection._hitTest(world.x, world.y); diff --git a/frontend/src/components/feedback/FeedbackPanel.tsx b/frontend/src/components/feedback/FeedbackPanel.tsx index 62b8294..3b84272 100644 --- a/frontend/src/components/feedback/FeedbackPanel.tsx +++ b/frontend/src/components/feedback/FeedbackPanel.tsx @@ -323,7 +323,7 @@ export default function FeedbackPanel({ onFilterChange={setFilter} onSelectThread={updateExpandedThread} onCollapse={() => setCollapsed(true)} - selectedObjectId={selectedObjectId} + selectedObjectId={draftPin ? null : selectedObjectId} selectedObjectLabel={selectedLabel} newCommentText={newCommentText} onNewCommentChange={setNewCommentText} diff --git a/frontend/src/pages/Editor.tsx b/frontend/src/pages/Editor.tsx index ef2d016..a45f537 100644 --- a/frontend/src/pages/Editor.tsx +++ b/frontend/src/pages/Editor.tsx @@ -102,6 +102,7 @@ export default function Editor({ isPublicView }: EditorProps) { const [showMmImport, setShowMmImport] = useState(false); const [showExport, setShowExport] = useState(false); const [reviewMode, setReviewMode] = useState(false); + const reviewModeRef = useRef(false); const [focusedThreadId, setFocusedThreadId] = useState(null); // Pulse signal: threadId to open, or null to collapse detail view const [expandRequest, setExpandRequest] = useState<{ threadId: string | null; seq: number } | null>(null); @@ -201,6 +202,11 @@ export default function Editor({ isPublicView }: EditorProps) { // eslint-disable-next-line react-hooks/exhaustive-deps }, [objectCount]); + // Keep reviewModeRef in sync for tool handlers to read + useEffect(() => { + reviewModeRef.current = reviewMode; + }, [reviewMode]); + // Pins visible only in review mode useEffect(() => { if (!pinOverlay) return; @@ -404,6 +410,8 @@ export default function Editor({ isPublicView }: EditorProps) { textEditor: textEditor ?? undefined, switchToSelect: () => setActiveTool(ToolType.SELECT), }; + // reviewMode is read at click time via getter so it stays current + Object.defineProperty(ctx, 'reviewMode', { get: () => reviewModeRef.current }); toolCleanupRef.current = activateTool(ctx, activeTool, { color, strokeWidth, fontSize }); }, [activeTool, color, strokeWidth, fontSize, onCanvasChange, textEditor]);