mirror of
https://github.com/facebook/lexical.git
synced 2025-07-03 14:08:57 +08:00
[lexical-playground] Bug Fix: Use natural dimensions for inherited image size (#7388)
This commit is contained in:
@ -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>
|
||||
`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user