Files
familienarchiv/frontend/src/lib/document/annotation/AnnotationLayer.svelte.spec.ts
Marcel ad820955fd fix(transcription): remove annotation canvas delete button that obscured text (#722)
The per-annotation delete button (a 44px circular control pinned to the
box's top-right) overlapped the box below and obscured the underlying
document text. It was redundant: every user-drawn annotation has a
transcription block, and the right-hand panel already offers a
non-overlapping delete per block that cascades to the annotation.

Remove the visible button and its `deleteVisible` derived. Keep the
keyboard Delete shortcut (and its `showDelete`/`onDeleteRequest`/
`deleteAnnotation` wiring) — it obscures nothing and remains a
power-user path and the only cleanup route for orphan annotations.

Tests: replace the button-render/click specs with contract tests
asserting no delete button ever renders; repoint the e2e delete flow
to the keyboard shortcut + confirm dialog.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 12:28:17 +02:00

116 lines
3.2 KiB
TypeScript

import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import AnnotationLayer from './AnnotationLayer.svelte';
afterEach(cleanup);
type Annotation = {
id: string;
documentId: string;
pageNumber: number;
x: number;
y: number;
width: number;
height: number;
color: string;
createdAt: string;
};
function makeAnnotation(id = 'ann-1', color = '#00C7B1'): Annotation {
return {
id,
documentId: 'doc-1',
pageNumber: 1,
x: 0.1,
y: 0.1,
width: 0.3,
height: 0.2,
color,
createdAt: new Date().toISOString()
};
}
describe('AnnotationLayer', () => {
it('renders a colored element for each annotation', async () => {
render(AnnotationLayer, {
annotations: [makeAnnotation('ann-1'), makeAnnotation('ann-2')],
canDraw: false,
color: '#00C7B1',
onDraw: () => {}
});
await expect.element(page.getByTestId('annotation-ann-1')).toBeInTheDocument();
await expect.element(page.getByTestId('annotation-ann-2')).toBeInTheDocument();
});
it('has crosshair cursor when canDraw is true', async () => {
render(AnnotationLayer, {
annotations: [],
canDraw: true,
color: '#00C7B1',
onDraw: () => {}
});
const container = document.querySelector('[role="presentation"]')!;
expect(container.getAttribute('style')).toContain('cursor: crosshair');
});
it('does not have crosshair cursor when canDraw is false', async () => {
render(AnnotationLayer, {
annotations: [],
canDraw: false,
color: '#00C7B1',
onDraw: () => {}
});
const container = document.querySelector('[role="presentation"]')!;
expect(container.getAttribute('style')).not.toContain('cursor: crosshair');
});
it('dims non-active annotations when activeAnnotationId is set', async () => {
render(AnnotationLayer, {
annotations: [makeAnnotation('ann-1'), makeAnnotation('ann-2')],
canDraw: false,
color: '#00C7B1',
activeAnnotationId: 'ann-1',
onDraw: () => {}
});
const active = page.getByTestId('annotation-ann-1').element();
const dimmed = page.getByTestId('annotation-ann-2').element();
expect(active.style.opacity).toBe('1');
expect(dimmed.style.opacity).toBe('0.3');
});
it('shows all annotations at full opacity when no activeAnnotationId', async () => {
render(AnnotationLayer, {
annotations: [makeAnnotation('ann-1'), makeAnnotation('ann-2')],
canDraw: false,
color: '#00C7B1',
onDraw: () => {}
});
const el1 = page.getByTestId('annotation-ann-1').element();
const el2 = page.getByTestId('annotation-ann-2').element();
expect(el1.style.opacity).toBe('1');
expect(el2.style.opacity).toBe('1');
});
// The on-canvas delete button was removed (issue #722). Even in annotate mode
// with an active annotation, no delete button must render over the document.
it('never renders a delete button, even in annotate mode with an active annotation', async () => {
render(AnnotationLayer, {
annotations: [makeAnnotation('ann-1')],
canDraw: true,
color: '#00C7B1',
activeAnnotationId: 'ann-1',
onDraw: () => {}
});
await expect.element(page.getByTestId('annotation-ann-1')).toBeInTheDocument();
await expect.element(page.getByTestId('annotation-delete-ann-1')).not.toBeInTheDocument();
});
});