mirror of
				https://github.com/excalidraw/excalidraw.git
				synced 2025-11-04 12:54:23 +01:00 
			
		
		
		
	docs: add next js with app router example (#7552)
* move the existing example to with-script-in-browser * Add example with next js app router * disable ssr for excalidraw client comp * typo * update output dir * don't include nextjs example in tsconfig * remove meta.json * lint * remove example.ts * port * move the examples outside packages and use the deps as workspaces in examples * update gitignore * fix example * update path of build dir * fix * fix scripts * try local path * fix * update commands * fix * fix * fix script * skip ts * disable ts * add vercel.json * install * update tsconfig * fix lint * remove console.log * lets see if this works * revert * remove ts nocheck * add types and some utils in nextjs example * fix types * updatw example and remove nextjs dynamic syntax so we don't import excal twice * move both examples to workspaces and create generic example to be used by browser and next js both * copy the static assets to nextjs * fix ts config * render custom menu items * fix custom footer * fix types in browser example * use regular imports for importing excal and import it using dynamic next js in app router instead * Add example for pages router * fix css discrepancies * fix css * configure output dir * fix * fix css * rename to with-nextjs * move components to examples/excalidraw/components
This commit is contained in:
		
							
								
								
									
										2
									
								
								packages/excalidraw/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								packages/excalidraw/.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,2 @@
 | 
			
		||||
node_modules
 | 
			
		||||
types
 | 
			
		||||
bundle.js
 | 
			
		||||
bundle.css
 | 
			
		||||
 
 | 
			
		||||
@@ -5780,7 +5780,10 @@ class App extends React.Component<AppProps, AppState> {
 | 
			
		||||
    event.preventDefault();
 | 
			
		||||
 | 
			
		||||
    let nextPastePrevented = false;
 | 
			
		||||
    const isLinux = /Linux/.test(window.navigator.platform);
 | 
			
		||||
    const isLinux =
 | 
			
		||||
      typeof window === undefined
 | 
			
		||||
        ? false
 | 
			
		||||
        : /Linux/.test(window.navigator.platform);
 | 
			
		||||
 | 
			
		||||
    setCursor(this.interactiveCanvas, CURSOR_TYPE.GRABBING);
 | 
			
		||||
    let { clientX: lastX, clientY: lastY } = event;
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,6 @@ import cssVariables from "./css/variables.module.scss";
 | 
			
		||||
import { AppProps } from "./types";
 | 
			
		||||
import { ExcalidrawElement, FontFamilyValues } from "./element/types";
 | 
			
		||||
import { COLOR_PALETTE } from "./colors";
 | 
			
		||||
 | 
			
		||||
export const isDarwin = /Mac|iPod|iPhone|iPad/.test(navigator.platform);
 | 
			
		||||
export const isWindows = /^Win/.test(navigator.platform);
 | 
			
		||||
export const isAndroid = /\b(android)\b/i.test(navigator.userAgent);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,83 +0,0 @@
 | 
			
		||||
.App {
 | 
			
		||||
  font-family: sans-serif;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
 | 
			
		||||
  .comment-avatar {
 | 
			
		||||
    background: #faa2c1;
 | 
			
		||||
    border-radius: 66px 67px 67px 0px;
 | 
			
		||||
    width: 2rem;
 | 
			
		||||
    height: 2rem;
 | 
			
		||||
    padding: 4px;
 | 
			
		||||
    margin: 4px;
 | 
			
		||||
    img {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
      height: 100%;
 | 
			
		||||
      border-radius: 50%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button-wrapper button {
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
  height: 40px;
 | 
			
		||||
  max-width: 200px;
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
  padding: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.excalidraw .App-menu_top .buttonList {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.excalidraw-wrapper {
 | 
			
		||||
  height: 800px;
 | 
			
		||||
  margin: 50px;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
:root[dir="ltr"]
 | 
			
		||||
  .excalidraw
 | 
			
		||||
  .layer-ui__wrapper
 | 
			
		||||
  .zen-mode-transition.App-menu_bottom--transition-left {
 | 
			
		||||
  transform: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.excalidraw .panelColumn {
 | 
			
		||||
  text-align: left;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.export-wrapper {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  margin: 50px;
 | 
			
		||||
 | 
			
		||||
  &__checkbox {
 | 
			
		||||
    display: flex;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.excalidraw {
 | 
			
		||||
  --color-primary: #faa2c1;
 | 
			
		||||
  --color-primary-darker: #f783ac;
 | 
			
		||||
  --color-primary-darkest: #e64980;
 | 
			
		||||
  --color-primary-light: #fcc2d7;
 | 
			
		||||
 | 
			
		||||
  button.custom-element {
 | 
			
		||||
    width: 2rem;
 | 
			
		||||
    height: 2rem;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .custom-footer,
 | 
			
		||||
  .custom-element {
 | 
			
		||||
    padding: 0.1rem;
 | 
			
		||||
    margin: 0 8px;
 | 
			
		||||
  }
 | 
			
		||||
  .layer-ui__wrapper__footer.App-menu_bottom {
 | 
			
		||||
    align-items: stretch;
 | 
			
		||||
  }
 | 
			
		||||
  // till its merged in OSS
 | 
			
		||||
  .App-toolbar-container .mobile-misc-tools-container {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,920 +0,0 @@
 | 
			
		||||
import ExampleSidebar from "./sidebar/ExampleSidebar";
 | 
			
		||||
 | 
			
		||||
import type * as TExcalidraw from "../index";
 | 
			
		||||
 | 
			
		||||
import "./App.scss";
 | 
			
		||||
import initialData from "./initialData";
 | 
			
		||||
import { nanoid } from "nanoid";
 | 
			
		||||
import { resolvablePromise, ResolvablePromise } from "../utils";
 | 
			
		||||
import { EVENT, ROUNDNESS } from "../constants";
 | 
			
		||||
import { distance2d } from "../math";
 | 
			
		||||
import { fileOpen } from "../data/filesystem";
 | 
			
		||||
import { loadSceneOrLibraryFromBlob } from "../../utils";
 | 
			
		||||
import type {
 | 
			
		||||
  AppState,
 | 
			
		||||
  BinaryFileData,
 | 
			
		||||
  ExcalidrawImperativeAPI,
 | 
			
		||||
  ExcalidrawInitialDataState,
 | 
			
		||||
  Gesture,
 | 
			
		||||
  LibraryItems,
 | 
			
		||||
  PointerDownState as ExcalidrawPointerDownState,
 | 
			
		||||
} from "../types";
 | 
			
		||||
import type { NonDeletedExcalidrawElement, Theme } from "../element/types";
 | 
			
		||||
import { ImportedLibraryData } from "../data/types";
 | 
			
		||||
import CustomFooter from "./CustomFooter";
 | 
			
		||||
import MobileFooter from "./MobileFooter";
 | 
			
		||||
import { KEYS } from "../keys";
 | 
			
		||||
import { withBatchedUpdates, withBatchedUpdatesThrottled } from "../reactUtils";
 | 
			
		||||
 | 
			
		||||
declare global {
 | 
			
		||||
  interface Window {
 | 
			
		||||
    ExcalidrawLib: typeof TExcalidraw;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Comment = {
 | 
			
		||||
  x: number;
 | 
			
		||||
  y: number;
 | 
			
		||||
  value: string;
 | 
			
		||||
  id?: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type PointerDownState = {
 | 
			
		||||
  x: number;
 | 
			
		||||
  y: number;
 | 
			
		||||
  hitElement: Comment;
 | 
			
		||||
  onMove: any;
 | 
			
		||||
  onUp: any;
 | 
			
		||||
  hitElementOffsets: {
 | 
			
		||||
    x: number;
 | 
			
		||||
    y: number;
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const { useEffect, useState, useRef, useCallback } = window.React;
 | 
			
		||||
 | 
			
		||||
// This is so that we use the bundled excalidraw.development.js file instead
 | 
			
		||||
// of the actual source code
 | 
			
		||||
const {
 | 
			
		||||
  exportToCanvas,
 | 
			
		||||
  exportToSvg,
 | 
			
		||||
  exportToBlob,
 | 
			
		||||
  exportToClipboard,
 | 
			
		||||
  Excalidraw,
 | 
			
		||||
  useHandleLibrary,
 | 
			
		||||
  MIME_TYPES,
 | 
			
		||||
  sceneCoordsToViewportCoords,
 | 
			
		||||
  viewportCoordsToSceneCoords,
 | 
			
		||||
  restoreElements,
 | 
			
		||||
  Sidebar,
 | 
			
		||||
  Footer,
 | 
			
		||||
  WelcomeScreen,
 | 
			
		||||
  MainMenu,
 | 
			
		||||
  LiveCollaborationTrigger,
 | 
			
		||||
  convertToExcalidrawElements,
 | 
			
		||||
  TTDDialog,
 | 
			
		||||
  TTDDialogTrigger,
 | 
			
		||||
} = window.ExcalidrawLib;
 | 
			
		||||
 | 
			
		||||
const COMMENT_ICON_DIMENSION = 32;
 | 
			
		||||
const COMMENT_INPUT_HEIGHT = 50;
 | 
			
		||||
const COMMENT_INPUT_WIDTH = 150;
 | 
			
		||||
 | 
			
		||||
export interface AppProps {
 | 
			
		||||
  appTitle: string;
 | 
			
		||||
  useCustom: (api: ExcalidrawImperativeAPI | null, customArgs?: any[]) => void;
 | 
			
		||||
  customArgs?: any[];
 | 
			
		||||
}
 | 
			
		||||
export default function App({ appTitle, useCustom, customArgs }: AppProps) {
 | 
			
		||||
  const appRef = useRef<any>(null);
 | 
			
		||||
  const [viewModeEnabled, setViewModeEnabled] = useState(false);
 | 
			
		||||
  const [zenModeEnabled, setZenModeEnabled] = useState(false);
 | 
			
		||||
  const [gridModeEnabled, setGridModeEnabled] = useState(false);
 | 
			
		||||
  const [blobUrl, setBlobUrl] = useState<string>("");
 | 
			
		||||
  const [canvasUrl, setCanvasUrl] = useState<string>("");
 | 
			
		||||
  const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
 | 
			
		||||
  const [exportEmbedScene, setExportEmbedScene] = useState(false);
 | 
			
		||||
  const [theme, setTheme] = useState<Theme>("light");
 | 
			
		||||
  const [disableImageTool, setDisableImageTool] = useState(false);
 | 
			
		||||
  const [isCollaborating, setIsCollaborating] = useState(false);
 | 
			
		||||
  const [commentIcons, setCommentIcons] = useState<{ [id: string]: Comment }>(
 | 
			
		||||
    {},
 | 
			
		||||
  );
 | 
			
		||||
  const [comment, setComment] = useState<Comment | null>(null);
 | 
			
		||||
 | 
			
		||||
  const initialStatePromiseRef = useRef<{
 | 
			
		||||
    promise: ResolvablePromise<ExcalidrawInitialDataState | null>;
 | 
			
		||||
  }>({ promise: null! });
 | 
			
		||||
  if (!initialStatePromiseRef.current.promise) {
 | 
			
		||||
    initialStatePromiseRef.current.promise =
 | 
			
		||||
      resolvablePromise<ExcalidrawInitialDataState | null>();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const [excalidrawAPI, setExcalidrawAPI] =
 | 
			
		||||
    useState<ExcalidrawImperativeAPI | null>(null);
 | 
			
		||||
 | 
			
		||||
  useCustom(excalidrawAPI, customArgs);
 | 
			
		||||
 | 
			
		||||
  useHandleLibrary({ excalidrawAPI });
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (!excalidrawAPI) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const fetchData = async () => {
 | 
			
		||||
      const res = await fetch("/images/rocket.jpeg");
 | 
			
		||||
      const imageData = await res.blob();
 | 
			
		||||
      const reader = new FileReader();
 | 
			
		||||
      reader.readAsDataURL(imageData);
 | 
			
		||||
 | 
			
		||||
      reader.onload = function () {
 | 
			
		||||
        const imagesArray: BinaryFileData[] = [
 | 
			
		||||
          {
 | 
			
		||||
            id: "rocket" as BinaryFileData["id"],
 | 
			
		||||
            dataURL: reader.result as BinaryFileData["dataURL"],
 | 
			
		||||
            mimeType: MIME_TYPES.jpg,
 | 
			
		||||
            created: 1644915140367,
 | 
			
		||||
            lastRetrieved: 1644915140367,
 | 
			
		||||
          },
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        //@ts-ignore
 | 
			
		||||
        initialStatePromiseRef.current.promise.resolve({
 | 
			
		||||
          ...initialData,
 | 
			
		||||
          elements: convertToExcalidrawElements(initialData.elements),
 | 
			
		||||
        });
 | 
			
		||||
        excalidrawAPI.addFiles(imagesArray);
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
    fetchData();
 | 
			
		||||
  }, [excalidrawAPI]);
 | 
			
		||||
 | 
			
		||||
  const renderTopRightUI = (isMobile: boolean) => {
 | 
			
		||||
    return (
 | 
			
		||||
      <>
 | 
			
		||||
        {!isMobile && (
 | 
			
		||||
          <LiveCollaborationTrigger
 | 
			
		||||
            isCollaborating={isCollaborating}
 | 
			
		||||
            onSelect={() => {
 | 
			
		||||
              window.alert("Collab dialog clicked");
 | 
			
		||||
            }}
 | 
			
		||||
          />
 | 
			
		||||
        )}
 | 
			
		||||
        <button
 | 
			
		||||
          onClick={() => alert("This is an empty top right UI")}
 | 
			
		||||
          style={{ height: "2.5rem" }}
 | 
			
		||||
        >
 | 
			
		||||
          Click me
 | 
			
		||||
        </button>
 | 
			
		||||
      </>
 | 
			
		||||
    );
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const loadSceneOrLibrary = async () => {
 | 
			
		||||
    const file = await fileOpen({ description: "Excalidraw or library file" });
 | 
			
		||||
    const contents = await loadSceneOrLibraryFromBlob(file, null, null);
 | 
			
		||||
    if (contents.type === MIME_TYPES.excalidraw) {
 | 
			
		||||
      excalidrawAPI?.updateScene(contents.data as any);
 | 
			
		||||
    } else if (contents.type === MIME_TYPES.excalidrawlib) {
 | 
			
		||||
      excalidrawAPI?.updateLibrary({
 | 
			
		||||
        libraryItems: (contents.data as ImportedLibraryData).libraryItems!,
 | 
			
		||||
        openLibraryMenu: true,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const updateScene = () => {
 | 
			
		||||
    const sceneData = {
 | 
			
		||||
      elements: restoreElements(
 | 
			
		||||
        convertToExcalidrawElements([
 | 
			
		||||
          {
 | 
			
		||||
            type: "rectangle",
 | 
			
		||||
            id: "rect-1",
 | 
			
		||||
            fillStyle: "hachure",
 | 
			
		||||
            strokeWidth: 1,
 | 
			
		||||
            strokeStyle: "solid",
 | 
			
		||||
            roughness: 1,
 | 
			
		||||
            angle: 0,
 | 
			
		||||
            x: 100.50390625,
 | 
			
		||||
            y: 93.67578125,
 | 
			
		||||
            strokeColor: "#c92a2a",
 | 
			
		||||
            width: 186.47265625,
 | 
			
		||||
            height: 141.9765625,
 | 
			
		||||
            seed: 1968410350,
 | 
			
		||||
            roundness: {
 | 
			
		||||
              type: ROUNDNESS.ADAPTIVE_RADIUS,
 | 
			
		||||
              value: 32,
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            type: "arrow",
 | 
			
		||||
            x: 300,
 | 
			
		||||
            y: 150,
 | 
			
		||||
            start: { id: "rect-1" },
 | 
			
		||||
            end: { type: "ellipse" },
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            type: "text",
 | 
			
		||||
            x: 300,
 | 
			
		||||
            y: 100,
 | 
			
		||||
            text: "HELLO WORLD!",
 | 
			
		||||
          },
 | 
			
		||||
        ]),
 | 
			
		||||
        null,
 | 
			
		||||
      ),
 | 
			
		||||
      appState: {
 | 
			
		||||
        viewBackgroundColor: "#edf2ff",
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
    excalidrawAPI?.updateScene(sceneData);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const onLinkOpen = useCallback(
 | 
			
		||||
    (
 | 
			
		||||
      element: NonDeletedExcalidrawElement,
 | 
			
		||||
      event: CustomEvent<{
 | 
			
		||||
        nativeEvent: MouseEvent | React.PointerEvent<HTMLCanvasElement>;
 | 
			
		||||
      }>,
 | 
			
		||||
    ) => {
 | 
			
		||||
      const link = element.link!;
 | 
			
		||||
      const { nativeEvent } = event.detail;
 | 
			
		||||
      const isNewTab = nativeEvent.ctrlKey || nativeEvent.metaKey;
 | 
			
		||||
      const isNewWindow = nativeEvent.shiftKey;
 | 
			
		||||
      const isInternalLink =
 | 
			
		||||
        link.startsWith("/") || link.includes(window.location.origin);
 | 
			
		||||
      if (isInternalLink && !isNewTab && !isNewWindow) {
 | 
			
		||||
        // signal that we're handling the redirect ourselves
 | 
			
		||||
        event.preventDefault();
 | 
			
		||||
        // do a custom redirect, such as passing to react-router
 | 
			
		||||
        // ...
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    [],
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const onCopy = async (type: "png" | "svg" | "json") => {
 | 
			
		||||
    if (!excalidrawAPI) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    await exportToClipboard({
 | 
			
		||||
      elements: excalidrawAPI.getSceneElements(),
 | 
			
		||||
      appState: excalidrawAPI.getAppState(),
 | 
			
		||||
      files: excalidrawAPI.getFiles(),
 | 
			
		||||
      type,
 | 
			
		||||
    });
 | 
			
		||||
    window.alert(`Copied to clipboard as ${type} successfully`);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const [pointerData, setPointerData] = useState<{
 | 
			
		||||
    pointer: { x: number; y: number };
 | 
			
		||||
    button: "down" | "up";
 | 
			
		||||
    pointersMap: Gesture["pointers"];
 | 
			
		||||
  } | null>(null);
 | 
			
		||||
 | 
			
		||||
  const onPointerDown = (
 | 
			
		||||
    activeTool: AppState["activeTool"],
 | 
			
		||||
    pointerDownState: ExcalidrawPointerDownState,
 | 
			
		||||
  ) => {
 | 
			
		||||
    if (activeTool.type === "custom" && activeTool.customType === "comment") {
 | 
			
		||||
      const { x, y } = pointerDownState.origin;
 | 
			
		||||
      setComment({ x, y, value: "" });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const rerenderCommentIcons = () => {
 | 
			
		||||
    if (!excalidrawAPI) {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    const commentIconsElements = appRef.current.querySelectorAll(
 | 
			
		||||
      ".comment-icon",
 | 
			
		||||
    ) as HTMLElement[];
 | 
			
		||||
    commentIconsElements.forEach((ele) => {
 | 
			
		||||
      const id = ele.id;
 | 
			
		||||
      const appstate = excalidrawAPI.getAppState();
 | 
			
		||||
      const { x, y } = sceneCoordsToViewportCoords(
 | 
			
		||||
        { sceneX: commentIcons[id].x, sceneY: commentIcons[id].y },
 | 
			
		||||
        appstate,
 | 
			
		||||
      );
 | 
			
		||||
      ele.style.left = `${
 | 
			
		||||
        x - COMMENT_ICON_DIMENSION / 2 - appstate!.offsetLeft
 | 
			
		||||
      }px`;
 | 
			
		||||
      ele.style.top = `${
 | 
			
		||||
        y - COMMENT_ICON_DIMENSION / 2 - appstate!.offsetTop
 | 
			
		||||
      }px`;
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const onPointerMoveFromPointerDownHandler = (
 | 
			
		||||
    pointerDownState: PointerDownState,
 | 
			
		||||
  ) => {
 | 
			
		||||
    return withBatchedUpdatesThrottled((event) => {
 | 
			
		||||
      if (!excalidrawAPI) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
      const { x, y } = viewportCoordsToSceneCoords(
 | 
			
		||||
        {
 | 
			
		||||
          clientX: event.clientX - pointerDownState.hitElementOffsets.x,
 | 
			
		||||
          clientY: event.clientY - pointerDownState.hitElementOffsets.y,
 | 
			
		||||
        },
 | 
			
		||||
        excalidrawAPI.getAppState(),
 | 
			
		||||
      );
 | 
			
		||||
      setCommentIcons({
 | 
			
		||||
        ...commentIcons,
 | 
			
		||||
        [pointerDownState.hitElement.id!]: {
 | 
			
		||||
          ...commentIcons[pointerDownState.hitElement.id!],
 | 
			
		||||
          x,
 | 
			
		||||
          y,
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
  const onPointerUpFromPointerDownHandler = (
 | 
			
		||||
    pointerDownState: PointerDownState,
 | 
			
		||||
  ) => {
 | 
			
		||||
    return withBatchedUpdates((event) => {
 | 
			
		||||
      window.removeEventListener(EVENT.POINTER_MOVE, pointerDownState.onMove);
 | 
			
		||||
      window.removeEventListener(EVENT.POINTER_UP, pointerDownState.onUp);
 | 
			
		||||
      excalidrawAPI?.setActiveTool({ type: "selection" });
 | 
			
		||||
      const distance = distance2d(
 | 
			
		||||
        pointerDownState.x,
 | 
			
		||||
        pointerDownState.y,
 | 
			
		||||
        event.clientX,
 | 
			
		||||
        event.clientY,
 | 
			
		||||
      );
 | 
			
		||||
      if (distance === 0) {
 | 
			
		||||
        if (!comment) {
 | 
			
		||||
          setComment({
 | 
			
		||||
            x: pointerDownState.hitElement.x + 60,
 | 
			
		||||
            y: pointerDownState.hitElement.y,
 | 
			
		||||
            value: pointerDownState.hitElement.value,
 | 
			
		||||
            id: pointerDownState.hitElement.id,
 | 
			
		||||
          });
 | 
			
		||||
        } else {
 | 
			
		||||
          setComment(null);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const renderCommentIcons = () => {
 | 
			
		||||
    return Object.values(commentIcons).map((commentIcon) => {
 | 
			
		||||
      if (!excalidrawAPI) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
      const appState = excalidrawAPI.getAppState();
 | 
			
		||||
      const { x, y } = sceneCoordsToViewportCoords(
 | 
			
		||||
        { sceneX: commentIcon.x, sceneY: commentIcon.y },
 | 
			
		||||
        excalidrawAPI.getAppState(),
 | 
			
		||||
      );
 | 
			
		||||
      return (
 | 
			
		||||
        <div
 | 
			
		||||
          id={commentIcon.id}
 | 
			
		||||
          key={commentIcon.id}
 | 
			
		||||
          style={{
 | 
			
		||||
            top: `${y - COMMENT_ICON_DIMENSION / 2 - appState!.offsetTop}px`,
 | 
			
		||||
            left: `${x - COMMENT_ICON_DIMENSION / 2 - appState!.offsetLeft}px`,
 | 
			
		||||
            position: "absolute",
 | 
			
		||||
            zIndex: 1,
 | 
			
		||||
            width: `${COMMENT_ICON_DIMENSION}px`,
 | 
			
		||||
            height: `${COMMENT_ICON_DIMENSION}px`,
 | 
			
		||||
            cursor: "pointer",
 | 
			
		||||
            touchAction: "none",
 | 
			
		||||
          }}
 | 
			
		||||
          className="comment-icon"
 | 
			
		||||
          onPointerDown={(event) => {
 | 
			
		||||
            event.preventDefault();
 | 
			
		||||
            if (comment) {
 | 
			
		||||
              commentIcon.value = comment.value;
 | 
			
		||||
              saveComment();
 | 
			
		||||
            }
 | 
			
		||||
            const pointerDownState: any = {
 | 
			
		||||
              x: event.clientX,
 | 
			
		||||
              y: event.clientY,
 | 
			
		||||
              hitElement: commentIcon,
 | 
			
		||||
              hitElementOffsets: { x: event.clientX - x, y: event.clientY - y },
 | 
			
		||||
            };
 | 
			
		||||
            const onPointerMove =
 | 
			
		||||
              onPointerMoveFromPointerDownHandler(pointerDownState);
 | 
			
		||||
            const onPointerUp =
 | 
			
		||||
              onPointerUpFromPointerDownHandler(pointerDownState);
 | 
			
		||||
            window.addEventListener(EVENT.POINTER_MOVE, onPointerMove);
 | 
			
		||||
            window.addEventListener(EVENT.POINTER_UP, onPointerUp);
 | 
			
		||||
 | 
			
		||||
            pointerDownState.onMove = onPointerMove;
 | 
			
		||||
            pointerDownState.onUp = onPointerUp;
 | 
			
		||||
 | 
			
		||||
            excalidrawAPI?.setActiveTool({
 | 
			
		||||
              type: "custom",
 | 
			
		||||
              customType: "comment",
 | 
			
		||||
            });
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          <div className="comment-avatar">
 | 
			
		||||
            <img src="images/doremon.png" alt="doremon" />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const saveComment = () => {
 | 
			
		||||
    if (!comment) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (!comment.id && !comment.value) {
 | 
			
		||||
      setComment(null);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    const id = comment.id || nanoid();
 | 
			
		||||
    setCommentIcons({
 | 
			
		||||
      ...commentIcons,
 | 
			
		||||
      [id]: {
 | 
			
		||||
        x: comment.id ? comment.x - 60 : comment.x,
 | 
			
		||||
        y: comment.y,
 | 
			
		||||
        id,
 | 
			
		||||
        value: comment.value,
 | 
			
		||||
      },
 | 
			
		||||
    });
 | 
			
		||||
    setComment(null);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const renderComment = () => {
 | 
			
		||||
    if (!comment) {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
    const appState = excalidrawAPI?.getAppState()!;
 | 
			
		||||
    const { x, y } = sceneCoordsToViewportCoords(
 | 
			
		||||
      { sceneX: comment.x, sceneY: comment.y },
 | 
			
		||||
      appState,
 | 
			
		||||
    );
 | 
			
		||||
    let top = y - COMMENT_ICON_DIMENSION / 2 - appState.offsetTop;
 | 
			
		||||
    let left = x - COMMENT_ICON_DIMENSION / 2 - appState.offsetLeft;
 | 
			
		||||
 | 
			
		||||
    if (
 | 
			
		||||
      top + COMMENT_INPUT_HEIGHT <
 | 
			
		||||
      appState.offsetTop + COMMENT_INPUT_HEIGHT
 | 
			
		||||
    ) {
 | 
			
		||||
      top = COMMENT_ICON_DIMENSION / 2;
 | 
			
		||||
    }
 | 
			
		||||
    if (top + COMMENT_INPUT_HEIGHT > appState.height) {
 | 
			
		||||
      top = appState.height - COMMENT_INPUT_HEIGHT - COMMENT_ICON_DIMENSION / 2;
 | 
			
		||||
    }
 | 
			
		||||
    if (
 | 
			
		||||
      left + COMMENT_INPUT_WIDTH <
 | 
			
		||||
      appState.offsetLeft + COMMENT_INPUT_WIDTH
 | 
			
		||||
    ) {
 | 
			
		||||
      left = COMMENT_ICON_DIMENSION / 2;
 | 
			
		||||
    }
 | 
			
		||||
    if (left + COMMENT_INPUT_WIDTH > appState.width) {
 | 
			
		||||
      left = appState.width - COMMENT_INPUT_WIDTH - COMMENT_ICON_DIMENSION / 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <textarea
 | 
			
		||||
        className="comment"
 | 
			
		||||
        style={{
 | 
			
		||||
          top: `${top}px`,
 | 
			
		||||
          left: `${left}px`,
 | 
			
		||||
          position: "absolute",
 | 
			
		||||
          zIndex: 1,
 | 
			
		||||
          height: `${COMMENT_INPUT_HEIGHT}px`,
 | 
			
		||||
          width: `${COMMENT_INPUT_WIDTH}px`,
 | 
			
		||||
        }}
 | 
			
		||||
        ref={(ref) => {
 | 
			
		||||
          setTimeout(() => ref?.focus());
 | 
			
		||||
        }}
 | 
			
		||||
        placeholder={comment.value ? "Reply" : "Comment"}
 | 
			
		||||
        value={comment.value}
 | 
			
		||||
        onChange={(event) => {
 | 
			
		||||
          setComment({ ...comment, value: event.target.value });
 | 
			
		||||
        }}
 | 
			
		||||
        onBlur={saveComment}
 | 
			
		||||
        onKeyDown={(event) => {
 | 
			
		||||
          if (!event.shiftKey && event.key === KEYS.ENTER) {
 | 
			
		||||
            event.preventDefault();
 | 
			
		||||
            saveComment();
 | 
			
		||||
          }
 | 
			
		||||
        }}
 | 
			
		||||
      />
 | 
			
		||||
    );
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const renderMenu = () => {
 | 
			
		||||
    return (
 | 
			
		||||
      <MainMenu>
 | 
			
		||||
        <MainMenu.DefaultItems.SaveAsImage />
 | 
			
		||||
        <MainMenu.DefaultItems.Export />
 | 
			
		||||
        <MainMenu.Separator />
 | 
			
		||||
        <MainMenu.DefaultItems.LiveCollaborationTrigger
 | 
			
		||||
          isCollaborating={isCollaborating}
 | 
			
		||||
          onSelect={() => window.alert("You clicked on collab button")}
 | 
			
		||||
        />
 | 
			
		||||
        <MainMenu.Group title="Excalidraw links">
 | 
			
		||||
          <MainMenu.DefaultItems.Socials />
 | 
			
		||||
        </MainMenu.Group>
 | 
			
		||||
        <MainMenu.Separator />
 | 
			
		||||
        <MainMenu.ItemCustom>
 | 
			
		||||
          <button
 | 
			
		||||
            style={{ height: "2rem" }}
 | 
			
		||||
            onClick={() => window.alert("custom menu item")}
 | 
			
		||||
          >
 | 
			
		||||
            custom item
 | 
			
		||||
          </button>
 | 
			
		||||
        </MainMenu.ItemCustom>
 | 
			
		||||
        <MainMenu.DefaultItems.Help />
 | 
			
		||||
 | 
			
		||||
        {excalidrawAPI && <MobileFooter excalidrawAPI={excalidrawAPI} />}
 | 
			
		||||
      </MainMenu>
 | 
			
		||||
    );
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className="App" ref={appRef}>
 | 
			
		||||
      <h1>{appTitle}</h1>
 | 
			
		||||
      {/* TODO fix type */}
 | 
			
		||||
      <ExampleSidebar>
 | 
			
		||||
        <div className="button-wrapper">
 | 
			
		||||
          <button onClick={loadSceneOrLibrary}>Load Scene or Library</button>
 | 
			
		||||
          <button className="update-scene" onClick={updateScene}>
 | 
			
		||||
            Update Scene
 | 
			
		||||
          </button>
 | 
			
		||||
          <button
 | 
			
		||||
            className="reset-scene"
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              excalidrawAPI?.resetScene();
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Reset Scene
 | 
			
		||||
          </button>
 | 
			
		||||
          <button
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              const libraryItems: LibraryItems = [
 | 
			
		||||
                {
 | 
			
		||||
                  status: "published",
 | 
			
		||||
                  id: "1",
 | 
			
		||||
                  created: 1,
 | 
			
		||||
                  elements: initialData.libraryItems[1] as any,
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                  status: "unpublished",
 | 
			
		||||
                  id: "2",
 | 
			
		||||
                  created: 2,
 | 
			
		||||
                  elements: initialData.libraryItems[1] as any,
 | 
			
		||||
                },
 | 
			
		||||
              ];
 | 
			
		||||
              excalidrawAPI?.updateLibrary({
 | 
			
		||||
                libraryItems,
 | 
			
		||||
              });
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Update Library
 | 
			
		||||
          </button>
 | 
			
		||||
 | 
			
		||||
          <label>
 | 
			
		||||
            <input
 | 
			
		||||
              type="checkbox"
 | 
			
		||||
              checked={viewModeEnabled}
 | 
			
		||||
              onChange={() => setViewModeEnabled(!viewModeEnabled)}
 | 
			
		||||
            />
 | 
			
		||||
            View mode
 | 
			
		||||
          </label>
 | 
			
		||||
          <label>
 | 
			
		||||
            <input
 | 
			
		||||
              type="checkbox"
 | 
			
		||||
              checked={zenModeEnabled}
 | 
			
		||||
              onChange={() => setZenModeEnabled(!zenModeEnabled)}
 | 
			
		||||
            />
 | 
			
		||||
            Zen mode
 | 
			
		||||
          </label>
 | 
			
		||||
          <label>
 | 
			
		||||
            <input
 | 
			
		||||
              type="checkbox"
 | 
			
		||||
              checked={gridModeEnabled}
 | 
			
		||||
              onChange={() => setGridModeEnabled(!gridModeEnabled)}
 | 
			
		||||
            />
 | 
			
		||||
            Grid mode
 | 
			
		||||
          </label>
 | 
			
		||||
          <label>
 | 
			
		||||
            <input
 | 
			
		||||
              type="checkbox"
 | 
			
		||||
              checked={theme === "dark"}
 | 
			
		||||
              onChange={() => {
 | 
			
		||||
                setTheme(theme === "light" ? "dark" : "light");
 | 
			
		||||
              }}
 | 
			
		||||
            />
 | 
			
		||||
            Switch to Dark Theme
 | 
			
		||||
          </label>
 | 
			
		||||
          <label>
 | 
			
		||||
            <input
 | 
			
		||||
              type="checkbox"
 | 
			
		||||
              checked={disableImageTool === true}
 | 
			
		||||
              onChange={() => {
 | 
			
		||||
                setDisableImageTool(!disableImageTool);
 | 
			
		||||
              }}
 | 
			
		||||
            />
 | 
			
		||||
            Disable Image Tool
 | 
			
		||||
          </label>
 | 
			
		||||
          <label>
 | 
			
		||||
            <input
 | 
			
		||||
              type="checkbox"
 | 
			
		||||
              checked={isCollaborating}
 | 
			
		||||
              onChange={() => {
 | 
			
		||||
                if (!isCollaborating) {
 | 
			
		||||
                  const collaborators = new Map();
 | 
			
		||||
                  collaborators.set("id1", {
 | 
			
		||||
                    username: "Doremon",
 | 
			
		||||
                    avatarUrl: "images/doremon.png",
 | 
			
		||||
                  });
 | 
			
		||||
                  collaborators.set("id2", {
 | 
			
		||||
                    username: "Excalibot",
 | 
			
		||||
                    avatarUrl: "images/excalibot.png",
 | 
			
		||||
                  });
 | 
			
		||||
                  collaborators.set("id3", {
 | 
			
		||||
                    username: "Pika",
 | 
			
		||||
                    avatarUrl: "images/pika.jpeg",
 | 
			
		||||
                  });
 | 
			
		||||
                  collaborators.set("id4", {
 | 
			
		||||
                    username: "fallback",
 | 
			
		||||
                    avatarUrl: "https://example.com",
 | 
			
		||||
                  });
 | 
			
		||||
                  excalidrawAPI?.updateScene({ collaborators });
 | 
			
		||||
                } else {
 | 
			
		||||
                  excalidrawAPI?.updateScene({
 | 
			
		||||
                    collaborators: new Map(),
 | 
			
		||||
                  });
 | 
			
		||||
                }
 | 
			
		||||
                setIsCollaborating(!isCollaborating);
 | 
			
		||||
              }}
 | 
			
		||||
            />
 | 
			
		||||
            Show collaborators
 | 
			
		||||
          </label>
 | 
			
		||||
          <div>
 | 
			
		||||
            <button onClick={onCopy.bind(null, "png")}>
 | 
			
		||||
              Copy to Clipboard as PNG
 | 
			
		||||
            </button>
 | 
			
		||||
            <button onClick={onCopy.bind(null, "svg")}>
 | 
			
		||||
              Copy to Clipboard as SVG
 | 
			
		||||
            </button>
 | 
			
		||||
            <button onClick={onCopy.bind(null, "json")}>
 | 
			
		||||
              Copy to Clipboard as JSON
 | 
			
		||||
            </button>
 | 
			
		||||
          </div>
 | 
			
		||||
          <div
 | 
			
		||||
            style={{
 | 
			
		||||
              display: "flex",
 | 
			
		||||
              gap: "1em",
 | 
			
		||||
              justifyContent: "center",
 | 
			
		||||
              marginTop: "1em",
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            <div>x: {pointerData?.pointer.x ?? 0}</div>
 | 
			
		||||
            <div>y: {pointerData?.pointer.y ?? 0}</div>
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div className="excalidraw-wrapper">
 | 
			
		||||
          <Excalidraw
 | 
			
		||||
            excalidrawAPI={(api: ExcalidrawImperativeAPI) =>
 | 
			
		||||
              setExcalidrawAPI(api)
 | 
			
		||||
            }
 | 
			
		||||
            initialData={initialStatePromiseRef.current.promise}
 | 
			
		||||
            onChange={(elements, state) => {
 | 
			
		||||
              // console.info("Elements :", elements, "State : ", state);
 | 
			
		||||
            }}
 | 
			
		||||
            onPointerUpdate={(payload: {
 | 
			
		||||
              pointer: { x: number; y: number };
 | 
			
		||||
              button: "down" | "up";
 | 
			
		||||
              pointersMap: Gesture["pointers"];
 | 
			
		||||
            }) => setPointerData(payload)}
 | 
			
		||||
            viewModeEnabled={viewModeEnabled}
 | 
			
		||||
            zenModeEnabled={zenModeEnabled}
 | 
			
		||||
            gridModeEnabled={gridModeEnabled}
 | 
			
		||||
            theme={theme}
 | 
			
		||||
            name="Custom name of drawing"
 | 
			
		||||
            UIOptions={{
 | 
			
		||||
              canvasActions: {
 | 
			
		||||
                loadScene: false,
 | 
			
		||||
              },
 | 
			
		||||
              tools: { image: !disableImageTool },
 | 
			
		||||
            }}
 | 
			
		||||
            renderTopRightUI={renderTopRightUI}
 | 
			
		||||
            onLinkOpen={onLinkOpen}
 | 
			
		||||
            onPointerDown={onPointerDown}
 | 
			
		||||
            onScrollChange={rerenderCommentIcons}
 | 
			
		||||
            // allow all urls
 | 
			
		||||
            validateEmbeddable={true}
 | 
			
		||||
          >
 | 
			
		||||
            {excalidrawAPI && (
 | 
			
		||||
              <Footer>
 | 
			
		||||
                <CustomFooter excalidrawAPI={excalidrawAPI} />
 | 
			
		||||
              </Footer>
 | 
			
		||||
            )}
 | 
			
		||||
            <WelcomeScreen />
 | 
			
		||||
            <Sidebar name="custom">
 | 
			
		||||
              <Sidebar.Tabs>
 | 
			
		||||
                <Sidebar.Header />
 | 
			
		||||
                <Sidebar.Tab tab="one">Tab one!</Sidebar.Tab>
 | 
			
		||||
                <Sidebar.Tab tab="two">Tab two!</Sidebar.Tab>
 | 
			
		||||
                <Sidebar.TabTriggers>
 | 
			
		||||
                  <Sidebar.TabTrigger tab="one">One</Sidebar.TabTrigger>
 | 
			
		||||
                  <Sidebar.TabTrigger tab="two">Two</Sidebar.TabTrigger>
 | 
			
		||||
                </Sidebar.TabTriggers>
 | 
			
		||||
              </Sidebar.Tabs>
 | 
			
		||||
            </Sidebar>
 | 
			
		||||
            <Sidebar.Trigger
 | 
			
		||||
              name="custom"
 | 
			
		||||
              tab="one"
 | 
			
		||||
              style={{
 | 
			
		||||
                position: "absolute",
 | 
			
		||||
                left: "50%",
 | 
			
		||||
                transform: "translateX(-50%)",
 | 
			
		||||
                bottom: "20px",
 | 
			
		||||
                zIndex: 9999999999999999,
 | 
			
		||||
              }}
 | 
			
		||||
            >
 | 
			
		||||
              Toggle Custom Sidebar
 | 
			
		||||
            </Sidebar.Trigger>
 | 
			
		||||
            {renderMenu()}
 | 
			
		||||
            {excalidrawAPI && (
 | 
			
		||||
              <TTDDialogTrigger icon={<span>😀</span>}>
 | 
			
		||||
                Text to diagram
 | 
			
		||||
              </TTDDialogTrigger>
 | 
			
		||||
            )}
 | 
			
		||||
            <TTDDialog
 | 
			
		||||
              onTextSubmit={async (_) => {
 | 
			
		||||
                console.info("submit");
 | 
			
		||||
                // sleep for 2s
 | 
			
		||||
                await new Promise((resolve) => setTimeout(resolve, 2000));
 | 
			
		||||
                throw new Error("error, go away now");
 | 
			
		||||
                // return "dummy";
 | 
			
		||||
              }}
 | 
			
		||||
            />
 | 
			
		||||
          </Excalidraw>
 | 
			
		||||
          {Object.keys(commentIcons || []).length > 0 && renderCommentIcons()}
 | 
			
		||||
          {comment && renderComment()}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        <div className="export-wrapper button-wrapper">
 | 
			
		||||
          <label className="export-wrapper__checkbox">
 | 
			
		||||
            <input
 | 
			
		||||
              type="checkbox"
 | 
			
		||||
              checked={exportWithDarkMode}
 | 
			
		||||
              onChange={() => setExportWithDarkMode(!exportWithDarkMode)}
 | 
			
		||||
            />
 | 
			
		||||
            Export with dark mode
 | 
			
		||||
          </label>
 | 
			
		||||
          <label className="export-wrapper__checkbox">
 | 
			
		||||
            <input
 | 
			
		||||
              type="checkbox"
 | 
			
		||||
              checked={exportEmbedScene}
 | 
			
		||||
              onChange={() => setExportEmbedScene(!exportEmbedScene)}
 | 
			
		||||
            />
 | 
			
		||||
            Export with embed scene
 | 
			
		||||
          </label>
 | 
			
		||||
          <button
 | 
			
		||||
            onClick={async () => {
 | 
			
		||||
              if (!excalidrawAPI) {
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
              const svg = await exportToSvg({
 | 
			
		||||
                elements: excalidrawAPI?.getSceneElements(),
 | 
			
		||||
                appState: {
 | 
			
		||||
                  ...initialData.appState,
 | 
			
		||||
                  exportWithDarkMode,
 | 
			
		||||
                  exportEmbedScene,
 | 
			
		||||
                  width: 300,
 | 
			
		||||
                  height: 100,
 | 
			
		||||
                },
 | 
			
		||||
                files: excalidrawAPI?.getFiles(),
 | 
			
		||||
              });
 | 
			
		||||
              appRef.current.querySelector(".export-svg").innerHTML =
 | 
			
		||||
                svg.outerHTML;
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Export to SVG
 | 
			
		||||
          </button>
 | 
			
		||||
          <div className="export export-svg"></div>
 | 
			
		||||
 | 
			
		||||
          <button
 | 
			
		||||
            onClick={async () => {
 | 
			
		||||
              if (!excalidrawAPI) {
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
              const blob = await exportToBlob({
 | 
			
		||||
                elements: excalidrawAPI?.getSceneElements(),
 | 
			
		||||
                mimeType: "image/png",
 | 
			
		||||
                appState: {
 | 
			
		||||
                  ...initialData.appState,
 | 
			
		||||
                  exportEmbedScene,
 | 
			
		||||
                  exportWithDarkMode,
 | 
			
		||||
                },
 | 
			
		||||
                files: excalidrawAPI?.getFiles(),
 | 
			
		||||
              });
 | 
			
		||||
              setBlobUrl(window.URL.createObjectURL(blob));
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Export to Blob
 | 
			
		||||
          </button>
 | 
			
		||||
          <div className="export export-blob">
 | 
			
		||||
            <img src={blobUrl} alt="" />
 | 
			
		||||
          </div>
 | 
			
		||||
          <button
 | 
			
		||||
            onClick={async () => {
 | 
			
		||||
              if (!excalidrawAPI) {
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
              const canvas = await exportToCanvas({
 | 
			
		||||
                elements: excalidrawAPI.getSceneElements(),
 | 
			
		||||
                appState: {
 | 
			
		||||
                  ...initialData.appState,
 | 
			
		||||
                  exportWithDarkMode,
 | 
			
		||||
                },
 | 
			
		||||
                files: excalidrawAPI.getFiles(),
 | 
			
		||||
              });
 | 
			
		||||
              const ctx = canvas.getContext("2d")!;
 | 
			
		||||
              ctx.font = "30px Virgil";
 | 
			
		||||
              ctx.strokeText("My custom text", 50, 60);
 | 
			
		||||
              setCanvasUrl(canvas.toDataURL());
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Export to Canvas
 | 
			
		||||
          </button>
 | 
			
		||||
          <button
 | 
			
		||||
            onClick={async () => {
 | 
			
		||||
              if (!excalidrawAPI) {
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
              const canvas = await exportToCanvas({
 | 
			
		||||
                elements: excalidrawAPI.getSceneElements(),
 | 
			
		||||
                appState: {
 | 
			
		||||
                  ...initialData.appState,
 | 
			
		||||
                  exportWithDarkMode,
 | 
			
		||||
                },
 | 
			
		||||
                files: excalidrawAPI.getFiles(),
 | 
			
		||||
              });
 | 
			
		||||
              const ctx = canvas.getContext("2d")!;
 | 
			
		||||
              ctx.font = "30px Virgil";
 | 
			
		||||
              ctx.strokeText("My custom text", 50, 60);
 | 
			
		||||
              setCanvasUrl(canvas.toDataURL());
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Export to Canvas
 | 
			
		||||
          </button>
 | 
			
		||||
          <button
 | 
			
		||||
            type="button"
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              if (!excalidrawAPI) {
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              const elements = excalidrawAPI.getSceneElements();
 | 
			
		||||
              excalidrawAPI.scrollToContent(elements[0], {
 | 
			
		||||
                fitToViewport: true,
 | 
			
		||||
              });
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Fit to viewport, first element
 | 
			
		||||
          </button>
 | 
			
		||||
          <button
 | 
			
		||||
            type="button"
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              if (!excalidrawAPI) {
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              const elements = excalidrawAPI.getSceneElements();
 | 
			
		||||
              excalidrawAPI.scrollToContent(elements[0], {
 | 
			
		||||
                fitToContent: true,
 | 
			
		||||
              });
 | 
			
		||||
 | 
			
		||||
              excalidrawAPI.scrollToContent(elements[0], {
 | 
			
		||||
                fitToContent: true,
 | 
			
		||||
              });
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Fit to content, first element
 | 
			
		||||
          </button>
 | 
			
		||||
          <button
 | 
			
		||||
            type="button"
 | 
			
		||||
            onClick={() => {
 | 
			
		||||
              if (!excalidrawAPI) {
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              const elements = excalidrawAPI.getSceneElements();
 | 
			
		||||
              excalidrawAPI.scrollToContent(elements[0], {
 | 
			
		||||
                fitToContent: true,
 | 
			
		||||
              });
 | 
			
		||||
 | 
			
		||||
              excalidrawAPI.scrollToContent(elements[0]);
 | 
			
		||||
            }}
 | 
			
		||||
          >
 | 
			
		||||
            Scroll to first element, no fitToContent, no fitToViewport
 | 
			
		||||
          </button>
 | 
			
		||||
          <div className="export export-canvas">
 | 
			
		||||
            <img src={canvasUrl} alt="" />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </ExampleSidebar>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -1,73 +0,0 @@
 | 
			
		||||
import type { ExcalidrawImperativeAPI } from "../types";
 | 
			
		||||
 | 
			
		||||
const { Button, MIME_TYPES } = window.ExcalidrawLib;
 | 
			
		||||
const COMMENT_SVG = (
 | 
			
		||||
  <svg
 | 
			
		||||
    xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
    width="24"
 | 
			
		||||
    height="24"
 | 
			
		||||
    viewBox="0 0 24 24"
 | 
			
		||||
    fill="none"
 | 
			
		||||
    stroke="currentColor"
 | 
			
		||||
    strokeWidth="2"
 | 
			
		||||
    strokeLinecap="round"
 | 
			
		||||
    strokeLinejoin="round"
 | 
			
		||||
    className="feather feather-message-circle"
 | 
			
		||||
  >
 | 
			
		||||
    <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
 | 
			
		||||
  </svg>
 | 
			
		||||
);
 | 
			
		||||
const CustomFooter = ({
 | 
			
		||||
  excalidrawAPI,
 | 
			
		||||
}: {
 | 
			
		||||
  excalidrawAPI: ExcalidrawImperativeAPI;
 | 
			
		||||
}) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <Button
 | 
			
		||||
        onSelect={() => alert("General Kenobi!")}
 | 
			
		||||
        className="you are a bold one"
 | 
			
		||||
        style={{ marginLeft: "1rem" }}
 | 
			
		||||
        title="Hello there!"
 | 
			
		||||
      >
 | 
			
		||||
        {COMMENT_SVG}
 | 
			
		||||
      </Button>
 | 
			
		||||
      <button
 | 
			
		||||
        className="custom-element"
 | 
			
		||||
        onClick={() => {
 | 
			
		||||
          excalidrawAPI?.setActiveTool({
 | 
			
		||||
            type: "custom",
 | 
			
		||||
            customType: "comment",
 | 
			
		||||
          });
 | 
			
		||||
          const url = `data:${MIME_TYPES.svg},${encodeURIComponent(
 | 
			
		||||
            `<svg
 | 
			
		||||
    xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
    width="24"
 | 
			
		||||
    height="24"
 | 
			
		||||
    viewBox="0 0 24 24"
 | 
			
		||||
    fill="none"
 | 
			
		||||
    stroke="currentColor"
 | 
			
		||||
    stroke-width="2"
 | 
			
		||||
    stroke-linecap="round"
 | 
			
		||||
    stroke-linejoin="round"
 | 
			
		||||
    class="feather feather-message-circle"
 | 
			
		||||
  >
 | 
			
		||||
    <path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
 | 
			
		||||
  </svg>`,
 | 
			
		||||
          )}`;
 | 
			
		||||
          excalidrawAPI?.setCursor(`url(${url}), auto`);
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        {COMMENT_SVG}
 | 
			
		||||
      </button>
 | 
			
		||||
      <button
 | 
			
		||||
        className="custom-footer"
 | 
			
		||||
        onClick={() => alert("This is dummy footer")}
 | 
			
		||||
      >
 | 
			
		||||
        custom footer
 | 
			
		||||
      </button>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default CustomFooter;
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
import type { ExcalidrawImperativeAPI } from "../types";
 | 
			
		||||
import CustomFooter from "./CustomFooter";
 | 
			
		||||
const { useDevice, Footer } = window.ExcalidrawLib;
 | 
			
		||||
 | 
			
		||||
const MobileFooter = ({
 | 
			
		||||
  excalidrawAPI,
 | 
			
		||||
}: {
 | 
			
		||||
  excalidrawAPI: ExcalidrawImperativeAPI;
 | 
			
		||||
}) => {
 | 
			
		||||
  const device = useDevice();
 | 
			
		||||
  if (device.editor.isMobile) {
 | 
			
		||||
    return (
 | 
			
		||||
      <Footer>
 | 
			
		||||
        <CustomFooter excalidrawAPI={excalidrawAPI} />
 | 
			
		||||
      </Footer>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
  return null;
 | 
			
		||||
};
 | 
			
		||||
export default MobileFooter;
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
import App from "./App";
 | 
			
		||||
 | 
			
		||||
const { StrictMode } = window.React;
 | 
			
		||||
//@ts-ignore
 | 
			
		||||
const { createRoot } = window.ReactDOM;
 | 
			
		||||
 | 
			
		||||
const rootElement = document.getElementById("root")!;
 | 
			
		||||
const root = createRoot(rootElement);
 | 
			
		||||
 | 
			
		||||
root.render(
 | 
			
		||||
  <StrictMode>
 | 
			
		||||
    <App
 | 
			
		||||
      appTitle={"Excalidraw Example"}
 | 
			
		||||
      useCustom={(api: any, args?: any[]) => {}}
 | 
			
		||||
    />
 | 
			
		||||
  </StrictMode>,
 | 
			
		||||
);
 | 
			
		||||
@@ -1,994 +0,0 @@
 | 
			
		||||
import type { ExcalidrawElementSkeleton } from "../data/transform";
 | 
			
		||||
import type { FileId } from "../element/types";
 | 
			
		||||
 | 
			
		||||
const elements: ExcalidrawElementSkeleton[] = [
 | 
			
		||||
  {
 | 
			
		||||
    type: "rectangle",
 | 
			
		||||
    x: 10,
 | 
			
		||||
    y: 10,
 | 
			
		||||
    strokeWidth: 2,
 | 
			
		||||
    id: "1",
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    type: "diamond",
 | 
			
		||||
    x: 120,
 | 
			
		||||
    y: 20,
 | 
			
		||||
    backgroundColor: "#fff3bf",
 | 
			
		||||
    strokeWidth: 2,
 | 
			
		||||
    label: {
 | 
			
		||||
      text: "HELLO EXCALIDRAW",
 | 
			
		||||
      strokeColor: "#099268",
 | 
			
		||||
      fontSize: 30,
 | 
			
		||||
    },
 | 
			
		||||
    id: "2",
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    type: "arrow",
 | 
			
		||||
    x: 100,
 | 
			
		||||
    y: 200,
 | 
			
		||||
    label: { text: "HELLO WORLD!!" },
 | 
			
		||||
    start: { type: "rectangle" },
 | 
			
		||||
    end: { type: "ellipse" },
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    type: "image",
 | 
			
		||||
    x: 606.1042326312408,
 | 
			
		||||
    y: 153.57729779411773,
 | 
			
		||||
    width: 230,
 | 
			
		||||
    height: 230,
 | 
			
		||||
    fileId: "rocket" as FileId,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    type: "frame",
 | 
			
		||||
    children: ["1", "2"],
 | 
			
		||||
    name: "My frame",
 | 
			
		||||
  },
 | 
			
		||||
];
 | 
			
		||||
export default {
 | 
			
		||||
  elements,
 | 
			
		||||
  appState: { viewBackgroundColor: "#AFEEEE", currentItemFontFamily: 1 },
 | 
			
		||||
  scrollToContent: true,
 | 
			
		||||
  libraryItems: [
 | 
			
		||||
    [
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
 | 
			
		||||
        x: 209.72304760646858,
 | 
			
		||||
        y: 338.83587294718825,
 | 
			
		||||
        strokeColor: "#881fa3",
 | 
			
		||||
        backgroundColor: "#be4bdb",
 | 
			
		||||
        width: 116.42036295658873,
 | 
			
		||||
        height: 103.65107323746608,
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
        points: [
 | 
			
		||||
          [-92.28090097254909, 7.105427357601002e-15],
 | 
			
		||||
          [-154.72281841151394, 19.199290805487394],
 | 
			
		||||
          [-155.45758928571422, 79.43840749607878],
 | 
			
		||||
          [-99.89923520113778, 103.6510732374661],
 | 
			
		||||
          [-40.317783799181804, 79.1587107641305],
 | 
			
		||||
          [-39.037226329125524, 21.285677238400705],
 | 
			
		||||
          [-92.28090097254909, 7.105427357601002e-15],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        x: -249.48446738689245,
 | 
			
		||||
        y: 374.851387389359,
 | 
			
		||||
        strokeColor: "#0a11d3",
 | 
			
		||||
        backgroundColor: "#228be6",
 | 
			
		||||
        width: 88.21658171083376,
 | 
			
		||||
        height: 113.8575037534261,
 | 
			
		||||
        groupIds: ["N2YAi9nU-wlRb0rDaDZoe"],
 | 
			
		||||
        points: [
 | 
			
		||||
          [-0.22814350714115691, -43.414939319563715],
 | 
			
		||||
          [0.06274947619197979, 42.63794490105306],
 | 
			
		||||
          [-0.21453039840335475, 52.43469208825097],
 | 
			
		||||
          [4.315205554872581, 56.66774540453215],
 | 
			
		||||
          [20.089784992984285, 60.25027917349701],
 | 
			
		||||
          [46.7532926683984, 61.365826671969444],
 | 
			
		||||
          [72.22851104292477, 59.584691681394986],
 | 
			
		||||
          [85.76368213524371, 55.325139565662596],
 | 
			
		||||
          [87.67263486434864, 51.7342924478499],
 | 
			
		||||
          [87.94074036468018, 43.84700272879395],
 | 
			
		||||
          [87.73030872197806, -36.195582644606276],
 | 
			
		||||
          [87.2559282533682, -43.758132174307036],
 | 
			
		||||
          [81.5915337527493, -47.984890854524416],
 | 
			
		||||
          [69.66352776578219, -50.4328058257654],
 | 
			
		||||
          [42.481213744224995, -52.49167708145666],
 | 
			
		||||
          [20.68789182864576, -51.26396751574663],
 | 
			
		||||
          [3.5475921483286084, -47.099726468136254],
 | 
			
		||||
          [-0.2758413461535838, -43.46664538034193],
 | 
			
		||||
          [-0.22814350714115691, -43.414939319563715],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -249.02524930453623,
 | 
			
		||||
        y: 398.8804363713438,
 | 
			
		||||
        strokeColor: "#0a11d3",
 | 
			
		||||
        backgroundColor: "transparent",
 | 
			
		||||
        width: 88.30808627974527,
 | 
			
		||||
        height: 9.797916664247975,
 | 
			
		||||
        seed: 683951089,
 | 
			
		||||
        groupIds: ["N2YAi9nU-wlRb0rDaDZoe"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, -2.1538602707609424],
 | 
			
		||||
          [2.326538897826852, 1.751753055375216],
 | 
			
		||||
          [12.359939318521995, 5.028526743934819],
 | 
			
		||||
          [25.710950037209347, 7.012921076245119],
 | 
			
		||||
          [46.6269757640547, 7.193749997581346],
 | 
			
		||||
          [71.03526003420632, 5.930375670950649],
 | 
			
		||||
          [85.2899738827162, 1.3342483900732343],
 | 
			
		||||
          [88.30808627974527, -2.6041666666666288],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -250.11899081659772,
 | 
			
		||||
        y: 365.80628180927204,
 | 
			
		||||
        strokeColor: "#0a11d3",
 | 
			
		||||
        backgroundColor: "transparent",
 | 
			
		||||
        width: 88.30808627974527,
 | 
			
		||||
        height: 9.797916664247975,
 | 
			
		||||
        seed: 1817746897,
 | 
			
		||||
        groupIds: ["N2YAi9nU-wlRb0rDaDZoe"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, -2.1538602707609424],
 | 
			
		||||
          [2.326538897826852, 1.751753055375216],
 | 
			
		||||
          [12.359939318521995, 5.028526743934819],
 | 
			
		||||
          [25.710950037209347, 7.012921076245119],
 | 
			
		||||
          [46.6269757640547, 7.193749997581346],
 | 
			
		||||
          [71.03526003420632, 5.930375670950649],
 | 
			
		||||
          [85.2899738827162, 1.3342483900732343],
 | 
			
		||||
          [88.30808627974527, -2.6041666666666288],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -251.23981350275943,
 | 
			
		||||
        y: 323.4117518426986,
 | 
			
		||||
        strokeColor: "#0a11d3",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 87.65074610854188,
 | 
			
		||||
        height: 17.72670397681366,
 | 
			
		||||
        seed: 1409727409,
 | 
			
		||||
        groupIds: ["N2YAi9nU-wlRb0rDaDZoe"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
        boundElementIds: ["bxuMGTzXLn7H-uBCptINx"],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -179.73008120217884,
 | 
			
		||||
        y: 347.98755471983213,
 | 
			
		||||
        strokeColor: "#0a11d3",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 12.846057046979809,
 | 
			
		||||
        height: 13.941904362416096,
 | 
			
		||||
        seed: 1073094033,
 | 
			
		||||
        groupIds: ["N2YAi9nU-wlRb0rDaDZoe"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -179.73008120217884,
 | 
			
		||||
        y: 378.5900085788926,
 | 
			
		||||
        strokeColor: "#0a11d3",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 12.846057046979809,
 | 
			
		||||
        height: 13.941904362416096,
 | 
			
		||||
        seed: 526271345,
 | 
			
		||||
        groupIds: ["N2YAi9nU-wlRb0rDaDZoe"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -179.73008120217884,
 | 
			
		||||
        y: 411.8508097533892,
 | 
			
		||||
        strokeColor: "#0a11d3",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 12.846057046979809,
 | 
			
		||||
        height: 13.941904362416096,
 | 
			
		||||
        seed: 243707217,
 | 
			
		||||
        groupIds: ["N2YAi9nU-wlRb0rDaDZoe"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      {
 | 
			
		||||
        type: "diamond",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -109.55894395256101,
 | 
			
		||||
        y: 381.22641397493356,
 | 
			
		||||
        strokeColor: "#c92a2a",
 | 
			
		||||
        backgroundColor: "#fd8888",
 | 
			
		||||
        width: 112.64736525303451,
 | 
			
		||||
        height: 36.77344700318558,
 | 
			
		||||
        seed: 511870335,
 | 
			
		||||
        groupIds: ["M6ByXuSmtHCr3RtPPKJQh"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "diamond",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -109.55894395256101,
 | 
			
		||||
        y: 372.354634046675,
 | 
			
		||||
        strokeColor: "#c92a2a",
 | 
			
		||||
        backgroundColor: "#fd8888",
 | 
			
		||||
        width: 112.64736525303451,
 | 
			
		||||
        height: 36.77344700318558,
 | 
			
		||||
        seed: 1283079231,
 | 
			
		||||
        groupIds: ["M6ByXuSmtHCr3RtPPKJQh"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "diamond",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -109.55894395256101,
 | 
			
		||||
        y: 359.72407445196296,
 | 
			
		||||
        strokeColor: "#c92a2a",
 | 
			
		||||
        backgroundColor: "#fd8888",
 | 
			
		||||
        width: 112.64736525303451,
 | 
			
		||||
        height: 36.77344700318558,
 | 
			
		||||
        seed: 996251633,
 | 
			
		||||
        groupIds: ["M6ByXuSmtHCr3RtPPKJQh"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "diamond",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -109.55894395256101,
 | 
			
		||||
        y: 347.1924021546656,
 | 
			
		||||
        strokeColor: "#c92a2a",
 | 
			
		||||
        backgroundColor: "#fd8888",
 | 
			
		||||
        width: 112.64736525303451,
 | 
			
		||||
        height: 36.77344700318558,
 | 
			
		||||
        seed: 1764842481,
 | 
			
		||||
        groupIds: ["M6ByXuSmtHCr3RtPPKJQh"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        fillStyle: "hachure",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 1.5707963267948957,
 | 
			
		||||
        x: -471.6208001976387,
 | 
			
		||||
        y: 520.7681448415112,
 | 
			
		||||
        strokeColor: "#087f5b",
 | 
			
		||||
        backgroundColor: "#40c057",
 | 
			
		||||
        width: 52.317507746132115,
 | 
			
		||||
        height: 154.56722543646003,
 | 
			
		||||
        seed: 1424381745,
 | 
			
		||||
        groupIds: ["HSrtfEf-CssQTf160Fb6R"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [-0.24755378372925183, -40.169554027464216],
 | 
			
		||||
          [-0.07503751055611152, 76.6515171914404],
 | 
			
		||||
          [-0.23948042713317108, 89.95108885873196],
 | 
			
		||||
          [2.446913573036335, 95.69766931810295],
 | 
			
		||||
          [11.802146636255692, 100.56113713047068],
 | 
			
		||||
          [27.615140546177496, 102.07554835500338],
 | 
			
		||||
          [42.72341054254274, 99.65756899883291],
 | 
			
		||||
          [50.75054563137204, 93.87501510096598],
 | 
			
		||||
          [51.88266441510958, 89.00026150397161],
 | 
			
		||||
          [52.04166639997853, 78.29287333983132],
 | 
			
		||||
          [51.916868330459295, -30.36891819848148],
 | 
			
		||||
          [51.635533423123285, -40.63545540065934],
 | 
			
		||||
          [48.27622163143906, -46.37349057843314],
 | 
			
		||||
          [41.202227904674494, -49.69665692879073],
 | 
			
		||||
          [25.081551986374073, -52.49167708145666],
 | 
			
		||||
          [12.15685839679867, -50.825000270901],
 | 
			
		||||
          [1.9916746648394732, -45.171835889467935],
 | 
			
		||||
          [-0.2758413461535838, -40.23974757720194],
 | 
			
		||||
          [-0.24755378372925183, -40.169554027464216],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        version: 2405,
 | 
			
		||||
        versionNonce: 2120341087,
 | 
			
		||||
        isDeleted: false,
 | 
			
		||||
        id: "TYsYe2VvJ60T_yKa3kyOw",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 1.5707963267948957,
 | 
			
		||||
        x: -496.3957643857249,
 | 
			
		||||
        y: 541.7241190920508,
 | 
			
		||||
        strokeColor: "#087f5b",
 | 
			
		||||
        backgroundColor: "transparent",
 | 
			
		||||
        width: 50.7174766392476,
 | 
			
		||||
        height: 12.698053371678215,
 | 
			
		||||
        seed: 726657713,
 | 
			
		||||
        groupIds: ["HSrtfEf-CssQTf160Fb6R"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, -2.0205717204386002],
 | 
			
		||||
          [1.3361877396713384, 3.0410845646550486],
 | 
			
		||||
          [7.098613049589299, 7.287767671898479],
 | 
			
		||||
          [14.766422451441104, 9.859533283467512],
 | 
			
		||||
          [26.779003528407447, 10.093886705011586],
 | 
			
		||||
          [40.79727342221974, 8.456559589697127],
 | 
			
		||||
          [48.98410145879092, 2.500000505196364],
 | 
			
		||||
          [50.7174766392476, -2.6041666666666288],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 1.5707963267948957,
 | 
			
		||||
        x: -450.969983237283,
 | 
			
		||||
        y: 542.1789894334747,
 | 
			
		||||
        strokeColor: "#087f5b",
 | 
			
		||||
        backgroundColor: "transparent",
 | 
			
		||||
        width: 50.57247907260371,
 | 
			
		||||
        height: 10.178760037658167,
 | 
			
		||||
        seed: 1977326481,
 | 
			
		||||
        groupIds: ["HSrtfEf-CssQTf160Fb6R"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, -2.136356936862347],
 | 
			
		||||
          [1.332367676378171, 1.9210669226078037],
 | 
			
		||||
          [7.078318632616268, 5.325208253515953],
 | 
			
		||||
          [14.724206326638113, 7.386735659885842],
 | 
			
		||||
          [26.70244431044034, 7.574593370991538],
 | 
			
		||||
          [40.68063699304561, 6.262111896696538],
 | 
			
		||||
          [48.84405948536458, 1.4873339211608216],
 | 
			
		||||
          [50.57247907260371, -2.6041666666666288],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 1.5707963267948957,
 | 
			
		||||
        x: -404.36521010516793,
 | 
			
		||||
        y: 534.1894365757241,
 | 
			
		||||
        strokeColor: "#087f5b",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 51.27812853552538,
 | 
			
		||||
        height: 22.797152568995934,
 | 
			
		||||
        seed: 1774660383,
 | 
			
		||||
        groupIds: ["HSrtfEf-CssQTf160Fb6R"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
        boundElementIds: ["bxuMGTzXLn7H-uBCptINx"],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      {
 | 
			
		||||
        type: "rectangle",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 2,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -393.3000561423187,
 | 
			
		||||
        y: 338.9742643666818,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 70.67858069123133,
 | 
			
		||||
        height: 107.25081879410921,
 | 
			
		||||
        seed: 371096063,
 | 
			
		||||
        groupIds: ["9ppmKFUbA4iKjt8FaDFox"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
        boundElementIds: [
 | 
			
		||||
          "CFu0B4Mw_1wC1Hbgx8Fs0",
 | 
			
		||||
          "XIl_NhaFtRO00pX5Pq6VU",
 | 
			
		||||
          "EndiSTFlx1AT7vcBVjgve",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "rectangle",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 2,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -400.8474891780329,
 | 
			
		||||
        y: 331.95417508096745,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 70.67858069123133,
 | 
			
		||||
        height: 107.25081879410921,
 | 
			
		||||
        seed: 685932433,
 | 
			
		||||
        groupIds: ["0RJwA-yKP5dqk5oMiSeot", "9ppmKFUbA4iKjt8FaDFox"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
        boundElementIds: [
 | 
			
		||||
          "CFu0B4Mw_1wC1Hbgx8Fs0",
 | 
			
		||||
          "XIl_NhaFtRO00pX5Pq6VU",
 | 
			
		||||
          "EndiSTFlx1AT7vcBVjgve",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "rectangle",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 2,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -410.24257846374826,
 | 
			
		||||
        y: 323.7002688309677,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 70.67858069123133,
 | 
			
		||||
        height: 107.25081879410921,
 | 
			
		||||
        seed: 58634943,
 | 
			
		||||
        groupIds: ["9ppmKFUbA4iKjt8FaDFox"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
        boundElementIds: [
 | 
			
		||||
          "CFu0B4Mw_1wC1Hbgx8Fs0",
 | 
			
		||||
          "XIl_NhaFtRO00pX5Pq6VU",
 | 
			
		||||
          "EndiSTFlx1AT7vcBVjgve",
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "draw",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -398.2561518768373,
 | 
			
		||||
        y: 371.84603609547054,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 46.57983585730082,
 | 
			
		||||
        height: 3.249953844290203,
 | 
			
		||||
        seed: 1673003743,
 | 
			
		||||
        groupIds: ["9ppmKFUbA4iKjt8FaDFox"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, 0.6014697828497827],
 | 
			
		||||
          [40.42449133807562, 0.7588628355182573],
 | 
			
		||||
          [46.57983585730082, -2.491091008771946],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "draw",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -396.400899638823,
 | 
			
		||||
        y: 340.9822185794818,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 45.567415680676426,
 | 
			
		||||
        height: 2.8032978840147194,
 | 
			
		||||
        seed: 1821527807,
 | 
			
		||||
        groupIds: ["9ppmKFUbA4iKjt8FaDFox"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, 0],
 | 
			
		||||
          [16.832548902953302, -2.8032978840147194],
 | 
			
		||||
          [45.567415680676426, -0.3275477042019195],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "draw",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -396.4774991551924,
 | 
			
		||||
        y: 408.37659284983897,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 48.33668263438425,
 | 
			
		||||
        height: 4.280657518731036,
 | 
			
		||||
        seed: 1485707039,
 | 
			
		||||
        groupIds: ["9ppmKFUbA4iKjt8FaDFox"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, 0],
 | 
			
		||||
          [26.41225578429045, -0.2552319773002338],
 | 
			
		||||
          [37.62000339651456, 2.3153712935189787],
 | 
			
		||||
          [48.33668263438425, -1.9652862252120569],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "draw",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -399.6615463367227,
 | 
			
		||||
        y: 419.61974125811776,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 54.40694982784246,
 | 
			
		||||
        height: 2.9096445412231735,
 | 
			
		||||
        seed: 1042012991,
 | 
			
		||||
        groupIds: ["9ppmKFUbA4iKjt8FaDFox"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, 0],
 | 
			
		||||
          [10.166093050596771, -1.166642430373031],
 | 
			
		||||
          [16.130660965377448, -0.8422655250909383],
 | 
			
		||||
          [46.26079588567538, 0.6125567455206506],
 | 
			
		||||
          [54.40694982784246, -2.297087795702523],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "draw",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -399.3767034411569,
 | 
			
		||||
        y: 356.042820132743,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 46.92865289294453,
 | 
			
		||||
        height: 2.4757501798128,
 | 
			
		||||
        seed: 295443295,
 | 
			
		||||
        groupIds: ["9ppmKFUbA4iKjt8FaDFox"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, 0],
 | 
			
		||||
          [18.193786115221407, -0.5912874140789839],
 | 
			
		||||
          [46.92865289294453, 1.884462765733816],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "draw",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -399.26921524500654,
 | 
			
		||||
        y: 390.5261491685826,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 46.92865289294453,
 | 
			
		||||
        height: 2.4757501798128,
 | 
			
		||||
        seed: 1734301567,
 | 
			
		||||
        groupIds: ["9ppmKFUbA4iKjt8FaDFox"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, 0],
 | 
			
		||||
          [8.093938105125233, 1.4279702913643746],
 | 
			
		||||
          [18.193786115221407, -0.5912874140789839],
 | 
			
		||||
          [46.92865289294453, 1.884462765733816],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      {
 | 
			
		||||
        type: "rectangle",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -593.9896997899341,
 | 
			
		||||
        y: 343.9798351106279,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "transparent",
 | 
			
		||||
        width: 127.88383573213892,
 | 
			
		||||
        height: 76.53703389977764,
 | 
			
		||||
        seed: 106569279,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -595.0652975408293,
 | 
			
		||||
        y: 354.6963695028721,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "transparent",
 | 
			
		||||
        width: 128.84193229844433,
 | 
			
		||||
        height: 0,
 | 
			
		||||
        seed: 73916127,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, 0],
 | 
			
		||||
          [128.84193229844433, 0],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 0,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -589.5016643209792,
 | 
			
		||||
        y: 348.2514049106367,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fa5252",
 | 
			
		||||
        width: 5.001953125,
 | 
			
		||||
        height: 5.001953125,
 | 
			
		||||
        seed: 387857791,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 0,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -579.2389690084792,
 | 
			
		||||
        y: 348.2514049106367,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fab005",
 | 
			
		||||
        width: 5.001953125,
 | 
			
		||||
        height: 5.001953125,
 | 
			
		||||
        seed: 1486370207,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 0,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -568.525552542133,
 | 
			
		||||
        y: 348.7021260644829,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#40c057",
 | 
			
		||||
        width: 5.001953125,
 | 
			
		||||
        height: 5.001953125,
 | 
			
		||||
        seed: 610150847,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 90,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -552.4984915525058,
 | 
			
		||||
        y: 364.75449494249875,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#04aaf7",
 | 
			
		||||
        width: 42.72020253937572,
 | 
			
		||||
        height: 42.72020253937572,
 | 
			
		||||
        seed: 144280593,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "draw",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        x: -530.327851842306,
 | 
			
		||||
        y: 378.9357912947449,
 | 
			
		||||
        strokeColor: "#087f5b",
 | 
			
		||||
        backgroundColor: "#40c057",
 | 
			
		||||
        width: 28.226201983883442,
 | 
			
		||||
        height: 24.44112284281997,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
        points: [
 | 
			
		||||
          [4.907524351775825, 2.043055712211473],
 | 
			
		||||
          [3.0769604829149455, 1.6284171290602836],
 | 
			
		||||
          [-2.66472604008681, -4.228569719133945],
 | 
			
		||||
          [-6.450168189798415, -2.304577297733668],
 | 
			
		||||
          [-7.704241049212052, 4.416384506147983],
 | 
			
		||||
          [-6.361372181234263, 8.783101300254884],
 | 
			
		||||
          [-12.516984713388897, 10.9291595737194],
 | 
			
		||||
          [-12.295677738198286, 15.686226498407976],
 | 
			
		||||
          [-7.473371426945252, 15.393030178104425],
 | 
			
		||||
          [-3.787654025313423, 11.5207568827343],
 | 
			
		||||
          [1.2873793872375165, 19.910682356036197],
 | 
			
		||||
          [4.492232250183542, 20.212553123686025],
 | 
			
		||||
          [1.1302787567009416, 6.843494873631317],
 | 
			
		||||
          [6.294108177816019, 6.390688722156585],
 | 
			
		||||
          [8.070028349098962, 7.910451897221202],
 | 
			
		||||
          [14.143675334886687, 7.910451897221202],
 | 
			
		||||
          [15.709217270494545, 2.6780252579576427],
 | 
			
		||||
          [9.128749989671498, 3.1533849725326517],
 | 
			
		||||
          [10.393751588600717, -3.7167773257046695],
 | 
			
		||||
          [7.380151667177483, -3.30213874255348],
 | 
			
		||||
          [4.669824267311791, 1.1200945145694894],
 | 
			
		||||
          [4.907524351775825, 2.043055712211473],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 90,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -551.4394290784783,
 | 
			
		||||
        y: 385.71736850567976,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#99bcff",
 | 
			
		||||
        width: 42.095115772272244,
 | 
			
		||||
        height: 0,
 | 
			
		||||
        seed: 1443027377,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, 0],
 | 
			
		||||
          [42.095115772272244, 0],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 0,
 | 
			
		||||
        opacity: 90,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -546.3441000487039,
 | 
			
		||||
        y: 372.6245229061568,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#99bcff",
 | 
			
		||||
        width: 29.31860660384862,
 | 
			
		||||
        height: 5.711199931375845,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, -2.341683327443203],
 | 
			
		||||
          [0.7724193963150375, -0.06510358900749044],
 | 
			
		||||
          [4.103544916365185, 1.84492589414448],
 | 
			
		||||
          [8.536129150893453, 3.0016281808630056],
 | 
			
		||||
          [15.480325949120388, 3.1070332647092163],
 | 
			
		||||
          [23.583965316012858, 2.3706131055211244],
 | 
			
		||||
          [28.316582284417855, -0.3084668090492442],
 | 
			
		||||
          [29.31860660384862, -2.6041666666666288],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 90,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -538.2701841247845,
 | 
			
		||||
        y: 363.37196531290607,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "transparent",
 | 
			
		||||
        width: 15.528434353116108,
 | 
			
		||||
        height: 44.82230388130942,
 | 
			
		||||
        seed: 683572113,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "line",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        opacity: 90,
 | 
			
		||||
        x: -544.828148539078,
 | 
			
		||||
        y: 402.0199316371545,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#99bcff",
 | 
			
		||||
        width: 29.31860660384862,
 | 
			
		||||
        height: 5.896061363392446,
 | 
			
		||||
        seed: 318798801,
 | 
			
		||||
        groupIds: ["TC0RSM64Cxmu17MlE12-o"],
 | 
			
		||||
        strokeSharpness: "round",
 | 
			
		||||
 | 
			
		||||
        points: [
 | 
			
		||||
          [0, 0],
 | 
			
		||||
          [4.103544916365185, -4.322122351104391],
 | 
			
		||||
          [8.536129150893453, -5.516265043290966],
 | 
			
		||||
          [15.480325949120388, -5.625081903117008],
 | 
			
		||||
          [23.583965316012858, -4.8648251269605955],
 | 
			
		||||
          [28.316582284417855, -2.0990281379671547],
 | 
			
		||||
          [29.31860660384862, 0.2709794602754383],
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
    [
 | 
			
		||||
      {
 | 
			
		||||
        type: "rectangle",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -715.1043446306466,
 | 
			
		||||
        y: 330.4231266309418,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#ced4da",
 | 
			
		||||
        width: 70.81644178885557,
 | 
			
		||||
        height: 108.30428902193904,
 | 
			
		||||
        seed: 1914896753,
 | 
			
		||||
        groupIds: ["GMZ-NW9lG7c1AtfBInZ0n"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "rectangle",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -706.996640540555,
 | 
			
		||||
        y: 338.68030798133873,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 55.801163535143246,
 | 
			
		||||
        height: 82.83278895375764,
 | 
			
		||||
        seed: 1306468145,
 | 
			
		||||
        groupIds: ["GMZ-NW9lG7c1AtfBInZ0n"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "ellipse",
 | 
			
		||||
        fillStyle: "solid",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -684.8099707762028,
 | 
			
		||||
        y: 425.0579911039235,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fff",
 | 
			
		||||
        width: 11.427824006438863,
 | 
			
		||||
        height: 11.427824006438863,
 | 
			
		||||
        seed: 93422161,
 | 
			
		||||
        groupIds: ["GMZ-NW9lG7c1AtfBInZ0n"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "rectangle",
 | 
			
		||||
        fillStyle: "cross-hatch",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        roughness: 1,
 | 
			
		||||
        opacity: 100,
 | 
			
		||||
        angle: 0,
 | 
			
		||||
        x: -698.7169501405845,
 | 
			
		||||
        y: 349.2244646574789,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fab005",
 | 
			
		||||
        width: 39.2417827352022,
 | 
			
		||||
        height: 19.889460471185775,
 | 
			
		||||
        seed: 11646495,
 | 
			
		||||
        groupIds: ["GMZ-NW9lG7c1AtfBInZ0n"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        type: "rectangle",
 | 
			
		||||
        fillStyle: "cross-hatch",
 | 
			
		||||
        strokeWidth: 1,
 | 
			
		||||
        strokeStyle: "solid",
 | 
			
		||||
        x: -698.7169501405845,
 | 
			
		||||
        y: 384.7822247024333,
 | 
			
		||||
        strokeColor: "#000000",
 | 
			
		||||
        backgroundColor: "#fab005",
 | 
			
		||||
        width: 39.2417827352022,
 | 
			
		||||
        height: 19.889460471185775,
 | 
			
		||||
        seed: 291717649,
 | 
			
		||||
        groupIds: ["GMZ-NW9lG7c1AtfBInZ0n"],
 | 
			
		||||
        strokeSharpness: "sharp",
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 197 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 30 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 6.1 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 39 KiB  | 
@@ -1,32 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="utf-8" />
 | 
			
		||||
    <meta
 | 
			
		||||
      name="viewport"
 | 
			
		||||
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
 | 
			
		||||
    />
 | 
			
		||||
    <meta name="theme-color" content="#000000" />
 | 
			
		||||
 | 
			
		||||
    <title>React App</title>
 | 
			
		||||
    <script>
 | 
			
		||||
      window.name = "codesandbox";
 | 
			
		||||
    </script>
 | 
			
		||||
    <link rel="stylesheet" href="/dist/browser/dev/index.css" />
 | 
			
		||||
    <link rel="stylesheet" href="bundle.css" />
 | 
			
		||||
  </head>
 | 
			
		||||
 | 
			
		||||
  <body>
 | 
			
		||||
    <noscript> You need to enable JavaScript to run this app. </noscript>
 | 
			
		||||
    <div id="root"></div>
 | 
			
		||||
    <script src="https://unpkg.com/react@18.2.0/umd/react.development.js"></script>
 | 
			
		||||
    <script src="https://unpkg.com/react-dom@18.2.0/umd/react-dom.development.js"></script>
 | 
			
		||||
    <!-- This is so that we use the bundled excalidraw.development.js file instead
 | 
			
		||||
    of the actual source code -->
 | 
			
		||||
    <script type="module">
 | 
			
		||||
      import * as ExcalidrawLib from "/dist/browser/dev/index.js";
 | 
			
		||||
      window.ExcalidrawLib = ExcalidrawLib;
 | 
			
		||||
    </script>
 | 
			
		||||
    <script type="module" src="bundle.js"></script>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
@@ -1,66 +0,0 @@
 | 
			
		||||
.sidebar {
 | 
			
		||||
  height: 100%;
 | 
			
		||||
  width: 0;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  z-index: 1;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  background-color: #111;
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
  transition: 0.5s;
 | 
			
		||||
  padding-top: 60px;
 | 
			
		||||
 | 
			
		||||
  &.open {
 | 
			
		||||
    width: 300px;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &-links {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    padding: 20px;
 | 
			
		||||
 | 
			
		||||
    button {
 | 
			
		||||
      padding: 10px;
 | 
			
		||||
      margin: 10px;
 | 
			
		||||
      background: #faa2c1;
 | 
			
		||||
      color: #fff;
 | 
			
		||||
      border: none;
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar a {
 | 
			
		||||
  padding: 8px 8px 8px 32px;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  font-size: 25px;
 | 
			
		||||
  color: #818181;
 | 
			
		||||
  display: block;
 | 
			
		||||
  transition: 0.3s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar a:hover {
 | 
			
		||||
  color: #f1f1f1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.sidebar .closebtn {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  font-size: 36px;
 | 
			
		||||
  margin-left: 50px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.openbtn {
 | 
			
		||||
  font-size: 20px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  background-color: #111;
 | 
			
		||||
  color: white;
 | 
			
		||||
  padding: 10px 15px;
 | 
			
		||||
  border: none;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  margin-left: 50px;
 | 
			
		||||
}
 | 
			
		||||
.sidebar-open {
 | 
			
		||||
  margin-left: 300px;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,32 +0,0 @@
 | 
			
		||||
import "./ExampleSidebar.scss";
 | 
			
		||||
 | 
			
		||||
const React = window.React;
 | 
			
		||||
 | 
			
		||||
export default function Sidebar({ children }: { children: React.ReactNode }) {
 | 
			
		||||
  const [open, setOpen] = React.useState(false);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <>
 | 
			
		||||
      <div id="mySidebar" className={`sidebar ${open ? "open" : ""}`}>
 | 
			
		||||
        <button className="closebtn" onClick={() => setOpen(false)}>
 | 
			
		||||
          x
 | 
			
		||||
        </button>
 | 
			
		||||
        <div className="sidebar-links">
 | 
			
		||||
          <button>Empty Home</button>
 | 
			
		||||
          <button>Empty About</button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div className={`${open ? "sidebar-open" : ""}`}>
 | 
			
		||||
        <button
 | 
			
		||||
          className="openbtn"
 | 
			
		||||
          onClick={() => {
 | 
			
		||||
            setOpen(!open);
 | 
			
		||||
          }}
 | 
			
		||||
        >
 | 
			
		||||
          Open Sidebar
 | 
			
		||||
        </button>
 | 
			
		||||
        {children}
 | 
			
		||||
      </div>
 | 
			
		||||
    </>
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
@@ -80,6 +80,13 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const importPolyfill = async () => {
 | 
			
		||||
      //@ts-ignore
 | 
			
		||||
      await import("canvas-roundrect-polyfill");
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    importPolyfill();
 | 
			
		||||
 | 
			
		||||
    // Block pinch-zooming on iOS outside of the content area
 | 
			
		||||
    const handleTouchMove = (event: TouchEvent) => {
 | 
			
		||||
      // @ts-ignore
 | 
			
		||||
@@ -223,7 +230,7 @@ export {
 | 
			
		||||
} from "../utils/export";
 | 
			
		||||
export { isLinearElement } from "./element/typeChecks";
 | 
			
		||||
 | 
			
		||||
export { FONT_FAMILY, THEME, MIME_TYPES } from "./constants";
 | 
			
		||||
export { FONT_FAMILY, THEME, MIME_TYPES, ROUNDNESS } from "./constants";
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
  mutateElement,
 | 
			
		||||
 
 | 
			
		||||
@@ -82,7 +82,6 @@ import {
 | 
			
		||||
  getTargetFrame,
 | 
			
		||||
  isElementInFrame,
 | 
			
		||||
} from "../frame";
 | 
			
		||||
import "canvas-roundrect-polyfill";
 | 
			
		||||
 | 
			
		||||
export const DEFAULT_SPACING = 2;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
  "exclude": ["**/*.test.*", "tests", "types", "example", "dist"],
 | 
			
		||||
  "exclude": ["**/*.test.*", "tests", "types", "examples", "dist"],
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "target": "ESNext",
 | 
			
		||||
    "strict": true,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "outputDirectory": "example/public",
 | 
			
		||||
  "installCommand": "yarn install"
 | 
			
		||||
}
 | 
			
		||||
@@ -1,15 +0,0 @@
 | 
			
		||||
import { defineConfig, loadEnv } from "vite";
 | 
			
		||||
import react from "@vitejs/plugin-react";
 | 
			
		||||
 | 
			
		||||
// To load .env.local variables
 | 
			
		||||
const envVars = loadEnv("", `../../`);
 | 
			
		||||
// https://vitejs.dev/config/
 | 
			
		||||
export default defineConfig({
 | 
			
		||||
  root: "example/public",
 | 
			
		||||
  server: {
 | 
			
		||||
    port: 3001,
 | 
			
		||||
    // open the browser
 | 
			
		||||
    open: true,
 | 
			
		||||
  },
 | 
			
		||||
  publicDir: "public",
 | 
			
		||||
});
 | 
			
		||||
		Reference in New Issue
	
	Block a user