From 3fb32ea285936f361e71fa6a365283163bf3f9d5 Mon Sep 17 00:00:00 2001 From: Marcel Date: Tue, 14 Apr 2026 10:57:13 +0200 Subject: [PATCH] feat(annotations): pass isResizable to AnnotationShape based on selection + transcribeMode Co-Authored-By: Claude Sonnet 4.6 --- .../src/lib/components/AnnotationLayer.svelte | 1 + .../components/AnnotationLayer.svelte.test.ts | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/frontend/src/lib/components/AnnotationLayer.svelte b/frontend/src/lib/components/AnnotationLayer.svelte index 65e87b42..ac7dbc7c 100644 --- a/frontend/src/lib/components/AnnotationLayer.svelte +++ b/frontend/src/lib/components/AnnotationLayer.svelte @@ -107,6 +107,7 @@ const containerStyle = $derived( annotation={annotation} isHovered={hoveredId === annotation.id} isActive={annotation.id === activeAnnotationId} + isResizable={canDraw && annotation.id === activeAnnotationId && !annotation.polygon} faded={!dimmed && !!activeAnnotationId && annotation.id !== activeAnnotationId} dimmed={dimmed} blockNumber={blockNumbers[annotation.id]} diff --git a/frontend/src/lib/components/AnnotationLayer.svelte.test.ts b/frontend/src/lib/components/AnnotationLayer.svelte.test.ts index 1f549cd3..5c78f3a2 100644 --- a/frontend/src/lib/components/AnnotationLayer.svelte.test.ts +++ b/frontend/src/lib/components/AnnotationLayer.svelte.test.ts @@ -16,6 +16,17 @@ const annotation: Annotation = { createdAt: '2026-01-01T00:00:00Z' }; +const polygonAnnotation: Annotation = { + ...annotation, + id: 'ann-poly', + polygon: [ + [0.1, 0.2], + [0.4, 0.21], + [0.39, 0.29], + [0.11, 0.28] + ] +}; + describe('AnnotationLayer', () => { describe('dimmed prop', () => { it('should hide block number badges when dimmed is true', async () => { @@ -65,6 +76,60 @@ describe('AnnotationLayer', () => { }); }); + describe('isResizable computation', () => { + it('passes isResizable=true when canDraw, annotation is active, and has no polygon', async () => { + render(AnnotationLayer, { + annotations: [annotation], + canDraw: true, + color: '#00c7b1', + activeAnnotationId: 'ann-1', + onDraw: () => {} + }); + + const handles = document.querySelectorAll('[data-handle]'); + expect(handles).toHaveLength(8); + }); + + it('passes isResizable=false when annotation has a polygon', async () => { + render(AnnotationLayer, { + annotations: [polygonAnnotation], + canDraw: true, + color: '#00c7b1', + activeAnnotationId: 'ann-poly', + onDraw: () => {} + }); + + const handles = document.querySelectorAll('[data-handle]'); + expect(handles).toHaveLength(0); + }); + + it('passes isResizable=false when canDraw is false', async () => { + render(AnnotationLayer, { + annotations: [annotation], + canDraw: false, + color: '#00c7b1', + activeAnnotationId: 'ann-1', + onDraw: () => {} + }); + + const handles = document.querySelectorAll('[data-handle]'); + expect(handles).toHaveLength(0); + }); + + it('passes isResizable=false when annotation is not active', async () => { + render(AnnotationLayer, { + annotations: [annotation], + canDraw: true, + color: '#00c7b1', + activeAnnotationId: 'other-id', + onDraw: () => {} + }); + + const handles = document.querySelectorAll('[data-handle]'); + expect(handles).toHaveLength(0); + }); + }); + describe('flashAnnotationId prop', () => { it('should apply annotation-flash class when flashAnnotationId matches', async () => { render(AnnotationLayer, {