From ee3f08a725dfd62457e931abbf65bc52415703f6 Mon Sep 17 00:00:00 2001 From: Abdullah Atta Date: Wed, 19 Aug 2026 13:31:01 +0500 Subject: [PATCH] editor: improve SVG size handling this is experimental and should be tested properly --- .../editor/src/extensions/image/component.tsx | 236 +++++++++++++----- 1 file changed, 167 insertions(+), 69 deletions(-) diff --git a/packages/editor/src/extensions/image/component.tsx b/packages/editor/src/extensions/image/component.tsx index fc6bb9946..a387585f6 100644 --- a/packages/editor/src/extensions/image/component.tsx +++ b/packages/editor/src/extensions/image/component.tsx @@ -60,19 +60,18 @@ export function ImageComponent( }); const dom = editor.view.dom; + const downloadOptions = useToolbarStore((store) => store.downloadOptions); + const isReadonly = !editor.isEditable; + const isSVG = !!mime && mime.includes("/svg"); const size = editor.view.dom.clientWidth === 0 ? node.attrs - : clampSize(node.attrs, dom.clientWidth, aspectRatio); + : clampSize(node.attrs, dom.clientWidth, aspectRatio, isSVG); let align = node.attrs.align; if (!align) align = textDirection ? "right" : "left"; - const downloadOptions = useToolbarStore((store) => store.downloadOptions); - const isReadonly = !editor.isEditable; - const isSVG = !!mime && mime.includes("/svg"); - useEffect(() => { if (!inView) return; if (src || !hash || bloburl) return; @@ -113,12 +112,114 @@ export function ImageComponent( } }} > + + {selected && ( + + + + )} + {Boolean(resizing) && ( + + + {resizing?.width} + {" × "} + {resizing?.height} + + + )} + + {isSVG ? ( + + ) : null} { setResizing({ width, height }); }} @@ -127,65 +228,6 @@ export function ImageComponent( editor.commands.setImageSize({ width, height }); }} > - - {selected && ( - - - - )} - {Boolean(resizing) && ( - - - {resizing?.width} - {" × "} - {resizing?.height} - - - )} - {progress ? ( { const { hash, filename, mime, size } = node.attrs; @@ -312,6 +364,47 @@ export function ImageComponent( onLoad={async function onLoad() { if (!imageRef.current) return; + // For SVGs rendered as iframes, naturalWidth/naturalHeight are 0. + // Read the viewBox from the SVG contentDocument instead. + if (isSVG) { + try { + const iframe = imageRef.current as unknown as HTMLIFrameElement; + const svgEl = + iframe.contentDocument?.querySelector("svg"); + const viewBox = svgEl?.getAttribute("viewBox"); + if (viewBox) { + const parts = viewBox.split(/[\s,]+/).map(Number); + if (parts.length === 4 && parts[2] > 0 && parts[3] > 0) { + const svgAspectRatio = parts[2] / parts[3]; + if ( + !aspectRatio || + Math.abs(aspectRatio - svgAspectRatio) > 0.01 + ) { + const fixedDimensions = fixAspectRatio( + size.width ?? 0, + svgAspectRatio + ); + await editor.threadsafe((editor) => + editor.commands.updateAttachment( + { + ...fixedDimensions, + aspectRatio: svgAspectRatio + }, + { + query: makeImageQuery(src, hash), + ignoreEdit: true + } + ) + ); + } + } + } + } catch { + // cross-origin or missing contentDocument — skip + } + return; + } + const { naturalWidth, naturalHeight, clientHeight, clientWidth } = imageRef.current; const originalWidth = naturalWidth || clientWidth; @@ -389,7 +482,8 @@ function canParse(src: string) { function clampSize( size: { width?: number; height?: number }, maxWidth: number, - aspectRatio?: number + aspectRatio?: number, + isSVG?: boolean ): { width: number; height: number } { if (typeof aspectRatio === "string" && isNaN(aspectRatio)) aspectRatio = 1; @@ -398,6 +492,10 @@ function clampSize( if (!aspectRatio) aspectRatio = size.width / size.height; + // SVGs (especially infinite canvas exports from OneNote) should preserve + // their original dimensions. The container handles overflow via scrolling. + if (isSVG) return { width: size.width, height: size.height }; + if (size.width > maxWidth) return { width: maxWidth, height: maxWidth / aspectRatio };