mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: crop tool overflows viewport with tall portrait images
The crop area flex container lacked min-h-0, preventing it from shrinking below its content's intrinsic height. For tall images, react-image-crop's CSS (max-height: inherit at specificity 0-1-1) overrides the Tailwind max-h constraint, and without min-h-0 the flex item refuses to shrink, causing viewport overflow. Closes #122
This commit is contained in:
@@ -98,7 +98,7 @@ export function CropCanvas({
|
||||
return (
|
||||
<div ref={containerRef} className="flex flex-col w-full h-full max-w-4xl mx-auto outline-none">
|
||||
{/* Crop area */}
|
||||
<div className="flex-1 flex items-center justify-center overflow-hidden bg-muted/20 p-4">
|
||||
<div className="flex-1 flex items-center justify-center overflow-hidden bg-muted/20 p-4 min-h-0">
|
||||
<ReactCrop
|
||||
crop={crop}
|
||||
onChange={(_pixelCrop, percentCrop) => onCropChange(percentCrop)}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { execFileSync } from "node:child_process";
|
||||
import path from "node:path";
|
||||
import { expect, test, uploadTestImage, waitForProcessing } from "./helpers";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -195,6 +197,34 @@ test.describe("GUI Essential Tools", () => {
|
||||
|
||||
await expect(page.getByTestId("crop-download")).toBeVisible({ timeout: 15_000 });
|
||||
});
|
||||
|
||||
test("tall portrait image fits within viewport without overflow", async ({
|
||||
loggedInPage: page,
|
||||
}) => {
|
||||
await page.goto("/crop");
|
||||
|
||||
// Create a tall portrait image (200x2000) to trigger overflow
|
||||
const portraitPath = path.join(process.cwd(), "test-results", "test-portrait-tall.png");
|
||||
const script = [
|
||||
"const sharp = require('sharp');",
|
||||
`sharp({create:{width:200,height:2000,channels:4,background:{r:0,g:128,b:255,alpha:1}}}).png().toFile('${portraitPath.replace(/'/g, "\\'")}')`,
|
||||
].join(" ");
|
||||
execFileSync("node", ["-e", script], { cwd: process.cwd(), timeout: 5000 });
|
||||
|
||||
const fileChooserPromise = page.waitForEvent("filechooser");
|
||||
await page.locator("[class*='border-dashed']").first().click();
|
||||
const fileChooser = await fileChooserPromise;
|
||||
await fileChooser.setFiles(portraitPath);
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
const img = page.locator(".ReactCrop img");
|
||||
await expect(img).toBeVisible();
|
||||
|
||||
const viewport = page.viewportSize()!;
|
||||
const box = await img.boundingBox();
|
||||
expect(box).not.toBeNull();
|
||||
expect(box!.y + box!.height).toBeLessThanOrEqual(viewport.height);
|
||||
});
|
||||
});
|
||||
|
||||
// ========================================================================
|
||||
|
||||
Reference in New Issue
Block a user