feat(ui): anchor de views — primitive de docking DockRegion + modèle ViewPlacement (#22)

Introduit la primitive de docking DockRegion et le modèle ViewPlacement
pour ancrer les vues dans le chrome, câblés dans ProjectsView. Tests
unitaires DockRegion et test d'intégration docking de ProjectsView.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 11:45:46 +02:00
parent 2f8467e2dd
commit 419e9b8498
6 changed files with 592 additions and 50 deletions

View File

@ -0,0 +1,59 @@
/**
* DockRegion (#22) — the in-flow resizable side column. Covers: it renders its
* children beside a resize handle, the handle carries the right a11y role, and a
* pointer drag maps to a clamped width delta whose sign depends on the side
* (left grows moving right, right grows moving left).
*/
import { describe, it, expect, vi } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { DockRegion } from "./DockRegion";
describe("DockRegion", () => {
it("renders its children and an inner-edge resize separator", () => {
render(
<DockRegion side="left" width={300} onResize={() => {}}>
<p>docked body</p>
</DockRegion>,
);
expect(screen.getByText("docked body")).toBeTruthy();
const handle = screen.getByRole("separator", { name: "resize left dock" });
expect(handle.getAttribute("aria-orientation")).toBe("vertical");
});
it("a left dock grows when the pointer drags right", () => {
const onResize = vi.fn();
render(
<DockRegion side="left" width={300} onResize={onResize}>
<p>body</p>
</DockRegion>,
);
const handle = screen.getByRole("separator", { name: "resize left dock" });
fireEvent.pointerDown(handle, { pointerId: 1, clientX: 100 });
fireEvent.pointerMove(handle, { pointerId: 1, clientX: 160 });
expect(onResize).toHaveBeenLastCalledWith(360);
});
it("a right dock grows when the pointer drags left, and width is clamped", () => {
const onResize = vi.fn();
render(
<DockRegion
side="right"
width={300}
onResize={onResize}
minWidth={240}
maxWidth={500}
>
<p>body</p>
</DockRegion>,
);
const handle = screen.getByRole("separator", { name: "resize right dock" });
// Dragging left (negative delta) grows a right dock.
fireEvent.pointerDown(handle, { pointerId: 1, clientX: 400 });
fireEvent.pointerMove(handle, { pointerId: 1, clientX: 320 });
expect(onResize).toHaveBeenLastCalledWith(380);
// A large leftward drag is clamped to maxWidth.
fireEvent.pointerMove(handle, { pointerId: 1, clientX: 0 });
expect(onResize).toHaveBeenLastCalledWith(500);
});
});