feat: introducing Web-Embeds (alias iframe element) (#6691)

Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
zsviczian 2023-07-24 16:51:53 +02:00 committed by GitHub
parent 744e5b2ab3
commit b57b3b573d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 1923 additions and 234 deletions

View file

@ -13,8 +13,27 @@ Please add the latest change on the top under the correct section.
## Unreleased
### renderEmbeddable
```tsx
(element: NonDeletedExcalidrawElement, radius: number, appState: UIAppState) => JSX.Element | null;`
```
The renderEmbeddable function allows you to customize the rendering of a JSX component instead of using the default `<iframe>`. By setting props.renderEmbeddable, you can provide a custom implementation for rendering the element.
#### Parameters:
- element (NonDeletedExcalidrawElement): The element to be rendered.
- radius (number): The calculated border radius in pixels.
- appState (UIAppState): The current state of the UI.
#### Return value:
JSX.Element | null: The JSX component representing the custom rendering, or null if the default `<iframe>` should be rendered.
### Features
- Added [`props.validateEmbeddable`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props#validateEmbeddable) to customize embeddable src url validation. [#6691](https://github.com/excalidraw/excalidraw/pull/6691)
- Add support for `opts.fitToViewport` and `opts.viewportZoomFactor` in the [`ExcalidrawAPI.scrollToContent`](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/props/ref#scrolltocontent) API. [#6581](https://github.com/excalidraw/excalidraw/pull/6581).
- Properly sanitize element `link` urls. [#6728](https://github.com/excalidraw/excalidraw/pull/6728).
- Sidebar component now supports tabs — for more detailed description of new behavior and breaking changes, see the linked PR. [#6213](https://github.com/excalidraw/excalidraw/pull/6213)

View file

@ -26,7 +26,7 @@ import {
LibraryItems,
PointerDownState as ExcalidrawPointerDownState,
} from "../../../types";
import { NonDeletedExcalidrawElement } from "../../../element/types";
import { NonDeletedExcalidrawElement, Theme } from "../../../element/types";
import { ImportedLibraryData } from "../../../data/types";
import CustomFooter from "./CustomFooter";
import MobileFooter from "./MobileFooter";
@ -96,7 +96,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
const [canvasUrl, setCanvasUrl] = useState<string>("");
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
const [exportEmbedScene, setExportEmbedScene] = useState(false);
const [theme, setTheme] = useState("light");
const [theme, setTheme] = useState<Theme>("light");
const [isCollaborating, setIsCollaborating] = useState(false);
const [commentIcons, setCommentIcons] = useState<{ [id: string]: Comment }>(
{},
@ -595,11 +595,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
type="checkbox"
checked={theme === "dark"}
onChange={() => {
let newTheme = "light";
if (theme === "light") {
newTheme = "dark";
}
setTheme(newTheme);
setTheme(theme === "light" ? "dark" : "light");
}}
/>
Switch to Dark Theme
@ -687,6 +683,8 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
onLinkOpen={onLinkOpen}
onPointerDown={onPointerDown}
onScrollChange={rerenderCommentIcons}
// allow all urls
validateEmbeddable={true}
>
{excalidrawAPI && (
<Footer>

View file

@ -42,6 +42,8 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
onPointerDown,
onScrollChange,
children,
validateEmbeddable,
renderEmbeddable,
} = props;
const canvasActions = props.UIOptions?.canvasActions;
@ -115,6 +117,8 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
onLinkOpen={onLinkOpen}
onPointerDown={onPointerDown}
onScrollChange={onScrollChange}
validateEmbeddable={validateEmbeddable}
renderEmbeddable={renderEmbeddable}
>
{children}
</App>

View file

@ -178,8 +178,10 @@ export const exportToSvg = async ({
appState = getDefaultAppState(),
files = {},
exportPadding,
renderEmbeddables,
}: Omit<ExportOpts, "getDimensions"> & {
exportPadding?: number;
renderEmbeddables?: boolean;
}): Promise<SVGSVGElement> => {
const { elements: restoredElements, appState: restoredAppState } = restore(
{ elements, appState },
@ -197,6 +199,7 @@ export const exportToSvg = async ({
exportAppState,
files,
{
renderEmbeddables,
// NOTE as long as we're using the Scene hack, we need to ensure
// we pass the original, uncloned elements when serializing
// so that we keep ids stable. Hence adding the serializeAsJSON helper