fix(ui): a small crop frame takes smaller handles, so it can still be grabbed to move

The handles reach 10 px into the frame from every side; a frame at its minimum on a small picture
(the Downloads editor at 800 px: 41 x 23) was then nearly all handle - 74 of its 920 px still moved
it. Below 64 px on its shorter side the frame takes 12 px corners and 8 px edges: 262 px move it.
This commit is contained in:
2026-10-10 13:54:04 +02:00
parent 0a16bc40ae
commit 72df11f2c0
2 changed files with 45 additions and 5 deletions
@@ -33,8 +33,16 @@ beforeAll(() => {
const WIDE = 16 / 9;
function Harness({ aspect = WIDE, ratio = null }: { aspect?: number; ratio?: number | null }) {
const [rect, setRect] = useState<Frac>({ x: 0.2, y: 0.2, w: 0.4, h: 0.4 });
function Harness({
aspect = WIDE,
ratio = null,
start = { x: 0.2, y: 0.2, w: 0.4, h: 0.4 },
}: {
aspect?: number;
ratio?: number | null;
start?: Frac;
}) {
const [rect, setRect] = useState<Frac>(start);
return (
<div>
<output data-testid="rect">
@@ -117,6 +125,20 @@ describe("CropFrame", () => {
expect(document.activeElement).toBe(frame);
});
it("shrinks its handles on a small frame, so the frame itself stays there to grab", () => {
const corner = () => screen.getByRole("group", { name: "common.cropFrame.se" });
const edge = () => document.querySelector<HTMLElement>(".cursor-ew-resize")!;
// 640 × 360 px of a 1600 × 900 picture: the full handles.
render(<Harness />);
expect(corner().className).toContain("size-5");
expect(edge().className).toContain("w-4");
cleanup();
// A 1:4 picture in that box is 225 px wide: a tenth of it is a 22 px frame.
render(<Harness aspect={0.25} start={{ x: 0.2, y: 0.2, w: 0.1, h: 0.5 }} />);
expect(corner().className).toContain("size-3");
expect(edge().className).toContain("w-2");
});
it("lets a press outside the frame through to the player, and keeps one on the frame", () => {
const click = vi.fn();
render(