[lexical-playground] Bug Fix: Use natural dimensions for inherited image size (#7388)

This commit is contained in:
Kiran Dash
2025-03-28 00:16:31 +08:00
committed by GitHub
parent 283a8fa4b1
commit 74efb1df70
2 changed files with 133 additions and 8 deletions

View File

@ -388,8 +388,12 @@ test.describe('Images', () => {
});
});
test('Can add images by arbitrary URL', async ({page, isPlainText}) => {
test.skip(isPlainText);
test('Can add images by arbitrary URL', async ({
page,
isPlainText,
isCollab,
}) => {
test.skip(isPlainText || isCollab, 'Skip in plain text and collab mode');
await focusEditor(page);
@ -418,7 +422,7 @@ test.describe('Images', () => {
alt="lexical logo"
draggable="false"
src="https://lexical.dev/img/logo.svg"
style="height: inherit; max-width: 500px; width: inherit;" />
style="height: 112px; max-width: 500px; width: 500px" />
</div>
</span>
<span
@ -790,4 +794,58 @@ test.describe('Images', () => {
`,
);
});
test(`Verifies image dimensions are properly calculated for both SVG and JPG formats`, async ({
page,
isPlainText,
isCollab,
}) => {
test.skip(isPlainText || isCollab, 'Skip in plain text and collab mode');
await focusEditor(page);
// Insert an SVG image using the Lexical logo
await insertUrlImage(
page,
'https://lexical.dev/img/logo.svg',
'lexical logo',
);
// Insert a JPG image
await insertUrlImage(page, SAMPLE_IMAGE_URL, 'sample image');
// Verify both images are inserted with proper dimensions and styling
await assertHTML(
page,
html`
<p class="PlaygroundEditorTheme__paragraph">
<span
class="editor-image"
contenteditable="false"
data-lexical-decorator="true">
<div draggable="false">
<img
alt="lexical logo"
draggable="false"
src="https://lexical.dev/img/logo.svg"
style="height: 112px; max-width: 500px; width: 500px" />
</div>
</span>
<span
class="editor-image"
contenteditable="false"
data-lexical-decorator="true">
<div draggable="false">
<img
alt="sample image"
draggable="false"
src="${SAMPLE_IMAGE_URL}"
style="height: inherit; max-width: 500px; width: inherit;" />
</div>
</span>
<br />
</p>
`,
);
});
});

View File

@ -79,6 +79,10 @@ function useSuspenseImage(src: string) {
}
}
function isSVG(src: string): boolean {
return src.toLowerCase().endsWith('.svg');
}
function LazyImage({
altText,
className,
@ -99,19 +103,82 @@ function LazyImage({
onError: () => void;
}): JSX.Element {
useSuspenseImage(src);
const [dimensions, setDimensions] = useState<{
width: number;
height: number;
} | null>(null);
const isSVGImage = isSVG(src);
// Set initial dimensions for SVG images
useEffect(() => {
if (imageRef.current && isSVGImage) {
const {naturalWidth, naturalHeight} = imageRef.current;
setDimensions({
height: naturalHeight,
width: naturalWidth,
});
}
}, [imageRef, isSVGImage]);
// Calculate final dimensions with proper scaling
const calculateDimensions = () => {
if (!isSVGImage) {
return {
height,
maxWidth,
width,
};
}
// Use natural dimensions if available, otherwise fallback to defaults
const naturalWidth = dimensions?.width || 200;
const naturalHeight = dimensions?.height || 200;
let finalWidth = naturalWidth;
let finalHeight = naturalHeight;
// Scale down if width exceeds maxWidth while maintaining aspect ratio
if (finalWidth > maxWidth) {
const scale = maxWidth / finalWidth;
finalWidth = maxWidth;
finalHeight = Math.round(finalHeight * scale);
}
// Scale down if height exceeds maxHeight while maintaining aspect ratio
const maxHeight = 500;
if (finalHeight > maxHeight) {
const scale = maxHeight / finalHeight;
finalHeight = maxHeight;
finalWidth = Math.round(finalWidth * scale);
}
return {
height: finalHeight,
maxWidth,
width: finalWidth,
};
};
const imageStyle = calculateDimensions();
return (
<img
className={className || undefined}
src={src}
alt={altText}
ref={imageRef}
style={{
height,
maxWidth,
width,
}}
style={imageStyle}
onError={onError}
draggable="false"
onLoad={(e) => {
if (isSVGImage) {
const img = e.currentTarget;
setDimensions({
height: img.naturalHeight,
width: img.naturalWidth,
});
}
}}
/>
);
}