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>
116 lines
3.2 KiB
TypeScript
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();
|
|
});
|
|
});
|