From 74efb1df70a54889fab5382c4932e7aa98281bc4 Mon Sep 17 00:00:00 2001 From: Kiran Dash Date: Fri, 28 Mar 2025 00:16:31 +0800 Subject: [PATCH] [lexical-playground] Bug Fix: Use natural dimensions for inherited image size (#7388) --- .../__tests__/e2e/Images.spec.mjs | 64 ++++++++++++++- .../src/nodes/ImageComponent.tsx | 77 +++++++++++++++++-- 2 files changed, 133 insertions(+), 8 deletions(-) diff --git a/packages/lexical-playground/__tests__/e2e/Images.spec.mjs b/packages/lexical-playground/__tests__/e2e/Images.spec.mjs index b99dc139f..be2e1348c 100644 --- a/packages/lexical-playground/__tests__/e2e/Images.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Images.spec.mjs @@ -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" /> { `, ); }); + + 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` +

+ +

+ lexical logo +
+
+ +
+ sample image +
+
+
+

+ `, + ); + }); }); diff --git a/packages/lexical-playground/src/nodes/ImageComponent.tsx b/packages/lexical-playground/src/nodes/ImageComponent.tsx index 3c263b082..03571bb7e 100644 --- a/packages/lexical-playground/src/nodes/ImageComponent.tsx +++ b/packages/lexical-playground/src/nodes/ImageComponent.tsx @@ -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 ( {altText} { + if (isSVGImage) { + const img = e.currentTarget; + setDimensions({ + height: img.naturalHeight, + width: img.naturalWidth, + }); + } + }} /> ); }