From a820fcde5304bc6e99867ebe3e51eb418aa74964 Mon Sep 17 00:00:00 2001 From: Ammar Ahmed <40239442+ammarahm-ed@users.noreply.github.com> Date: Thu, 4 Jun 2026 13:16:51 +0500 Subject: [PATCH] editor: allow any width/height value in EmbedSizeOptions when inserting embed (#9925) * editor: allow any width/height value in EmbedSizeOptions when inserting embeds * editor: only accept valid url as value * editor: allow embeding normal website urls * editor: check url if embedSource=url * editor: use defaultValue prop for width/height --- .../editor/src/toolbar/popups/embed-popup.tsx | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/packages/editor/src/toolbar/popups/embed-popup.tsx b/packages/editor/src/toolbar/popups/embed-popup.tsx index cb634952b..52747e407 100644 --- a/packages/editor/src/toolbar/popups/embed-popup.tsx +++ b/packages/editor/src/toolbar/popups/embed-popup.tsx @@ -17,17 +17,17 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -import { Flex, Text } from "@theme-ui/components"; -import { useCallback, useState } from "react"; -import { Popup } from "../components/popup.js"; -import { Input, Textarea } from "@theme-ui/components"; -import { Embed, EmbedSizeOptions } from "../../extensions/embed/index.js"; -import { convertUrlToEmbedUrl } from "@social-embed/lib"; -import { InlineInput } from "../../components/inline-input/index.js"; -import { Tabs, Tab } from "../../components/tabs/index.js"; import { strings } from "@notesnook/intl"; +import { convertUrlToEmbedUrl, isValidUrl } from "@social-embed/lib"; +import { Flex, Input, Text, Textarea } from "@theme-ui/components"; +import { useCallback, useState } from "react"; +import { InlineInput } from "../../components/inline-input/index.js"; +import { Tab, Tabs } from "../../components/tabs/index.js"; +import { Embed, EmbedSizeOptions } from "../../extensions/embed/index.js"; +import { Popup } from "../components/popup.js"; type EmbedSource = "url" | "code"; + export type EmbedPopupProps = { onClose: (embed?: Embed) => void; title: string; @@ -38,33 +38,30 @@ export type EmbedPopupProps = { export function EmbedPopup(props: EmbedPopupProps) { const { onClose, onSizeChanged, title, embed } = props; - const [width, setWidth] = useState(embed?.width || 300); - const [height, setHeight] = useState(embed?.height || 150); const [src, setSrc] = useState(embed?.src || ""); const [embedSource, setEmbedSource] = useState("url"); const [error, setError] = useState(null); + const [size, setSize] = useState({ + width: embed?.width || 300, + height: embed?.height || 150 + }); const onSizeChange = useCallback( (newWidth?: number, newHeight?: number) => { - const size: EmbedSizeOptions = newWidth - ? { - width: newWidth, - height: newWidth * (height / width) - } - : newHeight - ? { - width: newHeight * (width / height), - height: newHeight - } - : { - width: 0, - height: 0 - }; - setWidth(size.width); - setHeight(size.height); - if (onSizeChanged) onSizeChanged(size); + const hasNewWidth = Number.isFinite(newWidth); + const hasNewHeight = Number.isFinite(newHeight); + + if (!hasNewWidth && !hasNewHeight) return; + setSize((size) => { + const newSize = { + width: hasNewWidth ? ((newWidth || 0) as number) : size.width, + height: hasNewHeight ? ((newHeight || 0) as number) : size.height + }; + if (onSizeChanged) onSizeChanged(newSize); + return newSize; + }); }, - [height, width, onSizeChanged] + [onSizeChanged] ); return ( @@ -77,8 +74,9 @@ export function EmbedPopup(props: EmbedPopupProps) { onClick: () => { setError(null); let _src = src; - let _width = width; - let _height = height; + let _width = size.width; + let _height = size.height; + if (embedSource === "code") { const document = new DOMParser().parseFromString(src, "text/html"); if (document.getElementsByTagName("iframe").length <= 0) @@ -100,8 +98,19 @@ export function EmbedPopup(props: EmbedPopupProps) { if (heightValue && !isNaN(parseInt(heightValue))) _height = parseInt(heightValue); } + + if (embedSource === "url" && !isValidUrl(src)) { + return setError("Please provide a valid url."); + } + const convertedUrl = convertUrlToEmbedUrl(_src); + if (convertedUrl) _src = convertedUrl; + + if (!_src && embedSource === "url") { + return setError("Please provide a valid embed url."); + } + if (_src.startsWith("javascript:")) { return setError("Embedding javascript code is not supported."); } @@ -147,7 +156,7 @@ export function EmbedPopup(props: EmbedPopupProps) { label="width" type="number" placeholder={strings.width()} - value={width} + defaultValue={size.width} sx={{ mr: 1, fontSize: "body" @@ -158,7 +167,7 @@ export function EmbedPopup(props: EmbedPopupProps) { label="height" type="number" placeholder={strings.height()} - value={height} + defaultValue={size.height} sx={{ fontSize: "body" }} onChange={(e) => onSizeChange(undefined, e.target.valueAsNumber)