feat(annotations): add N/S/E/W edge midpoint handles to resize overlay

Extends the 4-corner L-bracket handles with 4 tick-mark edge handles
(short lines along each edge), enabling single-axis resize from any edge.
Updates applyHandleDrag to route each handle to the correct axis.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-14 11:40:39 +02:00
parent fcc0efbf02
commit 9fe5b32a69
4 changed files with 33 additions and 15 deletions

View File

@@ -16,27 +16,31 @@ const annotation: Annotation = {
};
describe('AnnotationEditOverlay', () => {
it('renders 4 corner handle elements', async () => {
it('renders 8 handle elements', async () => {
render(AnnotationEditOverlay, { annotation });
const handles = document.querySelectorAll('[data-handle]');
expect(handles).toHaveLength(4);
expect(handles).toHaveLength(8);
});
it('renders handles for all four corners', async () => {
it('renders handles for all four corners and four edge midpoints', async () => {
render(AnnotationEditOverlay, { annotation });
expect(document.querySelector('[data-handle="nw"]')).not.toBeNull();
expect(document.querySelector('[data-handle="ne"]')).not.toBeNull();
expect(document.querySelector('[data-handle="sw"]')).not.toBeNull();
expect(document.querySelector('[data-handle="se"]')).not.toBeNull();
expect(document.querySelector('[data-handle="n"]')).not.toBeNull();
expect(document.querySelector('[data-handle="s"]')).not.toBeNull();
expect(document.querySelector('[data-handle="e"]')).not.toBeNull();
expect(document.querySelector('[data-handle="w"]')).not.toBeNull();
});
it('each handle has a 44x44 hit area', async () => {
render(AnnotationEditOverlay, { annotation });
const hitAreas = document.querySelectorAll('[data-handle-hit]');
expect(hitAreas).toHaveLength(4);
expect(hitAreas).toHaveLength(8);
hitAreas.forEach((el) => {
expect(el.getAttribute('width')).toBe('44');
expect(el.getAttribute('height')).toBe('44');